@staff0rd/assist 0.281.3 → 0.282.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 +4 -5
- package/claude/commands/pr.md +14 -2
- package/dist/commands/sessions/web/bundle.js +62 -62
- package/dist/index.js +637 -491
- package/package.json +1 -1
- package/dist/commands/news/web/bundle.js +0 -66
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.282.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -230,9 +230,6 @@ var assistConfigSchema = z2.strictObject({
|
|
|
230
230
|
run: z2.array(z2.union([runConfigSchema, runLinkSchema])).optional(),
|
|
231
231
|
transcript: transcriptConfigSchema.optional(),
|
|
232
232
|
cliReadVerbs: z2.record(z2.string(), z2.array(z2.string())).optional(),
|
|
233
|
-
news: z2.strictObject({
|
|
234
|
-
feeds: z2.array(z2.string()).default([])
|
|
235
|
-
}).default({ feeds: [] }),
|
|
236
233
|
dotnet: z2.strictObject({
|
|
237
234
|
inspect: z2.strictObject({
|
|
238
235
|
suppress: z2.array(z2.string()).default([])
|
|
@@ -340,6 +337,7 @@ function loadConfig() {
|
|
|
340
337
|
const globalRaw = loadRawYaml(getGlobalConfigPath());
|
|
341
338
|
const projectRaw = loadRawYaml(getConfigPath());
|
|
342
339
|
const merged = mergeRawConfigs(globalRaw, projectRaw);
|
|
340
|
+
delete merged.news;
|
|
343
341
|
return assistConfigSchema.parse(merged);
|
|
344
342
|
}
|
|
345
343
|
function loadProjectConfig() {
|
|
@@ -444,13 +442,18 @@ var metadata = pgTable("metadata", {
|
|
|
444
442
|
key: text().primaryKey(),
|
|
445
443
|
value: text().notNull()
|
|
446
444
|
});
|
|
445
|
+
var feeds = pgTable("feeds", {
|
|
446
|
+
id: integer().generatedByDefaultAsIdentity().primaryKey(),
|
|
447
|
+
url: text().notNull().unique()
|
|
448
|
+
});
|
|
447
449
|
var backlogSchema = {
|
|
448
450
|
items,
|
|
449
451
|
comments,
|
|
450
452
|
links,
|
|
451
453
|
planPhases,
|
|
452
454
|
planTasks,
|
|
453
|
-
metadata
|
|
455
|
+
metadata,
|
|
456
|
+
feeds
|
|
454
457
|
};
|
|
455
458
|
|
|
456
459
|
// src/commands/backlog/BacklogOrm.ts
|
|
@@ -512,11 +515,45 @@ var SCHEMA = `
|
|
|
512
515
|
key TEXT PRIMARY KEY,
|
|
513
516
|
value TEXT NOT NULL
|
|
514
517
|
);
|
|
518
|
+
|
|
519
|
+
CREATE TABLE IF NOT EXISTS feeds (
|
|
520
|
+
id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
521
|
+
url TEXT NOT NULL UNIQUE
|
|
522
|
+
);
|
|
515
523
|
`;
|
|
516
524
|
async function ensureSchema(exec3) {
|
|
517
525
|
await exec3(SCHEMA);
|
|
518
526
|
}
|
|
519
527
|
|
|
528
|
+
// src/commands/backlog/addFeed.ts
|
|
529
|
+
async function addFeed(db, url) {
|
|
530
|
+
const inserted = await db.insert(feeds).values({ url }).onConflictDoNothing({ target: feeds.url }).returning({ id: feeds.id });
|
|
531
|
+
return inserted.length > 0;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/commands/backlog/listFeeds.ts
|
|
535
|
+
import { asc } from "drizzle-orm";
|
|
536
|
+
async function listFeeds(db) {
|
|
537
|
+
const rows = await db.select({ url: feeds.url }).from(feeds).orderBy(asc(feeds.id));
|
|
538
|
+
return rows.map((r) => r.url);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/commands/backlog/seedNewsFeeds.ts
|
|
542
|
+
function legacyFeeds(raw) {
|
|
543
|
+
const news = raw.news;
|
|
544
|
+
const feeds2 = news?.feeds;
|
|
545
|
+
return Array.isArray(feeds2) ? feeds2.filter((f) => typeof f === "string") : [];
|
|
546
|
+
}
|
|
547
|
+
async function seedNewsFeeds(db) {
|
|
548
|
+
const existing = await listFeeds(db);
|
|
549
|
+
if (existing.length > 0) return;
|
|
550
|
+
const projectFeeds = legacyFeeds(loadProjectConfig());
|
|
551
|
+
const configFeeds = projectFeeds.length > 0 ? projectFeeds : legacyFeeds(loadGlobalConfigRaw());
|
|
552
|
+
for (const url of configFeeds) {
|
|
553
|
+
await addFeed(db, url);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
520
557
|
// src/commands/backlog/getBacklogOrm.ts
|
|
521
558
|
var DATABASE_URL_ENV = "ASSIST_BACKLOG_DATABASE_URL";
|
|
522
559
|
var MISSING_URL_MESSAGE = `No backlog database configured.
|
|
@@ -549,6 +586,7 @@ function getBacklogOrm() {
|
|
|
549
586
|
_pool = pool;
|
|
550
587
|
await ensureSchema((sql4) => pool.query(sql4));
|
|
551
588
|
_orm = makeOrmFromPool(pool);
|
|
589
|
+
await seedNewsFeeds(_orm);
|
|
552
590
|
return _orm;
|
|
553
591
|
})();
|
|
554
592
|
return _connecting;
|
|
@@ -1835,7 +1873,7 @@ import { Project as Project2 } from "ts-morph";
|
|
|
1835
1873
|
function collectComments(sourceFile) {
|
|
1836
1874
|
const seen = /* @__PURE__ */ new Set();
|
|
1837
1875
|
const comments3 = [];
|
|
1838
|
-
const
|
|
1876
|
+
const collect4 = (node) => {
|
|
1839
1877
|
for (const range of [
|
|
1840
1878
|
...node.getLeadingCommentRanges(),
|
|
1841
1879
|
...node.getTrailingCommentRanges()
|
|
@@ -1846,8 +1884,8 @@ function collectComments(sourceFile) {
|
|
|
1846
1884
|
comments3.push({ pos, text: range.getText() });
|
|
1847
1885
|
}
|
|
1848
1886
|
};
|
|
1849
|
-
|
|
1850
|
-
sourceFile.forEachDescendant(
|
|
1887
|
+
collect4(sourceFile);
|
|
1888
|
+
sourceFile.forEachDescendant(collect4);
|
|
1851
1889
|
return comments3;
|
|
1852
1890
|
}
|
|
1853
1891
|
|
|
@@ -3190,10 +3228,10 @@ async function importItemsRemapped(orm, items2, origin) {
|
|
|
3190
3228
|
}
|
|
3191
3229
|
|
|
3192
3230
|
// src/commands/backlog/loadAllItems.ts
|
|
3193
|
-
import { asc as
|
|
3231
|
+
import { asc as asc3, eq as eq2 } from "drizzle-orm";
|
|
3194
3232
|
|
|
3195
3233
|
// src/commands/backlog/loadRelations.ts
|
|
3196
|
-
import { asc, inArray } from "drizzle-orm";
|
|
3234
|
+
import { asc as asc2, inArray } from "drizzle-orm";
|
|
3197
3235
|
function groupByItem(rows) {
|
|
3198
3236
|
const map = /* @__PURE__ */ new Map();
|
|
3199
3237
|
for (const row of rows) {
|
|
@@ -3203,13 +3241,13 @@ function groupByItem(rows) {
|
|
|
3203
3241
|
}
|
|
3204
3242
|
return map;
|
|
3205
3243
|
}
|
|
3206
|
-
var selectComments = (orm, ids) => orm.select().from(comments).where(inArray(comments.itemId, ids)).orderBy(
|
|
3207
|
-
var selectLinks = (orm, ids) => orm.select().from(links).where(inArray(links.itemId, ids)).orderBy(
|
|
3208
|
-
var selectPhases = (orm, ids) => orm.select().from(planPhases).where(inArray(planPhases.itemId, ids)).orderBy(
|
|
3244
|
+
var selectComments = (orm, ids) => orm.select().from(comments).where(inArray(comments.itemId, ids)).orderBy(asc2(comments.itemId), asc2(comments.idx));
|
|
3245
|
+
var selectLinks = (orm, ids) => orm.select().from(links).where(inArray(links.itemId, ids)).orderBy(asc2(links.itemId));
|
|
3246
|
+
var selectPhases = (orm, ids) => orm.select().from(planPhases).where(inArray(planPhases.itemId, ids)).orderBy(asc2(planPhases.itemId), asc2(planPhases.idx));
|
|
3209
3247
|
var selectTasks = (orm, ids) => orm.select().from(planTasks).where(inArray(planTasks.itemId, ids)).orderBy(
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3248
|
+
asc2(planTasks.itemId),
|
|
3249
|
+
asc2(planTasks.phaseIdx),
|
|
3250
|
+
asc2(planTasks.idx)
|
|
3213
3251
|
);
|
|
3214
3252
|
async function loadRelations(orm, ids, { includeComments = true, includeTasks = true } = {}) {
|
|
3215
3253
|
const [commentRows, linkRows, phaseRows, taskRows] = await Promise.all([
|
|
@@ -3299,7 +3337,7 @@ function rowToItem(row, rel) {
|
|
|
3299
3337
|
|
|
3300
3338
|
// src/commands/backlog/loadAllItems.ts
|
|
3301
3339
|
async function loadAllItems(orm, origin) {
|
|
3302
|
-
const rows = await orm.select().from(items).where(origin === void 0 ? void 0 : eq2(items.origin, origin)).orderBy(
|
|
3340
|
+
const rows = await orm.select().from(items).where(origin === void 0 ? void 0 : eq2(items.origin, origin)).orderBy(asc3(items.id));
|
|
3303
3341
|
if (rows.length === 0) return [];
|
|
3304
3342
|
const rel = await loadRelations(
|
|
3305
3343
|
orm,
|
|
@@ -3492,7 +3530,7 @@ import { eq as eq5, sql } from "drizzle-orm";
|
|
|
3492
3530
|
import { eq as eq4 } from "drizzle-orm";
|
|
3493
3531
|
|
|
3494
3532
|
// src/commands/backlog/searchItemIds.ts
|
|
3495
|
-
import { and, asc as
|
|
3533
|
+
import { and, asc as asc4, eq as eq6, ilike, or } from "drizzle-orm";
|
|
3496
3534
|
async function searchItemIds(orm, query, origin) {
|
|
3497
3535
|
const pattern2 = `%${query}%`;
|
|
3498
3536
|
const rows = await orm.selectDistinct({ id: items.id }).from(items).leftJoin(comments, eq6(comments.itemId, items.id)).leftJoin(planPhases, eq6(planPhases.itemId, items.id)).where(
|
|
@@ -3506,7 +3544,7 @@ async function searchItemIds(orm, query, origin) {
|
|
|
3506
3544
|
ilike(planPhases.name, pattern2)
|
|
3507
3545
|
)
|
|
3508
3546
|
)
|
|
3509
|
-
).orderBy(
|
|
3547
|
+
).orderBy(asc4(items.id));
|
|
3510
3548
|
return rows.map((r) => r.id);
|
|
3511
3549
|
}
|
|
3512
3550
|
|
|
@@ -4395,20 +4433,20 @@ function respondJson(res, status2, data) {
|
|
|
4395
4433
|
res.writeHead(status2, { "Content-Type": "application/json" });
|
|
4396
4434
|
res.end(JSON.stringify(data));
|
|
4397
4435
|
}
|
|
4398
|
-
function createHtmlHandler(
|
|
4436
|
+
function createHtmlHandler(getHtml2) {
|
|
4399
4437
|
return (_req, res) => {
|
|
4400
4438
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
4401
|
-
res.end(
|
|
4439
|
+
res.end(getHtml2());
|
|
4402
4440
|
};
|
|
4403
4441
|
}
|
|
4404
4442
|
function parseRoute(req, port) {
|
|
4405
4443
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
4406
4444
|
return { method: req.method ?? "GET", pathname: url.pathname };
|
|
4407
4445
|
}
|
|
4408
|
-
function createRouteHandler(
|
|
4446
|
+
function createRouteHandler(routes2) {
|
|
4409
4447
|
return async (req, res, port) => {
|
|
4410
4448
|
const { method, pathname } = parseRoute(req, port);
|
|
4411
|
-
const handler =
|
|
4449
|
+
const handler = routes2[`${method} ${pathname}`];
|
|
4412
4450
|
if (handler) {
|
|
4413
4451
|
await handler(req, res);
|
|
4414
4452
|
return;
|
|
@@ -4570,12 +4608,12 @@ function createBundleHandler(importMetaUrl, bundlePath) {
|
|
|
4570
4608
|
}
|
|
4571
4609
|
|
|
4572
4610
|
// src/shared/createFallbackHandler.ts
|
|
4573
|
-
function createFallbackHandler(
|
|
4574
|
-
const baseHandler = createRouteHandler(
|
|
4611
|
+
function createFallbackHandler(routes2, htmlHandler2, extra) {
|
|
4612
|
+
const baseHandler = createRouteHandler(routes2);
|
|
4575
4613
|
return async (req, res, port) => {
|
|
4576
4614
|
const { method, pathname } = parseRoute(req, port);
|
|
4577
4615
|
if (extra && await extra(req, res, pathname)) return;
|
|
4578
|
-
if (
|
|
4616
|
+
if (routes2[`${method} ${pathname}`]) {
|
|
4579
4617
|
await baseHandler(req, res, port);
|
|
4580
4618
|
return;
|
|
4581
4619
|
}
|
|
@@ -4634,7 +4672,7 @@ async function createItem(req, res) {
|
|
|
4634
4672
|
import { eq as eq11 } from "drizzle-orm";
|
|
4635
4673
|
|
|
4636
4674
|
// src/commands/backlog/loadItemSummaries.ts
|
|
4637
|
-
import { asc as
|
|
4675
|
+
import { asc as asc5, eq as eq10 } from "drizzle-orm";
|
|
4638
4676
|
async function loadItemSummaries(orm, origin) {
|
|
4639
4677
|
const rows = await orm.select({
|
|
4640
4678
|
id: items.id,
|
|
@@ -4642,7 +4680,7 @@ async function loadItemSummaries(orm, origin) {
|
|
|
4642
4680
|
type: items.type,
|
|
4643
4681
|
name: items.name,
|
|
4644
4682
|
status: items.status
|
|
4645
|
-
}).from(items).where(origin === void 0 ? void 0 : eq10(items.origin, origin)).orderBy(
|
|
4683
|
+
}).from(items).where(origin === void 0 ? void 0 : eq10(items.origin, origin)).orderBy(asc5(items.id));
|
|
4646
4684
|
return rows.map((row) => ({
|
|
4647
4685
|
id: row.id,
|
|
4648
4686
|
origin: row.origin,
|
|
@@ -5008,6 +5046,129 @@ function gitStatus(req, res) {
|
|
|
5008
5046
|
}
|
|
5009
5047
|
}
|
|
5010
5048
|
|
|
5049
|
+
// src/commands/news/shared.ts
|
|
5050
|
+
import { decodeHTML } from "entities";
|
|
5051
|
+
function extractText(xml, tag) {
|
|
5052
|
+
const cdataMatch = xml.match(
|
|
5053
|
+
new RegExp(`<${tag}>\\s*<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>\\s*</${tag}>`)
|
|
5054
|
+
);
|
|
5055
|
+
if (cdataMatch) return cdataMatch[1].trim();
|
|
5056
|
+
const match = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`));
|
|
5057
|
+
return match ? match[1].trim() : "";
|
|
5058
|
+
}
|
|
5059
|
+
function extractLink(itemXml) {
|
|
5060
|
+
const atomLink = itemXml.match(
|
|
5061
|
+
/<link[^>]*rel=["']alternate["'][^>]*href=["']([^"']+)["']/
|
|
5062
|
+
);
|
|
5063
|
+
if (atomLink) return atomLink[1];
|
|
5064
|
+
const atomLink2 = itemXml.match(/<link[^>]*href=["']([^"']+)["']/);
|
|
5065
|
+
if (atomLink2) return atomLink2[1];
|
|
5066
|
+
return extractText(itemXml, "link");
|
|
5067
|
+
}
|
|
5068
|
+
function parseDate(dateStr) {
|
|
5069
|
+
if (!dateStr) return (/* @__PURE__ */ new Date(0)).toISOString();
|
|
5070
|
+
try {
|
|
5071
|
+
return new Date(dateStr).toISOString();
|
|
5072
|
+
} catch {
|
|
5073
|
+
return (/* @__PURE__ */ new Date(0)).toISOString();
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
function stripHtml(html) {
|
|
5077
|
+
const decoded = decodeHTML(html);
|
|
5078
|
+
const stripped = decoded.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
5079
|
+
return decodeHTML(stripped);
|
|
5080
|
+
}
|
|
5081
|
+
function matchAll(xml, regex) {
|
|
5082
|
+
const results = [];
|
|
5083
|
+
for (const m of xml.matchAll(regex)) {
|
|
5084
|
+
results.push(m[1]);
|
|
5085
|
+
}
|
|
5086
|
+
return results;
|
|
5087
|
+
}
|
|
5088
|
+
var MAX_EXCERPT = 500;
|
|
5089
|
+
function excerpt(xml, ...tags) {
|
|
5090
|
+
for (const tag of tags) {
|
|
5091
|
+
const raw = extractText(xml, tag);
|
|
5092
|
+
if (!raw) continue;
|
|
5093
|
+
const text3 = stripHtml(raw);
|
|
5094
|
+
if (text3.length <= MAX_EXCERPT) return text3;
|
|
5095
|
+
return `${text3.slice(0, MAX_EXCERPT)}\u2026`;
|
|
5096
|
+
}
|
|
5097
|
+
return "";
|
|
5098
|
+
}
|
|
5099
|
+
|
|
5100
|
+
// src/commands/news/parseFeed.ts
|
|
5101
|
+
function parseRss(xml, feedOrigin) {
|
|
5102
|
+
const feedTitle = extractText(xml, "title");
|
|
5103
|
+
return matchAll(xml, /<item[\s>]([\s\S]*?)<\/item>/g).map((itemXml) => ({
|
|
5104
|
+
title: extractText(itemXml, "title"),
|
|
5105
|
+
link: extractLink(itemXml),
|
|
5106
|
+
pubDate: parseDate(
|
|
5107
|
+
extractText(itemXml, "pubDate") || extractText(itemXml, "dc:date")
|
|
5108
|
+
),
|
|
5109
|
+
feedTitle,
|
|
5110
|
+
feedOrigin,
|
|
5111
|
+
excerpt: excerpt(itemXml, "description", "content:encoded")
|
|
5112
|
+
}));
|
|
5113
|
+
}
|
|
5114
|
+
function parseAtom(xml, feedOrigin) {
|
|
5115
|
+
const feedTitle = extractText(xml, "title");
|
|
5116
|
+
return matchAll(xml, /<entry[\s>]([\s\S]*?)<\/entry>/g).map((entryXml) => ({
|
|
5117
|
+
title: extractText(entryXml, "title"),
|
|
5118
|
+
link: extractLink(entryXml),
|
|
5119
|
+
pubDate: parseDate(
|
|
5120
|
+
extractText(entryXml, "published") || extractText(entryXml, "updated")
|
|
5121
|
+
),
|
|
5122
|
+
feedTitle,
|
|
5123
|
+
feedOrigin,
|
|
5124
|
+
excerpt: excerpt(entryXml, "summary", "content")
|
|
5125
|
+
}));
|
|
5126
|
+
}
|
|
5127
|
+
function parseFeed(xml, feedOrigin) {
|
|
5128
|
+
if (xml.includes("<feed")) return parseAtom(xml, feedOrigin);
|
|
5129
|
+
return parseRss(xml, feedOrigin);
|
|
5130
|
+
}
|
|
5131
|
+
|
|
5132
|
+
// src/commands/news/fetchFeeds.ts
|
|
5133
|
+
async function fetchFeeds(urls, onProgress) {
|
|
5134
|
+
let done2 = 0;
|
|
5135
|
+
const results = await Promise.allSettled(
|
|
5136
|
+
urls.map(async (url) => {
|
|
5137
|
+
const origin = new URL(url).origin;
|
|
5138
|
+
const res = await fetch(url);
|
|
5139
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
5140
|
+
const items3 = parseFeed(await res.text(), origin);
|
|
5141
|
+
done2++;
|
|
5142
|
+
onProgress?.(done2, urls.length);
|
|
5143
|
+
return items3;
|
|
5144
|
+
})
|
|
5145
|
+
);
|
|
5146
|
+
const items2 = [];
|
|
5147
|
+
for (const result of results) {
|
|
5148
|
+
if (result.status === "fulfilled") {
|
|
5149
|
+
items2.push(...result.value);
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
items2.sort(
|
|
5153
|
+
(a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime()
|
|
5154
|
+
);
|
|
5155
|
+
return items2;
|
|
5156
|
+
}
|
|
5157
|
+
|
|
5158
|
+
// src/commands/sessions/web/listNewsItems.ts
|
|
5159
|
+
var cachedItems;
|
|
5160
|
+
var inflight;
|
|
5161
|
+
async function listNewsItems(_req, res) {
|
|
5162
|
+
if (!cachedItems) {
|
|
5163
|
+
if (!inflight)
|
|
5164
|
+
inflight = getReady().then(
|
|
5165
|
+
({ orm }) => listFeeds(orm).then((urls) => fetchFeeds(urls))
|
|
5166
|
+
);
|
|
5167
|
+
cachedItems = await inflight;
|
|
5168
|
+
}
|
|
5169
|
+
respondJson(res, 200, cachedItems);
|
|
5170
|
+
}
|
|
5171
|
+
|
|
5011
5172
|
// src/commands/sessions/web/openInCode.ts
|
|
5012
5173
|
import { exec } from "child_process";
|
|
5013
5174
|
import { promisify } from "util";
|
|
@@ -5052,7 +5213,8 @@ var routes = {
|
|
|
5052
5213
|
"POST /api/backlog/init": initBacklog,
|
|
5053
5214
|
"POST /api/open-in-code": openInCode,
|
|
5054
5215
|
"GET /api/github-url": githubUrl,
|
|
5055
|
-
"GET /api/git-status": gitStatus
|
|
5216
|
+
"GET /api/git-status": gitStatus,
|
|
5217
|
+
"GET /api/news/items": listNewsItems
|
|
5056
5218
|
};
|
|
5057
5219
|
var handleRequest = createFallbackHandler(
|
|
5058
5220
|
routes,
|
|
@@ -6621,9 +6783,9 @@ async function findPhase(id, phase) {
|
|
|
6621
6783
|
}
|
|
6622
6784
|
|
|
6623
6785
|
// src/commands/backlog/reindexPhases.ts
|
|
6624
|
-
import { and as and7, asc as
|
|
6786
|
+
import { and as and7, asc as asc6, count as count5, eq as eq24 } from "drizzle-orm";
|
|
6625
6787
|
async function reindexPhases(db, itemId) {
|
|
6626
|
-
const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq24(planPhases.itemId, itemId)).orderBy(
|
|
6788
|
+
const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq24(planPhases.itemId, itemId)).orderBy(asc6(planPhases.idx));
|
|
6627
6789
|
for (let i = 0; i < remaining.length; i++) {
|
|
6628
6790
|
const oldIdx = remaining[i].idx;
|
|
6629
6791
|
if (oldIdx === i) continue;
|
|
@@ -7433,7 +7595,7 @@ function matchesConfigDeny(command) {
|
|
|
7433
7595
|
var BUILTIN_DENIES = [
|
|
7434
7596
|
{
|
|
7435
7597
|
pattern: "gh pr create",
|
|
7436
|
-
message: "Do not run 'gh pr create' directly. Use 'assist prs
|
|
7598
|
+
message: "Do not run 'gh pr create' directly. Use 'assist prs raise --title <title> --what <what> --why <why>' instead \u2014 it assembles and validates the body before delegating to gh. Before running it, get explicit approval via the AskUserQuestion tool, regardless of permission mode, with the full proposed title and body in the approve option's preview field so the user actually sees them."
|
|
7437
7599
|
},
|
|
7438
7600
|
{
|
|
7439
7601
|
pattern: "git commit",
|
|
@@ -10729,212 +10891,23 @@ async function add2(url) {
|
|
|
10729
10891
|
});
|
|
10730
10892
|
url = response.url;
|
|
10731
10893
|
}
|
|
10732
|
-
const
|
|
10733
|
-
const
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
console.log(chalk118.yellow("Feed already exists in config"));
|
|
10894
|
+
const { orm } = await getReady();
|
|
10895
|
+
const added = await addFeed(orm, url);
|
|
10896
|
+
if (!added) {
|
|
10897
|
+
console.log(chalk118.yellow("Feed already exists"));
|
|
10737
10898
|
return;
|
|
10738
10899
|
}
|
|
10739
|
-
feeds.push(url);
|
|
10740
|
-
config.news = { ...news, feeds };
|
|
10741
|
-
saveGlobalConfig(config);
|
|
10742
10900
|
console.log(chalk118.green(`Added feed: ${url}`));
|
|
10743
10901
|
}
|
|
10744
10902
|
|
|
10745
|
-
// src/commands/news/web/handleRequest.ts
|
|
10746
|
-
import chalk119 from "chalk";
|
|
10747
|
-
|
|
10748
|
-
// src/commands/news/web/shared.ts
|
|
10749
|
-
import { decodeHTML } from "entities";
|
|
10750
|
-
function extractText(xml, tag) {
|
|
10751
|
-
const cdataMatch = xml.match(
|
|
10752
|
-
new RegExp(`<${tag}>\\s*<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>\\s*</${tag}>`)
|
|
10753
|
-
);
|
|
10754
|
-
if (cdataMatch) return cdataMatch[1].trim();
|
|
10755
|
-
const match = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`));
|
|
10756
|
-
return match ? match[1].trim() : "";
|
|
10757
|
-
}
|
|
10758
|
-
function extractLink(itemXml) {
|
|
10759
|
-
const atomLink = itemXml.match(
|
|
10760
|
-
/<link[^>]*rel=["']alternate["'][^>]*href=["']([^"']+)["']/
|
|
10761
|
-
);
|
|
10762
|
-
if (atomLink) return atomLink[1];
|
|
10763
|
-
const atomLink2 = itemXml.match(/<link[^>]*href=["']([^"']+)["']/);
|
|
10764
|
-
if (atomLink2) return atomLink2[1];
|
|
10765
|
-
return extractText(itemXml, "link");
|
|
10766
|
-
}
|
|
10767
|
-
function parseDate(dateStr) {
|
|
10768
|
-
if (!dateStr) return (/* @__PURE__ */ new Date(0)).toISOString();
|
|
10769
|
-
try {
|
|
10770
|
-
return new Date(dateStr).toISOString();
|
|
10771
|
-
} catch {
|
|
10772
|
-
return (/* @__PURE__ */ new Date(0)).toISOString();
|
|
10773
|
-
}
|
|
10774
|
-
}
|
|
10775
|
-
function stripHtml(html) {
|
|
10776
|
-
const decoded = decodeHTML(html);
|
|
10777
|
-
const stripped = decoded.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
10778
|
-
return decodeHTML(stripped);
|
|
10779
|
-
}
|
|
10780
|
-
function matchAll(xml, regex) {
|
|
10781
|
-
const results = [];
|
|
10782
|
-
for (const m of xml.matchAll(regex)) {
|
|
10783
|
-
results.push(m[1]);
|
|
10784
|
-
}
|
|
10785
|
-
return results;
|
|
10786
|
-
}
|
|
10787
|
-
var MAX_EXCERPT = 500;
|
|
10788
|
-
function excerpt(xml, ...tags) {
|
|
10789
|
-
for (const tag of tags) {
|
|
10790
|
-
const raw = extractText(xml, tag);
|
|
10791
|
-
if (!raw) continue;
|
|
10792
|
-
const text3 = stripHtml(raw);
|
|
10793
|
-
if (text3.length <= MAX_EXCERPT) return text3;
|
|
10794
|
-
return `${text3.slice(0, MAX_EXCERPT)}\u2026`;
|
|
10795
|
-
}
|
|
10796
|
-
return "";
|
|
10797
|
-
}
|
|
10798
|
-
|
|
10799
|
-
// src/commands/news/web/parseFeed.ts
|
|
10800
|
-
function parseRss(xml, feedOrigin) {
|
|
10801
|
-
const feedTitle = extractText(xml, "title");
|
|
10802
|
-
return matchAll(xml, /<item[\s>]([\s\S]*?)<\/item>/g).map((itemXml) => ({
|
|
10803
|
-
title: extractText(itemXml, "title"),
|
|
10804
|
-
link: extractLink(itemXml),
|
|
10805
|
-
pubDate: parseDate(
|
|
10806
|
-
extractText(itemXml, "pubDate") || extractText(itemXml, "dc:date")
|
|
10807
|
-
),
|
|
10808
|
-
feedTitle,
|
|
10809
|
-
feedOrigin,
|
|
10810
|
-
excerpt: excerpt(itemXml, "description", "content:encoded")
|
|
10811
|
-
}));
|
|
10812
|
-
}
|
|
10813
|
-
function parseAtom(xml, feedOrigin) {
|
|
10814
|
-
const feedTitle = extractText(xml, "title");
|
|
10815
|
-
return matchAll(xml, /<entry[\s>]([\s\S]*?)<\/entry>/g).map((entryXml) => ({
|
|
10816
|
-
title: extractText(entryXml, "title"),
|
|
10817
|
-
link: extractLink(entryXml),
|
|
10818
|
-
pubDate: parseDate(
|
|
10819
|
-
extractText(entryXml, "published") || extractText(entryXml, "updated")
|
|
10820
|
-
),
|
|
10821
|
-
feedTitle,
|
|
10822
|
-
feedOrigin,
|
|
10823
|
-
excerpt: excerpt(entryXml, "summary", "content")
|
|
10824
|
-
}));
|
|
10825
|
-
}
|
|
10826
|
-
function parseFeed(xml, feedOrigin) {
|
|
10827
|
-
if (xml.includes("<feed")) return parseAtom(xml, feedOrigin);
|
|
10828
|
-
return parseRss(xml, feedOrigin);
|
|
10829
|
-
}
|
|
10830
|
-
|
|
10831
|
-
// src/commands/news/web/fetchFeeds.ts
|
|
10832
|
-
async function fetchFeeds(urls, onProgress) {
|
|
10833
|
-
let done2 = 0;
|
|
10834
|
-
const results = await Promise.allSettled(
|
|
10835
|
-
urls.map(async (url) => {
|
|
10836
|
-
const origin = new URL(url).origin;
|
|
10837
|
-
const res = await fetch(url);
|
|
10838
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
10839
|
-
const items3 = parseFeed(await res.text(), origin);
|
|
10840
|
-
done2++;
|
|
10841
|
-
onProgress?.(done2, urls.length);
|
|
10842
|
-
return items3;
|
|
10843
|
-
})
|
|
10844
|
-
);
|
|
10845
|
-
const items2 = [];
|
|
10846
|
-
for (const result of results) {
|
|
10847
|
-
if (result.status === "fulfilled") {
|
|
10848
|
-
items2.push(...result.value);
|
|
10849
|
-
}
|
|
10850
|
-
}
|
|
10851
|
-
items2.sort(
|
|
10852
|
-
(a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime()
|
|
10853
|
-
);
|
|
10854
|
-
return items2;
|
|
10855
|
-
}
|
|
10856
|
-
|
|
10857
|
-
// src/commands/news/web/getHtml.ts
|
|
10858
|
-
function getHtml2() {
|
|
10859
|
-
return `<!DOCTYPE html>
|
|
10860
|
-
<html lang="en" class="dark">
|
|
10861
|
-
<head>
|
|
10862
|
-
<meta charset="UTF-8">
|
|
10863
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
10864
|
-
<title>News</title>
|
|
10865
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
10866
|
-
<script>tailwind.config={darkMode:'class'}</script>
|
|
10867
|
-
</head>
|
|
10868
|
-
<body class="font-[-apple-system,BlinkMacSystemFont,'Segoe_UI',Roboto,sans-serif] bg-gray-950 text-gray-200 leading-normal">
|
|
10869
|
-
<div class="max-w-3xl mx-auto px-4 py-6" id="app"></div>
|
|
10870
|
-
<script src="/bundle.js"></script>
|
|
10871
|
-
</body>
|
|
10872
|
-
</html>`;
|
|
10873
|
-
}
|
|
10874
|
-
|
|
10875
|
-
// src/commands/news/web/handleRequest.ts
|
|
10876
|
-
var cachedItems;
|
|
10877
|
-
var prefetchPromise;
|
|
10878
|
-
function prefetch() {
|
|
10879
|
-
const config = loadConfig();
|
|
10880
|
-
const total = config.news.feeds.length;
|
|
10881
|
-
if (total === 0) return;
|
|
10882
|
-
process.stdout.write(chalk119.dim(`Fetching ${total} feed(s)\u2026 `));
|
|
10883
|
-
prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
|
|
10884
|
-
const width = 20;
|
|
10885
|
-
const filled = Math.round(done2 / t * width);
|
|
10886
|
-
const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
|
|
10887
|
-
process.stdout.write(
|
|
10888
|
-
`\r${chalk119.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
|
|
10889
|
-
);
|
|
10890
|
-
}).then((items2) => {
|
|
10891
|
-
process.stdout.write(
|
|
10892
|
-
`\r${chalk119.green(`Fetched ${items2.length} items from ${total} feed(s)`)}
|
|
10893
|
-
`
|
|
10894
|
-
);
|
|
10895
|
-
cachedItems = items2;
|
|
10896
|
-
return items2;
|
|
10897
|
-
});
|
|
10898
|
-
}
|
|
10899
|
-
async function listItems2(_req, res) {
|
|
10900
|
-
if (!cachedItems && prefetchPromise) {
|
|
10901
|
-
await prefetchPromise;
|
|
10902
|
-
}
|
|
10903
|
-
if (!cachedItems) {
|
|
10904
|
-
const config = loadConfig();
|
|
10905
|
-
cachedItems = await fetchFeeds(config.news.feeds);
|
|
10906
|
-
}
|
|
10907
|
-
respondJson(res, 200, cachedItems);
|
|
10908
|
-
}
|
|
10909
|
-
var routes2 = {
|
|
10910
|
-
"GET /": createHtmlHandler(getHtml2),
|
|
10911
|
-
"GET /bundle.js": createBundleHandler(
|
|
10912
|
-
import.meta.url,
|
|
10913
|
-
"commands/news/web/bundle.js"
|
|
10914
|
-
),
|
|
10915
|
-
"GET /api/items": listItems2
|
|
10916
|
-
};
|
|
10917
|
-
var handleRequest2 = createRouteHandler(routes2);
|
|
10918
|
-
|
|
10919
|
-
// src/commands/news/web/index.ts
|
|
10920
|
-
async function web3(options2) {
|
|
10921
|
-
prefetch();
|
|
10922
|
-
startWebServer(
|
|
10923
|
-
"News web view",
|
|
10924
|
-
Number.parseInt(options2.port, 10),
|
|
10925
|
-
handleRequest2
|
|
10926
|
-
);
|
|
10927
|
-
}
|
|
10928
|
-
|
|
10929
10903
|
// src/commands/registerNews.ts
|
|
10930
10904
|
function registerNews(program2) {
|
|
10931
|
-
const newsCommand = program2.command("news").description("
|
|
10932
|
-
newsCommand.command("add").description("Add an RSS feed URL
|
|
10933
|
-
newsCommand.command("web").description("Start a web view of the news feeds").option("-p, --port <number>", "Port to listen on", "3001").action(web3);
|
|
10905
|
+
const newsCommand = program2.command("news").description("Manage RSS news feeds");
|
|
10906
|
+
newsCommand.command("add").description("Add an RSS feed URL").argument("<url>", "RSS feed URL").action(add2);
|
|
10934
10907
|
}
|
|
10935
10908
|
|
|
10936
10909
|
// src/commands/prompts/printPromptsTable.ts
|
|
10937
|
-
import
|
|
10910
|
+
import chalk119 from "chalk";
|
|
10938
10911
|
function truncate(str, max) {
|
|
10939
10912
|
if (str.length <= max) return str;
|
|
10940
10913
|
return `${str.slice(0, max - 1)}\u2026`;
|
|
@@ -10952,14 +10925,14 @@ function printPromptsTable(rows) {
|
|
|
10952
10925
|
"Command".padEnd(commandWidth),
|
|
10953
10926
|
"Repos"
|
|
10954
10927
|
].join(" ");
|
|
10955
|
-
console.log(
|
|
10956
|
-
console.log(
|
|
10928
|
+
console.log(chalk119.dim(header));
|
|
10929
|
+
console.log(chalk119.dim("-".repeat(header.length)));
|
|
10957
10930
|
for (const row of rows) {
|
|
10958
10931
|
const count6 = String(row.count).padStart(countWidth);
|
|
10959
10932
|
const tool = row.tool.padEnd(toolWidth);
|
|
10960
10933
|
const command = truncate(row.command, 60).padEnd(commandWidth);
|
|
10961
10934
|
console.log(
|
|
10962
|
-
`${
|
|
10935
|
+
`${chalk119.yellow(count6)} ${tool} ${command} ${chalk119.dim(row.repos)}`
|
|
10963
10936
|
);
|
|
10964
10937
|
}
|
|
10965
10938
|
}
|
|
@@ -11035,6 +11008,17 @@ function getCurrentPrNumber() {
|
|
|
11035
11008
|
throw error;
|
|
11036
11009
|
}
|
|
11037
11010
|
}
|
|
11011
|
+
function getCurrentPr() {
|
|
11012
|
+
try {
|
|
11013
|
+
return viewCurrentPr("number,body");
|
|
11014
|
+
} catch (error) {
|
|
11015
|
+
if (error instanceof Error && error.message.includes("no pull requests")) {
|
|
11016
|
+
console.error("Error: No pull request found for the current branch.");
|
|
11017
|
+
process.exit(1);
|
|
11018
|
+
}
|
|
11019
|
+
throw error;
|
|
11020
|
+
}
|
|
11021
|
+
}
|
|
11038
11022
|
function getCurrentPrNodeId() {
|
|
11039
11023
|
try {
|
|
11040
11024
|
return viewCurrentPr("id").id;
|
|
@@ -11111,37 +11095,102 @@ function comment2(path54, line, body, startLine) {
|
|
|
11111
11095
|
}
|
|
11112
11096
|
}
|
|
11113
11097
|
|
|
11114
|
-
// src/commands/prs/
|
|
11098
|
+
// src/commands/prs/edit.ts
|
|
11115
11099
|
import { execSync as execSync33 } from "child_process";
|
|
11116
11100
|
|
|
11117
|
-
// src/commands/prs/
|
|
11118
|
-
function
|
|
11119
|
-
const
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
|
|
11125
|
-
|
|
11126
|
-
|
|
11127
|
-
|
|
11128
|
-
];
|
|
11129
|
-
for (const [flag, value] of valueFlags) {
|
|
11130
|
-
if (value) args.push(`${flag} ${shellQuote(value)}`);
|
|
11101
|
+
// src/commands/prs/buildPrBody.ts
|
|
11102
|
+
function jiraBrowseUrl(key) {
|
|
11103
|
+
const { site } = loadJson("jira.json");
|
|
11104
|
+
return site ? `https://${site}/browse/${key}` : key;
|
|
11105
|
+
}
|
|
11106
|
+
function renderWhy(why, resolves) {
|
|
11107
|
+
if (resolves && resolves.length > 0) {
|
|
11108
|
+
const urls = resolves.map(jiraBrowseUrl).join(", ");
|
|
11109
|
+
return `${why}
|
|
11110
|
+
|
|
11111
|
+
Resolves ${urls}`;
|
|
11131
11112
|
}
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
11135
|
-
|
|
11136
|
-
|
|
11137
|
-
|
|
11113
|
+
return why;
|
|
11114
|
+
}
|
|
11115
|
+
function buildPrBody(sections) {
|
|
11116
|
+
const parts = [
|
|
11117
|
+
`## What
|
|
11118
|
+
|
|
11119
|
+
${sections.what}`,
|
|
11120
|
+
`## Why
|
|
11121
|
+
|
|
11122
|
+
${renderWhy(sections.why, sections.resolves)}`
|
|
11138
11123
|
];
|
|
11139
|
-
|
|
11140
|
-
|
|
11141
|
-
|
|
11124
|
+
if (sections.how) {
|
|
11125
|
+
parts.push(`## How
|
|
11126
|
+
|
|
11127
|
+
${sections.how}`);
|
|
11128
|
+
}
|
|
11129
|
+
return parts.join("\n\n");
|
|
11130
|
+
}
|
|
11131
|
+
|
|
11132
|
+
// src/commands/prs/parsePrBody.ts
|
|
11133
|
+
function parsePrBody(body) {
|
|
11134
|
+
const sections = [];
|
|
11135
|
+
let current = null;
|
|
11136
|
+
const flush = () => {
|
|
11137
|
+
if (current) {
|
|
11138
|
+
sections.push({
|
|
11139
|
+
heading: current.heading,
|
|
11140
|
+
content: current.lines.join("\n").trim()
|
|
11141
|
+
});
|
|
11142
|
+
}
|
|
11143
|
+
};
|
|
11144
|
+
for (const line of body.split("\n")) {
|
|
11145
|
+
const match = /^##\s+(.+?)\s*$/.exec(line);
|
|
11146
|
+
if (match) {
|
|
11147
|
+
flush();
|
|
11148
|
+
current = { heading: match[1], lines: [] };
|
|
11149
|
+
} else if (current) {
|
|
11150
|
+
current.lines.push(line);
|
|
11142
11151
|
}
|
|
11143
11152
|
}
|
|
11144
|
-
|
|
11153
|
+
flush();
|
|
11154
|
+
return sections;
|
|
11155
|
+
}
|
|
11156
|
+
function serializePrBody(sections) {
|
|
11157
|
+
return sections.map((section2) => `## ${section2.heading}
|
|
11158
|
+
|
|
11159
|
+
${section2.content}`).join("\n\n");
|
|
11160
|
+
}
|
|
11161
|
+
|
|
11162
|
+
// src/commands/prs/editPrBody.ts
|
|
11163
|
+
function stripResolves(content) {
|
|
11164
|
+
return content.replace(/\n+Resolves [^\n]*$/, "").trimEnd();
|
|
11165
|
+
}
|
|
11166
|
+
function extractResolves(content) {
|
|
11167
|
+
const match = /\n+(Resolves [^\n]*)$/.exec(content);
|
|
11168
|
+
return match ? match[1] : "";
|
|
11169
|
+
}
|
|
11170
|
+
function editPrBody(body, sections) {
|
|
11171
|
+
const parsed = parsePrBody(body);
|
|
11172
|
+
const find = (heading) => parsed.find((s) => s.heading.toLowerCase() === heading.toLowerCase());
|
|
11173
|
+
const upsert = (heading, content) => {
|
|
11174
|
+
const existing = find(heading);
|
|
11175
|
+
if (existing) existing.content = content;
|
|
11176
|
+
else parsed.push({ heading, content });
|
|
11177
|
+
};
|
|
11178
|
+
if (sections.what !== void 0) upsert("What", sections.what);
|
|
11179
|
+
const hasResolves = (sections.resolves?.length ?? 0) > 0;
|
|
11180
|
+
if (sections.why !== void 0 || hasResolves) {
|
|
11181
|
+
const existingWhy = find("Why")?.content ?? "";
|
|
11182
|
+
const baseWhy = sections.why !== void 0 ? sections.why : stripResolves(existingWhy);
|
|
11183
|
+
if (hasResolves) {
|
|
11184
|
+
upsert("Why", renderWhy(baseWhy, sections.resolves));
|
|
11185
|
+
} else {
|
|
11186
|
+
const resolves = extractResolves(existingWhy);
|
|
11187
|
+
upsert("Why", resolves ? `${baseWhy}
|
|
11188
|
+
|
|
11189
|
+
${resolves}` : baseWhy);
|
|
11190
|
+
}
|
|
11191
|
+
}
|
|
11192
|
+
if (sections.how !== void 0) upsert("How", sections.how);
|
|
11193
|
+
return serializePrBody(parsed);
|
|
11145
11194
|
}
|
|
11146
11195
|
|
|
11147
11196
|
// src/commands/prs/validatePrContent.ts
|
|
@@ -11156,16 +11205,22 @@ function validatePrContent(title, body) {
|
|
|
11156
11205
|
}
|
|
11157
11206
|
}
|
|
11158
11207
|
|
|
11159
|
-
// src/commands/prs/
|
|
11160
|
-
function
|
|
11161
|
-
|
|
11208
|
+
// src/commands/prs/edit.ts
|
|
11209
|
+
function edit(options2) {
|
|
11210
|
+
const hasResolves = (options2.resolves?.length ?? 0) > 0;
|
|
11211
|
+
const hasSection = options2.what !== void 0 || options2.why !== void 0 || options2.how !== void 0 || hasResolves;
|
|
11212
|
+
if (!options2.title && !hasSection) {
|
|
11162
11213
|
console.error(
|
|
11163
|
-
"Usage: assist prs
|
|
11214
|
+
"Usage: assist prs edit [--title <title>] [--what <what>] [--why <why>] [--how <how>] [--resolves <key>]"
|
|
11164
11215
|
);
|
|
11165
11216
|
process.exit(1);
|
|
11166
11217
|
}
|
|
11167
|
-
|
|
11168
|
-
const
|
|
11218
|
+
const { number, body } = getCurrentPr();
|
|
11219
|
+
const newBody = editPrBody(body, options2);
|
|
11220
|
+
validatePrContent(options2.title ?? "", newBody);
|
|
11221
|
+
const args = [`gh pr edit ${number}`];
|
|
11222
|
+
if (options2.title) args.push(`--title ${shellQuote(options2.title)}`);
|
|
11223
|
+
args.push(`--body ${shellQuote(newBody)}`);
|
|
11169
11224
|
try {
|
|
11170
11225
|
execSync33(args.join(" "), { stdio: "inherit" });
|
|
11171
11226
|
} catch (_error) {
|
|
@@ -11376,20 +11431,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
11376
11431
|
}
|
|
11377
11432
|
|
|
11378
11433
|
// src/commands/prs/listComments/printComments.ts
|
|
11379
|
-
import
|
|
11434
|
+
import chalk120 from "chalk";
|
|
11380
11435
|
function formatForHuman(comment3) {
|
|
11381
11436
|
if (comment3.type === "review") {
|
|
11382
|
-
const stateColor = comment3.state === "APPROVED" ?
|
|
11437
|
+
const stateColor = comment3.state === "APPROVED" ? chalk120.green : comment3.state === "CHANGES_REQUESTED" ? chalk120.red : chalk120.yellow;
|
|
11383
11438
|
return [
|
|
11384
|
-
`${
|
|
11439
|
+
`${chalk120.cyan("Review")} by ${chalk120.bold(comment3.user)} ${stateColor(`[${comment3.state}]`)}`,
|
|
11385
11440
|
comment3.body,
|
|
11386
11441
|
""
|
|
11387
11442
|
].join("\n");
|
|
11388
11443
|
}
|
|
11389
11444
|
const location = comment3.line ? `:${comment3.line}` : "";
|
|
11390
11445
|
return [
|
|
11391
|
-
`${
|
|
11392
|
-
|
|
11446
|
+
`${chalk120.cyan("Line comment")} by ${chalk120.bold(comment3.user)} on ${chalk120.dim(`${comment3.path}${location}`)}`,
|
|
11447
|
+
chalk120.dim(comment3.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
11393
11448
|
comment3.body,
|
|
11394
11449
|
""
|
|
11395
11450
|
].join("\n");
|
|
@@ -11479,13 +11534,13 @@ import { execSync as execSync38 } from "child_process";
|
|
|
11479
11534
|
import enquirer9 from "enquirer";
|
|
11480
11535
|
|
|
11481
11536
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
11482
|
-
import
|
|
11537
|
+
import chalk121 from "chalk";
|
|
11483
11538
|
var STATUS_MAP = {
|
|
11484
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
11485
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
11539
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk121.magenta("merged"), date: pr.mergedAt } : null,
|
|
11540
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk121.red("closed"), date: pr.closedAt } : null
|
|
11486
11541
|
};
|
|
11487
11542
|
function defaultStatus(pr) {
|
|
11488
|
-
return { label:
|
|
11543
|
+
return { label: chalk121.green("opened"), date: pr.createdAt };
|
|
11489
11544
|
}
|
|
11490
11545
|
function getStatus2(pr) {
|
|
11491
11546
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -11494,11 +11549,11 @@ function formatDate(dateStr) {
|
|
|
11494
11549
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
11495
11550
|
}
|
|
11496
11551
|
function formatPrHeader(pr, status2) {
|
|
11497
|
-
return `${
|
|
11552
|
+
return `${chalk121.cyan(`#${pr.number}`)} ${pr.title} ${chalk121.dim(`(${pr.author.login},`)} ${status2.label} ${chalk121.dim(`${formatDate(status2.date)})`)}`;
|
|
11498
11553
|
}
|
|
11499
11554
|
function logPrDetails(pr) {
|
|
11500
11555
|
console.log(
|
|
11501
|
-
|
|
11556
|
+
chalk121.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
11502
11557
|
);
|
|
11503
11558
|
console.log();
|
|
11504
11559
|
}
|
|
@@ -11602,8 +11657,75 @@ async function prs(options2) {
|
|
|
11602
11657
|
}
|
|
11603
11658
|
}
|
|
11604
11659
|
|
|
11605
|
-
// src/commands/prs/
|
|
11660
|
+
// src/commands/prs/raise.ts
|
|
11606
11661
|
import { execSync as execSync39 } from "child_process";
|
|
11662
|
+
|
|
11663
|
+
// src/commands/prs/buildCreateArgs.ts
|
|
11664
|
+
function buildCreateArgs(title, body, options2) {
|
|
11665
|
+
const args = [
|
|
11666
|
+
"gh pr create",
|
|
11667
|
+
`--title ${shellQuote(title)}`,
|
|
11668
|
+
`--body ${shellQuote(body)}`
|
|
11669
|
+
];
|
|
11670
|
+
const valueFlags = [
|
|
11671
|
+
["--base", options2.base],
|
|
11672
|
+
["--head", options2.head],
|
|
11673
|
+
["--milestone", options2.milestone]
|
|
11674
|
+
];
|
|
11675
|
+
for (const [flag, value] of valueFlags) {
|
|
11676
|
+
if (value) args.push(`${flag} ${shellQuote(value)}`);
|
|
11677
|
+
}
|
|
11678
|
+
if (options2.draft) args.push("--draft");
|
|
11679
|
+
if (options2.web) args.push("--web");
|
|
11680
|
+
const repeatableFlags = [
|
|
11681
|
+
["--label", options2.label],
|
|
11682
|
+
["--assignee", options2.assignee],
|
|
11683
|
+
["--reviewer", options2.reviewer]
|
|
11684
|
+
];
|
|
11685
|
+
for (const [flag, values] of repeatableFlags) {
|
|
11686
|
+
for (const value of values ?? []) {
|
|
11687
|
+
args.push(`${flag} ${shellQuote(value)}`);
|
|
11688
|
+
}
|
|
11689
|
+
}
|
|
11690
|
+
return args;
|
|
11691
|
+
}
|
|
11692
|
+
|
|
11693
|
+
// src/commands/prs/raise.ts
|
|
11694
|
+
function raise(options2) {
|
|
11695
|
+
if (!options2.title || !options2.what || !options2.why) {
|
|
11696
|
+
console.error(
|
|
11697
|
+
"Usage: assist prs raise --title <title> --what <what> --why <why> [--how <how>] [--resolves <key>] [--force]"
|
|
11698
|
+
);
|
|
11699
|
+
process.exit(1);
|
|
11700
|
+
}
|
|
11701
|
+
const body = buildPrBody({
|
|
11702
|
+
what: options2.what,
|
|
11703
|
+
why: options2.why,
|
|
11704
|
+
how: options2.how,
|
|
11705
|
+
resolves: options2.resolves
|
|
11706
|
+
});
|
|
11707
|
+
validatePrContent(options2.title, body);
|
|
11708
|
+
const existing = findCurrentPrNumber();
|
|
11709
|
+
if (existing !== null && !options2.force) {
|
|
11710
|
+
console.error(
|
|
11711
|
+
`Error: A pull request already exists for this branch (#${existing}). Pass --force to overwrite it, or use 'assist prs edit' to update individual sections.`
|
|
11712
|
+
);
|
|
11713
|
+
process.exit(1);
|
|
11714
|
+
}
|
|
11715
|
+
const args = existing !== null ? [
|
|
11716
|
+
`gh pr edit ${existing}`,
|
|
11717
|
+
`--title ${shellQuote(options2.title)}`,
|
|
11718
|
+
`--body ${shellQuote(body)}`
|
|
11719
|
+
] : buildCreateArgs(options2.title, body, options2);
|
|
11720
|
+
try {
|
|
11721
|
+
execSync39(args.join(" "), { stdio: "inherit" });
|
|
11722
|
+
} catch (_error) {
|
|
11723
|
+
process.exit(1);
|
|
11724
|
+
}
|
|
11725
|
+
}
|
|
11726
|
+
|
|
11727
|
+
// src/commands/prs/wontfix.ts
|
|
11728
|
+
import { execSync as execSync40 } from "child_process";
|
|
11607
11729
|
function validateReason(reason) {
|
|
11608
11730
|
const lowerReason = reason.toLowerCase();
|
|
11609
11731
|
if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
|
|
@@ -11620,7 +11742,7 @@ function validateShaReferences(reason) {
|
|
|
11620
11742
|
const invalidShas = [];
|
|
11621
11743
|
for (const sha of shas) {
|
|
11622
11744
|
try {
|
|
11623
|
-
|
|
11745
|
+
execSync40(`git cat-file -t ${sha}`, { stdio: "pipe" });
|
|
11624
11746
|
} catch {
|
|
11625
11747
|
invalidShas.push(sha);
|
|
11626
11748
|
}
|
|
@@ -11647,30 +11769,54 @@ function wontfix(commentId, reason) {
|
|
|
11647
11769
|
}
|
|
11648
11770
|
}
|
|
11649
11771
|
|
|
11650
|
-
// src/commands/
|
|
11772
|
+
// src/commands/registerPrsEdit.ts
|
|
11651
11773
|
function collect2(value, previous) {
|
|
11652
11774
|
return previous.concat([value]);
|
|
11653
11775
|
}
|
|
11654
|
-
function
|
|
11655
|
-
prsCommand.command("
|
|
11656
|
-
"
|
|
11657
|
-
).option("-t, --title <title>", "
|
|
11776
|
+
function registerPrsEdit(prsCommand) {
|
|
11777
|
+
prsCommand.command("edit").description(
|
|
11778
|
+
"Update individual sections of the current branch's pull request"
|
|
11779
|
+
).option("-t, --title <title>", "New title for the pull request").option("--what <what>", "Replace the ## What section").option("--why <why>", "Replace the ## Why section").option("--how <how>", "Replace the ## How section").option(
|
|
11780
|
+
"--resolves <key>",
|
|
11781
|
+
"Jira issue key resolved by this PR, appended to ## Why (repeatable)",
|
|
11782
|
+
collect2,
|
|
11783
|
+
[]
|
|
11784
|
+
).action(edit);
|
|
11785
|
+
}
|
|
11786
|
+
|
|
11787
|
+
// src/commands/registerPrsRaise.ts
|
|
11788
|
+
function collect3(value, previous) {
|
|
11789
|
+
return previous.concat([value]);
|
|
11790
|
+
}
|
|
11791
|
+
function registerPrsRaise(prsCommand) {
|
|
11792
|
+
prsCommand.command("raise").description(
|
|
11793
|
+
"Raise a pull request, assembling the body from discrete sections"
|
|
11794
|
+
).option("-t, --title <title>", "Title for the pull request").option("--what <what>", "What the change does (## What section)").option("--why <why>", "Why the change is needed (## Why section)").option("--how <how>", "How the change works (optional ## How section)").option(
|
|
11795
|
+
"--resolves <key>",
|
|
11796
|
+
"Jira issue key resolved by this PR, appended to ## Why (repeatable)",
|
|
11797
|
+
collect3,
|
|
11798
|
+
[]
|
|
11799
|
+
).option(
|
|
11800
|
+
"--force",
|
|
11801
|
+
"Overwrite the title and body of an existing pull request"
|
|
11802
|
+
).option("-B, --base <branch>", "Branch into which the pull request merges").option("-H, --head <branch>", "Branch that contains the commits").option("-d, --draft", "Mark the pull request as a draft").option("-w, --web", "Open the browser to create the pull request").option("-l, --label <label>", "Add a label (repeatable)", collect3, []).option(
|
|
11658
11803
|
"-a, --assignee <login>",
|
|
11659
11804
|
"Assign a person by login (repeatable)",
|
|
11660
|
-
|
|
11805
|
+
collect3,
|
|
11661
11806
|
[]
|
|
11662
11807
|
).option(
|
|
11663
11808
|
"-r, --reviewer <handle>",
|
|
11664
11809
|
"Request a review (repeatable)",
|
|
11665
|
-
|
|
11810
|
+
collect3,
|
|
11666
11811
|
[]
|
|
11667
|
-
).option("-m, --milestone <name>", "Add the pull request to a milestone").action(
|
|
11812
|
+
).option("-m, --milestone <name>", "Add the pull request to a milestone").action(raise);
|
|
11668
11813
|
}
|
|
11669
11814
|
|
|
11670
11815
|
// src/commands/registerPrs.ts
|
|
11671
11816
|
function registerPrs(program2) {
|
|
11672
11817
|
const prsCommand = program2.command("prs").description("Pull request utilities").option("--open", "List only open pull requests").option("--closed", "List only closed pull requests").action(prs);
|
|
11673
|
-
|
|
11818
|
+
registerPrsRaise(prsCommand);
|
|
11819
|
+
registerPrsEdit(prsCommand);
|
|
11674
11820
|
prsCommand.command("list-comments").description("List all comments on the current branch's pull request").action(() => {
|
|
11675
11821
|
listComments().then(printComments2);
|
|
11676
11822
|
});
|
|
@@ -11686,10 +11832,10 @@ function registerPrs(program2) {
|
|
|
11686
11832
|
}
|
|
11687
11833
|
|
|
11688
11834
|
// src/commands/ravendb/ravendbAuth.ts
|
|
11689
|
-
import
|
|
11835
|
+
import chalk127 from "chalk";
|
|
11690
11836
|
|
|
11691
11837
|
// src/shared/createConnectionAuth.ts
|
|
11692
|
-
import
|
|
11838
|
+
import chalk122 from "chalk";
|
|
11693
11839
|
function listConnections(connections, format2) {
|
|
11694
11840
|
if (connections.length === 0) {
|
|
11695
11841
|
console.log("No connections configured.");
|
|
@@ -11702,7 +11848,7 @@ function listConnections(connections, format2) {
|
|
|
11702
11848
|
function removeConnection(connections, name, save) {
|
|
11703
11849
|
const filtered = connections.filter((c) => c.name !== name);
|
|
11704
11850
|
if (filtered.length === connections.length) {
|
|
11705
|
-
console.error(
|
|
11851
|
+
console.error(chalk122.red(`Connection "${name}" not found.`));
|
|
11706
11852
|
process.exit(1);
|
|
11707
11853
|
}
|
|
11708
11854
|
save(filtered);
|
|
@@ -11748,17 +11894,17 @@ function saveConnections(connections) {
|
|
|
11748
11894
|
}
|
|
11749
11895
|
|
|
11750
11896
|
// src/commands/ravendb/promptConnection.ts
|
|
11751
|
-
import
|
|
11897
|
+
import chalk125 from "chalk";
|
|
11752
11898
|
|
|
11753
11899
|
// src/commands/ravendb/selectOpSecret.ts
|
|
11754
|
-
import
|
|
11900
|
+
import chalk124 from "chalk";
|
|
11755
11901
|
import Enquirer2 from "enquirer";
|
|
11756
11902
|
|
|
11757
11903
|
// src/commands/ravendb/searchItems.ts
|
|
11758
|
-
import { execSync as
|
|
11759
|
-
import
|
|
11904
|
+
import { execSync as execSync41 } from "child_process";
|
|
11905
|
+
import chalk123 from "chalk";
|
|
11760
11906
|
function opExec(args) {
|
|
11761
|
-
return
|
|
11907
|
+
return execSync41(`op ${args}`, {
|
|
11762
11908
|
encoding: "utf-8",
|
|
11763
11909
|
stdio: ["pipe", "pipe", "pipe"]
|
|
11764
11910
|
}).trim();
|
|
@@ -11769,7 +11915,7 @@ function searchItems(search2) {
|
|
|
11769
11915
|
items2 = JSON.parse(opExec("item list --format=json"));
|
|
11770
11916
|
} catch {
|
|
11771
11917
|
console.error(
|
|
11772
|
-
|
|
11918
|
+
chalk123.red(
|
|
11773
11919
|
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
11774
11920
|
)
|
|
11775
11921
|
);
|
|
@@ -11783,7 +11929,7 @@ function getItemFields(itemId) {
|
|
|
11783
11929
|
const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
|
|
11784
11930
|
return item.fields.filter((f) => f.reference && f.label);
|
|
11785
11931
|
} catch {
|
|
11786
|
-
console.error(
|
|
11932
|
+
console.error(chalk123.red("Failed to get item details from 1Password."));
|
|
11787
11933
|
process.exit(1);
|
|
11788
11934
|
}
|
|
11789
11935
|
}
|
|
@@ -11802,7 +11948,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
11802
11948
|
}).run();
|
|
11803
11949
|
const items2 = searchItems(search2);
|
|
11804
11950
|
if (items2.length === 0) {
|
|
11805
|
-
console.error(
|
|
11951
|
+
console.error(chalk124.red(`No items found matching "${search2}".`));
|
|
11806
11952
|
process.exit(1);
|
|
11807
11953
|
}
|
|
11808
11954
|
const itemId = await selectOne(
|
|
@@ -11811,7 +11957,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
11811
11957
|
);
|
|
11812
11958
|
const fields = getItemFields(itemId);
|
|
11813
11959
|
if (fields.length === 0) {
|
|
11814
|
-
console.error(
|
|
11960
|
+
console.error(chalk124.red("No fields with references found on this item."));
|
|
11815
11961
|
process.exit(1);
|
|
11816
11962
|
}
|
|
11817
11963
|
const ref = await selectOne(
|
|
@@ -11825,7 +11971,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
11825
11971
|
async function promptConnection(existingNames) {
|
|
11826
11972
|
const name = await promptInput("name", "Connection name:");
|
|
11827
11973
|
if (existingNames.includes(name)) {
|
|
11828
|
-
console.error(
|
|
11974
|
+
console.error(chalk125.red(`Connection "${name}" already exists.`));
|
|
11829
11975
|
process.exit(1);
|
|
11830
11976
|
}
|
|
11831
11977
|
const url = await promptInput(
|
|
@@ -11834,22 +11980,22 @@ async function promptConnection(existingNames) {
|
|
|
11834
11980
|
);
|
|
11835
11981
|
const database = await promptInput("database", "Database name:");
|
|
11836
11982
|
if (!name || !url || !database) {
|
|
11837
|
-
console.error(
|
|
11983
|
+
console.error(chalk125.red("All fields are required."));
|
|
11838
11984
|
process.exit(1);
|
|
11839
11985
|
}
|
|
11840
11986
|
const apiKeyRef = await selectOpSecret();
|
|
11841
|
-
console.log(
|
|
11987
|
+
console.log(chalk125.dim(`Using: ${apiKeyRef}`));
|
|
11842
11988
|
return { name, url, database, apiKeyRef };
|
|
11843
11989
|
}
|
|
11844
11990
|
|
|
11845
11991
|
// src/commands/ravendb/ravendbSetConnection.ts
|
|
11846
|
-
import
|
|
11992
|
+
import chalk126 from "chalk";
|
|
11847
11993
|
function ravendbSetConnection(name) {
|
|
11848
11994
|
const raw = loadGlobalConfigRaw();
|
|
11849
11995
|
const ravendb = raw.ravendb ?? {};
|
|
11850
11996
|
const connections = ravendb.connections ?? [];
|
|
11851
11997
|
if (!connections.some((c) => c.name === name)) {
|
|
11852
|
-
console.error(
|
|
11998
|
+
console.error(chalk126.red(`Connection "${name}" not found.`));
|
|
11853
11999
|
console.error(
|
|
11854
12000
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
11855
12001
|
);
|
|
@@ -11865,16 +12011,16 @@ function ravendbSetConnection(name) {
|
|
|
11865
12011
|
var ravendbAuth = createConnectionAuth({
|
|
11866
12012
|
load: loadConnections,
|
|
11867
12013
|
save: saveConnections,
|
|
11868
|
-
format: (c) => `${
|
|
12014
|
+
format: (c) => `${chalk127.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
|
|
11869
12015
|
promptNew: promptConnection,
|
|
11870
12016
|
onFirst: (c) => ravendbSetConnection(c.name)
|
|
11871
12017
|
});
|
|
11872
12018
|
|
|
11873
12019
|
// src/commands/ravendb/ravendbCollections.ts
|
|
11874
|
-
import
|
|
12020
|
+
import chalk131 from "chalk";
|
|
11875
12021
|
|
|
11876
12022
|
// src/commands/ravendb/ravenFetch.ts
|
|
11877
|
-
import
|
|
12023
|
+
import chalk129 from "chalk";
|
|
11878
12024
|
|
|
11879
12025
|
// src/commands/ravendb/getAccessToken.ts
|
|
11880
12026
|
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
@@ -11910,21 +12056,21 @@ ${errorText}`
|
|
|
11910
12056
|
}
|
|
11911
12057
|
|
|
11912
12058
|
// src/commands/ravendb/resolveOpSecret.ts
|
|
11913
|
-
import { execSync as
|
|
11914
|
-
import
|
|
12059
|
+
import { execSync as execSync42 } from "child_process";
|
|
12060
|
+
import chalk128 from "chalk";
|
|
11915
12061
|
function resolveOpSecret(reference) {
|
|
11916
12062
|
if (!reference.startsWith("op://")) {
|
|
11917
|
-
console.error(
|
|
12063
|
+
console.error(chalk128.red(`Invalid secret reference: must start with op://`));
|
|
11918
12064
|
process.exit(1);
|
|
11919
12065
|
}
|
|
11920
12066
|
try {
|
|
11921
|
-
return
|
|
12067
|
+
return execSync42(`op read "${reference}"`, {
|
|
11922
12068
|
encoding: "utf-8",
|
|
11923
12069
|
stdio: ["pipe", "pipe", "pipe"]
|
|
11924
12070
|
}).trim();
|
|
11925
12071
|
} catch {
|
|
11926
12072
|
console.error(
|
|
11927
|
-
|
|
12073
|
+
chalk128.red(
|
|
11928
12074
|
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
11929
12075
|
)
|
|
11930
12076
|
);
|
|
@@ -11951,7 +12097,7 @@ async function ravenFetch(connection, path54) {
|
|
|
11951
12097
|
if (!response.ok) {
|
|
11952
12098
|
const body = await response.text();
|
|
11953
12099
|
console.error(
|
|
11954
|
-
|
|
12100
|
+
chalk129.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
11955
12101
|
);
|
|
11956
12102
|
console.error(body.substring(0, 500));
|
|
11957
12103
|
process.exit(1);
|
|
@@ -11960,7 +12106,7 @@ async function ravenFetch(connection, path54) {
|
|
|
11960
12106
|
}
|
|
11961
12107
|
|
|
11962
12108
|
// src/commands/ravendb/resolveConnection.ts
|
|
11963
|
-
import
|
|
12109
|
+
import chalk130 from "chalk";
|
|
11964
12110
|
function loadRavendb() {
|
|
11965
12111
|
const raw = loadGlobalConfigRaw();
|
|
11966
12112
|
const ravendb = raw.ravendb;
|
|
@@ -11974,7 +12120,7 @@ function resolveConnection(name) {
|
|
|
11974
12120
|
const connectionName = name ?? defaultConnection;
|
|
11975
12121
|
if (!connectionName) {
|
|
11976
12122
|
console.error(
|
|
11977
|
-
|
|
12123
|
+
chalk130.red(
|
|
11978
12124
|
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
11979
12125
|
)
|
|
11980
12126
|
);
|
|
@@ -11982,7 +12128,7 @@ function resolveConnection(name) {
|
|
|
11982
12128
|
}
|
|
11983
12129
|
const connection = connections.find((c) => c.name === connectionName);
|
|
11984
12130
|
if (!connection) {
|
|
11985
|
-
console.error(
|
|
12131
|
+
console.error(chalk130.red(`Connection "${connectionName}" not found.`));
|
|
11986
12132
|
console.error(
|
|
11987
12133
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
11988
12134
|
);
|
|
@@ -12013,15 +12159,15 @@ async function ravendbCollections(connectionName) {
|
|
|
12013
12159
|
return;
|
|
12014
12160
|
}
|
|
12015
12161
|
for (const c of collections) {
|
|
12016
|
-
console.log(`${
|
|
12162
|
+
console.log(`${chalk131.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
12017
12163
|
}
|
|
12018
12164
|
}
|
|
12019
12165
|
|
|
12020
12166
|
// src/commands/ravendb/ravendbQuery.ts
|
|
12021
|
-
import
|
|
12167
|
+
import chalk133 from "chalk";
|
|
12022
12168
|
|
|
12023
12169
|
// src/commands/ravendb/fetchAllPages.ts
|
|
12024
|
-
import
|
|
12170
|
+
import chalk132 from "chalk";
|
|
12025
12171
|
|
|
12026
12172
|
// src/commands/ravendb/buildQueryPath.ts
|
|
12027
12173
|
function buildQueryPath(opts) {
|
|
@@ -12059,7 +12205,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
12059
12205
|
allResults.push(...results);
|
|
12060
12206
|
start3 += results.length;
|
|
12061
12207
|
process.stderr.write(
|
|
12062
|
-
`\r${
|
|
12208
|
+
`\r${chalk132.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
12063
12209
|
);
|
|
12064
12210
|
if (start3 >= totalResults) break;
|
|
12065
12211
|
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
@@ -12074,7 +12220,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
12074
12220
|
async function ravendbQuery(connectionName, collection, options2) {
|
|
12075
12221
|
const resolved = resolveArgs(connectionName, collection);
|
|
12076
12222
|
if (!resolved.collection && !options2.query) {
|
|
12077
|
-
console.error(
|
|
12223
|
+
console.error(chalk133.red("Provide a collection name or --query filter."));
|
|
12078
12224
|
process.exit(1);
|
|
12079
12225
|
}
|
|
12080
12226
|
const { collection: col } = resolved;
|
|
@@ -12112,7 +12258,7 @@ import { spawn as spawn5 } from "child_process";
|
|
|
12112
12258
|
import * as path26 from "path";
|
|
12113
12259
|
|
|
12114
12260
|
// src/commands/refactor/logViolations.ts
|
|
12115
|
-
import
|
|
12261
|
+
import chalk134 from "chalk";
|
|
12116
12262
|
var DEFAULT_MAX_LINES = 100;
|
|
12117
12263
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
12118
12264
|
if (violations.length === 0) {
|
|
@@ -12121,43 +12267,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
12121
12267
|
}
|
|
12122
12268
|
return;
|
|
12123
12269
|
}
|
|
12124
|
-
console.error(
|
|
12270
|
+
console.error(chalk134.red(`
|
|
12125
12271
|
Refactor check failed:
|
|
12126
12272
|
`));
|
|
12127
|
-
console.error(
|
|
12273
|
+
console.error(chalk134.red(` The following files exceed ${maxLines} lines:
|
|
12128
12274
|
`));
|
|
12129
12275
|
for (const violation of violations) {
|
|
12130
|
-
console.error(
|
|
12276
|
+
console.error(chalk134.red(` ${violation.file} (${violation.lines} lines)`));
|
|
12131
12277
|
}
|
|
12132
12278
|
console.error(
|
|
12133
|
-
|
|
12279
|
+
chalk134.yellow(
|
|
12134
12280
|
`
|
|
12135
12281
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
12136
12282
|
way to refactor it, ignore it with:
|
|
12137
12283
|
`
|
|
12138
12284
|
)
|
|
12139
12285
|
);
|
|
12140
|
-
console.error(
|
|
12286
|
+
console.error(chalk134.gray(` assist refactor ignore <file>
|
|
12141
12287
|
`));
|
|
12142
12288
|
if (process.env.CLAUDECODE) {
|
|
12143
|
-
console.error(
|
|
12289
|
+
console.error(chalk134.cyan(`
|
|
12144
12290
|
## Extracting Code to New Files
|
|
12145
12291
|
`));
|
|
12146
12292
|
console.error(
|
|
12147
|
-
|
|
12293
|
+
chalk134.cyan(
|
|
12148
12294
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
12149
12295
|
`
|
|
12150
12296
|
)
|
|
12151
12297
|
);
|
|
12152
12298
|
console.error(
|
|
12153
|
-
|
|
12299
|
+
chalk134.cyan(
|
|
12154
12300
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
12155
12301
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
12156
12302
|
`
|
|
12157
12303
|
)
|
|
12158
12304
|
);
|
|
12159
12305
|
console.error(
|
|
12160
|
-
|
|
12306
|
+
chalk134.cyan(
|
|
12161
12307
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
12162
12308
|
domains, move it to a common/shared folder.
|
|
12163
12309
|
`
|
|
@@ -12167,7 +12313,7 @@ Refactor check failed:
|
|
|
12167
12313
|
}
|
|
12168
12314
|
|
|
12169
12315
|
// src/commands/refactor/check/getViolations/index.ts
|
|
12170
|
-
import { execSync as
|
|
12316
|
+
import { execSync as execSync43 } from "child_process";
|
|
12171
12317
|
import fs18 from "fs";
|
|
12172
12318
|
import { minimatch as minimatch5 } from "minimatch";
|
|
12173
12319
|
|
|
@@ -12217,7 +12363,7 @@ function getGitFiles(options2) {
|
|
|
12217
12363
|
}
|
|
12218
12364
|
const files = /* @__PURE__ */ new Set();
|
|
12219
12365
|
if (options2.staged || options2.modified) {
|
|
12220
|
-
const staged =
|
|
12366
|
+
const staged = execSync43("git diff --cached --name-only", {
|
|
12221
12367
|
encoding: "utf-8"
|
|
12222
12368
|
});
|
|
12223
12369
|
for (const file of staged.trim().split("\n").filter(Boolean)) {
|
|
@@ -12225,7 +12371,7 @@ function getGitFiles(options2) {
|
|
|
12225
12371
|
}
|
|
12226
12372
|
}
|
|
12227
12373
|
if (options2.unstaged || options2.modified) {
|
|
12228
|
-
const unstaged =
|
|
12374
|
+
const unstaged = execSync43("git diff --name-only", { encoding: "utf-8" });
|
|
12229
12375
|
for (const file of unstaged.trim().split("\n").filter(Boolean)) {
|
|
12230
12376
|
files.add(file);
|
|
12231
12377
|
}
|
|
@@ -12313,7 +12459,7 @@ async function check(pattern2, options2) {
|
|
|
12313
12459
|
|
|
12314
12460
|
// src/commands/refactor/extract/index.ts
|
|
12315
12461
|
import path33 from "path";
|
|
12316
|
-
import
|
|
12462
|
+
import chalk137 from "chalk";
|
|
12317
12463
|
|
|
12318
12464
|
// src/commands/refactor/extract/applyExtraction.ts
|
|
12319
12465
|
import { SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
@@ -12888,23 +13034,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
|
|
|
12888
13034
|
|
|
12889
13035
|
// src/commands/refactor/extract/displayPlan.ts
|
|
12890
13036
|
import path30 from "path";
|
|
12891
|
-
import
|
|
13037
|
+
import chalk135 from "chalk";
|
|
12892
13038
|
function section(title) {
|
|
12893
13039
|
return `
|
|
12894
|
-
${
|
|
13040
|
+
${chalk135.cyan(title)}`;
|
|
12895
13041
|
}
|
|
12896
13042
|
function displayImporters(plan2, cwd) {
|
|
12897
13043
|
if (plan2.importersToUpdate.length === 0) return;
|
|
12898
13044
|
console.log(section("Update importers:"));
|
|
12899
13045
|
for (const imp of plan2.importersToUpdate) {
|
|
12900
13046
|
const rel = path30.relative(cwd, imp.file.getFilePath());
|
|
12901
|
-
console.log(` ${
|
|
13047
|
+
console.log(` ${chalk135.dim(rel)}: \u2192 import from "${imp.relPath}"`);
|
|
12902
13048
|
}
|
|
12903
13049
|
}
|
|
12904
13050
|
function displayPlan(functionName, relDest, plan2, cwd) {
|
|
12905
|
-
console.log(
|
|
13051
|
+
console.log(chalk135.bold(`Extract: ${functionName} \u2192 ${relDest}
|
|
12906
13052
|
`));
|
|
12907
|
-
console.log(` ${
|
|
13053
|
+
console.log(` ${chalk135.cyan("Functions to move:")}`);
|
|
12908
13054
|
for (const name of plan2.extractedNames) {
|
|
12909
13055
|
console.log(` ${name}`);
|
|
12910
13056
|
}
|
|
@@ -12938,7 +13084,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
|
|
|
12938
13084
|
|
|
12939
13085
|
// src/commands/refactor/extract/loadProjectFile.ts
|
|
12940
13086
|
import path32 from "path";
|
|
12941
|
-
import
|
|
13087
|
+
import chalk136 from "chalk";
|
|
12942
13088
|
import { Project as Project4 } from "ts-morph";
|
|
12943
13089
|
|
|
12944
13090
|
// src/commands/refactor/extract/findTsConfig.ts
|
|
@@ -12998,7 +13144,7 @@ function loadProjectFile(file) {
|
|
|
12998
13144
|
});
|
|
12999
13145
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
13000
13146
|
if (!sourceFile) {
|
|
13001
|
-
console.log(
|
|
13147
|
+
console.log(chalk136.red(`File not found in project: ${file}`));
|
|
13002
13148
|
process.exit(1);
|
|
13003
13149
|
}
|
|
13004
13150
|
return { project, sourceFile };
|
|
@@ -13021,19 +13167,19 @@ async function extract(file, functionName, destination, options2 = {}) {
|
|
|
13021
13167
|
displayPlan(functionName, relDest, plan2, cwd);
|
|
13022
13168
|
if (options2.apply) {
|
|
13023
13169
|
await applyExtraction(functionName, sourceFile, destPath, plan2, project);
|
|
13024
|
-
console.log(
|
|
13170
|
+
console.log(chalk137.green("\nExtraction complete"));
|
|
13025
13171
|
} else {
|
|
13026
|
-
console.log(
|
|
13172
|
+
console.log(chalk137.dim("\nDry run. Use --apply to execute."));
|
|
13027
13173
|
}
|
|
13028
13174
|
}
|
|
13029
13175
|
|
|
13030
13176
|
// src/commands/refactor/ignore.ts
|
|
13031
13177
|
import fs20 from "fs";
|
|
13032
|
-
import
|
|
13178
|
+
import chalk138 from "chalk";
|
|
13033
13179
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
13034
13180
|
function ignore(file) {
|
|
13035
13181
|
if (!fs20.existsSync(file)) {
|
|
13036
|
-
console.error(
|
|
13182
|
+
console.error(chalk138.red(`Error: File does not exist: ${file}`));
|
|
13037
13183
|
process.exit(1);
|
|
13038
13184
|
}
|
|
13039
13185
|
const content = fs20.readFileSync(file, "utf-8");
|
|
@@ -13049,7 +13195,7 @@ function ignore(file) {
|
|
|
13049
13195
|
fs20.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
13050
13196
|
}
|
|
13051
13197
|
console.log(
|
|
13052
|
-
|
|
13198
|
+
chalk138.green(
|
|
13053
13199
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
13054
13200
|
)
|
|
13055
13201
|
);
|
|
@@ -13057,25 +13203,25 @@ function ignore(file) {
|
|
|
13057
13203
|
|
|
13058
13204
|
// src/commands/refactor/rename/index.ts
|
|
13059
13205
|
import path34 from "path";
|
|
13060
|
-
import
|
|
13206
|
+
import chalk139 from "chalk";
|
|
13061
13207
|
async function rename(source, destination, options2 = {}) {
|
|
13062
13208
|
const destPath = path34.resolve(destination);
|
|
13063
13209
|
const cwd = process.cwd();
|
|
13064
13210
|
const relSource = path34.relative(cwd, path34.resolve(source));
|
|
13065
13211
|
const relDest = path34.relative(cwd, destPath);
|
|
13066
13212
|
const { project, sourceFile } = loadProjectFile(source);
|
|
13067
|
-
console.log(
|
|
13213
|
+
console.log(chalk139.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
13068
13214
|
if (options2.apply) {
|
|
13069
13215
|
sourceFile.move(destPath);
|
|
13070
13216
|
await project.save();
|
|
13071
|
-
console.log(
|
|
13217
|
+
console.log(chalk139.green("Done"));
|
|
13072
13218
|
} else {
|
|
13073
|
-
console.log(
|
|
13219
|
+
console.log(chalk139.dim("Dry run. Use --apply to execute."));
|
|
13074
13220
|
}
|
|
13075
13221
|
}
|
|
13076
13222
|
|
|
13077
13223
|
// src/commands/refactor/renameSymbol/index.ts
|
|
13078
|
-
import
|
|
13224
|
+
import chalk140 from "chalk";
|
|
13079
13225
|
|
|
13080
13226
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
13081
13227
|
import { SyntaxKind as SyntaxKind14 } from "ts-morph";
|
|
@@ -13121,33 +13267,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
|
13121
13267
|
const { project, sourceFile } = loadProjectFile(file);
|
|
13122
13268
|
const symbol = findSymbol(sourceFile, oldName);
|
|
13123
13269
|
if (!symbol) {
|
|
13124
|
-
console.log(
|
|
13270
|
+
console.log(chalk140.red(`Symbol "${oldName}" not found in ${file}`));
|
|
13125
13271
|
process.exit(1);
|
|
13126
13272
|
}
|
|
13127
13273
|
const grouped = groupReferences(symbol, cwd);
|
|
13128
13274
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
13129
13275
|
console.log(
|
|
13130
|
-
|
|
13276
|
+
chalk140.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
13131
13277
|
`)
|
|
13132
13278
|
);
|
|
13133
13279
|
for (const [refFile, lines] of grouped) {
|
|
13134
13280
|
console.log(
|
|
13135
|
-
` ${
|
|
13281
|
+
` ${chalk140.dim(refFile)}: lines ${chalk140.cyan(lines.join(", "))}`
|
|
13136
13282
|
);
|
|
13137
13283
|
}
|
|
13138
13284
|
if (options2.apply) {
|
|
13139
13285
|
symbol.rename(newName);
|
|
13140
13286
|
await project.save();
|
|
13141
|
-
console.log(
|
|
13287
|
+
console.log(chalk140.green(`
|
|
13142
13288
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
13143
13289
|
} else {
|
|
13144
|
-
console.log(
|
|
13290
|
+
console.log(chalk140.dim("\nDry run. Use --apply to execute."));
|
|
13145
13291
|
}
|
|
13146
13292
|
}
|
|
13147
13293
|
|
|
13148
13294
|
// src/commands/refactor/restructure/index.ts
|
|
13149
13295
|
import path44 from "path";
|
|
13150
|
-
import
|
|
13296
|
+
import chalk143 from "chalk";
|
|
13151
13297
|
|
|
13152
13298
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
13153
13299
|
import path36 from "path";
|
|
@@ -13390,50 +13536,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
13390
13536
|
|
|
13391
13537
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
13392
13538
|
import path40 from "path";
|
|
13393
|
-
import
|
|
13539
|
+
import chalk141 from "chalk";
|
|
13394
13540
|
function relPath(filePath) {
|
|
13395
13541
|
return path40.relative(process.cwd(), filePath);
|
|
13396
13542
|
}
|
|
13397
13543
|
function displayMoves(plan2) {
|
|
13398
13544
|
if (plan2.moves.length === 0) return;
|
|
13399
|
-
console.log(
|
|
13545
|
+
console.log(chalk141.bold("\nFile moves:"));
|
|
13400
13546
|
for (const move of plan2.moves) {
|
|
13401
13547
|
console.log(
|
|
13402
|
-
` ${
|
|
13548
|
+
` ${chalk141.red(relPath(move.from))} \u2192 ${chalk141.green(relPath(move.to))}`
|
|
13403
13549
|
);
|
|
13404
|
-
console.log(
|
|
13550
|
+
console.log(chalk141.dim(` ${move.reason}`));
|
|
13405
13551
|
}
|
|
13406
13552
|
}
|
|
13407
13553
|
function displayRewrites(rewrites) {
|
|
13408
13554
|
if (rewrites.length === 0) return;
|
|
13409
13555
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
13410
|
-
console.log(
|
|
13556
|
+
console.log(chalk141.bold(`
|
|
13411
13557
|
Import rewrites (${affectedFiles.size} files):`));
|
|
13412
13558
|
for (const file of affectedFiles) {
|
|
13413
|
-
console.log(` ${
|
|
13559
|
+
console.log(` ${chalk141.cyan(relPath(file))}:`);
|
|
13414
13560
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
13415
13561
|
(r) => r.file === file
|
|
13416
13562
|
)) {
|
|
13417
13563
|
console.log(
|
|
13418
|
-
` ${
|
|
13564
|
+
` ${chalk141.red(`"${oldSpecifier}"`)} \u2192 ${chalk141.green(`"${newSpecifier}"`)}`
|
|
13419
13565
|
);
|
|
13420
13566
|
}
|
|
13421
13567
|
}
|
|
13422
13568
|
}
|
|
13423
13569
|
function displayPlan2(plan2) {
|
|
13424
13570
|
if (plan2.warnings.length > 0) {
|
|
13425
|
-
console.log(
|
|
13426
|
-
for (const w of plan2.warnings) console.log(
|
|
13571
|
+
console.log(chalk141.yellow("\nWarnings:"));
|
|
13572
|
+
for (const w of plan2.warnings) console.log(chalk141.yellow(` ${w}`));
|
|
13427
13573
|
}
|
|
13428
13574
|
if (plan2.newDirectories.length > 0) {
|
|
13429
|
-
console.log(
|
|
13575
|
+
console.log(chalk141.bold("\nNew directories:"));
|
|
13430
13576
|
for (const dir of plan2.newDirectories)
|
|
13431
|
-
console.log(
|
|
13577
|
+
console.log(chalk141.green(` ${dir}/`));
|
|
13432
13578
|
}
|
|
13433
13579
|
displayMoves(plan2);
|
|
13434
13580
|
displayRewrites(plan2.rewrites);
|
|
13435
13581
|
console.log(
|
|
13436
|
-
|
|
13582
|
+
chalk141.dim(
|
|
13437
13583
|
`
|
|
13438
13584
|
Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
|
|
13439
13585
|
)
|
|
@@ -13443,18 +13589,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
|
|
|
13443
13589
|
// src/commands/refactor/restructure/executePlan.ts
|
|
13444
13590
|
import fs22 from "fs";
|
|
13445
13591
|
import path41 from "path";
|
|
13446
|
-
import
|
|
13592
|
+
import chalk142 from "chalk";
|
|
13447
13593
|
function executePlan(plan2) {
|
|
13448
13594
|
const updatedContents = applyRewrites(plan2.rewrites);
|
|
13449
13595
|
for (const [file, content] of updatedContents) {
|
|
13450
13596
|
fs22.writeFileSync(file, content, "utf-8");
|
|
13451
13597
|
console.log(
|
|
13452
|
-
|
|
13598
|
+
chalk142.cyan(` Rewrote imports in ${path41.relative(process.cwd(), file)}`)
|
|
13453
13599
|
);
|
|
13454
13600
|
}
|
|
13455
13601
|
for (const dir of plan2.newDirectories) {
|
|
13456
13602
|
fs22.mkdirSync(dir, { recursive: true });
|
|
13457
|
-
console.log(
|
|
13603
|
+
console.log(chalk142.green(` Created ${path41.relative(process.cwd(), dir)}/`));
|
|
13458
13604
|
}
|
|
13459
13605
|
for (const move of plan2.moves) {
|
|
13460
13606
|
const targetDir = path41.dirname(move.to);
|
|
@@ -13463,7 +13609,7 @@ function executePlan(plan2) {
|
|
|
13463
13609
|
}
|
|
13464
13610
|
fs22.renameSync(move.from, move.to);
|
|
13465
13611
|
console.log(
|
|
13466
|
-
|
|
13612
|
+
chalk142.white(
|
|
13467
13613
|
` Moved ${path41.relative(process.cwd(), move.from)} \u2192 ${path41.relative(process.cwd(), move.to)}`
|
|
13468
13614
|
)
|
|
13469
13615
|
);
|
|
@@ -13478,7 +13624,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
13478
13624
|
if (entries.length === 0) {
|
|
13479
13625
|
fs22.rmdirSync(dir);
|
|
13480
13626
|
console.log(
|
|
13481
|
-
|
|
13627
|
+
chalk142.dim(
|
|
13482
13628
|
` Removed empty directory ${path41.relative(process.cwd(), dir)}`
|
|
13483
13629
|
)
|
|
13484
13630
|
);
|
|
@@ -13611,22 +13757,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
13611
13757
|
const targetPattern = pattern2 ?? "src";
|
|
13612
13758
|
const files = findSourceFiles2(targetPattern);
|
|
13613
13759
|
if (files.length === 0) {
|
|
13614
|
-
console.log(
|
|
13760
|
+
console.log(chalk143.yellow("No files found matching pattern"));
|
|
13615
13761
|
return;
|
|
13616
13762
|
}
|
|
13617
13763
|
const tsConfigPath = path44.resolve("tsconfig.json");
|
|
13618
13764
|
const plan2 = buildPlan3(files, tsConfigPath);
|
|
13619
13765
|
if (plan2.moves.length === 0) {
|
|
13620
|
-
console.log(
|
|
13766
|
+
console.log(chalk143.green("No restructuring needed"));
|
|
13621
13767
|
return;
|
|
13622
13768
|
}
|
|
13623
13769
|
displayPlan2(plan2);
|
|
13624
13770
|
if (options2.apply) {
|
|
13625
|
-
console.log(
|
|
13771
|
+
console.log(chalk143.bold("\nApplying changes..."));
|
|
13626
13772
|
executePlan(plan2);
|
|
13627
|
-
console.log(
|
|
13773
|
+
console.log(chalk143.green("\nRestructuring complete"));
|
|
13628
13774
|
} else {
|
|
13629
|
-
console.log(
|
|
13775
|
+
console.log(chalk143.dim("\nDry run. Use --apply to execute."));
|
|
13630
13776
|
}
|
|
13631
13777
|
}
|
|
13632
13778
|
|
|
@@ -13801,9 +13947,9 @@ function buildReviewPaths(repoRoot, key) {
|
|
|
13801
13947
|
}
|
|
13802
13948
|
|
|
13803
13949
|
// src/commands/review/fetchExistingComments.ts
|
|
13804
|
-
import { execSync as
|
|
13950
|
+
import { execSync as execSync44 } from "child_process";
|
|
13805
13951
|
function fetchRawComments(org, repo, prNumber) {
|
|
13806
|
-
const out =
|
|
13952
|
+
const out = execSync44(
|
|
13807
13953
|
`gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
|
|
13808
13954
|
{ encoding: "utf-8", maxBuffer: 64 * 1024 * 1024 }
|
|
13809
13955
|
);
|
|
@@ -13834,14 +13980,14 @@ function fetchExistingComments() {
|
|
|
13834
13980
|
}
|
|
13835
13981
|
|
|
13836
13982
|
// src/commands/review/gatherContext.ts
|
|
13837
|
-
import { execSync as
|
|
13983
|
+
import { execSync as execSync47 } from "child_process";
|
|
13838
13984
|
|
|
13839
13985
|
// src/commands/review/fetchPrDiff.ts
|
|
13840
|
-
import { execSync as
|
|
13986
|
+
import { execSync as execSync45 } from "child_process";
|
|
13841
13987
|
function fetchPrDiff(prNumber, baseSha, headSha) {
|
|
13842
13988
|
const { org, repo } = getRepoInfo();
|
|
13843
13989
|
try {
|
|
13844
|
-
return
|
|
13990
|
+
return execSync45(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
|
|
13845
13991
|
encoding: "utf-8",
|
|
13846
13992
|
maxBuffer: 256 * 1024 * 1024,
|
|
13847
13993
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -13856,19 +14002,19 @@ function isDiffTooLarge(error) {
|
|
|
13856
14002
|
}
|
|
13857
14003
|
function fetchDiffViaGit(baseSha, headSha) {
|
|
13858
14004
|
try {
|
|
13859
|
-
|
|
14005
|
+
execSync45(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
|
|
13860
14006
|
} catch {
|
|
13861
14007
|
}
|
|
13862
|
-
return
|
|
14008
|
+
return execSync45(`git diff ${baseSha}...${headSha}`, {
|
|
13863
14009
|
encoding: "utf-8",
|
|
13864
14010
|
maxBuffer: 256 * 1024 * 1024
|
|
13865
14011
|
});
|
|
13866
14012
|
}
|
|
13867
14013
|
|
|
13868
14014
|
// src/commands/review/fetchPrDiffInfo.ts
|
|
13869
|
-
import { execSync as
|
|
14015
|
+
import { execSync as execSync46 } from "child_process";
|
|
13870
14016
|
function getCurrentBranch2() {
|
|
13871
|
-
return
|
|
14017
|
+
return execSync46("git rev-parse --abbrev-ref HEAD", {
|
|
13872
14018
|
encoding: "utf-8"
|
|
13873
14019
|
}).trim();
|
|
13874
14020
|
}
|
|
@@ -13878,7 +14024,7 @@ function fetchPrDiffInfo() {
|
|
|
13878
14024
|
const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
|
|
13879
14025
|
let raw;
|
|
13880
14026
|
try {
|
|
13881
|
-
raw =
|
|
14027
|
+
raw = execSync46(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
|
|
13882
14028
|
encoding: "utf-8",
|
|
13883
14029
|
stdio: ["ignore", "pipe", "pipe"]
|
|
13884
14030
|
});
|
|
@@ -13902,7 +14048,7 @@ function fetchPrDiffInfo() {
|
|
|
13902
14048
|
}
|
|
13903
14049
|
function fetchPrChangedFiles(prNumber) {
|
|
13904
14050
|
const { org, repo } = getRepoInfo();
|
|
13905
|
-
const out =
|
|
14051
|
+
const out = execSync46(
|
|
13906
14052
|
`gh api repos/${org}/${repo}/pulls/${prNumber}/files --paginate --jq ".[].filename"`,
|
|
13907
14053
|
{
|
|
13908
14054
|
encoding: "utf-8",
|
|
@@ -13914,11 +14060,11 @@ function fetchPrChangedFiles(prNumber) {
|
|
|
13914
14060
|
|
|
13915
14061
|
// src/commands/review/gatherContext.ts
|
|
13916
14062
|
function gatherContext() {
|
|
13917
|
-
const branch =
|
|
14063
|
+
const branch = execSync47("git rev-parse --abbrev-ref HEAD", {
|
|
13918
14064
|
encoding: "utf-8"
|
|
13919
14065
|
}).trim();
|
|
13920
|
-
const sha =
|
|
13921
|
-
const shortSha =
|
|
14066
|
+
const sha = execSync47("git rev-parse HEAD", { encoding: "utf-8" }).trim();
|
|
14067
|
+
const shortSha = execSync47("git rev-parse --short=7 HEAD", {
|
|
13922
14068
|
encoding: "utf-8"
|
|
13923
14069
|
}).trim();
|
|
13924
14070
|
const prInfo = fetchPrDiffInfo();
|
|
@@ -14195,18 +14341,18 @@ function partitionFindingsByDiff(findings, index2) {
|
|
|
14195
14341
|
}
|
|
14196
14342
|
|
|
14197
14343
|
// src/commands/review/warnOutOfDiff.ts
|
|
14198
|
-
import
|
|
14344
|
+
import chalk144 from "chalk";
|
|
14199
14345
|
function warnOutOfDiff(outOfDiff) {
|
|
14200
14346
|
if (outOfDiff.length === 0) return;
|
|
14201
14347
|
console.warn(
|
|
14202
|
-
|
|
14348
|
+
chalk144.yellow(
|
|
14203
14349
|
`Skipped ${outOfDiff.length} finding(s) whose lines fall outside the PR diff (GitHub would silently drop these):`
|
|
14204
14350
|
)
|
|
14205
14351
|
);
|
|
14206
14352
|
for (const finding of outOfDiff) {
|
|
14207
14353
|
const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
|
|
14208
14354
|
console.warn(
|
|
14209
|
-
` ${
|
|
14355
|
+
` ${chalk144.yellow("\xB7")} ${finding.title} ${chalk144.dim(
|
|
14210
14356
|
`(${finding.file}:${range})`
|
|
14211
14357
|
)}`
|
|
14212
14358
|
);
|
|
@@ -14225,18 +14371,18 @@ function selectInDiffFindings(lineBound, prDiff) {
|
|
|
14225
14371
|
}
|
|
14226
14372
|
|
|
14227
14373
|
// src/commands/review/warnUnlocated.ts
|
|
14228
|
-
import
|
|
14374
|
+
import chalk145 from "chalk";
|
|
14229
14375
|
function warnUnlocated(unlocated) {
|
|
14230
14376
|
if (unlocated.length === 0) return;
|
|
14231
14377
|
console.warn(
|
|
14232
|
-
|
|
14378
|
+
chalk145.yellow(
|
|
14233
14379
|
`Skipped ${unlocated.length} finding(s) without a parseable file:line:`
|
|
14234
14380
|
)
|
|
14235
14381
|
);
|
|
14236
14382
|
for (const finding of unlocated) {
|
|
14237
|
-
const where = finding.location ||
|
|
14383
|
+
const where = finding.location || chalk145.dim("missing");
|
|
14238
14384
|
console.warn(
|
|
14239
|
-
` ${
|
|
14385
|
+
` ${chalk145.yellow("\xB7")} ${finding.title} ${chalk145.dim(`(${where})`)}`
|
|
14240
14386
|
);
|
|
14241
14387
|
}
|
|
14242
14388
|
}
|
|
@@ -15409,7 +15555,7 @@ function registerReview(program2) {
|
|
|
15409
15555
|
}
|
|
15410
15556
|
|
|
15411
15557
|
// src/commands/seq/seqAuth.ts
|
|
15412
|
-
import
|
|
15558
|
+
import chalk147 from "chalk";
|
|
15413
15559
|
|
|
15414
15560
|
// src/commands/seq/loadConnections.ts
|
|
15415
15561
|
function loadConnections2() {
|
|
@@ -15438,10 +15584,10 @@ function setDefaultConnection(name) {
|
|
|
15438
15584
|
}
|
|
15439
15585
|
|
|
15440
15586
|
// src/shared/assertUniqueName.ts
|
|
15441
|
-
import
|
|
15587
|
+
import chalk146 from "chalk";
|
|
15442
15588
|
function assertUniqueName(existingNames, name) {
|
|
15443
15589
|
if (existingNames.includes(name)) {
|
|
15444
|
-
console.error(
|
|
15590
|
+
console.error(chalk146.red(`Connection "${name}" already exists.`));
|
|
15445
15591
|
process.exit(1);
|
|
15446
15592
|
}
|
|
15447
15593
|
}
|
|
@@ -15459,16 +15605,16 @@ async function promptConnection2(existingNames) {
|
|
|
15459
15605
|
var seqAuth = createConnectionAuth({
|
|
15460
15606
|
load: loadConnections2,
|
|
15461
15607
|
save: saveConnections2,
|
|
15462
|
-
format: (c) => `${
|
|
15608
|
+
format: (c) => `${chalk147.bold(c.name)} ${c.url}`,
|
|
15463
15609
|
promptNew: promptConnection2,
|
|
15464
15610
|
onFirst: (c) => setDefaultConnection(c.name)
|
|
15465
15611
|
});
|
|
15466
15612
|
|
|
15467
15613
|
// src/commands/seq/seqQuery.ts
|
|
15468
|
-
import
|
|
15614
|
+
import chalk151 from "chalk";
|
|
15469
15615
|
|
|
15470
15616
|
// src/commands/seq/fetchSeq.ts
|
|
15471
|
-
import
|
|
15617
|
+
import chalk148 from "chalk";
|
|
15472
15618
|
async function fetchSeq(conn, path54, params) {
|
|
15473
15619
|
const url = `${conn.url}${path54}?${params}`;
|
|
15474
15620
|
const response = await fetch(url, {
|
|
@@ -15479,7 +15625,7 @@ async function fetchSeq(conn, path54, params) {
|
|
|
15479
15625
|
});
|
|
15480
15626
|
if (!response.ok) {
|
|
15481
15627
|
const body = await response.text();
|
|
15482
|
-
console.error(
|
|
15628
|
+
console.error(chalk148.red(`Seq returned ${response.status}: ${body}`));
|
|
15483
15629
|
process.exit(1);
|
|
15484
15630
|
}
|
|
15485
15631
|
return response;
|
|
@@ -15534,23 +15680,23 @@ async function fetchSeqEvents(conn, params) {
|
|
|
15534
15680
|
}
|
|
15535
15681
|
|
|
15536
15682
|
// src/commands/seq/formatEvent.ts
|
|
15537
|
-
import
|
|
15683
|
+
import chalk149 from "chalk";
|
|
15538
15684
|
function levelColor(level) {
|
|
15539
15685
|
switch (level) {
|
|
15540
15686
|
case "Fatal":
|
|
15541
|
-
return
|
|
15687
|
+
return chalk149.bgRed.white;
|
|
15542
15688
|
case "Error":
|
|
15543
|
-
return
|
|
15689
|
+
return chalk149.red;
|
|
15544
15690
|
case "Warning":
|
|
15545
|
-
return
|
|
15691
|
+
return chalk149.yellow;
|
|
15546
15692
|
case "Information":
|
|
15547
|
-
return
|
|
15693
|
+
return chalk149.cyan;
|
|
15548
15694
|
case "Debug":
|
|
15549
|
-
return
|
|
15695
|
+
return chalk149.gray;
|
|
15550
15696
|
case "Verbose":
|
|
15551
|
-
return
|
|
15697
|
+
return chalk149.dim;
|
|
15552
15698
|
default:
|
|
15553
|
-
return
|
|
15699
|
+
return chalk149.white;
|
|
15554
15700
|
}
|
|
15555
15701
|
}
|
|
15556
15702
|
function levelAbbrev(level) {
|
|
@@ -15591,12 +15737,12 @@ function formatTimestamp(iso) {
|
|
|
15591
15737
|
function formatEvent(event) {
|
|
15592
15738
|
const color = levelColor(event.Level);
|
|
15593
15739
|
const abbrev = levelAbbrev(event.Level);
|
|
15594
|
-
const ts8 =
|
|
15740
|
+
const ts8 = chalk149.dim(formatTimestamp(event.Timestamp));
|
|
15595
15741
|
const msg = renderMessage(event);
|
|
15596
15742
|
const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
|
|
15597
15743
|
if (event.Exception) {
|
|
15598
15744
|
for (const line of event.Exception.split("\n")) {
|
|
15599
|
-
lines.push(
|
|
15745
|
+
lines.push(chalk149.red(` ${line}`));
|
|
15600
15746
|
}
|
|
15601
15747
|
}
|
|
15602
15748
|
return lines.join("\n");
|
|
@@ -15629,11 +15775,11 @@ function rejectTimestampFilter(filter) {
|
|
|
15629
15775
|
}
|
|
15630
15776
|
|
|
15631
15777
|
// src/shared/resolveNamedConnection.ts
|
|
15632
|
-
import
|
|
15778
|
+
import chalk150 from "chalk";
|
|
15633
15779
|
function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
|
|
15634
15780
|
if (connections.length === 0) {
|
|
15635
15781
|
console.error(
|
|
15636
|
-
|
|
15782
|
+
chalk150.red(
|
|
15637
15783
|
`No ${kind} connections configured. Run '${authCommand}' first.`
|
|
15638
15784
|
)
|
|
15639
15785
|
);
|
|
@@ -15642,7 +15788,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
|
|
|
15642
15788
|
const target = requested ?? defaultName ?? connections[0].name;
|
|
15643
15789
|
const connection = connections.find((c) => c.name === target);
|
|
15644
15790
|
if (!connection) {
|
|
15645
|
-
console.error(
|
|
15791
|
+
console.error(chalk150.red(`${kind} connection "${target}" not found.`));
|
|
15646
15792
|
process.exit(1);
|
|
15647
15793
|
}
|
|
15648
15794
|
return connection;
|
|
@@ -15671,7 +15817,7 @@ async function seqQuery(filter, options2) {
|
|
|
15671
15817
|
new URLSearchParams({ filter, count: String(count6) })
|
|
15672
15818
|
);
|
|
15673
15819
|
if (events.length === 0) {
|
|
15674
|
-
console.log(
|
|
15820
|
+
console.log(chalk151.yellow("No events found."));
|
|
15675
15821
|
return;
|
|
15676
15822
|
}
|
|
15677
15823
|
if (options2.json) {
|
|
@@ -15682,11 +15828,11 @@ async function seqQuery(filter, options2) {
|
|
|
15682
15828
|
for (const event of chronological) {
|
|
15683
15829
|
console.log(formatEvent(event));
|
|
15684
15830
|
}
|
|
15685
|
-
console.log(
|
|
15831
|
+
console.log(chalk151.dim(`
|
|
15686
15832
|
${events.length} events`));
|
|
15687
15833
|
if (events.length >= count6) {
|
|
15688
15834
|
console.log(
|
|
15689
|
-
|
|
15835
|
+
chalk151.yellow(
|
|
15690
15836
|
`Results limited to ${count6}. Use --count to retrieve more.`
|
|
15691
15837
|
)
|
|
15692
15838
|
);
|
|
@@ -15694,10 +15840,10 @@ ${events.length} events`));
|
|
|
15694
15840
|
}
|
|
15695
15841
|
|
|
15696
15842
|
// src/shared/setNamedDefaultConnection.ts
|
|
15697
|
-
import
|
|
15843
|
+
import chalk152 from "chalk";
|
|
15698
15844
|
function setNamedDefaultConnection(connections, name, setDefault, kind) {
|
|
15699
15845
|
if (!connections.find((c) => c.name === name)) {
|
|
15700
|
-
console.error(
|
|
15846
|
+
console.error(chalk152.red(`Connection "${name}" not found.`));
|
|
15701
15847
|
process.exit(1);
|
|
15702
15848
|
}
|
|
15703
15849
|
setDefault(name);
|
|
@@ -15745,7 +15891,7 @@ function registerSignal(program2) {
|
|
|
15745
15891
|
}
|
|
15746
15892
|
|
|
15747
15893
|
// src/commands/sql/sqlAuth.ts
|
|
15748
|
-
import
|
|
15894
|
+
import chalk154 from "chalk";
|
|
15749
15895
|
|
|
15750
15896
|
// src/commands/sql/loadConnections.ts
|
|
15751
15897
|
function loadConnections3() {
|
|
@@ -15774,7 +15920,7 @@ function setDefaultConnection2(name) {
|
|
|
15774
15920
|
}
|
|
15775
15921
|
|
|
15776
15922
|
// src/commands/sql/promptConnection.ts
|
|
15777
|
-
import
|
|
15923
|
+
import chalk153 from "chalk";
|
|
15778
15924
|
async function promptConnection3(existingNames) {
|
|
15779
15925
|
const name = await promptInput("name", "Connection name:", "default");
|
|
15780
15926
|
assertUniqueName(existingNames, name);
|
|
@@ -15782,7 +15928,7 @@ async function promptConnection3(existingNames) {
|
|
|
15782
15928
|
const portStr = await promptInput("port", "Port:", "1433");
|
|
15783
15929
|
const port = Number.parseInt(portStr, 10);
|
|
15784
15930
|
if (!Number.isFinite(port)) {
|
|
15785
|
-
console.error(
|
|
15931
|
+
console.error(chalk153.red(`Invalid port "${portStr}".`));
|
|
15786
15932
|
process.exit(1);
|
|
15787
15933
|
}
|
|
15788
15934
|
const user = await promptInput("user", "User:");
|
|
@@ -15795,13 +15941,13 @@ async function promptConnection3(existingNames) {
|
|
|
15795
15941
|
var sqlAuth = createConnectionAuth({
|
|
15796
15942
|
load: loadConnections3,
|
|
15797
15943
|
save: saveConnections3,
|
|
15798
|
-
format: (c) => `${
|
|
15944
|
+
format: (c) => `${chalk154.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
|
|
15799
15945
|
promptNew: promptConnection3,
|
|
15800
15946
|
onFirst: (c) => setDefaultConnection2(c.name)
|
|
15801
15947
|
});
|
|
15802
15948
|
|
|
15803
15949
|
// src/commands/sql/printTable.ts
|
|
15804
|
-
import
|
|
15950
|
+
import chalk155 from "chalk";
|
|
15805
15951
|
function formatCell(value) {
|
|
15806
15952
|
if (value === null || value === void 0) return "";
|
|
15807
15953
|
if (value instanceof Date) return value.toISOString();
|
|
@@ -15810,7 +15956,7 @@ function formatCell(value) {
|
|
|
15810
15956
|
}
|
|
15811
15957
|
function printTable(rows) {
|
|
15812
15958
|
if (rows.length === 0) {
|
|
15813
|
-
console.log(
|
|
15959
|
+
console.log(chalk155.yellow("(no rows)"));
|
|
15814
15960
|
return;
|
|
15815
15961
|
}
|
|
15816
15962
|
const columns = Object.keys(rows[0]);
|
|
@@ -15818,13 +15964,13 @@ function printTable(rows) {
|
|
|
15818
15964
|
(col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
|
|
15819
15965
|
);
|
|
15820
15966
|
const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
|
|
15821
|
-
console.log(
|
|
15822
|
-
console.log(
|
|
15967
|
+
console.log(chalk155.dim(header));
|
|
15968
|
+
console.log(chalk155.dim("-".repeat(header.length)));
|
|
15823
15969
|
for (const row of rows) {
|
|
15824
15970
|
const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
|
|
15825
15971
|
console.log(line);
|
|
15826
15972
|
}
|
|
15827
|
-
console.log(
|
|
15973
|
+
console.log(chalk155.dim(`
|
|
15828
15974
|
${rows.length} row${rows.length === 1 ? "" : "s"}`));
|
|
15829
15975
|
}
|
|
15830
15976
|
|
|
@@ -15884,7 +16030,7 @@ async function sqlColumns(table, connectionName) {
|
|
|
15884
16030
|
}
|
|
15885
16031
|
|
|
15886
16032
|
// src/commands/sql/sqlMutate.ts
|
|
15887
|
-
import
|
|
16033
|
+
import chalk156 from "chalk";
|
|
15888
16034
|
|
|
15889
16035
|
// src/commands/sql/isMutation.ts
|
|
15890
16036
|
var MUTATION_KEYWORDS = [
|
|
@@ -15918,7 +16064,7 @@ function isMutation(sql4) {
|
|
|
15918
16064
|
async function sqlMutate(query, connectionName) {
|
|
15919
16065
|
if (!isMutation(query)) {
|
|
15920
16066
|
console.error(
|
|
15921
|
-
|
|
16067
|
+
chalk156.red(
|
|
15922
16068
|
"assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
|
|
15923
16069
|
)
|
|
15924
16070
|
);
|
|
@@ -15928,18 +16074,18 @@ async function sqlMutate(query, connectionName) {
|
|
|
15928
16074
|
const pool = await sqlConnect(conn);
|
|
15929
16075
|
try {
|
|
15930
16076
|
const result = await pool.request().query(query);
|
|
15931
|
-
console.log(
|
|
16077
|
+
console.log(chalk156.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
|
|
15932
16078
|
} finally {
|
|
15933
16079
|
await pool.close();
|
|
15934
16080
|
}
|
|
15935
16081
|
}
|
|
15936
16082
|
|
|
15937
16083
|
// src/commands/sql/sqlQuery.ts
|
|
15938
|
-
import
|
|
16084
|
+
import chalk157 from "chalk";
|
|
15939
16085
|
async function sqlQuery(query, connectionName) {
|
|
15940
16086
|
if (isMutation(query)) {
|
|
15941
16087
|
console.error(
|
|
15942
|
-
|
|
16088
|
+
chalk157.red(
|
|
15943
16089
|
"assist sql query refuses mutating statements. Use `assist sql mutate` instead."
|
|
15944
16090
|
)
|
|
15945
16091
|
);
|
|
@@ -15954,7 +16100,7 @@ async function sqlQuery(query, connectionName) {
|
|
|
15954
16100
|
printTable(rows);
|
|
15955
16101
|
} else {
|
|
15956
16102
|
console.log(
|
|
15957
|
-
|
|
16103
|
+
chalk157.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
|
|
15958
16104
|
);
|
|
15959
16105
|
}
|
|
15960
16106
|
} finally {
|
|
@@ -16534,14 +16680,14 @@ import {
|
|
|
16534
16680
|
import { dirname as dirname22, join as join42 } from "path";
|
|
16535
16681
|
|
|
16536
16682
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
16537
|
-
import
|
|
16683
|
+
import chalk158 from "chalk";
|
|
16538
16684
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
16539
16685
|
function validateStagedContent(filename, content) {
|
|
16540
16686
|
const firstLine = content.split("\n")[0];
|
|
16541
16687
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
16542
16688
|
if (!match) {
|
|
16543
16689
|
console.error(
|
|
16544
|
-
|
|
16690
|
+
chalk158.red(
|
|
16545
16691
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
16546
16692
|
)
|
|
16547
16693
|
);
|
|
@@ -16550,7 +16696,7 @@ function validateStagedContent(filename, content) {
|
|
|
16550
16696
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
16551
16697
|
if (!contentAfterLink) {
|
|
16552
16698
|
console.error(
|
|
16553
|
-
|
|
16699
|
+
chalk158.red(
|
|
16554
16700
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
16555
16701
|
)
|
|
16556
16702
|
);
|
|
@@ -16754,7 +16900,7 @@ import { mkdirSync as mkdirSync18 } from "fs";
|
|
|
16754
16900
|
import { join as join47 } from "path";
|
|
16755
16901
|
|
|
16756
16902
|
// src/commands/voice/checkLockFile.ts
|
|
16757
|
-
import { execSync as
|
|
16903
|
+
import { execSync as execSync48 } from "child_process";
|
|
16758
16904
|
import { existsSync as existsSync45, mkdirSync as mkdirSync17, readFileSync as readFileSync35, writeFileSync as writeFileSync29 } from "fs";
|
|
16759
16905
|
import { join as join46 } from "path";
|
|
16760
16906
|
function isProcessAlive2(pid) {
|
|
@@ -16783,7 +16929,7 @@ function bootstrapVenv() {
|
|
|
16783
16929
|
if (existsSync45(getVenvPython())) return;
|
|
16784
16930
|
console.log("Setting up Python environment...");
|
|
16785
16931
|
const pythonDir = getPythonDir();
|
|
16786
|
-
|
|
16932
|
+
execSync48(
|
|
16787
16933
|
`uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
|
|
16788
16934
|
{
|
|
16789
16935
|
stdio: "inherit",
|
|
@@ -16947,7 +17093,7 @@ function registerVoice(program2) {
|
|
|
16947
17093
|
|
|
16948
17094
|
// src/commands/roam/auth.ts
|
|
16949
17095
|
import { randomBytes } from "crypto";
|
|
16950
|
-
import
|
|
17096
|
+
import chalk159 from "chalk";
|
|
16951
17097
|
|
|
16952
17098
|
// src/commands/roam/waitForCallback.ts
|
|
16953
17099
|
import { createServer as createServer2 } from "http";
|
|
@@ -17078,13 +17224,13 @@ async function auth() {
|
|
|
17078
17224
|
saveGlobalConfig(config);
|
|
17079
17225
|
const state = randomBytes(16).toString("hex");
|
|
17080
17226
|
console.log(
|
|
17081
|
-
|
|
17227
|
+
chalk159.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
17082
17228
|
);
|
|
17083
|
-
console.log(
|
|
17084
|
-
console.log(
|
|
17085
|
-
console.log(
|
|
17229
|
+
console.log(chalk159.white("http://localhost:14523/callback\n"));
|
|
17230
|
+
console.log(chalk159.blue("Opening browser for authorization..."));
|
|
17231
|
+
console.log(chalk159.dim("Waiting for authorization callback..."));
|
|
17086
17232
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
17087
|
-
console.log(
|
|
17233
|
+
console.log(chalk159.dim("Exchanging code for tokens..."));
|
|
17088
17234
|
const tokens = await exchangeToken({
|
|
17089
17235
|
code,
|
|
17090
17236
|
clientId,
|
|
@@ -17100,7 +17246,7 @@ async function auth() {
|
|
|
17100
17246
|
};
|
|
17101
17247
|
saveGlobalConfig(config);
|
|
17102
17248
|
console.log(
|
|
17103
|
-
|
|
17249
|
+
chalk159.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
17104
17250
|
);
|
|
17105
17251
|
}
|
|
17106
17252
|
|
|
@@ -17260,11 +17406,11 @@ function resolveParams(params, cliArgs) {
|
|
|
17260
17406
|
}
|
|
17261
17407
|
|
|
17262
17408
|
// src/commands/run/runPreCommands.ts
|
|
17263
|
-
import { execSync as
|
|
17409
|
+
import { execSync as execSync49 } from "child_process";
|
|
17264
17410
|
function runPreCommands(pre, cwd) {
|
|
17265
17411
|
for (const cmd of pre) {
|
|
17266
17412
|
try {
|
|
17267
|
-
|
|
17413
|
+
execSync49(cmd, { stdio: "inherit", cwd });
|
|
17268
17414
|
} catch (err) {
|
|
17269
17415
|
const code = err && typeof err === "object" && "status" in err ? err.status : 1;
|
|
17270
17416
|
process.exit(code);
|
|
@@ -17548,11 +17694,11 @@ function registerRun(program2) {
|
|
|
17548
17694
|
}
|
|
17549
17695
|
|
|
17550
17696
|
// src/commands/screenshot/index.ts
|
|
17551
|
-
import { execSync as
|
|
17697
|
+
import { execSync as execSync50 } from "child_process";
|
|
17552
17698
|
import { existsSync as existsSync50, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync32 } from "fs";
|
|
17553
17699
|
import { tmpdir as tmpdir7 } from "os";
|
|
17554
17700
|
import { join as join53, resolve as resolve13 } from "path";
|
|
17555
|
-
import
|
|
17701
|
+
import chalk160 from "chalk";
|
|
17556
17702
|
|
|
17557
17703
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
17558
17704
|
var captureWindowPs1 = `
|
|
@@ -17691,7 +17837,7 @@ function runPowerShellScript(processName, outputPath) {
|
|
|
17691
17837
|
const scriptPath = join53(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
17692
17838
|
writeFileSync32(scriptPath, captureWindowPs1, "utf-8");
|
|
17693
17839
|
try {
|
|
17694
|
-
|
|
17840
|
+
execSync50(
|
|
17695
17841
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
17696
17842
|
{ stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
|
|
17697
17843
|
);
|
|
@@ -17703,13 +17849,13 @@ function screenshot(processName) {
|
|
|
17703
17849
|
const config = loadConfig();
|
|
17704
17850
|
const outputDir = resolve13(config.screenshot.outputDir);
|
|
17705
17851
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
17706
|
-
console.log(
|
|
17852
|
+
console.log(chalk160.gray(`Capturing window for process "${processName}" ...`));
|
|
17707
17853
|
try {
|
|
17708
17854
|
runPowerShellScript(processName, outputPath);
|
|
17709
|
-
console.log(
|
|
17855
|
+
console.log(chalk160.green(`Screenshot saved: ${outputPath}`));
|
|
17710
17856
|
} catch (error) {
|
|
17711
17857
|
const msg = error instanceof Error ? error.message : String(error);
|
|
17712
|
-
console.error(
|
|
17858
|
+
console.error(chalk160.red(`Failed to capture screenshot: ${msg}`));
|
|
17713
17859
|
process.exit(1);
|
|
17714
17860
|
}
|
|
17715
17861
|
}
|
|
@@ -18609,8 +18755,8 @@ var SessionManager = class {
|
|
|
18609
18755
|
watchActivity(session, this.notify);
|
|
18610
18756
|
return session.id;
|
|
18611
18757
|
}
|
|
18612
|
-
spawnWith(
|
|
18613
|
-
return this.add(
|
|
18758
|
+
spawnWith(create) {
|
|
18759
|
+
return this.add(create(String(this.nextId++)));
|
|
18614
18760
|
}
|
|
18615
18761
|
spawn(prompt, cwd) {
|
|
18616
18762
|
return this.spawnWith((id) => createSession(id, prompt, cwd));
|
|
@@ -18989,7 +19135,7 @@ function registerDaemon(program2) {
|
|
|
18989
19135
|
|
|
18990
19136
|
// src/commands/sessions/summarise/index.ts
|
|
18991
19137
|
import * as fs31 from "fs";
|
|
18992
|
-
import
|
|
19138
|
+
import chalk161 from "chalk";
|
|
18993
19139
|
|
|
18994
19140
|
// src/commands/sessions/summarise/shared.ts
|
|
18995
19141
|
import * as fs29 from "fs";
|
|
@@ -19116,22 +19262,22 @@ ${firstMessage}`);
|
|
|
19116
19262
|
async function summarise4(options2) {
|
|
19117
19263
|
const files = await discoverSessionJsonlPaths();
|
|
19118
19264
|
if (files.length === 0) {
|
|
19119
|
-
console.log(
|
|
19265
|
+
console.log(chalk161.yellow("No sessions found."));
|
|
19120
19266
|
return;
|
|
19121
19267
|
}
|
|
19122
19268
|
const toProcess = selectCandidates(files, options2);
|
|
19123
19269
|
if (toProcess.length === 0) {
|
|
19124
|
-
console.log(
|
|
19270
|
+
console.log(chalk161.green("All sessions already summarised."));
|
|
19125
19271
|
return;
|
|
19126
19272
|
}
|
|
19127
19273
|
console.log(
|
|
19128
|
-
|
|
19274
|
+
chalk161.cyan(
|
|
19129
19275
|
`Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
|
|
19130
19276
|
)
|
|
19131
19277
|
);
|
|
19132
19278
|
const { succeeded, failed: failed2 } = processSessions(toProcess);
|
|
19133
19279
|
console.log(
|
|
19134
|
-
|
|
19280
|
+
chalk161.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk161.yellow(`, ${failed2} skipped`) : "")
|
|
19135
19281
|
);
|
|
19136
19282
|
}
|
|
19137
19283
|
function selectCandidates(files, options2) {
|
|
@@ -19151,16 +19297,16 @@ function processSessions(files) {
|
|
|
19151
19297
|
let failed2 = 0;
|
|
19152
19298
|
for (let i = 0; i < files.length; i++) {
|
|
19153
19299
|
const file = files[i];
|
|
19154
|
-
process.stdout.write(
|
|
19300
|
+
process.stdout.write(chalk161.dim(` [${i + 1}/${files.length}] `));
|
|
19155
19301
|
const summary = summariseSession(file);
|
|
19156
19302
|
if (summary) {
|
|
19157
19303
|
writeSummary(file, summary);
|
|
19158
19304
|
succeeded++;
|
|
19159
|
-
process.stdout.write(`${
|
|
19305
|
+
process.stdout.write(`${chalk161.green("\u2713")} ${summary}
|
|
19160
19306
|
`);
|
|
19161
19307
|
} else {
|
|
19162
19308
|
failed2++;
|
|
19163
|
-
process.stdout.write(` ${
|
|
19309
|
+
process.stdout.write(` ${chalk161.yellow("skip")}
|
|
19164
19310
|
`);
|
|
19165
19311
|
}
|
|
19166
19312
|
}
|
|
@@ -19175,10 +19321,10 @@ function registerSessions(program2) {
|
|
|
19175
19321
|
}
|
|
19176
19322
|
|
|
19177
19323
|
// src/commands/statusLine.ts
|
|
19178
|
-
import
|
|
19324
|
+
import chalk163 from "chalk";
|
|
19179
19325
|
|
|
19180
19326
|
// src/commands/buildLimitsSegment.ts
|
|
19181
|
-
import
|
|
19327
|
+
import chalk162 from "chalk";
|
|
19182
19328
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
19183
19329
|
var SEVEN_DAY_SECONDS = 7 * 86400;
|
|
19184
19330
|
function formatTimeLeft(resetsAt) {
|
|
@@ -19201,10 +19347,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
|
|
|
19201
19347
|
function colorizeRateLimit(pct, resetsAt, windowSeconds) {
|
|
19202
19348
|
const label2 = `${Math.round(pct)}%`;
|
|
19203
19349
|
const projected = projectUsage(pct, resetsAt, windowSeconds);
|
|
19204
|
-
if (projected == null) return
|
|
19205
|
-
if (projected > 100) return
|
|
19206
|
-
if (projected > 75) return
|
|
19207
|
-
return
|
|
19350
|
+
if (projected == null) return chalk162.green(label2);
|
|
19351
|
+
if (projected > 100) return chalk162.red(label2);
|
|
19352
|
+
if (projected > 75) return chalk162.yellow(label2);
|
|
19353
|
+
return chalk162.green(label2);
|
|
19208
19354
|
}
|
|
19209
19355
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
|
|
19210
19356
|
const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
|
|
@@ -19230,14 +19376,14 @@ function buildLimitsSegment(rateLimits) {
|
|
|
19230
19376
|
}
|
|
19231
19377
|
|
|
19232
19378
|
// src/commands/statusLine.ts
|
|
19233
|
-
|
|
19379
|
+
chalk163.level = 3;
|
|
19234
19380
|
function formatNumber(num) {
|
|
19235
19381
|
return num.toLocaleString("en-US");
|
|
19236
19382
|
}
|
|
19237
19383
|
function colorizePercent(pct) {
|
|
19238
19384
|
const label2 = `${Math.round(pct)}%`;
|
|
19239
|
-
if (pct > 80) return
|
|
19240
|
-
if (pct > 40) return
|
|
19385
|
+
if (pct > 80) return chalk163.red(label2);
|
|
19386
|
+
if (pct > 40) return chalk163.yellow(label2);
|
|
19241
19387
|
return label2;
|
|
19242
19388
|
}
|
|
19243
19389
|
async function statusLine() {
|
|
@@ -19260,7 +19406,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
19260
19406
|
// src/commands/sync/syncClaudeMd.ts
|
|
19261
19407
|
import * as fs32 from "fs";
|
|
19262
19408
|
import * as path50 from "path";
|
|
19263
|
-
import
|
|
19409
|
+
import chalk164 from "chalk";
|
|
19264
19410
|
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
19265
19411
|
const source = path50.join(claudeDir, "CLAUDE.md");
|
|
19266
19412
|
const target = path50.join(targetBase, "CLAUDE.md");
|
|
@@ -19269,12 +19415,12 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
19269
19415
|
const targetContent = fs32.readFileSync(target, "utf-8");
|
|
19270
19416
|
if (sourceContent !== targetContent) {
|
|
19271
19417
|
console.log(
|
|
19272
|
-
|
|
19418
|
+
chalk164.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
19273
19419
|
);
|
|
19274
19420
|
console.log();
|
|
19275
19421
|
printDiff(targetContent, sourceContent);
|
|
19276
19422
|
const confirm = options2?.yes || await promptConfirm(
|
|
19277
|
-
|
|
19423
|
+
chalk164.red("Overwrite existing CLAUDE.md?"),
|
|
19278
19424
|
false
|
|
19279
19425
|
);
|
|
19280
19426
|
if (!confirm) {
|
|
@@ -19290,7 +19436,7 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
19290
19436
|
// src/commands/sync/syncSettings.ts
|
|
19291
19437
|
import * as fs33 from "fs";
|
|
19292
19438
|
import * as path51 from "path";
|
|
19293
|
-
import
|
|
19439
|
+
import chalk165 from "chalk";
|
|
19294
19440
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
19295
19441
|
const source = path51.join(claudeDir, "settings.json");
|
|
19296
19442
|
const target = path51.join(targetBase, "settings.json");
|
|
@@ -19306,14 +19452,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
19306
19452
|
if (mergedContent !== normalizedTarget) {
|
|
19307
19453
|
if (!options2?.yes) {
|
|
19308
19454
|
console.log(
|
|
19309
|
-
|
|
19455
|
+
chalk165.yellow(
|
|
19310
19456
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
19311
19457
|
)
|
|
19312
19458
|
);
|
|
19313
19459
|
console.log();
|
|
19314
19460
|
printDiff(targetContent, mergedContent);
|
|
19315
19461
|
const confirm = await promptConfirm(
|
|
19316
|
-
|
|
19462
|
+
chalk165.red("Overwrite existing settings.json?"),
|
|
19317
19463
|
false
|
|
19318
19464
|
);
|
|
19319
19465
|
if (!confirm) {
|
|
@@ -19352,7 +19498,7 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
19352
19498
|
}
|
|
19353
19499
|
|
|
19354
19500
|
// src/commands/update.ts
|
|
19355
|
-
import { execSync as
|
|
19501
|
+
import { execSync as execSync51 } from "child_process";
|
|
19356
19502
|
import * as path53 from "path";
|
|
19357
19503
|
function isGlobalNpmInstall(dir) {
|
|
19358
19504
|
try {
|
|
@@ -19360,7 +19506,7 @@ function isGlobalNpmInstall(dir) {
|
|
|
19360
19506
|
if (resolved.split(path53.sep).includes("node_modules")) {
|
|
19361
19507
|
return true;
|
|
19362
19508
|
}
|
|
19363
|
-
const globalPrefix =
|
|
19509
|
+
const globalPrefix = execSync51("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
19364
19510
|
return resolved.toLowerCase().startsWith(path53.resolve(globalPrefix).toLowerCase());
|
|
19365
19511
|
} catch {
|
|
19366
19512
|
return false;
|
|
@@ -19371,18 +19517,18 @@ async function update2() {
|
|
|
19371
19517
|
console.log(`Assist is installed at: ${installDir}`);
|
|
19372
19518
|
if (isGitRepo(installDir)) {
|
|
19373
19519
|
console.log("Detected git repo installation, pulling latest...");
|
|
19374
|
-
|
|
19520
|
+
execSync51("git pull", { cwd: installDir, stdio: "inherit" });
|
|
19375
19521
|
console.log("Installing dependencies...");
|
|
19376
|
-
|
|
19522
|
+
execSync51("npm i", { cwd: installDir, stdio: "inherit" });
|
|
19377
19523
|
console.log("Building...");
|
|
19378
|
-
|
|
19524
|
+
execSync51("npm run build", { cwd: installDir, stdio: "inherit" });
|
|
19379
19525
|
console.log("Syncing commands...");
|
|
19380
|
-
|
|
19526
|
+
execSync51("assist sync", { stdio: "inherit" });
|
|
19381
19527
|
} else if (isGlobalNpmInstall(installDir)) {
|
|
19382
19528
|
console.log("Detected global npm installation, updating...");
|
|
19383
|
-
|
|
19529
|
+
execSync51("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
|
|
19384
19530
|
console.log("Syncing commands...");
|
|
19385
|
-
|
|
19531
|
+
execSync51("assist sync", { stdio: "inherit" });
|
|
19386
19532
|
} else {
|
|
19387
19533
|
console.error(
|
|
19388
19534
|
"Could not determine installation method. Expected a git repo or global npm install."
|