@staff0rd/assist 0.305.4 → 0.307.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 +15 -0
- package/dist/commands/netcap/netcap-extension/background.js +30 -0
- package/dist/commands/netcap/netcap-extension/interceptor.js +114 -0
- package/dist/commands/netcap/netcap-extension/manifest.json +25 -0
- package/dist/commands/netcap/netcap-extension/relay.js +14 -0
- package/dist/commands/sessions/web/bundle.js +72 -72
- package/dist/index.js +1115 -438
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.307.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -2178,7 +2178,7 @@ function flushIfFailed(exitCode, chunks) {
|
|
|
2178
2178
|
|
|
2179
2179
|
// src/commands/verify/run/runAllEntries.ts
|
|
2180
2180
|
function runEntry(entry, onComplete) {
|
|
2181
|
-
return new Promise((
|
|
2181
|
+
return new Promise((resolve17) => {
|
|
2182
2182
|
const child = spawnCommand(
|
|
2183
2183
|
entry.fullCommand,
|
|
2184
2184
|
entry.cwd,
|
|
@@ -2190,7 +2190,7 @@ function runEntry(entry, onComplete) {
|
|
|
2190
2190
|
const exitCode = code ?? 1;
|
|
2191
2191
|
flushIfFailed(exitCode, chunks);
|
|
2192
2192
|
onComplete?.(exitCode);
|
|
2193
|
-
|
|
2193
|
+
resolve17({ script: entry.name, code: exitCode });
|
|
2194
2194
|
});
|
|
2195
2195
|
});
|
|
2196
2196
|
}
|
|
@@ -2943,8 +2943,8 @@ function spawnClaude(prompt, options2 = {}) {
|
|
|
2943
2943
|
stdio: "inherit",
|
|
2944
2944
|
env
|
|
2945
2945
|
});
|
|
2946
|
-
const done2 = new Promise((
|
|
2947
|
-
child.on("close", (code) =>
|
|
2946
|
+
const done2 = new Promise((resolve17, reject) => {
|
|
2947
|
+
child.on("close", (code) => resolve17(code ?? 0));
|
|
2948
2948
|
child.on("error", reject);
|
|
2949
2949
|
});
|
|
2950
2950
|
return { child, done: done2 };
|
|
@@ -4752,9 +4752,9 @@ import {
|
|
|
4752
4752
|
// src/commands/sessions/daemon/connectToDaemon.ts
|
|
4753
4753
|
import * as net from "net";
|
|
4754
4754
|
function connectToDaemon() {
|
|
4755
|
-
return new Promise((
|
|
4755
|
+
return new Promise((resolve17, reject) => {
|
|
4756
4756
|
const socket = net.connect(daemonPaths.socket);
|
|
4757
|
-
socket.once("connect", () =>
|
|
4757
|
+
socket.once("connect", () => resolve17(socket));
|
|
4758
4758
|
socket.once("error", reject);
|
|
4759
4759
|
});
|
|
4760
4760
|
}
|
|
@@ -4834,7 +4834,7 @@ function spawnDaemon(reason) {
|
|
|
4834
4834
|
child.unref();
|
|
4835
4835
|
}
|
|
4836
4836
|
function delay(ms) {
|
|
4837
|
-
return new Promise((
|
|
4837
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
4838
4838
|
}
|
|
4839
4839
|
|
|
4840
4840
|
// src/commands/sessions/web/handleRequest.ts
|
|
@@ -4972,20 +4972,17 @@ async function loadVisibleItems(req) {
|
|
|
4972
4972
|
return loaded.filter((item) => !completedStatuses.has(item.status));
|
|
4973
4973
|
}
|
|
4974
4974
|
|
|
4975
|
-
// src/commands/backlog/web/
|
|
4975
|
+
// src/commands/backlog/web/parseStatusBody.ts
|
|
4976
4976
|
function readBody(req) {
|
|
4977
|
-
return new Promise((
|
|
4977
|
+
return new Promise((resolve17, reject) => {
|
|
4978
4978
|
let body = "";
|
|
4979
4979
|
req.on("data", (chunk) => {
|
|
4980
4980
|
body += chunk.toString();
|
|
4981
4981
|
});
|
|
4982
|
-
req.on("end", () =>
|
|
4982
|
+
req.on("end", () => resolve17(body));
|
|
4983
4983
|
req.on("error", reject);
|
|
4984
4984
|
});
|
|
4985
4985
|
}
|
|
4986
|
-
async function parseItemBody(req) {
|
|
4987
|
-
return JSON.parse(await readBody(req));
|
|
4988
|
-
}
|
|
4989
4986
|
async function parseStatusBody(req) {
|
|
4990
4987
|
return JSON.parse(await readBody(req));
|
|
4991
4988
|
}
|
|
@@ -5099,22 +5096,6 @@ function validateRewind(item, plan2, phase) {
|
|
|
5099
5096
|
return void 0;
|
|
5100
5097
|
}
|
|
5101
5098
|
|
|
5102
|
-
// src/commands/backlog/web/updateItem.ts
|
|
5103
|
-
import { eq as eq15 } from "drizzle-orm";
|
|
5104
|
-
async function updateItem(req, res, id2) {
|
|
5105
|
-
const body = await parseItemBody(req);
|
|
5106
|
-
const result = await findItemOr404(res, id2);
|
|
5107
|
-
if (!result) return;
|
|
5108
|
-
const { orm } = result;
|
|
5109
|
-
await orm.update(items).set({
|
|
5110
|
-
type: body.type ?? result.item.type,
|
|
5111
|
-
name: body.name,
|
|
5112
|
-
description: body.description ?? null,
|
|
5113
|
-
acceptanceCriteria: JSON.stringify(body.acceptanceCriteria ?? [])
|
|
5114
|
-
}).where(eq15(items.id, id2));
|
|
5115
|
-
respondJson(res, 200, await loadItem(orm, id2));
|
|
5116
|
-
}
|
|
5117
|
-
|
|
5118
5099
|
// src/commands/backlog/web/handleItemRoute.ts
|
|
5119
5100
|
var id = (match, group = 1) => Number.parseInt(match[group], 10);
|
|
5120
5101
|
var routes = [
|
|
@@ -5138,11 +5119,6 @@ var routes = [
|
|
|
5138
5119
|
method: "GET",
|
|
5139
5120
|
run: (_req, res, m) => getItemById(res, id(m))
|
|
5140
5121
|
},
|
|
5141
|
-
{
|
|
5142
|
-
pattern: /^\/api\/items\/(\d+)$/,
|
|
5143
|
-
method: "PUT",
|
|
5144
|
-
run: (req, res, m) => updateItem(req, res, id(m))
|
|
5145
|
-
},
|
|
5146
5122
|
{
|
|
5147
5123
|
pattern: /^\/api\/items\/(\d+)$/,
|
|
5148
5124
|
method: "PATCH",
|
|
@@ -5527,17 +5503,17 @@ async function stopDaemon() {
|
|
|
5527
5503
|
}
|
|
5528
5504
|
}
|
|
5529
5505
|
function closedBeforeTimeout(socket) {
|
|
5530
|
-
return new Promise((
|
|
5506
|
+
return new Promise((resolve17) => {
|
|
5531
5507
|
const timer = setTimeout(() => {
|
|
5532
5508
|
socket.destroy();
|
|
5533
|
-
|
|
5509
|
+
resolve17(false);
|
|
5534
5510
|
}, STOP_TIMEOUT_MS);
|
|
5535
5511
|
socket.resume();
|
|
5536
5512
|
socket.on("error", () => {
|
|
5537
5513
|
});
|
|
5538
5514
|
socket.once("close", () => {
|
|
5539
5515
|
clearTimeout(timer);
|
|
5540
|
-
|
|
5516
|
+
resolve17(true);
|
|
5541
5517
|
});
|
|
5542
5518
|
});
|
|
5543
5519
|
}
|
|
@@ -5588,8 +5564,8 @@ async function restartWeb(req, res, deps2 = {}) {
|
|
|
5588
5564
|
respondJson(res, 400, { error: "Invalid target" });
|
|
5589
5565
|
return;
|
|
5590
5566
|
}
|
|
5591
|
-
await new Promise((
|
|
5592
|
-
res.once("finish",
|
|
5567
|
+
await new Promise((resolve17) => {
|
|
5568
|
+
res.once("finish", resolve17);
|
|
5593
5569
|
respondJson(res, 200, { ok: true });
|
|
5594
5570
|
});
|
|
5595
5571
|
if (target === "daemon" || target === "both") {
|
|
@@ -6486,22 +6462,22 @@ async function add(options2) {
|
|
|
6486
6462
|
import chalk58 from "chalk";
|
|
6487
6463
|
|
|
6488
6464
|
// src/commands/backlog/insertPhaseAt.ts
|
|
6489
|
-
import { count, eq as
|
|
6465
|
+
import { count, eq as eq16 } from "drizzle-orm";
|
|
6490
6466
|
|
|
6491
6467
|
// src/commands/backlog/shiftPhasesUp.ts
|
|
6492
|
-
import { and as and3, desc as desc2, eq as
|
|
6468
|
+
import { and as and3, desc as desc2, eq as eq15, gte } from "drizzle-orm";
|
|
6493
6469
|
async function shiftPhasesUp(db, itemId, fromIdx) {
|
|
6494
|
-
const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and3(
|
|
6470
|
+
const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and3(eq15(planPhases.itemId, itemId), gte(planPhases.idx, fromIdx))).orderBy(desc2(planPhases.idx));
|
|
6495
6471
|
for (const p of toShift) {
|
|
6496
|
-
await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and3(
|
|
6497
|
-
await db.update(planPhases).set({ idx: p.idx + 1 }).where(and3(
|
|
6472
|
+
await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and3(eq15(planTasks.itemId, itemId), eq15(planTasks.phaseIdx, p.idx)));
|
|
6473
|
+
await db.update(planPhases).set({ idx: p.idx + 1 }).where(and3(eq15(planPhases.itemId, itemId), eq15(planPhases.idx, p.idx)));
|
|
6498
6474
|
}
|
|
6499
6475
|
}
|
|
6500
6476
|
|
|
6501
6477
|
// src/commands/backlog/insertPhaseAt.ts
|
|
6502
6478
|
async function insertPhaseAt(orm, itemId, phaseIdx, name, tasks, manualChecks, currentPhase) {
|
|
6503
6479
|
await orm.transaction(async (tx) => {
|
|
6504
|
-
const [row] = await tx.select({ cnt: count() }).from(planPhases).where(
|
|
6480
|
+
const [row] = await tx.select({ cnt: count() }).from(planPhases).where(eq16(planPhases.itemId, itemId));
|
|
6505
6481
|
const phaseCount = row?.cnt ?? 0;
|
|
6506
6482
|
await shiftPhasesUp(tx, itemId, phaseIdx);
|
|
6507
6483
|
await tx.insert(planPhases).values({ itemId, idx: phaseIdx, name, manualChecks });
|
|
@@ -6510,16 +6486,16 @@ async function insertPhaseAt(orm, itemId, phaseIdx, name, tasks, manualChecks, c
|
|
|
6510
6486
|
}
|
|
6511
6487
|
if (currentPhase !== void 0 && currentPhase - 1 >= phaseIdx) {
|
|
6512
6488
|
const atReviewSlot = currentPhase - 1 >= phaseCount;
|
|
6513
|
-
await tx.update(items).set({ currentPhase: atReviewSlot ? phaseIdx + 1 : currentPhase + 1 }).where(
|
|
6489
|
+
await tx.update(items).set({ currentPhase: atReviewSlot ? phaseIdx + 1 : currentPhase + 1 }).where(eq16(items.id, itemId));
|
|
6514
6490
|
}
|
|
6515
6491
|
});
|
|
6516
6492
|
}
|
|
6517
6493
|
|
|
6518
6494
|
// src/commands/backlog/resolveInsertPosition.ts
|
|
6519
6495
|
import chalk57 from "chalk";
|
|
6520
|
-
import { count as count2, eq as
|
|
6496
|
+
import { count as count2, eq as eq17 } from "drizzle-orm";
|
|
6521
6497
|
async function resolveInsertPosition(orm, itemId, position) {
|
|
6522
|
-
const [row] = await orm.select({ cnt: count2() }).from(planPhases).where(
|
|
6498
|
+
const [row] = await orm.select({ cnt: count2() }).from(planPhases).where(eq17(planPhases.itemId, itemId));
|
|
6523
6499
|
const phaseCount = row?.cnt ?? 0;
|
|
6524
6500
|
if (position === void 0) return phaseCount;
|
|
6525
6501
|
const pos = Number.parseInt(position, 10);
|
|
@@ -6680,9 +6656,9 @@ function hasCycle(adjacency, fromId, toId) {
|
|
|
6680
6656
|
}
|
|
6681
6657
|
|
|
6682
6658
|
// src/commands/backlog/loadDependencyGraph.ts
|
|
6683
|
-
import { eq as
|
|
6659
|
+
import { eq as eq18 } from "drizzle-orm";
|
|
6684
6660
|
async function loadDependencyGraph(orm) {
|
|
6685
|
-
const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(
|
|
6661
|
+
const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(eq18(links.type, "depends-on"));
|
|
6686
6662
|
const graph = /* @__PURE__ */ new Map();
|
|
6687
6663
|
for (const { itemId, targetId } of rows) {
|
|
6688
6664
|
const bucket = graph.get(itemId);
|
|
@@ -6745,7 +6721,7 @@ async function link(fromId, toId, opts) {
|
|
|
6745
6721
|
|
|
6746
6722
|
// src/commands/backlog/unlink.ts
|
|
6747
6723
|
import chalk62 from "chalk";
|
|
6748
|
-
import { and as and4, eq as
|
|
6724
|
+
import { and as and4, eq as eq19 } from "drizzle-orm";
|
|
6749
6725
|
async function unlink(fromId, toId) {
|
|
6750
6726
|
const fromNum = Number.parseInt(fromId, 10);
|
|
6751
6727
|
const toNum = Number.parseInt(toId, 10);
|
|
@@ -6763,7 +6739,7 @@ async function unlink(fromId, toId) {
|
|
|
6763
6739
|
console.log(chalk62.yellow(`No link from #${fromId} to #${toId} found.`));
|
|
6764
6740
|
return;
|
|
6765
6741
|
}
|
|
6766
|
-
await orm.delete(links).where(and4(
|
|
6742
|
+
await orm.delete(links).where(and4(eq19(links.itemId, fromNum), eq19(links.targetId, toNum)));
|
|
6767
6743
|
console.log(chalk62.green(`Removed link from #${fromId} to #${toId}.`));
|
|
6768
6744
|
}
|
|
6769
6745
|
|
|
@@ -6779,7 +6755,7 @@ function registerLinkCommands(cmd) {
|
|
|
6779
6755
|
|
|
6780
6756
|
// src/commands/backlog/move-repo/index.ts
|
|
6781
6757
|
import chalk64 from "chalk";
|
|
6782
|
-
import { eq as
|
|
6758
|
+
import { eq as eq21 } from "drizzle-orm";
|
|
6783
6759
|
|
|
6784
6760
|
// src/commands/backlog/move-repo/confirmMove.ts
|
|
6785
6761
|
import chalk63 from "chalk";
|
|
@@ -6794,9 +6770,9 @@ async function confirmMove(cnt, oldOrigin, newOrigin) {
|
|
|
6794
6770
|
}
|
|
6795
6771
|
|
|
6796
6772
|
// src/commands/backlog/move-repo/countByOrigin.ts
|
|
6797
|
-
import { count as count3, eq as
|
|
6773
|
+
import { count as count3, eq as eq20 } from "drizzle-orm";
|
|
6798
6774
|
async function countByOrigin(orm, origin) {
|
|
6799
|
-
const [{ cnt }] = await orm.select({ cnt: count3() }).from(items).where(
|
|
6775
|
+
const [{ cnt }] = await orm.select({ cnt: count3() }).from(items).where(eq20(items.origin, origin));
|
|
6800
6776
|
return cnt;
|
|
6801
6777
|
}
|
|
6802
6778
|
|
|
@@ -6839,7 +6815,7 @@ async function moveRepo(oldOriginRaw, newOriginRaw, options2 = {}) {
|
|
|
6839
6815
|
console.log(chalk64.yellow("Move cancelled; no changes made."));
|
|
6840
6816
|
return;
|
|
6841
6817
|
}
|
|
6842
|
-
await orm.update(items).set({ origin: newOrigin }).where(
|
|
6818
|
+
await orm.update(items).set({ origin: newOrigin }).where(eq21(items.origin, oldOrigin));
|
|
6843
6819
|
console.log(
|
|
6844
6820
|
chalk64.green(
|
|
6845
6821
|
`Moved ${pluralItems(cnt)} from "${oldOrigin}" to "${newOrigin}".`
|
|
@@ -7173,10 +7149,10 @@ async function start(id2) {
|
|
|
7173
7149
|
|
|
7174
7150
|
// src/commands/backlog/stop/index.ts
|
|
7175
7151
|
import chalk75 from "chalk";
|
|
7176
|
-
import { and as and5, eq as
|
|
7152
|
+
import { and as and5, eq as eq22 } from "drizzle-orm";
|
|
7177
7153
|
async function stop() {
|
|
7178
7154
|
const { orm } = await getReady();
|
|
7179
|
-
const stopped = await orm.update(items).set({ status: "todo", currentPhase: 1 }).where(and5(
|
|
7155
|
+
const stopped = await orm.update(items).set({ status: "todo", currentPhase: 1 }).where(and5(eq22(items.status, "in-progress"), eq22(items.origin, getOrigin()))).returning({ id: items.id, name: items.name });
|
|
7180
7156
|
if (stopped.length === 0) {
|
|
7181
7157
|
console.log(chalk75.yellow("No in-progress items to stop."));
|
|
7182
7158
|
return;
|
|
@@ -7222,18 +7198,18 @@ function registerStatusCommands(cmd) {
|
|
|
7222
7198
|
|
|
7223
7199
|
// src/commands/backlog/removePhase.ts
|
|
7224
7200
|
import chalk79 from "chalk";
|
|
7225
|
-
import { and as and8, eq as
|
|
7201
|
+
import { and as and8, eq as eq25 } from "drizzle-orm";
|
|
7226
7202
|
|
|
7227
7203
|
// src/commands/backlog/findPhase.ts
|
|
7228
7204
|
import chalk78 from "chalk";
|
|
7229
|
-
import { and as and6, count as count4, eq as
|
|
7205
|
+
import { and as and6, count as count4, eq as eq23 } from "drizzle-orm";
|
|
7230
7206
|
async function findPhase(id2, phase) {
|
|
7231
7207
|
const found = await findOneItem(id2);
|
|
7232
7208
|
if (!found) return void 0;
|
|
7233
7209
|
const { orm, item } = found;
|
|
7234
7210
|
const itemId = item.id;
|
|
7235
7211
|
const phaseIdx = Number.parseInt(phase, 10) - 1;
|
|
7236
|
-
const [row] = await orm.select({ cnt: count4() }).from(planPhases).where(and6(
|
|
7212
|
+
const [row] = await orm.select({ cnt: count4() }).from(planPhases).where(and6(eq23(planPhases.itemId, itemId), eq23(planPhases.idx, phaseIdx)));
|
|
7237
7213
|
if (!row || row.cnt === 0) {
|
|
7238
7214
|
console.log(
|
|
7239
7215
|
chalk78.red(`Phase ${phaseIdx + 1} not found on item #${itemId}.`)
|
|
@@ -7245,14 +7221,14 @@ async function findPhase(id2, phase) {
|
|
|
7245
7221
|
}
|
|
7246
7222
|
|
|
7247
7223
|
// src/commands/backlog/reindexPhases.ts
|
|
7248
|
-
import { and as and7, asc as asc6, count as count5, eq as
|
|
7224
|
+
import { and as and7, asc as asc6, count as count5, eq as eq24 } from "drizzle-orm";
|
|
7249
7225
|
async function reindexPhases(db, itemId) {
|
|
7250
|
-
const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(
|
|
7226
|
+
const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq24(planPhases.itemId, itemId)).orderBy(asc6(planPhases.idx));
|
|
7251
7227
|
for (let i = 0; i < remaining.length; i++) {
|
|
7252
7228
|
const oldIdx = remaining[i].idx;
|
|
7253
7229
|
if (oldIdx === i) continue;
|
|
7254
|
-
await db.update(planTasks).set({ phaseIdx: i }).where(and7(
|
|
7255
|
-
await db.update(planPhases).set({ idx: i }).where(and7(
|
|
7230
|
+
await db.update(planTasks).set({ phaseIdx: i }).where(and7(eq24(planTasks.itemId, itemId), eq24(planTasks.phaseIdx, oldIdx)));
|
|
7231
|
+
await db.update(planPhases).set({ idx: i }).where(and7(eq24(planPhases.itemId, itemId), eq24(planPhases.idx, oldIdx)));
|
|
7256
7232
|
}
|
|
7257
7233
|
}
|
|
7258
7234
|
async function adjustCurrentPhase(db, item, removedIdx) {
|
|
@@ -7260,13 +7236,13 @@ async function adjustCurrentPhase(db, item, removedIdx) {
|
|
|
7260
7236
|
if (currentPhase === void 0) return;
|
|
7261
7237
|
const currentIdx = currentPhase - 1;
|
|
7262
7238
|
if (removedIdx < currentIdx) {
|
|
7263
|
-
await db.update(items).set({ currentPhase: currentPhase - 1 }).where(
|
|
7239
|
+
await db.update(items).set({ currentPhase: currentPhase - 1 }).where(eq24(items.id, item.id));
|
|
7264
7240
|
return;
|
|
7265
7241
|
}
|
|
7266
7242
|
if (removedIdx !== currentIdx) return;
|
|
7267
|
-
const [row] = await db.select({ cnt: count5() }).from(planPhases).where(
|
|
7243
|
+
const [row] = await db.select({ cnt: count5() }).from(planPhases).where(eq24(planPhases.itemId, item.id));
|
|
7268
7244
|
const cnt = row?.cnt ?? 0;
|
|
7269
|
-
await db.update(items).set({ currentPhase: cnt === 0 ? null : Math.min(currentPhase, cnt) }).where(
|
|
7245
|
+
await db.update(items).set({ currentPhase: cnt === 0 ? null : Math.min(currentPhase, cnt) }).where(eq24(items.id, item.id));
|
|
7270
7246
|
}
|
|
7271
7247
|
|
|
7272
7248
|
// src/commands/backlog/removePhase.ts
|
|
@@ -7276,9 +7252,9 @@ async function removePhase(id2, phase) {
|
|
|
7276
7252
|
const { item, orm, itemId, phaseIdx } = found;
|
|
7277
7253
|
await orm.transaction(async (tx) => {
|
|
7278
7254
|
await tx.delete(planTasks).where(
|
|
7279
|
-
and8(
|
|
7255
|
+
and8(eq25(planTasks.itemId, itemId), eq25(planTasks.phaseIdx, phaseIdx))
|
|
7280
7256
|
);
|
|
7281
|
-
await tx.delete(planPhases).where(and8(
|
|
7257
|
+
await tx.delete(planPhases).where(and8(eq25(planPhases.itemId, itemId), eq25(planPhases.idx, phaseIdx)));
|
|
7282
7258
|
await reindexPhases(tx, itemId);
|
|
7283
7259
|
await adjustCurrentPhase(tx, item, phaseIdx);
|
|
7284
7260
|
});
|
|
@@ -7289,7 +7265,7 @@ async function removePhase(id2, phase) {
|
|
|
7289
7265
|
|
|
7290
7266
|
// src/commands/backlog/update/index.ts
|
|
7291
7267
|
import chalk81 from "chalk";
|
|
7292
|
-
import { eq as
|
|
7268
|
+
import { eq as eq26 } from "drizzle-orm";
|
|
7293
7269
|
|
|
7294
7270
|
// src/commands/backlog/update/parseListIndex.ts
|
|
7295
7271
|
function parseListIndex(raw, length, label2) {
|
|
@@ -7423,7 +7399,7 @@ async function update(id2, options2) {
|
|
|
7423
7399
|
if (!built) return;
|
|
7424
7400
|
const { orm } = found;
|
|
7425
7401
|
const itemId = found.item.id;
|
|
7426
|
-
await orm.update(items).set(built.set).where(
|
|
7402
|
+
await orm.update(items).set(built.set).where(eq26(items.id, itemId));
|
|
7427
7403
|
console.log(chalk81.green(`Updated ${built.fields} on item #${itemId}.`));
|
|
7428
7404
|
}
|
|
7429
7405
|
|
|
@@ -7431,22 +7407,22 @@ async function update(id2, options2) {
|
|
|
7431
7407
|
import chalk82 from "chalk";
|
|
7432
7408
|
|
|
7433
7409
|
// src/commands/backlog/applyPhaseUpdate.ts
|
|
7434
|
-
import { and as and9, eq as
|
|
7410
|
+
import { and as and9, eq as eq27 } from "drizzle-orm";
|
|
7435
7411
|
async function applyPhaseUpdate(orm, itemId, phaseIdx, fields) {
|
|
7436
7412
|
await orm.transaction(async (tx) => {
|
|
7437
7413
|
if (fields.name) {
|
|
7438
7414
|
await tx.update(planPhases).set({ name: fields.name }).where(
|
|
7439
|
-
and9(
|
|
7415
|
+
and9(eq27(planPhases.itemId, itemId), eq27(planPhases.idx, phaseIdx))
|
|
7440
7416
|
);
|
|
7441
7417
|
}
|
|
7442
7418
|
if (fields.manualCheck) {
|
|
7443
7419
|
await tx.update(planPhases).set({ manualChecks: JSON.stringify(fields.manualCheck) }).where(
|
|
7444
|
-
and9(
|
|
7420
|
+
and9(eq27(planPhases.itemId, itemId), eq27(planPhases.idx, phaseIdx))
|
|
7445
7421
|
);
|
|
7446
7422
|
}
|
|
7447
7423
|
if (fields.task) {
|
|
7448
7424
|
await tx.delete(planTasks).where(
|
|
7449
|
-
and9(
|
|
7425
|
+
and9(eq27(planTasks.itemId, itemId), eq27(planTasks.phaseIdx, phaseIdx))
|
|
7450
7426
|
);
|
|
7451
7427
|
if (fields.task.length) {
|
|
7452
7428
|
await tx.insert(planTasks).values(
|
|
@@ -8363,12 +8339,12 @@ function hasSubcommands(helpText) {
|
|
|
8363
8339
|
// src/commands/permitCliReads/runHelp.ts
|
|
8364
8340
|
import { exec as exec2 } from "child_process";
|
|
8365
8341
|
function runHelp(args) {
|
|
8366
|
-
return new Promise((
|
|
8342
|
+
return new Promise((resolve17) => {
|
|
8367
8343
|
exec2(
|
|
8368
8344
|
`${args.join(" ")} --help`,
|
|
8369
8345
|
{ encoding: "utf8", timeout: 3e4 },
|
|
8370
8346
|
(_err, stdout, stderr) => {
|
|
8371
|
-
|
|
8347
|
+
resolve17(stdout || stderr || "");
|
|
8372
8348
|
}
|
|
8373
8349
|
);
|
|
8374
8350
|
});
|
|
@@ -10755,9 +10731,9 @@ function registerGithub(program2) {
|
|
|
10755
10731
|
}
|
|
10756
10732
|
|
|
10757
10733
|
// src/commands/handover/countPendingHandovers.ts
|
|
10758
|
-
import { and as and10, eq as
|
|
10734
|
+
import { and as and10, eq as eq28, isNull, sql as sql3 } from "drizzle-orm";
|
|
10759
10735
|
async function countPendingHandovers(orm, origin) {
|
|
10760
|
-
const [row] = await orm.select({ count: sql3`count(*)::int` }).from(handovers).where(and10(
|
|
10736
|
+
const [row] = await orm.select({ count: sql3`count(*)::int` }).from(handovers).where(and10(eq28(handovers.origin, origin), isNull(handovers.recalledAt)));
|
|
10761
10737
|
return row?.count ?? 0;
|
|
10762
10738
|
}
|
|
10763
10739
|
|
|
@@ -10897,13 +10873,13 @@ async function load(options2 = {}) {
|
|
|
10897
10873
|
}
|
|
10898
10874
|
|
|
10899
10875
|
// src/commands/handover/listPendingHandovers.ts
|
|
10900
|
-
import { and as and11, desc as desc3, eq as
|
|
10876
|
+
import { and as and11, desc as desc3, eq as eq29, isNull as isNull2 } from "drizzle-orm";
|
|
10901
10877
|
async function listPendingHandovers(orm, origin) {
|
|
10902
10878
|
return orm.select({
|
|
10903
10879
|
id: handovers.id,
|
|
10904
10880
|
summary: handovers.summary,
|
|
10905
10881
|
createdAt: handovers.createdAt
|
|
10906
|
-
}).from(handovers).where(and11(
|
|
10882
|
+
}).from(handovers).where(and11(eq29(handovers.origin, origin), isNull2(handovers.recalledAt))).orderBy(desc3(handovers.createdAt), desc3(handovers.id));
|
|
10907
10883
|
}
|
|
10908
10884
|
|
|
10909
10885
|
// src/commands/handover/printPendingHandovers.ts
|
|
@@ -10916,17 +10892,17 @@ async function printPendingHandovers() {
|
|
|
10916
10892
|
}
|
|
10917
10893
|
|
|
10918
10894
|
// src/commands/handover/recallHandover.ts
|
|
10919
|
-
import { and as and12, desc as desc4, eq as
|
|
10895
|
+
import { and as and12, desc as desc4, eq as eq30, isNull as isNull3 } from "drizzle-orm";
|
|
10920
10896
|
async function recallHandover(orm, origin, id2) {
|
|
10921
10897
|
const [row] = await orm.select().from(handovers).where(
|
|
10922
10898
|
and12(
|
|
10923
|
-
|
|
10899
|
+
eq30(handovers.origin, origin),
|
|
10924
10900
|
isNull3(handovers.recalledAt),
|
|
10925
|
-
...id2 === void 0 ? [] : [
|
|
10901
|
+
...id2 === void 0 ? [] : [eq30(handovers.id, id2)]
|
|
10926
10902
|
)
|
|
10927
10903
|
).orderBy(desc4(handovers.createdAt), desc4(handovers.id)).limit(1);
|
|
10928
10904
|
if (!row) return void 0;
|
|
10929
|
-
await orm.update(handovers).set({ recalledAt: /* @__PURE__ */ new Date() }).where(
|
|
10905
|
+
await orm.update(handovers).set({ recalledAt: /* @__PURE__ */ new Date() }).where(eq30(handovers.id, row.id));
|
|
10930
10906
|
return row.content;
|
|
10931
10907
|
}
|
|
10932
10908
|
|
|
@@ -11356,8 +11332,666 @@ function registerMermaid(program2) {
|
|
|
11356
11332
|
);
|
|
11357
11333
|
}
|
|
11358
11334
|
|
|
11359
|
-
// src/commands/
|
|
11335
|
+
// src/commands/netcap/netcap.ts
|
|
11336
|
+
import { mkdir } from "fs/promises";
|
|
11337
|
+
import { createServer as createServer2 } from "http";
|
|
11338
|
+
import { dirname as dirname20 } from "path";
|
|
11339
|
+
import chalk124 from "chalk";
|
|
11340
|
+
|
|
11341
|
+
// src/commands/netcap/corsHeaders.ts
|
|
11342
|
+
var corsHeaders = {
|
|
11343
|
+
"Access-Control-Allow-Origin": "*",
|
|
11344
|
+
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
|
11345
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
11346
|
+
"Access-Control-Max-Age": "86400"
|
|
11347
|
+
};
|
|
11348
|
+
|
|
11349
|
+
// src/commands/netcap/handleNetcapPost.ts
|
|
11350
|
+
import { appendFile } from "fs/promises";
|
|
11351
|
+
|
|
11352
|
+
// src/commands/netcap/parseNetcapEntry.ts
|
|
11353
|
+
function parseNetcapEntry(body) {
|
|
11354
|
+
try {
|
|
11355
|
+
const parsed = JSON.parse(body);
|
|
11356
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
11357
|
+
return parsed;
|
|
11358
|
+
} catch {
|
|
11359
|
+
return null;
|
|
11360
|
+
}
|
|
11361
|
+
}
|
|
11362
|
+
|
|
11363
|
+
// src/commands/netcap/handleNetcapPost.ts
|
|
11364
|
+
function handleNetcapPost(req, res, options2) {
|
|
11365
|
+
let body = "";
|
|
11366
|
+
req.on("data", (chunk) => {
|
|
11367
|
+
body += chunk;
|
|
11368
|
+
});
|
|
11369
|
+
req.on("end", () => {
|
|
11370
|
+
const entry = parseNetcapEntry(body);
|
|
11371
|
+
if (!entry) {
|
|
11372
|
+
res.writeHead(400, corsHeaders);
|
|
11373
|
+
res.end();
|
|
11374
|
+
return;
|
|
11375
|
+
}
|
|
11376
|
+
void appendFile(options2.outPath, `${JSON.stringify(entry)}
|
|
11377
|
+
`).then(() => {
|
|
11378
|
+
options2.onCapture?.(entry);
|
|
11379
|
+
res.writeHead(200, {
|
|
11380
|
+
...corsHeaders,
|
|
11381
|
+
"Content-Type": "application/json"
|
|
11382
|
+
});
|
|
11383
|
+
res.end(JSON.stringify({ ok: true }));
|
|
11384
|
+
}).catch((error) => {
|
|
11385
|
+
res.writeHead(500, corsHeaders);
|
|
11386
|
+
res.end(String(error));
|
|
11387
|
+
});
|
|
11388
|
+
});
|
|
11389
|
+
}
|
|
11390
|
+
|
|
11391
|
+
// src/commands/netcap/createNetcapHandler.ts
|
|
11392
|
+
function createNetcapHandler(options2) {
|
|
11393
|
+
return (req, res) => {
|
|
11394
|
+
if (req.method === "OPTIONS") {
|
|
11395
|
+
res.writeHead(204, corsHeaders);
|
|
11396
|
+
res.end();
|
|
11397
|
+
return;
|
|
11398
|
+
}
|
|
11399
|
+
if (req.method === "GET") {
|
|
11400
|
+
options2.onPing?.(req);
|
|
11401
|
+
res.writeHead(200, { ...corsHeaders, "Content-Type": "text/plain" });
|
|
11402
|
+
res.end("netcap receiver");
|
|
11403
|
+
return;
|
|
11404
|
+
}
|
|
11405
|
+
if (req.method !== "POST") {
|
|
11406
|
+
res.writeHead(405, corsHeaders);
|
|
11407
|
+
res.end();
|
|
11408
|
+
return;
|
|
11409
|
+
}
|
|
11410
|
+
handleNetcapPost(req, res, options2);
|
|
11411
|
+
};
|
|
11412
|
+
}
|
|
11413
|
+
|
|
11414
|
+
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
11415
|
+
import { cp, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
11416
|
+
import { networkInterfaces } from "os";
|
|
11417
|
+
import { join as join35 } from "path";
|
|
11360
11418
|
import chalk123 from "chalk";
|
|
11419
|
+
|
|
11420
|
+
// src/commands/netcap/netcapExtensionDir.ts
|
|
11421
|
+
import { dirname as dirname19, join as join34 } from "path";
|
|
11422
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
11423
|
+
var moduleDir = dirname19(fileURLToPath5(import.meta.url));
|
|
11424
|
+
function netcapExtensionDir() {
|
|
11425
|
+
return join34(moduleDir, "commands", "netcap", "netcap-extension");
|
|
11426
|
+
}
|
|
11427
|
+
|
|
11428
|
+
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
11429
|
+
var WSL_WINDOWS_DIR = "/mnt/c/tools/netcap-extension";
|
|
11430
|
+
var WSL_WINDOWS_PATH = String.raw`C:\tools\netcap-extension`;
|
|
11431
|
+
function lanIPv4() {
|
|
11432
|
+
for (const addrs of Object.values(networkInterfaces())) {
|
|
11433
|
+
for (const addr of addrs ?? []) {
|
|
11434
|
+
if (addr.family === "IPv4" && !addr.internal) return addr.address;
|
|
11435
|
+
}
|
|
11436
|
+
}
|
|
11437
|
+
return void 0;
|
|
11438
|
+
}
|
|
11439
|
+
async function configureBackground(dir, host, port, filter) {
|
|
11440
|
+
const file = join35(dir, "background.js");
|
|
11441
|
+
const source = await readFile2(file, "utf8");
|
|
11442
|
+
await writeFile2(
|
|
11443
|
+
file,
|
|
11444
|
+
source.replace(
|
|
11445
|
+
/const RECEIVER = "[^"]*";/,
|
|
11446
|
+
`const RECEIVER = "http://${host}:${port}/";`
|
|
11447
|
+
).replace(
|
|
11448
|
+
/const FILTER = "[^"]*";/,
|
|
11449
|
+
`const FILTER = ${JSON.stringify(filter)};`
|
|
11450
|
+
)
|
|
11451
|
+
);
|
|
11452
|
+
}
|
|
11453
|
+
async function prepareExtensionForLoad(port, filter = "") {
|
|
11454
|
+
const source = netcapExtensionDir();
|
|
11455
|
+
if (detectPlatform() !== "wsl") {
|
|
11456
|
+
await configureBackground(source, "127.0.0.1", port, filter);
|
|
11457
|
+
return source;
|
|
11458
|
+
}
|
|
11459
|
+
const host = lanIPv4();
|
|
11460
|
+
if (!host) {
|
|
11461
|
+
console.log(
|
|
11462
|
+
chalk123.yellow("could not determine the WSL IP for the extension")
|
|
11463
|
+
);
|
|
11464
|
+
await configureBackground(source, "127.0.0.1", port, filter);
|
|
11465
|
+
return source;
|
|
11466
|
+
}
|
|
11467
|
+
try {
|
|
11468
|
+
await cp(source, WSL_WINDOWS_DIR, { recursive: true });
|
|
11469
|
+
await configureBackground(WSL_WINDOWS_DIR, host, port, filter);
|
|
11470
|
+
return WSL_WINDOWS_PATH;
|
|
11471
|
+
} catch {
|
|
11472
|
+
console.log(
|
|
11473
|
+
chalk123.yellow(`could not copy extension to ${WSL_WINDOWS_PATH}`)
|
|
11474
|
+
);
|
|
11475
|
+
return source;
|
|
11476
|
+
}
|
|
11477
|
+
}
|
|
11478
|
+
|
|
11479
|
+
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
11480
|
+
import { isAbsolute, join as join37, resolve as resolve11 } from "path";
|
|
11481
|
+
|
|
11482
|
+
// src/commands/netcap/defaultCapturePath.ts
|
|
11483
|
+
import { homedir as homedir12 } from "os";
|
|
11484
|
+
import { join as join36 } from "path";
|
|
11485
|
+
function defaultCapturePath() {
|
|
11486
|
+
return join36(homedir12(), ".assist", "netcap", "capture.jsonl");
|
|
11487
|
+
}
|
|
11488
|
+
|
|
11489
|
+
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
11490
|
+
function resolveNetcapOutPath(out) {
|
|
11491
|
+
if (!out) return defaultCapturePath();
|
|
11492
|
+
const dir = isAbsolute(out) ? out : resolve11(process.cwd(), out);
|
|
11493
|
+
return join37(dir, "capture.jsonl");
|
|
11494
|
+
}
|
|
11495
|
+
|
|
11496
|
+
// src/commands/netcap/netcap.ts
|
|
11497
|
+
async function netcap(options2) {
|
|
11498
|
+
const port = Number(options2.port);
|
|
11499
|
+
const outPath = resolveNetcapOutPath(options2.out);
|
|
11500
|
+
const filter = options2.filter ?? "";
|
|
11501
|
+
await mkdir(dirname20(outPath), { recursive: true });
|
|
11502
|
+
const extensionPath = await prepareExtensionForLoad(port, filter);
|
|
11503
|
+
let count6 = 0;
|
|
11504
|
+
const handler = createNetcapHandler({
|
|
11505
|
+
outPath,
|
|
11506
|
+
onPing: () => console.log(chalk124.dim("ping from extension")),
|
|
11507
|
+
onCapture: (entry) => {
|
|
11508
|
+
count6 += 1;
|
|
11509
|
+
console.log(
|
|
11510
|
+
chalk124.green(`captured #${count6}`),
|
|
11511
|
+
chalk124.dim(`${entry.method ?? "?"} ${entry.url ?? "?"}`)
|
|
11512
|
+
);
|
|
11513
|
+
}
|
|
11514
|
+
});
|
|
11515
|
+
const server = createServer2(handler);
|
|
11516
|
+
server.listen(port, () => {
|
|
11517
|
+
console.log(
|
|
11518
|
+
chalk124.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
|
|
11519
|
+
);
|
|
11520
|
+
console.log(chalk124.dim(`appending captures to ${outPath}`));
|
|
11521
|
+
if (filter)
|
|
11522
|
+
console.log(chalk124.dim(`forwarding only URLs matching "${filter}"`));
|
|
11523
|
+
console.log(chalk124.dim(`load the unpacked extension from ${extensionPath}`));
|
|
11524
|
+
console.log(chalk124.dim("press Ctrl-C to stop"));
|
|
11525
|
+
});
|
|
11526
|
+
process.on("SIGINT", () => {
|
|
11527
|
+
server.close();
|
|
11528
|
+
console.log(
|
|
11529
|
+
chalk124.bold(
|
|
11530
|
+
`
|
|
11531
|
+
netcap stopped \u2014 captured ${count6} ${count6 === 1 ? "entry" : "entries"} to ${outPath}`
|
|
11532
|
+
)
|
|
11533
|
+
);
|
|
11534
|
+
process.exit(0);
|
|
11535
|
+
});
|
|
11536
|
+
}
|
|
11537
|
+
|
|
11538
|
+
// src/commands/netcap/netcapExtract.ts
|
|
11539
|
+
import { writeFileSync as writeFileSync26 } from "fs";
|
|
11540
|
+
import { join as join38 } from "path";
|
|
11541
|
+
import chalk125 from "chalk";
|
|
11542
|
+
|
|
11543
|
+
// src/commands/netcap/extractPostsFromCapture.ts
|
|
11544
|
+
import { readFileSync as readFileSync30 } from "fs";
|
|
11545
|
+
|
|
11546
|
+
// src/commands/netcap/parseRscRows.ts
|
|
11547
|
+
var isRscRef = (v) => typeof v === "string" && /^\$[0-9a-fL@]/.test(v);
|
|
11548
|
+
function parseRscRows(flight) {
|
|
11549
|
+
const rows = {};
|
|
11550
|
+
for (const line of flight.split("\n")) {
|
|
11551
|
+
const m = line.match(/^([0-9a-f]+):(.*)$/s);
|
|
11552
|
+
if (!m) continue;
|
|
11553
|
+
let payload = m[2];
|
|
11554
|
+
if (payload && !/^[[{"\d\-tfn]/.test(payload[0]))
|
|
11555
|
+
payload = payload.slice(1);
|
|
11556
|
+
try {
|
|
11557
|
+
rows[m[1]] = JSON.parse(payload);
|
|
11558
|
+
} catch {
|
|
11559
|
+
rows[m[1]] = m[2];
|
|
11560
|
+
}
|
|
11561
|
+
}
|
|
11562
|
+
return rows;
|
|
11563
|
+
}
|
|
11564
|
+
function makeRscResolver(rows) {
|
|
11565
|
+
return (ref) => {
|
|
11566
|
+
const [id2, ...path58] = ref.slice(1).replace(/^[L@]/, "").split(":");
|
|
11567
|
+
let v = rows[id2];
|
|
11568
|
+
for (const key of path58) {
|
|
11569
|
+
if (v == null || typeof v !== "object") return void 0;
|
|
11570
|
+
v = v[key];
|
|
11571
|
+
}
|
|
11572
|
+
return v;
|
|
11573
|
+
};
|
|
11574
|
+
}
|
|
11575
|
+
|
|
11576
|
+
// src/commands/netcap/collectRscText.ts
|
|
11577
|
+
function isVisibleText(t) {
|
|
11578
|
+
if (/^(proto\.|com\.linkedin|react\.)/.test(t)) return false;
|
|
11579
|
+
if (!/\s/.test(t.trim())) return false;
|
|
11580
|
+
return /[a-zA-Z]{3,}/.test(t);
|
|
11581
|
+
}
|
|
11582
|
+
var isHashtag = (t) => /^#[A-Za-z0-9_]+$/.test(t);
|
|
11583
|
+
function collectRscText(v, resolve17, sink, seen) {
|
|
11584
|
+
if (v == null) return;
|
|
11585
|
+
if (typeof v === "string") {
|
|
11586
|
+
if (isRscRef(v)) {
|
|
11587
|
+
if (!seen.has(v)) {
|
|
11588
|
+
seen.add(v);
|
|
11589
|
+
collectRscText(resolve17(v), resolve17, sink, seen);
|
|
11590
|
+
}
|
|
11591
|
+
} else if (isHashtag(v)) sink.hashtags.push(v);
|
|
11592
|
+
else if (isVisibleText(v)) sink.text.push(v);
|
|
11593
|
+
return;
|
|
11594
|
+
}
|
|
11595
|
+
if (Array.isArray(v)) {
|
|
11596
|
+
for (const x of v) collectRscText(x, resolve17, sink, seen);
|
|
11597
|
+
return;
|
|
11598
|
+
}
|
|
11599
|
+
if (typeof v === "object") {
|
|
11600
|
+
for (const val of Object.values(v)) {
|
|
11601
|
+
collectRscText(val, resolve17, sink, seen);
|
|
11602
|
+
}
|
|
11603
|
+
}
|
|
11604
|
+
}
|
|
11605
|
+
|
|
11606
|
+
// src/commands/netcap/buildMentionMap.ts
|
|
11607
|
+
function asObject(v) {
|
|
11608
|
+
return v != null && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
11609
|
+
}
|
|
11610
|
+
function profileActionUrl(o) {
|
|
11611
|
+
const actions = asObject(o.action)?.actions;
|
|
11612
|
+
if (!Array.isArray(actions)) return void 0;
|
|
11613
|
+
for (const a of actions) {
|
|
11614
|
+
const url = asObject(asObject(asObject(a)?.value)?.content)?.url;
|
|
11615
|
+
const target = asObject(url)?.url;
|
|
11616
|
+
if (typeof target === "string" && /\/in\//.test(target)) return target;
|
|
11617
|
+
}
|
|
11618
|
+
return void 0;
|
|
11619
|
+
}
|
|
11620
|
+
var slugFromProfileUrl = (url) => url.match(/\/in\/([^/?]+)/)?.[1];
|
|
11621
|
+
function visitObjects(root, fn) {
|
|
11622
|
+
const stack = [root];
|
|
11623
|
+
while (stack.length) {
|
|
11624
|
+
const v = stack.pop();
|
|
11625
|
+
if (v == null || typeof v !== "object") continue;
|
|
11626
|
+
const o = asObject(v);
|
|
11627
|
+
if (o) fn(o);
|
|
11628
|
+
for (const child of Array.isArray(v) ? v : Object.values(v)) {
|
|
11629
|
+
if (child && typeof child === "object") stack.push(child);
|
|
11630
|
+
}
|
|
11631
|
+
}
|
|
11632
|
+
}
|
|
11633
|
+
function buildMentionMap(rows, resolve17) {
|
|
11634
|
+
const map = /* @__PURE__ */ new Map();
|
|
11635
|
+
visitObjects(rows, (o) => {
|
|
11636
|
+
const url = profileActionUrl(o);
|
|
11637
|
+
if (!url || o.children == null) return;
|
|
11638
|
+
const slug = slugFromProfileUrl(url);
|
|
11639
|
+
if (!slug || map.has(slug)) return;
|
|
11640
|
+
const sink = { text: [], hashtags: [] };
|
|
11641
|
+
collectRscText(o.children, resolve17, sink, /* @__PURE__ */ new Set());
|
|
11642
|
+
const name = sink.text.join(" ").replace(/\s+/g, " ").trim();
|
|
11643
|
+
map.set(slug, name ? { slug, name, url } : { slug, url });
|
|
11644
|
+
});
|
|
11645
|
+
return map;
|
|
11646
|
+
}
|
|
11647
|
+
|
|
11648
|
+
// src/commands/netcap/activityUrnDate.ts
|
|
11649
|
+
function activityUrnDate(urn) {
|
|
11650
|
+
if (!urn) return void 0;
|
|
11651
|
+
const id2 = urn.split(":").pop();
|
|
11652
|
+
if (!id2 || !/^\d+$/.test(id2)) return void 0;
|
|
11653
|
+
return new Date(Number(BigInt(id2) >> 22n)).toISOString();
|
|
11654
|
+
}
|
|
11655
|
+
|
|
11656
|
+
// src/commands/netcap/dedupeLinks.ts
|
|
11657
|
+
function decodeSafetyLink(url) {
|
|
11658
|
+
try {
|
|
11659
|
+
const wrapped = new URL(url).searchParams.get("url");
|
|
11660
|
+
return wrapped ? decodeURIComponent(wrapped) : url;
|
|
11661
|
+
} catch {
|
|
11662
|
+
return url;
|
|
11663
|
+
}
|
|
11664
|
+
}
|
|
11665
|
+
function dedupeLinks(links2) {
|
|
11666
|
+
return [
|
|
11667
|
+
...new Set(
|
|
11668
|
+
links2.map((l) => /\/safety\/go\//.test(l) ? decodeSafetyLink(l) : l)
|
|
11669
|
+
)
|
|
11670
|
+
];
|
|
11671
|
+
}
|
|
11672
|
+
|
|
11673
|
+
// src/commands/netcap/linkifyMentions.ts
|
|
11674
|
+
function linkifyMentions(text5, mentions) {
|
|
11675
|
+
let out = text5;
|
|
11676
|
+
for (const m of mentions) {
|
|
11677
|
+
if (m.name && out.includes(m.name)) {
|
|
11678
|
+
out = out.replace(m.name, `[${m.name}](${m.url})`);
|
|
11679
|
+
}
|
|
11680
|
+
}
|
|
11681
|
+
return out;
|
|
11682
|
+
}
|
|
11683
|
+
|
|
11684
|
+
// src/commands/netcap/buildPost.ts
|
|
11685
|
+
var profileUrl = (slug) => `https://www.linkedin.com/in/${slug}/`;
|
|
11686
|
+
var joinText = (parts) => parts.join(" ").replace(/\s+/g, " ").replace(/\s+([.,!?])/g, "$1").trim();
|
|
11687
|
+
function resolveMentions(raw, mentionMap, author) {
|
|
11688
|
+
const slugs = /* @__PURE__ */ new Set();
|
|
11689
|
+
for (const url of raw.profileUrls) {
|
|
11690
|
+
const slug = slugFromProfileUrl(url);
|
|
11691
|
+
if (slug && slug !== author) slugs.add(slug);
|
|
11692
|
+
}
|
|
11693
|
+
return [...slugs].map(
|
|
11694
|
+
(slug) => mentionMap.get(slug) ?? { slug, url: profileUrl(slug) }
|
|
11695
|
+
);
|
|
11696
|
+
}
|
|
11697
|
+
function resolveAuthor(mentionMap, author) {
|
|
11698
|
+
if (!author) return void 0;
|
|
11699
|
+
return mentionMap.get(author) ?? { slug: author, url: profileUrl(author) };
|
|
11700
|
+
}
|
|
11701
|
+
function buildPost(raw, mentionMap, author) {
|
|
11702
|
+
const text5 = joinText(raw.text);
|
|
11703
|
+
if (!text5) return void 0;
|
|
11704
|
+
const mentions = resolveMentions(raw, mentionMap, author);
|
|
11705
|
+
const relatedPosts = [...new Set(raw.related)];
|
|
11706
|
+
return {
|
|
11707
|
+
text: text5,
|
|
11708
|
+
markdown: linkifyMentions(text5, mentions),
|
|
11709
|
+
mentions,
|
|
11710
|
+
hashtags: [...new Set(raw.hashtags)],
|
|
11711
|
+
links: dedupeLinks(raw.links),
|
|
11712
|
+
relatedPosts,
|
|
11713
|
+
activityUrn: relatedPosts[0],
|
|
11714
|
+
postedAt: activityUrnDate(relatedPosts[0]),
|
|
11715
|
+
author: resolveAuthor(mentionMap, author)
|
|
11716
|
+
};
|
|
11717
|
+
}
|
|
11718
|
+
|
|
11719
|
+
// src/commands/netcap/walkPostRow.ts
|
|
11720
|
+
var isCommentary = (o) => asObject(o.viewTrackingSpecs)?.viewName === "feed-commentary";
|
|
11721
|
+
function walkPostRow(v, resolve17, raw) {
|
|
11722
|
+
if (v == null || typeof v !== "object") return;
|
|
11723
|
+
if (Array.isArray(v)) {
|
|
11724
|
+
for (const x of v) walkPostRow(x, resolve17, raw);
|
|
11725
|
+
return;
|
|
11726
|
+
}
|
|
11727
|
+
const o = v;
|
|
11728
|
+
if (o.$type === "proto.sdui.actions.core.NavigateToUrl" && typeof o.url === "string") {
|
|
11729
|
+
if (/\/in\//.test(o.url)) raw.profileUrls.push(o.url);
|
|
11730
|
+
else raw.links.push(o.url);
|
|
11731
|
+
}
|
|
11732
|
+
if (o.$type === "proto.sdui.actions.requests.RequestedArguments") {
|
|
11733
|
+
const a = JSON.stringify(o).match(/urn:li:activity:\d+/);
|
|
11734
|
+
if (a) raw.related.push(a[0]);
|
|
11735
|
+
}
|
|
11736
|
+
if (isCommentary(o)) {
|
|
11737
|
+
const sink = { text: raw.text, hashtags: raw.hashtags };
|
|
11738
|
+
collectRscText(o.children, resolve17, sink, /* @__PURE__ */ new Set());
|
|
11739
|
+
}
|
|
11740
|
+
for (const val of Object.values(o)) walkPostRow(val, resolve17, raw);
|
|
11741
|
+
}
|
|
11742
|
+
|
|
11743
|
+
// src/commands/netcap/extractLinkedInPosts.ts
|
|
11744
|
+
function findAuthorSlug(flight) {
|
|
11745
|
+
return flight.match(/profile-activity-load-([A-Za-z0-9-]+)/)?.[1];
|
|
11746
|
+
}
|
|
11747
|
+
function findCommentaryRows(rows) {
|
|
11748
|
+
return Object.keys(rows).filter(
|
|
11749
|
+
(id2) => /"componentkey":"feed-commentary_/.test(JSON.stringify(rows[id2]))
|
|
11750
|
+
);
|
|
11751
|
+
}
|
|
11752
|
+
function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
|
|
11753
|
+
const rows = parseRscRows(flight);
|
|
11754
|
+
const resolve17 = makeRscResolver(rows);
|
|
11755
|
+
const mentionMap = buildMentionMap(rows, resolve17);
|
|
11756
|
+
const posts = [];
|
|
11757
|
+
for (const id2 of findCommentaryRows(rows)) {
|
|
11758
|
+
const raw = {
|
|
11759
|
+
text: [],
|
|
11760
|
+
hashtags: [],
|
|
11761
|
+
profileUrls: [],
|
|
11762
|
+
links: [],
|
|
11763
|
+
related: []
|
|
11764
|
+
};
|
|
11765
|
+
walkPostRow(rows[id2], resolve17, raw);
|
|
11766
|
+
const post = buildPost(raw, mentionMap, author);
|
|
11767
|
+
if (post) posts.push(post);
|
|
11768
|
+
}
|
|
11769
|
+
return posts;
|
|
11770
|
+
}
|
|
11771
|
+
|
|
11772
|
+
// src/commands/netcap/collectVoyagerAttributes.ts
|
|
11773
|
+
function attributeDetails(update3) {
|
|
11774
|
+
const attrs = asObject(asObject(update3.commentary)?.text)?.attributesV2;
|
|
11775
|
+
if (!Array.isArray(attrs)) return [];
|
|
11776
|
+
return attrs.map((a) => asObject(asObject(a)?.detailData)).filter((d) => d !== void 0);
|
|
11777
|
+
}
|
|
11778
|
+
function mentionsFrom(details, profiles, authorSlug) {
|
|
11779
|
+
const bySlug = /* @__PURE__ */ new Map();
|
|
11780
|
+
for (const detail of details) {
|
|
11781
|
+
const urn = detail["*profileMention"];
|
|
11782
|
+
if (typeof urn !== "string") continue;
|
|
11783
|
+
const mention = profiles.get(urn);
|
|
11784
|
+
if (mention && mention.slug !== authorSlug)
|
|
11785
|
+
bySlug.set(mention.slug, mention);
|
|
11786
|
+
}
|
|
11787
|
+
return [...bySlug.values()];
|
|
11788
|
+
}
|
|
11789
|
+
function hashtagsFrom(details) {
|
|
11790
|
+
const tags = [];
|
|
11791
|
+
for (const detail of details) {
|
|
11792
|
+
const urn = detail["*hashtag"];
|
|
11793
|
+
const tag = typeof urn === "string" ? urn.match(/\(([^,]+),/)?.[1] : void 0;
|
|
11794
|
+
if (tag) tags.push(`#${tag}`);
|
|
11795
|
+
}
|
|
11796
|
+
return [...new Set(tags)];
|
|
11797
|
+
}
|
|
11798
|
+
function linksFrom(details) {
|
|
11799
|
+
const links2 = details.map((detail) => asObject(detail.textLink)?.url).filter((url) => typeof url === "string");
|
|
11800
|
+
return dedupeLinks(links2);
|
|
11801
|
+
}
|
|
11802
|
+
function collectVoyagerAttributes(update3, profiles, authorSlug) {
|
|
11803
|
+
const details = attributeDetails(update3);
|
|
11804
|
+
return {
|
|
11805
|
+
mentions: mentionsFrom(details, profiles, authorSlug),
|
|
11806
|
+
hashtags: hashtagsFrom(details),
|
|
11807
|
+
links: linksFrom(details)
|
|
11808
|
+
};
|
|
11809
|
+
}
|
|
11810
|
+
|
|
11811
|
+
// src/commands/netcap/resolveVoyagerAuthor.ts
|
|
11812
|
+
var profileUrl2 = (slug) => `https://www.linkedin.com/in/${slug}/`;
|
|
11813
|
+
function profileSlug(actor) {
|
|
11814
|
+
const target = asObject(actor?.navigationContext)?.actionTarget;
|
|
11815
|
+
if (typeof target !== "string") return void 0;
|
|
11816
|
+
return target.match(/\/in\/([^/?]+)/)?.[1];
|
|
11817
|
+
}
|
|
11818
|
+
function resolveVoyagerAuthor(update3) {
|
|
11819
|
+
const actor = asObject(update3.actor);
|
|
11820
|
+
const slug = profileSlug(actor);
|
|
11821
|
+
if (!slug) return void 0;
|
|
11822
|
+
const name = asObject(actor?.name)?.text;
|
|
11823
|
+
const mention = { slug, url: profileUrl2(slug) };
|
|
11824
|
+
if (typeof name === "string" && name.trim()) mention.name = name.trim();
|
|
11825
|
+
return mention;
|
|
11826
|
+
}
|
|
11827
|
+
|
|
11828
|
+
// src/commands/netcap/buildVoyagerPost.ts
|
|
11829
|
+
function commentaryText(update3) {
|
|
11830
|
+
const body = asObject(asObject(update3.commentary)?.text)?.text;
|
|
11831
|
+
return typeof body === "string" && body.trim() ? body.trim() : void 0;
|
|
11832
|
+
}
|
|
11833
|
+
function activityUrnOf(update3) {
|
|
11834
|
+
const urn = asObject(update3.metadata)?.backendUrn;
|
|
11835
|
+
return typeof urn === "string" ? urn : void 0;
|
|
11836
|
+
}
|
|
11837
|
+
function buildVoyagerPost(update3, profiles) {
|
|
11838
|
+
const text5 = commentaryText(update3);
|
|
11839
|
+
if (!text5) return void 0;
|
|
11840
|
+
const author = resolveVoyagerAuthor(update3);
|
|
11841
|
+
const { mentions, hashtags, links: links2 } = collectVoyagerAttributes(
|
|
11842
|
+
update3,
|
|
11843
|
+
profiles,
|
|
11844
|
+
author?.slug
|
|
11845
|
+
);
|
|
11846
|
+
const activityUrn = activityUrnOf(update3);
|
|
11847
|
+
return {
|
|
11848
|
+
text: text5,
|
|
11849
|
+
markdown: linkifyMentions(text5, mentions),
|
|
11850
|
+
mentions,
|
|
11851
|
+
hashtags,
|
|
11852
|
+
links: links2,
|
|
11853
|
+
relatedPosts: activityUrn ? [activityUrn] : [],
|
|
11854
|
+
activityUrn,
|
|
11855
|
+
postedAt: activityUrnDate(activityUrn),
|
|
11856
|
+
author
|
|
11857
|
+
};
|
|
11858
|
+
}
|
|
11859
|
+
|
|
11860
|
+
// src/commands/netcap/voyagerProfileMentions.ts
|
|
11861
|
+
var PROFILE_TYPE = "com.linkedin.voyager.dash.identity.profile.Profile";
|
|
11862
|
+
var profileUrl3 = (slug) => `https://www.linkedin.com/in/${slug}/`;
|
|
11863
|
+
function profileName(o) {
|
|
11864
|
+
return [o.firstName, o.lastName].filter((s) => typeof s === "string" && s.length > 0).join(" ");
|
|
11865
|
+
}
|
|
11866
|
+
function voyagerProfileMentions(included) {
|
|
11867
|
+
const map = /* @__PURE__ */ new Map();
|
|
11868
|
+
for (const o of included) {
|
|
11869
|
+
const urn = o.entityUrn;
|
|
11870
|
+
const slug = o.publicIdentifier;
|
|
11871
|
+
if (o.$type !== PROFILE_TYPE) continue;
|
|
11872
|
+
if (typeof urn !== "string" || typeof slug !== "string") continue;
|
|
11873
|
+
const name = profileName(o);
|
|
11874
|
+
const url = profileUrl3(slug);
|
|
11875
|
+
map.set(urn, name ? { slug, name, url } : { slug, url });
|
|
11876
|
+
}
|
|
11877
|
+
return map;
|
|
11878
|
+
}
|
|
11879
|
+
|
|
11880
|
+
// src/commands/netcap/extractVoyagerPosts.ts
|
|
11881
|
+
function includedObjects(root) {
|
|
11882
|
+
const included = root.included;
|
|
11883
|
+
if (!Array.isArray(included)) return [];
|
|
11884
|
+
return included.map((item) => asObject(item)).filter((o) => o !== void 0);
|
|
11885
|
+
}
|
|
11886
|
+
function elementUrns(root) {
|
|
11887
|
+
const data = asObject(asObject(root.data)?.data);
|
|
11888
|
+
if (!data) return [];
|
|
11889
|
+
for (const value of Object.values(data)) {
|
|
11890
|
+
const elements = asObject(value)?.["*elements"];
|
|
11891
|
+
if (Array.isArray(elements))
|
|
11892
|
+
return elements.filter((e) => typeof e === "string");
|
|
11893
|
+
}
|
|
11894
|
+
return [];
|
|
11895
|
+
}
|
|
11896
|
+
function extractVoyagerPosts(body) {
|
|
11897
|
+
let root;
|
|
11898
|
+
try {
|
|
11899
|
+
root = JSON.parse(body);
|
|
11900
|
+
} catch {
|
|
11901
|
+
return [];
|
|
11902
|
+
}
|
|
11903
|
+
const rootObj = asObject(root);
|
|
11904
|
+
if (!rootObj) return [];
|
|
11905
|
+
const included = includedObjects(rootObj);
|
|
11906
|
+
const byUrn = /* @__PURE__ */ new Map();
|
|
11907
|
+
for (const o of included) {
|
|
11908
|
+
if (typeof o.entityUrn === "string") byUrn.set(o.entityUrn, o);
|
|
11909
|
+
}
|
|
11910
|
+
const profiles = voyagerProfileMentions(included);
|
|
11911
|
+
const posts = [];
|
|
11912
|
+
for (const ref of elementUrns(rootObj)) {
|
|
11913
|
+
const update3 = byUrn.get(ref);
|
|
11914
|
+
if (!update3) continue;
|
|
11915
|
+
const post = buildVoyagerPost(update3, profiles);
|
|
11916
|
+
if (post) posts.push(post);
|
|
11917
|
+
}
|
|
11918
|
+
return posts;
|
|
11919
|
+
}
|
|
11920
|
+
|
|
11921
|
+
// src/commands/netcap/extractPostsFromCapture.ts
|
|
11922
|
+
function captureEntries(captureFile) {
|
|
11923
|
+
const lines = readFileSync30(captureFile, "utf8").split("\n").filter(Boolean);
|
|
11924
|
+
const entries = [];
|
|
11925
|
+
for (const line of lines) {
|
|
11926
|
+
let entry;
|
|
11927
|
+
try {
|
|
11928
|
+
entry = JSON.parse(line);
|
|
11929
|
+
} catch {
|
|
11930
|
+
continue;
|
|
11931
|
+
}
|
|
11932
|
+
if (typeof entry.url !== "string" || typeof entry.responseBody !== "string")
|
|
11933
|
+
continue;
|
|
11934
|
+
entries.push({ url: entry.url, responseBody: entry.responseBody });
|
|
11935
|
+
}
|
|
11936
|
+
return entries;
|
|
11937
|
+
}
|
|
11938
|
+
function dedupeByActivity(posts) {
|
|
11939
|
+
const byUrn = /* @__PURE__ */ new Map();
|
|
11940
|
+
const noUrn = [];
|
|
11941
|
+
for (const post of posts) {
|
|
11942
|
+
if (!post.activityUrn) {
|
|
11943
|
+
noUrn.push(post);
|
|
11944
|
+
continue;
|
|
11945
|
+
}
|
|
11946
|
+
const existing = byUrn.get(post.activityUrn);
|
|
11947
|
+
if (!existing || post.text.length > existing.text.length)
|
|
11948
|
+
byUrn.set(post.activityUrn, post);
|
|
11949
|
+
}
|
|
11950
|
+
return [...byUrn.values(), ...noUrn];
|
|
11951
|
+
}
|
|
11952
|
+
function extractPostsFromCapture(captureFile) {
|
|
11953
|
+
const entries = captureEntries(captureFile);
|
|
11954
|
+
const rscBodies = entries.filter((e) => /rsc-action/.test(e.url)).map((e) => e.responseBody);
|
|
11955
|
+
const voyagerBodies = entries.filter((e) => /voyagerFeedDashProfileUpdates/.test(e.url)).map((e) => e.responseBody);
|
|
11956
|
+
const author = rscBodies.map(findAuthorSlug).find(Boolean);
|
|
11957
|
+
const all = [
|
|
11958
|
+
...rscBodies.flatMap((body) => extractLinkedInPosts(body, author)),
|
|
11959
|
+
...voyagerBodies.flatMap(extractVoyagerPosts)
|
|
11960
|
+
];
|
|
11961
|
+
return dedupeByActivity(all);
|
|
11962
|
+
}
|
|
11963
|
+
|
|
11964
|
+
// src/commands/netcap/netcapExtract.ts
|
|
11965
|
+
function netcapExtract(file) {
|
|
11966
|
+
const captureFile = file ?? defaultCapturePath();
|
|
11967
|
+
const posts = extractPostsFromCapture(captureFile);
|
|
11968
|
+
const outFile = join38(captureFile, "..", "posts.json");
|
|
11969
|
+
writeFileSync26(outFile, `${JSON.stringify(posts, null, 2)}
|
|
11970
|
+
`);
|
|
11971
|
+
console.log(
|
|
11972
|
+
chalk125.green(`extracted ${posts.length} posts`),
|
|
11973
|
+
chalk125.dim(`-> ${outFile}`)
|
|
11974
|
+
);
|
|
11975
|
+
}
|
|
11976
|
+
|
|
11977
|
+
// src/commands/registerNetcap.ts
|
|
11978
|
+
function registerNetcap(program2) {
|
|
11979
|
+
const command = program2.command("netcap").description(
|
|
11980
|
+
"Start a local receiver that captures browser network traffic (fetch/XHR) to a JSONL file via the netcap browser extension"
|
|
11981
|
+
).option("-p, --port <port>", "Port to listen on", "8723").option(
|
|
11982
|
+
"-o, --out <dir>",
|
|
11983
|
+
"Directory to write the capture file into (default ~/.assist/netcap)"
|
|
11984
|
+
).option(
|
|
11985
|
+
"-f, --filter <pattern>",
|
|
11986
|
+
"Only forward requests whose URL contains this substring"
|
|
11987
|
+
).action((options2) => netcap(options2));
|
|
11988
|
+
command.command("extract [file]").description(
|
|
11989
|
+
"Extract LinkedIn posts (text, author, mentions, links) from a netcap capture file to posts.json"
|
|
11990
|
+
).action((file) => netcapExtract(file));
|
|
11991
|
+
}
|
|
11992
|
+
|
|
11993
|
+
// src/commands/news/add/index.ts
|
|
11994
|
+
import chalk126 from "chalk";
|
|
11361
11995
|
import enquirer8 from "enquirer";
|
|
11362
11996
|
async function add2(url) {
|
|
11363
11997
|
if (!url) {
|
|
@@ -11379,10 +12013,10 @@ async function add2(url) {
|
|
|
11379
12013
|
const { orm } = await getReady();
|
|
11380
12014
|
const added = await addFeed(orm, url);
|
|
11381
12015
|
if (!added) {
|
|
11382
|
-
console.log(
|
|
12016
|
+
console.log(chalk126.yellow("Feed already exists"));
|
|
11383
12017
|
return;
|
|
11384
12018
|
}
|
|
11385
|
-
console.log(
|
|
12019
|
+
console.log(chalk126.green(`Added feed: ${url}`));
|
|
11386
12020
|
}
|
|
11387
12021
|
|
|
11388
12022
|
// src/commands/registerNews.ts
|
|
@@ -11392,7 +12026,7 @@ function registerNews(program2) {
|
|
|
11392
12026
|
}
|
|
11393
12027
|
|
|
11394
12028
|
// src/commands/prompts/printPromptsTable.ts
|
|
11395
|
-
import
|
|
12029
|
+
import chalk127 from "chalk";
|
|
11396
12030
|
function truncate(str, max) {
|
|
11397
12031
|
if (str.length <= max) return str;
|
|
11398
12032
|
return `${str.slice(0, max - 1)}\u2026`;
|
|
@@ -11410,14 +12044,14 @@ function printPromptsTable(rows) {
|
|
|
11410
12044
|
"Command".padEnd(commandWidth),
|
|
11411
12045
|
"Repos"
|
|
11412
12046
|
].join(" ");
|
|
11413
|
-
console.log(
|
|
11414
|
-
console.log(
|
|
12047
|
+
console.log(chalk127.dim(header));
|
|
12048
|
+
console.log(chalk127.dim("-".repeat(header.length)));
|
|
11415
12049
|
for (const row of rows) {
|
|
11416
12050
|
const count6 = String(row.count).padStart(countWidth);
|
|
11417
12051
|
const tool = row.tool.padEnd(toolWidth);
|
|
11418
12052
|
const command = truncate(row.command, 60).padEnd(commandWidth);
|
|
11419
12053
|
console.log(
|
|
11420
|
-
`${
|
|
12054
|
+
`${chalk127.yellow(count6)} ${tool} ${command} ${chalk127.dim(row.repos)}`
|
|
11421
12055
|
);
|
|
11422
12056
|
}
|
|
11423
12057
|
}
|
|
@@ -11765,23 +12399,23 @@ import { execSync as execSync33 } from "child_process";
|
|
|
11765
12399
|
|
|
11766
12400
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
11767
12401
|
import { execSync as execSync32 } from "child_process";
|
|
11768
|
-
import { unlinkSync as unlinkSync10, writeFileSync as
|
|
12402
|
+
import { unlinkSync as unlinkSync10, writeFileSync as writeFileSync27 } from "fs";
|
|
11769
12403
|
import { tmpdir as tmpdir5 } from "os";
|
|
11770
|
-
import { join as
|
|
12404
|
+
import { join as join40 } from "path";
|
|
11771
12405
|
|
|
11772
12406
|
// src/commands/prs/loadCommentsCache.ts
|
|
11773
|
-
import { existsSync as existsSync33, readFileSync as
|
|
11774
|
-
import { join as
|
|
12407
|
+
import { existsSync as existsSync33, readFileSync as readFileSync31, unlinkSync as unlinkSync9 } from "fs";
|
|
12408
|
+
import { join as join39 } from "path";
|
|
11775
12409
|
import { parse as parse2 } from "yaml";
|
|
11776
12410
|
function getCachePath(prNumber) {
|
|
11777
|
-
return
|
|
12411
|
+
return join39(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
|
|
11778
12412
|
}
|
|
11779
12413
|
function loadCommentsCache(prNumber) {
|
|
11780
12414
|
const cachePath = getCachePath(prNumber);
|
|
11781
12415
|
if (!existsSync33(cachePath)) {
|
|
11782
12416
|
return null;
|
|
11783
12417
|
}
|
|
11784
|
-
const content =
|
|
12418
|
+
const content = readFileSync31(cachePath, "utf8");
|
|
11785
12419
|
return parse2(content);
|
|
11786
12420
|
}
|
|
11787
12421
|
function deleteCommentsCache(prNumber) {
|
|
@@ -11801,8 +12435,8 @@ function replyToComment(org, repo, prNumber, commentId, message) {
|
|
|
11801
12435
|
}
|
|
11802
12436
|
function resolveThread(threadId) {
|
|
11803
12437
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
11804
|
-
const queryFile =
|
|
11805
|
-
|
|
12438
|
+
const queryFile = join40(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
|
|
12439
|
+
writeFileSync27(queryFile, mutation);
|
|
11806
12440
|
try {
|
|
11807
12441
|
execSync32(
|
|
11808
12442
|
`gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
|
|
@@ -11883,19 +12517,19 @@ function fixed(commentId, sha) {
|
|
|
11883
12517
|
}
|
|
11884
12518
|
|
|
11885
12519
|
// src/commands/prs/listComments/index.ts
|
|
11886
|
-
import { existsSync as existsSync34, mkdirSync as mkdirSync13, writeFileSync as
|
|
11887
|
-
import { join as
|
|
12520
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync13, writeFileSync as writeFileSync29 } from "fs";
|
|
12521
|
+
import { join as join42 } from "path";
|
|
11888
12522
|
import { stringify } from "yaml";
|
|
11889
12523
|
|
|
11890
12524
|
// src/commands/prs/fetchThreadIds.ts
|
|
11891
12525
|
import { execSync as execSync34 } from "child_process";
|
|
11892
|
-
import { unlinkSync as unlinkSync11, writeFileSync as
|
|
12526
|
+
import { unlinkSync as unlinkSync11, writeFileSync as writeFileSync28 } from "fs";
|
|
11893
12527
|
import { tmpdir as tmpdir6 } from "os";
|
|
11894
|
-
import { join as
|
|
12528
|
+
import { join as join41 } from "path";
|
|
11895
12529
|
var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
|
|
11896
12530
|
function fetchThreadIds(org, repo, prNumber) {
|
|
11897
|
-
const queryFile =
|
|
11898
|
-
|
|
12531
|
+
const queryFile = join41(tmpdir6(), `gh-query-${Date.now()}.graphql`);
|
|
12532
|
+
writeFileSync28(queryFile, THREAD_QUERY);
|
|
11899
12533
|
try {
|
|
11900
12534
|
const result = execSync34(
|
|
11901
12535
|
`gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
|
|
@@ -11963,20 +12597,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
11963
12597
|
}
|
|
11964
12598
|
|
|
11965
12599
|
// src/commands/prs/listComments/printComments.ts
|
|
11966
|
-
import
|
|
12600
|
+
import chalk128 from "chalk";
|
|
11967
12601
|
function formatForHuman(comment3) {
|
|
11968
12602
|
if (comment3.type === "review") {
|
|
11969
|
-
const stateColor = comment3.state === "APPROVED" ?
|
|
12603
|
+
const stateColor = comment3.state === "APPROVED" ? chalk128.green : comment3.state === "CHANGES_REQUESTED" ? chalk128.red : chalk128.yellow;
|
|
11970
12604
|
return [
|
|
11971
|
-
`${
|
|
12605
|
+
`${chalk128.cyan("Review")} by ${chalk128.bold(comment3.user)} ${stateColor(`[${comment3.state}]`)}`,
|
|
11972
12606
|
comment3.body,
|
|
11973
12607
|
""
|
|
11974
12608
|
].join("\n");
|
|
11975
12609
|
}
|
|
11976
12610
|
const location = comment3.line ? `:${comment3.line}` : "";
|
|
11977
12611
|
return [
|
|
11978
|
-
`${
|
|
11979
|
-
|
|
12612
|
+
`${chalk128.cyan("Line comment")} by ${chalk128.bold(comment3.user)} on ${chalk128.dim(`${comment3.path}${location}`)}`,
|
|
12613
|
+
chalk128.dim(comment3.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
11980
12614
|
comment3.body,
|
|
11981
12615
|
""
|
|
11982
12616
|
].join("\n");
|
|
@@ -12008,7 +12642,7 @@ function printComments2(result) {
|
|
|
12008
12642
|
|
|
12009
12643
|
// src/commands/prs/listComments/index.ts
|
|
12010
12644
|
function writeCommentsCache(prNumber, comments3) {
|
|
12011
|
-
const assistDir =
|
|
12645
|
+
const assistDir = join42(process.cwd(), ".assist");
|
|
12012
12646
|
if (!existsSync34(assistDir)) {
|
|
12013
12647
|
mkdirSync13(assistDir, { recursive: true });
|
|
12014
12648
|
}
|
|
@@ -12017,8 +12651,8 @@ function writeCommentsCache(prNumber, comments3) {
|
|
|
12017
12651
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12018
12652
|
comments: comments3
|
|
12019
12653
|
};
|
|
12020
|
-
const cachePath =
|
|
12021
|
-
|
|
12654
|
+
const cachePath = join42(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
12655
|
+
writeFileSync29(cachePath, stringify(cacheData));
|
|
12022
12656
|
}
|
|
12023
12657
|
function handleKnownErrors(error) {
|
|
12024
12658
|
if (isGhNotInstalled(error)) {
|
|
@@ -12050,7 +12684,7 @@ async function listComments() {
|
|
|
12050
12684
|
];
|
|
12051
12685
|
updateCache(prNumber, allComments);
|
|
12052
12686
|
const hasLineComments = allComments.some((c) => c.type === "line");
|
|
12053
|
-
const cachePath = hasLineComments ?
|
|
12687
|
+
const cachePath = hasLineComments ? join42(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
|
|
12054
12688
|
return { comments: allComments, cachePath };
|
|
12055
12689
|
} catch (error) {
|
|
12056
12690
|
const handled = handleKnownErrors(error);
|
|
@@ -12066,13 +12700,13 @@ import { execSync as execSync36 } from "child_process";
|
|
|
12066
12700
|
import enquirer9 from "enquirer";
|
|
12067
12701
|
|
|
12068
12702
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
12069
|
-
import
|
|
12703
|
+
import chalk129 from "chalk";
|
|
12070
12704
|
var STATUS_MAP = {
|
|
12071
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
12072
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
12705
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk129.magenta("merged"), date: pr.mergedAt } : null,
|
|
12706
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk129.red("closed"), date: pr.closedAt } : null
|
|
12073
12707
|
};
|
|
12074
12708
|
function defaultStatus(pr) {
|
|
12075
|
-
return { label:
|
|
12709
|
+
return { label: chalk129.green("opened"), date: pr.createdAt };
|
|
12076
12710
|
}
|
|
12077
12711
|
function getStatus2(pr) {
|
|
12078
12712
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -12081,11 +12715,11 @@ function formatDate(dateStr) {
|
|
|
12081
12715
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
12082
12716
|
}
|
|
12083
12717
|
function formatPrHeader(pr, status2) {
|
|
12084
|
-
return `${
|
|
12718
|
+
return `${chalk129.cyan(`#${pr.number}`)} ${pr.title} ${chalk129.dim(`(${pr.author.login},`)} ${status2.label} ${chalk129.dim(`${formatDate(status2.date)})`)}`;
|
|
12085
12719
|
}
|
|
12086
12720
|
function logPrDetails(pr) {
|
|
12087
12721
|
console.log(
|
|
12088
|
-
|
|
12722
|
+
chalk129.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
12089
12723
|
);
|
|
12090
12724
|
console.log();
|
|
12091
12725
|
}
|
|
@@ -12364,10 +12998,10 @@ function registerPrs(program2) {
|
|
|
12364
12998
|
}
|
|
12365
12999
|
|
|
12366
13000
|
// src/commands/ravendb/ravendbAuth.ts
|
|
12367
|
-
import
|
|
13001
|
+
import chalk135 from "chalk";
|
|
12368
13002
|
|
|
12369
13003
|
// src/shared/createConnectionAuth.ts
|
|
12370
|
-
import
|
|
13004
|
+
import chalk130 from "chalk";
|
|
12371
13005
|
function listConnections(connections, format2) {
|
|
12372
13006
|
if (connections.length === 0) {
|
|
12373
13007
|
console.log("No connections configured.");
|
|
@@ -12380,7 +13014,7 @@ function listConnections(connections, format2) {
|
|
|
12380
13014
|
function removeConnection(connections, name, save) {
|
|
12381
13015
|
const filtered = connections.filter((c) => c.name !== name);
|
|
12382
13016
|
if (filtered.length === connections.length) {
|
|
12383
|
-
console.error(
|
|
13017
|
+
console.error(chalk130.red(`Connection "${name}" not found.`));
|
|
12384
13018
|
process.exit(1);
|
|
12385
13019
|
}
|
|
12386
13020
|
save(filtered);
|
|
@@ -12426,15 +13060,15 @@ function saveConnections(connections) {
|
|
|
12426
13060
|
}
|
|
12427
13061
|
|
|
12428
13062
|
// src/commands/ravendb/promptConnection.ts
|
|
12429
|
-
import
|
|
13063
|
+
import chalk133 from "chalk";
|
|
12430
13064
|
|
|
12431
13065
|
// src/commands/ravendb/selectOpSecret.ts
|
|
12432
|
-
import
|
|
13066
|
+
import chalk132 from "chalk";
|
|
12433
13067
|
import Enquirer2 from "enquirer";
|
|
12434
13068
|
|
|
12435
13069
|
// src/commands/ravendb/searchItems.ts
|
|
12436
13070
|
import { execSync as execSync39 } from "child_process";
|
|
12437
|
-
import
|
|
13071
|
+
import chalk131 from "chalk";
|
|
12438
13072
|
function opExec(args) {
|
|
12439
13073
|
return execSync39(`op ${args}`, {
|
|
12440
13074
|
encoding: "utf8",
|
|
@@ -12447,7 +13081,7 @@ function searchItems(search2) {
|
|
|
12447
13081
|
items2 = JSON.parse(opExec("item list --format=json"));
|
|
12448
13082
|
} catch {
|
|
12449
13083
|
console.error(
|
|
12450
|
-
|
|
13084
|
+
chalk131.red(
|
|
12451
13085
|
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
12452
13086
|
)
|
|
12453
13087
|
);
|
|
@@ -12461,7 +13095,7 @@ function getItemFields(itemId) {
|
|
|
12461
13095
|
const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
|
|
12462
13096
|
return item.fields.filter((f) => f.reference && f.label);
|
|
12463
13097
|
} catch {
|
|
12464
|
-
console.error(
|
|
13098
|
+
console.error(chalk131.red("Failed to get item details from 1Password."));
|
|
12465
13099
|
process.exit(1);
|
|
12466
13100
|
}
|
|
12467
13101
|
}
|
|
@@ -12480,7 +13114,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
12480
13114
|
}).run();
|
|
12481
13115
|
const items2 = searchItems(search2);
|
|
12482
13116
|
if (items2.length === 0) {
|
|
12483
|
-
console.error(
|
|
13117
|
+
console.error(chalk132.red(`No items found matching "${search2}".`));
|
|
12484
13118
|
process.exit(1);
|
|
12485
13119
|
}
|
|
12486
13120
|
const itemId = await selectOne(
|
|
@@ -12489,7 +13123,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
12489
13123
|
);
|
|
12490
13124
|
const fields = getItemFields(itemId);
|
|
12491
13125
|
if (fields.length === 0) {
|
|
12492
|
-
console.error(
|
|
13126
|
+
console.error(chalk132.red("No fields with references found on this item."));
|
|
12493
13127
|
process.exit(1);
|
|
12494
13128
|
}
|
|
12495
13129
|
const ref = await selectOne(
|
|
@@ -12503,7 +13137,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
12503
13137
|
async function promptConnection(existingNames) {
|
|
12504
13138
|
const name = await promptInput("name", "Connection name:");
|
|
12505
13139
|
if (existingNames.includes(name)) {
|
|
12506
|
-
console.error(
|
|
13140
|
+
console.error(chalk133.red(`Connection "${name}" already exists.`));
|
|
12507
13141
|
process.exit(1);
|
|
12508
13142
|
}
|
|
12509
13143
|
const url = await promptInput(
|
|
@@ -12512,22 +13146,22 @@ async function promptConnection(existingNames) {
|
|
|
12512
13146
|
);
|
|
12513
13147
|
const database = await promptInput("database", "Database name:");
|
|
12514
13148
|
if (!name || !url || !database) {
|
|
12515
|
-
console.error(
|
|
13149
|
+
console.error(chalk133.red("All fields are required."));
|
|
12516
13150
|
process.exit(1);
|
|
12517
13151
|
}
|
|
12518
13152
|
const apiKeyRef = await selectOpSecret();
|
|
12519
|
-
console.log(
|
|
13153
|
+
console.log(chalk133.dim(`Using: ${apiKeyRef}`));
|
|
12520
13154
|
return { name, url, database, apiKeyRef };
|
|
12521
13155
|
}
|
|
12522
13156
|
|
|
12523
13157
|
// src/commands/ravendb/ravendbSetConnection.ts
|
|
12524
|
-
import
|
|
13158
|
+
import chalk134 from "chalk";
|
|
12525
13159
|
function ravendbSetConnection(name) {
|
|
12526
13160
|
const raw = loadGlobalConfigRaw();
|
|
12527
13161
|
const ravendb = raw.ravendb ?? {};
|
|
12528
13162
|
const connections = ravendb.connections ?? [];
|
|
12529
13163
|
if (!connections.some((c) => c.name === name)) {
|
|
12530
|
-
console.error(
|
|
13164
|
+
console.error(chalk134.red(`Connection "${name}" not found.`));
|
|
12531
13165
|
console.error(
|
|
12532
13166
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
12533
13167
|
);
|
|
@@ -12543,16 +13177,16 @@ function ravendbSetConnection(name) {
|
|
|
12543
13177
|
var ravendbAuth = createConnectionAuth({
|
|
12544
13178
|
load: loadConnections,
|
|
12545
13179
|
save: saveConnections,
|
|
12546
|
-
format: (c) => `${
|
|
13180
|
+
format: (c) => `${chalk135.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
|
|
12547
13181
|
promptNew: promptConnection,
|
|
12548
13182
|
onFirst: (c) => ravendbSetConnection(c.name)
|
|
12549
13183
|
});
|
|
12550
13184
|
|
|
12551
13185
|
// src/commands/ravendb/ravendbCollections.ts
|
|
12552
|
-
import
|
|
13186
|
+
import chalk139 from "chalk";
|
|
12553
13187
|
|
|
12554
13188
|
// src/commands/ravendb/ravenFetch.ts
|
|
12555
|
-
import
|
|
13189
|
+
import chalk137 from "chalk";
|
|
12556
13190
|
|
|
12557
13191
|
// src/commands/ravendb/getAccessToken.ts
|
|
12558
13192
|
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
@@ -12589,10 +13223,10 @@ ${errorText}`
|
|
|
12589
13223
|
|
|
12590
13224
|
// src/commands/ravendb/resolveOpSecret.ts
|
|
12591
13225
|
import { execSync as execSync40 } from "child_process";
|
|
12592
|
-
import
|
|
13226
|
+
import chalk136 from "chalk";
|
|
12593
13227
|
function resolveOpSecret(reference) {
|
|
12594
13228
|
if (!reference.startsWith("op://")) {
|
|
12595
|
-
console.error(
|
|
13229
|
+
console.error(chalk136.red(`Invalid secret reference: must start with op://`));
|
|
12596
13230
|
process.exit(1);
|
|
12597
13231
|
}
|
|
12598
13232
|
try {
|
|
@@ -12602,7 +13236,7 @@ function resolveOpSecret(reference) {
|
|
|
12602
13236
|
}).trim();
|
|
12603
13237
|
} catch {
|
|
12604
13238
|
console.error(
|
|
12605
|
-
|
|
13239
|
+
chalk136.red(
|
|
12606
13240
|
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
12607
13241
|
)
|
|
12608
13242
|
);
|
|
@@ -12629,7 +13263,7 @@ async function ravenFetch(connection, path58) {
|
|
|
12629
13263
|
if (!response.ok) {
|
|
12630
13264
|
const body = await response.text();
|
|
12631
13265
|
console.error(
|
|
12632
|
-
|
|
13266
|
+
chalk137.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
12633
13267
|
);
|
|
12634
13268
|
console.error(body.substring(0, 500));
|
|
12635
13269
|
process.exit(1);
|
|
@@ -12638,7 +13272,7 @@ async function ravenFetch(connection, path58) {
|
|
|
12638
13272
|
}
|
|
12639
13273
|
|
|
12640
13274
|
// src/commands/ravendb/resolveConnection.ts
|
|
12641
|
-
import
|
|
13275
|
+
import chalk138 from "chalk";
|
|
12642
13276
|
function loadRavendb() {
|
|
12643
13277
|
const raw = loadGlobalConfigRaw();
|
|
12644
13278
|
const ravendb = raw.ravendb;
|
|
@@ -12652,7 +13286,7 @@ function resolveConnection(name) {
|
|
|
12652
13286
|
const connectionName = name ?? defaultConnection;
|
|
12653
13287
|
if (!connectionName) {
|
|
12654
13288
|
console.error(
|
|
12655
|
-
|
|
13289
|
+
chalk138.red(
|
|
12656
13290
|
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
12657
13291
|
)
|
|
12658
13292
|
);
|
|
@@ -12660,7 +13294,7 @@ function resolveConnection(name) {
|
|
|
12660
13294
|
}
|
|
12661
13295
|
const connection = connections.find((c) => c.name === connectionName);
|
|
12662
13296
|
if (!connection) {
|
|
12663
|
-
console.error(
|
|
13297
|
+
console.error(chalk138.red(`Connection "${connectionName}" not found.`));
|
|
12664
13298
|
console.error(
|
|
12665
13299
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
12666
13300
|
);
|
|
@@ -12691,15 +13325,15 @@ async function ravendbCollections(connectionName) {
|
|
|
12691
13325
|
return;
|
|
12692
13326
|
}
|
|
12693
13327
|
for (const c of collections) {
|
|
12694
|
-
console.log(`${
|
|
13328
|
+
console.log(`${chalk139.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
12695
13329
|
}
|
|
12696
13330
|
}
|
|
12697
13331
|
|
|
12698
13332
|
// src/commands/ravendb/ravendbQuery.ts
|
|
12699
|
-
import
|
|
13333
|
+
import chalk141 from "chalk";
|
|
12700
13334
|
|
|
12701
13335
|
// src/commands/ravendb/fetchAllPages.ts
|
|
12702
|
-
import
|
|
13336
|
+
import chalk140 from "chalk";
|
|
12703
13337
|
|
|
12704
13338
|
// src/commands/ravendb/buildQueryPath.ts
|
|
12705
13339
|
function buildQueryPath(opts) {
|
|
@@ -12737,7 +13371,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
12737
13371
|
allResults.push(...results);
|
|
12738
13372
|
start3 += results.length;
|
|
12739
13373
|
process.stderr.write(
|
|
12740
|
-
`\r${
|
|
13374
|
+
`\r${chalk140.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
12741
13375
|
);
|
|
12742
13376
|
if (start3 >= totalResults) break;
|
|
12743
13377
|
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
@@ -12752,7 +13386,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
12752
13386
|
async function ravendbQuery(connectionName, collection, options2) {
|
|
12753
13387
|
const resolved = resolveArgs(connectionName, collection);
|
|
12754
13388
|
if (!resolved.collection && !options2.query) {
|
|
12755
|
-
console.error(
|
|
13389
|
+
console.error(chalk141.red("Provide a collection name or --query filter."));
|
|
12756
13390
|
process.exit(1);
|
|
12757
13391
|
}
|
|
12758
13392
|
const { collection: col } = resolved;
|
|
@@ -12790,7 +13424,7 @@ import { spawn as spawn5 } from "child_process";
|
|
|
12790
13424
|
import * as path28 from "path";
|
|
12791
13425
|
|
|
12792
13426
|
// src/commands/refactor/logViolations.ts
|
|
12793
|
-
import
|
|
13427
|
+
import chalk142 from "chalk";
|
|
12794
13428
|
var DEFAULT_MAX_LINES = 100;
|
|
12795
13429
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
12796
13430
|
if (violations.length === 0) {
|
|
@@ -12799,43 +13433,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
12799
13433
|
}
|
|
12800
13434
|
return;
|
|
12801
13435
|
}
|
|
12802
|
-
console.error(
|
|
13436
|
+
console.error(chalk142.red(`
|
|
12803
13437
|
Refactor check failed:
|
|
12804
13438
|
`));
|
|
12805
|
-
console.error(
|
|
13439
|
+
console.error(chalk142.red(` The following files exceed ${maxLines} lines:
|
|
12806
13440
|
`));
|
|
12807
13441
|
for (const violation of violations) {
|
|
12808
|
-
console.error(
|
|
13442
|
+
console.error(chalk142.red(` ${violation.file} (${violation.lines} lines)`));
|
|
12809
13443
|
}
|
|
12810
13444
|
console.error(
|
|
12811
|
-
|
|
13445
|
+
chalk142.yellow(
|
|
12812
13446
|
`
|
|
12813
13447
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
12814
13448
|
way to refactor it, ignore it with:
|
|
12815
13449
|
`
|
|
12816
13450
|
)
|
|
12817
13451
|
);
|
|
12818
|
-
console.error(
|
|
13452
|
+
console.error(chalk142.gray(` assist refactor ignore <file>
|
|
12819
13453
|
`));
|
|
12820
13454
|
if (process.env.CLAUDECODE) {
|
|
12821
|
-
console.error(
|
|
13455
|
+
console.error(chalk142.cyan(`
|
|
12822
13456
|
## Extracting Code to New Files
|
|
12823
13457
|
`));
|
|
12824
13458
|
console.error(
|
|
12825
|
-
|
|
13459
|
+
chalk142.cyan(
|
|
12826
13460
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
12827
13461
|
`
|
|
12828
13462
|
)
|
|
12829
13463
|
);
|
|
12830
13464
|
console.error(
|
|
12831
|
-
|
|
13465
|
+
chalk142.cyan(
|
|
12832
13466
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
12833
13467
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
12834
13468
|
`
|
|
12835
13469
|
)
|
|
12836
13470
|
);
|
|
12837
13471
|
console.error(
|
|
12838
|
-
|
|
13472
|
+
chalk142.cyan(
|
|
12839
13473
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
12840
13474
|
domains, move it to a common/shared folder.
|
|
12841
13475
|
`
|
|
@@ -12933,7 +13567,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
|
|
|
12933
13567
|
|
|
12934
13568
|
// src/commands/refactor/check/index.ts
|
|
12935
13569
|
function runScript(script, cwd) {
|
|
12936
|
-
return new Promise((
|
|
13570
|
+
return new Promise((resolve17) => {
|
|
12937
13571
|
const child = spawn5("npm", ["run", script], {
|
|
12938
13572
|
stdio: "pipe",
|
|
12939
13573
|
shell: true,
|
|
@@ -12947,7 +13581,7 @@ function runScript(script, cwd) {
|
|
|
12947
13581
|
output += data.toString();
|
|
12948
13582
|
});
|
|
12949
13583
|
child.on("close", (code) => {
|
|
12950
|
-
|
|
13584
|
+
resolve17({ script, code: code ?? 1, output });
|
|
12951
13585
|
});
|
|
12952
13586
|
});
|
|
12953
13587
|
}
|
|
@@ -12991,7 +13625,7 @@ async function check(pattern2, options2) {
|
|
|
12991
13625
|
|
|
12992
13626
|
// src/commands/refactor/extract/index.ts
|
|
12993
13627
|
import path35 from "path";
|
|
12994
|
-
import
|
|
13628
|
+
import chalk145 from "chalk";
|
|
12995
13629
|
|
|
12996
13630
|
// src/commands/refactor/extract/applyExtraction.ts
|
|
12997
13631
|
import { SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
@@ -13566,23 +14200,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
|
|
|
13566
14200
|
|
|
13567
14201
|
// src/commands/refactor/extract/displayPlan.ts
|
|
13568
14202
|
import path32 from "path";
|
|
13569
|
-
import
|
|
14203
|
+
import chalk143 from "chalk";
|
|
13570
14204
|
function section(title) {
|
|
13571
14205
|
return `
|
|
13572
|
-
${
|
|
14206
|
+
${chalk143.cyan(title)}`;
|
|
13573
14207
|
}
|
|
13574
14208
|
function displayImporters(plan2, cwd) {
|
|
13575
14209
|
if (plan2.importersToUpdate.length === 0) return;
|
|
13576
14210
|
console.log(section("Update importers:"));
|
|
13577
14211
|
for (const imp of plan2.importersToUpdate) {
|
|
13578
14212
|
const rel = path32.relative(cwd, imp.file.getFilePath());
|
|
13579
|
-
console.log(` ${
|
|
14213
|
+
console.log(` ${chalk143.dim(rel)}: \u2192 import from "${imp.relPath}"`);
|
|
13580
14214
|
}
|
|
13581
14215
|
}
|
|
13582
14216
|
function displayPlan(functionName, relDest, plan2, cwd) {
|
|
13583
|
-
console.log(
|
|
14217
|
+
console.log(chalk143.bold(`Extract: ${functionName} \u2192 ${relDest}
|
|
13584
14218
|
`));
|
|
13585
|
-
console.log(` ${
|
|
14219
|
+
console.log(` ${chalk143.cyan("Functions to move:")}`);
|
|
13586
14220
|
for (const name of plan2.extractedNames) {
|
|
13587
14221
|
console.log(` ${name}`);
|
|
13588
14222
|
}
|
|
@@ -13616,7 +14250,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
|
|
|
13616
14250
|
|
|
13617
14251
|
// src/commands/refactor/extract/loadProjectFile.ts
|
|
13618
14252
|
import path34 from "path";
|
|
13619
|
-
import
|
|
14253
|
+
import chalk144 from "chalk";
|
|
13620
14254
|
import { Project as Project4 } from "ts-morph";
|
|
13621
14255
|
|
|
13622
14256
|
// src/commands/refactor/extract/findTsConfig.ts
|
|
@@ -13676,7 +14310,7 @@ function loadProjectFile(file) {
|
|
|
13676
14310
|
});
|
|
13677
14311
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
13678
14312
|
if (!sourceFile) {
|
|
13679
|
-
console.log(
|
|
14313
|
+
console.log(chalk144.red(`File not found in project: ${file}`));
|
|
13680
14314
|
process.exit(1);
|
|
13681
14315
|
}
|
|
13682
14316
|
return { project, sourceFile };
|
|
@@ -13699,19 +14333,19 @@ async function extract(file, functionName, destination, options2 = {}) {
|
|
|
13699
14333
|
displayPlan(functionName, relDest, plan2, cwd);
|
|
13700
14334
|
if (options2.apply) {
|
|
13701
14335
|
await applyExtraction(functionName, sourceFile, destPath, plan2, project);
|
|
13702
|
-
console.log(
|
|
14336
|
+
console.log(chalk145.green("\nExtraction complete"));
|
|
13703
14337
|
} else {
|
|
13704
|
-
console.log(
|
|
14338
|
+
console.log(chalk145.dim("\nDry run. Use --apply to execute."));
|
|
13705
14339
|
}
|
|
13706
14340
|
}
|
|
13707
14341
|
|
|
13708
14342
|
// src/commands/refactor/ignore.ts
|
|
13709
14343
|
import fs22 from "fs";
|
|
13710
|
-
import
|
|
14344
|
+
import chalk146 from "chalk";
|
|
13711
14345
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
13712
14346
|
function ignore(file) {
|
|
13713
14347
|
if (!fs22.existsSync(file)) {
|
|
13714
|
-
console.error(
|
|
14348
|
+
console.error(chalk146.red(`Error: File does not exist: ${file}`));
|
|
13715
14349
|
process.exit(1);
|
|
13716
14350
|
}
|
|
13717
14351
|
const content = fs22.readFileSync(file, "utf8");
|
|
@@ -13727,7 +14361,7 @@ function ignore(file) {
|
|
|
13727
14361
|
fs22.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
13728
14362
|
}
|
|
13729
14363
|
console.log(
|
|
13730
|
-
|
|
14364
|
+
chalk146.green(
|
|
13731
14365
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
13732
14366
|
)
|
|
13733
14367
|
);
|
|
@@ -13736,12 +14370,12 @@ function ignore(file) {
|
|
|
13736
14370
|
// src/commands/refactor/rename/index.ts
|
|
13737
14371
|
import fs25 from "fs";
|
|
13738
14372
|
import path40 from "path";
|
|
13739
|
-
import
|
|
14373
|
+
import chalk149 from "chalk";
|
|
13740
14374
|
|
|
13741
14375
|
// src/commands/refactor/rename/applyRename.ts
|
|
13742
14376
|
import fs24 from "fs";
|
|
13743
14377
|
import path37 from "path";
|
|
13744
|
-
import
|
|
14378
|
+
import chalk147 from "chalk";
|
|
13745
14379
|
|
|
13746
14380
|
// src/commands/refactor/restructure/computeRewrites/index.ts
|
|
13747
14381
|
import path36 from "path";
|
|
@@ -13846,13 +14480,13 @@ function applyRename(rewrites, sourcePath, destPath, cwd) {
|
|
|
13846
14480
|
const updatedContents = applyRewrites(rewrites);
|
|
13847
14481
|
for (const [file, content] of updatedContents) {
|
|
13848
14482
|
fs24.writeFileSync(file, content, "utf8");
|
|
13849
|
-
console.log(
|
|
14483
|
+
console.log(chalk147.cyan(` Updated imports in ${path37.relative(cwd, file)}`));
|
|
13850
14484
|
}
|
|
13851
14485
|
const destDir = path37.dirname(destPath);
|
|
13852
14486
|
if (!fs24.existsSync(destDir)) fs24.mkdirSync(destDir, { recursive: true });
|
|
13853
14487
|
fs24.renameSync(sourcePath, destPath);
|
|
13854
14488
|
console.log(
|
|
13855
|
-
|
|
14489
|
+
chalk147.white(
|
|
13856
14490
|
` Moved ${path37.relative(cwd, sourcePath)} \u2192 ${path37.relative(cwd, destPath)}`
|
|
13857
14491
|
)
|
|
13858
14492
|
);
|
|
@@ -13939,16 +14573,16 @@ function computeRenameRewrites(sourcePath, destPath) {
|
|
|
13939
14573
|
|
|
13940
14574
|
// src/commands/refactor/rename/printRenamePreview.ts
|
|
13941
14575
|
import path39 from "path";
|
|
13942
|
-
import
|
|
14576
|
+
import chalk148 from "chalk";
|
|
13943
14577
|
function printRenamePreview(rewrites, cwd) {
|
|
13944
14578
|
for (const rewrite of rewrites) {
|
|
13945
14579
|
console.log(
|
|
13946
|
-
|
|
14580
|
+
chalk148.dim(
|
|
13947
14581
|
` ${path39.relative(cwd, rewrite.file)}: ${rewrite.oldSpecifier} \u2192 ${rewrite.newSpecifier}`
|
|
13948
14582
|
)
|
|
13949
14583
|
);
|
|
13950
14584
|
}
|
|
13951
|
-
console.log(
|
|
14585
|
+
console.log(chalk148.dim("Dry run. Use --apply to execute."));
|
|
13952
14586
|
}
|
|
13953
14587
|
|
|
13954
14588
|
// src/commands/refactor/rename/index.ts
|
|
@@ -13959,20 +14593,20 @@ async function rename(source, destination, options2 = {}) {
|
|
|
13959
14593
|
const relSource = path40.relative(cwd, sourcePath);
|
|
13960
14594
|
const relDest = path40.relative(cwd, destPath);
|
|
13961
14595
|
if (!fs25.existsSync(sourcePath)) {
|
|
13962
|
-
console.log(
|
|
14596
|
+
console.log(chalk149.red(`File not found: ${source}`));
|
|
13963
14597
|
process.exit(1);
|
|
13964
14598
|
}
|
|
13965
14599
|
if (destPath !== sourcePath && fs25.existsSync(destPath)) {
|
|
13966
|
-
console.log(
|
|
14600
|
+
console.log(chalk149.red(`Destination already exists: ${destination}`));
|
|
13967
14601
|
process.exit(1);
|
|
13968
14602
|
}
|
|
13969
|
-
console.log(
|
|
13970
|
-
console.log(
|
|
13971
|
-
console.log(
|
|
14603
|
+
console.log(chalk149.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
14604
|
+
console.log(chalk149.dim("Loading project..."));
|
|
14605
|
+
console.log(chalk149.dim("Scanning imports across the project..."));
|
|
13972
14606
|
const rewrites = computeRenameRewrites(sourcePath, destPath);
|
|
13973
14607
|
const affectedFiles = new Set(rewrites.map((r) => r.file)).size;
|
|
13974
14608
|
console.log(
|
|
13975
|
-
|
|
14609
|
+
chalk149.dim(
|
|
13976
14610
|
`${rewrites.length} import path(s) to update across ${affectedFiles} file(s)`
|
|
13977
14611
|
)
|
|
13978
14612
|
);
|
|
@@ -13981,11 +14615,11 @@ async function rename(source, destination, options2 = {}) {
|
|
|
13981
14615
|
return;
|
|
13982
14616
|
}
|
|
13983
14617
|
applyRename(rewrites, sourcePath, destPath, cwd);
|
|
13984
|
-
console.log(
|
|
14618
|
+
console.log(chalk149.green("Done"));
|
|
13985
14619
|
}
|
|
13986
14620
|
|
|
13987
14621
|
// src/commands/refactor/renameSymbol/index.ts
|
|
13988
|
-
import
|
|
14622
|
+
import chalk150 from "chalk";
|
|
13989
14623
|
|
|
13990
14624
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
13991
14625
|
import { SyntaxKind as SyntaxKind14 } from "ts-morph";
|
|
@@ -14031,33 +14665,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
|
14031
14665
|
const { project, sourceFile } = loadProjectFile(file);
|
|
14032
14666
|
const symbol = findSymbol(sourceFile, oldName);
|
|
14033
14667
|
if (!symbol) {
|
|
14034
|
-
console.log(
|
|
14668
|
+
console.log(chalk150.red(`Symbol "${oldName}" not found in ${file}`));
|
|
14035
14669
|
process.exit(1);
|
|
14036
14670
|
}
|
|
14037
14671
|
const grouped = groupReferences(symbol, cwd);
|
|
14038
14672
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
14039
14673
|
console.log(
|
|
14040
|
-
|
|
14674
|
+
chalk150.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
14041
14675
|
`)
|
|
14042
14676
|
);
|
|
14043
14677
|
for (const [refFile, lines] of grouped) {
|
|
14044
14678
|
console.log(
|
|
14045
|
-
` ${
|
|
14679
|
+
` ${chalk150.dim(refFile)}: lines ${chalk150.cyan(lines.join(", "))}`
|
|
14046
14680
|
);
|
|
14047
14681
|
}
|
|
14048
14682
|
if (options2.apply) {
|
|
14049
14683
|
symbol.rename(newName);
|
|
14050
14684
|
await project.save();
|
|
14051
|
-
console.log(
|
|
14685
|
+
console.log(chalk150.green(`
|
|
14052
14686
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
14053
14687
|
} else {
|
|
14054
|
-
console.log(
|
|
14688
|
+
console.log(chalk150.dim("\nDry run. Use --apply to execute."));
|
|
14055
14689
|
}
|
|
14056
14690
|
}
|
|
14057
14691
|
|
|
14058
14692
|
// src/commands/refactor/restructure/index.ts
|
|
14059
14693
|
import path48 from "path";
|
|
14060
|
-
import
|
|
14694
|
+
import chalk153 from "chalk";
|
|
14061
14695
|
|
|
14062
14696
|
// src/commands/refactor/restructure/clusterDirectories.ts
|
|
14063
14697
|
import path42 from "path";
|
|
@@ -14136,50 +14770,50 @@ function clusterFiles(graph) {
|
|
|
14136
14770
|
|
|
14137
14771
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
14138
14772
|
import path44 from "path";
|
|
14139
|
-
import
|
|
14773
|
+
import chalk151 from "chalk";
|
|
14140
14774
|
function relPath(filePath) {
|
|
14141
14775
|
return path44.relative(process.cwd(), filePath);
|
|
14142
14776
|
}
|
|
14143
14777
|
function displayMoves(plan2) {
|
|
14144
14778
|
if (plan2.moves.length === 0) return;
|
|
14145
|
-
console.log(
|
|
14779
|
+
console.log(chalk151.bold("\nFile moves:"));
|
|
14146
14780
|
for (const move of plan2.moves) {
|
|
14147
14781
|
console.log(
|
|
14148
|
-
` ${
|
|
14782
|
+
` ${chalk151.red(relPath(move.from))} \u2192 ${chalk151.green(relPath(move.to))}`
|
|
14149
14783
|
);
|
|
14150
|
-
console.log(
|
|
14784
|
+
console.log(chalk151.dim(` ${move.reason}`));
|
|
14151
14785
|
}
|
|
14152
14786
|
}
|
|
14153
14787
|
function displayRewrites(rewrites) {
|
|
14154
14788
|
if (rewrites.length === 0) return;
|
|
14155
14789
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
14156
|
-
console.log(
|
|
14790
|
+
console.log(chalk151.bold(`
|
|
14157
14791
|
Import rewrites (${affectedFiles.size} files):`));
|
|
14158
14792
|
for (const file of affectedFiles) {
|
|
14159
|
-
console.log(` ${
|
|
14793
|
+
console.log(` ${chalk151.cyan(relPath(file))}:`);
|
|
14160
14794
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
14161
14795
|
(r) => r.file === file
|
|
14162
14796
|
)) {
|
|
14163
14797
|
console.log(
|
|
14164
|
-
` ${
|
|
14798
|
+
` ${chalk151.red(`"${oldSpecifier}"`)} \u2192 ${chalk151.green(`"${newSpecifier}"`)}`
|
|
14165
14799
|
);
|
|
14166
14800
|
}
|
|
14167
14801
|
}
|
|
14168
14802
|
}
|
|
14169
14803
|
function displayPlan2(plan2) {
|
|
14170
14804
|
if (plan2.warnings.length > 0) {
|
|
14171
|
-
console.log(
|
|
14172
|
-
for (const w of plan2.warnings) console.log(
|
|
14805
|
+
console.log(chalk151.yellow("\nWarnings:"));
|
|
14806
|
+
for (const w of plan2.warnings) console.log(chalk151.yellow(` ${w}`));
|
|
14173
14807
|
}
|
|
14174
14808
|
if (plan2.newDirectories.length > 0) {
|
|
14175
|
-
console.log(
|
|
14809
|
+
console.log(chalk151.bold("\nNew directories:"));
|
|
14176
14810
|
for (const dir of plan2.newDirectories)
|
|
14177
|
-
console.log(
|
|
14811
|
+
console.log(chalk151.green(` ${dir}/`));
|
|
14178
14812
|
}
|
|
14179
14813
|
displayMoves(plan2);
|
|
14180
14814
|
displayRewrites(plan2.rewrites);
|
|
14181
14815
|
console.log(
|
|
14182
|
-
|
|
14816
|
+
chalk151.dim(
|
|
14183
14817
|
`
|
|
14184
14818
|
Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
|
|
14185
14819
|
)
|
|
@@ -14189,18 +14823,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
|
|
|
14189
14823
|
// src/commands/refactor/restructure/executePlan.ts
|
|
14190
14824
|
import fs26 from "fs";
|
|
14191
14825
|
import path45 from "path";
|
|
14192
|
-
import
|
|
14826
|
+
import chalk152 from "chalk";
|
|
14193
14827
|
function executePlan(plan2) {
|
|
14194
14828
|
const updatedContents = applyRewrites(plan2.rewrites);
|
|
14195
14829
|
for (const [file, content] of updatedContents) {
|
|
14196
14830
|
fs26.writeFileSync(file, content, "utf8");
|
|
14197
14831
|
console.log(
|
|
14198
|
-
|
|
14832
|
+
chalk152.cyan(` Rewrote imports in ${path45.relative(process.cwd(), file)}`)
|
|
14199
14833
|
);
|
|
14200
14834
|
}
|
|
14201
14835
|
for (const dir of plan2.newDirectories) {
|
|
14202
14836
|
fs26.mkdirSync(dir, { recursive: true });
|
|
14203
|
-
console.log(
|
|
14837
|
+
console.log(chalk152.green(` Created ${path45.relative(process.cwd(), dir)}/`));
|
|
14204
14838
|
}
|
|
14205
14839
|
for (const move of plan2.moves) {
|
|
14206
14840
|
const targetDir = path45.dirname(move.to);
|
|
@@ -14209,7 +14843,7 @@ function executePlan(plan2) {
|
|
|
14209
14843
|
}
|
|
14210
14844
|
fs26.renameSync(move.from, move.to);
|
|
14211
14845
|
console.log(
|
|
14212
|
-
|
|
14846
|
+
chalk152.white(
|
|
14213
14847
|
` Moved ${path45.relative(process.cwd(), move.from)} \u2192 ${path45.relative(process.cwd(), move.to)}`
|
|
14214
14848
|
)
|
|
14215
14849
|
);
|
|
@@ -14224,7 +14858,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
14224
14858
|
if (entries.length === 0) {
|
|
14225
14859
|
fs26.rmdirSync(dir);
|
|
14226
14860
|
console.log(
|
|
14227
|
-
|
|
14861
|
+
chalk152.dim(
|
|
14228
14862
|
` Removed empty directory ${path45.relative(process.cwd(), dir)}`
|
|
14229
14863
|
)
|
|
14230
14864
|
);
|
|
@@ -14357,22 +14991,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
14357
14991
|
const targetPattern = pattern2 ?? "src";
|
|
14358
14992
|
const files = findSourceFiles2(targetPattern);
|
|
14359
14993
|
if (files.length === 0) {
|
|
14360
|
-
console.log(
|
|
14994
|
+
console.log(chalk153.yellow("No files found matching pattern"));
|
|
14361
14995
|
return;
|
|
14362
14996
|
}
|
|
14363
14997
|
const tsConfigPath = path48.resolve("tsconfig.json");
|
|
14364
14998
|
const plan2 = buildPlan3(files, tsConfigPath);
|
|
14365
14999
|
if (plan2.moves.length === 0) {
|
|
14366
|
-
console.log(
|
|
15000
|
+
console.log(chalk153.green("No restructuring needed"));
|
|
14367
15001
|
return;
|
|
14368
15002
|
}
|
|
14369
15003
|
displayPlan2(plan2);
|
|
14370
15004
|
if (options2.apply) {
|
|
14371
|
-
console.log(
|
|
15005
|
+
console.log(chalk153.bold("\nApplying changes..."));
|
|
14372
15006
|
executePlan(plan2);
|
|
14373
|
-
console.log(
|
|
15007
|
+
console.log(chalk153.green("\nRestructuring complete"));
|
|
14374
15008
|
} else {
|
|
14375
|
-
console.log(
|
|
15009
|
+
console.log(chalk153.dim("\nDry run. Use --apply to execute."));
|
|
14376
15010
|
}
|
|
14377
15011
|
}
|
|
14378
15012
|
|
|
@@ -14527,11 +15161,11 @@ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
|
|
|
14527
15161
|
}
|
|
14528
15162
|
|
|
14529
15163
|
// src/commands/review/buildReviewPaths.ts
|
|
14530
|
-
import { homedir as
|
|
14531
|
-
import { basename as basename7, join as
|
|
15164
|
+
import { homedir as homedir13 } from "os";
|
|
15165
|
+
import { basename as basename7, join as join43 } from "path";
|
|
14532
15166
|
function buildReviewPaths(repoRoot, key) {
|
|
14533
|
-
const reviewDir =
|
|
14534
|
-
|
|
15167
|
+
const reviewDir = join43(
|
|
15168
|
+
homedir13(),
|
|
14535
15169
|
".assist",
|
|
14536
15170
|
"reviews",
|
|
14537
15171
|
basename7(repoRoot),
|
|
@@ -14539,10 +15173,10 @@ function buildReviewPaths(repoRoot, key) {
|
|
|
14539
15173
|
);
|
|
14540
15174
|
return {
|
|
14541
15175
|
reviewDir,
|
|
14542
|
-
requestPath:
|
|
14543
|
-
claudePath:
|
|
14544
|
-
codexPath:
|
|
14545
|
-
synthesisPath:
|
|
15176
|
+
requestPath: join43(reviewDir, "request.md"),
|
|
15177
|
+
claudePath: join43(reviewDir, "claude.md"),
|
|
15178
|
+
codexPath: join43(reviewDir, "codex.md"),
|
|
15179
|
+
synthesisPath: join43(reviewDir, "synthesis.md")
|
|
14546
15180
|
};
|
|
14547
15181
|
}
|
|
14548
15182
|
|
|
@@ -14685,7 +15319,7 @@ function gatherContext() {
|
|
|
14685
15319
|
}
|
|
14686
15320
|
|
|
14687
15321
|
// src/commands/review/postReviewToPr.ts
|
|
14688
|
-
import { readFileSync as
|
|
15322
|
+
import { readFileSync as readFileSync32 } from "fs";
|
|
14689
15323
|
|
|
14690
15324
|
// src/commands/review/parseFindings.ts
|
|
14691
15325
|
var SEVERITIES = ["blocker", "major", "minor", "nit"];
|
|
@@ -14941,18 +15575,18 @@ function partitionFindingsByDiff(findings, index3) {
|
|
|
14941
15575
|
}
|
|
14942
15576
|
|
|
14943
15577
|
// src/commands/review/warnOutOfDiff.ts
|
|
14944
|
-
import
|
|
15578
|
+
import chalk154 from "chalk";
|
|
14945
15579
|
function warnOutOfDiff(outOfDiff) {
|
|
14946
15580
|
if (outOfDiff.length === 0) return;
|
|
14947
15581
|
console.warn(
|
|
14948
|
-
|
|
15582
|
+
chalk154.yellow(
|
|
14949
15583
|
`Skipped ${outOfDiff.length} finding(s) whose lines fall outside the PR diff (GitHub would silently drop these):`
|
|
14950
15584
|
)
|
|
14951
15585
|
);
|
|
14952
15586
|
for (const finding of outOfDiff) {
|
|
14953
15587
|
const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
|
|
14954
15588
|
console.warn(
|
|
14955
|
-
` ${
|
|
15589
|
+
` ${chalk154.yellow("\xB7")} ${finding.title} ${chalk154.dim(
|
|
14956
15590
|
`(${finding.file}:${range})`
|
|
14957
15591
|
)}`
|
|
14958
15592
|
);
|
|
@@ -14971,18 +15605,18 @@ function selectInDiffFindings(lineBound, prDiff) {
|
|
|
14971
15605
|
}
|
|
14972
15606
|
|
|
14973
15607
|
// src/commands/review/warnUnlocated.ts
|
|
14974
|
-
import
|
|
15608
|
+
import chalk155 from "chalk";
|
|
14975
15609
|
function warnUnlocated(unlocated) {
|
|
14976
15610
|
if (unlocated.length === 0) return;
|
|
14977
15611
|
console.warn(
|
|
14978
|
-
|
|
15612
|
+
chalk155.yellow(
|
|
14979
15613
|
`Skipped ${unlocated.length} finding(s) without a parseable file:line:`
|
|
14980
15614
|
)
|
|
14981
15615
|
);
|
|
14982
15616
|
for (const finding of unlocated) {
|
|
14983
|
-
const where = finding.location ||
|
|
15617
|
+
const where = finding.location || chalk155.dim("missing");
|
|
14984
15618
|
console.warn(
|
|
14985
|
-
` ${
|
|
15619
|
+
` ${chalk155.yellow("\xB7")} ${finding.title} ${chalk155.dim(`(${where})`)}`
|
|
14986
15620
|
);
|
|
14987
15621
|
}
|
|
14988
15622
|
}
|
|
@@ -14995,7 +15629,7 @@ async function confirmPost(prNumber, count6, options2) {
|
|
|
14995
15629
|
async function postReviewToPr(synthesisPath, options2) {
|
|
14996
15630
|
const prInfo = fetchPrDiffInfo();
|
|
14997
15631
|
const prNumber = prInfo.prNumber;
|
|
14998
|
-
const markdown =
|
|
15632
|
+
const markdown = readFileSync32(synthesisPath, "utf8");
|
|
14999
15633
|
const findings = parseFindings(markdown);
|
|
15000
15634
|
if (findings.length === 0) {
|
|
15001
15635
|
console.log("Synthesis contains no findings; nothing to post.");
|
|
@@ -15077,7 +15711,7 @@ async function handlePostSynthesis(synthesisPath, options2) {
|
|
|
15077
15711
|
}
|
|
15078
15712
|
|
|
15079
15713
|
// src/commands/review/prepareReviewDir.ts
|
|
15080
|
-
import { existsSync as existsSync35, mkdirSync as mkdirSync14, unlinkSync as unlinkSync12, writeFileSync as
|
|
15714
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync14, unlinkSync as unlinkSync12, writeFileSync as writeFileSync30 } from "fs";
|
|
15081
15715
|
function clearReviewFiles(paths) {
|
|
15082
15716
|
for (const path58 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
15083
15717
|
if (existsSync35(path58)) unlinkSync12(path58);
|
|
@@ -15086,7 +15720,7 @@ function clearReviewFiles(paths) {
|
|
|
15086
15720
|
function prepareReviewDir(paths, requestBody, force) {
|
|
15087
15721
|
mkdirSync14(paths.reviewDir, { recursive: true });
|
|
15088
15722
|
if (force) clearReviewFiles(paths);
|
|
15089
|
-
|
|
15723
|
+
writeFileSync30(paths.requestPath, requestBody);
|
|
15090
15724
|
}
|
|
15091
15725
|
|
|
15092
15726
|
// src/commands/review/runApplySession.ts
|
|
@@ -15431,7 +16065,7 @@ The review request is at: ${requestPath}
|
|
|
15431
16065
|
}
|
|
15432
16066
|
|
|
15433
16067
|
// src/commands/review/runClaudeReviewer.ts
|
|
15434
|
-
import { writeFileSync as
|
|
16068
|
+
import { writeFileSync as writeFileSync31 } from "fs";
|
|
15435
16069
|
|
|
15436
16070
|
// src/commands/review/finaliseReviewerSpinner.ts
|
|
15437
16071
|
var SUMMARY_MAX_LEN = 80;
|
|
@@ -15689,12 +16323,12 @@ function onCloseResult(ctx, code) {
|
|
|
15689
16323
|
return { ...closed, stderr: ctx.stderr.value, stdout: ctx.stdout.value };
|
|
15690
16324
|
}
|
|
15691
16325
|
function waitForChildExit(ctx) {
|
|
15692
|
-
return new Promise((
|
|
16326
|
+
return new Promise((resolve17) => {
|
|
15693
16327
|
let settled = false;
|
|
15694
16328
|
const settle = (result) => {
|
|
15695
16329
|
if (settled) return;
|
|
15696
16330
|
settled = true;
|
|
15697
|
-
|
|
16331
|
+
resolve17(result);
|
|
15698
16332
|
};
|
|
15699
16333
|
ctx.child.on("error", (err) => settle(onErrorResult(ctx, err)));
|
|
15700
16334
|
ctx.child.on("close", (code) => settle(onCloseResult(ctx, code)));
|
|
@@ -15767,7 +16401,7 @@ async function runClaudeReviewer(spec) {
|
|
|
15767
16401
|
}
|
|
15768
16402
|
});
|
|
15769
16403
|
if (result.exitCode === 0 && finalText)
|
|
15770
|
-
|
|
16404
|
+
writeFileSync31(spec.outputPath, finalText);
|
|
15771
16405
|
return finaliseReviewerRun({ ...spec, command }, spinner, result);
|
|
15772
16406
|
}
|
|
15773
16407
|
|
|
@@ -15879,7 +16513,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
|
|
|
15879
16513
|
}
|
|
15880
16514
|
|
|
15881
16515
|
// src/commands/review/synthesise.ts
|
|
15882
|
-
import { readFileSync as
|
|
16516
|
+
import { readFileSync as readFileSync33 } from "fs";
|
|
15883
16517
|
|
|
15884
16518
|
// src/commands/review/buildSynthesisStdin.ts
|
|
15885
16519
|
var SYNTHESIS_PROMPT = `You are consolidating two independent code reviews of the same change. The original review request is in request.md. The two reviews are in claude.md and codex.md in the current working directory.
|
|
@@ -15935,7 +16569,7 @@ Files:
|
|
|
15935
16569
|
|
|
15936
16570
|
// src/commands/review/synthesise.ts
|
|
15937
16571
|
function printSummary2(synthesisPath) {
|
|
15938
|
-
const markdown =
|
|
16572
|
+
const markdown = readFileSync33(synthesisPath, "utf8");
|
|
15939
16573
|
console.log("");
|
|
15940
16574
|
console.log(buildReviewSummary(markdown));
|
|
15941
16575
|
console.log("");
|
|
@@ -16153,7 +16787,7 @@ function registerReview(program2) {
|
|
|
16153
16787
|
}
|
|
16154
16788
|
|
|
16155
16789
|
// src/commands/seq/seqAuth.ts
|
|
16156
|
-
import
|
|
16790
|
+
import chalk157 from "chalk";
|
|
16157
16791
|
|
|
16158
16792
|
// src/commands/seq/loadConnections.ts
|
|
16159
16793
|
function loadConnections2() {
|
|
@@ -16182,10 +16816,10 @@ function setDefaultConnection(name) {
|
|
|
16182
16816
|
}
|
|
16183
16817
|
|
|
16184
16818
|
// src/shared/assertUniqueName.ts
|
|
16185
|
-
import
|
|
16819
|
+
import chalk156 from "chalk";
|
|
16186
16820
|
function assertUniqueName(existingNames, name) {
|
|
16187
16821
|
if (existingNames.includes(name)) {
|
|
16188
|
-
console.error(
|
|
16822
|
+
console.error(chalk156.red(`Connection "${name}" already exists.`));
|
|
16189
16823
|
process.exit(1);
|
|
16190
16824
|
}
|
|
16191
16825
|
}
|
|
@@ -16203,16 +16837,16 @@ async function promptConnection2(existingNames) {
|
|
|
16203
16837
|
var seqAuth = createConnectionAuth({
|
|
16204
16838
|
load: loadConnections2,
|
|
16205
16839
|
save: saveConnections2,
|
|
16206
|
-
format: (c) => `${
|
|
16840
|
+
format: (c) => `${chalk157.bold(c.name)} ${c.url}`,
|
|
16207
16841
|
promptNew: promptConnection2,
|
|
16208
16842
|
onFirst: (c) => setDefaultConnection(c.name)
|
|
16209
16843
|
});
|
|
16210
16844
|
|
|
16211
16845
|
// src/commands/seq/seqQuery.ts
|
|
16212
|
-
import
|
|
16846
|
+
import chalk161 from "chalk";
|
|
16213
16847
|
|
|
16214
16848
|
// src/commands/seq/fetchSeq.ts
|
|
16215
|
-
import
|
|
16849
|
+
import chalk158 from "chalk";
|
|
16216
16850
|
async function fetchSeq(conn, path58, params) {
|
|
16217
16851
|
const url = `${conn.url}${path58}?${params}`;
|
|
16218
16852
|
const response = await fetch(url, {
|
|
@@ -16223,7 +16857,7 @@ async function fetchSeq(conn, path58, params) {
|
|
|
16223
16857
|
});
|
|
16224
16858
|
if (!response.ok) {
|
|
16225
16859
|
const body = await response.text();
|
|
16226
|
-
console.error(
|
|
16860
|
+
console.error(chalk158.red(`Seq returned ${response.status}: ${body}`));
|
|
16227
16861
|
process.exit(1);
|
|
16228
16862
|
}
|
|
16229
16863
|
return response;
|
|
@@ -16282,23 +16916,23 @@ async function fetchSeqEvents(conn, params) {
|
|
|
16282
16916
|
}
|
|
16283
16917
|
|
|
16284
16918
|
// src/commands/seq/formatEvent.ts
|
|
16285
|
-
import
|
|
16919
|
+
import chalk159 from "chalk";
|
|
16286
16920
|
function levelColor(level) {
|
|
16287
16921
|
switch (level) {
|
|
16288
16922
|
case "Fatal":
|
|
16289
|
-
return
|
|
16923
|
+
return chalk159.bgRed.white;
|
|
16290
16924
|
case "Error":
|
|
16291
|
-
return
|
|
16925
|
+
return chalk159.red;
|
|
16292
16926
|
case "Warning":
|
|
16293
|
-
return
|
|
16927
|
+
return chalk159.yellow;
|
|
16294
16928
|
case "Information":
|
|
16295
|
-
return
|
|
16929
|
+
return chalk159.cyan;
|
|
16296
16930
|
case "Debug":
|
|
16297
|
-
return
|
|
16931
|
+
return chalk159.gray;
|
|
16298
16932
|
case "Verbose":
|
|
16299
|
-
return
|
|
16933
|
+
return chalk159.dim;
|
|
16300
16934
|
default:
|
|
16301
|
-
return
|
|
16935
|
+
return chalk159.white;
|
|
16302
16936
|
}
|
|
16303
16937
|
}
|
|
16304
16938
|
function levelAbbrev(level) {
|
|
@@ -16339,12 +16973,12 @@ function formatTimestamp(iso) {
|
|
|
16339
16973
|
function formatEvent(event) {
|
|
16340
16974
|
const color = levelColor(event.Level);
|
|
16341
16975
|
const abbrev = levelAbbrev(event.Level);
|
|
16342
|
-
const ts8 =
|
|
16976
|
+
const ts8 = chalk159.dim(formatTimestamp(event.Timestamp));
|
|
16343
16977
|
const msg = renderMessage(event);
|
|
16344
16978
|
const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
|
|
16345
16979
|
if (event.Exception) {
|
|
16346
16980
|
for (const line of event.Exception.split("\n")) {
|
|
16347
|
-
lines.push(
|
|
16981
|
+
lines.push(chalk159.red(` ${line}`));
|
|
16348
16982
|
}
|
|
16349
16983
|
}
|
|
16350
16984
|
return lines.join("\n");
|
|
@@ -16377,11 +17011,11 @@ function rejectTimestampFilter(filter) {
|
|
|
16377
17011
|
}
|
|
16378
17012
|
|
|
16379
17013
|
// src/shared/resolveNamedConnection.ts
|
|
16380
|
-
import
|
|
17014
|
+
import chalk160 from "chalk";
|
|
16381
17015
|
function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
|
|
16382
17016
|
if (connections.length === 0) {
|
|
16383
17017
|
console.error(
|
|
16384
|
-
|
|
17018
|
+
chalk160.red(
|
|
16385
17019
|
`No ${kind} connections configured. Run '${authCommand}' first.`
|
|
16386
17020
|
)
|
|
16387
17021
|
);
|
|
@@ -16390,7 +17024,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
|
|
|
16390
17024
|
const target = requested ?? defaultName ?? connections[0].name;
|
|
16391
17025
|
const connection = connections.find((c) => c.name === target);
|
|
16392
17026
|
if (!connection) {
|
|
16393
|
-
console.error(
|
|
17027
|
+
console.error(chalk160.red(`${kind} connection "${target}" not found.`));
|
|
16394
17028
|
process.exit(1);
|
|
16395
17029
|
}
|
|
16396
17030
|
return connection;
|
|
@@ -16419,7 +17053,7 @@ async function seqQuery(filter, options2) {
|
|
|
16419
17053
|
new URLSearchParams({ filter, count: String(count6) })
|
|
16420
17054
|
);
|
|
16421
17055
|
if (events.length === 0) {
|
|
16422
|
-
console.log(
|
|
17056
|
+
console.log(chalk161.yellow("No events found."));
|
|
16423
17057
|
return;
|
|
16424
17058
|
}
|
|
16425
17059
|
if (options2.json) {
|
|
@@ -16430,11 +17064,11 @@ async function seqQuery(filter, options2) {
|
|
|
16430
17064
|
for (const event of chronological) {
|
|
16431
17065
|
console.log(formatEvent(event));
|
|
16432
17066
|
}
|
|
16433
|
-
console.log(
|
|
17067
|
+
console.log(chalk161.dim(`
|
|
16434
17068
|
${events.length} events`));
|
|
16435
17069
|
if (events.length >= count6) {
|
|
16436
17070
|
console.log(
|
|
16437
|
-
|
|
17071
|
+
chalk161.yellow(
|
|
16438
17072
|
`Results limited to ${count6}. Use --count to retrieve more.`
|
|
16439
17073
|
)
|
|
16440
17074
|
);
|
|
@@ -16442,10 +17076,10 @@ ${events.length} events`));
|
|
|
16442
17076
|
}
|
|
16443
17077
|
|
|
16444
17078
|
// src/shared/setNamedDefaultConnection.ts
|
|
16445
|
-
import
|
|
17079
|
+
import chalk162 from "chalk";
|
|
16446
17080
|
function setNamedDefaultConnection(connections, name, setDefault, kind) {
|
|
16447
17081
|
if (!connections.find((c) => c.name === name)) {
|
|
16448
|
-
console.error(
|
|
17082
|
+
console.error(chalk162.red(`Connection "${name}" not found.`));
|
|
16449
17083
|
process.exit(1);
|
|
16450
17084
|
}
|
|
16451
17085
|
setDefault(name);
|
|
@@ -16493,7 +17127,7 @@ function registerSignal(program2) {
|
|
|
16493
17127
|
}
|
|
16494
17128
|
|
|
16495
17129
|
// src/commands/sql/sqlAuth.ts
|
|
16496
|
-
import
|
|
17130
|
+
import chalk164 from "chalk";
|
|
16497
17131
|
|
|
16498
17132
|
// src/commands/sql/loadConnections.ts
|
|
16499
17133
|
function loadConnections3() {
|
|
@@ -16522,7 +17156,7 @@ function setDefaultConnection2(name) {
|
|
|
16522
17156
|
}
|
|
16523
17157
|
|
|
16524
17158
|
// src/commands/sql/promptConnection.ts
|
|
16525
|
-
import
|
|
17159
|
+
import chalk163 from "chalk";
|
|
16526
17160
|
async function promptConnection3(existingNames) {
|
|
16527
17161
|
const name = await promptInput("name", "Connection name:", "default");
|
|
16528
17162
|
assertUniqueName(existingNames, name);
|
|
@@ -16530,7 +17164,7 @@ async function promptConnection3(existingNames) {
|
|
|
16530
17164
|
const portStr = await promptInput("port", "Port:", "1433");
|
|
16531
17165
|
const port = Number.parseInt(portStr, 10);
|
|
16532
17166
|
if (!Number.isFinite(port)) {
|
|
16533
|
-
console.error(
|
|
17167
|
+
console.error(chalk163.red(`Invalid port "${portStr}".`));
|
|
16534
17168
|
process.exit(1);
|
|
16535
17169
|
}
|
|
16536
17170
|
const user = await promptInput("user", "User:");
|
|
@@ -16543,13 +17177,13 @@ async function promptConnection3(existingNames) {
|
|
|
16543
17177
|
var sqlAuth = createConnectionAuth({
|
|
16544
17178
|
load: loadConnections3,
|
|
16545
17179
|
save: saveConnections3,
|
|
16546
|
-
format: (c) => `${
|
|
17180
|
+
format: (c) => `${chalk164.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
|
|
16547
17181
|
promptNew: promptConnection3,
|
|
16548
17182
|
onFirst: (c) => setDefaultConnection2(c.name)
|
|
16549
17183
|
});
|
|
16550
17184
|
|
|
16551
17185
|
// src/commands/sql/printTable.ts
|
|
16552
|
-
import
|
|
17186
|
+
import chalk165 from "chalk";
|
|
16553
17187
|
function formatCell(value) {
|
|
16554
17188
|
if (value === null || value === void 0) return "";
|
|
16555
17189
|
if (value instanceof Date) return value.toISOString();
|
|
@@ -16558,7 +17192,7 @@ function formatCell(value) {
|
|
|
16558
17192
|
}
|
|
16559
17193
|
function printTable(rows) {
|
|
16560
17194
|
if (rows.length === 0) {
|
|
16561
|
-
console.log(
|
|
17195
|
+
console.log(chalk165.yellow("(no rows)"));
|
|
16562
17196
|
return;
|
|
16563
17197
|
}
|
|
16564
17198
|
const columns = Object.keys(rows[0]);
|
|
@@ -16566,13 +17200,13 @@ function printTable(rows) {
|
|
|
16566
17200
|
(col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
|
|
16567
17201
|
);
|
|
16568
17202
|
const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
|
|
16569
|
-
console.log(
|
|
16570
|
-
console.log(
|
|
17203
|
+
console.log(chalk165.dim(header));
|
|
17204
|
+
console.log(chalk165.dim("-".repeat(header.length)));
|
|
16571
17205
|
for (const row of rows) {
|
|
16572
17206
|
const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
|
|
16573
17207
|
console.log(line);
|
|
16574
17208
|
}
|
|
16575
|
-
console.log(
|
|
17209
|
+
console.log(chalk165.dim(`
|
|
16576
17210
|
${rows.length} row${rows.length === 1 ? "" : "s"}`));
|
|
16577
17211
|
}
|
|
16578
17212
|
|
|
@@ -16632,7 +17266,7 @@ async function sqlColumns(table, connectionName) {
|
|
|
16632
17266
|
}
|
|
16633
17267
|
|
|
16634
17268
|
// src/commands/sql/sqlMutate.ts
|
|
16635
|
-
import
|
|
17269
|
+
import chalk166 from "chalk";
|
|
16636
17270
|
|
|
16637
17271
|
// src/commands/sql/isMutation.ts
|
|
16638
17272
|
var MUTATION_KEYWORDS = [
|
|
@@ -16666,7 +17300,7 @@ function isMutation(sql6) {
|
|
|
16666
17300
|
async function sqlMutate(query, connectionName) {
|
|
16667
17301
|
if (!isMutation(query)) {
|
|
16668
17302
|
console.error(
|
|
16669
|
-
|
|
17303
|
+
chalk166.red(
|
|
16670
17304
|
"assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
|
|
16671
17305
|
)
|
|
16672
17306
|
);
|
|
@@ -16676,18 +17310,18 @@ async function sqlMutate(query, connectionName) {
|
|
|
16676
17310
|
const pool = await sqlConnect(conn);
|
|
16677
17311
|
try {
|
|
16678
17312
|
const result = await pool.request().query(query);
|
|
16679
|
-
console.log(
|
|
17313
|
+
console.log(chalk166.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
|
|
16680
17314
|
} finally {
|
|
16681
17315
|
await pool.close();
|
|
16682
17316
|
}
|
|
16683
17317
|
}
|
|
16684
17318
|
|
|
16685
17319
|
// src/commands/sql/sqlQuery.ts
|
|
16686
|
-
import
|
|
17320
|
+
import chalk167 from "chalk";
|
|
16687
17321
|
async function sqlQuery(query, connectionName) {
|
|
16688
17322
|
if (isMutation(query)) {
|
|
16689
17323
|
console.error(
|
|
16690
|
-
|
|
17324
|
+
chalk167.red(
|
|
16691
17325
|
"assist sql query refuses mutating statements. Use `assist sql mutate` instead."
|
|
16692
17326
|
)
|
|
16693
17327
|
);
|
|
@@ -16702,7 +17336,7 @@ async function sqlQuery(query, connectionName) {
|
|
|
16702
17336
|
printTable(rows);
|
|
16703
17337
|
} else {
|
|
16704
17338
|
console.log(
|
|
16705
|
-
|
|
17339
|
+
chalk167.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
|
|
16706
17340
|
);
|
|
16707
17341
|
}
|
|
16708
17342
|
} finally {
|
|
@@ -16763,7 +17397,7 @@ function registerSql(program2) {
|
|
|
16763
17397
|
|
|
16764
17398
|
// src/commands/transcript/shared.ts
|
|
16765
17399
|
import { existsSync as existsSync38, readdirSync as readdirSync7, statSync as statSync5 } from "fs";
|
|
16766
|
-
import { basename as basename8, join as
|
|
17400
|
+
import { basename as basename8, join as join44, relative as relative2 } from "path";
|
|
16767
17401
|
import * as readline2 from "readline";
|
|
16768
17402
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
16769
17403
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -16781,7 +17415,7 @@ function collectFiles(dir, extension) {
|
|
|
16781
17415
|
if (!existsSync38(dir)) return [];
|
|
16782
17416
|
const results = [];
|
|
16783
17417
|
for (const entry of readdirSync7(dir)) {
|
|
16784
|
-
const fullPath =
|
|
17418
|
+
const fullPath = join44(dir, entry);
|
|
16785
17419
|
if (statSync5(fullPath).isDirectory()) {
|
|
16786
17420
|
results.push(...collectFiles(fullPath, extension));
|
|
16787
17421
|
} else if (entry.endsWith(extension)) {
|
|
@@ -16813,9 +17447,9 @@ function createReadlineInterface() {
|
|
|
16813
17447
|
});
|
|
16814
17448
|
}
|
|
16815
17449
|
function askQuestion(rl, question) {
|
|
16816
|
-
return new Promise((
|
|
17450
|
+
return new Promise((resolve17) => {
|
|
16817
17451
|
rl.question(question, (answer) => {
|
|
16818
|
-
|
|
17452
|
+
resolve17(answer.trim());
|
|
16819
17453
|
});
|
|
16820
17454
|
});
|
|
16821
17455
|
}
|
|
@@ -16878,11 +17512,11 @@ async function configure() {
|
|
|
16878
17512
|
import { existsSync as existsSync40 } from "fs";
|
|
16879
17513
|
|
|
16880
17514
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
16881
|
-
import { dirname as
|
|
17515
|
+
import { dirname as dirname22, join as join46 } from "path";
|
|
16882
17516
|
|
|
16883
17517
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
16884
17518
|
import { renameSync as renameSync2 } from "fs";
|
|
16885
|
-
import { join as
|
|
17519
|
+
import { join as join45 } from "path";
|
|
16886
17520
|
async function resolveDate(rl, choice) {
|
|
16887
17521
|
if (choice === "1") return getDatePrefix(0);
|
|
16888
17522
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -16897,7 +17531,7 @@ async function resolveDate(rl, choice) {
|
|
|
16897
17531
|
}
|
|
16898
17532
|
function renameWithPrefix(vttDir, vttFile, prefix2) {
|
|
16899
17533
|
const newFilename = `${prefix2}.${vttFile}`;
|
|
16900
|
-
renameSync2(
|
|
17534
|
+
renameSync2(join45(vttDir, vttFile), join45(vttDir, newFilename));
|
|
16901
17535
|
console.log(`Renamed to: ${newFilename}`);
|
|
16902
17536
|
return newFilename;
|
|
16903
17537
|
}
|
|
@@ -16928,15 +17562,15 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
16928
17562
|
for (let i = 0; i < vttFiles.length; i++) {
|
|
16929
17563
|
const vttFile = vttFiles[i];
|
|
16930
17564
|
if (!isValidDatePrefix(vttFile.filename)) {
|
|
16931
|
-
const vttFileDir =
|
|
17565
|
+
const vttFileDir = dirname22(vttFile.absolutePath);
|
|
16932
17566
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
16933
17567
|
if (newFilename) {
|
|
16934
|
-
const newRelativePath =
|
|
16935
|
-
|
|
17568
|
+
const newRelativePath = join46(
|
|
17569
|
+
dirname22(vttFile.relativePath),
|
|
16936
17570
|
newFilename
|
|
16937
17571
|
);
|
|
16938
17572
|
vttFiles[i] = {
|
|
16939
|
-
absolutePath:
|
|
17573
|
+
absolutePath: join46(vttFileDir, newFilename),
|
|
16940
17574
|
relativePath: newRelativePath,
|
|
16941
17575
|
filename: newFilename
|
|
16942
17576
|
};
|
|
@@ -16949,8 +17583,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
16949
17583
|
}
|
|
16950
17584
|
|
|
16951
17585
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
16952
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync15, readFileSync as
|
|
16953
|
-
import { basename as basename9, dirname as
|
|
17586
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync32 } from "fs";
|
|
17587
|
+
import { basename as basename9, dirname as dirname23, join as join47 } from "path";
|
|
16954
17588
|
|
|
16955
17589
|
// src/commands/transcript/cleanText.ts
|
|
16956
17590
|
function cleanText(text5) {
|
|
@@ -17160,17 +17794,17 @@ function toMdFilename(vttFilename) {
|
|
|
17160
17794
|
return `${basename9(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
17161
17795
|
}
|
|
17162
17796
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
17163
|
-
return relativeDir === "." ? transcriptsDir :
|
|
17797
|
+
return relativeDir === "." ? transcriptsDir : join47(transcriptsDir, relativeDir);
|
|
17164
17798
|
}
|
|
17165
17799
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
17166
17800
|
const mdFile = toMdFilename(vttFile.filename);
|
|
17167
|
-
const relativeDir =
|
|
17801
|
+
const relativeDir = dirname23(vttFile.relativePath);
|
|
17168
17802
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
17169
|
-
const outputPath =
|
|
17803
|
+
const outputPath = join47(outputDir, mdFile);
|
|
17170
17804
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
17171
17805
|
}
|
|
17172
17806
|
function logSkipped(relativeDir, mdFile) {
|
|
17173
|
-
console.log(`Skipping (already exists): ${
|
|
17807
|
+
console.log(`Skipping (already exists): ${join47(relativeDir, mdFile)}`);
|
|
17174
17808
|
return "skipped";
|
|
17175
17809
|
}
|
|
17176
17810
|
function ensureDirectory(dir, label2) {
|
|
@@ -17197,10 +17831,10 @@ function logReduction(cueCount, messageCount) {
|
|
|
17197
17831
|
}
|
|
17198
17832
|
function readAndParseCues(inputPath) {
|
|
17199
17833
|
console.log(`Reading: ${inputPath}`);
|
|
17200
|
-
return processCues(
|
|
17834
|
+
return processCues(readFileSync34(inputPath, "utf8"));
|
|
17201
17835
|
}
|
|
17202
17836
|
function writeFormatted(outputPath, content) {
|
|
17203
|
-
|
|
17837
|
+
writeFileSync32(outputPath, content, "utf8");
|
|
17204
17838
|
console.log(`Written: ${outputPath}`);
|
|
17205
17839
|
}
|
|
17206
17840
|
function convertVttToMarkdown(inputPath, outputPath) {
|
|
@@ -17269,27 +17903,27 @@ async function format() {
|
|
|
17269
17903
|
|
|
17270
17904
|
// src/commands/transcript/summarise/index.ts
|
|
17271
17905
|
import { existsSync as existsSync42 } from "fs";
|
|
17272
|
-
import { basename as basename10, dirname as
|
|
17906
|
+
import { basename as basename10, dirname as dirname25, join as join49, relative as relative3 } from "path";
|
|
17273
17907
|
|
|
17274
17908
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
17275
17909
|
import {
|
|
17276
17910
|
existsSync as existsSync41,
|
|
17277
17911
|
mkdirSync as mkdirSync16,
|
|
17278
|
-
readFileSync as
|
|
17912
|
+
readFileSync as readFileSync35,
|
|
17279
17913
|
renameSync as renameSync3,
|
|
17280
17914
|
rmSync as rmSync4
|
|
17281
17915
|
} from "fs";
|
|
17282
|
-
import { dirname as
|
|
17916
|
+
import { dirname as dirname24, join as join48 } from "path";
|
|
17283
17917
|
|
|
17284
17918
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
17285
|
-
import
|
|
17919
|
+
import chalk168 from "chalk";
|
|
17286
17920
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
17287
17921
|
function validateStagedContent(filename, content) {
|
|
17288
17922
|
const firstLine = content.split("\n")[0];
|
|
17289
17923
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
17290
17924
|
if (!match) {
|
|
17291
17925
|
console.error(
|
|
17292
|
-
|
|
17926
|
+
chalk168.red(
|
|
17293
17927
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
17294
17928
|
)
|
|
17295
17929
|
);
|
|
@@ -17298,7 +17932,7 @@ function validateStagedContent(filename, content) {
|
|
|
17298
17932
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
17299
17933
|
if (!contentAfterLink) {
|
|
17300
17934
|
console.error(
|
|
17301
|
-
|
|
17935
|
+
chalk168.red(
|
|
17302
17936
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
17303
17937
|
)
|
|
17304
17938
|
);
|
|
@@ -17308,7 +17942,7 @@ function validateStagedContent(filename, content) {
|
|
|
17308
17942
|
}
|
|
17309
17943
|
|
|
17310
17944
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
17311
|
-
var STAGING_DIR =
|
|
17945
|
+
var STAGING_DIR = join48(process.cwd(), ".assist", "transcript");
|
|
17312
17946
|
function processStagedFile() {
|
|
17313
17947
|
if (!existsSync41(STAGING_DIR)) {
|
|
17314
17948
|
return false;
|
|
@@ -17319,7 +17953,7 @@ function processStagedFile() {
|
|
|
17319
17953
|
}
|
|
17320
17954
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
17321
17955
|
const stagedFile = stagedFiles[0];
|
|
17322
|
-
const content =
|
|
17956
|
+
const content = readFileSync35(stagedFile.absolutePath, "utf8");
|
|
17323
17957
|
validateStagedContent(stagedFile.filename, content);
|
|
17324
17958
|
const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
|
|
17325
17959
|
const transcriptFiles = findMdFilesRecursive(transcriptsDir);
|
|
@@ -17332,8 +17966,8 @@ function processStagedFile() {
|
|
|
17332
17966
|
);
|
|
17333
17967
|
process.exit(1);
|
|
17334
17968
|
}
|
|
17335
|
-
const destPath =
|
|
17336
|
-
const destDir =
|
|
17969
|
+
const destPath = join48(summaryDir, matchingTranscript.relativePath);
|
|
17970
|
+
const destDir = dirname24(destPath);
|
|
17337
17971
|
if (!existsSync41(destDir)) {
|
|
17338
17972
|
mkdirSync16(destDir, { recursive: true });
|
|
17339
17973
|
}
|
|
@@ -17347,8 +17981,8 @@ function processStagedFile() {
|
|
|
17347
17981
|
|
|
17348
17982
|
// src/commands/transcript/summarise/index.ts
|
|
17349
17983
|
function buildRelativeKey(relativePath, baseName) {
|
|
17350
|
-
const relDir =
|
|
17351
|
-
return relDir === "." ? baseName :
|
|
17984
|
+
const relDir = dirname25(relativePath);
|
|
17985
|
+
return relDir === "." ? baseName : join49(relDir, baseName);
|
|
17352
17986
|
}
|
|
17353
17987
|
function buildSummaryIndex(summaryDir) {
|
|
17354
17988
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -17382,8 +18016,8 @@ function summarise2() {
|
|
|
17382
18016
|
}
|
|
17383
18017
|
const next3 = missing[0];
|
|
17384
18018
|
const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
|
|
17385
|
-
const outputPath =
|
|
17386
|
-
const summaryFileDir =
|
|
18019
|
+
const outputPath = join49(STAGING_DIR, outputFilename);
|
|
18020
|
+
const summaryFileDir = join49(summaryDir, dirname25(next3.relativePath));
|
|
17387
18021
|
const relativeTranscriptPath = encodeURI(
|
|
17388
18022
|
relative3(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
|
|
17389
18023
|
);
|
|
@@ -17433,50 +18067,50 @@ function registerVerify(program2) {
|
|
|
17433
18067
|
|
|
17434
18068
|
// src/commands/voice/devices.ts
|
|
17435
18069
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
17436
|
-
import { join as
|
|
18070
|
+
import { join as join51 } from "path";
|
|
17437
18071
|
|
|
17438
18072
|
// src/commands/voice/shared.ts
|
|
17439
|
-
import { homedir as
|
|
17440
|
-
import { dirname as
|
|
17441
|
-
import { fileURLToPath as
|
|
17442
|
-
var __dirname5 =
|
|
17443
|
-
var VOICE_DIR =
|
|
18073
|
+
import { homedir as homedir14 } from "os";
|
|
18074
|
+
import { dirname as dirname26, join as join50 } from "path";
|
|
18075
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
18076
|
+
var __dirname5 = dirname26(fileURLToPath6(import.meta.url));
|
|
18077
|
+
var VOICE_DIR = join50(homedir14(), ".assist", "voice");
|
|
17444
18078
|
var voicePaths = {
|
|
17445
18079
|
dir: VOICE_DIR,
|
|
17446
|
-
pid:
|
|
17447
|
-
log:
|
|
17448
|
-
venv:
|
|
17449
|
-
lock:
|
|
18080
|
+
pid: join50(VOICE_DIR, "voice.pid"),
|
|
18081
|
+
log: join50(VOICE_DIR, "voice.log"),
|
|
18082
|
+
venv: join50(VOICE_DIR, ".venv"),
|
|
18083
|
+
lock: join50(VOICE_DIR, "voice.lock")
|
|
17450
18084
|
};
|
|
17451
18085
|
function getPythonDir() {
|
|
17452
|
-
return
|
|
18086
|
+
return join50(__dirname5, "commands", "voice", "python");
|
|
17453
18087
|
}
|
|
17454
18088
|
function getVenvPython() {
|
|
17455
|
-
return process.platform === "win32" ?
|
|
18089
|
+
return process.platform === "win32" ? join50(voicePaths.venv, "Scripts", "python.exe") : join50(voicePaths.venv, "bin", "python");
|
|
17456
18090
|
}
|
|
17457
18091
|
function getLockDir() {
|
|
17458
18092
|
const config = loadConfig();
|
|
17459
18093
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
17460
18094
|
}
|
|
17461
18095
|
function getLockFile() {
|
|
17462
|
-
return
|
|
18096
|
+
return join50(getLockDir(), "voice.lock");
|
|
17463
18097
|
}
|
|
17464
18098
|
|
|
17465
18099
|
// src/commands/voice/devices.ts
|
|
17466
18100
|
function devices() {
|
|
17467
|
-
const script =
|
|
18101
|
+
const script = join51(getPythonDir(), "list_devices.py");
|
|
17468
18102
|
spawnSync5(getVenvPython(), [script], { stdio: "inherit" });
|
|
17469
18103
|
}
|
|
17470
18104
|
|
|
17471
18105
|
// src/commands/voice/logs.ts
|
|
17472
|
-
import { existsSync as existsSync43, readFileSync as
|
|
18106
|
+
import { existsSync as existsSync43, readFileSync as readFileSync36 } from "fs";
|
|
17473
18107
|
function logs(options2) {
|
|
17474
18108
|
if (!existsSync43(voicePaths.log)) {
|
|
17475
18109
|
console.log("No voice log file found");
|
|
17476
18110
|
return;
|
|
17477
18111
|
}
|
|
17478
18112
|
const count6 = Number.parseInt(options2.lines ?? "150", 10);
|
|
17479
|
-
const content =
|
|
18113
|
+
const content = readFileSync36(voicePaths.log, "utf8").trim();
|
|
17480
18114
|
if (!content) {
|
|
17481
18115
|
console.log("Voice log is empty");
|
|
17482
18116
|
return;
|
|
@@ -17499,12 +18133,12 @@ function logs(options2) {
|
|
|
17499
18133
|
// src/commands/voice/setup.ts
|
|
17500
18134
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
17501
18135
|
import { mkdirSync as mkdirSync18 } from "fs";
|
|
17502
|
-
import { join as
|
|
18136
|
+
import { join as join53 } from "path";
|
|
17503
18137
|
|
|
17504
18138
|
// src/commands/voice/checkLockFile.ts
|
|
17505
18139
|
import { execSync as execSync46 } from "child_process";
|
|
17506
|
-
import { existsSync as existsSync44, mkdirSync as mkdirSync17, readFileSync as
|
|
17507
|
-
import { join as
|
|
18140
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync17, readFileSync as readFileSync37, writeFileSync as writeFileSync33 } from "fs";
|
|
18141
|
+
import { join as join52 } from "path";
|
|
17508
18142
|
function isProcessAlive2(pid) {
|
|
17509
18143
|
try {
|
|
17510
18144
|
process.kill(pid, 0);
|
|
@@ -17517,7 +18151,7 @@ function checkLockFile() {
|
|
|
17517
18151
|
const lockFile = getLockFile();
|
|
17518
18152
|
if (!existsSync44(lockFile)) return;
|
|
17519
18153
|
try {
|
|
17520
|
-
const lock = JSON.parse(
|
|
18154
|
+
const lock = JSON.parse(readFileSync37(lockFile, "utf8"));
|
|
17521
18155
|
if (lock.pid && isProcessAlive2(lock.pid)) {
|
|
17522
18156
|
console.error(
|
|
17523
18157
|
`Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
|
|
@@ -17541,8 +18175,8 @@ function bootstrapVenv() {
|
|
|
17541
18175
|
}
|
|
17542
18176
|
function writeLockFile(pid) {
|
|
17543
18177
|
const lockFile = getLockFile();
|
|
17544
|
-
mkdirSync17(
|
|
17545
|
-
|
|
18178
|
+
mkdirSync17(join52(lockFile, ".."), { recursive: true });
|
|
18179
|
+
writeFileSync33(
|
|
17546
18180
|
lockFile,
|
|
17547
18181
|
JSON.stringify({
|
|
17548
18182
|
pid,
|
|
@@ -17557,7 +18191,7 @@ function setup() {
|
|
|
17557
18191
|
mkdirSync18(voicePaths.dir, { recursive: true });
|
|
17558
18192
|
bootstrapVenv();
|
|
17559
18193
|
console.log("\nDownloading models...\n");
|
|
17560
|
-
const script =
|
|
18194
|
+
const script = join53(getPythonDir(), "setup_models.py");
|
|
17561
18195
|
const result = spawnSync6(getVenvPython(), [script], {
|
|
17562
18196
|
stdio: "inherit",
|
|
17563
18197
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -17570,8 +18204,8 @@ function setup() {
|
|
|
17570
18204
|
|
|
17571
18205
|
// src/commands/voice/start.ts
|
|
17572
18206
|
import { spawn as spawn7 } from "child_process";
|
|
17573
|
-
import { mkdirSync as mkdirSync19, writeFileSync as
|
|
17574
|
-
import { join as
|
|
18207
|
+
import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync34 } from "fs";
|
|
18208
|
+
import { join as join54 } from "path";
|
|
17575
18209
|
|
|
17576
18210
|
// src/commands/voice/buildDaemonEnv.ts
|
|
17577
18211
|
function buildDaemonEnv(options2) {
|
|
@@ -17599,7 +18233,7 @@ function spawnBackground(python, script, env) {
|
|
|
17599
18233
|
console.error("Failed to start voice daemon");
|
|
17600
18234
|
process.exit(1);
|
|
17601
18235
|
}
|
|
17602
|
-
|
|
18236
|
+
writeFileSync34(voicePaths.pid, String(pid));
|
|
17603
18237
|
writeLockFile(pid);
|
|
17604
18238
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
17605
18239
|
}
|
|
@@ -17609,7 +18243,7 @@ function start2(options2) {
|
|
|
17609
18243
|
bootstrapVenv();
|
|
17610
18244
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
17611
18245
|
const env = buildDaemonEnv({ debug });
|
|
17612
|
-
const script =
|
|
18246
|
+
const script = join54(getPythonDir(), "voice_daemon.py");
|
|
17613
18247
|
const python = getVenvPython();
|
|
17614
18248
|
if (options2.foreground) {
|
|
17615
18249
|
spawnForeground(python, script, env);
|
|
@@ -17619,7 +18253,7 @@ function start2(options2) {
|
|
|
17619
18253
|
}
|
|
17620
18254
|
|
|
17621
18255
|
// src/commands/voice/status.ts
|
|
17622
|
-
import { existsSync as existsSync45, readFileSync as
|
|
18256
|
+
import { existsSync as existsSync45, readFileSync as readFileSync38 } from "fs";
|
|
17623
18257
|
function isProcessAlive3(pid) {
|
|
17624
18258
|
try {
|
|
17625
18259
|
process.kill(pid, 0);
|
|
@@ -17630,7 +18264,7 @@ function isProcessAlive3(pid) {
|
|
|
17630
18264
|
}
|
|
17631
18265
|
function readRecentLogs(count6) {
|
|
17632
18266
|
if (!existsSync45(voicePaths.log)) return [];
|
|
17633
|
-
const lines =
|
|
18267
|
+
const lines = readFileSync38(voicePaths.log, "utf8").trim().split("\n");
|
|
17634
18268
|
return lines.slice(-count6);
|
|
17635
18269
|
}
|
|
17636
18270
|
function status() {
|
|
@@ -17638,7 +18272,7 @@ function status() {
|
|
|
17638
18272
|
console.log("Voice daemon: not running (no PID file)");
|
|
17639
18273
|
return;
|
|
17640
18274
|
}
|
|
17641
|
-
const pid = Number.parseInt(
|
|
18275
|
+
const pid = Number.parseInt(readFileSync38(voicePaths.pid, "utf8").trim(), 10);
|
|
17642
18276
|
const alive = isProcessAlive3(pid);
|
|
17643
18277
|
console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
|
|
17644
18278
|
const recent = readRecentLogs(5);
|
|
@@ -17657,13 +18291,13 @@ function status() {
|
|
|
17657
18291
|
}
|
|
17658
18292
|
|
|
17659
18293
|
// src/commands/voice/stop.ts
|
|
17660
|
-
import { existsSync as existsSync46, readFileSync as
|
|
18294
|
+
import { existsSync as existsSync46, readFileSync as readFileSync39, unlinkSync as unlinkSync15 } from "fs";
|
|
17661
18295
|
function stop2() {
|
|
17662
18296
|
if (!existsSync46(voicePaths.pid)) {
|
|
17663
18297
|
console.log("Voice daemon is not running (no PID file)");
|
|
17664
18298
|
return;
|
|
17665
18299
|
}
|
|
17666
|
-
const pid = Number.parseInt(
|
|
18300
|
+
const pid = Number.parseInt(readFileSync39(voicePaths.pid, "utf8").trim(), 10);
|
|
17667
18301
|
try {
|
|
17668
18302
|
process.kill(pid, "SIGTERM");
|
|
17669
18303
|
console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
|
|
@@ -17695,10 +18329,10 @@ function registerVoice(program2) {
|
|
|
17695
18329
|
|
|
17696
18330
|
// src/commands/roam/auth.ts
|
|
17697
18331
|
import { randomBytes } from "crypto";
|
|
17698
|
-
import
|
|
18332
|
+
import chalk169 from "chalk";
|
|
17699
18333
|
|
|
17700
18334
|
// src/commands/roam/waitForCallback.ts
|
|
17701
|
-
import { createServer as
|
|
18335
|
+
import { createServer as createServer3 } from "http";
|
|
17702
18336
|
function respondHtml(res, status2, title) {
|
|
17703
18337
|
res.writeHead(status2, { "Content-Type": "text/html" });
|
|
17704
18338
|
res.end(
|
|
@@ -17716,12 +18350,12 @@ function extractCode(url, expectedState) {
|
|
|
17716
18350
|
return code;
|
|
17717
18351
|
}
|
|
17718
18352
|
function waitForCallback(port, expectedState) {
|
|
17719
|
-
return new Promise((
|
|
18353
|
+
return new Promise((resolve17, reject) => {
|
|
17720
18354
|
const timeout = setTimeout(() => {
|
|
17721
18355
|
server.close();
|
|
17722
18356
|
reject(new Error("Authorization timed out after 120 seconds"));
|
|
17723
18357
|
}, 12e4);
|
|
17724
|
-
const server =
|
|
18358
|
+
const server = createServer3((req, res) => {
|
|
17725
18359
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
17726
18360
|
if (url.pathname !== "/callback") {
|
|
17727
18361
|
res.writeHead(404);
|
|
@@ -17733,7 +18367,7 @@ function waitForCallback(port, expectedState) {
|
|
|
17733
18367
|
const code = extractCode(url, expectedState);
|
|
17734
18368
|
respondHtml(res, 200, "Authorization successful!");
|
|
17735
18369
|
server.close();
|
|
17736
|
-
|
|
18370
|
+
resolve17(code);
|
|
17737
18371
|
} catch (error) {
|
|
17738
18372
|
respondHtml(res, 400, error.message);
|
|
17739
18373
|
server.close();
|
|
@@ -17826,13 +18460,13 @@ async function auth() {
|
|
|
17826
18460
|
saveGlobalConfig(config);
|
|
17827
18461
|
const state = randomBytes(16).toString("hex");
|
|
17828
18462
|
console.log(
|
|
17829
|
-
|
|
18463
|
+
chalk169.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
17830
18464
|
);
|
|
17831
|
-
console.log(
|
|
17832
|
-
console.log(
|
|
17833
|
-
console.log(
|
|
18465
|
+
console.log(chalk169.white("http://localhost:14523/callback\n"));
|
|
18466
|
+
console.log(chalk169.blue("Opening browser for authorization..."));
|
|
18467
|
+
console.log(chalk169.dim("Waiting for authorization callback..."));
|
|
17834
18468
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
17835
|
-
console.log(
|
|
18469
|
+
console.log(chalk169.dim("Exchanging code for tokens..."));
|
|
17836
18470
|
const tokens = await exchangeToken({
|
|
17837
18471
|
code,
|
|
17838
18472
|
clientId,
|
|
@@ -17848,14 +18482,14 @@ async function auth() {
|
|
|
17848
18482
|
};
|
|
17849
18483
|
saveGlobalConfig(config);
|
|
17850
18484
|
console.log(
|
|
17851
|
-
|
|
18485
|
+
chalk169.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
17852
18486
|
);
|
|
17853
18487
|
}
|
|
17854
18488
|
|
|
17855
18489
|
// src/commands/roam/postRoamActivity.ts
|
|
17856
18490
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
17857
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
17858
|
-
import { join as
|
|
18491
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync40, statSync as statSync6 } from "fs";
|
|
18492
|
+
import { join as join55 } from "path";
|
|
17859
18493
|
function findPortFile(roamDir) {
|
|
17860
18494
|
let entries;
|
|
17861
18495
|
try {
|
|
@@ -17864,7 +18498,7 @@ function findPortFile(roamDir) {
|
|
|
17864
18498
|
return void 0;
|
|
17865
18499
|
}
|
|
17866
18500
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
17867
|
-
const path58 =
|
|
18501
|
+
const path58 = join55(roamDir, name);
|
|
17868
18502
|
try {
|
|
17869
18503
|
return { path: path58, mtimeMs: statSync6(path58).mtimeMs };
|
|
17870
18504
|
} catch {
|
|
@@ -17876,11 +18510,11 @@ function findPortFile(roamDir) {
|
|
|
17876
18510
|
function postRoamActivity(app, event) {
|
|
17877
18511
|
const appData = process.env.APPDATA;
|
|
17878
18512
|
if (!appData) return;
|
|
17879
|
-
const portFile = findPortFile(
|
|
18513
|
+
const portFile = findPortFile(join55(appData, "Roam"));
|
|
17880
18514
|
if (!portFile) return;
|
|
17881
18515
|
let port;
|
|
17882
18516
|
try {
|
|
17883
|
-
port =
|
|
18517
|
+
port = readFileSync40(portFile, "utf8").trim();
|
|
17884
18518
|
} catch {
|
|
17885
18519
|
return;
|
|
17886
18520
|
}
|
|
@@ -17924,7 +18558,7 @@ function registerRoam(program2) {
|
|
|
17924
18558
|
}
|
|
17925
18559
|
|
|
17926
18560
|
// src/commands/run/index.ts
|
|
17927
|
-
import { resolve as
|
|
18561
|
+
import { resolve as resolve13 } from "path";
|
|
17928
18562
|
|
|
17929
18563
|
// src/commands/run/findRunConfig.ts
|
|
17930
18564
|
function exitNoRunConfigs() {
|
|
@@ -18023,13 +18657,13 @@ function runPreCommands(pre, cwd) {
|
|
|
18023
18657
|
// src/commands/run/spawnRunCommand.ts
|
|
18024
18658
|
import { execFileSync as execFileSync8, spawn as spawn8 } from "child_process";
|
|
18025
18659
|
import { existsSync as existsSync47 } from "fs";
|
|
18026
|
-
import { dirname as
|
|
18660
|
+
import { dirname as dirname27, join as join56, resolve as resolve12 } from "path";
|
|
18027
18661
|
function resolveCommand2(command) {
|
|
18028
18662
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
18029
18663
|
try {
|
|
18030
18664
|
const gitPath = execFileSync8("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
18031
|
-
const gitRoot =
|
|
18032
|
-
const gitBash =
|
|
18665
|
+
const gitRoot = resolve12(dirname27(gitPath), "..");
|
|
18666
|
+
const gitBash = join56(gitRoot, "bin", "bash.exe");
|
|
18033
18667
|
if (existsSync47(gitBash)) return gitBash;
|
|
18034
18668
|
} catch {
|
|
18035
18669
|
}
|
|
@@ -18076,7 +18710,7 @@ function listRunConfigs(verbose) {
|
|
|
18076
18710
|
}
|
|
18077
18711
|
}
|
|
18078
18712
|
function execRunConfig(config, args) {
|
|
18079
|
-
const cwd = config.cwd ?
|
|
18713
|
+
const cwd = config.cwd ? resolve13(getConfigDir(), config.cwd) : void 0;
|
|
18080
18714
|
if (config.pre) runPreCommands(config.pre, cwd);
|
|
18081
18715
|
const resolved = resolveParams(config.params, args);
|
|
18082
18716
|
spawnRunCommand(
|
|
@@ -18115,8 +18749,8 @@ async function run3(name, args) {
|
|
|
18115
18749
|
}
|
|
18116
18750
|
|
|
18117
18751
|
// src/commands/run/add.ts
|
|
18118
|
-
import { mkdirSync as mkdirSync20, writeFileSync as
|
|
18119
|
-
import { join as
|
|
18752
|
+
import { mkdirSync as mkdirSync20, writeFileSync as writeFileSync35 } from "fs";
|
|
18753
|
+
import { join as join57 } from "path";
|
|
18120
18754
|
|
|
18121
18755
|
// src/commands/run/extractOption.ts
|
|
18122
18756
|
function extractOption(args, flag) {
|
|
@@ -18177,7 +18811,7 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
18177
18811
|
saveConfig(config);
|
|
18178
18812
|
}
|
|
18179
18813
|
function createCommandFile(name) {
|
|
18180
|
-
const dir =
|
|
18814
|
+
const dir = join57(".claude", "commands");
|
|
18181
18815
|
mkdirSync20(dir, { recursive: true });
|
|
18182
18816
|
const content = `---
|
|
18183
18817
|
description: Run ${name}
|
|
@@ -18185,8 +18819,8 @@ description: Run ${name}
|
|
|
18185
18819
|
|
|
18186
18820
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
18187
18821
|
`;
|
|
18188
|
-
const filePath =
|
|
18189
|
-
|
|
18822
|
+
const filePath = join57(dir, `${name}.md`);
|
|
18823
|
+
writeFileSync35(filePath, content);
|
|
18190
18824
|
console.log(`Created command file: ${filePath}`);
|
|
18191
18825
|
}
|
|
18192
18826
|
function add3() {
|
|
@@ -18242,7 +18876,7 @@ function link2() {
|
|
|
18242
18876
|
|
|
18243
18877
|
// src/commands/run/remove.ts
|
|
18244
18878
|
import { existsSync as existsSync48, unlinkSync as unlinkSync16 } from "fs";
|
|
18245
|
-
import { join as
|
|
18879
|
+
import { join as join58 } from "path";
|
|
18246
18880
|
function findRemoveIndex() {
|
|
18247
18881
|
const idx = process.argv.indexOf("remove");
|
|
18248
18882
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -18257,7 +18891,7 @@ function parseRemoveName() {
|
|
|
18257
18891
|
return process.argv[idx + 1];
|
|
18258
18892
|
}
|
|
18259
18893
|
function deleteCommandFile(name) {
|
|
18260
|
-
const filePath =
|
|
18894
|
+
const filePath = join58(".claude", "commands", `${name}.md`);
|
|
18261
18895
|
if (existsSync48(filePath)) {
|
|
18262
18896
|
unlinkSync16(filePath);
|
|
18263
18897
|
console.log(`Deleted command file: ${filePath}`);
|
|
@@ -18297,10 +18931,10 @@ function registerRun(program2) {
|
|
|
18297
18931
|
|
|
18298
18932
|
// src/commands/screenshot/index.ts
|
|
18299
18933
|
import { execSync as execSync48 } from "child_process";
|
|
18300
|
-
import { existsSync as existsSync49, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as
|
|
18934
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync36 } from "fs";
|
|
18301
18935
|
import { tmpdir as tmpdir7 } from "os";
|
|
18302
|
-
import { join as
|
|
18303
|
-
import
|
|
18936
|
+
import { join as join59, resolve as resolve14 } from "path";
|
|
18937
|
+
import chalk170 from "chalk";
|
|
18304
18938
|
|
|
18305
18939
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
18306
18940
|
var captureWindowPs1 = `
|
|
@@ -18433,11 +19067,11 @@ function buildOutputPath(outputDir, processName) {
|
|
|
18433
19067
|
mkdirSync21(outputDir, { recursive: true });
|
|
18434
19068
|
}
|
|
18435
19069
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
18436
|
-
return
|
|
19070
|
+
return resolve14(outputDir, `${processName}-${timestamp2}.png`);
|
|
18437
19071
|
}
|
|
18438
19072
|
function runPowerShellScript(processName, outputPath) {
|
|
18439
|
-
const scriptPath =
|
|
18440
|
-
|
|
19073
|
+
const scriptPath = join59(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
19074
|
+
writeFileSync36(scriptPath, captureWindowPs1, "utf8");
|
|
18441
19075
|
try {
|
|
18442
19076
|
execSync48(
|
|
18443
19077
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
@@ -18449,15 +19083,15 @@ function runPowerShellScript(processName, outputPath) {
|
|
|
18449
19083
|
}
|
|
18450
19084
|
function screenshot(processName) {
|
|
18451
19085
|
const config = loadConfig();
|
|
18452
|
-
const outputDir =
|
|
19086
|
+
const outputDir = resolve14(config.screenshot.outputDir);
|
|
18453
19087
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
18454
|
-
console.log(
|
|
19088
|
+
console.log(chalk170.gray(`Capturing window for process "${processName}" ...`));
|
|
18455
19089
|
try {
|
|
18456
19090
|
runPowerShellScript(processName, outputPath);
|
|
18457
|
-
console.log(
|
|
19091
|
+
console.log(chalk170.green(`Screenshot saved: ${outputPath}`));
|
|
18458
19092
|
} catch (error) {
|
|
18459
19093
|
const msg = error instanceof Error ? error.message : String(error);
|
|
18460
|
-
console.error(
|
|
19094
|
+
console.error(chalk170.red(`Failed to capture screenshot: ${msg}`));
|
|
18461
19095
|
process.exit(1);
|
|
18462
19096
|
}
|
|
18463
19097
|
}
|
|
@@ -18482,10 +19116,10 @@ var STATUS_TIMEOUT_MS = 5e3;
|
|
|
18482
19116
|
function queryDaemon(socket) {
|
|
18483
19117
|
socket.write(`${JSON.stringify({ type: "ping" })}
|
|
18484
19118
|
`);
|
|
18485
|
-
return new Promise((
|
|
19119
|
+
return new Promise((resolve17) => {
|
|
18486
19120
|
const result = { sessions: [] };
|
|
18487
19121
|
const pending = /* @__PURE__ */ new Set(["sessions", "pong"]);
|
|
18488
|
-
const timer = setTimeout(() =>
|
|
19122
|
+
const timer = setTimeout(() => resolve17(result), STATUS_TIMEOUT_MS);
|
|
18489
19123
|
const lines = createInterface4({ input: socket });
|
|
18490
19124
|
lines.on("error", () => {
|
|
18491
19125
|
});
|
|
@@ -18493,7 +19127,7 @@ function queryDaemon(socket) {
|
|
|
18493
19127
|
applyLine(result, pending, line);
|
|
18494
19128
|
if (pending.size === 0) {
|
|
18495
19129
|
clearTimeout(timer);
|
|
18496
|
-
|
|
19130
|
+
resolve17(result);
|
|
18497
19131
|
}
|
|
18498
19132
|
});
|
|
18499
19133
|
});
|
|
@@ -18513,7 +19147,7 @@ function applyLine(result, pending, line) {
|
|
|
18513
19147
|
}
|
|
18514
19148
|
|
|
18515
19149
|
// src/commands/sessions/daemon/reportStolenSocket.ts
|
|
18516
|
-
import { readFileSync as
|
|
19150
|
+
import { readFileSync as readFileSync41 } from "fs";
|
|
18517
19151
|
function reportStolenSocket(socketPid) {
|
|
18518
19152
|
if (!socketPid) return;
|
|
18519
19153
|
const filePid = readPidFile();
|
|
@@ -18525,7 +19159,7 @@ function reportStolenSocket(socketPid) {
|
|
|
18525
19159
|
function readPidFile() {
|
|
18526
19160
|
try {
|
|
18527
19161
|
const pid = Number.parseInt(
|
|
18528
|
-
|
|
19162
|
+
readFileSync41(daemonPaths.pid, "utf8").trim(),
|
|
18529
19163
|
10
|
|
18530
19164
|
);
|
|
18531
19165
|
return Number.isInteger(pid) ? pid : void 0;
|
|
@@ -18644,6 +19278,7 @@ var persistedSessionSchema = z6.object({
|
|
|
18644
19278
|
commandType: z6.enum(["claude", "run", "assist"]),
|
|
18645
19279
|
cwd: z6.string(),
|
|
18646
19280
|
startedAt: z6.number(),
|
|
19281
|
+
runningMs: z6.number().optional(),
|
|
18647
19282
|
claudeSessionId: z6.string().optional(),
|
|
18648
19283
|
runName: z6.string().optional(),
|
|
18649
19284
|
runArgs: z6.array(z6.string()).optional(),
|
|
@@ -18672,6 +19307,7 @@ function toPersistedSession(session) {
|
|
|
18672
19307
|
commandType: session.commandType,
|
|
18673
19308
|
cwd: session.cwd ?? process.cwd(),
|
|
18674
19309
|
startedAt: session.startedAt,
|
|
19310
|
+
runningMs: accumulatedRunningMs(session),
|
|
18675
19311
|
claudeSessionId: session.claudeSessionId,
|
|
18676
19312
|
runName: session.runName,
|
|
18677
19313
|
runArgs: session.runArgs,
|
|
@@ -18679,6 +19315,9 @@ function toPersistedSession(session) {
|
|
|
18679
19315
|
activity: session.activity
|
|
18680
19316
|
};
|
|
18681
19317
|
}
|
|
19318
|
+
function accumulatedRunningMs(session) {
|
|
19319
|
+
return session.runningSince != null ? session.runningMs + Date.now() - session.runningSince : session.runningMs;
|
|
19320
|
+
}
|
|
18682
19321
|
|
|
18683
19322
|
// src/commands/sessions/daemon/toSessionInfo.ts
|
|
18684
19323
|
function toSessionInfo({
|
|
@@ -18687,6 +19326,8 @@ function toSessionInfo({
|
|
|
18687
19326
|
commandType,
|
|
18688
19327
|
status: status2,
|
|
18689
19328
|
startedAt,
|
|
19329
|
+
runningMs,
|
|
19330
|
+
runningSince,
|
|
18690
19331
|
runName,
|
|
18691
19332
|
runArgs,
|
|
18692
19333
|
assistArgs,
|
|
@@ -18703,6 +19344,8 @@ function toSessionInfo({
|
|
|
18703
19344
|
commandType,
|
|
18704
19345
|
status: status2,
|
|
18705
19346
|
startedAt,
|
|
19347
|
+
runningMs,
|
|
19348
|
+
runningSince,
|
|
18706
19349
|
runName,
|
|
18707
19350
|
runArgs,
|
|
18708
19351
|
assistArgs,
|
|
@@ -18828,12 +19471,15 @@ function shellEscape(s) {
|
|
|
18828
19471
|
|
|
18829
19472
|
// src/commands/sessions/daemon/createAssistSession.ts
|
|
18830
19473
|
function createAssistSession(id2, assistArgs, cwd) {
|
|
19474
|
+
const startedAt = Date.now();
|
|
18831
19475
|
return {
|
|
18832
19476
|
id: id2,
|
|
18833
19477
|
name: `assist ${assistArgs.join(" ")}`,
|
|
18834
19478
|
commandType: "assist",
|
|
18835
19479
|
status: "running",
|
|
18836
|
-
startedAt
|
|
19480
|
+
startedAt,
|
|
19481
|
+
runningMs: 0,
|
|
19482
|
+
runningSince: startedAt,
|
|
18837
19483
|
pty: spawnPty(["assist", ...assistArgs], cwd, id2),
|
|
18838
19484
|
scrollback: "",
|
|
18839
19485
|
assistArgs,
|
|
@@ -18861,24 +19507,30 @@ function spawnRun(opts) {
|
|
|
18861
19507
|
|
|
18862
19508
|
// src/commands/sessions/daemon/createSession.ts
|
|
18863
19509
|
function createSession(id2, prompt, cwd) {
|
|
19510
|
+
const startedAt = Date.now();
|
|
18864
19511
|
return {
|
|
18865
19512
|
id: id2,
|
|
18866
19513
|
name: prompt?.slice(0, 40) || `Session ${id2}`,
|
|
18867
19514
|
commandType: "claude",
|
|
18868
19515
|
status: "running",
|
|
18869
|
-
startedAt
|
|
19516
|
+
startedAt,
|
|
19517
|
+
runningMs: 0,
|
|
19518
|
+
runningSince: startedAt,
|
|
18870
19519
|
pty: spawnClaude2({ prompt, cwd, sessionId: id2 }),
|
|
18871
19520
|
scrollback: "",
|
|
18872
19521
|
cwd
|
|
18873
19522
|
};
|
|
18874
19523
|
}
|
|
18875
19524
|
function createRunSession(id2, runName, runArgs, cwd) {
|
|
19525
|
+
const startedAt = Date.now();
|
|
18876
19526
|
return {
|
|
18877
19527
|
id: id2,
|
|
18878
19528
|
name: `run: ${runName}`,
|
|
18879
19529
|
commandType: "run",
|
|
18880
19530
|
status: "running",
|
|
18881
|
-
startedAt
|
|
19531
|
+
startedAt,
|
|
19532
|
+
runningMs: 0,
|
|
19533
|
+
runningSince: startedAt,
|
|
18882
19534
|
pty: spawnRun({ name: runName, args: runArgs, cwd }),
|
|
18883
19535
|
scrollback: "",
|
|
18884
19536
|
runName,
|
|
@@ -18902,6 +19554,16 @@ function greetClient(client, sessions, windowsProxy) {
|
|
|
18902
19554
|
void windowsProxy.discover();
|
|
18903
19555
|
}
|
|
18904
19556
|
|
|
19557
|
+
// src/commands/sessions/daemon/setStatus.ts
|
|
19558
|
+
function setStatus2(session, newStatus) {
|
|
19559
|
+
const now = Date.now();
|
|
19560
|
+
if (session.status === "running" && session.runningSince != null) {
|
|
19561
|
+
session.runningMs += now - session.runningSince;
|
|
19562
|
+
}
|
|
19563
|
+
session.runningSince = newStatus === "running" ? now : null;
|
|
19564
|
+
session.status = newStatus;
|
|
19565
|
+
}
|
|
19566
|
+
|
|
18905
19567
|
// src/commands/sessions/daemon/watchEscInterrupt.ts
|
|
18906
19568
|
var ESC2 = "\x1B";
|
|
18907
19569
|
var SETTLE_MS = 1e3;
|
|
@@ -18957,7 +19619,7 @@ function applyStatusChange(session, status2, exitCode, dismiss, notify2, reuseFo
|
|
|
18957
19619
|
disarmEscInterrupt(session);
|
|
18958
19620
|
if (session.status === status2) return;
|
|
18959
19621
|
daemonLog(`session ${session.id} status: ${session.status} -> ${status2}`);
|
|
18960
|
-
session
|
|
19622
|
+
setStatus2(session, status2);
|
|
18961
19623
|
if (shouldAutoRun(session, exitCode) && session.activity?.itemId != null) {
|
|
18962
19624
|
reuseForRun(session, session.activity.itemId);
|
|
18963
19625
|
notify2();
|
|
@@ -18990,6 +19652,8 @@ function errorSession(id2, persisted, error) {
|
|
|
18990
19652
|
...restoreBase(id2, persisted),
|
|
18991
19653
|
status: "error",
|
|
18992
19654
|
startedAt: persisted.startedAt,
|
|
19655
|
+
runningMs: persisted.runningMs ?? 0,
|
|
19656
|
+
runningSince: null,
|
|
18993
19657
|
pty: null,
|
|
18994
19658
|
runName: persisted.runName,
|
|
18995
19659
|
runArgs: persisted.runArgs,
|
|
@@ -19006,10 +19670,13 @@ function backlogRunArgs(persisted) {
|
|
|
19006
19670
|
|
|
19007
19671
|
// src/commands/sessions/daemon/runningSession.ts
|
|
19008
19672
|
function runningSession(base, persisted, pty2) {
|
|
19673
|
+
const startedAt = Date.now();
|
|
19009
19674
|
return {
|
|
19010
19675
|
...base,
|
|
19011
19676
|
status: "running",
|
|
19012
|
-
startedAt
|
|
19677
|
+
startedAt,
|
|
19678
|
+
runningMs: persisted.runningMs ?? 0,
|
|
19679
|
+
runningSince: startedAt,
|
|
19013
19680
|
pty: pty2,
|
|
19014
19681
|
claudeSessionId: persisted.claudeSessionId,
|
|
19015
19682
|
restored: true,
|
|
@@ -19044,6 +19711,8 @@ function restoreSession(id2, persisted) {
|
|
|
19044
19711
|
...base,
|
|
19045
19712
|
status: "done",
|
|
19046
19713
|
startedAt: persisted.startedAt,
|
|
19714
|
+
runningMs: persisted.runningMs ?? 0,
|
|
19715
|
+
runningSince: null,
|
|
19047
19716
|
pty: null,
|
|
19048
19717
|
runName: persisted.runName,
|
|
19049
19718
|
runArgs: persisted.runArgs,
|
|
@@ -19086,12 +19755,15 @@ function restoreAll(spawn12, sessions) {
|
|
|
19086
19755
|
|
|
19087
19756
|
// src/commands/sessions/daemon/resumeSession.ts
|
|
19088
19757
|
function resumeSession(id2, sessionId, cwd, name) {
|
|
19758
|
+
const startedAt = Date.now();
|
|
19089
19759
|
return {
|
|
19090
19760
|
id: id2,
|
|
19091
19761
|
name: name ? `${name.slice(0, 36)} (R)` : `Resume ${sessionId.slice(0, 8)}`,
|
|
19092
19762
|
commandType: "claude",
|
|
19093
19763
|
status: "running",
|
|
19094
|
-
startedAt
|
|
19764
|
+
startedAt,
|
|
19765
|
+
runningMs: 0,
|
|
19766
|
+
runningSince: startedAt,
|
|
19095
19767
|
pty: spawnClaude2({ resumeSessionId: sessionId, cwd, sessionId: id2 }),
|
|
19096
19768
|
scrollback: "",
|
|
19097
19769
|
cwd
|
|
@@ -19100,12 +19772,12 @@ function resumeSession(id2, sessionId, cwd, name) {
|
|
|
19100
19772
|
|
|
19101
19773
|
// src/commands/sessions/daemon/watchActivity.ts
|
|
19102
19774
|
import { existsSync as existsSync51, mkdirSync as mkdirSync22, watch } from "fs";
|
|
19103
|
-
import { dirname as
|
|
19775
|
+
import { dirname as dirname28 } from "path";
|
|
19104
19776
|
var DEBOUNCE_MS = 50;
|
|
19105
19777
|
function watchActivity(session, notify2) {
|
|
19106
19778
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
19107
19779
|
const path58 = activityPath(session.id);
|
|
19108
|
-
const dir =
|
|
19780
|
+
const dir = dirname28(path58);
|
|
19109
19781
|
try {
|
|
19110
19782
|
mkdirSync22(dir, { recursive: true });
|
|
19111
19783
|
} catch {
|
|
@@ -19172,8 +19844,10 @@ function retrySession(session, clients, onStatusChange) {
|
|
|
19172
19844
|
if (!respawn) return false;
|
|
19173
19845
|
if (session.status !== "done") session.pty?.kill();
|
|
19174
19846
|
session.scrollback = "";
|
|
19175
|
-
session.status = "running";
|
|
19176
19847
|
session.startedAt = Date.now();
|
|
19848
|
+
session.runningMs = 0;
|
|
19849
|
+
session.runningSince = null;
|
|
19850
|
+
setStatus2(session, "running");
|
|
19177
19851
|
session.restored = void 0;
|
|
19178
19852
|
session.pty = respawn();
|
|
19179
19853
|
broadcast(clients, { type: "clear", sessionId: session.id });
|
|
@@ -19196,8 +19870,10 @@ function reuseSessionForRun(session, itemId, clients, onStatusChange) {
|
|
|
19196
19870
|
session.assistArgs = assistArgs;
|
|
19197
19871
|
session.name = `assist ${assistArgs.join(" ")}`;
|
|
19198
19872
|
session.commandType = "assist";
|
|
19199
|
-
session.status = "running";
|
|
19200
19873
|
session.startedAt = Date.now();
|
|
19874
|
+
session.runningMs = 0;
|
|
19875
|
+
session.runningSince = null;
|
|
19876
|
+
setStatus2(session, "running");
|
|
19201
19877
|
session.restored = void 0;
|
|
19202
19878
|
session.pty = spawnPty(["assist", ...assistArgs], session.cwd, session.id);
|
|
19203
19879
|
wirePtyEvents(session, clients, onStatusChange);
|
|
@@ -19225,10 +19901,10 @@ function windowsDaemonHost() {
|
|
|
19225
19901
|
|
|
19226
19902
|
// src/commands/sessions/daemon/connectToWindowsDaemon.ts
|
|
19227
19903
|
function connectToWindowsDaemon() {
|
|
19228
|
-
return new Promise((
|
|
19904
|
+
return new Promise((resolve17, reject) => {
|
|
19229
19905
|
const socket = net2.connect(windowsDaemonPort(), windowsDaemonHost());
|
|
19230
19906
|
socket.setKeepAlive(true, 1e4);
|
|
19231
|
-
socket.once("connect", () =>
|
|
19907
|
+
socket.once("connect", () => resolve17(socket));
|
|
19232
19908
|
socket.once("error", reject);
|
|
19233
19909
|
});
|
|
19234
19910
|
}
|
|
@@ -19305,7 +19981,7 @@ async function waitForWindowsDaemon() {
|
|
|
19305
19981
|
);
|
|
19306
19982
|
}
|
|
19307
19983
|
function delay2(ms) {
|
|
19308
|
-
return new Promise((
|
|
19984
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
19309
19985
|
}
|
|
19310
19986
|
|
|
19311
19987
|
// src/commands/sessions/daemon/defaultConnect.ts
|
|
@@ -19472,7 +20148,7 @@ async function healWindowsDaemon() {
|
|
|
19472
20148
|
daemonLog("windows daemon: auto-heal: stale daemon stopped");
|
|
19473
20149
|
}
|
|
19474
20150
|
function runOnWindowsHost(command, timeoutMs) {
|
|
19475
|
-
return new Promise((
|
|
20151
|
+
return new Promise((resolve17, reject) => {
|
|
19476
20152
|
const child = spawn11("pwsh.exe", ["-Command", command], {
|
|
19477
20153
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19478
20154
|
});
|
|
@@ -19492,7 +20168,7 @@ function runOnWindowsHost(command, timeoutMs) {
|
|
|
19492
20168
|
});
|
|
19493
20169
|
child.on("exit", (code) => {
|
|
19494
20170
|
clearTimeout(timer);
|
|
19495
|
-
if (code === 0)
|
|
20171
|
+
if (code === 0) resolve17();
|
|
19496
20172
|
else
|
|
19497
20173
|
reject(
|
|
19498
20174
|
new Error(
|
|
@@ -19967,7 +20643,7 @@ async function createdSince(filePath, sinceMs) {
|
|
|
19967
20643
|
}
|
|
19968
20644
|
}
|
|
19969
20645
|
function sleep(ms) {
|
|
19970
|
-
return new Promise((
|
|
20646
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
19971
20647
|
}
|
|
19972
20648
|
|
|
19973
20649
|
// src/commands/sessions/daemon/watchForClaudeSessionId.ts
|
|
@@ -20346,10 +21022,10 @@ function handleConnection(socket, manager) {
|
|
|
20346
21022
|
}
|
|
20347
21023
|
|
|
20348
21024
|
// src/commands/sessions/daemon/onListening.ts
|
|
20349
|
-
import { unlinkSync as unlinkSync18, writeFileSync as
|
|
21025
|
+
import { unlinkSync as unlinkSync18, writeFileSync as writeFileSync37 } from "fs";
|
|
20350
21026
|
|
|
20351
21027
|
// src/commands/sessions/daemon/startPidFileWatchdog.ts
|
|
20352
|
-
import { readFileSync as
|
|
21028
|
+
import { readFileSync as readFileSync42 } from "fs";
|
|
20353
21029
|
var WATCHDOG_INTERVAL_MS = 5e3;
|
|
20354
21030
|
function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
20355
21031
|
const timer = setInterval(() => {
|
|
@@ -20360,7 +21036,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
|
20360
21036
|
}
|
|
20361
21037
|
function ownsPidFile() {
|
|
20362
21038
|
try {
|
|
20363
|
-
return
|
|
21039
|
+
return readFileSync42(daemonPaths.pid, "utf8").trim() === String(process.pid);
|
|
20364
21040
|
} catch {
|
|
20365
21041
|
return false;
|
|
20366
21042
|
}
|
|
@@ -20368,7 +21044,7 @@ function ownsPidFile() {
|
|
|
20368
21044
|
|
|
20369
21045
|
// src/commands/sessions/daemon/onListening.ts
|
|
20370
21046
|
function onListening(manager, checkAutoExit) {
|
|
20371
|
-
|
|
21047
|
+
writeFileSync37(daemonPaths.pid, String(process.pid));
|
|
20372
21048
|
startPidFileWatchdog(() => {
|
|
20373
21049
|
daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
|
|
20374
21050
|
manager.shutdown();
|
|
@@ -20502,7 +21178,7 @@ async function setSessionStatus(status2) {
|
|
|
20502
21178
|
|
|
20503
21179
|
// src/commands/sessions/summarise/index.ts
|
|
20504
21180
|
import * as fs35 from "fs";
|
|
20505
|
-
import
|
|
21181
|
+
import chalk171 from "chalk";
|
|
20506
21182
|
|
|
20507
21183
|
// src/commands/sessions/summarise/shared.ts
|
|
20508
21184
|
import * as fs33 from "fs";
|
|
@@ -20656,22 +21332,22 @@ ${firstMessage}`);
|
|
|
20656
21332
|
async function summarise3(options2) {
|
|
20657
21333
|
const files = await discoverSessionFiles();
|
|
20658
21334
|
if (files.length === 0) {
|
|
20659
|
-
console.log(
|
|
21335
|
+
console.log(chalk171.yellow("No sessions found."));
|
|
20660
21336
|
return;
|
|
20661
21337
|
}
|
|
20662
21338
|
const toProcess = selectCandidates(files, options2);
|
|
20663
21339
|
if (toProcess.length === 0) {
|
|
20664
|
-
console.log(
|
|
21340
|
+
console.log(chalk171.green("All sessions already summarised."));
|
|
20665
21341
|
return;
|
|
20666
21342
|
}
|
|
20667
21343
|
console.log(
|
|
20668
|
-
|
|
21344
|
+
chalk171.cyan(
|
|
20669
21345
|
`Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
|
|
20670
21346
|
)
|
|
20671
21347
|
);
|
|
20672
21348
|
const { succeeded, failed: failed2 } = processSessions(toProcess);
|
|
20673
21349
|
console.log(
|
|
20674
|
-
|
|
21350
|
+
chalk171.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk171.yellow(`, ${failed2} skipped`) : "")
|
|
20675
21351
|
);
|
|
20676
21352
|
}
|
|
20677
21353
|
function selectCandidates(files, options2) {
|
|
@@ -20691,16 +21367,16 @@ function processSessions(files) {
|
|
|
20691
21367
|
let failed2 = 0;
|
|
20692
21368
|
for (let i = 0; i < files.length; i++) {
|
|
20693
21369
|
const file = files[i];
|
|
20694
|
-
process.stdout.write(
|
|
21370
|
+
process.stdout.write(chalk171.dim(` [${i + 1}/${files.length}] `));
|
|
20695
21371
|
const summary = summariseSession(file);
|
|
20696
21372
|
if (summary) {
|
|
20697
21373
|
writeSummary(file, summary);
|
|
20698
21374
|
succeeded++;
|
|
20699
|
-
process.stdout.write(`${
|
|
21375
|
+
process.stdout.write(`${chalk171.green("\u2713")} ${summary}
|
|
20700
21376
|
`);
|
|
20701
21377
|
} else {
|
|
20702
21378
|
failed2++;
|
|
20703
|
-
process.stdout.write(` ${
|
|
21379
|
+
process.stdout.write(` ${chalk171.yellow("skip")}
|
|
20704
21380
|
`);
|
|
20705
21381
|
}
|
|
20706
21382
|
}
|
|
@@ -20718,10 +21394,10 @@ function registerSessions(program2) {
|
|
|
20718
21394
|
}
|
|
20719
21395
|
|
|
20720
21396
|
// src/commands/statusLine.ts
|
|
20721
|
-
import
|
|
21397
|
+
import chalk173 from "chalk";
|
|
20722
21398
|
|
|
20723
21399
|
// src/commands/buildLimitsSegment.ts
|
|
20724
|
-
import
|
|
21400
|
+
import chalk172 from "chalk";
|
|
20725
21401
|
|
|
20726
21402
|
// src/shared/rateLimitLevel.ts
|
|
20727
21403
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
@@ -20752,9 +21428,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
|
|
|
20752
21428
|
|
|
20753
21429
|
// src/commands/buildLimitsSegment.ts
|
|
20754
21430
|
var LEVEL_COLOR = {
|
|
20755
|
-
ok:
|
|
20756
|
-
warn:
|
|
20757
|
-
over:
|
|
21431
|
+
ok: chalk172.green,
|
|
21432
|
+
warn: chalk172.yellow,
|
|
21433
|
+
over: chalk172.red
|
|
20758
21434
|
};
|
|
20759
21435
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
|
|
20760
21436
|
const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
|
|
@@ -20794,14 +21470,14 @@ async function relayRateLimits(rateLimits) {
|
|
|
20794
21470
|
}
|
|
20795
21471
|
|
|
20796
21472
|
// src/commands/statusLine.ts
|
|
20797
|
-
|
|
21473
|
+
chalk173.level = 3;
|
|
20798
21474
|
function formatNumber(num) {
|
|
20799
21475
|
return num.toLocaleString("en-US");
|
|
20800
21476
|
}
|
|
20801
21477
|
function colorizePercent(pct) {
|
|
20802
21478
|
const label2 = `${Math.round(pct)}%`;
|
|
20803
|
-
if (pct > 80) return
|
|
20804
|
-
if (pct > 40) return
|
|
21479
|
+
if (pct > 80) return chalk173.red(label2);
|
|
21480
|
+
if (pct > 40) return chalk173.yellow(label2);
|
|
20805
21481
|
return label2;
|
|
20806
21482
|
}
|
|
20807
21483
|
async function statusLine() {
|
|
@@ -20820,12 +21496,12 @@ async function statusLine() {
|
|
|
20820
21496
|
import * as fs38 from "fs";
|
|
20821
21497
|
import * as os2 from "os";
|
|
20822
21498
|
import * as path56 from "path";
|
|
20823
|
-
import { fileURLToPath as
|
|
21499
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
20824
21500
|
|
|
20825
21501
|
// src/commands/sync/syncClaudeMd.ts
|
|
20826
21502
|
import * as fs36 from "fs";
|
|
20827
21503
|
import * as path54 from "path";
|
|
20828
|
-
import
|
|
21504
|
+
import chalk174 from "chalk";
|
|
20829
21505
|
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
20830
21506
|
const source = path54.join(claudeDir, "CLAUDE.md");
|
|
20831
21507
|
const target = path54.join(targetBase, "CLAUDE.md");
|
|
@@ -20834,12 +21510,12 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
20834
21510
|
const targetContent = fs36.readFileSync(target, "utf8");
|
|
20835
21511
|
if (sourceContent !== targetContent) {
|
|
20836
21512
|
console.log(
|
|
20837
|
-
|
|
21513
|
+
chalk174.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
20838
21514
|
);
|
|
20839
21515
|
console.log();
|
|
20840
21516
|
printDiff(targetContent, sourceContent);
|
|
20841
21517
|
const confirm = options2?.yes || await promptConfirm(
|
|
20842
|
-
|
|
21518
|
+
chalk174.red("Overwrite existing CLAUDE.md?"),
|
|
20843
21519
|
false
|
|
20844
21520
|
);
|
|
20845
21521
|
if (!confirm) {
|
|
@@ -20855,7 +21531,7 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
20855
21531
|
// src/commands/sync/syncSettings.ts
|
|
20856
21532
|
import * as fs37 from "fs";
|
|
20857
21533
|
import * as path55 from "path";
|
|
20858
|
-
import
|
|
21534
|
+
import chalk175 from "chalk";
|
|
20859
21535
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
20860
21536
|
const source = path55.join(claudeDir, "settings.json");
|
|
20861
21537
|
const target = path55.join(targetBase, "settings.json");
|
|
@@ -20871,14 +21547,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
20871
21547
|
if (mergedContent !== normalizedTarget) {
|
|
20872
21548
|
if (!options2?.yes) {
|
|
20873
21549
|
console.log(
|
|
20874
|
-
|
|
21550
|
+
chalk175.yellow(
|
|
20875
21551
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
20876
21552
|
)
|
|
20877
21553
|
);
|
|
20878
21554
|
console.log();
|
|
20879
21555
|
printDiff(targetContent, mergedContent);
|
|
20880
21556
|
const confirm = await promptConfirm(
|
|
20881
|
-
|
|
21557
|
+
chalk175.red("Overwrite existing settings.json?"),
|
|
20882
21558
|
false
|
|
20883
21559
|
);
|
|
20884
21560
|
if (!confirm) {
|
|
@@ -20893,7 +21569,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
20893
21569
|
}
|
|
20894
21570
|
|
|
20895
21571
|
// src/commands/sync.ts
|
|
20896
|
-
var __filename4 =
|
|
21572
|
+
var __filename4 = fileURLToPath7(import.meta.url);
|
|
20897
21573
|
var __dirname6 = path56.dirname(__filename4);
|
|
20898
21574
|
async function sync(options2) {
|
|
20899
21575
|
const config = loadConfig();
|
|
@@ -21011,6 +21687,7 @@ registerDeploy(program);
|
|
|
21011
21687
|
registerComplexity(program);
|
|
21012
21688
|
registerDotnet(program);
|
|
21013
21689
|
registerNews(program);
|
|
21690
|
+
registerNetcap(program);
|
|
21014
21691
|
registerRavendb(program);
|
|
21015
21692
|
registerSeq(program);
|
|
21016
21693
|
registerSql(program);
|