@staff0rd/assist 0.252.0 → 0.254.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/allowed.cli-reads +1 -0
- package/claude/CLAUDE.md +3 -0
- package/claude/settings.json +1 -2
- package/dist/allowed.cli-reads +1 -0
- package/dist/commands/sessions/web/bundle.js +63 -63
- package/dist/index.js +546 -407
- package/package.json +4 -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.254.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -73,6 +73,8 @@ var package_default = {
|
|
|
73
73
|
"@semantic-release/changelog": "^6.0.3",
|
|
74
74
|
"@semantic-release/exec": "^7.1.0",
|
|
75
75
|
"@semantic-release/git": "^10.0.1",
|
|
76
|
+
"@testing-library/dom": "^10.4.1",
|
|
77
|
+
"@testing-library/react": "^16.3.2",
|
|
76
78
|
"@types/better-sqlite3": "^7.6.13",
|
|
77
79
|
"@types/blessed": "^0.1.27",
|
|
78
80
|
"@types/mssql": "^12.3.0",
|
|
@@ -90,6 +92,7 @@ var package_default = {
|
|
|
90
92
|
"@xterm/xterm": "^6.0.0",
|
|
91
93
|
esbuild: "^0.27.3",
|
|
92
94
|
jscpd: "^4.0.5",
|
|
95
|
+
jsdom: "^29.1.1",
|
|
93
96
|
knip: "^5.71.0",
|
|
94
97
|
marked: "^15.0.12",
|
|
95
98
|
react: "^19.2.4",
|
|
@@ -115,10 +118,10 @@ import { stringify as stringifyYaml } from "yaml";
|
|
|
115
118
|
// src/shared/loadRawYaml.ts
|
|
116
119
|
import { existsSync, readFileSync } from "fs";
|
|
117
120
|
import { parse as parseYaml } from "yaml";
|
|
118
|
-
function loadRawYaml(
|
|
119
|
-
if (!existsSync(
|
|
121
|
+
function loadRawYaml(path53) {
|
|
122
|
+
if (!existsSync(path53)) return {};
|
|
120
123
|
try {
|
|
121
|
-
const content = readFileSync(
|
|
124
|
+
const content = readFileSync(path53, "utf-8");
|
|
122
125
|
return parseYaml(content) || {};
|
|
123
126
|
} catch {
|
|
124
127
|
return {};
|
|
@@ -2743,9 +2746,9 @@ var LOCAL_FILES = ["backlog.jsonl", "backlog.db"];
|
|
|
2743
2746
|
function backupLocalBacklogFiles(dir) {
|
|
2744
2747
|
const moved = [];
|
|
2745
2748
|
for (const name of LOCAL_FILES) {
|
|
2746
|
-
const
|
|
2747
|
-
if (existsSync14(
|
|
2748
|
-
renameSync(
|
|
2749
|
+
const path53 = join10(dir, ".assist", name);
|
|
2750
|
+
if (existsSync14(path53)) {
|
|
2751
|
+
renameSync(path53, `${path53}.bak`);
|
|
2749
2752
|
moved.push(`${name} \u2192 ${name}.bak`);
|
|
2750
2753
|
}
|
|
2751
2754
|
}
|
|
@@ -2893,12 +2896,12 @@ var selectTasks = (orm, ids) => orm.select().from(planTasks).where(inArray(planT
|
|
|
2893
2896
|
asc(planTasks.phaseIdx),
|
|
2894
2897
|
asc(planTasks.idx)
|
|
2895
2898
|
);
|
|
2896
|
-
async function loadRelations(orm, ids) {
|
|
2899
|
+
async function loadRelations(orm, ids, { includeComments = true, includeTasks = true } = {}) {
|
|
2897
2900
|
const [commentRows, linkRows, phaseRows, taskRows] = await Promise.all([
|
|
2898
|
-
selectComments(orm, ids),
|
|
2901
|
+
includeComments ? selectComments(orm, ids) : [],
|
|
2899
2902
|
selectLinks(orm, ids),
|
|
2900
2903
|
selectPhases(orm, ids),
|
|
2901
|
-
selectTasks(orm, ids)
|
|
2904
|
+
includeTasks ? selectTasks(orm, ids) : []
|
|
2902
2905
|
]);
|
|
2903
2906
|
return {
|
|
2904
2907
|
comments: groupByItem(commentRows),
|
|
@@ -2985,7 +2988,8 @@ async function loadAllItems(orm, origin) {
|
|
|
2985
2988
|
if (rows.length === 0) return [];
|
|
2986
2989
|
const rel = await loadRelations(
|
|
2987
2990
|
orm,
|
|
2988
|
-
rows.map((r) => r.id)
|
|
2991
|
+
rows.map((r) => r.id),
|
|
2992
|
+
{ includeComments: false, includeTasks: false }
|
|
2989
2993
|
);
|
|
2990
2994
|
return rows.map((row) => rowToItem(row, rel));
|
|
2991
2995
|
}
|
|
@@ -3034,8 +3038,8 @@ var backlogItemSchema = z3.strictObject({
|
|
|
3034
3038
|
var backlogFileSchema = z3.array(backlogItemSchema);
|
|
3035
3039
|
|
|
3036
3040
|
// src/commands/backlog/parseBacklogJsonl.ts
|
|
3037
|
-
function parseBacklogJsonl(
|
|
3038
|
-
const content = readFileSync9(
|
|
3041
|
+
function parseBacklogJsonl(path53) {
|
|
3042
|
+
const content = readFileSync9(path53, "utf-8").trim();
|
|
3039
3043
|
if (content.length === 0) return [];
|
|
3040
3044
|
return content.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => backlogItemSchema.parse(JSON.parse(line)));
|
|
3041
3045
|
}
|
|
@@ -3110,8 +3114,8 @@ function findBacklogUp(startDir) {
|
|
|
3110
3114
|
|
|
3111
3115
|
// src/commands/backlog/getCurrentOrigin.ts
|
|
3112
3116
|
import { execSync as execSync17 } from "child_process";
|
|
3113
|
-
function stripLeadingSlashes(
|
|
3114
|
-
return
|
|
3117
|
+
function stripLeadingSlashes(path53) {
|
|
3118
|
+
return path53.replace(/^\/+/, "");
|
|
3115
3119
|
}
|
|
3116
3120
|
function normalizeOrigin(raw) {
|
|
3117
3121
|
const trimmed = raw.trim().replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
@@ -3423,6 +3427,33 @@ async function reloadPlan(id) {
|
|
|
3423
3427
|
// src/commands/backlog/executePhase.ts
|
|
3424
3428
|
import chalk34 from "chalk";
|
|
3425
3429
|
|
|
3430
|
+
// src/shared/emitActivity.ts
|
|
3431
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync12 } from "fs";
|
|
3432
|
+
import { dirname as dirname14, join as join14 } from "path";
|
|
3433
|
+
function activityPath(cwd, sessionId) {
|
|
3434
|
+
return join14(cwd, ".assist", `activity-${sessionId}.json`);
|
|
3435
|
+
}
|
|
3436
|
+
function emitActivity(activity2) {
|
|
3437
|
+
const sessionId = process.env.ASSIST_ACTIVITY_ID;
|
|
3438
|
+
if (!sessionId) return;
|
|
3439
|
+
const path53 = activityPath(process.cwd(), sessionId);
|
|
3440
|
+
mkdirSync4(dirname14(path53), { recursive: true });
|
|
3441
|
+
writeFileSync12(path53, JSON.stringify({ ...activity2, startedAt: Date.now() }));
|
|
3442
|
+
}
|
|
3443
|
+
function readActivity(path53) {
|
|
3444
|
+
try {
|
|
3445
|
+
return JSON.parse(readFileSync11(path53, "utf-8"));
|
|
3446
|
+
} catch {
|
|
3447
|
+
return void 0;
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
function removeActivity(cwd, sessionId) {
|
|
3451
|
+
try {
|
|
3452
|
+
rmSync(activityPath(cwd, sessionId));
|
|
3453
|
+
} catch {
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
|
|
3426
3457
|
// src/shared/spawnClaude.ts
|
|
3427
3458
|
import { spawn as spawn3 } from "child_process";
|
|
3428
3459
|
function spawnClaude(prompt, options2 = {}) {
|
|
@@ -3430,8 +3461,10 @@ function spawnClaude(prompt, options2 = {}) {
|
|
|
3430
3461
|
if (options2.allowEdits) {
|
|
3431
3462
|
args.push("--permission-mode", "auto");
|
|
3432
3463
|
}
|
|
3464
|
+
const { ASSIST_ACTIVITY_ID: _activityId, ...env } = process.env;
|
|
3433
3465
|
const child = spawn3("claude", args, {
|
|
3434
|
-
stdio: "inherit"
|
|
3466
|
+
stdio: "inherit",
|
|
3467
|
+
env
|
|
3435
3468
|
});
|
|
3436
3469
|
const done2 = new Promise((resolve16, reject) => {
|
|
3437
3470
|
child.on("close", (code) => resolve16(code ?? 0));
|
|
@@ -3565,28 +3598,28 @@ async function handleIncompletePhase() {
|
|
|
3565
3598
|
}
|
|
3566
3599
|
|
|
3567
3600
|
// src/commands/backlog/readSignal.ts
|
|
3568
|
-
import { existsSync as existsSync18, readFileSync as
|
|
3601
|
+
import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
|
|
3569
3602
|
|
|
3570
3603
|
// src/commands/backlog/writeSignal.ts
|
|
3571
|
-
import { writeFileSync as
|
|
3572
|
-
import { join as
|
|
3604
|
+
import { writeFileSync as writeFileSync13 } from "fs";
|
|
3605
|
+
import { join as join15 } from "path";
|
|
3573
3606
|
function getSignalPath() {
|
|
3574
3607
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
3575
3608
|
const filename = sessionId ? `.assist-signal-${sessionId}.json` : ".assist-signal.json";
|
|
3576
|
-
return
|
|
3609
|
+
return join15(getBacklogDir(), filename);
|
|
3577
3610
|
}
|
|
3578
3611
|
function writeSignal(event, data) {
|
|
3579
3612
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
3580
3613
|
const signal = { event, ...sessionId && { sessionId }, ...data };
|
|
3581
|
-
|
|
3614
|
+
writeFileSync13(getSignalPath(), JSON.stringify(signal));
|
|
3582
3615
|
}
|
|
3583
3616
|
|
|
3584
3617
|
// src/commands/backlog/readSignal.ts
|
|
3585
3618
|
function readSignal() {
|
|
3586
|
-
const
|
|
3587
|
-
if (!existsSync18(
|
|
3619
|
+
const path53 = getSignalPath();
|
|
3620
|
+
if (!existsSync18(path53)) return void 0;
|
|
3588
3621
|
try {
|
|
3589
|
-
return JSON.parse(
|
|
3622
|
+
return JSON.parse(readFileSync12(path53, "utf-8"));
|
|
3590
3623
|
} catch {
|
|
3591
3624
|
return void 0;
|
|
3592
3625
|
}
|
|
@@ -3600,8 +3633,8 @@ function cleanupSignal() {
|
|
|
3600
3633
|
}
|
|
3601
3634
|
}
|
|
3602
3635
|
async function isTerminalStatus(itemId) {
|
|
3603
|
-
const
|
|
3604
|
-
const item =
|
|
3636
|
+
const { orm } = await getReady();
|
|
3637
|
+
const item = await loadItem(orm, itemId);
|
|
3605
3638
|
return item?.status === "done" || item?.status === "wontdo";
|
|
3606
3639
|
}
|
|
3607
3640
|
async function resolvePhaseResult(phaseIndex, itemId) {
|
|
@@ -3644,17 +3677,24 @@ function stopWatching() {
|
|
|
3644
3677
|
}
|
|
3645
3678
|
|
|
3646
3679
|
// src/commands/backlog/executePhase.ts
|
|
3647
|
-
async function executePhase(item, phaseIndex, phases, spawnOptions) {
|
|
3680
|
+
async function executePhase(item, phaseIndex, phases, spawnOptions, totalPhases = phases.length) {
|
|
3648
3681
|
const phase = phases[phaseIndex];
|
|
3649
3682
|
const phaseNumber = phaseIndex + 1;
|
|
3650
3683
|
console.log(
|
|
3651
3684
|
chalk34.bold(
|
|
3652
3685
|
`
|
|
3653
|
-
--- Phase ${phaseNumber}/${
|
|
3686
|
+
--- Phase ${phaseNumber}/${totalPhases}: ${phase.name} ---
|
|
3654
3687
|
`
|
|
3655
3688
|
)
|
|
3656
3689
|
);
|
|
3657
|
-
process.env.ASSIST_SESSION_ID
|
|
3690
|
+
process.env.ASSIST_SESSION_ID ??= String(process.pid);
|
|
3691
|
+
emitActivity({
|
|
3692
|
+
kind: "backlog",
|
|
3693
|
+
itemId: item.id,
|
|
3694
|
+
itemName: item.name,
|
|
3695
|
+
phase: phaseNumber,
|
|
3696
|
+
totalPhases
|
|
3697
|
+
});
|
|
3658
3698
|
const { child, done: done2 } = spawnClaude(
|
|
3659
3699
|
buildPhasePrompt(item, phaseNumber, phase),
|
|
3660
3700
|
spawnOptions
|
|
@@ -3674,7 +3714,9 @@ async function runPhases(item, startPhase, plan2, spawnOptions) {
|
|
|
3674
3714
|
item,
|
|
3675
3715
|
phaseIndex,
|
|
3676
3716
|
currentPlan,
|
|
3677
|
-
spawnOptions
|
|
3717
|
+
spawnOptions,
|
|
3718
|
+
// +1 for the review phase appended after the authored phases complete
|
|
3719
|
+
currentPlan.length + 1
|
|
3678
3720
|
);
|
|
3679
3721
|
if (phaseIndex < 0) return false;
|
|
3680
3722
|
currentPlan = await reloadPlan(item.id) ?? currentPlan;
|
|
@@ -4023,10 +4065,10 @@ import { WebSocketServer } from "ws";
|
|
|
4023
4065
|
|
|
4024
4066
|
// src/shared/getInstallDir.ts
|
|
4025
4067
|
import { execSync as execSync18 } from "child_process";
|
|
4026
|
-
import { dirname as
|
|
4068
|
+
import { dirname as dirname15, resolve as resolve6 } from "path";
|
|
4027
4069
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4028
4070
|
var __filename2 = fileURLToPath3(import.meta.url);
|
|
4029
|
-
var __dirname4 =
|
|
4071
|
+
var __dirname4 = dirname15(__filename2);
|
|
4030
4072
|
function getInstallDir() {
|
|
4031
4073
|
return resolve6(__dirname4, "..");
|
|
4032
4074
|
}
|
|
@@ -4103,7 +4145,7 @@ function startWebServer(label2, port, handler, initialPath) {
|
|
|
4103
4145
|
import { spawn as spawn4 } from "child_process";
|
|
4104
4146
|
import {
|
|
4105
4147
|
closeSync,
|
|
4106
|
-
mkdirSync as
|
|
4148
|
+
mkdirSync as mkdirSync5,
|
|
4107
4149
|
openSync,
|
|
4108
4150
|
statSync,
|
|
4109
4151
|
unlinkSync as unlinkSync4,
|
|
@@ -4115,14 +4157,14 @@ import * as net from "net";
|
|
|
4115
4157
|
|
|
4116
4158
|
// src/commands/sessions/daemon/daemonPaths.ts
|
|
4117
4159
|
import { homedir as homedir3 } from "os";
|
|
4118
|
-
import { join as
|
|
4119
|
-
var DAEMON_DIR =
|
|
4160
|
+
import { join as join16 } from "path";
|
|
4161
|
+
var DAEMON_DIR = join16(homedir3(), ".assist", "daemon");
|
|
4120
4162
|
var daemonPaths = {
|
|
4121
4163
|
dir: DAEMON_DIR,
|
|
4122
|
-
socket: process.platform === "win32" ? "\\\\.\\pipe\\assist-sessions-daemon" :
|
|
4123
|
-
log:
|
|
4124
|
-
pid:
|
|
4125
|
-
spawnLock:
|
|
4164
|
+
socket: process.platform === "win32" ? "\\\\.\\pipe\\assist-sessions-daemon" : join16(DAEMON_DIR, "daemon.sock"),
|
|
4165
|
+
log: join16(DAEMON_DIR, "daemon.log"),
|
|
4166
|
+
pid: join16(DAEMON_DIR, "daemon.pid"),
|
|
4167
|
+
spawnLock: join16(DAEMON_DIR, "spawn.lock")
|
|
4126
4168
|
};
|
|
4127
4169
|
|
|
4128
4170
|
// src/commands/sessions/daemon/connectToDaemon.ts
|
|
@@ -4148,7 +4190,7 @@ var RETRY_DELAY_MS = 200;
|
|
|
4148
4190
|
var STALE_LOCK_MS = SPAWN_TIMEOUT_MS + 5e3;
|
|
4149
4191
|
async function ensureDaemonRunning(reason = "unspecified") {
|
|
4150
4192
|
if (await isDaemonRunning()) return;
|
|
4151
|
-
|
|
4193
|
+
mkdirSync5(daemonPaths.dir, { recursive: true });
|
|
4152
4194
|
const holdsLock = acquireSpawnLock();
|
|
4153
4195
|
if (holdsLock) spawnDaemon(reason);
|
|
4154
4196
|
try {
|
|
@@ -4213,19 +4255,19 @@ function delay(ms) {
|
|
|
4213
4255
|
}
|
|
4214
4256
|
|
|
4215
4257
|
// src/commands/sessions/web/handleRequest.ts
|
|
4216
|
-
import { readFileSync as
|
|
4258
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
4217
4259
|
import { createRequire as createRequire2 } from "module";
|
|
4218
4260
|
|
|
4219
4261
|
// src/shared/createBundleHandler.ts
|
|
4220
|
-
import { readFileSync as
|
|
4221
|
-
import { dirname as
|
|
4262
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
4263
|
+
import { dirname as dirname16, join as join17 } from "path";
|
|
4222
4264
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
4223
4265
|
function createBundleHandler(importMetaUrl, bundlePath) {
|
|
4224
|
-
const dir =
|
|
4266
|
+
const dir = dirname16(fileURLToPath4(importMetaUrl));
|
|
4225
4267
|
let cache;
|
|
4226
4268
|
return (_req, res) => {
|
|
4227
4269
|
if (!cache) {
|
|
4228
|
-
cache =
|
|
4270
|
+
cache = readFileSync13(join17(dir, bundlePath), "utf-8");
|
|
4229
4271
|
}
|
|
4230
4272
|
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
4231
4273
|
res.end(cache);
|
|
@@ -4293,31 +4335,79 @@ async function createItem(req, res) {
|
|
|
4293
4335
|
respondJson(res, 201, { id, ...newItem });
|
|
4294
4336
|
}
|
|
4295
4337
|
|
|
4338
|
+
// src/commands/backlog/loadBacklogSummaries.ts
|
|
4339
|
+
import { eq as eq11 } from "drizzle-orm";
|
|
4340
|
+
|
|
4341
|
+
// src/commands/backlog/loadItemSummaries.ts
|
|
4342
|
+
import { asc as asc4, eq as eq10 } from "drizzle-orm";
|
|
4343
|
+
async function loadItemSummaries(orm, origin) {
|
|
4344
|
+
const rows = await orm.select({
|
|
4345
|
+
id: items.id,
|
|
4346
|
+
origin: items.origin,
|
|
4347
|
+
type: items.type,
|
|
4348
|
+
name: items.name,
|
|
4349
|
+
status: items.status
|
|
4350
|
+
}).from(items).where(origin === void 0 ? void 0 : eq10(items.origin, origin)).orderBy(asc4(items.id));
|
|
4351
|
+
return rows.map((row) => ({
|
|
4352
|
+
id: row.id,
|
|
4353
|
+
origin: row.origin,
|
|
4354
|
+
type: row.type,
|
|
4355
|
+
name: row.name,
|
|
4356
|
+
status: row.status
|
|
4357
|
+
}));
|
|
4358
|
+
}
|
|
4359
|
+
|
|
4360
|
+
// src/commands/backlog/loadBacklogSummaries.ts
|
|
4361
|
+
async function loadBacklogSummaries(allRepos = false) {
|
|
4362
|
+
const { orm } = await getReady();
|
|
4363
|
+
return loadItemSummaries(orm, allRepos ? void 0 : getOrigin());
|
|
4364
|
+
}
|
|
4365
|
+
async function searchBacklogSummaries(query) {
|
|
4366
|
+
const { orm } = await getReady();
|
|
4367
|
+
const origin = getOrigin();
|
|
4368
|
+
const ids = await searchItemIds(orm, query, origin);
|
|
4369
|
+
const summaries = await loadItemSummaries(orm, origin);
|
|
4370
|
+
return summaries.filter((item) => ids.includes(item.id));
|
|
4371
|
+
}
|
|
4372
|
+
async function backlogHasItems() {
|
|
4373
|
+
const { orm } = await getReady();
|
|
4374
|
+
const [row] = await orm.select({ id: items.id }).from(items).where(eq11(items.origin, getOrigin())).limit(1);
|
|
4375
|
+
return row !== void 0;
|
|
4376
|
+
}
|
|
4377
|
+
|
|
4296
4378
|
// src/commands/backlog/web/getBacklogExists.ts
|
|
4297
4379
|
async function getBacklogExists(req, res) {
|
|
4298
4380
|
applyCwdFromReq(req);
|
|
4299
|
-
|
|
4300
|
-
respondJson(res, 200, { exists: items2.length > 0 });
|
|
4381
|
+
respondJson(res, 200, { exists: await backlogHasItems() });
|
|
4301
4382
|
}
|
|
4302
4383
|
|
|
4303
4384
|
// src/commands/backlog/web/rewindItemPhase.ts
|
|
4304
|
-
import { eq as
|
|
4385
|
+
import { eq as eq13 } from "drizzle-orm";
|
|
4305
4386
|
|
|
4306
4387
|
// src/commands/backlog/deleteComment.ts
|
|
4307
|
-
import { and as and2, eq as
|
|
4388
|
+
import { and as and2, eq as eq12 } from "drizzle-orm";
|
|
4308
4389
|
async function deleteComment(orm, itemId, commentId) {
|
|
4309
|
-
const [row] = await orm.select({ type: comments.type }).from(comments).where(and2(
|
|
4390
|
+
const [row] = await orm.select({ type: comments.type }).from(comments).where(and2(eq12(comments.id, commentId), eq12(comments.itemId, itemId)));
|
|
4310
4391
|
if (!row) return "not-found";
|
|
4311
4392
|
if (row.type === "summary") return "is-summary";
|
|
4312
|
-
await orm.delete(comments).where(and2(
|
|
4393
|
+
await orm.delete(comments).where(and2(eq12(comments.id, commentId), eq12(comments.itemId, itemId)));
|
|
4313
4394
|
return "deleted";
|
|
4314
4395
|
}
|
|
4315
4396
|
|
|
4397
|
+
// src/commands/backlog/web/loadVisibleItems.ts
|
|
4398
|
+
var completedStatuses = /* @__PURE__ */ new Set(["done", "wontdo"]);
|
|
4399
|
+
async function loadVisibleItems(req) {
|
|
4400
|
+
const params = new URL(req.url ?? "/", "http://localhost").searchParams;
|
|
4401
|
+
const q = params.get("q");
|
|
4402
|
+
const loaded = q ? await searchBacklogSummaries(q) : await loadBacklogSummaries();
|
|
4403
|
+
if (params.get("showCompleted") === "true") return loaded;
|
|
4404
|
+
return loaded.filter((item) => !completedStatuses.has(item.status));
|
|
4405
|
+
}
|
|
4406
|
+
|
|
4316
4407
|
// src/commands/backlog/web/shared.ts
|
|
4317
4408
|
async function listItems(req, res) {
|
|
4318
4409
|
applyCwdFromReq(req);
|
|
4319
|
-
const
|
|
4320
|
-
const items2 = q ? await searchBacklog(q) : await loadBacklog();
|
|
4410
|
+
const items2 = await loadVisibleItems(req);
|
|
4321
4411
|
respondJson(res, 200, items2.slice().reverse());
|
|
4322
4412
|
}
|
|
4323
4413
|
async function findItemOr404(res, id) {
|
|
@@ -4384,7 +4474,7 @@ async function rewindItemPhase(req, res, id) {
|
|
|
4384
4474
|
`Rewound to phase ${phase} (${phaseName}): ${reason}`,
|
|
4385
4475
|
{ phase }
|
|
4386
4476
|
);
|
|
4387
|
-
await orm.update(items).set({ currentPhase: phase, status: "in-progress" }).where(
|
|
4477
|
+
await orm.update(items).set({ currentPhase: phase, status: "in-progress" }).where(eq13(items.id, id));
|
|
4388
4478
|
respondJson(res, 200, await loadItem(orm, id));
|
|
4389
4479
|
}
|
|
4390
4480
|
function validateRewind(item, phase) {
|
|
@@ -4402,7 +4492,7 @@ function validateRewind(item, phase) {
|
|
|
4402
4492
|
}
|
|
4403
4493
|
|
|
4404
4494
|
// src/commands/backlog/web/updateItem.ts
|
|
4405
|
-
import { eq as
|
|
4495
|
+
import { eq as eq14 } from "drizzle-orm";
|
|
4406
4496
|
async function updateItem(req, res, id) {
|
|
4407
4497
|
const body = await parseItemBody(req);
|
|
4408
4498
|
const result = await findItemOr404(res, id);
|
|
@@ -4413,7 +4503,7 @@ async function updateItem(req, res, id) {
|
|
|
4413
4503
|
name: body.name,
|
|
4414
4504
|
description: body.description ?? null,
|
|
4415
4505
|
acceptanceCriteria: JSON.stringify(body.acceptanceCriteria ?? [])
|
|
4416
|
-
}).where(
|
|
4506
|
+
}).where(eq14(items.id, id));
|
|
4417
4507
|
respondJson(res, 200, await loadItem(orm, id));
|
|
4418
4508
|
}
|
|
4419
4509
|
|
|
@@ -4525,7 +4615,7 @@ function createCssHandler(packageEntry) {
|
|
|
4525
4615
|
return (_req, res) => {
|
|
4526
4616
|
if (!cache) {
|
|
4527
4617
|
const resolved = require3.resolve(packageEntry);
|
|
4528
|
-
cache =
|
|
4618
|
+
cache = readFileSync14(resolved, "utf-8");
|
|
4529
4619
|
}
|
|
4530
4620
|
res.writeHead(200, { "Content-Type": "text/css" });
|
|
4531
4621
|
res.end(cache);
|
|
@@ -4996,9 +5086,9 @@ import chalk51 from "chalk";
|
|
|
4996
5086
|
|
|
4997
5087
|
// src/commands/backlog/add/shared.ts
|
|
4998
5088
|
import { spawnSync } from "child_process";
|
|
4999
|
-
import { mkdtempSync, readFileSync as
|
|
5089
|
+
import { mkdtempSync, readFileSync as readFileSync15, unlinkSync as unlinkSync5, writeFileSync as writeFileSync14 } from "fs";
|
|
5000
5090
|
import { tmpdir } from "os";
|
|
5001
|
-
import { join as
|
|
5091
|
+
import { join as join18 } from "path";
|
|
5002
5092
|
import enquirer6 from "enquirer";
|
|
5003
5093
|
async function promptType() {
|
|
5004
5094
|
const { type } = await enquirer6.prompt({
|
|
@@ -5038,15 +5128,15 @@ async function promptDescription() {
|
|
|
5038
5128
|
}
|
|
5039
5129
|
function openEditor() {
|
|
5040
5130
|
const editor = process.env.EDITOR || process.env.VISUAL || "vi";
|
|
5041
|
-
const dir = mkdtempSync(
|
|
5042
|
-
const filePath =
|
|
5043
|
-
|
|
5131
|
+
const dir = mkdtempSync(join18(tmpdir(), "assist-"));
|
|
5132
|
+
const filePath = join18(dir, "description.md");
|
|
5133
|
+
writeFileSync14(filePath, "");
|
|
5044
5134
|
const result = spawnSync(editor, [filePath], { stdio: "inherit" });
|
|
5045
5135
|
if (result.status !== 0) {
|
|
5046
5136
|
unlinkSync5(filePath);
|
|
5047
5137
|
return void 0;
|
|
5048
5138
|
}
|
|
5049
|
-
const content =
|
|
5139
|
+
const content = readFileSync15(filePath, "utf-8").trim();
|
|
5050
5140
|
unlinkSync5(filePath);
|
|
5051
5141
|
return content || void 0;
|
|
5052
5142
|
}
|
|
@@ -5089,22 +5179,22 @@ async function add(options2) {
|
|
|
5089
5179
|
import chalk53 from "chalk";
|
|
5090
5180
|
|
|
5091
5181
|
// src/commands/backlog/insertPhaseAt.ts
|
|
5092
|
-
import { count, eq as
|
|
5182
|
+
import { count, eq as eq16 } from "drizzle-orm";
|
|
5093
5183
|
|
|
5094
5184
|
// src/commands/backlog/shiftPhasesUp.ts
|
|
5095
|
-
import { and as and3, desc, eq as
|
|
5185
|
+
import { and as and3, desc, eq as eq15, gte } from "drizzle-orm";
|
|
5096
5186
|
async function shiftPhasesUp(db, itemId, fromIdx) {
|
|
5097
|
-
const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and3(
|
|
5187
|
+
const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and3(eq15(planPhases.itemId, itemId), gte(planPhases.idx, fromIdx))).orderBy(desc(planPhases.idx));
|
|
5098
5188
|
for (const p of toShift) {
|
|
5099
|
-
await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and3(
|
|
5100
|
-
await db.update(planPhases).set({ idx: p.idx + 1 }).where(and3(
|
|
5189
|
+
await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and3(eq15(planTasks.itemId, itemId), eq15(planTasks.phaseIdx, p.idx)));
|
|
5190
|
+
await db.update(planPhases).set({ idx: p.idx + 1 }).where(and3(eq15(planPhases.itemId, itemId), eq15(planPhases.idx, p.idx)));
|
|
5101
5191
|
}
|
|
5102
5192
|
}
|
|
5103
5193
|
|
|
5104
5194
|
// src/commands/backlog/insertPhaseAt.ts
|
|
5105
5195
|
async function insertPhaseAt(orm, itemId, phaseIdx, name, tasks, manualChecks, currentPhase) {
|
|
5106
5196
|
await orm.transaction(async (tx) => {
|
|
5107
|
-
const [row] = await tx.select({ cnt: count() }).from(planPhases).where(
|
|
5197
|
+
const [row] = await tx.select({ cnt: count() }).from(planPhases).where(eq16(planPhases.itemId, itemId));
|
|
5108
5198
|
const phaseCount = row?.cnt ?? 0;
|
|
5109
5199
|
await shiftPhasesUp(tx, itemId, phaseIdx);
|
|
5110
5200
|
await tx.insert(planPhases).values({ itemId, idx: phaseIdx, name, manualChecks });
|
|
@@ -5113,16 +5203,16 @@ async function insertPhaseAt(orm, itemId, phaseIdx, name, tasks, manualChecks, c
|
|
|
5113
5203
|
}
|
|
5114
5204
|
if (currentPhase !== void 0 && currentPhase - 1 >= phaseIdx) {
|
|
5115
5205
|
const atReviewSlot = currentPhase - 1 >= phaseCount;
|
|
5116
|
-
await tx.update(items).set({ currentPhase: atReviewSlot ? phaseIdx + 1 : currentPhase + 1 }).where(
|
|
5206
|
+
await tx.update(items).set({ currentPhase: atReviewSlot ? phaseIdx + 1 : currentPhase + 1 }).where(eq16(items.id, itemId));
|
|
5117
5207
|
}
|
|
5118
5208
|
});
|
|
5119
5209
|
}
|
|
5120
5210
|
|
|
5121
5211
|
// src/commands/backlog/resolveInsertPosition.ts
|
|
5122
5212
|
import chalk52 from "chalk";
|
|
5123
|
-
import { count as count2, eq as
|
|
5213
|
+
import { count as count2, eq as eq17 } from "drizzle-orm";
|
|
5124
5214
|
async function resolveInsertPosition(orm, itemId, position) {
|
|
5125
|
-
const [row] = await orm.select({ cnt: count2() }).from(planPhases).where(
|
|
5215
|
+
const [row] = await orm.select({ cnt: count2() }).from(planPhases).where(eq17(planPhases.itemId, itemId));
|
|
5126
5216
|
const phaseCount = row?.cnt ?? 0;
|
|
5127
5217
|
if (position === void 0) return phaseCount;
|
|
5128
5218
|
const pos = Number.parseInt(position, 10);
|
|
@@ -5180,8 +5270,8 @@ import chalk54 from "chalk";
|
|
|
5180
5270
|
// src/commands/backlog/originDisplayName.ts
|
|
5181
5271
|
function originDisplayName(origin) {
|
|
5182
5272
|
if (origin.startsWith("local:")) {
|
|
5183
|
-
const
|
|
5184
|
-
const segments =
|
|
5273
|
+
const path53 = origin.slice("local:".length).replace(/\/+$/, "");
|
|
5274
|
+
const segments = path53.split("/").filter(Boolean);
|
|
5185
5275
|
return segments[segments.length - 1] ?? origin;
|
|
5186
5276
|
}
|
|
5187
5277
|
const firstSlash = origin.indexOf("/");
|
|
@@ -5236,9 +5326,9 @@ async function list2(options2) {
|
|
|
5236
5326
|
const repoNameOf = (item) => item.origin ? labels.get(item.origin) ?? "" : "";
|
|
5237
5327
|
const prefixWidth = options2.allRepos ? Math.max(0, ...items2.map((i) => repoNameOf(i).length)) : 0;
|
|
5238
5328
|
for (const item of items2) {
|
|
5239
|
-
const
|
|
5329
|
+
const repoPrefix = options2.allRepos ? `${chalk54.dim(repoNameOf(item).padEnd(prefixWidth))} ` : "";
|
|
5240
5330
|
console.log(
|
|
5241
|
-
`${
|
|
5331
|
+
`${repoPrefix}${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk54.dim(`#${item.id}`)} ${item.name}${phaseLabel(item)}${dependencyLabel(item, allItems)}`
|
|
5242
5332
|
);
|
|
5243
5333
|
if (options2.verbose) {
|
|
5244
5334
|
printVerboseDetails(item);
|
|
@@ -5283,9 +5373,9 @@ function hasCycle(adjacency, fromId, toId) {
|
|
|
5283
5373
|
}
|
|
5284
5374
|
|
|
5285
5375
|
// src/commands/backlog/loadDependencyGraph.ts
|
|
5286
|
-
import { eq as
|
|
5376
|
+
import { eq as eq18 } from "drizzle-orm";
|
|
5287
5377
|
async function loadDependencyGraph(orm) {
|
|
5288
|
-
const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(
|
|
5378
|
+
const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(eq18(links.type, "depends-on"));
|
|
5289
5379
|
const graph = /* @__PURE__ */ new Map();
|
|
5290
5380
|
for (const { itemId, targetId } of rows) {
|
|
5291
5381
|
const bucket = graph.get(itemId);
|
|
@@ -5348,7 +5438,7 @@ async function link(fromId, toId, opts) {
|
|
|
5348
5438
|
|
|
5349
5439
|
// src/commands/backlog/unlink.ts
|
|
5350
5440
|
import chalk57 from "chalk";
|
|
5351
|
-
import { and as and4, eq as
|
|
5441
|
+
import { and as and4, eq as eq19 } from "drizzle-orm";
|
|
5352
5442
|
async function unlink(fromId, toId) {
|
|
5353
5443
|
const fromNum = Number.parseInt(fromId, 10);
|
|
5354
5444
|
const toNum = Number.parseInt(toId, 10);
|
|
@@ -5366,7 +5456,7 @@ async function unlink(fromId, toId) {
|
|
|
5366
5456
|
console.log(chalk57.yellow(`No link from #${fromId} to #${toId} found.`));
|
|
5367
5457
|
return;
|
|
5368
5458
|
}
|
|
5369
|
-
await orm.delete(links).where(and4(
|
|
5459
|
+
await orm.delete(links).where(and4(eq19(links.itemId, fromNum), eq19(links.targetId, toNum)));
|
|
5370
5460
|
console.log(chalk57.green(`Removed link from #${fromId} to #${toId}.`));
|
|
5371
5461
|
}
|
|
5372
5462
|
|
|
@@ -5382,7 +5472,7 @@ function registerLinkCommands(cmd) {
|
|
|
5382
5472
|
|
|
5383
5473
|
// src/commands/backlog/move-repo/index.ts
|
|
5384
5474
|
import chalk59 from "chalk";
|
|
5385
|
-
import { eq as
|
|
5475
|
+
import { eq as eq21 } from "drizzle-orm";
|
|
5386
5476
|
|
|
5387
5477
|
// src/commands/backlog/move-repo/confirmMove.ts
|
|
5388
5478
|
import chalk58 from "chalk";
|
|
@@ -5397,9 +5487,9 @@ async function confirmMove(cnt, oldOrigin, newOrigin) {
|
|
|
5397
5487
|
}
|
|
5398
5488
|
|
|
5399
5489
|
// src/commands/backlog/move-repo/countByOrigin.ts
|
|
5400
|
-
import { count as count3, eq as
|
|
5490
|
+
import { count as count3, eq as eq20 } from "drizzle-orm";
|
|
5401
5491
|
async function countByOrigin(orm, origin) {
|
|
5402
|
-
const [{ cnt }] = await orm.select({ cnt: count3() }).from(items).where(
|
|
5492
|
+
const [{ cnt }] = await orm.select({ cnt: count3() }).from(items).where(eq20(items.origin, origin));
|
|
5403
5493
|
return cnt;
|
|
5404
5494
|
}
|
|
5405
5495
|
|
|
@@ -5442,7 +5532,7 @@ async function moveRepo(oldOriginRaw, newOriginRaw, options2 = {}) {
|
|
|
5442
5532
|
console.log(chalk59.yellow("Move cancelled; no changes made."));
|
|
5443
5533
|
return;
|
|
5444
5534
|
}
|
|
5445
|
-
await orm.update(items).set({ origin: newOrigin }).where(
|
|
5535
|
+
await orm.update(items).set({ origin: newOrigin }).where(eq21(items.origin, oldOrigin));
|
|
5446
5536
|
console.log(
|
|
5447
5537
|
chalk59.green(
|
|
5448
5538
|
`Moved ${pluralItems(cnt)} from "${oldOrigin}" to "${newOrigin}".`
|
|
@@ -5482,9 +5572,9 @@ import chalk61 from "chalk";
|
|
|
5482
5572
|
// src/commands/backlog/tryRunById.ts
|
|
5483
5573
|
import chalk60 from "chalk";
|
|
5484
5574
|
async function tryRunById(id, options2) {
|
|
5485
|
-
const items2 = await loadBacklog();
|
|
5486
5575
|
const numericId = Number.parseInt(id, 10);
|
|
5487
|
-
const
|
|
5576
|
+
const { orm } = await getReady();
|
|
5577
|
+
const item = Number.isNaN(numericId) ? void 0 : await loadItem(orm, numericId);
|
|
5488
5578
|
if (!item) {
|
|
5489
5579
|
console.log(chalk60.red(`Item #${id} not found.`));
|
|
5490
5580
|
return false;
|
|
@@ -5497,7 +5587,8 @@ async function tryRunById(id, options2) {
|
|
|
5497
5587
|
console.log(chalk60.red(`Item #${id} is marked won't do.`));
|
|
5498
5588
|
return false;
|
|
5499
5589
|
}
|
|
5500
|
-
|
|
5590
|
+
const hasDeps = (item.links ?? []).some((l) => l.type === "depends-on");
|
|
5591
|
+
if (hasDeps && isBlocked(item, await loadItemSummaries(orm, getOrigin()))) {
|
|
5501
5592
|
console.log(
|
|
5502
5593
|
chalk60.red(`Item #${id} is blocked by unresolved dependencies.`)
|
|
5503
5594
|
);
|
|
@@ -5511,10 +5602,18 @@ Running backlog item #${id}...
|
|
|
5511
5602
|
}
|
|
5512
5603
|
|
|
5513
5604
|
// src/commands/backlog/launchMode.ts
|
|
5605
|
+
function buildSlashCommand(slashCommand, description) {
|
|
5606
|
+
const trimmed = description?.trim();
|
|
5607
|
+
return trimmed ? `/${slashCommand} ${trimmed}` : `/${slashCommand}`;
|
|
5608
|
+
}
|
|
5514
5609
|
async function launchMode(slashCommand, options2) {
|
|
5515
5610
|
pullIfConfigured();
|
|
5516
|
-
process.env.ASSIST_SESSION_ID
|
|
5517
|
-
|
|
5611
|
+
process.env.ASSIST_SESSION_ID ??= String(process.pid);
|
|
5612
|
+
emitActivity({ kind: "command", name: slashCommand });
|
|
5613
|
+
const { child, done: done2 } = spawnClaude(
|
|
5614
|
+
buildSlashCommand(slashCommand, options2?.description),
|
|
5615
|
+
{ allowEdits: true }
|
|
5616
|
+
);
|
|
5518
5617
|
watchForMarker(child, { actOnDone: options2?.once });
|
|
5519
5618
|
await done2;
|
|
5520
5619
|
stopWatching();
|
|
@@ -5531,7 +5630,7 @@ async function launchMode(slashCommand, options2) {
|
|
|
5531
5630
|
|
|
5532
5631
|
// src/commands/backlog/refine.ts
|
|
5533
5632
|
async function pickItemForRefine() {
|
|
5534
|
-
const items2 = await
|
|
5633
|
+
const items2 = await loadBacklogSummaries();
|
|
5535
5634
|
const active = items2.filter(
|
|
5536
5635
|
(i) => i.status === "todo" || i.status === "in-progress"
|
|
5537
5636
|
);
|
|
@@ -5706,10 +5805,10 @@ async function start(id) {
|
|
|
5706
5805
|
|
|
5707
5806
|
// src/commands/backlog/stop/index.ts
|
|
5708
5807
|
import chalk68 from "chalk";
|
|
5709
|
-
import { and as and5, eq as
|
|
5808
|
+
import { and as and5, eq as eq22 } from "drizzle-orm";
|
|
5710
5809
|
async function stop() {
|
|
5711
5810
|
const { orm } = await getReady();
|
|
5712
|
-
const stopped = await orm.update(items).set({ status: "todo", currentPhase: 1 }).where(and5(
|
|
5811
|
+
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 });
|
|
5713
5812
|
if (stopped.length === 0) {
|
|
5714
5813
|
console.log(chalk68.yellow("No in-progress items to stop."));
|
|
5715
5814
|
return;
|
|
@@ -5744,18 +5843,18 @@ function registerStatusCommands(cmd) {
|
|
|
5744
5843
|
|
|
5745
5844
|
// src/commands/backlog/removePhase.ts
|
|
5746
5845
|
import chalk71 from "chalk";
|
|
5747
|
-
import { and as and8, eq as
|
|
5846
|
+
import { and as and8, eq as eq25 } from "drizzle-orm";
|
|
5748
5847
|
|
|
5749
5848
|
// src/commands/backlog/findPhase.ts
|
|
5750
5849
|
import chalk70 from "chalk";
|
|
5751
|
-
import { and as and6, count as count4, eq as
|
|
5850
|
+
import { and as and6, count as count4, eq as eq23 } from "drizzle-orm";
|
|
5752
5851
|
async function findPhase(id, phase) {
|
|
5753
5852
|
const found = await findOneItem(id);
|
|
5754
5853
|
if (!found) return void 0;
|
|
5755
5854
|
const { orm, item } = found;
|
|
5756
5855
|
const itemId = item.id;
|
|
5757
5856
|
const phaseIdx = Number.parseInt(phase, 10) - 1;
|
|
5758
|
-
const [row] = await orm.select({ cnt: count4() }).from(planPhases).where(and6(
|
|
5857
|
+
const [row] = await orm.select({ cnt: count4() }).from(planPhases).where(and6(eq23(planPhases.itemId, itemId), eq23(planPhases.idx, phaseIdx)));
|
|
5759
5858
|
if (!row || row.cnt === 0) {
|
|
5760
5859
|
console.log(
|
|
5761
5860
|
chalk70.red(`Phase ${phaseIdx + 1} not found on item #${itemId}.`)
|
|
@@ -5767,14 +5866,14 @@ async function findPhase(id, phase) {
|
|
|
5767
5866
|
}
|
|
5768
5867
|
|
|
5769
5868
|
// src/commands/backlog/reindexPhases.ts
|
|
5770
|
-
import { and as and7, asc as
|
|
5869
|
+
import { and as and7, asc as asc5, count as count5, eq as eq24 } from "drizzle-orm";
|
|
5771
5870
|
async function reindexPhases(db, itemId) {
|
|
5772
|
-
const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(
|
|
5871
|
+
const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq24(planPhases.itemId, itemId)).orderBy(asc5(planPhases.idx));
|
|
5773
5872
|
for (let i = 0; i < remaining.length; i++) {
|
|
5774
5873
|
const oldIdx = remaining[i].idx;
|
|
5775
5874
|
if (oldIdx === i) continue;
|
|
5776
|
-
await db.update(planTasks).set({ phaseIdx: i }).where(and7(
|
|
5777
|
-
await db.update(planPhases).set({ idx: i }).where(and7(
|
|
5875
|
+
await db.update(planTasks).set({ phaseIdx: i }).where(and7(eq24(planTasks.itemId, itemId), eq24(planTasks.phaseIdx, oldIdx)));
|
|
5876
|
+
await db.update(planPhases).set({ idx: i }).where(and7(eq24(planPhases.itemId, itemId), eq24(planPhases.idx, oldIdx)));
|
|
5778
5877
|
}
|
|
5779
5878
|
}
|
|
5780
5879
|
async function adjustCurrentPhase(db, item, removedIdx) {
|
|
@@ -5782,13 +5881,13 @@ async function adjustCurrentPhase(db, item, removedIdx) {
|
|
|
5782
5881
|
if (currentPhase === void 0) return;
|
|
5783
5882
|
const currentIdx = currentPhase - 1;
|
|
5784
5883
|
if (removedIdx < currentIdx) {
|
|
5785
|
-
await db.update(items).set({ currentPhase: currentPhase - 1 }).where(
|
|
5884
|
+
await db.update(items).set({ currentPhase: currentPhase - 1 }).where(eq24(items.id, item.id));
|
|
5786
5885
|
return;
|
|
5787
5886
|
}
|
|
5788
5887
|
if (removedIdx !== currentIdx) return;
|
|
5789
|
-
const [row] = await db.select({ cnt: count5() }).from(planPhases).where(
|
|
5888
|
+
const [row] = await db.select({ cnt: count5() }).from(planPhases).where(eq24(planPhases.itemId, item.id));
|
|
5790
5889
|
const cnt = row?.cnt ?? 0;
|
|
5791
|
-
await db.update(items).set({ currentPhase: cnt === 0 ? null : Math.min(currentPhase, cnt) }).where(
|
|
5890
|
+
await db.update(items).set({ currentPhase: cnt === 0 ? null : Math.min(currentPhase, cnt) }).where(eq24(items.id, item.id));
|
|
5792
5891
|
}
|
|
5793
5892
|
|
|
5794
5893
|
// src/commands/backlog/removePhase.ts
|
|
@@ -5798,9 +5897,9 @@ async function removePhase(id, phase) {
|
|
|
5798
5897
|
const { item, orm, itemId, phaseIdx } = found;
|
|
5799
5898
|
await orm.transaction(async (tx) => {
|
|
5800
5899
|
await tx.delete(planTasks).where(
|
|
5801
|
-
and8(
|
|
5900
|
+
and8(eq25(planTasks.itemId, itemId), eq25(planTasks.phaseIdx, phaseIdx))
|
|
5802
5901
|
);
|
|
5803
|
-
await tx.delete(planPhases).where(and8(
|
|
5902
|
+
await tx.delete(planPhases).where(and8(eq25(planPhases.itemId, itemId), eq25(planPhases.idx, phaseIdx)));
|
|
5804
5903
|
await reindexPhases(tx, itemId);
|
|
5805
5904
|
await adjustCurrentPhase(tx, item, phaseIdx);
|
|
5806
5905
|
});
|
|
@@ -5811,7 +5910,7 @@ async function removePhase(id, phase) {
|
|
|
5811
5910
|
|
|
5812
5911
|
// src/commands/backlog/update/index.ts
|
|
5813
5912
|
import chalk73 from "chalk";
|
|
5814
|
-
import { eq as
|
|
5913
|
+
import { eq as eq26 } from "drizzle-orm";
|
|
5815
5914
|
|
|
5816
5915
|
// src/commands/backlog/update/parseListIndex.ts
|
|
5817
5916
|
function parseListIndex(raw, length, label2) {
|
|
@@ -5945,7 +6044,7 @@ async function update(id, options2) {
|
|
|
5945
6044
|
if (!built) return;
|
|
5946
6045
|
const { orm } = found;
|
|
5947
6046
|
const itemId = found.item.id;
|
|
5948
|
-
await orm.update(items).set(built.set).where(
|
|
6047
|
+
await orm.update(items).set(built.set).where(eq26(items.id, itemId));
|
|
5949
6048
|
console.log(chalk73.green(`Updated ${built.fields} on item #${itemId}.`));
|
|
5950
6049
|
}
|
|
5951
6050
|
|
|
@@ -5953,22 +6052,22 @@ async function update(id, options2) {
|
|
|
5953
6052
|
import chalk74 from "chalk";
|
|
5954
6053
|
|
|
5955
6054
|
// src/commands/backlog/applyPhaseUpdate.ts
|
|
5956
|
-
import { and as and9, eq as
|
|
6055
|
+
import { and as and9, eq as eq27 } from "drizzle-orm";
|
|
5957
6056
|
async function applyPhaseUpdate(orm, itemId, phaseIdx, fields) {
|
|
5958
6057
|
await orm.transaction(async (tx) => {
|
|
5959
6058
|
if (fields.name) {
|
|
5960
6059
|
await tx.update(planPhases).set({ name: fields.name }).where(
|
|
5961
|
-
and9(
|
|
6060
|
+
and9(eq27(planPhases.itemId, itemId), eq27(planPhases.idx, phaseIdx))
|
|
5962
6061
|
);
|
|
5963
6062
|
}
|
|
5964
6063
|
if (fields.manualCheck) {
|
|
5965
6064
|
await tx.update(planPhases).set({ manualChecks: JSON.stringify(fields.manualCheck) }).where(
|
|
5966
|
-
and9(
|
|
6065
|
+
and9(eq27(planPhases.itemId, itemId), eq27(planPhases.idx, phaseIdx))
|
|
5967
6066
|
);
|
|
5968
6067
|
}
|
|
5969
6068
|
if (fields.task) {
|
|
5970
6069
|
await tx.delete(planTasks).where(
|
|
5971
|
-
and9(
|
|
6070
|
+
and9(eq27(planTasks.itemId, itemId), eq27(planTasks.phaseIdx, phaseIdx))
|
|
5972
6071
|
);
|
|
5973
6072
|
if (fields.task.length) {
|
|
5974
6073
|
await tx.insert(planTasks).values(
|
|
@@ -6258,13 +6357,13 @@ function stripEnvPrefix(parts) {
|
|
|
6258
6357
|
}
|
|
6259
6358
|
|
|
6260
6359
|
// src/commands/cliHook/logDeniedToolCall.ts
|
|
6261
|
-
import { mkdirSync as
|
|
6360
|
+
import { mkdirSync as mkdirSync6 } from "fs";
|
|
6262
6361
|
import { homedir as homedir4 } from "os";
|
|
6263
|
-
import { join as
|
|
6362
|
+
import { join as join19 } from "path";
|
|
6264
6363
|
import Database from "better-sqlite3";
|
|
6265
6364
|
var _db;
|
|
6266
6365
|
function getDbDir() {
|
|
6267
|
-
return
|
|
6366
|
+
return join19(homedir4(), ".assist");
|
|
6268
6367
|
}
|
|
6269
6368
|
function initSchema(db) {
|
|
6270
6369
|
db.exec(`
|
|
@@ -6282,8 +6381,8 @@ function initSchema(db) {
|
|
|
6282
6381
|
function openPromptsDb(dir) {
|
|
6283
6382
|
if (_db) return _db;
|
|
6284
6383
|
const dbDir = dir ?? getDbDir();
|
|
6285
|
-
|
|
6286
|
-
const db = new Database(
|
|
6384
|
+
mkdirSync6(dbDir, { recursive: true });
|
|
6385
|
+
const db = new Database(join19(dbDir, "assist.db"));
|
|
6287
6386
|
db.pragma("journal_mode = WAL");
|
|
6288
6387
|
initSchema(db);
|
|
6289
6388
|
_db = db;
|
|
@@ -6385,17 +6484,17 @@ function extractGraphqlQuery(args) {
|
|
|
6385
6484
|
}
|
|
6386
6485
|
|
|
6387
6486
|
// src/shared/loadCliReads.ts
|
|
6388
|
-
import { existsSync as existsSync21, readFileSync as
|
|
6389
|
-
import { dirname as
|
|
6487
|
+
import { existsSync as existsSync21, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
|
|
6488
|
+
import { dirname as dirname17, resolve as resolve7 } from "path";
|
|
6390
6489
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
6391
6490
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
6392
|
-
var __dirname5 =
|
|
6491
|
+
var __dirname5 = dirname17(__filename3);
|
|
6393
6492
|
function packageRoot() {
|
|
6394
6493
|
return __dirname5;
|
|
6395
6494
|
}
|
|
6396
|
-
function readLines(
|
|
6397
|
-
if (!existsSync21(
|
|
6398
|
-
return
|
|
6495
|
+
function readLines(path53) {
|
|
6496
|
+
if (!existsSync21(path53)) return [];
|
|
6497
|
+
return readFileSync16(path53, "utf-8").split("\n").filter((line) => line.trim() !== "");
|
|
6399
6498
|
}
|
|
6400
6499
|
var cachedReads;
|
|
6401
6500
|
var cachedWrites;
|
|
@@ -6415,7 +6514,7 @@ function loadCliReads() {
|
|
|
6415
6514
|
return getCliReadsLines();
|
|
6416
6515
|
}
|
|
6417
6516
|
function saveCliReads(commands) {
|
|
6418
|
-
|
|
6517
|
+
writeFileSync15(
|
|
6419
6518
|
resolve7(packageRoot(), "allowed.cli-reads"),
|
|
6420
6519
|
`${commands.join("\n")}
|
|
6421
6520
|
`
|
|
@@ -6441,14 +6540,14 @@ function findCliWrite(command) {
|
|
|
6441
6540
|
}
|
|
6442
6541
|
|
|
6443
6542
|
// src/shared/readSettingsPerms.ts
|
|
6444
|
-
import { existsSync as existsSync22, readFileSync as
|
|
6543
|
+
import { existsSync as existsSync22, readFileSync as readFileSync17 } from "fs";
|
|
6445
6544
|
import { homedir as homedir5 } from "os";
|
|
6446
|
-
import { join as
|
|
6545
|
+
import { join as join20 } from "path";
|
|
6447
6546
|
function readSettingsPerms(key) {
|
|
6448
6547
|
const paths = [
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6548
|
+
join20(homedir5(), ".claude", "settings.json"),
|
|
6549
|
+
join20(process.cwd(), ".claude", "settings.json"),
|
|
6550
|
+
join20(process.cwd(), ".claude", "settings.local.json")
|
|
6452
6551
|
];
|
|
6453
6552
|
const entries = [];
|
|
6454
6553
|
for (const p of paths) {
|
|
@@ -6459,7 +6558,7 @@ function readSettingsPerms(key) {
|
|
|
6459
6558
|
function readPermissionArray(filePath, key) {
|
|
6460
6559
|
if (!existsSync22(filePath)) return [];
|
|
6461
6560
|
try {
|
|
6462
|
-
const data = JSON.parse(
|
|
6561
|
+
const data = JSON.parse(readFileSync17(filePath, "utf-8"));
|
|
6463
6562
|
const arr = data?.permissions?.[key];
|
|
6464
6563
|
return Array.isArray(arr) ? arr.filter((e) => typeof e === "string") : [];
|
|
6465
6564
|
} catch {
|
|
@@ -6739,9 +6838,9 @@ ${reasons.join("\n")}`);
|
|
|
6739
6838
|
}
|
|
6740
6839
|
|
|
6741
6840
|
// src/commands/permitCliReads/index.ts
|
|
6742
|
-
import { existsSync as existsSync23, mkdirSync as
|
|
6841
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync7, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
6743
6842
|
import { homedir as homedir6 } from "os";
|
|
6744
|
-
import { join as
|
|
6843
|
+
import { join as join21 } from "path";
|
|
6745
6844
|
|
|
6746
6845
|
// src/shared/checkCliAvailable.ts
|
|
6747
6846
|
import { execSync as execSync19 } from "child_process";
|
|
@@ -6878,14 +6977,14 @@ function showProgress(p, label2) {
|
|
|
6878
6977
|
const pct = Math.round(p.done / p.total * 100);
|
|
6879
6978
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
6880
6979
|
}
|
|
6881
|
-
async function resolveCommand(cli,
|
|
6882
|
-
showProgress(p,
|
|
6883
|
-
const subHelp = await runHelp([cli, ...
|
|
6980
|
+
async function resolveCommand(cli, path53, description, depth, p) {
|
|
6981
|
+
showProgress(p, path53.join(" "));
|
|
6982
|
+
const subHelp = await runHelp([cli, ...path53]);
|
|
6884
6983
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
6885
|
-
return [{ path:
|
|
6984
|
+
return [{ path: path53, description }];
|
|
6886
6985
|
}
|
|
6887
|
-
const children = await discoverAt(cli,
|
|
6888
|
-
return children.length > 0 ? children : [{ path:
|
|
6986
|
+
const children = await discoverAt(cli, path53, depth + 1, p);
|
|
6987
|
+
return children.length > 0 ? children : [{ path: path53, description }];
|
|
6889
6988
|
}
|
|
6890
6989
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
6891
6990
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -7030,17 +7129,17 @@ function updateSettings(cli, commands) {
|
|
|
7030
7129
|
// src/commands/permitCliReads/index.ts
|
|
7031
7130
|
function logPath(cli) {
|
|
7032
7131
|
const safeName = cli.replace(/\s+/g, "-");
|
|
7033
|
-
return
|
|
7132
|
+
return join21(homedir6(), ".assist", `cli-discover-${safeName}.log`);
|
|
7034
7133
|
}
|
|
7035
7134
|
function readCache(cli) {
|
|
7036
|
-
const
|
|
7037
|
-
if (!existsSync23(
|
|
7038
|
-
return
|
|
7135
|
+
const path53 = logPath(cli);
|
|
7136
|
+
if (!existsSync23(path53)) return void 0;
|
|
7137
|
+
return readFileSync18(path53, "utf-8");
|
|
7039
7138
|
}
|
|
7040
7139
|
function writeCache(cli, output) {
|
|
7041
|
-
const dir =
|
|
7042
|
-
|
|
7043
|
-
|
|
7140
|
+
const dir = join21(homedir6(), ".assist");
|
|
7141
|
+
mkdirSync7(dir, { recursive: true });
|
|
7142
|
+
writeFileSync16(logPath(cli), output);
|
|
7044
7143
|
}
|
|
7045
7144
|
async function permitCliReads(cli, options2 = { noCache: false }) {
|
|
7046
7145
|
if (!cli) {
|
|
@@ -7634,6 +7733,11 @@ async function analyze(pattern2) {
|
|
|
7634
7733
|
await halstead(file);
|
|
7635
7734
|
console.log();
|
|
7636
7735
|
console.log(chalk84.bold.underline("Maintainability Index"));
|
|
7736
|
+
console.log(
|
|
7737
|
+
chalk84.dim(
|
|
7738
|
+
"171 - 5.2*ln(HalsteadVolume) - 0.23*CyclomaticComplexity - 16.2*ln(SLOC), clamped 0-100"
|
|
7739
|
+
)
|
|
7740
|
+
);
|
|
7637
7741
|
await maintainability(file);
|
|
7638
7742
|
return;
|
|
7639
7743
|
}
|
|
@@ -7700,8 +7804,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
7700
7804
|
}
|
|
7701
7805
|
return ensureObject(container, resolved);
|
|
7702
7806
|
}
|
|
7703
|
-
function setNestedValue(obj,
|
|
7704
|
-
const keys =
|
|
7807
|
+
function setNestedValue(obj, path53, value) {
|
|
7808
|
+
const keys = path53.split(".");
|
|
7705
7809
|
const result = { ...obj };
|
|
7706
7810
|
let current = result;
|
|
7707
7811
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -7781,9 +7885,9 @@ function isTraversable(value) {
|
|
|
7781
7885
|
function stepInto(current, key) {
|
|
7782
7886
|
return isTraversable(current) ? current[key] : void 0;
|
|
7783
7887
|
}
|
|
7784
|
-
function getNestedValue(obj,
|
|
7888
|
+
function getNestedValue(obj, path53) {
|
|
7785
7889
|
let current = obj;
|
|
7786
|
-
for (const key of
|
|
7890
|
+
for (const key of path53.split(".")) current = stepInto(current, key);
|
|
7787
7891
|
return current;
|
|
7788
7892
|
}
|
|
7789
7893
|
|
|
@@ -7817,7 +7921,7 @@ function registerConfig(program2) {
|
|
|
7817
7921
|
}
|
|
7818
7922
|
|
|
7819
7923
|
// src/commands/deploy/redirect.ts
|
|
7820
|
-
import { existsSync as existsSync24, readFileSync as
|
|
7924
|
+
import { existsSync as existsSync24, readFileSync as readFileSync19, writeFileSync as writeFileSync17 } from "fs";
|
|
7821
7925
|
import chalk87 from "chalk";
|
|
7822
7926
|
var TRAILING_SLASH_SCRIPT = ` <script>
|
|
7823
7927
|
if (!window.location.pathname.endsWith('/')) {
|
|
@@ -7830,7 +7934,7 @@ function redirect() {
|
|
|
7830
7934
|
console.log(chalk87.yellow("No index.html found"));
|
|
7831
7935
|
return;
|
|
7832
7936
|
}
|
|
7833
|
-
const content =
|
|
7937
|
+
const content = readFileSync19(indexPath, "utf-8");
|
|
7834
7938
|
if (content.includes("window.location.pathname.endsWith('/')")) {
|
|
7835
7939
|
console.log(chalk87.dim("Trailing slash script already present"));
|
|
7836
7940
|
return;
|
|
@@ -7841,7 +7945,7 @@ function redirect() {
|
|
|
7841
7945
|
return;
|
|
7842
7946
|
}
|
|
7843
7947
|
const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
|
|
7844
|
-
|
|
7948
|
+
writeFileSync17(indexPath, newContent);
|
|
7845
7949
|
console.log(chalk87.green("Added trailing slash redirect to index.html"));
|
|
7846
7950
|
}
|
|
7847
7951
|
|
|
@@ -7858,10 +7962,10 @@ import { basename as basename4 } from "path";
|
|
|
7858
7962
|
|
|
7859
7963
|
// src/commands/devlog/loadBlogSkipDays.ts
|
|
7860
7964
|
import { homedir as homedir7 } from "os";
|
|
7861
|
-
import { join as
|
|
7862
|
-
var BLOG_REPO_ROOT =
|
|
7965
|
+
import { join as join22 } from "path";
|
|
7966
|
+
var BLOG_REPO_ROOT = join22(homedir7(), "git/blog");
|
|
7863
7967
|
function loadBlogSkipDays(repoName) {
|
|
7864
|
-
const config = loadRawYaml(
|
|
7968
|
+
const config = loadRawYaml(join22(BLOG_REPO_ROOT, "assist.yml"));
|
|
7865
7969
|
const devlog = config.devlog;
|
|
7866
7970
|
const skip2 = devlog?.skip;
|
|
7867
7971
|
return new Set(skip2?.[repoName] ?? []);
|
|
@@ -7872,17 +7976,17 @@ import { execSync as execSync20 } from "child_process";
|
|
|
7872
7976
|
import chalk88 from "chalk";
|
|
7873
7977
|
|
|
7874
7978
|
// src/shared/getRepoName.ts
|
|
7875
|
-
import { existsSync as existsSync25, readFileSync as
|
|
7876
|
-
import { basename as basename3, join as
|
|
7979
|
+
import { existsSync as existsSync25, readFileSync as readFileSync20 } from "fs";
|
|
7980
|
+
import { basename as basename3, join as join23 } from "path";
|
|
7877
7981
|
function getRepoName() {
|
|
7878
7982
|
const config = loadConfig();
|
|
7879
7983
|
if (config.devlog?.name) {
|
|
7880
7984
|
return config.devlog.name;
|
|
7881
7985
|
}
|
|
7882
|
-
const packageJsonPath =
|
|
7986
|
+
const packageJsonPath = join23(process.cwd(), "package.json");
|
|
7883
7987
|
if (existsSync25(packageJsonPath)) {
|
|
7884
7988
|
try {
|
|
7885
|
-
const content =
|
|
7989
|
+
const content = readFileSync20(packageJsonPath, "utf-8");
|
|
7886
7990
|
const pkg = JSON.parse(content);
|
|
7887
7991
|
if (pkg.name) {
|
|
7888
7992
|
return pkg.name;
|
|
@@ -7894,9 +7998,9 @@ function getRepoName() {
|
|
|
7894
7998
|
}
|
|
7895
7999
|
|
|
7896
8000
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
7897
|
-
import { readdirSync, readFileSync as
|
|
7898
|
-
import { join as
|
|
7899
|
-
var DEVLOG_DIR =
|
|
8001
|
+
import { readdirSync, readFileSync as readFileSync21 } from "fs";
|
|
8002
|
+
import { join as join24 } from "path";
|
|
8003
|
+
var DEVLOG_DIR = join24(BLOG_REPO_ROOT, "src/content/devlog");
|
|
7900
8004
|
function extractFrontmatter(content) {
|
|
7901
8005
|
const fm = content.match(/^---\n([\s\S]*?)\n---/);
|
|
7902
8006
|
return fm?.[1] ?? null;
|
|
@@ -7924,7 +8028,7 @@ function readDevlogFiles(callback) {
|
|
|
7924
8028
|
try {
|
|
7925
8029
|
const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
|
|
7926
8030
|
for (const file of files) {
|
|
7927
|
-
const content =
|
|
8031
|
+
const content = readFileSync21(join24(DEVLOG_DIR, file), "utf-8");
|
|
7928
8032
|
const parsed = parseFrontmatter(content, file);
|
|
7929
8033
|
if (parsed) callback(parsed);
|
|
7930
8034
|
}
|
|
@@ -8311,12 +8415,12 @@ function repos(options2) {
|
|
|
8311
8415
|
}
|
|
8312
8416
|
|
|
8313
8417
|
// src/commands/devlog/skip.ts
|
|
8314
|
-
import { writeFileSync as
|
|
8315
|
-
import { join as
|
|
8418
|
+
import { writeFileSync as writeFileSync18 } from "fs";
|
|
8419
|
+
import { join as join25 } from "path";
|
|
8316
8420
|
import chalk93 from "chalk";
|
|
8317
8421
|
import { stringify as stringifyYaml3 } from "yaml";
|
|
8318
8422
|
function getBlogConfigPath() {
|
|
8319
|
-
return
|
|
8423
|
+
return join25(BLOG_REPO_ROOT, "assist.yml");
|
|
8320
8424
|
}
|
|
8321
8425
|
function skip(date) {
|
|
8322
8426
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
@@ -8340,7 +8444,7 @@ function skip(date) {
|
|
|
8340
8444
|
skip2[repoName] = skipDays;
|
|
8341
8445
|
devlog.skip = skip2;
|
|
8342
8446
|
config.devlog = devlog;
|
|
8343
|
-
|
|
8447
|
+
writeFileSync18(configPath, stringifyYaml3(config, { lineWidth: 0 }));
|
|
8344
8448
|
console.log(chalk93.green(`Added ${date} to skip list for ${repoName}`));
|
|
8345
8449
|
}
|
|
8346
8450
|
|
|
@@ -8377,7 +8481,7 @@ function registerDevlog(program2) {
|
|
|
8377
8481
|
|
|
8378
8482
|
// src/commands/dotnet/checkBuildLocks.ts
|
|
8379
8483
|
import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync2 } from "fs";
|
|
8380
|
-
import { join as
|
|
8484
|
+
import { join as join26 } from "path";
|
|
8381
8485
|
import chalk95 from "chalk";
|
|
8382
8486
|
|
|
8383
8487
|
// src/shared/findRepoRoot.ts
|
|
@@ -8405,7 +8509,7 @@ function isLockedDll(debugDir) {
|
|
|
8405
8509
|
}
|
|
8406
8510
|
for (const file of files) {
|
|
8407
8511
|
if (!file.toLowerCase().endsWith(".dll")) continue;
|
|
8408
|
-
const dllPath =
|
|
8512
|
+
const dllPath = join26(debugDir, file);
|
|
8409
8513
|
try {
|
|
8410
8514
|
const fd = openSync2(dllPath, "r+");
|
|
8411
8515
|
closeSync2(fd);
|
|
@@ -8423,13 +8527,13 @@ function findFirstLockedDll(dir) {
|
|
|
8423
8527
|
return null;
|
|
8424
8528
|
}
|
|
8425
8529
|
if (entries.includes("bin")) {
|
|
8426
|
-
const locked = isLockedDll(
|
|
8530
|
+
const locked = isLockedDll(join26(dir, "bin", "Debug"));
|
|
8427
8531
|
if (locked) return locked;
|
|
8428
8532
|
}
|
|
8429
8533
|
for (const entry of entries) {
|
|
8430
8534
|
if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
|
|
8431
8535
|
continue;
|
|
8432
|
-
const found = findFirstLockedDll(
|
|
8536
|
+
const found = findFirstLockedDll(join26(dir, entry));
|
|
8433
8537
|
if (found) return found;
|
|
8434
8538
|
}
|
|
8435
8539
|
return null;
|
|
@@ -8452,11 +8556,11 @@ async function checkBuildLocksCommand() {
|
|
|
8452
8556
|
}
|
|
8453
8557
|
|
|
8454
8558
|
// src/commands/dotnet/buildTree.ts
|
|
8455
|
-
import { readFileSync as
|
|
8559
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
8456
8560
|
import path21 from "path";
|
|
8457
8561
|
var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
|
|
8458
8562
|
function getProjectRefs(csprojPath) {
|
|
8459
|
-
const content =
|
|
8563
|
+
const content = readFileSync22(csprojPath, "utf-8");
|
|
8460
8564
|
const refs = [];
|
|
8461
8565
|
for (const match of content.matchAll(PROJECT_REF_RE)) {
|
|
8462
8566
|
refs.push(match[1].replace(/\\/g, "/"));
|
|
@@ -8473,7 +8577,7 @@ function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
|
|
|
8473
8577
|
for (const ref of getProjectRefs(abs)) {
|
|
8474
8578
|
const childAbs = path21.resolve(dir, ref);
|
|
8475
8579
|
try {
|
|
8476
|
-
|
|
8580
|
+
readFileSync22(childAbs);
|
|
8477
8581
|
node.children.push(buildTree(childAbs, repoRoot, visited));
|
|
8478
8582
|
} catch {
|
|
8479
8583
|
node.children.push({
|
|
@@ -8498,7 +8602,7 @@ function collectAllDeps(node) {
|
|
|
8498
8602
|
}
|
|
8499
8603
|
|
|
8500
8604
|
// src/commands/dotnet/findContainingSolutions.ts
|
|
8501
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
8605
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync23, statSync as statSync2 } from "fs";
|
|
8502
8606
|
import path22 from "path";
|
|
8503
8607
|
function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
8504
8608
|
if (depth > maxDepth) return [];
|
|
@@ -8533,7 +8637,7 @@ function findContainingSolutions(csprojPath, repoRoot) {
|
|
|
8533
8637
|
const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
|
|
8534
8638
|
for (const sln of slnFiles) {
|
|
8535
8639
|
try {
|
|
8536
|
-
const content =
|
|
8640
|
+
const content = readFileSync23(sln, "utf-8");
|
|
8537
8641
|
if (pattern2.test(content)) {
|
|
8538
8642
|
matches.push(path22.relative(repoRoot, sln));
|
|
8539
8643
|
}
|
|
@@ -8776,11 +8880,11 @@ import chalk101 from "chalk";
|
|
|
8776
8880
|
|
|
8777
8881
|
// src/commands/dotnet/findSolution.ts
|
|
8778
8882
|
import { readdirSync as readdirSync4 } from "fs";
|
|
8779
|
-
import { dirname as
|
|
8883
|
+
import { dirname as dirname18, join as join27 } from "path";
|
|
8780
8884
|
import chalk100 from "chalk";
|
|
8781
8885
|
function findSlnInDir(dir) {
|
|
8782
8886
|
try {
|
|
8783
|
-
return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) =>
|
|
8887
|
+
return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join27(dir, f));
|
|
8784
8888
|
} catch {
|
|
8785
8889
|
return [];
|
|
8786
8890
|
}
|
|
@@ -8801,7 +8905,7 @@ function findSolution() {
|
|
|
8801
8905
|
process.exit(1);
|
|
8802
8906
|
}
|
|
8803
8907
|
if (current === ceiling) break;
|
|
8804
|
-
current =
|
|
8908
|
+
current = dirname18(current);
|
|
8805
8909
|
}
|
|
8806
8910
|
console.error(chalk100.red("No .sln file found between cwd and repo root"));
|
|
8807
8911
|
process.exit(1);
|
|
@@ -8851,7 +8955,7 @@ function parseInspectReport(json) {
|
|
|
8851
8955
|
|
|
8852
8956
|
// src/commands/dotnet/runInspectCode.ts
|
|
8853
8957
|
import { execSync as execSync24 } from "child_process";
|
|
8854
|
-
import { existsSync as existsSync29, readFileSync as
|
|
8958
|
+
import { existsSync as existsSync29, readFileSync as readFileSync24, unlinkSync as unlinkSync6 } from "fs";
|
|
8855
8959
|
import { tmpdir as tmpdir3 } from "os";
|
|
8856
8960
|
import path25 from "path";
|
|
8857
8961
|
import chalk102 from "chalk";
|
|
@@ -8886,7 +8990,7 @@ function runInspectCode(slnPath, include, swea) {
|
|
|
8886
8990
|
console.error(chalk102.red("Report file not generated"));
|
|
8887
8991
|
process.exit(1);
|
|
8888
8992
|
}
|
|
8889
|
-
const xml =
|
|
8993
|
+
const xml = readFileSync24(reportPath, "utf-8");
|
|
8890
8994
|
unlinkSync6(reportPath);
|
|
8891
8995
|
return xml;
|
|
8892
8996
|
}
|
|
@@ -9013,9 +9117,9 @@ function aggregateCommitters(authorLists) {
|
|
|
9013
9117
|
|
|
9014
9118
|
// src/shared/runGhGraphql.ts
|
|
9015
9119
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
9016
|
-
import { unlinkSync as unlinkSync7, writeFileSync as
|
|
9120
|
+
import { unlinkSync as unlinkSync7, writeFileSync as writeFileSync19 } from "fs";
|
|
9017
9121
|
import { tmpdir as tmpdir4 } from "os";
|
|
9018
|
-
import { join as
|
|
9122
|
+
import { join as join28 } from "path";
|
|
9019
9123
|
function buildArgs(queryFile, vars) {
|
|
9020
9124
|
const args = ["api", "graphql", "-F", `query=@${queryFile}`];
|
|
9021
9125
|
for (const [key, value] of Object.entries(vars)) {
|
|
@@ -9025,8 +9129,8 @@ function buildArgs(queryFile, vars) {
|
|
|
9025
9129
|
return args;
|
|
9026
9130
|
}
|
|
9027
9131
|
function runGhGraphql(mutation, vars) {
|
|
9028
|
-
const queryFile =
|
|
9029
|
-
|
|
9132
|
+
const queryFile = join28(tmpdir4(), `gh-query-${Date.now()}.graphql`);
|
|
9133
|
+
writeFileSync19(queryFile, mutation);
|
|
9030
9134
|
try {
|
|
9031
9135
|
const result = spawnSync2("gh", buildArgs(queryFile, vars), {
|
|
9032
9136
|
encoding: "utf-8"
|
|
@@ -9203,8 +9307,8 @@ function registerGithub(program2) {
|
|
|
9203
9307
|
}
|
|
9204
9308
|
|
|
9205
9309
|
// src/commands/handover/archive.ts
|
|
9206
|
-
import { existsSync as existsSync30, mkdirSync as
|
|
9207
|
-
import { join as
|
|
9310
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync8, renameSync as renameSync2 } from "fs";
|
|
9311
|
+
import { join as join30 } from "path";
|
|
9208
9312
|
|
|
9209
9313
|
// src/commands/handover/formatArchiveTimestamp.ts
|
|
9210
9314
|
function formatArchiveTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
@@ -9219,9 +9323,9 @@ function formatArchiveTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
|
9219
9323
|
}
|
|
9220
9324
|
|
|
9221
9325
|
// src/commands/handover/getHandoverArchiveDir.ts
|
|
9222
|
-
import { join as
|
|
9326
|
+
import { join as join29 } from "path";
|
|
9223
9327
|
function getHandoverArchiveDir(cwd = process.cwd()) {
|
|
9224
|
-
return
|
|
9328
|
+
return join29(cwd, ".assist", "handovers", "archive");
|
|
9225
9329
|
}
|
|
9226
9330
|
|
|
9227
9331
|
// src/commands/handover/archive.ts
|
|
@@ -9231,11 +9335,11 @@ function buildArchiveFilename(timestamp, suffix) {
|
|
|
9231
9335
|
return `${base}.md`;
|
|
9232
9336
|
}
|
|
9233
9337
|
function resolveCollisionPath(archiveDir, timestamp, suffix) {
|
|
9234
|
-
const initial =
|
|
9338
|
+
const initial = join30(archiveDir, buildArchiveFilename(timestamp, suffix));
|
|
9235
9339
|
if (!existsSync30(initial)) return initial;
|
|
9236
9340
|
for (let i = 1; i <= MAX_COLLISION_SUFFIX; i++) {
|
|
9237
9341
|
const collisionSuffix = suffix ? `${suffix}-${i}` : `${i}`;
|
|
9238
|
-
const candidate =
|
|
9342
|
+
const candidate = join30(
|
|
9239
9343
|
archiveDir,
|
|
9240
9344
|
buildArchiveFilename(timestamp, collisionSuffix)
|
|
9241
9345
|
);
|
|
@@ -9250,7 +9354,7 @@ function archive(options2 = {}) {
|
|
|
9250
9354
|
const handoverPath = getHandoverPath(cwd);
|
|
9251
9355
|
if (!existsSync30(handoverPath)) return void 0;
|
|
9252
9356
|
const archiveDir = getHandoverArchiveDir(cwd);
|
|
9253
|
-
|
|
9357
|
+
mkdirSync8(archiveDir, { recursive: true });
|
|
9254
9358
|
const timestamp = formatArchiveTimestamp(options2.now);
|
|
9255
9359
|
const destination = resolveCollisionPath(
|
|
9256
9360
|
archiveDir,
|
|
@@ -9262,7 +9366,7 @@ function archive(options2 = {}) {
|
|
|
9262
9366
|
}
|
|
9263
9367
|
|
|
9264
9368
|
// src/commands/handover/load.ts
|
|
9265
|
-
import { existsSync as existsSync31, readFileSync as
|
|
9369
|
+
import { existsSync as existsSync31, readFileSync as readFileSync26 } from "fs";
|
|
9266
9370
|
|
|
9267
9371
|
// src/commands/handover/parseLoadInput.ts
|
|
9268
9372
|
async function parseLoadInput(stdin) {
|
|
@@ -9378,7 +9482,7 @@ function normaliseOutput(raw) {
|
|
|
9378
9482
|
function loadFromHandover(cwd) {
|
|
9379
9483
|
const handoverPath = getHandoverPath(cwd);
|
|
9380
9484
|
if (!existsSync31(handoverPath)) return void 0;
|
|
9381
|
-
const content =
|
|
9485
|
+
const content = readFileSync26(handoverPath, "utf-8");
|
|
9382
9486
|
archive({ cwd });
|
|
9383
9487
|
return {
|
|
9384
9488
|
additionalContext: content,
|
|
@@ -9545,20 +9649,20 @@ function acceptanceCriteria(issueKey) {
|
|
|
9545
9649
|
import { execSync as execSync27 } from "child_process";
|
|
9546
9650
|
|
|
9547
9651
|
// src/shared/loadJson.ts
|
|
9548
|
-
import { existsSync as existsSync32, mkdirSync as
|
|
9652
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync9, readFileSync as readFileSync27, writeFileSync as writeFileSync20 } from "fs";
|
|
9549
9653
|
import { homedir as homedir8 } from "os";
|
|
9550
|
-
import { join as
|
|
9654
|
+
import { join as join31 } from "path";
|
|
9551
9655
|
function getStoreDir() {
|
|
9552
|
-
return
|
|
9656
|
+
return join31(homedir8(), ".assist");
|
|
9553
9657
|
}
|
|
9554
9658
|
function getStorePath(filename) {
|
|
9555
|
-
return
|
|
9659
|
+
return join31(getStoreDir(), filename);
|
|
9556
9660
|
}
|
|
9557
9661
|
function loadJson(filename) {
|
|
9558
|
-
const
|
|
9559
|
-
if (existsSync32(
|
|
9662
|
+
const path53 = getStorePath(filename);
|
|
9663
|
+
if (existsSync32(path53)) {
|
|
9560
9664
|
try {
|
|
9561
|
-
return JSON.parse(
|
|
9665
|
+
return JSON.parse(readFileSync27(path53, "utf-8"));
|
|
9562
9666
|
} catch {
|
|
9563
9667
|
return {};
|
|
9564
9668
|
}
|
|
@@ -9568,9 +9672,9 @@ function loadJson(filename) {
|
|
|
9568
9672
|
function saveJson(filename, data) {
|
|
9569
9673
|
const dir = getStoreDir();
|
|
9570
9674
|
if (!existsSync32(dir)) {
|
|
9571
|
-
|
|
9675
|
+
mkdirSync9(dir, { recursive: true });
|
|
9572
9676
|
}
|
|
9573
|
-
|
|
9677
|
+
writeFileSync20(getStorePath(filename), JSON.stringify(data, null, 2));
|
|
9574
9678
|
}
|
|
9575
9679
|
|
|
9576
9680
|
// src/shared/promptInput.ts
|
|
@@ -9677,13 +9781,13 @@ function registerLaunch(program2) {
|
|
|
9677
9781
|
program2.command("next").argument("[id]", "Backlog item ID to run first").description("Alias for backlog next").option("--once", "Exit after the first completed item run").action(
|
|
9678
9782
|
(id, opts) => next({ allowEdits: true, once: opts.once }, id)
|
|
9679
9783
|
);
|
|
9680
|
-
program2.command("draft").alias("feat").description(
|
|
9784
|
+
program2.command("draft").alias("feat").argument("[description]", "Text to forward to the /draft slash command").description(
|
|
9681
9785
|
"Launch Claude in /draft mode, chain into next on /next signal"
|
|
9682
9786
|
).option("--once", "Exit when the initial task completes").action(
|
|
9683
|
-
(opts) => launchMode("draft", { once: opts.once })
|
|
9787
|
+
(description, opts) => launchMode("draft", { once: opts.once, description })
|
|
9684
9788
|
);
|
|
9685
|
-
program2.command("bug").description("Launch Claude in /bug mode, chain into next on /next signal").option("--once", "Exit when the initial task completes").action(
|
|
9686
|
-
(opts) => launchMode("bug", { once: opts.once })
|
|
9789
|
+
program2.command("bug").argument("[description]", "Text to forward to the /bug slash command").description("Launch Claude in /bug mode, chain into next on /next signal").option("--once", "Exit when the initial task completes").action(
|
|
9790
|
+
(description, opts) => launchMode("bug", { once: opts.once, description })
|
|
9687
9791
|
);
|
|
9688
9792
|
program2.command("review-comments").argument("[number]", "PR number to check out first").description("Launch Claude in /review-comments mode (single session)").action((number) => reviewComments(number));
|
|
9689
9793
|
program2.command("refine").argument("[id]", "Backlog item ID").description("Launch Claude in /refine mode to refine a backlog item").option("--once", "Exit when the initial task completes").action(
|
|
@@ -9703,12 +9807,12 @@ function registerList(program2) {
|
|
|
9703
9807
|
}
|
|
9704
9808
|
|
|
9705
9809
|
// src/commands/mermaid/index.ts
|
|
9706
|
-
import { mkdirSync as
|
|
9810
|
+
import { mkdirSync as mkdirSync10, readdirSync as readdirSync5 } from "fs";
|
|
9707
9811
|
import { resolve as resolve10 } from "path";
|
|
9708
9812
|
import chalk113 from "chalk";
|
|
9709
9813
|
|
|
9710
9814
|
// src/commands/mermaid/exportFile.ts
|
|
9711
|
-
import { readFileSync as
|
|
9815
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync21 } from "fs";
|
|
9712
9816
|
import { basename as basename5, extname, resolve as resolve9 } from "path";
|
|
9713
9817
|
import chalk112 from "chalk";
|
|
9714
9818
|
|
|
@@ -9734,7 +9838,7 @@ async function renderBlock(krokiUrl, source) {
|
|
|
9734
9838
|
|
|
9735
9839
|
// src/commands/mermaid/exportFile.ts
|
|
9736
9840
|
async function exportFile(file, outDir, krokiUrl, onlyIndex) {
|
|
9737
|
-
const content =
|
|
9841
|
+
const content = readFileSync28(file, "utf8");
|
|
9738
9842
|
const blocks = extractMermaidBlocks(content);
|
|
9739
9843
|
const stem = basename5(file, extname(file));
|
|
9740
9844
|
if (onlyIndex !== void 0) {
|
|
@@ -9759,7 +9863,7 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
|
|
|
9759
9863
|
if (onlyIndex !== void 0 && idx !== onlyIndex) continue;
|
|
9760
9864
|
const outPath = resolve9(outDir, `${stem}-${idx}.svg`);
|
|
9761
9865
|
const svg = await renderBlock(krokiUrl, source);
|
|
9762
|
-
|
|
9866
|
+
writeFileSync21(outPath, svg, "utf8");
|
|
9763
9867
|
console.log(chalk112.green(` \u2192 ${outPath}`));
|
|
9764
9868
|
}
|
|
9765
9869
|
}
|
|
@@ -9772,7 +9876,7 @@ function extractMermaidBlocks(markdown) {
|
|
|
9772
9876
|
async function mermaidExport(file, options2 = {}) {
|
|
9773
9877
|
const { mermaid } = loadConfig();
|
|
9774
9878
|
const outDir = resolve10(process.cwd(), options2.out ?? ".");
|
|
9775
|
-
|
|
9879
|
+
mkdirSync10(outDir, { recursive: true });
|
|
9776
9880
|
if (options2.index !== void 0) {
|
|
9777
9881
|
if (!Number.isInteger(options2.index) || options2.index < 1) {
|
|
9778
9882
|
console.error(
|
|
@@ -10242,15 +10346,15 @@ function postComment(vars) {
|
|
|
10242
10346
|
}
|
|
10243
10347
|
runGhGraphql(MUTATION_MULTI, { ...base, startLine });
|
|
10244
10348
|
}
|
|
10245
|
-
function comment2(
|
|
10349
|
+
function comment2(path53, line, body, startLine) {
|
|
10246
10350
|
validateBody(body);
|
|
10247
10351
|
validateLine(line);
|
|
10248
10352
|
if (startLine !== void 0) validateLine(startLine);
|
|
10249
10353
|
try {
|
|
10250
10354
|
const prId = getCurrentPrNodeId();
|
|
10251
|
-
postComment({ prId, body, path:
|
|
10355
|
+
postComment({ prId, body, path: path53, line, startLine });
|
|
10252
10356
|
const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
|
|
10253
|
-
console.log(`Added review comment on ${
|
|
10357
|
+
console.log(`Added review comment on ${path53}:${range}`);
|
|
10254
10358
|
} catch (error) {
|
|
10255
10359
|
if (isGhNotInstalled(error)) {
|
|
10256
10360
|
console.error("Error: GitHub CLI (gh) is not installed.");
|
|
@@ -10328,23 +10432,23 @@ import { execSync as execSync32 } from "child_process";
|
|
|
10328
10432
|
|
|
10329
10433
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
10330
10434
|
import { execSync as execSync31 } from "child_process";
|
|
10331
|
-
import { unlinkSync as unlinkSync9, writeFileSync as
|
|
10435
|
+
import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync22 } from "fs";
|
|
10332
10436
|
import { tmpdir as tmpdir5 } from "os";
|
|
10333
|
-
import { join as
|
|
10437
|
+
import { join as join33 } from "path";
|
|
10334
10438
|
|
|
10335
10439
|
// src/commands/prs/loadCommentsCache.ts
|
|
10336
|
-
import { existsSync as existsSync33, readFileSync as
|
|
10337
|
-
import { join as
|
|
10440
|
+
import { existsSync as existsSync33, readFileSync as readFileSync29, unlinkSync as unlinkSync8 } from "fs";
|
|
10441
|
+
import { join as join32 } from "path";
|
|
10338
10442
|
import { parse as parse2 } from "yaml";
|
|
10339
10443
|
function getCachePath(prNumber) {
|
|
10340
|
-
return
|
|
10444
|
+
return join32(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
|
|
10341
10445
|
}
|
|
10342
10446
|
function loadCommentsCache(prNumber) {
|
|
10343
10447
|
const cachePath = getCachePath(prNumber);
|
|
10344
10448
|
if (!existsSync33(cachePath)) {
|
|
10345
10449
|
return null;
|
|
10346
10450
|
}
|
|
10347
|
-
const content =
|
|
10451
|
+
const content = readFileSync29(cachePath, "utf-8");
|
|
10348
10452
|
return parse2(content);
|
|
10349
10453
|
}
|
|
10350
10454
|
function deleteCommentsCache(prNumber) {
|
|
@@ -10364,8 +10468,8 @@ function replyToComment(org, repo, prNumber, commentId, message) {
|
|
|
10364
10468
|
}
|
|
10365
10469
|
function resolveThread(threadId) {
|
|
10366
10470
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
10367
|
-
const queryFile =
|
|
10368
|
-
|
|
10471
|
+
const queryFile = join33(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
|
|
10472
|
+
writeFileSync22(queryFile, mutation);
|
|
10369
10473
|
try {
|
|
10370
10474
|
execSync31(
|
|
10371
10475
|
`gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
|
|
@@ -10446,19 +10550,19 @@ function fixed(commentId, sha) {
|
|
|
10446
10550
|
}
|
|
10447
10551
|
|
|
10448
10552
|
// src/commands/prs/listComments/index.ts
|
|
10449
|
-
import { existsSync as existsSync34, mkdirSync as
|
|
10450
|
-
import { join as
|
|
10553
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync11, writeFileSync as writeFileSync24 } from "fs";
|
|
10554
|
+
import { join as join35 } from "path";
|
|
10451
10555
|
import { stringify } from "yaml";
|
|
10452
10556
|
|
|
10453
10557
|
// src/commands/prs/fetchThreadIds.ts
|
|
10454
10558
|
import { execSync as execSync33 } from "child_process";
|
|
10455
|
-
import { unlinkSync as unlinkSync10, writeFileSync as
|
|
10559
|
+
import { unlinkSync as unlinkSync10, writeFileSync as writeFileSync23 } from "fs";
|
|
10456
10560
|
import { tmpdir as tmpdir6 } from "os";
|
|
10457
|
-
import { join as
|
|
10561
|
+
import { join as join34 } from "path";
|
|
10458
10562
|
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 } } } } } } }`;
|
|
10459
10563
|
function fetchThreadIds(org, repo, prNumber) {
|
|
10460
|
-
const queryFile =
|
|
10461
|
-
|
|
10564
|
+
const queryFile = join34(tmpdir6(), `gh-query-${Date.now()}.graphql`);
|
|
10565
|
+
writeFileSync23(queryFile, THREAD_QUERY);
|
|
10462
10566
|
try {
|
|
10463
10567
|
const result = execSync33(
|
|
10464
10568
|
`gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
|
|
@@ -10571,17 +10675,17 @@ function printComments2(result) {
|
|
|
10571
10675
|
|
|
10572
10676
|
// src/commands/prs/listComments/index.ts
|
|
10573
10677
|
function writeCommentsCache(prNumber, comments3) {
|
|
10574
|
-
const assistDir =
|
|
10678
|
+
const assistDir = join35(process.cwd(), ".assist");
|
|
10575
10679
|
if (!existsSync34(assistDir)) {
|
|
10576
|
-
|
|
10680
|
+
mkdirSync11(assistDir, { recursive: true });
|
|
10577
10681
|
}
|
|
10578
10682
|
const cacheData = {
|
|
10579
10683
|
prNumber,
|
|
10580
10684
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10581
10685
|
comments: comments3
|
|
10582
10686
|
};
|
|
10583
|
-
const cachePath =
|
|
10584
|
-
|
|
10687
|
+
const cachePath = join35(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
10688
|
+
writeFileSync24(cachePath, stringify(cacheData));
|
|
10585
10689
|
}
|
|
10586
10690
|
function handleKnownErrors(error) {
|
|
10587
10691
|
if (isGhNotInstalled(error)) {
|
|
@@ -10613,7 +10717,7 @@ async function listComments() {
|
|
|
10613
10717
|
];
|
|
10614
10718
|
updateCache(prNumber, allComments);
|
|
10615
10719
|
const hasLineComments = allComments.some((c) => c.type === "line");
|
|
10616
|
-
const cachePath = hasLineComments ?
|
|
10720
|
+
const cachePath = hasLineComments ? join35(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
|
|
10617
10721
|
return { comments: allComments, cachePath };
|
|
10618
10722
|
} catch (error) {
|
|
10619
10723
|
const handled = handleKnownErrors(error);
|
|
@@ -10830,8 +10934,8 @@ function registerPrs(program2) {
|
|
|
10830
10934
|
prsCommand.command("wontfix <comment-id> <reason>").description("Reply with reason and resolve thread").action((commentId, reason) => {
|
|
10831
10935
|
wontfix(Number.parseInt(commentId, 10), reason);
|
|
10832
10936
|
});
|
|
10833
|
-
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((
|
|
10834
|
-
comment2(
|
|
10937
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path53, line, body) => {
|
|
10938
|
+
comment2(path53, Number.parseInt(line, 10), body);
|
|
10835
10939
|
});
|
|
10836
10940
|
}
|
|
10837
10941
|
|
|
@@ -11083,10 +11187,10 @@ function resolveOpSecret(reference) {
|
|
|
11083
11187
|
}
|
|
11084
11188
|
|
|
11085
11189
|
// src/commands/ravendb/ravenFetch.ts
|
|
11086
|
-
async function ravenFetch(connection,
|
|
11190
|
+
async function ravenFetch(connection, path53) {
|
|
11087
11191
|
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
11088
11192
|
let accessToken = await getAccessToken(apiKey);
|
|
11089
|
-
const url = `${connection.url}${
|
|
11193
|
+
const url = `${connection.url}${path53}`;
|
|
11090
11194
|
const headers = {
|
|
11091
11195
|
Authorization: `Bearer ${accessToken}`,
|
|
11092
11196
|
"Content-Type": "application/json"
|
|
@@ -11176,16 +11280,16 @@ import chalk129 from "chalk";
|
|
|
11176
11280
|
// src/commands/ravendb/buildQueryPath.ts
|
|
11177
11281
|
function buildQueryPath(opts) {
|
|
11178
11282
|
const db = encodeURIComponent(opts.db);
|
|
11179
|
-
let
|
|
11283
|
+
let path53;
|
|
11180
11284
|
if (opts.collection) {
|
|
11181
|
-
|
|
11285
|
+
path53 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
11182
11286
|
} else {
|
|
11183
|
-
|
|
11287
|
+
path53 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
11184
11288
|
}
|
|
11185
11289
|
if (opts.query) {
|
|
11186
|
-
|
|
11290
|
+
path53 += `&query=${encodeURIComponent(opts.query)}`;
|
|
11187
11291
|
}
|
|
11188
|
-
return
|
|
11292
|
+
return path53;
|
|
11189
11293
|
}
|
|
11190
11294
|
|
|
11191
11295
|
// src/commands/ravendb/fetchAllPages.ts
|
|
@@ -11194,7 +11298,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
11194
11298
|
let start3 = 0;
|
|
11195
11299
|
while (true) {
|
|
11196
11300
|
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
11197
|
-
const
|
|
11301
|
+
const path53 = buildQueryPath({
|
|
11198
11302
|
db: connection.database,
|
|
11199
11303
|
collection: opts.collection,
|
|
11200
11304
|
start: start3,
|
|
@@ -11202,7 +11306,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
11202
11306
|
sort: opts.sort,
|
|
11203
11307
|
query: opts.query
|
|
11204
11308
|
});
|
|
11205
|
-
const data = await ravenFetch(connection,
|
|
11309
|
+
const data = await ravenFetch(connection, path53);
|
|
11206
11310
|
const results = data.Results ?? [];
|
|
11207
11311
|
const totalResults = data.TotalResults ?? 0;
|
|
11208
11312
|
if (results.length === 0) break;
|
|
@@ -12420,8 +12524,8 @@ function findRootParent(file, importedBy, visited) {
|
|
|
12420
12524
|
function clusterFiles(graph) {
|
|
12421
12525
|
const clusters = /* @__PURE__ */ new Map();
|
|
12422
12526
|
for (const file of graph.files) {
|
|
12423
|
-
const
|
|
12424
|
-
if (
|
|
12527
|
+
const basename10 = path38.basename(file, path38.extname(file));
|
|
12528
|
+
if (basename10 === "index") continue;
|
|
12425
12529
|
const importers = graph.importedBy.get(file);
|
|
12426
12530
|
if (!importers || importers.size !== 1) continue;
|
|
12427
12531
|
const parent = [...importers][0];
|
|
@@ -12898,15 +13002,15 @@ ${context.diff.trimEnd()}
|
|
|
12898
13002
|
}
|
|
12899
13003
|
|
|
12900
13004
|
// src/commands/review/buildReviewPaths.ts
|
|
12901
|
-
import { join as
|
|
13005
|
+
import { join as join36 } from "path";
|
|
12902
13006
|
function buildReviewPaths(repoRoot, key) {
|
|
12903
|
-
const reviewDir =
|
|
13007
|
+
const reviewDir = join36(repoRoot, ".assist", "reviews", key);
|
|
12904
13008
|
return {
|
|
12905
13009
|
reviewDir,
|
|
12906
|
-
requestPath:
|
|
12907
|
-
claudePath:
|
|
12908
|
-
codexPath:
|
|
12909
|
-
synthesisPath:
|
|
13010
|
+
requestPath: join36(reviewDir, "request.md"),
|
|
13011
|
+
claudePath: join36(reviewDir, "claude.md"),
|
|
13012
|
+
codexPath: join36(reviewDir, "codex.md"),
|
|
13013
|
+
synthesisPath: join36(reviewDir, "synthesis.md")
|
|
12910
13014
|
};
|
|
12911
13015
|
}
|
|
12912
13016
|
|
|
@@ -12914,24 +13018,24 @@ function buildReviewPaths(repoRoot, key) {
|
|
|
12914
13018
|
import {
|
|
12915
13019
|
appendFileSync,
|
|
12916
13020
|
existsSync as existsSync35,
|
|
12917
|
-
readFileSync as
|
|
12918
|
-
writeFileSync as
|
|
13021
|
+
readFileSync as readFileSync30,
|
|
13022
|
+
writeFileSync as writeFileSync25
|
|
12919
13023
|
} from "fs";
|
|
12920
|
-
import { join as
|
|
13024
|
+
import { join as join37 } from "path";
|
|
12921
13025
|
var REVIEWS_ENTRY = ".assist/reviews";
|
|
12922
13026
|
function coversReviews(line) {
|
|
12923
13027
|
const pattern2 = line.trim().replace(/^\//, "").replace(/\/$/, "");
|
|
12924
13028
|
return pattern2 === ".assist" || pattern2 === REVIEWS_ENTRY;
|
|
12925
13029
|
}
|
|
12926
13030
|
function ensureReviewsIgnored(repoRoot) {
|
|
12927
|
-
const gitignorePath =
|
|
13031
|
+
const gitignorePath = join37(repoRoot, ".gitignore");
|
|
12928
13032
|
if (!existsSync35(gitignorePath)) {
|
|
12929
|
-
|
|
13033
|
+
writeFileSync25(gitignorePath, `${REVIEWS_ENTRY}
|
|
12930
13034
|
`);
|
|
12931
13035
|
console.log(`Created .gitignore with ${REVIEWS_ENTRY} entry.`);
|
|
12932
13036
|
return;
|
|
12933
13037
|
}
|
|
12934
|
-
const content =
|
|
13038
|
+
const content = readFileSync30(gitignorePath, "utf-8");
|
|
12935
13039
|
if (content.split("\n").some(coversReviews)) return;
|
|
12936
13040
|
const separator = content === "" || content.endsWith("\n") ? "" : "\n";
|
|
12937
13041
|
appendFileSync(gitignorePath, `${separator}${REVIEWS_ENTRY}
|
|
@@ -13078,7 +13182,7 @@ function gatherContext() {
|
|
|
13078
13182
|
}
|
|
13079
13183
|
|
|
13080
13184
|
// src/commands/review/postReviewToPr.ts
|
|
13081
|
-
import { readFileSync as
|
|
13185
|
+
import { readFileSync as readFileSync31 } from "fs";
|
|
13082
13186
|
|
|
13083
13187
|
// src/commands/review/parseFindings.ts
|
|
13084
13188
|
var SEVERITIES = ["blocker", "major", "minor", "nit"];
|
|
@@ -13308,7 +13412,7 @@ async function postReviewToPr(synthesisPath, options2) {
|
|
|
13308
13412
|
console.log("No PR found for current branch; nothing posted.");
|
|
13309
13413
|
return;
|
|
13310
13414
|
}
|
|
13311
|
-
const markdown =
|
|
13415
|
+
const markdown = readFileSync31(synthesisPath, "utf-8");
|
|
13312
13416
|
const findings = parseFindings(markdown);
|
|
13313
13417
|
if (findings.length === 0) {
|
|
13314
13418
|
console.log("Synthesis contains no findings; nothing to post.");
|
|
@@ -13385,16 +13489,16 @@ async function handlePostSynthesis(synthesisPath, options2) {
|
|
|
13385
13489
|
}
|
|
13386
13490
|
|
|
13387
13491
|
// src/commands/review/prepareReviewDir.ts
|
|
13388
|
-
import { existsSync as existsSync36, mkdirSync as
|
|
13492
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync12, unlinkSync as unlinkSync11, writeFileSync as writeFileSync26 } from "fs";
|
|
13389
13493
|
function clearReviewFiles(paths) {
|
|
13390
|
-
for (const
|
|
13391
|
-
if (existsSync36(
|
|
13494
|
+
for (const path53 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
13495
|
+
if (existsSync36(path53)) unlinkSync11(path53);
|
|
13392
13496
|
}
|
|
13393
13497
|
}
|
|
13394
13498
|
function prepareReviewDir(paths, requestBody, force) {
|
|
13395
|
-
|
|
13499
|
+
mkdirSync12(paths.reviewDir, { recursive: true });
|
|
13396
13500
|
if (force) clearReviewFiles(paths);
|
|
13397
|
-
|
|
13501
|
+
writeFileSync26(paths.requestPath, requestBody);
|
|
13398
13502
|
}
|
|
13399
13503
|
|
|
13400
13504
|
// src/commands/review/runApplySession.ts
|
|
@@ -13737,7 +13841,7 @@ The review request is at: ${requestPath}
|
|
|
13737
13841
|
}
|
|
13738
13842
|
|
|
13739
13843
|
// src/commands/review/runClaudeReviewer.ts
|
|
13740
|
-
import { writeFileSync as
|
|
13844
|
+
import { writeFileSync as writeFileSync27 } from "fs";
|
|
13741
13845
|
|
|
13742
13846
|
// src/commands/review/finaliseReviewerSpinner.ts
|
|
13743
13847
|
var SUMMARY_MAX_LEN = 80;
|
|
@@ -14073,7 +14177,7 @@ async function runClaudeReviewer(spec) {
|
|
|
14073
14177
|
}
|
|
14074
14178
|
});
|
|
14075
14179
|
if (result.exitCode === 0 && finalText)
|
|
14076
|
-
|
|
14180
|
+
writeFileSync27(spec.outputPath, finalText);
|
|
14077
14181
|
return finaliseReviewerRun({ ...spec, command }, spinner, result);
|
|
14078
14182
|
}
|
|
14079
14183
|
|
|
@@ -14189,7 +14293,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
|
|
|
14189
14293
|
}
|
|
14190
14294
|
|
|
14191
14295
|
// src/commands/review/synthesise.ts
|
|
14192
|
-
import { readFileSync as
|
|
14296
|
+
import { readFileSync as readFileSync32 } from "fs";
|
|
14193
14297
|
|
|
14194
14298
|
// src/commands/review/buildSynthesisStdin.ts
|
|
14195
14299
|
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.
|
|
@@ -14245,7 +14349,7 @@ Files:
|
|
|
14245
14349
|
|
|
14246
14350
|
// src/commands/review/synthesise.ts
|
|
14247
14351
|
function printSummary2(synthesisPath) {
|
|
14248
|
-
const markdown =
|
|
14352
|
+
const markdown = readFileSync32(synthesisPath, "utf-8");
|
|
14249
14353
|
console.log("");
|
|
14250
14354
|
console.log(buildReviewSummary(markdown));
|
|
14251
14355
|
console.log("");
|
|
@@ -14524,8 +14628,8 @@ import chalk147 from "chalk";
|
|
|
14524
14628
|
|
|
14525
14629
|
// src/commands/seq/fetchSeq.ts
|
|
14526
14630
|
import chalk144 from "chalk";
|
|
14527
|
-
async function fetchSeq(conn,
|
|
14528
|
-
const url = `${conn.url}${
|
|
14631
|
+
async function fetchSeq(conn, path53, params) {
|
|
14632
|
+
const url = `${conn.url}${path53}?${params}`;
|
|
14529
14633
|
const response = await fetch(url, {
|
|
14530
14634
|
headers: {
|
|
14531
14635
|
Accept: "application/json",
|
|
@@ -15070,7 +15174,7 @@ function registerSql(program2) {
|
|
|
15070
15174
|
|
|
15071
15175
|
// src/commands/transcript/shared.ts
|
|
15072
15176
|
import { existsSync as existsSync39, readdirSync as readdirSync6, statSync as statSync4 } from "fs";
|
|
15073
|
-
import { basename as basename6, join as
|
|
15177
|
+
import { basename as basename6, join as join38, relative as relative2 } from "path";
|
|
15074
15178
|
import * as readline2 from "readline";
|
|
15075
15179
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
15076
15180
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -15088,7 +15192,7 @@ function collectFiles(dir, extension) {
|
|
|
15088
15192
|
if (!existsSync39(dir)) return [];
|
|
15089
15193
|
const results = [];
|
|
15090
15194
|
for (const entry of readdirSync6(dir)) {
|
|
15091
|
-
const fullPath =
|
|
15195
|
+
const fullPath = join38(dir, entry);
|
|
15092
15196
|
if (statSync4(fullPath).isDirectory()) {
|
|
15093
15197
|
results.push(...collectFiles(fullPath, extension));
|
|
15094
15198
|
} else if (entry.endsWith(extension)) {
|
|
@@ -15185,11 +15289,11 @@ async function configure() {
|
|
|
15185
15289
|
import { existsSync as existsSync41 } from "fs";
|
|
15186
15290
|
|
|
15187
15291
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
15188
|
-
import { dirname as
|
|
15292
|
+
import { dirname as dirname20, join as join40 } from "path";
|
|
15189
15293
|
|
|
15190
15294
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
15191
15295
|
import { renameSync as renameSync3 } from "fs";
|
|
15192
|
-
import { join as
|
|
15296
|
+
import { join as join39 } from "path";
|
|
15193
15297
|
async function resolveDate(rl, choice) {
|
|
15194
15298
|
if (choice === "1") return getDatePrefix(0);
|
|
15195
15299
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -15204,7 +15308,7 @@ async function resolveDate(rl, choice) {
|
|
|
15204
15308
|
}
|
|
15205
15309
|
function renameWithPrefix(vttDir, vttFile, prefix2) {
|
|
15206
15310
|
const newFilename = `${prefix2}.${vttFile}`;
|
|
15207
|
-
renameSync3(
|
|
15311
|
+
renameSync3(join39(vttDir, vttFile), join39(vttDir, newFilename));
|
|
15208
15312
|
console.log(`Renamed to: ${newFilename}`);
|
|
15209
15313
|
return newFilename;
|
|
15210
15314
|
}
|
|
@@ -15235,15 +15339,15 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
15235
15339
|
for (let i = 0; i < vttFiles.length; i++) {
|
|
15236
15340
|
const vttFile = vttFiles[i];
|
|
15237
15341
|
if (!isValidDatePrefix(vttFile.filename)) {
|
|
15238
|
-
const vttFileDir =
|
|
15342
|
+
const vttFileDir = dirname20(vttFile.absolutePath);
|
|
15239
15343
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
15240
15344
|
if (newFilename) {
|
|
15241
|
-
const newRelativePath =
|
|
15242
|
-
|
|
15345
|
+
const newRelativePath = join40(
|
|
15346
|
+
dirname20(vttFile.relativePath),
|
|
15243
15347
|
newFilename
|
|
15244
15348
|
);
|
|
15245
15349
|
vttFiles[i] = {
|
|
15246
|
-
absolutePath:
|
|
15350
|
+
absolutePath: join40(vttFileDir, newFilename),
|
|
15247
15351
|
relativePath: newRelativePath,
|
|
15248
15352
|
filename: newFilename
|
|
15249
15353
|
};
|
|
@@ -15256,8 +15360,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
15256
15360
|
}
|
|
15257
15361
|
|
|
15258
15362
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
15259
|
-
import { existsSync as existsSync40, mkdirSync as
|
|
15260
|
-
import { basename as basename7, dirname as
|
|
15363
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync13, readFileSync as readFileSync33, writeFileSync as writeFileSync28 } from "fs";
|
|
15364
|
+
import { basename as basename7, dirname as dirname21, join as join41 } from "path";
|
|
15261
15365
|
|
|
15262
15366
|
// src/commands/transcript/cleanText.ts
|
|
15263
15367
|
function cleanText(text2) {
|
|
@@ -15467,22 +15571,22 @@ function toMdFilename(vttFilename) {
|
|
|
15467
15571
|
return `${basename7(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
15468
15572
|
}
|
|
15469
15573
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
15470
|
-
return relativeDir === "." ? transcriptsDir :
|
|
15574
|
+
return relativeDir === "." ? transcriptsDir : join41(transcriptsDir, relativeDir);
|
|
15471
15575
|
}
|
|
15472
15576
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
15473
15577
|
const mdFile = toMdFilename(vttFile.filename);
|
|
15474
|
-
const relativeDir =
|
|
15578
|
+
const relativeDir = dirname21(vttFile.relativePath);
|
|
15475
15579
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
15476
|
-
const outputPath =
|
|
15580
|
+
const outputPath = join41(outputDir, mdFile);
|
|
15477
15581
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
15478
15582
|
}
|
|
15479
15583
|
function logSkipped(relativeDir, mdFile) {
|
|
15480
|
-
console.log(`Skipping (already exists): ${
|
|
15584
|
+
console.log(`Skipping (already exists): ${join41(relativeDir, mdFile)}`);
|
|
15481
15585
|
return "skipped";
|
|
15482
15586
|
}
|
|
15483
15587
|
function ensureDirectory(dir, label2) {
|
|
15484
15588
|
if (!existsSync40(dir)) {
|
|
15485
|
-
|
|
15589
|
+
mkdirSync13(dir, { recursive: true });
|
|
15486
15590
|
console.log(`Created ${label2}: ${dir}`);
|
|
15487
15591
|
}
|
|
15488
15592
|
}
|
|
@@ -15504,10 +15608,10 @@ function logReduction(cueCount, messageCount) {
|
|
|
15504
15608
|
}
|
|
15505
15609
|
function readAndParseCues(inputPath) {
|
|
15506
15610
|
console.log(`Reading: ${inputPath}`);
|
|
15507
|
-
return processCues(
|
|
15611
|
+
return processCues(readFileSync33(inputPath, "utf-8"));
|
|
15508
15612
|
}
|
|
15509
15613
|
function writeFormatted(outputPath, content) {
|
|
15510
|
-
|
|
15614
|
+
writeFileSync28(outputPath, content, "utf-8");
|
|
15511
15615
|
console.log(`Written: ${outputPath}`);
|
|
15512
15616
|
}
|
|
15513
15617
|
function convertVttToMarkdown(inputPath, outputPath) {
|
|
@@ -15576,17 +15680,17 @@ async function format() {
|
|
|
15576
15680
|
|
|
15577
15681
|
// src/commands/transcript/summarise/index.ts
|
|
15578
15682
|
import { existsSync as existsSync43 } from "fs";
|
|
15579
|
-
import { basename as basename8, dirname as
|
|
15683
|
+
import { basename as basename8, dirname as dirname23, join as join43, relative as relative3 } from "path";
|
|
15580
15684
|
|
|
15581
15685
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
15582
15686
|
import {
|
|
15583
15687
|
existsSync as existsSync42,
|
|
15584
|
-
mkdirSync as
|
|
15585
|
-
readFileSync as
|
|
15688
|
+
mkdirSync as mkdirSync14,
|
|
15689
|
+
readFileSync as readFileSync34,
|
|
15586
15690
|
renameSync as renameSync4,
|
|
15587
|
-
rmSync
|
|
15691
|
+
rmSync as rmSync2
|
|
15588
15692
|
} from "fs";
|
|
15589
|
-
import { dirname as
|
|
15693
|
+
import { dirname as dirname22, join as join42 } from "path";
|
|
15590
15694
|
|
|
15591
15695
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
15592
15696
|
import chalk154 from "chalk";
|
|
@@ -15615,7 +15719,7 @@ function validateStagedContent(filename, content) {
|
|
|
15615
15719
|
}
|
|
15616
15720
|
|
|
15617
15721
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
15618
|
-
var STAGING_DIR =
|
|
15722
|
+
var STAGING_DIR = join42(process.cwd(), ".assist", "transcript");
|
|
15619
15723
|
function processStagedFile() {
|
|
15620
15724
|
if (!existsSync42(STAGING_DIR)) {
|
|
15621
15725
|
return false;
|
|
@@ -15626,7 +15730,7 @@ function processStagedFile() {
|
|
|
15626
15730
|
}
|
|
15627
15731
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
15628
15732
|
const stagedFile = stagedFiles[0];
|
|
15629
|
-
const content =
|
|
15733
|
+
const content = readFileSync34(stagedFile.absolutePath, "utf-8");
|
|
15630
15734
|
validateStagedContent(stagedFile.filename, content);
|
|
15631
15735
|
const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
|
|
15632
15736
|
const transcriptFiles = findMdFilesRecursive(transcriptsDir);
|
|
@@ -15639,23 +15743,23 @@ function processStagedFile() {
|
|
|
15639
15743
|
);
|
|
15640
15744
|
process.exit(1);
|
|
15641
15745
|
}
|
|
15642
|
-
const destPath =
|
|
15643
|
-
const destDir =
|
|
15746
|
+
const destPath = join42(summaryDir, matchingTranscript.relativePath);
|
|
15747
|
+
const destDir = dirname22(destPath);
|
|
15644
15748
|
if (!existsSync42(destDir)) {
|
|
15645
|
-
|
|
15749
|
+
mkdirSync14(destDir, { recursive: true });
|
|
15646
15750
|
}
|
|
15647
15751
|
renameSync4(stagedFile.absolutePath, destPath);
|
|
15648
15752
|
const remaining = findMdFilesRecursive(STAGING_DIR);
|
|
15649
15753
|
if (remaining.length === 0) {
|
|
15650
|
-
|
|
15754
|
+
rmSync2(STAGING_DIR, { recursive: true });
|
|
15651
15755
|
}
|
|
15652
15756
|
return true;
|
|
15653
15757
|
}
|
|
15654
15758
|
|
|
15655
15759
|
// src/commands/transcript/summarise/index.ts
|
|
15656
15760
|
function buildRelativeKey(relativePath, baseName) {
|
|
15657
|
-
const relDir =
|
|
15658
|
-
return relDir === "." ? baseName :
|
|
15761
|
+
const relDir = dirname23(relativePath);
|
|
15762
|
+
return relDir === "." ? baseName : join43(relDir, baseName);
|
|
15659
15763
|
}
|
|
15660
15764
|
function buildSummaryIndex(summaryDir) {
|
|
15661
15765
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -15689,8 +15793,8 @@ function summarise3() {
|
|
|
15689
15793
|
}
|
|
15690
15794
|
const next3 = missing[0];
|
|
15691
15795
|
const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
|
|
15692
|
-
const outputPath =
|
|
15693
|
-
const summaryFileDir =
|
|
15796
|
+
const outputPath = join43(STAGING_DIR, outputFilename);
|
|
15797
|
+
const summaryFileDir = join43(summaryDir, dirname23(next3.relativePath));
|
|
15694
15798
|
const relativeTranscriptPath = encodeURI(
|
|
15695
15799
|
relative3(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
|
|
15696
15800
|
);
|
|
@@ -15739,50 +15843,50 @@ function registerVerify(program2) {
|
|
|
15739
15843
|
|
|
15740
15844
|
// src/commands/voice/devices.ts
|
|
15741
15845
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
15742
|
-
import { join as
|
|
15846
|
+
import { join as join45 } from "path";
|
|
15743
15847
|
|
|
15744
15848
|
// src/commands/voice/shared.ts
|
|
15745
15849
|
import { homedir as homedir9 } from "os";
|
|
15746
|
-
import { dirname as
|
|
15850
|
+
import { dirname as dirname24, join as join44 } from "path";
|
|
15747
15851
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
15748
|
-
var __dirname6 =
|
|
15749
|
-
var VOICE_DIR =
|
|
15852
|
+
var __dirname6 = dirname24(fileURLToPath6(import.meta.url));
|
|
15853
|
+
var VOICE_DIR = join44(homedir9(), ".assist", "voice");
|
|
15750
15854
|
var voicePaths = {
|
|
15751
15855
|
dir: VOICE_DIR,
|
|
15752
|
-
pid:
|
|
15753
|
-
log:
|
|
15754
|
-
venv:
|
|
15755
|
-
lock:
|
|
15856
|
+
pid: join44(VOICE_DIR, "voice.pid"),
|
|
15857
|
+
log: join44(VOICE_DIR, "voice.log"),
|
|
15858
|
+
venv: join44(VOICE_DIR, ".venv"),
|
|
15859
|
+
lock: join44(VOICE_DIR, "voice.lock")
|
|
15756
15860
|
};
|
|
15757
15861
|
function getPythonDir() {
|
|
15758
|
-
return
|
|
15862
|
+
return join44(__dirname6, "commands", "voice", "python");
|
|
15759
15863
|
}
|
|
15760
15864
|
function getVenvPython() {
|
|
15761
|
-
return process.platform === "win32" ?
|
|
15865
|
+
return process.platform === "win32" ? join44(voicePaths.venv, "Scripts", "python.exe") : join44(voicePaths.venv, "bin", "python");
|
|
15762
15866
|
}
|
|
15763
15867
|
function getLockDir() {
|
|
15764
15868
|
const config = loadConfig();
|
|
15765
15869
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
15766
15870
|
}
|
|
15767
15871
|
function getLockFile() {
|
|
15768
|
-
return
|
|
15872
|
+
return join44(getLockDir(), "voice.lock");
|
|
15769
15873
|
}
|
|
15770
15874
|
|
|
15771
15875
|
// src/commands/voice/devices.ts
|
|
15772
15876
|
function devices() {
|
|
15773
|
-
const script =
|
|
15877
|
+
const script = join45(getPythonDir(), "list_devices.py");
|
|
15774
15878
|
spawnSync4(getVenvPython(), [script], { stdio: "inherit" });
|
|
15775
15879
|
}
|
|
15776
15880
|
|
|
15777
15881
|
// src/commands/voice/logs.ts
|
|
15778
|
-
import { existsSync as existsSync44, readFileSync as
|
|
15882
|
+
import { existsSync as existsSync44, readFileSync as readFileSync35 } from "fs";
|
|
15779
15883
|
function logs(options2) {
|
|
15780
15884
|
if (!existsSync44(voicePaths.log)) {
|
|
15781
15885
|
console.log("No voice log file found");
|
|
15782
15886
|
return;
|
|
15783
15887
|
}
|
|
15784
15888
|
const count6 = Number.parseInt(options2.lines ?? "150", 10);
|
|
15785
|
-
const content =
|
|
15889
|
+
const content = readFileSync35(voicePaths.log, "utf-8").trim();
|
|
15786
15890
|
if (!content) {
|
|
15787
15891
|
console.log("Voice log is empty");
|
|
15788
15892
|
return;
|
|
@@ -15804,13 +15908,13 @@ function logs(options2) {
|
|
|
15804
15908
|
|
|
15805
15909
|
// src/commands/voice/setup.ts
|
|
15806
15910
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
15807
|
-
import { mkdirSync as
|
|
15808
|
-
import { join as
|
|
15911
|
+
import { mkdirSync as mkdirSync16 } from "fs";
|
|
15912
|
+
import { join as join47 } from "path";
|
|
15809
15913
|
|
|
15810
15914
|
// src/commands/voice/checkLockFile.ts
|
|
15811
15915
|
import { execSync as execSync44 } from "child_process";
|
|
15812
|
-
import { existsSync as existsSync45, mkdirSync as
|
|
15813
|
-
import { join as
|
|
15916
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync15, readFileSync as readFileSync36, writeFileSync as writeFileSync29 } from "fs";
|
|
15917
|
+
import { join as join46 } from "path";
|
|
15814
15918
|
function isProcessAlive2(pid) {
|
|
15815
15919
|
try {
|
|
15816
15920
|
process.kill(pid, 0);
|
|
@@ -15823,7 +15927,7 @@ function checkLockFile() {
|
|
|
15823
15927
|
const lockFile = getLockFile();
|
|
15824
15928
|
if (!existsSync45(lockFile)) return;
|
|
15825
15929
|
try {
|
|
15826
|
-
const lock = JSON.parse(
|
|
15930
|
+
const lock = JSON.parse(readFileSync36(lockFile, "utf-8"));
|
|
15827
15931
|
if (lock.pid && isProcessAlive2(lock.pid)) {
|
|
15828
15932
|
console.error(
|
|
15829
15933
|
`Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
|
|
@@ -15847,8 +15951,8 @@ function bootstrapVenv() {
|
|
|
15847
15951
|
}
|
|
15848
15952
|
function writeLockFile(pid) {
|
|
15849
15953
|
const lockFile = getLockFile();
|
|
15850
|
-
|
|
15851
|
-
|
|
15954
|
+
mkdirSync15(join46(lockFile, ".."), { recursive: true });
|
|
15955
|
+
writeFileSync29(
|
|
15852
15956
|
lockFile,
|
|
15853
15957
|
JSON.stringify({
|
|
15854
15958
|
pid,
|
|
@@ -15860,10 +15964,10 @@ function writeLockFile(pid) {
|
|
|
15860
15964
|
|
|
15861
15965
|
// src/commands/voice/setup.ts
|
|
15862
15966
|
function setup() {
|
|
15863
|
-
|
|
15967
|
+
mkdirSync16(voicePaths.dir, { recursive: true });
|
|
15864
15968
|
bootstrapVenv();
|
|
15865
15969
|
console.log("\nDownloading models...\n");
|
|
15866
|
-
const script =
|
|
15970
|
+
const script = join47(getPythonDir(), "setup_models.py");
|
|
15867
15971
|
const result = spawnSync5(getVenvPython(), [script], {
|
|
15868
15972
|
stdio: "inherit",
|
|
15869
15973
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -15876,8 +15980,8 @@ function setup() {
|
|
|
15876
15980
|
|
|
15877
15981
|
// src/commands/voice/start.ts
|
|
15878
15982
|
import { spawn as spawn7 } from "child_process";
|
|
15879
|
-
import { mkdirSync as
|
|
15880
|
-
import { join as
|
|
15983
|
+
import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync30 } from "fs";
|
|
15984
|
+
import { join as join48 } from "path";
|
|
15881
15985
|
|
|
15882
15986
|
// src/commands/voice/buildDaemonEnv.ts
|
|
15883
15987
|
function buildDaemonEnv(options2) {
|
|
@@ -15905,17 +16009,17 @@ function spawnBackground(python, script, env) {
|
|
|
15905
16009
|
console.error("Failed to start voice daemon");
|
|
15906
16010
|
process.exit(1);
|
|
15907
16011
|
}
|
|
15908
|
-
|
|
16012
|
+
writeFileSync30(voicePaths.pid, String(pid));
|
|
15909
16013
|
writeLockFile(pid);
|
|
15910
16014
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
15911
16015
|
}
|
|
15912
16016
|
function start2(options2) {
|
|
15913
|
-
|
|
16017
|
+
mkdirSync17(voicePaths.dir, { recursive: true });
|
|
15914
16018
|
checkLockFile();
|
|
15915
16019
|
bootstrapVenv();
|
|
15916
16020
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
15917
16021
|
const env = buildDaemonEnv({ debug });
|
|
15918
|
-
const script =
|
|
16022
|
+
const script = join48(getPythonDir(), "voice_daemon.py");
|
|
15919
16023
|
const python = getVenvPython();
|
|
15920
16024
|
if (options2.foreground) {
|
|
15921
16025
|
spawnForeground(python, script, env);
|
|
@@ -15925,7 +16029,7 @@ function start2(options2) {
|
|
|
15925
16029
|
}
|
|
15926
16030
|
|
|
15927
16031
|
// src/commands/voice/status.ts
|
|
15928
|
-
import { existsSync as existsSync46, readFileSync as
|
|
16032
|
+
import { existsSync as existsSync46, readFileSync as readFileSync37 } from "fs";
|
|
15929
16033
|
function isProcessAlive3(pid) {
|
|
15930
16034
|
try {
|
|
15931
16035
|
process.kill(pid, 0);
|
|
@@ -15936,7 +16040,7 @@ function isProcessAlive3(pid) {
|
|
|
15936
16040
|
}
|
|
15937
16041
|
function readRecentLogs(count6) {
|
|
15938
16042
|
if (!existsSync46(voicePaths.log)) return [];
|
|
15939
|
-
const lines =
|
|
16043
|
+
const lines = readFileSync37(voicePaths.log, "utf-8").trim().split("\n");
|
|
15940
16044
|
return lines.slice(-count6);
|
|
15941
16045
|
}
|
|
15942
16046
|
function status() {
|
|
@@ -15944,7 +16048,7 @@ function status() {
|
|
|
15944
16048
|
console.log("Voice daemon: not running (no PID file)");
|
|
15945
16049
|
return;
|
|
15946
16050
|
}
|
|
15947
|
-
const pid = Number.parseInt(
|
|
16051
|
+
const pid = Number.parseInt(readFileSync37(voicePaths.pid, "utf-8").trim(), 10);
|
|
15948
16052
|
const alive = isProcessAlive3(pid);
|
|
15949
16053
|
console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
|
|
15950
16054
|
const recent = readRecentLogs(5);
|
|
@@ -15963,13 +16067,13 @@ function status() {
|
|
|
15963
16067
|
}
|
|
15964
16068
|
|
|
15965
16069
|
// src/commands/voice/stop.ts
|
|
15966
|
-
import { existsSync as existsSync47, readFileSync as
|
|
16070
|
+
import { existsSync as existsSync47, readFileSync as readFileSync38, unlinkSync as unlinkSync14 } from "fs";
|
|
15967
16071
|
function stop2() {
|
|
15968
16072
|
if (!existsSync47(voicePaths.pid)) {
|
|
15969
16073
|
console.log("Voice daemon is not running (no PID file)");
|
|
15970
16074
|
return;
|
|
15971
16075
|
}
|
|
15972
|
-
const pid = Number.parseInt(
|
|
16076
|
+
const pid = Number.parseInt(readFileSync38(voicePaths.pid, "utf-8").trim(), 10);
|
|
15973
16077
|
try {
|
|
15974
16078
|
process.kill(pid, "SIGTERM");
|
|
15975
16079
|
console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
|
|
@@ -16204,8 +16308,8 @@ async function auth() {
|
|
|
16204
16308
|
|
|
16205
16309
|
// src/commands/roam/postRoamActivity.ts
|
|
16206
16310
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
16207
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
16208
|
-
import { join as
|
|
16311
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync39, statSync as statSync5 } from "fs";
|
|
16312
|
+
import { join as join49 } from "path";
|
|
16209
16313
|
function findPortFile(roamDir) {
|
|
16210
16314
|
let entries;
|
|
16211
16315
|
try {
|
|
@@ -16214,9 +16318,9 @@ function findPortFile(roamDir) {
|
|
|
16214
16318
|
return void 0;
|
|
16215
16319
|
}
|
|
16216
16320
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
16217
|
-
const
|
|
16321
|
+
const path53 = join49(roamDir, name);
|
|
16218
16322
|
try {
|
|
16219
|
-
return { path:
|
|
16323
|
+
return { path: path53, mtimeMs: statSync5(path53).mtimeMs };
|
|
16220
16324
|
} catch {
|
|
16221
16325
|
return void 0;
|
|
16222
16326
|
}
|
|
@@ -16226,11 +16330,11 @@ function findPortFile(roamDir) {
|
|
|
16226
16330
|
function postRoamActivity(app, event) {
|
|
16227
16331
|
const appData = process.env.APPDATA;
|
|
16228
16332
|
if (!appData) return;
|
|
16229
|
-
const portFile = findPortFile(
|
|
16333
|
+
const portFile = findPortFile(join49(appData, "Roam"));
|
|
16230
16334
|
if (!portFile) return;
|
|
16231
16335
|
let port;
|
|
16232
16336
|
try {
|
|
16233
|
-
port =
|
|
16337
|
+
port = readFileSync39(portFile, "utf-8").trim();
|
|
16234
16338
|
} catch {
|
|
16235
16339
|
return;
|
|
16236
16340
|
}
|
|
@@ -16373,13 +16477,13 @@ function runPreCommands(pre, cwd) {
|
|
|
16373
16477
|
// src/commands/run/spawnRunCommand.ts
|
|
16374
16478
|
import { execFileSync as execFileSync8, spawn as spawn8 } from "child_process";
|
|
16375
16479
|
import { existsSync as existsSync48 } from "fs";
|
|
16376
|
-
import { dirname as
|
|
16480
|
+
import { dirname as dirname25, join as join50, resolve as resolve11 } from "path";
|
|
16377
16481
|
function resolveCommand2(command) {
|
|
16378
16482
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
16379
16483
|
try {
|
|
16380
16484
|
const gitPath = execFileSync8("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
16381
|
-
const gitRoot = resolve11(
|
|
16382
|
-
const gitBash =
|
|
16485
|
+
const gitRoot = resolve11(dirname25(gitPath), "..");
|
|
16486
|
+
const gitBash = join50(gitRoot, "bin", "bash.exe");
|
|
16383
16487
|
if (existsSync48(gitBash)) return gitBash;
|
|
16384
16488
|
} catch {
|
|
16385
16489
|
}
|
|
@@ -16465,8 +16569,8 @@ async function run3(name, args) {
|
|
|
16465
16569
|
}
|
|
16466
16570
|
|
|
16467
16571
|
// src/commands/run/add.ts
|
|
16468
|
-
import { mkdirSync as
|
|
16469
|
-
import { join as
|
|
16572
|
+
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync31 } from "fs";
|
|
16573
|
+
import { join as join51 } from "path";
|
|
16470
16574
|
|
|
16471
16575
|
// src/commands/run/extractOption.ts
|
|
16472
16576
|
function extractOption(args, flag) {
|
|
@@ -16527,16 +16631,16 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
16527
16631
|
saveConfig(config);
|
|
16528
16632
|
}
|
|
16529
16633
|
function createCommandFile(name) {
|
|
16530
|
-
const dir =
|
|
16531
|
-
|
|
16634
|
+
const dir = join51(".claude", "commands");
|
|
16635
|
+
mkdirSync18(dir, { recursive: true });
|
|
16532
16636
|
const content = `---
|
|
16533
16637
|
description: Run ${name}
|
|
16534
16638
|
---
|
|
16535
16639
|
|
|
16536
16640
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
16537
16641
|
`;
|
|
16538
|
-
const filePath =
|
|
16539
|
-
|
|
16642
|
+
const filePath = join51(dir, `${name}.md`);
|
|
16643
|
+
writeFileSync31(filePath, content);
|
|
16540
16644
|
console.log(`Created command file: ${filePath}`);
|
|
16541
16645
|
}
|
|
16542
16646
|
function add3() {
|
|
@@ -16559,11 +16663,11 @@ function findLinkIndex() {
|
|
|
16559
16663
|
function parseLinkArgs() {
|
|
16560
16664
|
const idx = findLinkIndex();
|
|
16561
16665
|
if (idx === -1) return null;
|
|
16562
|
-
const
|
|
16666
|
+
const path53 = process.argv[idx + 1];
|
|
16563
16667
|
const rest = process.argv.slice(idx + 2);
|
|
16564
16668
|
const { value: prefix2 } = extractOption(rest, "--prefix");
|
|
16565
16669
|
if (!prefix2) return null;
|
|
16566
|
-
return { path:
|
|
16670
|
+
return { path: path53, prefix: prefix2 };
|
|
16567
16671
|
}
|
|
16568
16672
|
function hasDuplicateLink(runList, linkPath) {
|
|
16569
16673
|
return runList.some(
|
|
@@ -16592,7 +16696,7 @@ function link2() {
|
|
|
16592
16696
|
|
|
16593
16697
|
// src/commands/run/remove.ts
|
|
16594
16698
|
import { existsSync as existsSync49, unlinkSync as unlinkSync15 } from "fs";
|
|
16595
|
-
import { join as
|
|
16699
|
+
import { join as join52 } from "path";
|
|
16596
16700
|
function findRemoveIndex() {
|
|
16597
16701
|
const idx = process.argv.indexOf("remove");
|
|
16598
16702
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -16607,7 +16711,7 @@ function parseRemoveName() {
|
|
|
16607
16711
|
return process.argv[idx + 1];
|
|
16608
16712
|
}
|
|
16609
16713
|
function deleteCommandFile(name) {
|
|
16610
|
-
const filePath =
|
|
16714
|
+
const filePath = join52(".claude", "commands", `${name}.md`);
|
|
16611
16715
|
if (existsSync49(filePath)) {
|
|
16612
16716
|
unlinkSync15(filePath);
|
|
16613
16717
|
console.log(`Deleted command file: ${filePath}`);
|
|
@@ -16647,9 +16751,9 @@ function registerRun(program2) {
|
|
|
16647
16751
|
|
|
16648
16752
|
// src/commands/screenshot/index.ts
|
|
16649
16753
|
import { execSync as execSync47 } from "child_process";
|
|
16650
|
-
import { existsSync as existsSync50, mkdirSync as
|
|
16754
|
+
import { existsSync as existsSync50, mkdirSync as mkdirSync19, unlinkSync as unlinkSync16, writeFileSync as writeFileSync32 } from "fs";
|
|
16651
16755
|
import { tmpdir as tmpdir7 } from "os";
|
|
16652
|
-
import { join as
|
|
16756
|
+
import { join as join53, resolve as resolve13 } from "path";
|
|
16653
16757
|
import chalk156 from "chalk";
|
|
16654
16758
|
|
|
16655
16759
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
@@ -16780,14 +16884,14 @@ Write-Output $OutputPath
|
|
|
16780
16884
|
// src/commands/screenshot/index.ts
|
|
16781
16885
|
function buildOutputPath(outputDir, processName) {
|
|
16782
16886
|
if (!existsSync50(outputDir)) {
|
|
16783
|
-
|
|
16887
|
+
mkdirSync19(outputDir, { recursive: true });
|
|
16784
16888
|
}
|
|
16785
16889
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
16786
16890
|
return resolve13(outputDir, `${processName}-${timestamp}.png`);
|
|
16787
16891
|
}
|
|
16788
16892
|
function runPowerShellScript(processName, outputPath) {
|
|
16789
|
-
const scriptPath =
|
|
16790
|
-
|
|
16893
|
+
const scriptPath = join53(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
16894
|
+
writeFileSync32(scriptPath, captureWindowPs1, "utf-8");
|
|
16791
16895
|
try {
|
|
16792
16896
|
execSync47(
|
|
16793
16897
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
@@ -16863,7 +16967,7 @@ function applyLine(result, pending, line) {
|
|
|
16863
16967
|
}
|
|
16864
16968
|
|
|
16865
16969
|
// src/commands/sessions/daemon/reportStolenSocket.ts
|
|
16866
|
-
import { readFileSync as
|
|
16970
|
+
import { readFileSync as readFileSync40 } from "fs";
|
|
16867
16971
|
function reportStolenSocket(socketPid) {
|
|
16868
16972
|
if (!socketPid) return;
|
|
16869
16973
|
const filePid = readPidFile();
|
|
@@ -16875,7 +16979,7 @@ function reportStolenSocket(socketPid) {
|
|
|
16875
16979
|
function readPidFile() {
|
|
16876
16980
|
try {
|
|
16877
16981
|
const pid = Number.parseInt(
|
|
16878
|
-
|
|
16982
|
+
readFileSync40(daemonPaths.pid, "utf-8").trim(),
|
|
16879
16983
|
10
|
|
16880
16984
|
);
|
|
16881
16985
|
return Number.isInteger(pid) ? pid : void 0;
|
|
@@ -16962,7 +17066,7 @@ async function restartDaemon() {
|
|
|
16962
17066
|
}
|
|
16963
17067
|
|
|
16964
17068
|
// src/commands/sessions/daemon/runDaemon.ts
|
|
16965
|
-
import { mkdirSync as
|
|
17069
|
+
import { mkdirSync as mkdirSync21 } from "fs";
|
|
16966
17070
|
|
|
16967
17071
|
// src/commands/sessions/daemon/createAutoExit.ts
|
|
16968
17072
|
var DEFAULT_GRACE_MS = 6e4;
|
|
@@ -17122,27 +17226,20 @@ function broadcast(clients, msg) {
|
|
|
17122
17226
|
}
|
|
17123
17227
|
}
|
|
17124
17228
|
|
|
17125
|
-
// src/commands/sessions/daemon/repoPrefix.ts
|
|
17126
|
-
import * as path47 from "path";
|
|
17127
|
-
function repoPrefix(cwd) {
|
|
17128
|
-
if (!cwd) return "";
|
|
17129
|
-
return `${path47.basename(cwd)}/`;
|
|
17130
|
-
}
|
|
17131
|
-
|
|
17132
17229
|
// src/commands/sessions/daemon/spawnPty.ts
|
|
17133
17230
|
import * as pty from "node-pty";
|
|
17134
17231
|
|
|
17135
17232
|
// src/commands/sessions/daemon/ensureSpawnHelperExecutable.ts
|
|
17136
17233
|
import { chmodSync, existsSync as existsSync51, statSync as statSync6 } from "fs";
|
|
17137
17234
|
import { createRequire as createRequire3 } from "module";
|
|
17138
|
-
import
|
|
17235
|
+
import path47 from "path";
|
|
17139
17236
|
var require4 = createRequire3(import.meta.url);
|
|
17140
17237
|
var ensured = false;
|
|
17141
17238
|
function ensureSpawnHelperExecutable() {
|
|
17142
17239
|
if (ensured || process.platform !== "darwin") return;
|
|
17143
17240
|
ensured = true;
|
|
17144
|
-
const ptyRoot =
|
|
17145
|
-
const helper =
|
|
17241
|
+
const ptyRoot = path47.join(path47.dirname(require4.resolve("node-pty")), "..");
|
|
17242
|
+
const helper = path47.join(
|
|
17146
17243
|
ptyRoot,
|
|
17147
17244
|
"prebuilds",
|
|
17148
17245
|
`${process.platform}-${process.arch}`,
|
|
@@ -17154,7 +17251,7 @@ function ensureSpawnHelperExecutable() {
|
|
|
17154
17251
|
}
|
|
17155
17252
|
|
|
17156
17253
|
// src/commands/sessions/daemon/spawnPty.ts
|
|
17157
|
-
function spawnPty(args, cwd) {
|
|
17254
|
+
function spawnPty(args, cwd, sessionId) {
|
|
17158
17255
|
ensureSpawnHelperExecutable();
|
|
17159
17256
|
const shell = process.platform === "win32" ? "cmd.exe" : process.env.SHELL ?? "bash";
|
|
17160
17257
|
const shellArgs = process.platform === "win32" ? ["/c", ...args] : ["-c", `exec ${args.map(shellEscape).join(" ")}`];
|
|
@@ -17163,7 +17260,13 @@ function spawnPty(args, cwd) {
|
|
|
17163
17260
|
cols: 120,
|
|
17164
17261
|
rows: 30,
|
|
17165
17262
|
cwd: cwd ?? process.cwd(),
|
|
17166
|
-
env: {
|
|
17263
|
+
env: {
|
|
17264
|
+
...process.env,
|
|
17265
|
+
...sessionId && {
|
|
17266
|
+
ASSIST_SESSION_ID: sessionId,
|
|
17267
|
+
ASSIST_ACTIVITY_ID: sessionId
|
|
17268
|
+
}
|
|
17269
|
+
}
|
|
17167
17270
|
});
|
|
17168
17271
|
}
|
|
17169
17272
|
function shellEscape(s) {
|
|
@@ -17174,11 +17277,11 @@ function shellEscape(s) {
|
|
|
17174
17277
|
function createAssistSession(id, assistArgs, cwd) {
|
|
17175
17278
|
return {
|
|
17176
17279
|
id,
|
|
17177
|
-
name:
|
|
17280
|
+
name: `assist ${assistArgs.join(" ")}`,
|
|
17178
17281
|
commandType: "assist",
|
|
17179
17282
|
status: "running",
|
|
17180
17283
|
startedAt: Date.now(),
|
|
17181
|
-
pty: spawnPty(["assist", ...assistArgs], cwd),
|
|
17284
|
+
pty: spawnPty(["assist", ...assistArgs], cwd, id),
|
|
17182
17285
|
scrollback: "",
|
|
17183
17286
|
idleTimer: null,
|
|
17184
17287
|
lastResizeAt: 0,
|
|
@@ -17206,7 +17309,7 @@ function spawnRun(opts) {
|
|
|
17206
17309
|
function createSession(id, prompt, cwd) {
|
|
17207
17310
|
return {
|
|
17208
17311
|
id,
|
|
17209
|
-
name:
|
|
17312
|
+
name: prompt?.slice(0, 40) || `Session ${id}`,
|
|
17210
17313
|
commandType: "claude",
|
|
17211
17314
|
status: "running",
|
|
17212
17315
|
startedAt: Date.now(),
|
|
@@ -17220,7 +17323,7 @@ function createSession(id, prompt, cwd) {
|
|
|
17220
17323
|
function createRunSession(id, runName, runArgs, cwd) {
|
|
17221
17324
|
return {
|
|
17222
17325
|
id,
|
|
17223
|
-
name:
|
|
17326
|
+
name: `run: ${runName}`,
|
|
17224
17327
|
commandType: "run",
|
|
17225
17328
|
status: "running",
|
|
17226
17329
|
startedAt: Date.now(),
|
|
@@ -17334,7 +17437,7 @@ function restoreSession(id, persisted) {
|
|
|
17334
17437
|
function resumeSession(id, sessionId, cwd, name) {
|
|
17335
17438
|
return {
|
|
17336
17439
|
id,
|
|
17337
|
-
name:
|
|
17440
|
+
name: name ? `${name.slice(0, 36)} (R)` : `Resume ${sessionId.slice(0, 8)}`,
|
|
17338
17441
|
commandType: "claude",
|
|
17339
17442
|
status: "running",
|
|
17340
17443
|
startedAt: Date.now(),
|
|
@@ -17406,7 +17509,7 @@ function respawnThunk(session) {
|
|
|
17406
17509
|
if (session.commandType === "run" && runName)
|
|
17407
17510
|
return () => spawnRun({ name: runName, args: runArgs, cwd });
|
|
17408
17511
|
if (session.commandType === "assist" && assistArgs)
|
|
17409
|
-
return () => spawnPty(["assist", ...assistArgs], cwd);
|
|
17512
|
+
return () => spawnPty(["assist", ...assistArgs], cwd, session.id);
|
|
17410
17513
|
return null;
|
|
17411
17514
|
}
|
|
17412
17515
|
|
|
@@ -17427,8 +17530,10 @@ function toSessionInfo({
|
|
|
17427
17530
|
startedAt,
|
|
17428
17531
|
runName,
|
|
17429
17532
|
runArgs,
|
|
17533
|
+
assistArgs,
|
|
17430
17534
|
cwd,
|
|
17431
|
-
restored
|
|
17535
|
+
restored,
|
|
17536
|
+
activity: activity2
|
|
17432
17537
|
}) {
|
|
17433
17538
|
return {
|
|
17434
17539
|
id,
|
|
@@ -17438,14 +17543,45 @@ function toSessionInfo({
|
|
|
17438
17543
|
startedAt,
|
|
17439
17544
|
runName,
|
|
17440
17545
|
runArgs,
|
|
17546
|
+
assistArgs,
|
|
17441
17547
|
cwd,
|
|
17442
|
-
restored
|
|
17548
|
+
restored,
|
|
17549
|
+
activity: activity2
|
|
17550
|
+
};
|
|
17551
|
+
}
|
|
17552
|
+
|
|
17553
|
+
// src/commands/sessions/daemon/watchActivity.ts
|
|
17554
|
+
import { existsSync as existsSync52, mkdirSync as mkdirSync20, watch } from "fs";
|
|
17555
|
+
import { dirname as dirname27 } from "path";
|
|
17556
|
+
var DEBOUNCE_MS = 50;
|
|
17557
|
+
function watchActivity(session, notify2) {
|
|
17558
|
+
if (session.commandType !== "assist" || !session.cwd) return;
|
|
17559
|
+
const path53 = activityPath(session.cwd, session.id);
|
|
17560
|
+
const dir = dirname27(path53);
|
|
17561
|
+
try {
|
|
17562
|
+
mkdirSync20(dir, { recursive: true });
|
|
17563
|
+
} catch {
|
|
17564
|
+
return;
|
|
17565
|
+
}
|
|
17566
|
+
let timer = null;
|
|
17567
|
+
const read = () => {
|
|
17568
|
+
timer = null;
|
|
17569
|
+
const activity2 = readActivity(path53);
|
|
17570
|
+
if (!activity2) return;
|
|
17571
|
+
session.activity = activity2;
|
|
17572
|
+
notify2();
|
|
17443
17573
|
};
|
|
17574
|
+
session.activityWatcher = watch(dir, (_event, filename) => {
|
|
17575
|
+
if (filename && !path53.endsWith(filename)) return;
|
|
17576
|
+
if (timer) clearTimeout(timer);
|
|
17577
|
+
timer = setTimeout(read, DEBOUNCE_MS);
|
|
17578
|
+
});
|
|
17579
|
+
if (existsSync52(path53)) read();
|
|
17444
17580
|
}
|
|
17445
17581
|
|
|
17446
17582
|
// src/commands/sessions/daemon/discoverClaudeSessionId.ts
|
|
17447
17583
|
import * as fs26 from "fs";
|
|
17448
|
-
import * as
|
|
17584
|
+
import * as path48 from "path";
|
|
17449
17585
|
var POLL_MS = 3e3;
|
|
17450
17586
|
async function discoverClaudeSessionId(options2) {
|
|
17451
17587
|
while (options2.isActive()) {
|
|
@@ -17461,7 +17597,7 @@ async function findNewSessionId(options2) {
|
|
|
17461
17597
|
if (!await isCreatedSince(filePath, options2.sinceMs)) continue;
|
|
17462
17598
|
const meta = await parseSessionFile(filePath);
|
|
17463
17599
|
if (!meta?.cwd || options2.isClaimed(meta.sessionId)) continue;
|
|
17464
|
-
if (
|
|
17600
|
+
if (path48.resolve(meta.cwd) === path48.resolve(options2.cwd))
|
|
17465
17601
|
return meta.sessionId;
|
|
17466
17602
|
}
|
|
17467
17603
|
return null;
|
|
@@ -17513,6 +17649,8 @@ function dismissSession(sessions, id) {
|
|
|
17513
17649
|
if (!s) return false;
|
|
17514
17650
|
if (s.status !== "done") s.pty?.kill();
|
|
17515
17651
|
clearIdle(s);
|
|
17652
|
+
s.activityWatcher?.close();
|
|
17653
|
+
if (s.cwd) removeActivity(s.cwd, s.id);
|
|
17516
17654
|
sessions.delete(id);
|
|
17517
17655
|
return true;
|
|
17518
17656
|
}
|
|
@@ -17551,6 +17689,7 @@ var SessionManager = class {
|
|
|
17551
17689
|
add(session) {
|
|
17552
17690
|
this.wire(session);
|
|
17553
17691
|
watchForClaudeSessionId(session, this.sessions, this.notify);
|
|
17692
|
+
watchActivity(session, this.notify);
|
|
17554
17693
|
return session.id;
|
|
17555
17694
|
}
|
|
17556
17695
|
spawn(prompt, cwd) {
|
|
@@ -17715,10 +17854,10 @@ function handleConnection(socket, manager) {
|
|
|
17715
17854
|
}
|
|
17716
17855
|
|
|
17717
17856
|
// src/commands/sessions/daemon/onListening.ts
|
|
17718
|
-
import { unlinkSync as unlinkSync17, writeFileSync as
|
|
17857
|
+
import { unlinkSync as unlinkSync17, writeFileSync as writeFileSync33 } from "fs";
|
|
17719
17858
|
|
|
17720
17859
|
// src/commands/sessions/daemon/startPidFileWatchdog.ts
|
|
17721
|
-
import { readFileSync as
|
|
17860
|
+
import { readFileSync as readFileSync41 } from "fs";
|
|
17722
17861
|
var WATCHDOG_INTERVAL_MS = 5e3;
|
|
17723
17862
|
function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
17724
17863
|
const timer = setInterval(() => {
|
|
@@ -17729,7 +17868,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
|
17729
17868
|
}
|
|
17730
17869
|
function ownsPidFile() {
|
|
17731
17870
|
try {
|
|
17732
|
-
return
|
|
17871
|
+
return readFileSync41(daemonPaths.pid, "utf-8").trim() === String(process.pid);
|
|
17733
17872
|
} catch {
|
|
17734
17873
|
return false;
|
|
17735
17874
|
}
|
|
@@ -17737,7 +17876,7 @@ function ownsPidFile() {
|
|
|
17737
17876
|
|
|
17738
17877
|
// src/commands/sessions/daemon/onListening.ts
|
|
17739
17878
|
function onListening(manager, checkAutoExit) {
|
|
17740
|
-
|
|
17879
|
+
writeFileSync33(daemonPaths.pid, String(process.pid));
|
|
17741
17880
|
startPidFileWatchdog(() => {
|
|
17742
17881
|
daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
|
|
17743
17882
|
manager.shutdown();
|
|
@@ -17798,7 +17937,7 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
|
|
|
17798
17937
|
|
|
17799
17938
|
// src/commands/sessions/daemon/runDaemon.ts
|
|
17800
17939
|
async function runDaemon() {
|
|
17801
|
-
|
|
17940
|
+
mkdirSync21(daemonPaths.dir, { recursive: true });
|
|
17802
17941
|
daemonLog(
|
|
17803
17942
|
`starting (reason: ${process.env.ASSIST_DAEMON_SPAWN_REASON ?? "manual"})`
|
|
17804
17943
|
);
|
|
@@ -18098,16 +18237,16 @@ async function statusLine() {
|
|
|
18098
18237
|
// src/commands/sync.ts
|
|
18099
18238
|
import * as fs32 from "fs";
|
|
18100
18239
|
import * as os2 from "os";
|
|
18101
|
-
import * as
|
|
18240
|
+
import * as path51 from "path";
|
|
18102
18241
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
18103
18242
|
|
|
18104
18243
|
// src/commands/sync/syncClaudeMd.ts
|
|
18105
18244
|
import * as fs30 from "fs";
|
|
18106
|
-
import * as
|
|
18245
|
+
import * as path49 from "path";
|
|
18107
18246
|
import chalk160 from "chalk";
|
|
18108
18247
|
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
18109
|
-
const source =
|
|
18110
|
-
const target =
|
|
18248
|
+
const source = path49.join(claudeDir, "CLAUDE.md");
|
|
18249
|
+
const target = path49.join(targetBase, "CLAUDE.md");
|
|
18111
18250
|
const sourceContent = fs30.readFileSync(source, "utf-8");
|
|
18112
18251
|
if (fs30.existsSync(target)) {
|
|
18113
18252
|
const targetContent = fs30.readFileSync(target, "utf-8");
|
|
@@ -18133,11 +18272,11 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
18133
18272
|
|
|
18134
18273
|
// src/commands/sync/syncSettings.ts
|
|
18135
18274
|
import * as fs31 from "fs";
|
|
18136
|
-
import * as
|
|
18275
|
+
import * as path50 from "path";
|
|
18137
18276
|
import chalk161 from "chalk";
|
|
18138
18277
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
18139
|
-
const source =
|
|
18140
|
-
const target =
|
|
18278
|
+
const source = path50.join(claudeDir, "settings.json");
|
|
18279
|
+
const target = path50.join(targetBase, "settings.json");
|
|
18141
18280
|
const sourceContent = fs31.readFileSync(source, "utf-8");
|
|
18142
18281
|
const mergedContent = JSON.stringify(JSON.parse(sourceContent), null, " ");
|
|
18143
18282
|
if (fs31.existsSync(target)) {
|
|
@@ -18173,23 +18312,23 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
18173
18312
|
|
|
18174
18313
|
// src/commands/sync.ts
|
|
18175
18314
|
var __filename4 = fileURLToPath7(import.meta.url);
|
|
18176
|
-
var __dirname7 =
|
|
18315
|
+
var __dirname7 = path51.dirname(__filename4);
|
|
18177
18316
|
async function sync(options2) {
|
|
18178
18317
|
const config = loadConfig();
|
|
18179
18318
|
const yes = options2?.yes ?? config.sync.autoConfirm;
|
|
18180
|
-
const claudeDir =
|
|
18181
|
-
const targetBase =
|
|
18319
|
+
const claudeDir = path51.join(__dirname7, "..", "claude");
|
|
18320
|
+
const targetBase = path51.join(os2.homedir(), ".claude");
|
|
18182
18321
|
syncCommands(claudeDir, targetBase);
|
|
18183
18322
|
await syncSettings(claudeDir, targetBase, { yes });
|
|
18184
18323
|
await syncClaudeMd(claudeDir, targetBase, { yes });
|
|
18185
18324
|
}
|
|
18186
18325
|
function syncCommands(claudeDir, targetBase) {
|
|
18187
|
-
const sourceDir =
|
|
18188
|
-
const targetDir =
|
|
18326
|
+
const sourceDir = path51.join(claudeDir, "commands");
|
|
18327
|
+
const targetDir = path51.join(targetBase, "commands");
|
|
18189
18328
|
fs32.mkdirSync(targetDir, { recursive: true });
|
|
18190
18329
|
const files = fs32.readdirSync(sourceDir);
|
|
18191
18330
|
for (const file of files) {
|
|
18192
|
-
fs32.copyFileSync(
|
|
18331
|
+
fs32.copyFileSync(path51.join(sourceDir, file), path51.join(targetDir, file));
|
|
18193
18332
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
18194
18333
|
}
|
|
18195
18334
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -18197,15 +18336,15 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
18197
18336
|
|
|
18198
18337
|
// src/commands/update.ts
|
|
18199
18338
|
import { execSync as execSync48 } from "child_process";
|
|
18200
|
-
import * as
|
|
18339
|
+
import * as path52 from "path";
|
|
18201
18340
|
function isGlobalNpmInstall(dir) {
|
|
18202
18341
|
try {
|
|
18203
|
-
const resolved =
|
|
18204
|
-
if (resolved.split(
|
|
18342
|
+
const resolved = path52.resolve(dir);
|
|
18343
|
+
if (resolved.split(path52.sep).includes("node_modules")) {
|
|
18205
18344
|
return true;
|
|
18206
18345
|
}
|
|
18207
18346
|
const globalPrefix = execSync48("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
18208
|
-
return resolved.toLowerCase().startsWith(
|
|
18347
|
+
return resolved.toLowerCase().startsWith(path52.resolve(globalPrefix).toLowerCase());
|
|
18209
18348
|
} catch {
|
|
18210
18349
|
return false;
|
|
18211
18350
|
}
|