@staff0rd/assist 0.392.0 → 0.394.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/commands/sessions/web/bundle.js +77 -77
- package/dist/index.js +326 -180
- package/package.json +2 -1
- package/pi/permission-gate.ts +46 -0
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.394.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -18,6 +18,7 @@ var package_default = {
|
|
|
18
18
|
"dist",
|
|
19
19
|
"claude",
|
|
20
20
|
"codex",
|
|
21
|
+
"pi",
|
|
21
22
|
"allowed.cli-reads",
|
|
22
23
|
"allowed.cli-writes"
|
|
23
24
|
],
|
|
@@ -141,10 +142,10 @@ import { stringify as stringifyYaml } from "yaml";
|
|
|
141
142
|
// src/shared/loadRawYaml.ts
|
|
142
143
|
import { existsSync, readFileSync } from "fs";
|
|
143
144
|
import { parse as parseYaml } from "yaml";
|
|
144
|
-
function loadRawYaml(
|
|
145
|
-
if (!existsSync(
|
|
145
|
+
function loadRawYaml(path67) {
|
|
146
|
+
if (!existsSync(path67)) return {};
|
|
146
147
|
try {
|
|
147
|
-
const content = readFileSync(
|
|
148
|
+
const content = readFileSync(path67, "utf8");
|
|
148
149
|
return parseYaml(content) || {};
|
|
149
150
|
} catch {
|
|
150
151
|
return {};
|
|
@@ -344,8 +345,9 @@ var assistConfigSchema = z2.strictObject({
|
|
|
344
345
|
autoConfirm: z2.boolean().default(false)
|
|
345
346
|
}).default({ autoConfirm: false }),
|
|
346
347
|
harness: z2.strictObject({
|
|
347
|
-
engine: z2.enum(["claude", "codex"]).default("claude"),
|
|
348
|
-
exposeCodexActions: z2.boolean().optional()
|
|
348
|
+
engine: z2.enum(["claude", "codex", "pi"]).default("claude"),
|
|
349
|
+
exposeCodexActions: z2.boolean().optional(),
|
|
350
|
+
exposePiActions: z2.boolean().optional()
|
|
349
351
|
}).default({ engine: "claude" }),
|
|
350
352
|
voice: z2.strictObject({
|
|
351
353
|
wakeWords: z2.array(z2.string()).default(DEFAULT_WAKE_WORDS),
|
|
@@ -1361,8 +1363,8 @@ function findUnmergedPaths() {
|
|
|
1361
1363
|
}
|
|
1362
1364
|
const found = /* @__PURE__ */ new Set();
|
|
1363
1365
|
for (const line of output.split("\n")) {
|
|
1364
|
-
const
|
|
1365
|
-
if (
|
|
1366
|
+
const path67 = line.split(" ")[1];
|
|
1367
|
+
if (path67) found.add(path67.trim());
|
|
1366
1368
|
}
|
|
1367
1369
|
return [...found];
|
|
1368
1370
|
}
|
|
@@ -1461,8 +1463,8 @@ function getPreferredRemoteRepo(cwd) {
|
|
|
1461
1463
|
function gitRefUrl(kind, ref, cwd) {
|
|
1462
1464
|
const repo = getPreferredRemoteRepo(cwd);
|
|
1463
1465
|
if (!repo) return void 0;
|
|
1464
|
-
const
|
|
1465
|
-
return `https://github.com/${repo.org}/${repo.repo}/${
|
|
1466
|
+
const path67 = kind === "branch" ? "tree" : "commit";
|
|
1467
|
+
return `https://github.com/${repo.org}/${repo.repo}/${path67}/${ref}`;
|
|
1466
1468
|
}
|
|
1467
1469
|
|
|
1468
1470
|
// src/commands/commit/collectCommitRefs.ts
|
|
@@ -3233,9 +3235,9 @@ import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
|
3233
3235
|
|
|
3234
3236
|
// src/commands/verify/forbiddenStrings/findForbiddenStrings.ts
|
|
3235
3237
|
import { minimatch as minimatch2 } from "minimatch";
|
|
3236
|
-
function resolveStringsAtPath(data,
|
|
3238
|
+
function resolveStringsAtPath(data, path67) {
|
|
3237
3239
|
let current = data;
|
|
3238
|
-
for (const segment of
|
|
3240
|
+
for (const segment of path67.split(".")) {
|
|
3239
3241
|
if (current === null || typeof current !== "object") return [];
|
|
3240
3242
|
current = current[segment];
|
|
3241
3243
|
}
|
|
@@ -3248,10 +3250,10 @@ function resolveStringsAtPath(data, path64) {
|
|
|
3248
3250
|
}
|
|
3249
3251
|
function findRuleViolations(data, rule) {
|
|
3250
3252
|
const violations = [];
|
|
3251
|
-
for (const
|
|
3252
|
-
for (const value of resolveStringsAtPath(data,
|
|
3253
|
+
for (const path67 of rule.paths) {
|
|
3254
|
+
for (const value of resolveStringsAtPath(data, path67)) {
|
|
3253
3255
|
if (minimatch2(value, rule.disallowed))
|
|
3254
|
-
violations.push({ file: rule.file, path:
|
|
3256
|
+
violations.push({ file: rule.file, path: path67, value });
|
|
3255
3257
|
}
|
|
3256
3258
|
}
|
|
3257
3259
|
return violations;
|
|
@@ -3290,8 +3292,8 @@ function forbiddenStrings() {
|
|
|
3290
3292
|
process.exit(0);
|
|
3291
3293
|
}
|
|
3292
3294
|
console.log("Forbidden strings found:\n");
|
|
3293
|
-
for (const { file, path:
|
|
3294
|
-
console.log(` ${file} ${
|
|
3295
|
+
for (const { file, path: path67, value } of violations) {
|
|
3296
|
+
console.log(` ${file} ${path67}: ${value}`);
|
|
3295
3297
|
}
|
|
3296
3298
|
console.log(`
|
|
3297
3299
|
Total: ${violations.length} forbidden string(s).`);
|
|
@@ -3583,15 +3585,15 @@ function readBaselineMigrations(repoRelativeDir, ref) {
|
|
|
3583
3585
|
} catch {
|
|
3584
3586
|
return baseline;
|
|
3585
3587
|
}
|
|
3586
|
-
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((
|
|
3587
|
-
for (const
|
|
3588
|
+
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path67) => MIGRATION_FILE3.test(basename(path67)));
|
|
3589
|
+
for (const path67 of paths) {
|
|
3588
3590
|
try {
|
|
3589
|
-
const content = execSync12(`git show "${ref}:${
|
|
3591
|
+
const content = execSync12(`git show "${ref}:${path67}"`, {
|
|
3590
3592
|
encoding: "utf8",
|
|
3591
3593
|
maxBuffer: 16 * 1024 * 1024,
|
|
3592
3594
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3593
3595
|
});
|
|
3594
|
-
baseline.set(basename(
|
|
3596
|
+
baseline.set(basename(path67), content);
|
|
3595
3597
|
} catch {
|
|
3596
3598
|
}
|
|
3597
3599
|
}
|
|
@@ -4956,15 +4958,15 @@ var hooksSettings = {
|
|
|
4956
4958
|
}
|
|
4957
4959
|
};
|
|
4958
4960
|
function ensureHooksSettings() {
|
|
4959
|
-
const
|
|
4960
|
-
mkdirSync5(dirname12(
|
|
4961
|
-
writeFileSync15(
|
|
4962
|
-
return
|
|
4961
|
+
const path67 = daemonPaths.hooksSettings;
|
|
4962
|
+
mkdirSync5(dirname12(path67), { recursive: true });
|
|
4963
|
+
writeFileSync15(path67, JSON.stringify(hooksSettings, null, 2));
|
|
4964
|
+
return path67;
|
|
4963
4965
|
}
|
|
4964
4966
|
|
|
4965
4967
|
// src/shared/spawnInherit.ts
|
|
4966
4968
|
import { spawn as spawn3 } from "child_process";
|
|
4967
|
-
function spawnInherit(command, args) {
|
|
4969
|
+
function spawnInherit(command, args, options2 = {}) {
|
|
4968
4970
|
const {
|
|
4969
4971
|
ASSIST_ACTIVITY_ID: _activityId,
|
|
4970
4972
|
CLAUDE_CODE_CHILD_SESSION: _childSession,
|
|
@@ -4972,7 +4974,8 @@ function spawnInherit(command, args) {
|
|
|
4972
4974
|
} = process.env;
|
|
4973
4975
|
const child = spawn3(command, args, {
|
|
4974
4976
|
stdio: "inherit",
|
|
4975
|
-
env
|
|
4977
|
+
env,
|
|
4978
|
+
cwd: options2.cwd
|
|
4976
4979
|
});
|
|
4977
4980
|
const done2 = new Promise((resolve18, reject) => {
|
|
4978
4981
|
child.on("close", (code) => resolve18(code ?? 0));
|
|
@@ -5223,9 +5226,9 @@ var LOCAL_FILES = ["backlog.jsonl", "backlog.db"];
|
|
|
5223
5226
|
function backupLocalBacklogFiles(dir) {
|
|
5224
5227
|
const moved = [];
|
|
5225
5228
|
for (const name of LOCAL_FILES) {
|
|
5226
|
-
const
|
|
5227
|
-
if (existsSync18(
|
|
5228
|
-
renameSync(
|
|
5229
|
+
const path67 = join15(dir, ".assist", name);
|
|
5230
|
+
if (existsSync18(path67)) {
|
|
5231
|
+
renameSync(path67, `${path67}.bak`);
|
|
5229
5232
|
moved.push(`${name} \u2192 ${name}.bak`);
|
|
5230
5233
|
}
|
|
5231
5234
|
}
|
|
@@ -5664,8 +5667,8 @@ var backlogItemSchema = z3.strictObject({
|
|
|
5664
5667
|
var backlogFileSchema = z3.array(backlogItemSchema);
|
|
5665
5668
|
|
|
5666
5669
|
// src/commands/backlog/parseBacklogJsonl.ts
|
|
5667
|
-
function parseBacklogJsonl(
|
|
5668
|
-
const content = readFileSync14(
|
|
5670
|
+
function parseBacklogJsonl(path67) {
|
|
5671
|
+
const content = readFileSync14(path67, "utf8").trim();
|
|
5669
5672
|
if (content.length === 0) return [];
|
|
5670
5673
|
return content.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => backlogItemSchema.parse(JSON.parse(line)));
|
|
5671
5674
|
}
|
|
@@ -5747,8 +5750,8 @@ function findBacklogUp(startDir) {
|
|
|
5747
5750
|
|
|
5748
5751
|
// src/commands/backlog/getCurrentOrigin.ts
|
|
5749
5752
|
import { execFileSync } from "child_process";
|
|
5750
|
-
function stripLeadingSlashes(
|
|
5751
|
-
return
|
|
5753
|
+
function stripLeadingSlashes(path67) {
|
|
5754
|
+
return path67.replace(/^\/+/, "");
|
|
5752
5755
|
}
|
|
5753
5756
|
function normalizeOrigin(raw) {
|
|
5754
5757
|
const trimmed = raw.trim().replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
@@ -6288,24 +6291,24 @@ function getOwnerPath(itemId2) {
|
|
|
6288
6291
|
function recordSignalOwner(itemId2) {
|
|
6289
6292
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
6290
6293
|
if (!sessionId) return;
|
|
6291
|
-
const
|
|
6292
|
-
mkdirSync7(dirname14(
|
|
6293
|
-
writeFileSync17(
|
|
6294
|
+
const path67 = getOwnerPath(itemId2);
|
|
6295
|
+
mkdirSync7(dirname14(path67), { recursive: true });
|
|
6296
|
+
writeFileSync17(path67, JSON.stringify({ sessionId }));
|
|
6294
6297
|
}
|
|
6295
6298
|
function readSignalOwner(itemId2) {
|
|
6296
|
-
const
|
|
6297
|
-
if (!existsSync21(
|
|
6299
|
+
const path67 = getOwnerPath(itemId2);
|
|
6300
|
+
if (!existsSync21(path67)) return void 0;
|
|
6298
6301
|
try {
|
|
6299
|
-
const parsed = JSON.parse(readFileSync15(
|
|
6302
|
+
const parsed = JSON.parse(readFileSync15(path67, "utf8"));
|
|
6300
6303
|
return parsed.sessionId;
|
|
6301
6304
|
} catch {
|
|
6302
6305
|
return void 0;
|
|
6303
6306
|
}
|
|
6304
6307
|
}
|
|
6305
6308
|
function clearSignalOwner(itemId2) {
|
|
6306
|
-
const
|
|
6309
|
+
const path67 = getOwnerPath(itemId2);
|
|
6307
6310
|
try {
|
|
6308
|
-
rmSync(
|
|
6311
|
+
rmSync(path67);
|
|
6309
6312
|
} catch {
|
|
6310
6313
|
}
|
|
6311
6314
|
}
|
|
@@ -6342,19 +6345,19 @@ function resolveSignalTarget(event, data) {
|
|
|
6342
6345
|
function writeSignal(event, data) {
|
|
6343
6346
|
const target = resolveSignalTarget(event, data);
|
|
6344
6347
|
if (!target) return;
|
|
6345
|
-
const
|
|
6346
|
-
if (!
|
|
6348
|
+
const path67 = getSignalPath(target);
|
|
6349
|
+
if (!path67) return;
|
|
6347
6350
|
const signal = { event, sessionId: target, ...data };
|
|
6348
|
-
mkdirSync8(dirname15(
|
|
6349
|
-
writeFileSync18(
|
|
6351
|
+
mkdirSync8(dirname15(path67), { recursive: true });
|
|
6352
|
+
writeFileSync18(path67, JSON.stringify(signal));
|
|
6350
6353
|
}
|
|
6351
6354
|
|
|
6352
6355
|
// src/commands/backlog/readSignal.ts
|
|
6353
6356
|
function readSignal() {
|
|
6354
|
-
const
|
|
6355
|
-
if (!
|
|
6357
|
+
const path67 = getSignalPath();
|
|
6358
|
+
if (!path67 || !existsSync22(path67)) return void 0;
|
|
6356
6359
|
try {
|
|
6357
|
-
return JSON.parse(readFileSync16(
|
|
6360
|
+
return JSON.parse(readFileSync16(path67, "utf8"));
|
|
6358
6361
|
} catch {
|
|
6359
6362
|
return void 0;
|
|
6360
6363
|
}
|
|
@@ -6449,13 +6452,13 @@ function activityPath(sessionId) {
|
|
|
6449
6452
|
function emitActivity(activity2) {
|
|
6450
6453
|
const sessionId = process.env.ASSIST_ACTIVITY_ID;
|
|
6451
6454
|
if (!sessionId) return;
|
|
6452
|
-
const
|
|
6453
|
-
mkdirSync9(dirname16(
|
|
6454
|
-
writeFileSync19(
|
|
6455
|
+
const path67 = activityPath(sessionId);
|
|
6456
|
+
mkdirSync9(dirname16(path67), { recursive: true });
|
|
6457
|
+
writeFileSync19(path67, JSON.stringify({ ...activity2, startedAt: Date.now() }));
|
|
6455
6458
|
}
|
|
6456
|
-
function readActivity(
|
|
6459
|
+
function readActivity(path67) {
|
|
6457
6460
|
try {
|
|
6458
|
-
return JSON.parse(readFileSync17(
|
|
6461
|
+
return JSON.parse(readFileSync17(path67, "utf8"));
|
|
6459
6462
|
} catch {
|
|
6460
6463
|
return void 0;
|
|
6461
6464
|
}
|
|
@@ -6465,9 +6468,9 @@ function reconcileActivity(sessionId, activity2) {
|
|
|
6465
6468
|
removeActivity(sessionId);
|
|
6466
6469
|
return;
|
|
6467
6470
|
}
|
|
6468
|
-
const
|
|
6469
|
-
mkdirSync9(dirname16(
|
|
6470
|
-
writeFileSync19(
|
|
6471
|
+
const path67 = activityPath(sessionId);
|
|
6472
|
+
mkdirSync9(dirname16(path67), { recursive: true });
|
|
6473
|
+
writeFileSync19(path67, JSON.stringify(activity2));
|
|
6471
6474
|
}
|
|
6472
6475
|
function removeActivity(sessionId) {
|
|
6473
6476
|
try {
|
|
@@ -7698,8 +7701,8 @@ async function getBacklogExists(req, res) {
|
|
|
7698
7701
|
// src/commands/backlog/originDisplayName.ts
|
|
7699
7702
|
function originDisplayName(origin) {
|
|
7700
7703
|
if (origin.startsWith("local:")) {
|
|
7701
|
-
const
|
|
7702
|
-
const segments =
|
|
7704
|
+
const path67 = origin.slice("local:".length).replace(/\/+$/, "");
|
|
7705
|
+
const segments = path67.split("/").filter(Boolean);
|
|
7703
7706
|
return segments[segments.length - 1] ?? origin;
|
|
7704
7707
|
}
|
|
7705
7708
|
const firstSlash = origin.indexOf("/");
|
|
@@ -7785,14 +7788,26 @@ async function updateStarred(orm, id, starred) {
|
|
|
7785
7788
|
return row?.name;
|
|
7786
7789
|
}
|
|
7787
7790
|
|
|
7791
|
+
// src/commands/backlog/web/parseBacklogFilter.ts
|
|
7792
|
+
var validFilters = /* @__PURE__ */ new Set(["todo", "done", "all"]);
|
|
7793
|
+
function parseBacklogFilter(value) {
|
|
7794
|
+
return value && validFilters.has(value) ? value : "todo";
|
|
7795
|
+
}
|
|
7796
|
+
|
|
7788
7797
|
// src/commands/backlog/web/loadVisibleItems.ts
|
|
7789
|
-
var
|
|
7798
|
+
var doneStatuses = /* @__PURE__ */ new Set(["done", "wontdo"]);
|
|
7799
|
+
var todoStatuses = /* @__PURE__ */ new Set(["todo", "in-progress"]);
|
|
7800
|
+
function matchesFilter(status3, filter) {
|
|
7801
|
+
if (filter === "all") return true;
|
|
7802
|
+
if (filter === "done") return doneStatuses.has(status3);
|
|
7803
|
+
return todoStatuses.has(status3);
|
|
7804
|
+
}
|
|
7790
7805
|
async function loadVisibleItems(req) {
|
|
7791
7806
|
const params = new URL(req.url ?? "/", "http://localhost").searchParams;
|
|
7792
7807
|
const q = params.get("q");
|
|
7808
|
+
const filter = parseBacklogFilter(params.get("filter"));
|
|
7793
7809
|
const loaded = q ? await searchBacklogSummaries(q) : await loadBacklogSummaries();
|
|
7794
|
-
|
|
7795
|
-
return loaded.filter((item) => !completedStatuses2.has(item.status));
|
|
7810
|
+
return loaded.filter((item) => matchesFilter(item.status, filter));
|
|
7796
7811
|
}
|
|
7797
7812
|
|
|
7798
7813
|
// src/commands/backlog/web/parseStatusBody.ts
|
|
@@ -8090,7 +8105,7 @@ function findSynthesisForBranch(repoReviewsDir, branch2) {
|
|
|
8090
8105
|
const parent = dirname20(branchKeyPath);
|
|
8091
8106
|
const branchPrefix = basename5(branchKeyPath);
|
|
8092
8107
|
if (!existsSync25(parent)) return null;
|
|
8093
|
-
const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join23(parent, name, "synthesis.md")).filter((
|
|
8108
|
+
const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join23(parent, name, "synthesis.md")).filter((path67) => existsSync25(path67)).map((path67) => ({ path: path67, mtime: statSync2(path67).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
8094
8109
|
return synthesisFiles[0]?.path ?? null;
|
|
8095
8110
|
}
|
|
8096
8111
|
|
|
@@ -8144,12 +8159,12 @@ async function getReviewSynthesis(req, res) {
|
|
|
8144
8159
|
const cwd = getCwdParam(req, res);
|
|
8145
8160
|
if (!cwd) return;
|
|
8146
8161
|
try {
|
|
8147
|
-
const
|
|
8148
|
-
if (!
|
|
8162
|
+
const path67 = await resolveSynthesisPath(cwd);
|
|
8163
|
+
if (!path67) {
|
|
8149
8164
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
8150
8165
|
return;
|
|
8151
8166
|
}
|
|
8152
|
-
respondJson(res, 200, { synthesis: readFileSync19(
|
|
8167
|
+
respondJson(res, 200, { synthesis: readFileSync19(path67, "utf8") });
|
|
8153
8168
|
} catch {
|
|
8154
8169
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
8155
8170
|
}
|
|
@@ -8260,6 +8275,15 @@ var harnesses = {
|
|
|
8260
8275
|
agentsFile: "AGENTS.md",
|
|
8261
8276
|
commandDest: (name) => path25.join("skills", name, "SKILL.md")
|
|
8262
8277
|
}
|
|
8278
|
+
},
|
|
8279
|
+
pi: {
|
|
8280
|
+
kind: "pi",
|
|
8281
|
+
command: "pi",
|
|
8282
|
+
homeDir: path25.join(os2.homedir(), ".pi", "agent"),
|
|
8283
|
+
sync: {
|
|
8284
|
+
agentsFile: "AGENTS.md",
|
|
8285
|
+
commandDest: (name) => path25.join("prompts", `${name}.md`)
|
|
8286
|
+
}
|
|
8263
8287
|
}
|
|
8264
8288
|
};
|
|
8265
8289
|
function isHarnessAvailable(kind) {
|
|
@@ -8268,9 +8292,12 @@ function isHarnessAvailable(kind) {
|
|
|
8268
8292
|
|
|
8269
8293
|
// src/commands/sessions/web/harnessCapabilities.ts
|
|
8270
8294
|
function harnessCapabilities(_req, res) {
|
|
8271
|
-
const
|
|
8272
|
-
const
|
|
8273
|
-
|
|
8295
|
+
const config = loadConfig().harness;
|
|
8296
|
+
const codexForcedOff = config.exposeCodexActions === false;
|
|
8297
|
+
const exposeCodexActions = !codexForcedOff && isHarnessAvailable("codex");
|
|
8298
|
+
const piForcedOff = config.exposePiActions === false;
|
|
8299
|
+
const exposePiActions = !piForcedOff && isHarnessAvailable("pi");
|
|
8300
|
+
respondJson(res, 200, { exposeCodexActions, exposePiActions });
|
|
8274
8301
|
}
|
|
8275
8302
|
|
|
8276
8303
|
// src/shared/loadJson.ts
|
|
@@ -8284,10 +8311,10 @@ function getStorePath(filename) {
|
|
|
8284
8311
|
return join26(getStoreDir(), filename);
|
|
8285
8312
|
}
|
|
8286
8313
|
function loadJson(filename) {
|
|
8287
|
-
const
|
|
8288
|
-
if (existsSync26(
|
|
8314
|
+
const path67 = getStorePath(filename);
|
|
8315
|
+
if (existsSync26(path67)) {
|
|
8289
8316
|
try {
|
|
8290
|
-
return JSON.parse(readFileSync20(
|
|
8317
|
+
return JSON.parse(readFileSync20(path67, "utf8"));
|
|
8291
8318
|
} catch {
|
|
8292
8319
|
return {};
|
|
8293
8320
|
}
|
|
@@ -10080,11 +10107,20 @@ function spawnCodex(prompt, options2 = {}) {
|
|
|
10080
10107
|
return spawnInherit(harnesses.codex.command, ["-C", cwd, prompt]);
|
|
10081
10108
|
}
|
|
10082
10109
|
|
|
10110
|
+
// src/shared/spawnPi.ts
|
|
10111
|
+
function spawnPi(prompt, options2 = {}) {
|
|
10112
|
+
const cwd = options2.cwd ?? process.cwd();
|
|
10113
|
+
return spawnInherit(harnesses.pi.command, [prompt], { cwd });
|
|
10114
|
+
}
|
|
10115
|
+
|
|
10083
10116
|
// src/shared/spawnHarness.ts
|
|
10084
10117
|
function spawnHarness(harness, prompt, options2 = {}) {
|
|
10085
10118
|
if (harness === "codex") {
|
|
10086
10119
|
return spawnCodex(prompt, { cwd: options2.cwd });
|
|
10087
10120
|
}
|
|
10121
|
+
if (harness === "pi") {
|
|
10122
|
+
return spawnPi(prompt, { cwd: options2.cwd });
|
|
10123
|
+
}
|
|
10088
10124
|
return spawnClaude(prompt, {
|
|
10089
10125
|
allowEdits: true,
|
|
10090
10126
|
sessionId: options2.sessionId,
|
|
@@ -10249,7 +10285,7 @@ async function refine(id, options2) {
|
|
|
10249
10285
|
|
|
10250
10286
|
// src/commands/backlog/resolveHarness.ts
|
|
10251
10287
|
function resolveHarness(value) {
|
|
10252
|
-
if (value === "claude" || value === "codex") return value;
|
|
10288
|
+
if (value === "claude" || value === "codex" || value === "pi") return value;
|
|
10253
10289
|
return loadConfig().harness.engine;
|
|
10254
10290
|
}
|
|
10255
10291
|
|
|
@@ -10257,7 +10293,7 @@ function resolveHarness(value) {
|
|
|
10257
10293
|
function registerRefineCommand(cmd) {
|
|
10258
10294
|
cmd.command("refine").argument("[id]", "Backlog item ID").description("Alias for refine").option("--once", "Exit when the initial task completes").option(
|
|
10259
10295
|
"--harness <kind>",
|
|
10260
|
-
"Coding harness to launch (claude|codex); defaults to the configured harness.engine"
|
|
10296
|
+
"Coding harness to launch (claude|codex|pi); defaults to the configured harness.engine"
|
|
10261
10297
|
).action(
|
|
10262
10298
|
(id, opts) => refine(id, {
|
|
10263
10299
|
once: opts.once,
|
|
@@ -11531,9 +11567,9 @@ var __dirname4 = dirname21(__filename3);
|
|
|
11531
11567
|
function packageRoot() {
|
|
11532
11568
|
return __dirname4;
|
|
11533
11569
|
}
|
|
11534
|
-
function readLines(
|
|
11535
|
-
if (!existsSync27(
|
|
11536
|
-
return readFileSync23(
|
|
11570
|
+
function readLines(path67) {
|
|
11571
|
+
if (!existsSync27(path67)) return [];
|
|
11572
|
+
return readFileSync23(path67, "utf8").split("\n").filter((line) => line.trim() !== "");
|
|
11537
11573
|
}
|
|
11538
11574
|
var cachedReads;
|
|
11539
11575
|
var cachedWrites;
|
|
@@ -12025,14 +12061,14 @@ function showProgress(p, label2) {
|
|
|
12025
12061
|
const pct = Math.round(p.done / p.total * 100);
|
|
12026
12062
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
12027
12063
|
}
|
|
12028
|
-
async function resolveCommand(cli,
|
|
12029
|
-
showProgress(p,
|
|
12030
|
-
const subHelp = await runHelp([cli, ...
|
|
12064
|
+
async function resolveCommand(cli, path67, description, depth, p) {
|
|
12065
|
+
showProgress(p, path67.join(" "));
|
|
12066
|
+
const subHelp = await runHelp([cli, ...path67]);
|
|
12031
12067
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
12032
|
-
return [{ path:
|
|
12068
|
+
return [{ path: path67, description }];
|
|
12033
12069
|
}
|
|
12034
|
-
const children = await discoverAt(cli,
|
|
12035
|
-
return children.length > 0 ? children : [{ path:
|
|
12070
|
+
const children = await discoverAt(cli, path67, depth + 1, p);
|
|
12071
|
+
return children.length > 0 ? children : [{ path: path67, description }];
|
|
12036
12072
|
}
|
|
12037
12073
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
12038
12074
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -12180,9 +12216,9 @@ function logPath(cli) {
|
|
|
12180
12216
|
return join30(homedir16(), ".assist", `cli-discover-${safeName}.log`);
|
|
12181
12217
|
}
|
|
12182
12218
|
function readCache(cli) {
|
|
12183
|
-
const
|
|
12184
|
-
if (!existsSync29(
|
|
12185
|
-
return readFileSync25(
|
|
12219
|
+
const path67 = logPath(cli);
|
|
12220
|
+
if (!existsSync29(path67)) return void 0;
|
|
12221
|
+
return readFileSync25(path67, "utf8");
|
|
12186
12222
|
}
|
|
12187
12223
|
function writeCache(cli, output) {
|
|
12188
12224
|
const dir = join30(homedir16(), ".assist");
|
|
@@ -12354,9 +12390,9 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
12354
12390
|
}
|
|
12355
12391
|
const cutoff = Date.now() - STALE_AFTER_MS;
|
|
12356
12392
|
for (const entry of entries) {
|
|
12357
|
-
const
|
|
12393
|
+
const path67 = join32(dir, entry);
|
|
12358
12394
|
try {
|
|
12359
|
-
if (statSync3(
|
|
12395
|
+
if (statSync3(path67).mtimeMs < cutoff) unlinkSync7(path67);
|
|
12360
12396
|
} catch {
|
|
12361
12397
|
continue;
|
|
12362
12398
|
}
|
|
@@ -12366,10 +12402,10 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
12366
12402
|
// src/commands/codeComment/readPinState.ts
|
|
12367
12403
|
import { existsSync as existsSync30, readFileSync as readFileSync26 } from "fs";
|
|
12368
12404
|
function readPinState(pin) {
|
|
12369
|
-
const
|
|
12370
|
-
if (!existsSync30(
|
|
12405
|
+
const path67 = getPinStatePath(pin);
|
|
12406
|
+
if (!existsSync30(path67)) return void 0;
|
|
12371
12407
|
try {
|
|
12372
|
-
const state = JSON.parse(readFileSync26(
|
|
12408
|
+
const state = JSON.parse(readFileSync26(path67, "utf8"));
|
|
12373
12409
|
if (state.pin !== pin) return void 0;
|
|
12374
12410
|
return state;
|
|
12375
12411
|
} catch {
|
|
@@ -13194,8 +13230,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
13194
13230
|
}
|
|
13195
13231
|
return ensureObject(container, resolved);
|
|
13196
13232
|
}
|
|
13197
|
-
function setNestedValue(obj,
|
|
13198
|
-
const keys =
|
|
13233
|
+
function setNestedValue(obj, path67, value) {
|
|
13234
|
+
const keys = path67.split(".");
|
|
13199
13235
|
const result = { ...obj };
|
|
13200
13236
|
let current = result;
|
|
13201
13237
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -13275,9 +13311,9 @@ function isTraversable(value) {
|
|
|
13275
13311
|
function stepInto(current, key) {
|
|
13276
13312
|
return isTraversable(current) ? current[key] : void 0;
|
|
13277
13313
|
}
|
|
13278
|
-
function getNestedValue(obj,
|
|
13314
|
+
function getNestedValue(obj, path67) {
|
|
13279
13315
|
let current = obj;
|
|
13280
|
-
for (const key of
|
|
13316
|
+
for (const key of path67.split(".")) current = stepInto(current, key);
|
|
13281
13317
|
return current;
|
|
13282
13318
|
}
|
|
13283
13319
|
|
|
@@ -15416,17 +15452,22 @@ function registerJira(program2) {
|
|
|
15416
15452
|
}
|
|
15417
15453
|
|
|
15418
15454
|
// src/commands/backlog/registerRefineLaunch.ts
|
|
15419
|
-
var HARNESS_FLAG = "Coding harness to launch (claude|codex); defaults to the configured harness.engine";
|
|
15455
|
+
var HARNESS_FLAG = "Coding harness to launch (claude|codex|pi); defaults to the configured harness.engine";
|
|
15420
15456
|
var HARNESS_CONFIG_HELP = [
|
|
15421
15457
|
{
|
|
15422
15458
|
key: "harness.engine",
|
|
15423
|
-
setter: "assist config set harness.engine <claude|codex>",
|
|
15459
|
+
setter: "assist config set harness.engine <claude|codex|pi>",
|
|
15424
15460
|
note: "default coding harness launched by refine and other flows"
|
|
15425
15461
|
},
|
|
15426
15462
|
{
|
|
15427
15463
|
key: "harness.exposeCodexActions",
|
|
15428
15464
|
setter: "assist config set harness.exposeCodexActions <true|false>",
|
|
15429
15465
|
note: "force the web UI 'with Codex' actions off even when codex is on PATH"
|
|
15466
|
+
},
|
|
15467
|
+
{
|
|
15468
|
+
key: "harness.exposePiActions",
|
|
15469
|
+
setter: "assist config set harness.exposePiActions <true|false>",
|
|
15470
|
+
note: "force the web UI 'with pi' actions off even when pi is on PATH"
|
|
15430
15471
|
}
|
|
15431
15472
|
];
|
|
15432
15473
|
function runRefine(id, opts) {
|
|
@@ -15863,9 +15904,9 @@ function parseRscRows(flight) {
|
|
|
15863
15904
|
}
|
|
15864
15905
|
function makeRscResolver(rows) {
|
|
15865
15906
|
return (ref) => {
|
|
15866
|
-
const [id, ...
|
|
15907
|
+
const [id, ...path67] = ref.slice(1).replace(/^[L@]/, "").split(":");
|
|
15867
15908
|
let v = rows[id];
|
|
15868
|
-
for (const key of
|
|
15909
|
+
for (const key of path67) {
|
|
15869
15910
|
if (v == null || typeof v !== "object") return void 0;
|
|
15870
15911
|
v = v[key];
|
|
15871
15912
|
}
|
|
@@ -16342,6 +16383,43 @@ function registerNews(program2) {
|
|
|
16342
16383
|
newsCommand.command("add").description("Add an RSS feed URL").argument("<url>", "RSS feed URL").action(add2);
|
|
16343
16384
|
}
|
|
16344
16385
|
|
|
16386
|
+
// src/commands/piHook/index.ts
|
|
16387
|
+
var TOOL_MAP = {
|
|
16388
|
+
bash: "Bash",
|
|
16389
|
+
powershell: "PowerShell"
|
|
16390
|
+
};
|
|
16391
|
+
function parseInput2(raw) {
|
|
16392
|
+
try {
|
|
16393
|
+
const data = JSON.parse(raw);
|
|
16394
|
+
const command = data.command;
|
|
16395
|
+
if (typeof command !== "string" || !command.trim()) return void 0;
|
|
16396
|
+
const toolName = TOOL_MAP[(data.toolName ?? "bash").toLowerCase()];
|
|
16397
|
+
if (!toolName) return void 0;
|
|
16398
|
+
return { toolName, command: command.trim() };
|
|
16399
|
+
} catch {
|
|
16400
|
+
return void 0;
|
|
16401
|
+
}
|
|
16402
|
+
}
|
|
16403
|
+
async function piHook() {
|
|
16404
|
+
const input = parseInput2(await readStdin());
|
|
16405
|
+
if (!input) return;
|
|
16406
|
+
const decision = decideCommand(input.toolName, input.command);
|
|
16407
|
+
const output = decision ? {
|
|
16408
|
+
decision: decision.permissionDecision,
|
|
16409
|
+
reason: decision.permissionDecisionReason
|
|
16410
|
+
} : { decision: "gate" };
|
|
16411
|
+
console.log(JSON.stringify(output));
|
|
16412
|
+
}
|
|
16413
|
+
|
|
16414
|
+
// src/commands/registerPiHook.ts
|
|
16415
|
+
function registerPiHook(program2) {
|
|
16416
|
+
program2.command("pi-hook").description(
|
|
16417
|
+
"pi tool-call permission gate: reads pi's tool-call JSON from stdin and emits an allow/deny/gate decision, auto-approving read-only CLI commands via the shared cli-hook allowlist"
|
|
16418
|
+
).action(() => {
|
|
16419
|
+
piHook();
|
|
16420
|
+
});
|
|
16421
|
+
}
|
|
16422
|
+
|
|
16345
16423
|
// src/commands/prompts/printPromptsTable.ts
|
|
16346
16424
|
import chalk153 from "chalk";
|
|
16347
16425
|
function truncate(str, max) {
|
|
@@ -16512,15 +16590,15 @@ function postComment(vars) {
|
|
|
16512
16590
|
const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
|
|
16513
16591
|
assertThreadCreated(stdout);
|
|
16514
16592
|
}
|
|
16515
|
-
function comment2(
|
|
16593
|
+
function comment2(path67, line, body, startLine) {
|
|
16516
16594
|
validateBody(body);
|
|
16517
16595
|
validateLine(line);
|
|
16518
16596
|
if (startLine !== void 0) validateLine(startLine);
|
|
16519
16597
|
try {
|
|
16520
16598
|
const prId = getCurrentPrNodeId();
|
|
16521
|
-
postComment({ prId, body, path:
|
|
16599
|
+
postComment({ prId, body, path: path67, line, startLine });
|
|
16522
16600
|
const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
|
|
16523
|
-
console.log(`Added review comment on ${
|
|
16601
|
+
console.log(`Added review comment on ${path67}:${range}`);
|
|
16524
16602
|
} catch (error) {
|
|
16525
16603
|
if (isGhNotInstalled(error)) {
|
|
16526
16604
|
console.error("Error: GitHub CLI (gh) is not installed.");
|
|
@@ -17381,8 +17459,8 @@ function registerPrs(program2) {
|
|
|
17381
17459
|
prsCommand.command("reply <comment-id> <body>").description("Reply to a comment thread without resolving it").action((commentId, body) => {
|
|
17382
17460
|
reply(Number.parseInt(commentId, 10), body);
|
|
17383
17461
|
});
|
|
17384
|
-
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((
|
|
17385
|
-
comment2(
|
|
17462
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path67, line, body) => {
|
|
17463
|
+
comment2(path67, Number.parseInt(line, 10), body);
|
|
17386
17464
|
});
|
|
17387
17465
|
configHelp(prsCommand, prsConfigHelp);
|
|
17388
17466
|
}
|
|
@@ -17635,10 +17713,10 @@ function resolveOpSecret(reference) {
|
|
|
17635
17713
|
}
|
|
17636
17714
|
|
|
17637
17715
|
// src/commands/ravendb/ravenFetch.ts
|
|
17638
|
-
async function ravenFetch(connection,
|
|
17716
|
+
async function ravenFetch(connection, path67) {
|
|
17639
17717
|
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
17640
17718
|
let accessToken = await getAccessToken(apiKey);
|
|
17641
|
-
const url = `${connection.url}${
|
|
17719
|
+
const url = `${connection.url}${path67}`;
|
|
17642
17720
|
const headers = {
|
|
17643
17721
|
Authorization: `Bearer ${accessToken}`,
|
|
17644
17722
|
"Content-Type": "application/json"
|
|
@@ -17742,16 +17820,16 @@ import chalk166 from "chalk";
|
|
|
17742
17820
|
// src/commands/ravendb/buildQueryPath.ts
|
|
17743
17821
|
function buildQueryPath(opts) {
|
|
17744
17822
|
const db = encodeURIComponent(opts.db);
|
|
17745
|
-
let
|
|
17823
|
+
let path67;
|
|
17746
17824
|
if (opts.collection) {
|
|
17747
|
-
|
|
17825
|
+
path67 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
17748
17826
|
} else {
|
|
17749
|
-
|
|
17827
|
+
path67 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
17750
17828
|
}
|
|
17751
17829
|
if (opts.query) {
|
|
17752
|
-
|
|
17830
|
+
path67 += `&query=${encodeURIComponent(opts.query)}`;
|
|
17753
17831
|
}
|
|
17754
|
-
return
|
|
17832
|
+
return path67;
|
|
17755
17833
|
}
|
|
17756
17834
|
|
|
17757
17835
|
// src/commands/ravendb/fetchAllPages.ts
|
|
@@ -17760,7 +17838,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
17760
17838
|
let start3 = 0;
|
|
17761
17839
|
while (true) {
|
|
17762
17840
|
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
17763
|
-
const
|
|
17841
|
+
const path67 = buildQueryPath({
|
|
17764
17842
|
db: connection.database,
|
|
17765
17843
|
collection: opts.collection,
|
|
17766
17844
|
start: start3,
|
|
@@ -17768,7 +17846,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
17768
17846
|
sort: opts.sort,
|
|
17769
17847
|
query: opts.query
|
|
17770
17848
|
});
|
|
17771
|
-
const data = await ravenFetch(connection,
|
|
17849
|
+
const data = await ravenFetch(connection, path67);
|
|
17772
17850
|
const results = data.Results ?? [];
|
|
17773
17851
|
const totalResults = data.TotalResults ?? 0;
|
|
17774
17852
|
if (results.length === 0) break;
|
|
@@ -20156,8 +20234,8 @@ async function handlePostSynthesis(synthesisPath, options2) {
|
|
|
20156
20234
|
// src/commands/review/prepareReviewDir.ts
|
|
20157
20235
|
import { existsSync as existsSync41, mkdirSync as mkdirSync17, unlinkSync as unlinkSync14, writeFileSync as writeFileSync34 } from "fs";
|
|
20158
20236
|
function clearReviewFiles(paths) {
|
|
20159
|
-
for (const
|
|
20160
|
-
if (existsSync41(
|
|
20237
|
+
for (const path67 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
20238
|
+
if (existsSync41(path67)) unlinkSync14(path67);
|
|
20161
20239
|
}
|
|
20162
20240
|
}
|
|
20163
20241
|
function prepareReviewDir(paths, requestBody, force) {
|
|
@@ -21305,8 +21383,8 @@ import chalk187 from "chalk";
|
|
|
21305
21383
|
|
|
21306
21384
|
// src/commands/seq/fetchSeq.ts
|
|
21307
21385
|
import chalk184 from "chalk";
|
|
21308
|
-
async function fetchSeq(conn,
|
|
21309
|
-
const url = `${conn.url}${
|
|
21386
|
+
async function fetchSeq(conn, path67, params) {
|
|
21387
|
+
const url = `${conn.url}${path67}?${params}`;
|
|
21310
21388
|
const response = await fetch(url, {
|
|
21311
21389
|
headers: {
|
|
21312
21390
|
Accept: "application/json",
|
|
@@ -22793,9 +22871,9 @@ function findPortFile(roamDir) {
|
|
|
22793
22871
|
return void 0;
|
|
22794
22872
|
}
|
|
22795
22873
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
22796
|
-
const
|
|
22874
|
+
const path67 = join60(roamDir, name);
|
|
22797
22875
|
try {
|
|
22798
|
-
return { path:
|
|
22876
|
+
return { path: path67, mtimeMs: statSync8(path67).mtimeMs };
|
|
22799
22877
|
} catch {
|
|
22800
22878
|
return void 0;
|
|
22801
22879
|
}
|
|
@@ -23214,11 +23292,11 @@ function findLinkIndex() {
|
|
|
23214
23292
|
function parseLinkArgs() {
|
|
23215
23293
|
const idx = findLinkIndex();
|
|
23216
23294
|
if (idx === -1) return null;
|
|
23217
|
-
const
|
|
23295
|
+
const path67 = process.argv[idx + 1];
|
|
23218
23296
|
const rest = process.argv.slice(idx + 2);
|
|
23219
23297
|
const { value: prefix2 } = extractOption(rest, "--prefix");
|
|
23220
23298
|
if (!prefix2) return null;
|
|
23221
|
-
return { path:
|
|
23299
|
+
return { path: path67, prefix: prefix2 };
|
|
23222
23300
|
}
|
|
23223
23301
|
function hasDuplicateLink(runList, linkPath) {
|
|
23224
23302
|
return runList.some(
|
|
@@ -24498,8 +24576,8 @@ async function seedRunningMsFromUsage(session, notify2) {
|
|
|
24498
24576
|
var DEBOUNCE_MS = 50;
|
|
24499
24577
|
function watchActivity(session, notify2) {
|
|
24500
24578
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
24501
|
-
const
|
|
24502
|
-
const dir = dirname29(
|
|
24579
|
+
const path67 = activityPath(session.id);
|
|
24580
|
+
const dir = dirname29(path67);
|
|
24503
24581
|
try {
|
|
24504
24582
|
mkdirSync24(dir, { recursive: true });
|
|
24505
24583
|
} catch {
|
|
@@ -24509,7 +24587,7 @@ function watchActivity(session, notify2) {
|
|
|
24509
24587
|
let timer = null;
|
|
24510
24588
|
const read = () => {
|
|
24511
24589
|
timer = null;
|
|
24512
|
-
const activity2 = readActivity(
|
|
24590
|
+
const activity2 = readActivity(path67);
|
|
24513
24591
|
if (!activity2) return;
|
|
24514
24592
|
session.activity = activity2;
|
|
24515
24593
|
if (activity2.claudeSessionId)
|
|
@@ -24519,11 +24597,11 @@ function watchActivity(session, notify2) {
|
|
|
24519
24597
|
notify2();
|
|
24520
24598
|
};
|
|
24521
24599
|
session.activityWatcher = watch(dir, (_event, filename) => {
|
|
24522
|
-
if (filename && !
|
|
24600
|
+
if (filename && !path67.endsWith(filename)) return;
|
|
24523
24601
|
if (timer) clearTimeout(timer);
|
|
24524
24602
|
timer = setTimeout(read, DEBOUNCE_MS);
|
|
24525
24603
|
});
|
|
24526
|
-
if (existsSync54(
|
|
24604
|
+
if (existsSync54(path67)) read();
|
|
24527
24605
|
}
|
|
24528
24606
|
function refreshActivity(session) {
|
|
24529
24607
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
@@ -26612,9 +26690,9 @@ async function statusLine() {
|
|
|
26612
26690
|
}
|
|
26613
26691
|
|
|
26614
26692
|
// src/commands/sync.ts
|
|
26615
|
-
import * as
|
|
26693
|
+
import * as fs45 from "fs";
|
|
26616
26694
|
import * as os3 from "os";
|
|
26617
|
-
import * as
|
|
26695
|
+
import * as path65 from "path";
|
|
26618
26696
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
26619
26697
|
|
|
26620
26698
|
// src/commands/sync/syncClaudeMd.ts
|
|
@@ -26648,12 +26726,33 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
26648
26726
|
}
|
|
26649
26727
|
|
|
26650
26728
|
// src/commands/sync/syncCodex.ts
|
|
26651
|
-
import * as
|
|
26652
|
-
import * as path59 from "path";
|
|
26729
|
+
import * as path60 from "path";
|
|
26653
26730
|
|
|
26654
|
-
// src/commands/sync/
|
|
26731
|
+
// src/commands/sync/installHarnessCommands.ts
|
|
26655
26732
|
import * as fs40 from "fs";
|
|
26656
26733
|
import * as path58 from "path";
|
|
26734
|
+
function installHarnessCommands(claudeDir, harness, transform) {
|
|
26735
|
+
const commandsSource = path58.join(claudeDir, "commands");
|
|
26736
|
+
const files = fs40.readdirSync(commandsSource);
|
|
26737
|
+
let synced = 0;
|
|
26738
|
+
for (const file of files) {
|
|
26739
|
+
if (!file.endsWith(".md")) continue;
|
|
26740
|
+
const name = file.replace(/\.md$/, "");
|
|
26741
|
+
const content = fs40.readFileSync(path58.join(commandsSource, file), "utf8");
|
|
26742
|
+
const target = path58.join(harness.homeDir, harness.sync.commandDest(name));
|
|
26743
|
+
fs40.mkdirSync(path58.dirname(target), { recursive: true });
|
|
26744
|
+
fs40.writeFileSync(target, transform(name, content));
|
|
26745
|
+
synced++;
|
|
26746
|
+
}
|
|
26747
|
+
const agentsTarget = path58.join(harness.homeDir, harness.sync.agentsFile);
|
|
26748
|
+
fs40.mkdirSync(path58.dirname(agentsTarget), { recursive: true });
|
|
26749
|
+
fs40.copyFileSync(path58.join(claudeDir, "CLAUDE.md"), agentsTarget);
|
|
26750
|
+
return { total: files.length, synced };
|
|
26751
|
+
}
|
|
26752
|
+
|
|
26753
|
+
// src/commands/sync/syncCodexHooks.ts
|
|
26754
|
+
import * as fs41 from "fs";
|
|
26755
|
+
import * as path59 from "path";
|
|
26657
26756
|
var BEGIN = "# >>> assist codex hooks (managed) \u2014 do not edit >>>";
|
|
26658
26757
|
var END = "# <<< assist codex hooks (managed) <<<";
|
|
26659
26758
|
function upsertManagedBlock(existing, body) {
|
|
@@ -26683,11 +26782,11 @@ ${rest}
|
|
|
26683
26782
|
`;
|
|
26684
26783
|
}
|
|
26685
26784
|
function syncCodexHooks(sourcePath) {
|
|
26686
|
-
const body =
|
|
26687
|
-
const configPath =
|
|
26688
|
-
const existing =
|
|
26689
|
-
|
|
26690
|
-
|
|
26785
|
+
const body = fs41.readFileSync(sourcePath, "utf8");
|
|
26786
|
+
const configPath = path59.join(harnesses.codex.homeDir, "config.toml");
|
|
26787
|
+
const existing = fs41.existsSync(configPath) ? fs41.readFileSync(configPath, "utf8") : "";
|
|
26788
|
+
fs41.mkdirSync(path59.dirname(configPath), { recursive: true });
|
|
26789
|
+
fs41.writeFileSync(configPath, upsertManagedBlock(existing, body));
|
|
26691
26790
|
console.log(
|
|
26692
26791
|
"Registered assist codex-hook in ~/.codex/config.toml (PreToolUse, PermissionRequest)"
|
|
26693
26792
|
);
|
|
@@ -26713,58 +26812,103 @@ description: ${quoteYaml(description)}
|
|
|
26713
26812
|
}
|
|
26714
26813
|
function syncCodex(claudeDir) {
|
|
26715
26814
|
if (!isHarnessAvailable("codex")) return;
|
|
26716
|
-
const
|
|
26717
|
-
|
|
26718
|
-
|
|
26719
|
-
|
|
26720
|
-
|
|
26721
|
-
|
|
26722
|
-
const content = fs41.readFileSync(path59.join(commandsSource, file), "utf8");
|
|
26723
|
-
const target = path59.join(codex.homeDir, codex.sync.commandDest(name));
|
|
26724
|
-
fs41.mkdirSync(path59.dirname(target), { recursive: true });
|
|
26725
|
-
fs41.writeFileSync(target, commandToSkill(name, content));
|
|
26726
|
-
}
|
|
26727
|
-
const agentsTarget = path59.join(codex.homeDir, codex.sync.agentsFile);
|
|
26728
|
-
fs41.mkdirSync(path59.dirname(agentsTarget), { recursive: true });
|
|
26729
|
-
fs41.copyFileSync(path59.join(claudeDir, "CLAUDE.md"), agentsTarget);
|
|
26730
|
-
syncCodexHooks(path59.join(claudeDir, "..", "codex", "config.toml"));
|
|
26815
|
+
const { total } = installHarnessCommands(
|
|
26816
|
+
claudeDir,
|
|
26817
|
+
harnesses.codex,
|
|
26818
|
+
commandToSkill
|
|
26819
|
+
);
|
|
26820
|
+
syncCodexHooks(path60.join(claudeDir, "..", "codex", "config.toml"));
|
|
26731
26821
|
console.log(
|
|
26732
|
-
`Synced ${
|
|
26822
|
+
`Synced ${total} skill(s) to ~/.codex/skills and CLAUDE.md to ~/.codex/AGENTS.md`
|
|
26733
26823
|
);
|
|
26734
26824
|
}
|
|
26735
26825
|
|
|
26736
26826
|
// src/commands/sync/syncDesign.ts
|
|
26737
26827
|
import * as fs42 from "fs";
|
|
26738
|
-
import * as
|
|
26828
|
+
import * as path61 from "path";
|
|
26739
26829
|
function syncDesign(claudeDir, targetBase) {
|
|
26740
|
-
const systemPromptSource =
|
|
26741
|
-
const systemPromptTarget =
|
|
26830
|
+
const systemPromptSource = path61.join(claudeDir, "system-prompt.md");
|
|
26831
|
+
const systemPromptTarget = path61.join(targetBase, "system-prompt.md");
|
|
26742
26832
|
fs42.copyFileSync(systemPromptSource, systemPromptTarget);
|
|
26743
26833
|
console.log("Copied system-prompt.md to ~/.claude/system-prompt.md");
|
|
26744
|
-
const skillsSource =
|
|
26745
|
-
const skillsTarget =
|
|
26834
|
+
const skillsSource = path61.join(claudeDir, "skills");
|
|
26835
|
+
const skillsTarget = path61.join(targetBase, "skills");
|
|
26746
26836
|
fs42.mkdirSync(skillsTarget, { recursive: true });
|
|
26747
26837
|
const files = fs42.readdirSync(skillsSource);
|
|
26748
26838
|
for (const file of files) {
|
|
26749
26839
|
fs42.copyFileSync(
|
|
26750
|
-
|
|
26751
|
-
|
|
26840
|
+
path61.join(skillsSource, file),
|
|
26841
|
+
path61.join(skillsTarget, file)
|
|
26752
26842
|
);
|
|
26753
26843
|
}
|
|
26754
26844
|
console.log(`Synced ${files.length} design skill(s) to ~/.claude/skills`);
|
|
26755
26845
|
}
|
|
26756
26846
|
|
|
26757
|
-
// src/commands/sync/
|
|
26847
|
+
// src/commands/sync/syncPi.ts
|
|
26848
|
+
import * as path63 from "path";
|
|
26849
|
+
|
|
26850
|
+
// src/commands/sync/syncPiHooks.ts
|
|
26758
26851
|
import * as fs43 from "fs";
|
|
26759
|
-
import * as
|
|
26852
|
+
import * as path62 from "path";
|
|
26853
|
+
var PI_PERMISSION_GATE_FILE = "assist-permission-gate.ts";
|
|
26854
|
+
function piPermissionGateTarget() {
|
|
26855
|
+
return path62.join(harnesses.pi.homeDir, "extensions", PI_PERMISSION_GATE_FILE);
|
|
26856
|
+
}
|
|
26857
|
+
function syncPiHooks(sourcePath) {
|
|
26858
|
+
const target = piPermissionGateTarget();
|
|
26859
|
+
fs43.mkdirSync(path62.dirname(target), { recursive: true });
|
|
26860
|
+
fs43.copyFileSync(sourcePath, target);
|
|
26861
|
+
console.log(
|
|
26862
|
+
"Registered assist permission-gate extension in ~/.pi/agent/extensions"
|
|
26863
|
+
);
|
|
26864
|
+
}
|
|
26865
|
+
|
|
26866
|
+
// src/commands/sync/syncPi.ts
|
|
26867
|
+
function unquote(value) {
|
|
26868
|
+
return value.trim().replace(/^["']|["']$/g, "");
|
|
26869
|
+
}
|
|
26870
|
+
function commandToPrompt(name, content) {
|
|
26871
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
26872
|
+
const frontmatter = match ? match[1] : "";
|
|
26873
|
+
const body = match ? content.slice(match[0].length) : content;
|
|
26874
|
+
const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
|
|
26875
|
+
const description = descriptionMatch ? unquote(descriptionMatch[1]) : name;
|
|
26876
|
+
const argsMatch = frontmatter.match(/^allowed_args:\s*(.*)$/m);
|
|
26877
|
+
const argumentHint = argsMatch ? unquote(argsMatch[1]) : void 0;
|
|
26878
|
+
const header = [
|
|
26879
|
+
"---",
|
|
26880
|
+
`description: ${description}`,
|
|
26881
|
+
...argumentHint ? [`argument-hint: ${argumentHint}`] : [],
|
|
26882
|
+
"---",
|
|
26883
|
+
"",
|
|
26884
|
+
""
|
|
26885
|
+
].join("\n");
|
|
26886
|
+
return header + body.replace(/^\r?\n+/, "");
|
|
26887
|
+
}
|
|
26888
|
+
function syncPi(claudeDir) {
|
|
26889
|
+
if (!isHarnessAvailable("pi")) return;
|
|
26890
|
+
const { synced } = installHarnessCommands(
|
|
26891
|
+
claudeDir,
|
|
26892
|
+
harnesses.pi,
|
|
26893
|
+
commandToPrompt
|
|
26894
|
+
);
|
|
26895
|
+
syncPiHooks(path63.join(claudeDir, "..", "pi", "permission-gate.ts"));
|
|
26896
|
+
console.log(
|
|
26897
|
+
`Synced ${synced} prompt(s) to ~/.pi/agent/prompts and CLAUDE.md to ~/.pi/agent/AGENTS.md`
|
|
26898
|
+
);
|
|
26899
|
+
}
|
|
26900
|
+
|
|
26901
|
+
// src/commands/sync/syncSettings.ts
|
|
26902
|
+
import * as fs44 from "fs";
|
|
26903
|
+
import * as path64 from "path";
|
|
26760
26904
|
import chalk200 from "chalk";
|
|
26761
26905
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
26762
|
-
const source =
|
|
26763
|
-
const target =
|
|
26764
|
-
const sourceContent =
|
|
26906
|
+
const source = path64.join(claudeDir, "settings.json");
|
|
26907
|
+
const target = path64.join(targetBase, "settings.json");
|
|
26908
|
+
const sourceContent = fs44.readFileSync(source, "utf8");
|
|
26765
26909
|
const sourceSettings = JSON.parse(sourceContent);
|
|
26766
|
-
const targetExists =
|
|
26767
|
-
const targetContent = targetExists ?
|
|
26910
|
+
const targetExists = fs44.existsSync(target);
|
|
26911
|
+
const targetContent = targetExists ? fs44.readFileSync(target, "utf8") : "";
|
|
26768
26912
|
const preservedUserSettings = targetExists ? JSON.parse(targetContent) : {};
|
|
26769
26913
|
const mergedContent = JSON.stringify(
|
|
26770
26914
|
{ ...preservedUserSettings, ...sourceSettings },
|
|
@@ -26793,31 +26937,32 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
26793
26937
|
}
|
|
26794
26938
|
}
|
|
26795
26939
|
}
|
|
26796
|
-
|
|
26940
|
+
fs44.writeFileSync(target, mergedContent);
|
|
26797
26941
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
26798
26942
|
}
|
|
26799
26943
|
|
|
26800
26944
|
// src/commands/sync.ts
|
|
26801
26945
|
var __filename5 = fileURLToPath9(import.meta.url);
|
|
26802
|
-
var __dirname7 =
|
|
26946
|
+
var __dirname7 = path65.dirname(__filename5);
|
|
26803
26947
|
async function sync(options2) {
|
|
26804
26948
|
const config = loadConfig();
|
|
26805
26949
|
const yes = options2?.yes ?? config.sync.autoConfirm;
|
|
26806
|
-
const claudeDir =
|
|
26807
|
-
const targetBase =
|
|
26950
|
+
const claudeDir = path65.join(__dirname7, "..", "claude");
|
|
26951
|
+
const targetBase = path65.join(os3.homedir(), ".claude");
|
|
26808
26952
|
syncCommands(claudeDir, targetBase);
|
|
26809
26953
|
syncDesign(claudeDir, targetBase);
|
|
26810
26954
|
await syncSettings(claudeDir, targetBase, { yes });
|
|
26811
26955
|
await syncClaudeMd(claudeDir, targetBase, { yes });
|
|
26812
26956
|
syncCodex(claudeDir);
|
|
26957
|
+
syncPi(claudeDir);
|
|
26813
26958
|
}
|
|
26814
26959
|
function syncCommands(claudeDir, targetBase) {
|
|
26815
|
-
const sourceDir =
|
|
26816
|
-
const targetDir =
|
|
26817
|
-
|
|
26818
|
-
const files =
|
|
26960
|
+
const sourceDir = path65.join(claudeDir, "commands");
|
|
26961
|
+
const targetDir = path65.join(targetBase, "commands");
|
|
26962
|
+
fs45.mkdirSync(targetDir, { recursive: true });
|
|
26963
|
+
const files = fs45.readdirSync(sourceDir);
|
|
26819
26964
|
for (const file of files) {
|
|
26820
|
-
|
|
26965
|
+
fs45.copyFileSync(path65.join(sourceDir, file), path65.join(targetDir, file));
|
|
26821
26966
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
26822
26967
|
}
|
|
26823
26968
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -26825,7 +26970,7 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
26825
26970
|
|
|
26826
26971
|
// src/commands/update.ts
|
|
26827
26972
|
import { execSync as execSync57 } from "child_process";
|
|
26828
|
-
import * as
|
|
26973
|
+
import * as path66 from "path";
|
|
26829
26974
|
|
|
26830
26975
|
// src/commands/restartDaemonAfterUpdate.ts
|
|
26831
26976
|
async function restartDaemonAfterUpdate() {
|
|
@@ -26844,12 +26989,12 @@ async function restartDaemonAfterUpdate() {
|
|
|
26844
26989
|
// src/commands/update.ts
|
|
26845
26990
|
function isGlobalNpmInstall(dir) {
|
|
26846
26991
|
try {
|
|
26847
|
-
const resolved =
|
|
26848
|
-
if (resolved.split(
|
|
26992
|
+
const resolved = path66.resolve(dir);
|
|
26993
|
+
if (resolved.split(path66.sep).includes("node_modules")) {
|
|
26849
26994
|
return true;
|
|
26850
26995
|
}
|
|
26851
26996
|
const globalPrefix = execSync57("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
26852
|
-
return resolved.toLowerCase().startsWith(
|
|
26997
|
+
return resolved.toLowerCase().startsWith(path66.resolve(globalPrefix).toLowerCase());
|
|
26853
26998
|
} catch {
|
|
26854
26999
|
return false;
|
|
26855
27000
|
}
|
|
@@ -26895,7 +27040,7 @@ function reportCliError(error) {
|
|
|
26895
27040
|
var program = new Command();
|
|
26896
27041
|
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 }));
|
|
26897
27042
|
var syncCommand = program.command("sync").description(
|
|
26898
|
-
"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"
|
|
27043
|
+
"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; when pi is detected, also install commands as ~/.pi/agent/prompts/<name>.md, CLAUDE.md as ~/.pi/agent/AGENTS.md, and register the assist pi-hook permission-gate extension in ~/.pi/agent/extensions"
|
|
26899
27044
|
).option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
|
|
26900
27045
|
configHelp(syncCommand, rootConfigHelp.sync);
|
|
26901
27046
|
program.command("init").description("Initialize VS Code and verify configurations").action(init5);
|
|
@@ -26923,6 +27068,7 @@ registerDb(program);
|
|
|
26923
27068
|
registerCliHook(program);
|
|
26924
27069
|
registerCodeComment(program);
|
|
26925
27070
|
registerCodexHook(program);
|
|
27071
|
+
registerPiHook(program);
|
|
26926
27072
|
registerEditHook(program);
|
|
26927
27073
|
registerGithub(program);
|
|
26928
27074
|
registerHandover(program);
|