@staff0rd/assist 0.391.4 → 0.393.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 -1
- package/codex/config.toml +14 -0
- package/dist/commands/sessions/web/bundle.js +72 -72
- package/dist/index.js +337 -217
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.393.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -17,6 +17,7 @@ var package_default = {
|
|
|
17
17
|
files: [
|
|
18
18
|
"dist",
|
|
19
19
|
"claude",
|
|
20
|
+
"codex",
|
|
20
21
|
"allowed.cli-reads",
|
|
21
22
|
"allowed.cli-writes"
|
|
22
23
|
],
|
|
@@ -140,10 +141,10 @@ import { stringify as stringifyYaml } from "yaml";
|
|
|
140
141
|
// src/shared/loadRawYaml.ts
|
|
141
142
|
import { existsSync, readFileSync } from "fs";
|
|
142
143
|
import { parse as parseYaml } from "yaml";
|
|
143
|
-
function loadRawYaml(
|
|
144
|
-
if (!existsSync(
|
|
144
|
+
function loadRawYaml(path64) {
|
|
145
|
+
if (!existsSync(path64)) return {};
|
|
145
146
|
try {
|
|
146
|
-
const content = readFileSync(
|
|
147
|
+
const content = readFileSync(path64, "utf8");
|
|
147
148
|
return parseYaml(content) || {};
|
|
148
149
|
} catch {
|
|
149
150
|
return {};
|
|
@@ -1360,8 +1361,8 @@ function findUnmergedPaths() {
|
|
|
1360
1361
|
}
|
|
1361
1362
|
const found = /* @__PURE__ */ new Set();
|
|
1362
1363
|
for (const line of output.split("\n")) {
|
|
1363
|
-
const
|
|
1364
|
-
if (
|
|
1364
|
+
const path64 = line.split(" ")[1];
|
|
1365
|
+
if (path64) found.add(path64.trim());
|
|
1365
1366
|
}
|
|
1366
1367
|
return [...found];
|
|
1367
1368
|
}
|
|
@@ -1460,8 +1461,8 @@ function getPreferredRemoteRepo(cwd) {
|
|
|
1460
1461
|
function gitRefUrl(kind, ref, cwd) {
|
|
1461
1462
|
const repo = getPreferredRemoteRepo(cwd);
|
|
1462
1463
|
if (!repo) return void 0;
|
|
1463
|
-
const
|
|
1464
|
-
return `https://github.com/${repo.org}/${repo.repo}/${
|
|
1464
|
+
const path64 = kind === "branch" ? "tree" : "commit";
|
|
1465
|
+
return `https://github.com/${repo.org}/${repo.repo}/${path64}/${ref}`;
|
|
1465
1466
|
}
|
|
1466
1467
|
|
|
1467
1468
|
// src/commands/commit/collectCommitRefs.ts
|
|
@@ -3232,9 +3233,9 @@ import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
|
3232
3233
|
|
|
3233
3234
|
// src/commands/verify/forbiddenStrings/findForbiddenStrings.ts
|
|
3234
3235
|
import { minimatch as minimatch2 } from "minimatch";
|
|
3235
|
-
function resolveStringsAtPath(data,
|
|
3236
|
+
function resolveStringsAtPath(data, path64) {
|
|
3236
3237
|
let current = data;
|
|
3237
|
-
for (const segment of
|
|
3238
|
+
for (const segment of path64.split(".")) {
|
|
3238
3239
|
if (current === null || typeof current !== "object") return [];
|
|
3239
3240
|
current = current[segment];
|
|
3240
3241
|
}
|
|
@@ -3247,10 +3248,10 @@ function resolveStringsAtPath(data, path63) {
|
|
|
3247
3248
|
}
|
|
3248
3249
|
function findRuleViolations(data, rule) {
|
|
3249
3250
|
const violations = [];
|
|
3250
|
-
for (const
|
|
3251
|
-
for (const value of resolveStringsAtPath(data,
|
|
3251
|
+
for (const path64 of rule.paths) {
|
|
3252
|
+
for (const value of resolveStringsAtPath(data, path64)) {
|
|
3252
3253
|
if (minimatch2(value, rule.disallowed))
|
|
3253
|
-
violations.push({ file: rule.file, path:
|
|
3254
|
+
violations.push({ file: rule.file, path: path64, value });
|
|
3254
3255
|
}
|
|
3255
3256
|
}
|
|
3256
3257
|
return violations;
|
|
@@ -3289,8 +3290,8 @@ function forbiddenStrings() {
|
|
|
3289
3290
|
process.exit(0);
|
|
3290
3291
|
}
|
|
3291
3292
|
console.log("Forbidden strings found:\n");
|
|
3292
|
-
for (const { file, path:
|
|
3293
|
-
console.log(` ${file} ${
|
|
3293
|
+
for (const { file, path: path64, value } of violations) {
|
|
3294
|
+
console.log(` ${file} ${path64}: ${value}`);
|
|
3294
3295
|
}
|
|
3295
3296
|
console.log(`
|
|
3296
3297
|
Total: ${violations.length} forbidden string(s).`);
|
|
@@ -3582,15 +3583,15 @@ function readBaselineMigrations(repoRelativeDir, ref) {
|
|
|
3582
3583
|
} catch {
|
|
3583
3584
|
return baseline;
|
|
3584
3585
|
}
|
|
3585
|
-
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((
|
|
3586
|
-
for (const
|
|
3586
|
+
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path64) => MIGRATION_FILE3.test(basename(path64)));
|
|
3587
|
+
for (const path64 of paths) {
|
|
3587
3588
|
try {
|
|
3588
|
-
const content = execSync12(`git show "${ref}:${
|
|
3589
|
+
const content = execSync12(`git show "${ref}:${path64}"`, {
|
|
3589
3590
|
encoding: "utf8",
|
|
3590
3591
|
maxBuffer: 16 * 1024 * 1024,
|
|
3591
3592
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3592
3593
|
});
|
|
3593
|
-
baseline.set(basename(
|
|
3594
|
+
baseline.set(basename(path64), content);
|
|
3594
3595
|
} catch {
|
|
3595
3596
|
}
|
|
3596
3597
|
}
|
|
@@ -4955,10 +4956,10 @@ var hooksSettings = {
|
|
|
4955
4956
|
}
|
|
4956
4957
|
};
|
|
4957
4958
|
function ensureHooksSettings() {
|
|
4958
|
-
const
|
|
4959
|
-
mkdirSync5(dirname12(
|
|
4960
|
-
writeFileSync15(
|
|
4961
|
-
return
|
|
4959
|
+
const path64 = daemonPaths.hooksSettings;
|
|
4960
|
+
mkdirSync5(dirname12(path64), { recursive: true });
|
|
4961
|
+
writeFileSync15(path64, JSON.stringify(hooksSettings, null, 2));
|
|
4962
|
+
return path64;
|
|
4962
4963
|
}
|
|
4963
4964
|
|
|
4964
4965
|
// src/shared/spawnInherit.ts
|
|
@@ -5222,9 +5223,9 @@ var LOCAL_FILES = ["backlog.jsonl", "backlog.db"];
|
|
|
5222
5223
|
function backupLocalBacklogFiles(dir) {
|
|
5223
5224
|
const moved = [];
|
|
5224
5225
|
for (const name of LOCAL_FILES) {
|
|
5225
|
-
const
|
|
5226
|
-
if (existsSync18(
|
|
5227
|
-
renameSync(
|
|
5226
|
+
const path64 = join15(dir, ".assist", name);
|
|
5227
|
+
if (existsSync18(path64)) {
|
|
5228
|
+
renameSync(path64, `${path64}.bak`);
|
|
5228
5229
|
moved.push(`${name} \u2192 ${name}.bak`);
|
|
5229
5230
|
}
|
|
5230
5231
|
}
|
|
@@ -5663,8 +5664,8 @@ var backlogItemSchema = z3.strictObject({
|
|
|
5663
5664
|
var backlogFileSchema = z3.array(backlogItemSchema);
|
|
5664
5665
|
|
|
5665
5666
|
// src/commands/backlog/parseBacklogJsonl.ts
|
|
5666
|
-
function parseBacklogJsonl(
|
|
5667
|
-
const content = readFileSync14(
|
|
5667
|
+
function parseBacklogJsonl(path64) {
|
|
5668
|
+
const content = readFileSync14(path64, "utf8").trim();
|
|
5668
5669
|
if (content.length === 0) return [];
|
|
5669
5670
|
return content.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => backlogItemSchema.parse(JSON.parse(line)));
|
|
5670
5671
|
}
|
|
@@ -5746,8 +5747,8 @@ function findBacklogUp(startDir) {
|
|
|
5746
5747
|
|
|
5747
5748
|
// src/commands/backlog/getCurrentOrigin.ts
|
|
5748
5749
|
import { execFileSync } from "child_process";
|
|
5749
|
-
function stripLeadingSlashes(
|
|
5750
|
-
return
|
|
5750
|
+
function stripLeadingSlashes(path64) {
|
|
5751
|
+
return path64.replace(/^\/+/, "");
|
|
5751
5752
|
}
|
|
5752
5753
|
function normalizeOrigin(raw) {
|
|
5753
5754
|
const trimmed = raw.trim().replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
@@ -6287,24 +6288,24 @@ function getOwnerPath(itemId2) {
|
|
|
6287
6288
|
function recordSignalOwner(itemId2) {
|
|
6288
6289
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
6289
6290
|
if (!sessionId) return;
|
|
6290
|
-
const
|
|
6291
|
-
mkdirSync7(dirname14(
|
|
6292
|
-
writeFileSync17(
|
|
6291
|
+
const path64 = getOwnerPath(itemId2);
|
|
6292
|
+
mkdirSync7(dirname14(path64), { recursive: true });
|
|
6293
|
+
writeFileSync17(path64, JSON.stringify({ sessionId }));
|
|
6293
6294
|
}
|
|
6294
6295
|
function readSignalOwner(itemId2) {
|
|
6295
|
-
const
|
|
6296
|
-
if (!existsSync21(
|
|
6296
|
+
const path64 = getOwnerPath(itemId2);
|
|
6297
|
+
if (!existsSync21(path64)) return void 0;
|
|
6297
6298
|
try {
|
|
6298
|
-
const parsed = JSON.parse(readFileSync15(
|
|
6299
|
+
const parsed = JSON.parse(readFileSync15(path64, "utf8"));
|
|
6299
6300
|
return parsed.sessionId;
|
|
6300
6301
|
} catch {
|
|
6301
6302
|
return void 0;
|
|
6302
6303
|
}
|
|
6303
6304
|
}
|
|
6304
6305
|
function clearSignalOwner(itemId2) {
|
|
6305
|
-
const
|
|
6306
|
+
const path64 = getOwnerPath(itemId2);
|
|
6306
6307
|
try {
|
|
6307
|
-
rmSync(
|
|
6308
|
+
rmSync(path64);
|
|
6308
6309
|
} catch {
|
|
6309
6310
|
}
|
|
6310
6311
|
}
|
|
@@ -6341,19 +6342,19 @@ function resolveSignalTarget(event, data) {
|
|
|
6341
6342
|
function writeSignal(event, data) {
|
|
6342
6343
|
const target = resolveSignalTarget(event, data);
|
|
6343
6344
|
if (!target) return;
|
|
6344
|
-
const
|
|
6345
|
-
if (!
|
|
6345
|
+
const path64 = getSignalPath(target);
|
|
6346
|
+
if (!path64) return;
|
|
6346
6347
|
const signal = { event, sessionId: target, ...data };
|
|
6347
|
-
mkdirSync8(dirname15(
|
|
6348
|
-
writeFileSync18(
|
|
6348
|
+
mkdirSync8(dirname15(path64), { recursive: true });
|
|
6349
|
+
writeFileSync18(path64, JSON.stringify(signal));
|
|
6349
6350
|
}
|
|
6350
6351
|
|
|
6351
6352
|
// src/commands/backlog/readSignal.ts
|
|
6352
6353
|
function readSignal() {
|
|
6353
|
-
const
|
|
6354
|
-
if (!
|
|
6354
|
+
const path64 = getSignalPath();
|
|
6355
|
+
if (!path64 || !existsSync22(path64)) return void 0;
|
|
6355
6356
|
try {
|
|
6356
|
-
return JSON.parse(readFileSync16(
|
|
6357
|
+
return JSON.parse(readFileSync16(path64, "utf8"));
|
|
6357
6358
|
} catch {
|
|
6358
6359
|
return void 0;
|
|
6359
6360
|
}
|
|
@@ -6448,13 +6449,13 @@ function activityPath(sessionId) {
|
|
|
6448
6449
|
function emitActivity(activity2) {
|
|
6449
6450
|
const sessionId = process.env.ASSIST_ACTIVITY_ID;
|
|
6450
6451
|
if (!sessionId) return;
|
|
6451
|
-
const
|
|
6452
|
-
mkdirSync9(dirname16(
|
|
6453
|
-
writeFileSync19(
|
|
6452
|
+
const path64 = activityPath(sessionId);
|
|
6453
|
+
mkdirSync9(dirname16(path64), { recursive: true });
|
|
6454
|
+
writeFileSync19(path64, JSON.stringify({ ...activity2, startedAt: Date.now() }));
|
|
6454
6455
|
}
|
|
6455
|
-
function readActivity(
|
|
6456
|
+
function readActivity(path64) {
|
|
6456
6457
|
try {
|
|
6457
|
-
return JSON.parse(readFileSync17(
|
|
6458
|
+
return JSON.parse(readFileSync17(path64, "utf8"));
|
|
6458
6459
|
} catch {
|
|
6459
6460
|
return void 0;
|
|
6460
6461
|
}
|
|
@@ -6464,9 +6465,9 @@ function reconcileActivity(sessionId, activity2) {
|
|
|
6464
6465
|
removeActivity(sessionId);
|
|
6465
6466
|
return;
|
|
6466
6467
|
}
|
|
6467
|
-
const
|
|
6468
|
-
mkdirSync9(dirname16(
|
|
6469
|
-
writeFileSync19(
|
|
6468
|
+
const path64 = activityPath(sessionId);
|
|
6469
|
+
mkdirSync9(dirname16(path64), { recursive: true });
|
|
6470
|
+
writeFileSync19(path64, JSON.stringify(activity2));
|
|
6470
6471
|
}
|
|
6471
6472
|
function removeActivity(sessionId) {
|
|
6472
6473
|
try {
|
|
@@ -7697,8 +7698,8 @@ async function getBacklogExists(req, res) {
|
|
|
7697
7698
|
// src/commands/backlog/originDisplayName.ts
|
|
7698
7699
|
function originDisplayName(origin) {
|
|
7699
7700
|
if (origin.startsWith("local:")) {
|
|
7700
|
-
const
|
|
7701
|
-
const segments =
|
|
7701
|
+
const path64 = origin.slice("local:".length).replace(/\/+$/, "");
|
|
7702
|
+
const segments = path64.split("/").filter(Boolean);
|
|
7702
7703
|
return segments[segments.length - 1] ?? origin;
|
|
7703
7704
|
}
|
|
7704
7705
|
const firstSlash = origin.indexOf("/");
|
|
@@ -7784,14 +7785,26 @@ async function updateStarred(orm, id, starred) {
|
|
|
7784
7785
|
return row?.name;
|
|
7785
7786
|
}
|
|
7786
7787
|
|
|
7788
|
+
// src/commands/backlog/web/parseBacklogFilter.ts
|
|
7789
|
+
var validFilters = /* @__PURE__ */ new Set(["todo", "done", "all"]);
|
|
7790
|
+
function parseBacklogFilter(value) {
|
|
7791
|
+
return value && validFilters.has(value) ? value : "todo";
|
|
7792
|
+
}
|
|
7793
|
+
|
|
7787
7794
|
// src/commands/backlog/web/loadVisibleItems.ts
|
|
7788
|
-
var
|
|
7795
|
+
var doneStatuses = /* @__PURE__ */ new Set(["done", "wontdo"]);
|
|
7796
|
+
var todoStatuses = /* @__PURE__ */ new Set(["todo", "in-progress"]);
|
|
7797
|
+
function matchesFilter(status3, filter) {
|
|
7798
|
+
if (filter === "all") return true;
|
|
7799
|
+
if (filter === "done") return doneStatuses.has(status3);
|
|
7800
|
+
return todoStatuses.has(status3);
|
|
7801
|
+
}
|
|
7789
7802
|
async function loadVisibleItems(req) {
|
|
7790
7803
|
const params = new URL(req.url ?? "/", "http://localhost").searchParams;
|
|
7791
7804
|
const q = params.get("q");
|
|
7805
|
+
const filter = parseBacklogFilter(params.get("filter"));
|
|
7792
7806
|
const loaded = q ? await searchBacklogSummaries(q) : await loadBacklogSummaries();
|
|
7793
|
-
|
|
7794
|
-
return loaded.filter((item) => !completedStatuses2.has(item.status));
|
|
7807
|
+
return loaded.filter((item) => matchesFilter(item.status, filter));
|
|
7795
7808
|
}
|
|
7796
7809
|
|
|
7797
7810
|
// src/commands/backlog/web/parseStatusBody.ts
|
|
@@ -8089,7 +8102,7 @@ function findSynthesisForBranch(repoReviewsDir, branch2) {
|
|
|
8089
8102
|
const parent = dirname20(branchKeyPath);
|
|
8090
8103
|
const branchPrefix = basename5(branchKeyPath);
|
|
8091
8104
|
if (!existsSync25(parent)) return null;
|
|
8092
|
-
const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join23(parent, name, "synthesis.md")).filter((
|
|
8105
|
+
const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join23(parent, name, "synthesis.md")).filter((path64) => existsSync25(path64)).map((path64) => ({ path: path64, mtime: statSync2(path64).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
8093
8106
|
return synthesisFiles[0]?.path ?? null;
|
|
8094
8107
|
}
|
|
8095
8108
|
|
|
@@ -8143,12 +8156,12 @@ async function getReviewSynthesis(req, res) {
|
|
|
8143
8156
|
const cwd = getCwdParam(req, res);
|
|
8144
8157
|
if (!cwd) return;
|
|
8145
8158
|
try {
|
|
8146
|
-
const
|
|
8147
|
-
if (!
|
|
8159
|
+
const path64 = await resolveSynthesisPath(cwd);
|
|
8160
|
+
if (!path64) {
|
|
8148
8161
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
8149
8162
|
return;
|
|
8150
8163
|
}
|
|
8151
|
-
respondJson(res, 200, { synthesis: readFileSync19(
|
|
8164
|
+
respondJson(res, 200, { synthesis: readFileSync19(path64, "utf8") });
|
|
8152
8165
|
} catch {
|
|
8153
8166
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
8154
8167
|
}
|
|
@@ -8283,10 +8296,10 @@ function getStorePath(filename) {
|
|
|
8283
8296
|
return join26(getStoreDir(), filename);
|
|
8284
8297
|
}
|
|
8285
8298
|
function loadJson(filename) {
|
|
8286
|
-
const
|
|
8287
|
-
if (existsSync26(
|
|
8299
|
+
const path64 = getStorePath(filename);
|
|
8300
|
+
if (existsSync26(path64)) {
|
|
8288
8301
|
try {
|
|
8289
|
-
return JSON.parse(readFileSync20(
|
|
8302
|
+
return JSON.parse(readFileSync20(path64, "utf8"));
|
|
8290
8303
|
} catch {
|
|
8291
8304
|
return {};
|
|
8292
8305
|
}
|
|
@@ -11440,52 +11453,6 @@ function findBuiltinDenyRaw(rawCommand) {
|
|
|
11440
11453
|
return toDecision(matchBuiltinDeny(rawCommand));
|
|
11441
11454
|
}
|
|
11442
11455
|
|
|
11443
|
-
// src/commands/cliHook/logDeniedToolCall.ts
|
|
11444
|
-
import { mkdirSync as mkdirSync12 } from "fs";
|
|
11445
|
-
import { homedir as homedir14 } from "os";
|
|
11446
|
-
import { join as join28 } from "path";
|
|
11447
|
-
import Database from "better-sqlite3";
|
|
11448
|
-
var _db;
|
|
11449
|
-
function getDbDir() {
|
|
11450
|
-
return join28(homedir14(), ".assist");
|
|
11451
|
-
}
|
|
11452
|
-
function initSchema(db) {
|
|
11453
|
-
db.exec(`
|
|
11454
|
-
CREATE TABLE IF NOT EXISTS denied_tool_calls (
|
|
11455
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
11456
|
-
tool TEXT NOT NULL,
|
|
11457
|
-
command TEXT NOT NULL,
|
|
11458
|
-
repo TEXT NOT NULL,
|
|
11459
|
-
session_id TEXT,
|
|
11460
|
-
deny_reason TEXT NOT NULL,
|
|
11461
|
-
timestamp TEXT NOT NULL DEFAULT (datetime('now'))
|
|
11462
|
-
);
|
|
11463
|
-
`);
|
|
11464
|
-
}
|
|
11465
|
-
function openPromptsDb(dir) {
|
|
11466
|
-
if (_db) return _db;
|
|
11467
|
-
const dbDir = dir ?? getDbDir();
|
|
11468
|
-
mkdirSync12(dbDir, { recursive: true });
|
|
11469
|
-
const db = new Database(join28(dbDir, "assist.db"));
|
|
11470
|
-
db.pragma("journal_mode = WAL");
|
|
11471
|
-
initSchema(db);
|
|
11472
|
-
_db = db;
|
|
11473
|
-
return db;
|
|
11474
|
-
}
|
|
11475
|
-
function logDeniedToolCall(entry) {
|
|
11476
|
-
const db = openPromptsDb();
|
|
11477
|
-
db.prepare(
|
|
11478
|
-
`INSERT INTO denied_tool_calls (tool, command, repo, session_id, deny_reason)
|
|
11479
|
-
VALUES (@tool, @command, @repo, @sessionId, @denyReason)`
|
|
11480
|
-
).run({
|
|
11481
|
-
tool: entry.tool,
|
|
11482
|
-
command: entry.command,
|
|
11483
|
-
repo: entry.repo,
|
|
11484
|
-
sessionId: entry.sessionId ?? null,
|
|
11485
|
-
denyReason: entry.denyReason
|
|
11486
|
-
});
|
|
11487
|
-
}
|
|
11488
|
-
|
|
11489
11456
|
// src/shared/isApprovedRead.ts
|
|
11490
11457
|
import { resolve as resolve9, sep } from "path";
|
|
11491
11458
|
|
|
@@ -11576,9 +11543,9 @@ var __dirname4 = dirname21(__filename3);
|
|
|
11576
11543
|
function packageRoot() {
|
|
11577
11544
|
return __dirname4;
|
|
11578
11545
|
}
|
|
11579
|
-
function readLines(
|
|
11580
|
-
if (!existsSync27(
|
|
11581
|
-
return readFileSync23(
|
|
11546
|
+
function readLines(path64) {
|
|
11547
|
+
if (!existsSync27(path64)) return [];
|
|
11548
|
+
return readFileSync23(path64, "utf8").split("\n").filter((line) => line.trim() !== "");
|
|
11582
11549
|
}
|
|
11583
11550
|
var cachedReads;
|
|
11584
11551
|
var cachedWrites;
|
|
@@ -11625,13 +11592,13 @@ function findCliWrite(command) {
|
|
|
11625
11592
|
|
|
11626
11593
|
// src/shared/readSettingsPerms.ts
|
|
11627
11594
|
import { existsSync as existsSync28, readFileSync as readFileSync24 } from "fs";
|
|
11628
|
-
import { homedir as
|
|
11629
|
-
import { join as
|
|
11595
|
+
import { homedir as homedir14 } from "os";
|
|
11596
|
+
import { join as join28 } from "path";
|
|
11630
11597
|
function readSettingsPerms(key) {
|
|
11631
11598
|
const paths = [
|
|
11632
|
-
|
|
11633
|
-
|
|
11634
|
-
|
|
11599
|
+
join28(homedir14(), ".claude", "settings.json"),
|
|
11600
|
+
join28(process.cwd(), ".claude", "settings.json"),
|
|
11601
|
+
join28(process.cwd(), ".claude", "settings.local.json")
|
|
11635
11602
|
];
|
|
11636
11603
|
const entries = [];
|
|
11637
11604
|
for (const p of paths) {
|
|
@@ -11823,6 +11790,59 @@ function resolvePermission(toolName, parts) {
|
|
|
11823
11790
|
};
|
|
11824
11791
|
}
|
|
11825
11792
|
|
|
11793
|
+
// src/commands/cliHook/decideCommand.ts
|
|
11794
|
+
function decideCommand(toolName, rawCommand) {
|
|
11795
|
+
const result = splitCompound(rawCommand);
|
|
11796
|
+
if (result.ok) return resolvePermission(toolName, result.parts);
|
|
11797
|
+
return findBuiltinDenyRaw(rawCommand) ?? findDeny(toolName, [rawCommand]);
|
|
11798
|
+
}
|
|
11799
|
+
|
|
11800
|
+
// src/commands/cliHook/logDeniedToolCall.ts
|
|
11801
|
+
import { mkdirSync as mkdirSync12 } from "fs";
|
|
11802
|
+
import { homedir as homedir15 } from "os";
|
|
11803
|
+
import { join as join29 } from "path";
|
|
11804
|
+
import Database from "better-sqlite3";
|
|
11805
|
+
var _db;
|
|
11806
|
+
function getDbDir() {
|
|
11807
|
+
return join29(homedir15(), ".assist");
|
|
11808
|
+
}
|
|
11809
|
+
function initSchema(db) {
|
|
11810
|
+
db.exec(`
|
|
11811
|
+
CREATE TABLE IF NOT EXISTS denied_tool_calls (
|
|
11812
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
11813
|
+
tool TEXT NOT NULL,
|
|
11814
|
+
command TEXT NOT NULL,
|
|
11815
|
+
repo TEXT NOT NULL,
|
|
11816
|
+
session_id TEXT,
|
|
11817
|
+
deny_reason TEXT NOT NULL,
|
|
11818
|
+
timestamp TEXT NOT NULL DEFAULT (datetime('now'))
|
|
11819
|
+
);
|
|
11820
|
+
`);
|
|
11821
|
+
}
|
|
11822
|
+
function openPromptsDb(dir) {
|
|
11823
|
+
if (_db) return _db;
|
|
11824
|
+
const dbDir = dir ?? getDbDir();
|
|
11825
|
+
mkdirSync12(dbDir, { recursive: true });
|
|
11826
|
+
const db = new Database(join29(dbDir, "assist.db"));
|
|
11827
|
+
db.pragma("journal_mode = WAL");
|
|
11828
|
+
initSchema(db);
|
|
11829
|
+
_db = db;
|
|
11830
|
+
return db;
|
|
11831
|
+
}
|
|
11832
|
+
function logDeniedToolCall(entry) {
|
|
11833
|
+
const db = openPromptsDb();
|
|
11834
|
+
db.prepare(
|
|
11835
|
+
`INSERT INTO denied_tool_calls (tool, command, repo, session_id, deny_reason)
|
|
11836
|
+
VALUES (@tool, @command, @repo, @sessionId, @denyReason)`
|
|
11837
|
+
).run({
|
|
11838
|
+
tool: entry.tool,
|
|
11839
|
+
command: entry.command,
|
|
11840
|
+
repo: entry.repo,
|
|
11841
|
+
sessionId: entry.sessionId ?? null,
|
|
11842
|
+
denyReason: entry.denyReason
|
|
11843
|
+
});
|
|
11844
|
+
}
|
|
11845
|
+
|
|
11826
11846
|
// src/commands/cliHook/index.ts
|
|
11827
11847
|
var SUPPORTED_TOOLS = /* @__PURE__ */ new Set(["Bash", "PowerShell"]);
|
|
11828
11848
|
function tryParseInput(raw) {
|
|
@@ -11838,15 +11858,10 @@ function tryParseInput(raw) {
|
|
|
11838
11858
|
return void 0;
|
|
11839
11859
|
}
|
|
11840
11860
|
}
|
|
11841
|
-
function decide(toolName, rawCommand) {
|
|
11842
|
-
const result = splitCompound(rawCommand);
|
|
11843
|
-
if (result.ok) return resolvePermission(toolName, result.parts);
|
|
11844
|
-
return findBuiltinDenyRaw(rawCommand) ?? findDeny(toolName, [rawCommand]);
|
|
11845
|
-
}
|
|
11846
11861
|
async function cliHook() {
|
|
11847
11862
|
const input = tryParseInput(await readStdin());
|
|
11848
11863
|
if (!input) return;
|
|
11849
|
-
const decision =
|
|
11864
|
+
const decision = decideCommand(input.toolName, input.command);
|
|
11850
11865
|
if (!decision) return;
|
|
11851
11866
|
console.log(
|
|
11852
11867
|
JSON.stringify({
|
|
@@ -12022,14 +12037,14 @@ function showProgress(p, label2) {
|
|
|
12022
12037
|
const pct = Math.round(p.done / p.total * 100);
|
|
12023
12038
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
12024
12039
|
}
|
|
12025
|
-
async function resolveCommand(cli,
|
|
12026
|
-
showProgress(p,
|
|
12027
|
-
const subHelp = await runHelp([cli, ...
|
|
12040
|
+
async function resolveCommand(cli, path64, description, depth, p) {
|
|
12041
|
+
showProgress(p, path64.join(" "));
|
|
12042
|
+
const subHelp = await runHelp([cli, ...path64]);
|
|
12028
12043
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
12029
|
-
return [{ path:
|
|
12044
|
+
return [{ path: path64, description }];
|
|
12030
12045
|
}
|
|
12031
|
-
const children = await discoverAt(cli,
|
|
12032
|
-
return children.length > 0 ? children : [{ path:
|
|
12046
|
+
const children = await discoverAt(cli, path64, depth + 1, p);
|
|
12047
|
+
return children.length > 0 ? children : [{ path: path64, description }];
|
|
12033
12048
|
}
|
|
12034
12049
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
12035
12050
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -12177,9 +12192,9 @@ function logPath(cli) {
|
|
|
12177
12192
|
return join30(homedir16(), ".assist", `cli-discover-${safeName}.log`);
|
|
12178
12193
|
}
|
|
12179
12194
|
function readCache(cli) {
|
|
12180
|
-
const
|
|
12181
|
-
if (!existsSync29(
|
|
12182
|
-
return readFileSync25(
|
|
12195
|
+
const path64 = logPath(cli);
|
|
12196
|
+
if (!existsSync29(path64)) return void 0;
|
|
12197
|
+
return readFileSync25(path64, "utf8");
|
|
12183
12198
|
}
|
|
12184
12199
|
function writeCache(cli, output) {
|
|
12185
12200
|
const dir = join30(homedir16(), ".assist");
|
|
@@ -12351,9 +12366,9 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
12351
12366
|
}
|
|
12352
12367
|
const cutoff = Date.now() - STALE_AFTER_MS;
|
|
12353
12368
|
for (const entry of entries) {
|
|
12354
|
-
const
|
|
12369
|
+
const path64 = join32(dir, entry);
|
|
12355
12370
|
try {
|
|
12356
|
-
if (statSync3(
|
|
12371
|
+
if (statSync3(path64).mtimeMs < cutoff) unlinkSync7(path64);
|
|
12357
12372
|
} catch {
|
|
12358
12373
|
continue;
|
|
12359
12374
|
}
|
|
@@ -12363,10 +12378,10 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
12363
12378
|
// src/commands/codeComment/readPinState.ts
|
|
12364
12379
|
import { existsSync as existsSync30, readFileSync as readFileSync26 } from "fs";
|
|
12365
12380
|
function readPinState(pin) {
|
|
12366
|
-
const
|
|
12367
|
-
if (!existsSync30(
|
|
12381
|
+
const path64 = getPinStatePath(pin);
|
|
12382
|
+
if (!existsSync30(path64)) return void 0;
|
|
12368
12383
|
try {
|
|
12369
|
-
const state = JSON.parse(readFileSync26(
|
|
12384
|
+
const state = JSON.parse(readFileSync26(path64, "utf8"));
|
|
12370
12385
|
if (state.pin !== pin) return void 0;
|
|
12371
12386
|
return state;
|
|
12372
12387
|
} catch {
|
|
@@ -12515,6 +12530,65 @@ function registerCodeComment(parent) {
|
|
|
12515
12530
|
codeComment.command("confirm").description("Confirm a pin to insert its comment and clear the pin state").argument("<pin>", "Pin issued by 'code-comment set'").action(codeCommentConfirm);
|
|
12516
12531
|
}
|
|
12517
12532
|
|
|
12533
|
+
// src/commands/codexHook/index.ts
|
|
12534
|
+
var SUPPORTED_TOOLS2 = /* @__PURE__ */ new Set(["Bash", "PowerShell"]);
|
|
12535
|
+
function parseInput(raw) {
|
|
12536
|
+
try {
|
|
12537
|
+
const data = JSON.parse(raw);
|
|
12538
|
+
const command = data.tool_input?.command;
|
|
12539
|
+
if (typeof command !== "string" || !command.trim()) return void 0;
|
|
12540
|
+
if (!data.tool_name || !SUPPORTED_TOOLS2.has(data.tool_name))
|
|
12541
|
+
return void 0;
|
|
12542
|
+
return {
|
|
12543
|
+
event: data.hook_event_name ?? "PreToolUse",
|
|
12544
|
+
toolName: data.tool_name,
|
|
12545
|
+
command: command.trim()
|
|
12546
|
+
};
|
|
12547
|
+
} catch {
|
|
12548
|
+
return void 0;
|
|
12549
|
+
}
|
|
12550
|
+
}
|
|
12551
|
+
function preToolUseOutput(decision) {
|
|
12552
|
+
if (decision.permissionDecision === "allow") {
|
|
12553
|
+
return {
|
|
12554
|
+
hookSpecificOutput: {
|
|
12555
|
+
hookEventName: "PreToolUse",
|
|
12556
|
+
permissionDecision: "allow",
|
|
12557
|
+
permissionDecisionReason: decision.permissionDecisionReason
|
|
12558
|
+
}
|
|
12559
|
+
};
|
|
12560
|
+
}
|
|
12561
|
+
return { decision: "block", reason: decision.permissionDecisionReason };
|
|
12562
|
+
}
|
|
12563
|
+
function permissionRequestOutput(decision) {
|
|
12564
|
+
return {
|
|
12565
|
+
hookSpecificOutput: {
|
|
12566
|
+
hookEventName: "PermissionRequest",
|
|
12567
|
+
decision: {
|
|
12568
|
+
behavior: decision.permissionDecision === "allow" ? "allow" : "deny",
|
|
12569
|
+
message: decision.permissionDecisionReason
|
|
12570
|
+
}
|
|
12571
|
+
}
|
|
12572
|
+
};
|
|
12573
|
+
}
|
|
12574
|
+
async function codexHook() {
|
|
12575
|
+
const input = parseInput(await readStdin());
|
|
12576
|
+
if (!input) return;
|
|
12577
|
+
const decision = decideCommand(input.toolName, input.command);
|
|
12578
|
+
if (!decision) return;
|
|
12579
|
+
const output = input.event === "PermissionRequest" ? permissionRequestOutput(decision) : preToolUseOutput(decision);
|
|
12580
|
+
console.log(JSON.stringify(output));
|
|
12581
|
+
}
|
|
12582
|
+
|
|
12583
|
+
// src/commands/registerCodexHook.ts
|
|
12584
|
+
function registerCodexHook(program2) {
|
|
12585
|
+
program2.command("codex-hook").description(
|
|
12586
|
+
"Codex PreToolUse/PermissionRequest hook for auto-approving read-only CLI commands"
|
|
12587
|
+
).action(() => {
|
|
12588
|
+
codexHook();
|
|
12589
|
+
});
|
|
12590
|
+
}
|
|
12591
|
+
|
|
12518
12592
|
// src/commands/complexity/analyze.ts
|
|
12519
12593
|
import chalk119 from "chalk";
|
|
12520
12594
|
|
|
@@ -13132,8 +13206,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
13132
13206
|
}
|
|
13133
13207
|
return ensureObject(container, resolved);
|
|
13134
13208
|
}
|
|
13135
|
-
function setNestedValue(obj,
|
|
13136
|
-
const keys =
|
|
13209
|
+
function setNestedValue(obj, path64, value) {
|
|
13210
|
+
const keys = path64.split(".");
|
|
13137
13211
|
const result = { ...obj };
|
|
13138
13212
|
let current = result;
|
|
13139
13213
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -13213,9 +13287,9 @@ function isTraversable(value) {
|
|
|
13213
13287
|
function stepInto(current, key) {
|
|
13214
13288
|
return isTraversable(current) ? current[key] : void 0;
|
|
13215
13289
|
}
|
|
13216
|
-
function getNestedValue(obj,
|
|
13290
|
+
function getNestedValue(obj, path64) {
|
|
13217
13291
|
let current = obj;
|
|
13218
|
-
for (const key of
|
|
13292
|
+
for (const key of path64.split(".")) current = stepInto(current, key);
|
|
13219
13293
|
return current;
|
|
13220
13294
|
}
|
|
13221
13295
|
|
|
@@ -15801,9 +15875,9 @@ function parseRscRows(flight) {
|
|
|
15801
15875
|
}
|
|
15802
15876
|
function makeRscResolver(rows) {
|
|
15803
15877
|
return (ref) => {
|
|
15804
|
-
const [id, ...
|
|
15878
|
+
const [id, ...path64] = ref.slice(1).replace(/^[L@]/, "").split(":");
|
|
15805
15879
|
let v = rows[id];
|
|
15806
|
-
for (const key of
|
|
15880
|
+
for (const key of path64) {
|
|
15807
15881
|
if (v == null || typeof v !== "object") return void 0;
|
|
15808
15882
|
v = v[key];
|
|
15809
15883
|
}
|
|
@@ -16450,15 +16524,15 @@ function postComment(vars) {
|
|
|
16450
16524
|
const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
|
|
16451
16525
|
assertThreadCreated(stdout);
|
|
16452
16526
|
}
|
|
16453
|
-
function comment2(
|
|
16527
|
+
function comment2(path64, line, body, startLine) {
|
|
16454
16528
|
validateBody(body);
|
|
16455
16529
|
validateLine(line);
|
|
16456
16530
|
if (startLine !== void 0) validateLine(startLine);
|
|
16457
16531
|
try {
|
|
16458
16532
|
const prId = getCurrentPrNodeId();
|
|
16459
|
-
postComment({ prId, body, path:
|
|
16533
|
+
postComment({ prId, body, path: path64, line, startLine });
|
|
16460
16534
|
const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
|
|
16461
|
-
console.log(`Added review comment on ${
|
|
16535
|
+
console.log(`Added review comment on ${path64}:${range}`);
|
|
16462
16536
|
} catch (error) {
|
|
16463
16537
|
if (isGhNotInstalled(error)) {
|
|
16464
16538
|
console.error("Error: GitHub CLI (gh) is not installed.");
|
|
@@ -17319,8 +17393,8 @@ function registerPrs(program2) {
|
|
|
17319
17393
|
prsCommand.command("reply <comment-id> <body>").description("Reply to a comment thread without resolving it").action((commentId, body) => {
|
|
17320
17394
|
reply(Number.parseInt(commentId, 10), body);
|
|
17321
17395
|
});
|
|
17322
|
-
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((
|
|
17323
|
-
comment2(
|
|
17396
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path64, line, body) => {
|
|
17397
|
+
comment2(path64, Number.parseInt(line, 10), body);
|
|
17324
17398
|
});
|
|
17325
17399
|
configHelp(prsCommand, prsConfigHelp);
|
|
17326
17400
|
}
|
|
@@ -17573,10 +17647,10 @@ function resolveOpSecret(reference) {
|
|
|
17573
17647
|
}
|
|
17574
17648
|
|
|
17575
17649
|
// src/commands/ravendb/ravenFetch.ts
|
|
17576
|
-
async function ravenFetch(connection,
|
|
17650
|
+
async function ravenFetch(connection, path64) {
|
|
17577
17651
|
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
17578
17652
|
let accessToken = await getAccessToken(apiKey);
|
|
17579
|
-
const url = `${connection.url}${
|
|
17653
|
+
const url = `${connection.url}${path64}`;
|
|
17580
17654
|
const headers = {
|
|
17581
17655
|
Authorization: `Bearer ${accessToken}`,
|
|
17582
17656
|
"Content-Type": "application/json"
|
|
@@ -17680,16 +17754,16 @@ import chalk166 from "chalk";
|
|
|
17680
17754
|
// src/commands/ravendb/buildQueryPath.ts
|
|
17681
17755
|
function buildQueryPath(opts) {
|
|
17682
17756
|
const db = encodeURIComponent(opts.db);
|
|
17683
|
-
let
|
|
17757
|
+
let path64;
|
|
17684
17758
|
if (opts.collection) {
|
|
17685
|
-
|
|
17759
|
+
path64 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
17686
17760
|
} else {
|
|
17687
|
-
|
|
17761
|
+
path64 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
17688
17762
|
}
|
|
17689
17763
|
if (opts.query) {
|
|
17690
|
-
|
|
17764
|
+
path64 += `&query=${encodeURIComponent(opts.query)}`;
|
|
17691
17765
|
}
|
|
17692
|
-
return
|
|
17766
|
+
return path64;
|
|
17693
17767
|
}
|
|
17694
17768
|
|
|
17695
17769
|
// src/commands/ravendb/fetchAllPages.ts
|
|
@@ -17698,7 +17772,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
17698
17772
|
let start3 = 0;
|
|
17699
17773
|
while (true) {
|
|
17700
17774
|
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
17701
|
-
const
|
|
17775
|
+
const path64 = buildQueryPath({
|
|
17702
17776
|
db: connection.database,
|
|
17703
17777
|
collection: opts.collection,
|
|
17704
17778
|
start: start3,
|
|
@@ -17706,7 +17780,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
17706
17780
|
sort: opts.sort,
|
|
17707
17781
|
query: opts.query
|
|
17708
17782
|
});
|
|
17709
|
-
const data = await ravenFetch(connection,
|
|
17783
|
+
const data = await ravenFetch(connection, path64);
|
|
17710
17784
|
const results = data.Results ?? [];
|
|
17711
17785
|
const totalResults = data.TotalResults ?? 0;
|
|
17712
17786
|
if (results.length === 0) break;
|
|
@@ -20094,8 +20168,8 @@ async function handlePostSynthesis(synthesisPath, options2) {
|
|
|
20094
20168
|
// src/commands/review/prepareReviewDir.ts
|
|
20095
20169
|
import { existsSync as existsSync41, mkdirSync as mkdirSync17, unlinkSync as unlinkSync14, writeFileSync as writeFileSync34 } from "fs";
|
|
20096
20170
|
function clearReviewFiles(paths) {
|
|
20097
|
-
for (const
|
|
20098
|
-
if (existsSync41(
|
|
20171
|
+
for (const path64 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
20172
|
+
if (existsSync41(path64)) unlinkSync14(path64);
|
|
20099
20173
|
}
|
|
20100
20174
|
}
|
|
20101
20175
|
function prepareReviewDir(paths, requestBody, force) {
|
|
@@ -21243,8 +21317,8 @@ import chalk187 from "chalk";
|
|
|
21243
21317
|
|
|
21244
21318
|
// src/commands/seq/fetchSeq.ts
|
|
21245
21319
|
import chalk184 from "chalk";
|
|
21246
|
-
async function fetchSeq(conn,
|
|
21247
|
-
const url = `${conn.url}${
|
|
21320
|
+
async function fetchSeq(conn, path64, params) {
|
|
21321
|
+
const url = `${conn.url}${path64}?${params}`;
|
|
21248
21322
|
const response = await fetch(url, {
|
|
21249
21323
|
headers: {
|
|
21250
21324
|
Accept: "application/json",
|
|
@@ -22731,9 +22805,9 @@ function findPortFile(roamDir) {
|
|
|
22731
22805
|
return void 0;
|
|
22732
22806
|
}
|
|
22733
22807
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
22734
|
-
const
|
|
22808
|
+
const path64 = join60(roamDir, name);
|
|
22735
22809
|
try {
|
|
22736
|
-
return { path:
|
|
22810
|
+
return { path: path64, mtimeMs: statSync8(path64).mtimeMs };
|
|
22737
22811
|
} catch {
|
|
22738
22812
|
return void 0;
|
|
22739
22813
|
}
|
|
@@ -23152,11 +23226,11 @@ function findLinkIndex() {
|
|
|
23152
23226
|
function parseLinkArgs() {
|
|
23153
23227
|
const idx = findLinkIndex();
|
|
23154
23228
|
if (idx === -1) return null;
|
|
23155
|
-
const
|
|
23229
|
+
const path64 = process.argv[idx + 1];
|
|
23156
23230
|
const rest = process.argv.slice(idx + 2);
|
|
23157
23231
|
const { value: prefix2 } = extractOption(rest, "--prefix");
|
|
23158
23232
|
if (!prefix2) return null;
|
|
23159
|
-
return { path:
|
|
23233
|
+
return { path: path64, prefix: prefix2 };
|
|
23160
23234
|
}
|
|
23161
23235
|
function hasDuplicateLink(runList, linkPath) {
|
|
23162
23236
|
return runList.some(
|
|
@@ -24436,8 +24510,8 @@ async function seedRunningMsFromUsage(session, notify2) {
|
|
|
24436
24510
|
var DEBOUNCE_MS = 50;
|
|
24437
24511
|
function watchActivity(session, notify2) {
|
|
24438
24512
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
24439
|
-
const
|
|
24440
|
-
const dir = dirname29(
|
|
24513
|
+
const path64 = activityPath(session.id);
|
|
24514
|
+
const dir = dirname29(path64);
|
|
24441
24515
|
try {
|
|
24442
24516
|
mkdirSync24(dir, { recursive: true });
|
|
24443
24517
|
} catch {
|
|
@@ -24447,7 +24521,7 @@ function watchActivity(session, notify2) {
|
|
|
24447
24521
|
let timer = null;
|
|
24448
24522
|
const read = () => {
|
|
24449
24523
|
timer = null;
|
|
24450
|
-
const activity2 = readActivity(
|
|
24524
|
+
const activity2 = readActivity(path64);
|
|
24451
24525
|
if (!activity2) return;
|
|
24452
24526
|
session.activity = activity2;
|
|
24453
24527
|
if (activity2.claudeSessionId)
|
|
@@ -24457,11 +24531,11 @@ function watchActivity(session, notify2) {
|
|
|
24457
24531
|
notify2();
|
|
24458
24532
|
};
|
|
24459
24533
|
session.activityWatcher = watch(dir, (_event, filename) => {
|
|
24460
|
-
if (filename && !
|
|
24534
|
+
if (filename && !path64.endsWith(filename)) return;
|
|
24461
24535
|
if (timer) clearTimeout(timer);
|
|
24462
24536
|
timer = setTimeout(read, DEBOUNCE_MS);
|
|
24463
24537
|
});
|
|
24464
|
-
if (existsSync54(
|
|
24538
|
+
if (existsSync54(path64)) read();
|
|
24465
24539
|
}
|
|
24466
24540
|
function refreshActivity(session) {
|
|
24467
24541
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
@@ -26550,9 +26624,9 @@ async function statusLine() {
|
|
|
26550
26624
|
}
|
|
26551
26625
|
|
|
26552
26626
|
// src/commands/sync.ts
|
|
26553
|
-
import * as
|
|
26627
|
+
import * as fs44 from "fs";
|
|
26554
26628
|
import * as os3 from "os";
|
|
26555
|
-
import * as
|
|
26629
|
+
import * as path62 from "path";
|
|
26556
26630
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
26557
26631
|
|
|
26558
26632
|
// src/commands/sync/syncClaudeMd.ts
|
|
@@ -26586,8 +26660,52 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
26586
26660
|
}
|
|
26587
26661
|
|
|
26588
26662
|
// src/commands/sync/syncCodex.ts
|
|
26663
|
+
import * as fs41 from "fs";
|
|
26664
|
+
import * as path59 from "path";
|
|
26665
|
+
|
|
26666
|
+
// src/commands/sync/syncCodexHooks.ts
|
|
26589
26667
|
import * as fs40 from "fs";
|
|
26590
26668
|
import * as path58 from "path";
|
|
26669
|
+
var BEGIN = "# >>> assist codex hooks (managed) \u2014 do not edit >>>";
|
|
26670
|
+
var END = "# <<< assist codex hooks (managed) <<<";
|
|
26671
|
+
function upsertManagedBlock(existing, body) {
|
|
26672
|
+
const block = `${BEGIN}
|
|
26673
|
+
${body.trim()}
|
|
26674
|
+
${END}`;
|
|
26675
|
+
const begin = existing.indexOf(BEGIN);
|
|
26676
|
+
if (begin === -1) {
|
|
26677
|
+
const base = existing.replace(/\s*$/, "");
|
|
26678
|
+
return base ? `${base}
|
|
26679
|
+
|
|
26680
|
+
${block}
|
|
26681
|
+
` : `${block}
|
|
26682
|
+
`;
|
|
26683
|
+
}
|
|
26684
|
+
const endMarker = existing.indexOf(END, begin);
|
|
26685
|
+
const after = endMarker === -1 ? existing.length : endMarker + END.length;
|
|
26686
|
+
const before = existing.slice(0, begin).replace(/\s*$/, "");
|
|
26687
|
+
const rest = existing.slice(after).replace(/^\s*/, "");
|
|
26688
|
+
const head = before ? `${before}
|
|
26689
|
+
|
|
26690
|
+
${block}` : block;
|
|
26691
|
+
return rest ? `${head}
|
|
26692
|
+
|
|
26693
|
+
${rest}
|
|
26694
|
+
` : `${head}
|
|
26695
|
+
`;
|
|
26696
|
+
}
|
|
26697
|
+
function syncCodexHooks(sourcePath) {
|
|
26698
|
+
const body = fs40.readFileSync(sourcePath, "utf8");
|
|
26699
|
+
const configPath = path58.join(harnesses.codex.homeDir, "config.toml");
|
|
26700
|
+
const existing = fs40.existsSync(configPath) ? fs40.readFileSync(configPath, "utf8") : "";
|
|
26701
|
+
fs40.mkdirSync(path58.dirname(configPath), { recursive: true });
|
|
26702
|
+
fs40.writeFileSync(configPath, upsertManagedBlock(existing, body));
|
|
26703
|
+
console.log(
|
|
26704
|
+
"Registered assist codex-hook in ~/.codex/config.toml (PreToolUse, PermissionRequest)"
|
|
26705
|
+
);
|
|
26706
|
+
}
|
|
26707
|
+
|
|
26708
|
+
// src/commands/sync/syncCodex.ts
|
|
26591
26709
|
function quoteYaml(value) {
|
|
26592
26710
|
return `"${value.replace(/\\/g, String.raw`\\`).replace(/"/g, String.raw`\"`)}"`;
|
|
26593
26711
|
}
|
|
@@ -26608,56 +26726,57 @@ description: ${quoteYaml(description)}
|
|
|
26608
26726
|
function syncCodex(claudeDir) {
|
|
26609
26727
|
if (!isHarnessAvailable("codex")) return;
|
|
26610
26728
|
const codex = harnesses.codex;
|
|
26611
|
-
const commandsSource =
|
|
26612
|
-
const files =
|
|
26729
|
+
const commandsSource = path59.join(claudeDir, "commands");
|
|
26730
|
+
const files = fs41.readdirSync(commandsSource);
|
|
26613
26731
|
for (const file of files) {
|
|
26614
26732
|
if (!file.endsWith(".md")) continue;
|
|
26615
26733
|
const name = file.replace(/\.md$/, "");
|
|
26616
|
-
const content =
|
|
26617
|
-
const target =
|
|
26618
|
-
|
|
26619
|
-
|
|
26620
|
-
}
|
|
26621
|
-
const agentsTarget =
|
|
26622
|
-
|
|
26623
|
-
|
|
26734
|
+
const content = fs41.readFileSync(path59.join(commandsSource, file), "utf8");
|
|
26735
|
+
const target = path59.join(codex.homeDir, codex.sync.commandDest(name));
|
|
26736
|
+
fs41.mkdirSync(path59.dirname(target), { recursive: true });
|
|
26737
|
+
fs41.writeFileSync(target, commandToSkill(name, content));
|
|
26738
|
+
}
|
|
26739
|
+
const agentsTarget = path59.join(codex.homeDir, codex.sync.agentsFile);
|
|
26740
|
+
fs41.mkdirSync(path59.dirname(agentsTarget), { recursive: true });
|
|
26741
|
+
fs41.copyFileSync(path59.join(claudeDir, "CLAUDE.md"), agentsTarget);
|
|
26742
|
+
syncCodexHooks(path59.join(claudeDir, "..", "codex", "config.toml"));
|
|
26624
26743
|
console.log(
|
|
26625
26744
|
`Synced ${files.length} skill(s) to ~/.codex/skills and CLAUDE.md to ~/.codex/AGENTS.md`
|
|
26626
26745
|
);
|
|
26627
26746
|
}
|
|
26628
26747
|
|
|
26629
26748
|
// src/commands/sync/syncDesign.ts
|
|
26630
|
-
import * as
|
|
26631
|
-
import * as
|
|
26749
|
+
import * as fs42 from "fs";
|
|
26750
|
+
import * as path60 from "path";
|
|
26632
26751
|
function syncDesign(claudeDir, targetBase) {
|
|
26633
|
-
const systemPromptSource =
|
|
26634
|
-
const systemPromptTarget =
|
|
26635
|
-
|
|
26752
|
+
const systemPromptSource = path60.join(claudeDir, "system-prompt.md");
|
|
26753
|
+
const systemPromptTarget = path60.join(targetBase, "system-prompt.md");
|
|
26754
|
+
fs42.copyFileSync(systemPromptSource, systemPromptTarget);
|
|
26636
26755
|
console.log("Copied system-prompt.md to ~/.claude/system-prompt.md");
|
|
26637
|
-
const skillsSource =
|
|
26638
|
-
const skillsTarget =
|
|
26639
|
-
|
|
26640
|
-
const files =
|
|
26756
|
+
const skillsSource = path60.join(claudeDir, "skills");
|
|
26757
|
+
const skillsTarget = path60.join(targetBase, "skills");
|
|
26758
|
+
fs42.mkdirSync(skillsTarget, { recursive: true });
|
|
26759
|
+
const files = fs42.readdirSync(skillsSource);
|
|
26641
26760
|
for (const file of files) {
|
|
26642
|
-
|
|
26643
|
-
|
|
26644
|
-
|
|
26761
|
+
fs42.copyFileSync(
|
|
26762
|
+
path60.join(skillsSource, file),
|
|
26763
|
+
path60.join(skillsTarget, file)
|
|
26645
26764
|
);
|
|
26646
26765
|
}
|
|
26647
26766
|
console.log(`Synced ${files.length} design skill(s) to ~/.claude/skills`);
|
|
26648
26767
|
}
|
|
26649
26768
|
|
|
26650
26769
|
// src/commands/sync/syncSettings.ts
|
|
26651
|
-
import * as
|
|
26652
|
-
import * as
|
|
26770
|
+
import * as fs43 from "fs";
|
|
26771
|
+
import * as path61 from "path";
|
|
26653
26772
|
import chalk200 from "chalk";
|
|
26654
26773
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
26655
|
-
const source =
|
|
26656
|
-
const target =
|
|
26657
|
-
const sourceContent =
|
|
26774
|
+
const source = path61.join(claudeDir, "settings.json");
|
|
26775
|
+
const target = path61.join(targetBase, "settings.json");
|
|
26776
|
+
const sourceContent = fs43.readFileSync(source, "utf8");
|
|
26658
26777
|
const sourceSettings = JSON.parse(sourceContent);
|
|
26659
|
-
const targetExists =
|
|
26660
|
-
const targetContent = targetExists ?
|
|
26778
|
+
const targetExists = fs43.existsSync(target);
|
|
26779
|
+
const targetContent = targetExists ? fs43.readFileSync(target, "utf8") : "";
|
|
26661
26780
|
const preservedUserSettings = targetExists ? JSON.parse(targetContent) : {};
|
|
26662
26781
|
const mergedContent = JSON.stringify(
|
|
26663
26782
|
{ ...preservedUserSettings, ...sourceSettings },
|
|
@@ -26686,18 +26805,18 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
26686
26805
|
}
|
|
26687
26806
|
}
|
|
26688
26807
|
}
|
|
26689
|
-
|
|
26808
|
+
fs43.writeFileSync(target, mergedContent);
|
|
26690
26809
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
26691
26810
|
}
|
|
26692
26811
|
|
|
26693
26812
|
// src/commands/sync.ts
|
|
26694
26813
|
var __filename5 = fileURLToPath9(import.meta.url);
|
|
26695
|
-
var __dirname7 =
|
|
26814
|
+
var __dirname7 = path62.dirname(__filename5);
|
|
26696
26815
|
async function sync(options2) {
|
|
26697
26816
|
const config = loadConfig();
|
|
26698
26817
|
const yes = options2?.yes ?? config.sync.autoConfirm;
|
|
26699
|
-
const claudeDir =
|
|
26700
|
-
const targetBase =
|
|
26818
|
+
const claudeDir = path62.join(__dirname7, "..", "claude");
|
|
26819
|
+
const targetBase = path62.join(os3.homedir(), ".claude");
|
|
26701
26820
|
syncCommands(claudeDir, targetBase);
|
|
26702
26821
|
syncDesign(claudeDir, targetBase);
|
|
26703
26822
|
await syncSettings(claudeDir, targetBase, { yes });
|
|
@@ -26705,12 +26824,12 @@ async function sync(options2) {
|
|
|
26705
26824
|
syncCodex(claudeDir);
|
|
26706
26825
|
}
|
|
26707
26826
|
function syncCommands(claudeDir, targetBase) {
|
|
26708
|
-
const sourceDir =
|
|
26709
|
-
const targetDir =
|
|
26710
|
-
|
|
26711
|
-
const files =
|
|
26827
|
+
const sourceDir = path62.join(claudeDir, "commands");
|
|
26828
|
+
const targetDir = path62.join(targetBase, "commands");
|
|
26829
|
+
fs44.mkdirSync(targetDir, { recursive: true });
|
|
26830
|
+
const files = fs44.readdirSync(sourceDir);
|
|
26712
26831
|
for (const file of files) {
|
|
26713
|
-
|
|
26832
|
+
fs44.copyFileSync(path62.join(sourceDir, file), path62.join(targetDir, file));
|
|
26714
26833
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
26715
26834
|
}
|
|
26716
26835
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -26718,7 +26837,7 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
26718
26837
|
|
|
26719
26838
|
// src/commands/update.ts
|
|
26720
26839
|
import { execSync as execSync57 } from "child_process";
|
|
26721
|
-
import * as
|
|
26840
|
+
import * as path63 from "path";
|
|
26722
26841
|
|
|
26723
26842
|
// src/commands/restartDaemonAfterUpdate.ts
|
|
26724
26843
|
async function restartDaemonAfterUpdate() {
|
|
@@ -26737,12 +26856,12 @@ async function restartDaemonAfterUpdate() {
|
|
|
26737
26856
|
// src/commands/update.ts
|
|
26738
26857
|
function isGlobalNpmInstall(dir) {
|
|
26739
26858
|
try {
|
|
26740
|
-
const resolved =
|
|
26741
|
-
if (resolved.split(
|
|
26859
|
+
const resolved = path63.resolve(dir);
|
|
26860
|
+
if (resolved.split(path63.sep).includes("node_modules")) {
|
|
26742
26861
|
return true;
|
|
26743
26862
|
}
|
|
26744
26863
|
const globalPrefix = execSync57("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
26745
|
-
return resolved.toLowerCase().startsWith(
|
|
26864
|
+
return resolved.toLowerCase().startsWith(path63.resolve(globalPrefix).toLowerCase());
|
|
26746
26865
|
} catch {
|
|
26747
26866
|
return false;
|
|
26748
26867
|
}
|
|
@@ -26788,7 +26907,7 @@ function reportCliError(error) {
|
|
|
26788
26907
|
var program = new Command();
|
|
26789
26908
|
program.name("assist").description("CLI application").version(package_default.version).option("--no-open", "Do not open a browser on startup").action((options2) => web({ port: "3100", open: options2.open }));
|
|
26790
26909
|
var syncCommand = program.command("sync").description(
|
|
26791
|
-
"Copy command files to ~/.claude/commands; when codex is detected, also install commands as ~/.codex/skills/<name>/SKILL.md
|
|
26910
|
+
"Copy command files to ~/.claude/commands; when codex is detected, also install commands as ~/.codex/skills/<name>/SKILL.md, CLAUDE.md as ~/.codex/AGENTS.md, and register the assist codex-hook auto-approval hook in ~/.codex/config.toml"
|
|
26792
26911
|
).option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
|
|
26793
26912
|
configHelp(syncCommand, rootConfigHelp.sync);
|
|
26794
26913
|
program.command("init").description("Initialize VS Code and verify configurations").action(init5);
|
|
@@ -26815,6 +26934,7 @@ registerBackup(program);
|
|
|
26815
26934
|
registerDb(program);
|
|
26816
26935
|
registerCliHook(program);
|
|
26817
26936
|
registerCodeComment(program);
|
|
26937
|
+
registerCodexHook(program);
|
|
26818
26938
|
registerEditHook(program);
|
|
26819
26939
|
registerGithub(program);
|
|
26820
26940
|
registerHandover(program);
|