@staff0rd/assist 0.533.3 → 0.535.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 +1 -1
- package/allowed.cli-writes +1 -0
- package/dist/allowed.cli-writes +1 -0
- package/dist/commands/sessions/web/bundle.js +385 -385
- package/dist/index.js +1002 -813
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.535.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -149,8 +149,8 @@ import { dirname as dirname2, join as join2 } from "path";
|
|
|
149
149
|
|
|
150
150
|
// src/commands/backlog/getCurrentOrigin.ts
|
|
151
151
|
import { execFileSync } from "child_process";
|
|
152
|
-
function stripLeadingSlashes(
|
|
153
|
-
return
|
|
152
|
+
function stripLeadingSlashes(path73) {
|
|
153
|
+
return path73.replace(/^\/+/, "");
|
|
154
154
|
}
|
|
155
155
|
function normalizeOrigin(raw) {
|
|
156
156
|
const trimmed = raw.trim().replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
@@ -225,9 +225,9 @@ function findGitLink(dir) {
|
|
|
225
225
|
}
|
|
226
226
|
return null;
|
|
227
227
|
}
|
|
228
|
-
function isFile(
|
|
228
|
+
function isFile(path73) {
|
|
229
229
|
try {
|
|
230
|
-
return statSync(
|
|
230
|
+
return statSync(path73).isFile();
|
|
231
231
|
} catch {
|
|
232
232
|
return false;
|
|
233
233
|
}
|
|
@@ -246,9 +246,9 @@ function linkedGitDirParent(gitDir) {
|
|
|
246
246
|
const match = /^(.*)[/\\]worktrees[/\\][^/\\]+[/\\]?$/.exec(gitDir);
|
|
247
247
|
return match ? match[1] : null;
|
|
248
248
|
}
|
|
249
|
-
function readTrimmed(
|
|
249
|
+
function readTrimmed(path73) {
|
|
250
250
|
try {
|
|
251
|
-
const content = readFileSync(
|
|
251
|
+
const content = readFileSync(path73, "utf8").trim();
|
|
252
252
|
return content === "" ? null : content;
|
|
253
253
|
} catch {
|
|
254
254
|
return null;
|
|
@@ -261,10 +261,10 @@ function absolute(target, from) {
|
|
|
261
261
|
// src/shared/loadRawYaml.ts
|
|
262
262
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
263
263
|
import { parse as parseYaml } from "yaml";
|
|
264
|
-
function loadRawYaml(
|
|
265
|
-
if (!existsSync2(
|
|
264
|
+
function loadRawYaml(path73) {
|
|
265
|
+
if (!existsSync2(path73)) return {};
|
|
266
266
|
try {
|
|
267
|
-
const content = readFileSync2(
|
|
267
|
+
const content = readFileSync2(path73, "utf8");
|
|
268
268
|
return parseYaml(content) || {};
|
|
269
269
|
} catch {
|
|
270
270
|
return {};
|
|
@@ -336,8 +336,8 @@ function mergeRawConfigs(globalRaw, projectRaw) {
|
|
|
336
336
|
// src/commands/backlog/originDisplayName.ts
|
|
337
337
|
function originDisplayName(origin) {
|
|
338
338
|
if (origin.startsWith("local:")) {
|
|
339
|
-
const
|
|
340
|
-
const segments =
|
|
339
|
+
const path73 = origin.slice("local:".length).replace(/\/+$/, "");
|
|
340
|
+
const segments = path73.split("/").filter(Boolean);
|
|
341
341
|
return segments[segments.length - 1] ?? origin;
|
|
342
342
|
}
|
|
343
343
|
const firstSlash = origin.indexOf("/");
|
|
@@ -1746,8 +1746,8 @@ function findUnmergedPaths() {
|
|
|
1746
1746
|
}
|
|
1747
1747
|
const found = /* @__PURE__ */ new Set();
|
|
1748
1748
|
for (const line of output.split("\n")) {
|
|
1749
|
-
const
|
|
1750
|
-
if (
|
|
1749
|
+
const path73 = line.split(" ")[1];
|
|
1750
|
+
if (path73) found.add(path73.trim());
|
|
1751
1751
|
}
|
|
1752
1752
|
return [...found];
|
|
1753
1753
|
}
|
|
@@ -1857,8 +1857,8 @@ function getPreferredRemoteRepo(cwd) {
|
|
|
1857
1857
|
function gitRefUrl(kind, ref, cwd) {
|
|
1858
1858
|
const repo = getPreferredRemoteRepo(cwd);
|
|
1859
1859
|
if (!repo) return void 0;
|
|
1860
|
-
const
|
|
1861
|
-
return `https://github.com/${repo.org}/${repo.repo}/${
|
|
1860
|
+
const path73 = kind === "branch" ? "tree" : "commit";
|
|
1861
|
+
return `https://github.com/${repo.org}/${repo.repo}/${path73}/${ref}`;
|
|
1862
1862
|
}
|
|
1863
1863
|
|
|
1864
1864
|
// src/commands/commit/collectCommitRefs.ts
|
|
@@ -3833,11 +3833,11 @@ function enumValues(node) {
|
|
|
3833
3833
|
function opaqueConfigNode(inner, base) {
|
|
3834
3834
|
return { ...base, kind: "other", type: leafTypeOf(inner) };
|
|
3835
3835
|
}
|
|
3836
|
-
function build(node,
|
|
3836
|
+
function build(node, path73) {
|
|
3837
3837
|
const { inner, defaultValue, optional } = unwrapSchemaNode(node);
|
|
3838
3838
|
const secret = isSecretSchemaNode(node) || isSecretSchemaNode(inner);
|
|
3839
3839
|
const base = {
|
|
3840
|
-
path:
|
|
3840
|
+
path: path73,
|
|
3841
3841
|
...optional ? { optional: true } : {},
|
|
3842
3842
|
...defaultValue === void 0 ? {} : { defaultValue },
|
|
3843
3843
|
...secret ? { secret: true } : {}
|
|
@@ -3856,9 +3856,9 @@ function segmentText(segment) {
|
|
|
3856
3856
|
if (segment.kind === "index") return `[${segment.index}]`;
|
|
3857
3857
|
return "[]";
|
|
3858
3858
|
}
|
|
3859
|
-
function formatConfigPath(
|
|
3859
|
+
function formatConfigPath(path73) {
|
|
3860
3860
|
let text17 = "";
|
|
3861
|
-
for (const segment of
|
|
3861
|
+
for (const segment of path73) {
|
|
3862
3862
|
const dotted = segment.kind === "key" || segment.kind === "entry";
|
|
3863
3863
|
const rendered = segmentText(segment);
|
|
3864
3864
|
text17 += dotted && text17 ? `.${rendered}` : rendered;
|
|
@@ -4471,9 +4471,9 @@ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
|
|
|
4471
4471
|
|
|
4472
4472
|
// src/commands/verify/forbiddenStrings/findForbiddenStrings.ts
|
|
4473
4473
|
import { minimatch as minimatch2 } from "minimatch";
|
|
4474
|
-
function resolveStringsAtPath(data,
|
|
4474
|
+
function resolveStringsAtPath(data, path73) {
|
|
4475
4475
|
let current = data;
|
|
4476
|
-
for (const segment of
|
|
4476
|
+
for (const segment of path73.split(".")) {
|
|
4477
4477
|
if (current === null || typeof current !== "object") return [];
|
|
4478
4478
|
current = current[segment];
|
|
4479
4479
|
}
|
|
@@ -4486,10 +4486,10 @@ function resolveStringsAtPath(data, path71) {
|
|
|
4486
4486
|
}
|
|
4487
4487
|
function findRuleViolations(data, rule) {
|
|
4488
4488
|
const violations = [];
|
|
4489
|
-
for (const
|
|
4490
|
-
for (const value of resolveStringsAtPath(data,
|
|
4489
|
+
for (const path73 of rule.paths) {
|
|
4490
|
+
for (const value of resolveStringsAtPath(data, path73)) {
|
|
4491
4491
|
if (minimatch2(value, rule.disallowed))
|
|
4492
|
-
violations.push({ file: rule.file, path:
|
|
4492
|
+
violations.push({ file: rule.file, path: path73, value });
|
|
4493
4493
|
}
|
|
4494
4494
|
}
|
|
4495
4495
|
return violations;
|
|
@@ -4528,8 +4528,8 @@ function forbiddenStrings() {
|
|
|
4528
4528
|
process.exit(0);
|
|
4529
4529
|
}
|
|
4530
4530
|
console.log("Forbidden strings found:\n");
|
|
4531
|
-
for (const { file, path:
|
|
4532
|
-
console.log(` ${file} ${
|
|
4531
|
+
for (const { file, path: path73, value } of violations) {
|
|
4532
|
+
console.log(` ${file} ${path73}: ${value}`);
|
|
4533
4533
|
}
|
|
4534
4534
|
console.log(`
|
|
4535
4535
|
Total: ${violations.length} forbidden string(s).`);
|
|
@@ -4844,15 +4844,15 @@ function readBaselineMigrations(repoRelativeDir, ref) {
|
|
|
4844
4844
|
} catch {
|
|
4845
4845
|
return baseline;
|
|
4846
4846
|
}
|
|
4847
|
-
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((
|
|
4848
|
-
for (const
|
|
4847
|
+
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path73) => MIGRATION_FILE3.test(basename2(path73)));
|
|
4848
|
+
for (const path73 of paths) {
|
|
4849
4849
|
try {
|
|
4850
|
-
const content = execSync14(`git show "${ref}:${
|
|
4850
|
+
const content = execSync14(`git show "${ref}:${path73}"`, {
|
|
4851
4851
|
encoding: "utf8",
|
|
4852
4852
|
maxBuffer: 16 * 1024 * 1024,
|
|
4853
4853
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4854
4854
|
});
|
|
4855
|
-
baseline.set(basename2(
|
|
4855
|
+
baseline.set(basename2(path73), content);
|
|
4856
4856
|
} catch {
|
|
4857
4857
|
}
|
|
4858
4858
|
}
|
|
@@ -6286,10 +6286,10 @@ var hooksSettings = {
|
|
|
6286
6286
|
}
|
|
6287
6287
|
};
|
|
6288
6288
|
function ensureHooksSettings() {
|
|
6289
|
-
const
|
|
6290
|
-
mkdirSync5(dirname13(
|
|
6291
|
-
writeFileSync15(
|
|
6292
|
-
return
|
|
6289
|
+
const path73 = daemonPaths.hooksSettings;
|
|
6290
|
+
mkdirSync5(dirname13(path73), { recursive: true });
|
|
6291
|
+
writeFileSync15(path73, JSON.stringify(hooksSettings, null, 2));
|
|
6292
|
+
return path73;
|
|
6293
6293
|
}
|
|
6294
6294
|
|
|
6295
6295
|
// src/shared/spawnInherit.ts
|
|
@@ -6587,9 +6587,9 @@ var LOCAL_FILES = ["backlog.jsonl", "backlog.db"];
|
|
|
6587
6587
|
function backupLocalBacklogFiles(dir) {
|
|
6588
6588
|
const moved = [];
|
|
6589
6589
|
for (const name of LOCAL_FILES) {
|
|
6590
|
-
const
|
|
6591
|
-
if (existsSync19(
|
|
6592
|
-
renameSync(
|
|
6590
|
+
const path73 = join15(dir, ".assist", name);
|
|
6591
|
+
if (existsSync19(path73)) {
|
|
6592
|
+
renameSync(path73, `${path73}.bak`);
|
|
6593
6593
|
moved.push(`${name} \u2192 ${name}.bak`);
|
|
6594
6594
|
}
|
|
6595
6595
|
}
|
|
@@ -7068,8 +7068,8 @@ var backlogItemSchema = z4.strictObject({
|
|
|
7068
7068
|
var backlogFileSchema = z4.array(backlogItemSchema);
|
|
7069
7069
|
|
|
7070
7070
|
// src/commands/backlog/parseBacklogJsonl.ts
|
|
7071
|
-
function parseBacklogJsonl(
|
|
7072
|
-
const content = readFileSync15(
|
|
7071
|
+
function parseBacklogJsonl(path73) {
|
|
7072
|
+
const content = readFileSync15(path73, "utf8").trim();
|
|
7073
7073
|
if (content.length === 0) return [];
|
|
7074
7074
|
return content.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => backlogItemSchema.parse(JSON.parse(line)));
|
|
7075
7075
|
}
|
|
@@ -7856,24 +7856,24 @@ function getOwnerPath(itemId2) {
|
|
|
7856
7856
|
function recordSignalOwner(itemId2) {
|
|
7857
7857
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
7858
7858
|
if (!sessionId) return;
|
|
7859
|
-
const
|
|
7860
|
-
mkdirSync7(dirname15(
|
|
7861
|
-
writeFileSync17(
|
|
7859
|
+
const path73 = getOwnerPath(itemId2);
|
|
7860
|
+
mkdirSync7(dirname15(path73), { recursive: true });
|
|
7861
|
+
writeFileSync17(path73, JSON.stringify({ sessionId }));
|
|
7862
7862
|
}
|
|
7863
7863
|
function readSignalOwner(itemId2) {
|
|
7864
|
-
const
|
|
7865
|
-
if (!existsSync23(
|
|
7864
|
+
const path73 = getOwnerPath(itemId2);
|
|
7865
|
+
if (!existsSync23(path73)) return void 0;
|
|
7866
7866
|
try {
|
|
7867
|
-
const parsed = JSON.parse(readFileSync16(
|
|
7867
|
+
const parsed = JSON.parse(readFileSync16(path73, "utf8"));
|
|
7868
7868
|
return parsed.sessionId;
|
|
7869
7869
|
} catch {
|
|
7870
7870
|
return void 0;
|
|
7871
7871
|
}
|
|
7872
7872
|
}
|
|
7873
7873
|
function clearSignalOwner(itemId2) {
|
|
7874
|
-
const
|
|
7874
|
+
const path73 = getOwnerPath(itemId2);
|
|
7875
7875
|
try {
|
|
7876
|
-
rmSync(
|
|
7876
|
+
rmSync(path73);
|
|
7877
7877
|
} catch {
|
|
7878
7878
|
}
|
|
7879
7879
|
}
|
|
@@ -7910,19 +7910,19 @@ function resolveSignalTarget(event, data) {
|
|
|
7910
7910
|
function writeSignal(event, data) {
|
|
7911
7911
|
const target = resolveSignalTarget(event, data);
|
|
7912
7912
|
if (!target) return;
|
|
7913
|
-
const
|
|
7914
|
-
if (!
|
|
7913
|
+
const path73 = getSignalPath(target);
|
|
7914
|
+
if (!path73) return;
|
|
7915
7915
|
const signal = { event, sessionId: target, ...data };
|
|
7916
|
-
mkdirSync8(dirname16(
|
|
7917
|
-
writeFileSync18(
|
|
7916
|
+
mkdirSync8(dirname16(path73), { recursive: true });
|
|
7917
|
+
writeFileSync18(path73, JSON.stringify(signal));
|
|
7918
7918
|
}
|
|
7919
7919
|
|
|
7920
7920
|
// src/commands/backlog/readSignal.ts
|
|
7921
7921
|
function readSignal() {
|
|
7922
|
-
const
|
|
7923
|
-
if (!
|
|
7922
|
+
const path73 = getSignalPath();
|
|
7923
|
+
if (!path73 || !existsSync24(path73)) return void 0;
|
|
7924
7924
|
try {
|
|
7925
|
-
return JSON.parse(readFileSync17(
|
|
7925
|
+
return JSON.parse(readFileSync17(path73, "utf8"));
|
|
7926
7926
|
} catch {
|
|
7927
7927
|
return void 0;
|
|
7928
7928
|
}
|
|
@@ -8119,13 +8119,13 @@ function activityPath(sessionId) {
|
|
|
8119
8119
|
function emitActivity(activity2) {
|
|
8120
8120
|
const sessionId = process.env.ASSIST_ACTIVITY_ID;
|
|
8121
8121
|
if (!sessionId) return;
|
|
8122
|
-
const
|
|
8123
|
-
mkdirSync9(dirname17(
|
|
8124
|
-
writeFileSync19(
|
|
8122
|
+
const path73 = activityPath(sessionId);
|
|
8123
|
+
mkdirSync9(dirname17(path73), { recursive: true });
|
|
8124
|
+
writeFileSync19(path73, JSON.stringify({ ...activity2, startedAt: Date.now() }));
|
|
8125
8125
|
}
|
|
8126
|
-
function readActivity(
|
|
8126
|
+
function readActivity(path73) {
|
|
8127
8127
|
try {
|
|
8128
|
-
return JSON.parse(readFileSync18(
|
|
8128
|
+
return JSON.parse(readFileSync18(path73, "utf8"));
|
|
8129
8129
|
} catch {
|
|
8130
8130
|
return void 0;
|
|
8131
8131
|
}
|
|
@@ -8135,9 +8135,9 @@ function reconcileActivity(sessionId, activity2) {
|
|
|
8135
8135
|
removeActivity(sessionId);
|
|
8136
8136
|
return;
|
|
8137
8137
|
}
|
|
8138
|
-
const
|
|
8139
|
-
mkdirSync9(dirname17(
|
|
8140
|
-
writeFileSync19(
|
|
8138
|
+
const path73 = activityPath(sessionId);
|
|
8139
|
+
mkdirSync9(dirname17(path73), { recursive: true });
|
|
8140
|
+
writeFileSync19(path73, JSON.stringify(activity2));
|
|
8141
8141
|
}
|
|
8142
8142
|
function removeActivity(sessionId) {
|
|
8143
8143
|
try {
|
|
@@ -8146,8 +8146,27 @@ function removeActivity(sessionId) {
|
|
|
8146
8146
|
}
|
|
8147
8147
|
}
|
|
8148
8148
|
|
|
8149
|
+
// src/shared/harnessLabel.ts
|
|
8150
|
+
var HARNESS_LABELS = {
|
|
8151
|
+
claude: "Claude",
|
|
8152
|
+
codex: "Codex",
|
|
8153
|
+
pi: "pi"
|
|
8154
|
+
};
|
|
8155
|
+
function resolveHarness(harness) {
|
|
8156
|
+
return harness ?? "claude";
|
|
8157
|
+
}
|
|
8158
|
+
function harnessLabel(harness) {
|
|
8159
|
+
return HARNESS_LABELS[resolveHarness(harness)];
|
|
8160
|
+
}
|
|
8161
|
+
|
|
8162
|
+
// src/shared/harnessActivityFields.ts
|
|
8163
|
+
function harnessActivityFields(harness, claudeSessionId) {
|
|
8164
|
+
const kind = resolveHarness(harness);
|
|
8165
|
+
return kind === "claude" ? { claudeSessionId } : { harness: kind };
|
|
8166
|
+
}
|
|
8167
|
+
|
|
8149
8168
|
// src/commands/backlog/reportPhaseActivity.ts
|
|
8150
|
-
function reportPhaseActivity(item, phaseNumber, totalPhases, phase, claudeSessionId) {
|
|
8169
|
+
function reportPhaseActivity(item, phaseNumber, totalPhases, phase, claudeSessionId, harness) {
|
|
8151
8170
|
const isReviewPhase = phaseNumber >= totalPhases;
|
|
8152
8171
|
emitActivity({
|
|
8153
8172
|
kind: "backlog",
|
|
@@ -8156,7 +8175,7 @@ function reportPhaseActivity(item, phaseNumber, totalPhases, phase, claudeSessio
|
|
|
8156
8175
|
phase: phaseNumber,
|
|
8157
8176
|
phaseName: isReviewPhase ? REVIEW_PHASE_NAME : phase.name,
|
|
8158
8177
|
totalPhases,
|
|
8159
|
-
claudeSessionId
|
|
8178
|
+
...harnessActivityFields(harness, claudeSessionId)
|
|
8160
8179
|
});
|
|
8161
8180
|
}
|
|
8162
8181
|
|
|
@@ -8405,7 +8424,14 @@ async function preparePhaseSession(item, phase, phaseIndex, phaseNumber, totalPh
|
|
|
8405
8424
|
if (resumeSessionId && !await verifyPhaseResume(item.id, resumeSessionId, phaseLabel2)) {
|
|
8406
8425
|
return void 0;
|
|
8407
8426
|
}
|
|
8408
|
-
reportPhaseActivity(
|
|
8427
|
+
reportPhaseActivity(
|
|
8428
|
+
item,
|
|
8429
|
+
phaseNumber,
|
|
8430
|
+
totalPhases,
|
|
8431
|
+
phase,
|
|
8432
|
+
claudeSessionId,
|
|
8433
|
+
spawnOptions?.harness
|
|
8434
|
+
);
|
|
8409
8435
|
if (!resumeSessionId) {
|
|
8410
8436
|
await persistPhaseSessionId(item.id, phaseIndex, claudeSessionId);
|
|
8411
8437
|
}
|
|
@@ -9380,10 +9406,10 @@ function getStorePath(filename) {
|
|
|
9380
9406
|
return join24(getStoreDir(), filename);
|
|
9381
9407
|
}
|
|
9382
9408
|
function loadJson(filename) {
|
|
9383
|
-
const
|
|
9384
|
-
if (existsSync27(
|
|
9409
|
+
const path73 = getStorePath(filename);
|
|
9410
|
+
if (existsSync27(path73)) {
|
|
9385
9411
|
try {
|
|
9386
|
-
return JSON.parse(readFileSync19(
|
|
9412
|
+
return JSON.parse(readFileSync19(path73, "utf8"));
|
|
9387
9413
|
} catch {
|
|
9388
9414
|
return {};
|
|
9389
9415
|
}
|
|
@@ -9402,22 +9428,22 @@ function saveJson(filename, data) {
|
|
|
9402
9428
|
var REGISTRY_FILE = "worktrees.json";
|
|
9403
9429
|
function readWorktreeRegistry() {
|
|
9404
9430
|
const data = loadJson(REGISTRY_FILE);
|
|
9405
|
-
return Object.entries(data).filter(([, record]) => !record.reaped).map(([
|
|
9431
|
+
return Object.entries(data).filter(([, record]) => !record.reaped).map(([path73, record]) => ({ path: path73, ...record }));
|
|
9406
9432
|
}
|
|
9407
|
-
function worktreeAttributionIncludingReaped(
|
|
9408
|
-
const record = loadJson(REGISTRY_FILE)[
|
|
9433
|
+
function worktreeAttributionIncludingReaped(path73) {
|
|
9434
|
+
const record = loadJson(REGISTRY_FILE)[path73];
|
|
9409
9435
|
return record ? { clone: record.clone, origin: record.origin } : void 0;
|
|
9410
9436
|
}
|
|
9411
|
-
function recordWorktree(
|
|
9437
|
+
function recordWorktree(path73, clone, origin) {
|
|
9412
9438
|
const data = loadJson(REGISTRY_FILE);
|
|
9413
|
-
data[
|
|
9439
|
+
data[path73] = { clone, origin };
|
|
9414
9440
|
saveJson(REGISTRY_FILE, data);
|
|
9415
9441
|
}
|
|
9416
|
-
function forgetWorktree(
|
|
9442
|
+
function forgetWorktree(path73) {
|
|
9417
9443
|
const data = loadJson(REGISTRY_FILE);
|
|
9418
|
-
const record = data[
|
|
9444
|
+
const record = data[path73];
|
|
9419
9445
|
if (!record || record.reaped) return;
|
|
9420
|
-
data[
|
|
9446
|
+
data[path73] = { ...record, reaped: true };
|
|
9421
9447
|
saveJson(REGISTRY_FILE, data);
|
|
9422
9448
|
}
|
|
9423
9449
|
|
|
@@ -10173,8 +10199,8 @@ async function loadCommittedPaths(cwd, sessionId) {
|
|
|
10173
10199
|
for (const commit2 of commits2) {
|
|
10174
10200
|
const resolved = await resolveCommit(cwd, commit2.sha);
|
|
10175
10201
|
if (!resolved) continue;
|
|
10176
|
-
for (const
|
|
10177
|
-
if (!bases.has(
|
|
10202
|
+
for (const path73 of resolved.paths) {
|
|
10203
|
+
if (!bases.has(path73)) bases.set(path73, resolved.base);
|
|
10178
10204
|
}
|
|
10179
10205
|
}
|
|
10180
10206
|
return { commits: commits2, bases };
|
|
@@ -10192,16 +10218,16 @@ async function itemChangeSet(cwd, sessionId) {
|
|
|
10192
10218
|
}
|
|
10193
10219
|
function groupByBase(bases) {
|
|
10194
10220
|
const groups = /* @__PURE__ */ new Map();
|
|
10195
|
-
for (const [
|
|
10221
|
+
for (const [path73, base] of bases) {
|
|
10196
10222
|
const paths = groups.get(base);
|
|
10197
|
-
if (paths) paths.push(
|
|
10198
|
-
else groups.set(base, [
|
|
10223
|
+
if (paths) paths.push(path73);
|
|
10224
|
+
else groups.set(base, [path73]);
|
|
10199
10225
|
}
|
|
10200
10226
|
return [...groups].map(([base, paths]) => ({ base, paths: paths.sort() }));
|
|
10201
10227
|
}
|
|
10202
10228
|
async function dirtyPaths(cwd, bases) {
|
|
10203
10229
|
const output = await execGit(cwd, ["diff", "--name-only", "HEAD"]);
|
|
10204
|
-
return output.split("\n").filter((
|
|
10230
|
+
return output.split("\n").filter((path73) => path73 && !bases.has(path73)).sort();
|
|
10205
10231
|
}
|
|
10206
10232
|
|
|
10207
10233
|
// src/commands/sessions/web/scopedDiff.ts
|
|
@@ -10210,8 +10236,8 @@ async function scopedDiff(cwd, session, scope) {
|
|
|
10210
10236
|
if (scope.kind === "commit") return commitDiff(cwd, scope.sha);
|
|
10211
10237
|
return await trackedScopeDiff(cwd, session, scope) + await untrackedDiff(cwd);
|
|
10212
10238
|
}
|
|
10213
|
-
async function untrackedFileDiff(cwd,
|
|
10214
|
-
return execGit(cwd, ["diff", "--no-index", "--", "/dev/null",
|
|
10239
|
+
async function untrackedFileDiff(cwd, path73) {
|
|
10240
|
+
return execGit(cwd, ["diff", "--no-index", "--", "/dev/null", path73], {
|
|
10215
10241
|
maxBuffer: MAX_DIFF_BYTES,
|
|
10216
10242
|
allowFailure: true
|
|
10217
10243
|
});
|
|
@@ -10224,7 +10250,7 @@ async function untrackedDiff(cwd) {
|
|
|
10224
10250
|
]);
|
|
10225
10251
|
const paths = list5.split("\n").filter(Boolean);
|
|
10226
10252
|
const diffs = await Promise.all(
|
|
10227
|
-
paths.map((
|
|
10253
|
+
paths.map((path73) => untrackedFileDiff(cwd, path73))
|
|
10228
10254
|
);
|
|
10229
10255
|
return diffs.join("");
|
|
10230
10256
|
}
|
|
@@ -10317,9 +10343,9 @@ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve10
|
|
|
10317
10343
|
function repoRoot(cwd) {
|
|
10318
10344
|
return resolve10(toGitCwd(cwd));
|
|
10319
10345
|
}
|
|
10320
|
-
function resolveWithinCwd(cwd,
|
|
10346
|
+
function resolveWithinCwd(cwd, path73) {
|
|
10321
10347
|
const root = repoRoot(cwd);
|
|
10322
|
-
const target = resolve10(root,
|
|
10348
|
+
const target = resolve10(root, path73);
|
|
10323
10349
|
const rel = relative2(root, target);
|
|
10324
10350
|
if (rel === "" || rel.startsWith("..") || isAbsolute2(rel)) return null;
|
|
10325
10351
|
return target;
|
|
@@ -10329,14 +10355,14 @@ function resolveWithinCwd(cwd, path71) {
|
|
|
10329
10355
|
function getFileTarget(req, res) {
|
|
10330
10356
|
const cwd = getCwdParam(req, res);
|
|
10331
10357
|
if (!cwd) return null;
|
|
10332
|
-
const
|
|
10358
|
+
const path73 = new URL(req.url ?? "/", "http://localhost").searchParams.get(
|
|
10333
10359
|
"path"
|
|
10334
10360
|
);
|
|
10335
|
-
if (!
|
|
10361
|
+
if (!path73) {
|
|
10336
10362
|
respondJson(res, 400, { error: "Missing path" });
|
|
10337
10363
|
return null;
|
|
10338
10364
|
}
|
|
10339
|
-
const target = resolveWithinCwd(cwd,
|
|
10365
|
+
const target = resolveWithinCwd(cwd, path73);
|
|
10340
10366
|
if (!target) {
|
|
10341
10367
|
respondJson(res, 400, { error: "Path outside cwd" });
|
|
10342
10368
|
return null;
|
|
@@ -10405,35 +10431,35 @@ function isPlainRecord(value) {
|
|
|
10405
10431
|
}
|
|
10406
10432
|
|
|
10407
10433
|
// src/shared/mapConfigSecrets.ts
|
|
10408
|
-
function mapChildren(value,
|
|
10434
|
+
function mapChildren(value, path73, childNode, map) {
|
|
10409
10435
|
if (!isPlainRecord(value)) return value;
|
|
10410
10436
|
return Object.fromEntries(
|
|
10411
10437
|
Object.entries(value).map(([name, child]) => [
|
|
10412
10438
|
name,
|
|
10413
|
-
walk(child, [...
|
|
10439
|
+
walk(child, [...path73, name], childNode(name), map)
|
|
10414
10440
|
])
|
|
10415
10441
|
);
|
|
10416
10442
|
}
|
|
10417
|
-
function mapItems(value,
|
|
10443
|
+
function mapItems(value, path73, item, map) {
|
|
10418
10444
|
if (!Array.isArray(value)) return value;
|
|
10419
|
-
return value.map((entry, index3) => walk(entry, [...
|
|
10445
|
+
return value.map((entry, index3) => walk(entry, [...path73, index3], item, map));
|
|
10420
10446
|
}
|
|
10421
|
-
function walk(value,
|
|
10447
|
+
function walk(value, path73, node, map) {
|
|
10422
10448
|
if (!node || value === void 0 || value === null) return value;
|
|
10423
|
-
if (node.secret) return map(value,
|
|
10449
|
+
if (node.secret) return map(value, path73);
|
|
10424
10450
|
switch (node.kind) {
|
|
10425
10451
|
case "object":
|
|
10426
10452
|
case "unionOfObjects":
|
|
10427
10453
|
return mapChildren(
|
|
10428
10454
|
value,
|
|
10429
|
-
|
|
10455
|
+
path73,
|
|
10430
10456
|
(name) => configNodeField(node, name),
|
|
10431
10457
|
map
|
|
10432
10458
|
);
|
|
10433
10459
|
case "objectList":
|
|
10434
|
-
return mapItems(value,
|
|
10460
|
+
return mapItems(value, path73, node.item, map);
|
|
10435
10461
|
case "record":
|
|
10436
|
-
return mapChildren(value,
|
|
10462
|
+
return mapChildren(value, path73, () => node.value, map);
|
|
10437
10463
|
default:
|
|
10438
10464
|
return value;
|
|
10439
10465
|
}
|
|
@@ -10465,9 +10491,9 @@ function isTraversable(value) {
|
|
|
10465
10491
|
function stepInto(current, key) {
|
|
10466
10492
|
return isTraversable(current) ? current[key] : void 0;
|
|
10467
10493
|
}
|
|
10468
|
-
function getNestedValue(obj,
|
|
10494
|
+
function getNestedValue(obj, path73) {
|
|
10469
10495
|
let current = obj;
|
|
10470
|
-
for (const key of
|
|
10496
|
+
for (const key of path73.split(".")) current = stepInto(current, key);
|
|
10471
10497
|
return current;
|
|
10472
10498
|
}
|
|
10473
10499
|
|
|
@@ -10552,9 +10578,9 @@ function step(node, segment) {
|
|
|
10552
10578
|
return void 0;
|
|
10553
10579
|
}
|
|
10554
10580
|
}
|
|
10555
|
-
function findConfigNode(root,
|
|
10581
|
+
function findConfigNode(root, path73) {
|
|
10556
10582
|
let current = root;
|
|
10557
|
-
for (const segment of
|
|
10583
|
+
for (const segment of path73) {
|
|
10558
10584
|
if (!current) return void 0;
|
|
10559
10585
|
current = step(current, segment);
|
|
10560
10586
|
}
|
|
@@ -10571,34 +10597,34 @@ function nameSegment(name) {
|
|
|
10571
10597
|
return name === RECORD_ENTRY_TOKEN ? { kind: "entry" } : { kind: "key", name };
|
|
10572
10598
|
}
|
|
10573
10599
|
function parseConfigPath(text17) {
|
|
10574
|
-
const
|
|
10600
|
+
const path73 = [];
|
|
10575
10601
|
let at2 = 0;
|
|
10576
10602
|
while (at2 < text17.length) {
|
|
10577
10603
|
if (text17[at2] === "[") {
|
|
10578
10604
|
const close = text17.indexOf("]", at2);
|
|
10579
10605
|
const segment = close === -1 ? void 0 : bracketSegment(text17.slice(at2 + 1, close));
|
|
10580
10606
|
if (!segment) return void 0;
|
|
10581
|
-
|
|
10607
|
+
path73.push(segment);
|
|
10582
10608
|
at2 = close + 1;
|
|
10583
10609
|
continue;
|
|
10584
10610
|
}
|
|
10585
10611
|
if (text17[at2] === ".") {
|
|
10586
|
-
if (
|
|
10612
|
+
if (path73.length === 0) return void 0;
|
|
10587
10613
|
at2 += 1;
|
|
10588
10614
|
}
|
|
10589
10615
|
const start3 = at2;
|
|
10590
10616
|
while (at2 < text17.length && text17[at2] !== "." && text17[at2] !== "[") at2 += 1;
|
|
10591
10617
|
const name = text17.slice(start3, at2);
|
|
10592
10618
|
if (!name) return void 0;
|
|
10593
|
-
|
|
10619
|
+
path73.push(nameSegment(name));
|
|
10594
10620
|
}
|
|
10595
|
-
return
|
|
10621
|
+
return path73;
|
|
10596
10622
|
}
|
|
10597
10623
|
|
|
10598
10624
|
// src/commands/config/configEntryNode.ts
|
|
10599
10625
|
function configEntryNode(root, key) {
|
|
10600
|
-
const
|
|
10601
|
-
return
|
|
10626
|
+
const path73 = parseConfigPath(key);
|
|
10627
|
+
return path73 ? findConfigNode(root, path73) : void 0;
|
|
10602
10628
|
}
|
|
10603
10629
|
|
|
10604
10630
|
// src/commands/config/readConfigEntries.ts
|
|
@@ -10703,7 +10729,7 @@ function findSynthesisForBranch(repoReviewsDir, branch2) {
|
|
|
10703
10729
|
const parent = dirname21(branchKeyPath);
|
|
10704
10730
|
const branchPrefix = basename7(branchKeyPath);
|
|
10705
10731
|
if (!existsSync29(parent)) return null;
|
|
10706
|
-
const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join27(parent, name, "synthesis.md")).filter((
|
|
10732
|
+
const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join27(parent, name, "synthesis.md")).filter((path73) => existsSync29(path73)).map((path73) => ({ path: path73, mtime: statSync4(path73).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
10707
10733
|
return synthesisFiles[0]?.path ?? null;
|
|
10708
10734
|
}
|
|
10709
10735
|
|
|
@@ -10733,12 +10759,12 @@ async function getReviewSynthesis(req, res) {
|
|
|
10733
10759
|
const cwd = getCwdParam(req, res);
|
|
10734
10760
|
if (!cwd) return;
|
|
10735
10761
|
try {
|
|
10736
|
-
const
|
|
10737
|
-
if (!
|
|
10762
|
+
const path73 = await resolveSynthesisPath(cwd);
|
|
10763
|
+
if (!path73) {
|
|
10738
10764
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
10739
10765
|
return;
|
|
10740
10766
|
}
|
|
10741
|
-
respondJson(res, 200, { synthesis: readFileSync21(
|
|
10767
|
+
respondJson(res, 200, { synthesis: readFileSync21(path73, "utf8") });
|
|
10742
10768
|
} catch {
|
|
10743
10769
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
10744
10770
|
}
|
|
@@ -10821,8 +10847,8 @@ function parseDiffNameStatus(output) {
|
|
|
10821
10847
|
if (!status3 || fields.length < 2) continue;
|
|
10822
10848
|
const category = categorize(status3[0]);
|
|
10823
10849
|
if (!category) continue;
|
|
10824
|
-
const
|
|
10825
|
-
if (
|
|
10850
|
+
const path73 = fields[fields.length - 1];
|
|
10851
|
+
if (path73) result[category].push(path73);
|
|
10826
10852
|
}
|
|
10827
10853
|
return result;
|
|
10828
10854
|
}
|
|
@@ -10958,21 +10984,21 @@ function subsequenceScore(text17, query) {
|
|
|
10958
10984
|
}
|
|
10959
10985
|
return score - Math.min(text17.length, MAX_LENGTH_PENALTY);
|
|
10960
10986
|
}
|
|
10961
|
-
function scoreFilePath(
|
|
10987
|
+
function scoreFilePath(path73, query) {
|
|
10962
10988
|
const needle = query.trim().toLowerCase();
|
|
10963
10989
|
if (!needle) return 0;
|
|
10964
|
-
const
|
|
10965
|
-
const inBasename = subsequenceScore(
|
|
10990
|
+
const basename23 = path73.slice(path73.lastIndexOf("/") + 1);
|
|
10991
|
+
const inBasename = subsequenceScore(basename23, needle);
|
|
10966
10992
|
if (inBasename !== null) return BASENAME_WEIGHT + inBasename;
|
|
10967
|
-
return subsequenceScore(
|
|
10993
|
+
return subsequenceScore(path73, needle);
|
|
10968
10994
|
}
|
|
10969
10995
|
|
|
10970
10996
|
// src/commands/sessions/web/rankFilePaths.ts
|
|
10971
10997
|
function rankFilePaths(paths, query, limit) {
|
|
10972
10998
|
const scored = [];
|
|
10973
|
-
for (const
|
|
10974
|
-
const score = scoreFilePath(
|
|
10975
|
-
if (score !== null) scored.push({ path:
|
|
10999
|
+
for (const path73 of paths) {
|
|
11000
|
+
const score = scoreFilePath(path73, query);
|
|
11001
|
+
if (score !== null) scored.push({ path: path73, score });
|
|
10976
11002
|
}
|
|
10977
11003
|
scored.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path));
|
|
10978
11004
|
return scored.slice(0, limit).map((entry) => entry.path);
|
|
@@ -11437,38 +11463,38 @@ async function restartWeb(req, res, deps2 = {}) {
|
|
|
11437
11463
|
import { relative as relative3 } from "path";
|
|
11438
11464
|
|
|
11439
11465
|
// src/commands/sessions/web/revertPathChanges.ts
|
|
11440
|
-
async function isTracked(cwd,
|
|
11466
|
+
async function isTracked(cwd, path73) {
|
|
11441
11467
|
try {
|
|
11442
|
-
await execGit(cwd, ["ls-files", "--error-unmatch", "--",
|
|
11468
|
+
await execGit(cwd, ["ls-files", "--error-unmatch", "--", path73]);
|
|
11443
11469
|
return true;
|
|
11444
11470
|
} catch {
|
|
11445
11471
|
return false;
|
|
11446
11472
|
}
|
|
11447
11473
|
}
|
|
11448
|
-
async function isInHead(cwd,
|
|
11449
|
-
const listing = await execGit(cwd, ["ls-tree", "HEAD", "--",
|
|
11474
|
+
async function isInHead(cwd, path73) {
|
|
11475
|
+
const listing = await execGit(cwd, ["ls-tree", "HEAD", "--", path73]);
|
|
11450
11476
|
return listing.trim().length > 0;
|
|
11451
11477
|
}
|
|
11452
|
-
async function revertPathChanges(cwd,
|
|
11453
|
-
if (!await isTracked(cwd,
|
|
11454
|
-
await execGit(cwd, ["clean", "-f", "--",
|
|
11478
|
+
async function revertPathChanges(cwd, path73) {
|
|
11479
|
+
if (!await isTracked(cwd, path73)) {
|
|
11480
|
+
await execGit(cwd, ["clean", "-f", "--", path73]);
|
|
11455
11481
|
return;
|
|
11456
11482
|
}
|
|
11457
|
-
if (await isInHead(cwd,
|
|
11458
|
-
await execGit(cwd, ["checkout", "HEAD", "--",
|
|
11483
|
+
if (await isInHead(cwd, path73)) {
|
|
11484
|
+
await execGit(cwd, ["checkout", "HEAD", "--", path73]);
|
|
11459
11485
|
return;
|
|
11460
11486
|
}
|
|
11461
|
-
await execGit(cwd, ["rm", "-f", "--",
|
|
11487
|
+
await execGit(cwd, ["rm", "-f", "--", path73]);
|
|
11462
11488
|
}
|
|
11463
11489
|
|
|
11464
11490
|
// src/commands/sessions/web/revertDiffFile.ts
|
|
11465
11491
|
async function revertDiffFile(req, res) {
|
|
11466
11492
|
const resolved = getFileTarget(req, res);
|
|
11467
11493
|
if (!resolved) return;
|
|
11468
|
-
const
|
|
11494
|
+
const path73 = relative3(repoRoot(resolved.cwd), resolved.target);
|
|
11469
11495
|
try {
|
|
11470
|
-
await revertPathChanges(resolved.cwd,
|
|
11471
|
-
respondJson(res, 200, { reverted:
|
|
11496
|
+
await revertPathChanges(resolved.cwd, path73);
|
|
11497
|
+
respondJson(res, 200, { reverted: path73 });
|
|
11472
11498
|
} catch (error) {
|
|
11473
11499
|
respondJson(res, 500, {
|
|
11474
11500
|
error: error instanceof Error ? error.message : "Failed to revert file"
|
|
@@ -11549,11 +11575,11 @@ function coerceStructuredConfigValue(key, raw) {
|
|
|
11549
11575
|
};
|
|
11550
11576
|
}
|
|
11551
11577
|
function formatIssue(key, issue) {
|
|
11552
|
-
const
|
|
11578
|
+
const path73 = formatConfigPath([
|
|
11553
11579
|
{ kind: "key", name: key },
|
|
11554
11580
|
...issue.path.map(toSegment)
|
|
11555
11581
|
]);
|
|
11556
|
-
return `${
|
|
11582
|
+
return `${path73}: ${issue.message}`;
|
|
11557
11583
|
}
|
|
11558
11584
|
function toSegment(part) {
|
|
11559
11585
|
return typeof part === "number" ? { kind: "index", index: part } : { kind: "key", name: String(part) };
|
|
@@ -11648,9 +11674,9 @@ function coerceUnion(key, raw, types) {
|
|
|
11648
11674
|
}
|
|
11649
11675
|
|
|
11650
11676
|
// src/shared/valueAtConfigPath.ts
|
|
11651
|
-
function valueAtConfigPath(value,
|
|
11677
|
+
function valueAtConfigPath(value, path73) {
|
|
11652
11678
|
let current = value;
|
|
11653
|
-
for (const key of
|
|
11679
|
+
for (const key of path73) {
|
|
11654
11680
|
if (typeof key === "number") {
|
|
11655
11681
|
if (!Array.isArray(current)) return void 0;
|
|
11656
11682
|
current = current[key];
|
|
@@ -11667,7 +11693,7 @@ function restoreConfigSecrets(value, stored, node) {
|
|
|
11667
11693
|
return mapConfigSecrets(
|
|
11668
11694
|
value,
|
|
11669
11695
|
node,
|
|
11670
|
-
(secret,
|
|
11696
|
+
(secret, path73) => isRedactedSecret(secret) ? valueAtConfigPath(stored, path73) : secret
|
|
11671
11697
|
);
|
|
11672
11698
|
}
|
|
11673
11699
|
|
|
@@ -11716,8 +11742,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
11716
11742
|
}
|
|
11717
11743
|
return ensureObject(container, resolved);
|
|
11718
11744
|
}
|
|
11719
|
-
function setNestedValue(obj,
|
|
11720
|
-
const keys =
|
|
11745
|
+
function setNestedValue(obj, path73, value) {
|
|
11746
|
+
const keys = path73.split(".");
|
|
11721
11747
|
const result = { ...obj };
|
|
11722
11748
|
let current = result;
|
|
11723
11749
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -11738,8 +11764,8 @@ function validateConfig(updated, key, schema2 = assistConfigSchema) {
|
|
|
11738
11764
|
};
|
|
11739
11765
|
}
|
|
11740
11766
|
function formatIssue2(issue, key) {
|
|
11741
|
-
const
|
|
11742
|
-
return `${
|
|
11767
|
+
const path73 = issue.path.length > 0 ? issue.path.join(".") : key;
|
|
11768
|
+
return `${path73}: ${issue.message}`;
|
|
11743
11769
|
}
|
|
11744
11770
|
|
|
11745
11771
|
// src/commands/config/applyConfigSet.ts
|
|
@@ -11970,8 +11996,8 @@ function removeAt(container, keys) {
|
|
|
11970
11996
|
}
|
|
11971
11997
|
return removeFromChild(container, key, rest);
|
|
11972
11998
|
}
|
|
11973
|
-
function unsetNestedValue(obj,
|
|
11974
|
-
const { container, removed } = removeAt(obj,
|
|
11999
|
+
function unsetNestedValue(obj, path73) {
|
|
12000
|
+
const { container, removed } = removeAt(obj, path73.split("."));
|
|
11975
12001
|
return { config: container, removed };
|
|
11976
12002
|
}
|
|
11977
12003
|
|
|
@@ -12963,9 +12989,9 @@ function originToSshUrl(origin) {
|
|
|
12963
12989
|
const firstSlash = origin.indexOf("/");
|
|
12964
12990
|
if (firstSlash <= 0) return null;
|
|
12965
12991
|
const host = origin.slice(0, firstSlash);
|
|
12966
|
-
const
|
|
12967
|
-
if (!
|
|
12968
|
-
return `git@${host}:${
|
|
12992
|
+
const path73 = origin.slice(firstSlash + 1);
|
|
12993
|
+
if (!path73) return null;
|
|
12994
|
+
return `git@${host}:${path73}.git`;
|
|
12969
12995
|
}
|
|
12970
12996
|
|
|
12971
12997
|
// src/commands/backlog/cloneRepo.ts
|
|
@@ -14192,6 +14218,17 @@ This is usually a transient database/network blip \u2014 the work is saved and t
|
|
|
14192
14218
|
}
|
|
14193
14219
|
}
|
|
14194
14220
|
|
|
14221
|
+
// src/commands/backlog/reportLaunchActivity.ts
|
|
14222
|
+
function reportLaunchActivity(slashCommand, claudeSessionId, harness, item) {
|
|
14223
|
+
emitActivity({
|
|
14224
|
+
kind: "command",
|
|
14225
|
+
name: slashCommand,
|
|
14226
|
+
itemId: item?.itemId,
|
|
14227
|
+
itemName: item?.itemName,
|
|
14228
|
+
...harnessActivityFields(harness, claudeSessionId)
|
|
14229
|
+
});
|
|
14230
|
+
}
|
|
14231
|
+
|
|
14195
14232
|
// src/commands/backlog/launchMode.ts
|
|
14196
14233
|
function buildSlashCommand(slashCommand, description) {
|
|
14197
14234
|
const trimmed = description?.trim();
|
|
@@ -14202,15 +14239,10 @@ async function launchMode(slashCommand, options2) {
|
|
|
14202
14239
|
if (!resumeSessionId) pullIfConfigured();
|
|
14203
14240
|
process.env.ASSIST_SESSION_ID ??= String(process.pid);
|
|
14204
14241
|
const claudeSessionId = resumeSessionId ?? randomUUID4();
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
name: slashCommand,
|
|
14208
|
-
itemId: options2?.itemId,
|
|
14209
|
-
itemName: options2?.itemName,
|
|
14210
|
-
claudeSessionId
|
|
14211
|
-
});
|
|
14242
|
+
const harness = options2?.harness ?? "claude";
|
|
14243
|
+
reportLaunchActivity(slashCommand, claudeSessionId, harness, options2);
|
|
14212
14244
|
const prompt = resumeSessionId ? resumeNudge() : buildSlashCommand(slashCommand, options2?.description);
|
|
14213
|
-
const { child, done: done2 } = spawnHarness(
|
|
14245
|
+
const { child, done: done2 } = spawnHarness(harness, prompt, {
|
|
14214
14246
|
sessionId: claudeSessionId,
|
|
14215
14247
|
resumeSessionId,
|
|
14216
14248
|
cwd: process.cwd()
|
|
@@ -14265,7 +14297,7 @@ async function refine(id, options2) {
|
|
|
14265
14297
|
}
|
|
14266
14298
|
|
|
14267
14299
|
// src/commands/backlog/resolveHarness.ts
|
|
14268
|
-
function
|
|
14300
|
+
function resolveHarness2(value) {
|
|
14269
14301
|
if (value === "claude" || value === "codex" || value === "pi") return value;
|
|
14270
14302
|
return loadConfig().harness.engine;
|
|
14271
14303
|
}
|
|
@@ -14278,7 +14310,7 @@ function registerRefineCommand(cmd) {
|
|
|
14278
14310
|
).action(
|
|
14279
14311
|
(id, opts) => refine(id, {
|
|
14280
14312
|
once: opts.once,
|
|
14281
|
-
harness:
|
|
14313
|
+
harness: resolveHarness2(opts.harness)
|
|
14282
14314
|
})
|
|
14283
14315
|
);
|
|
14284
14316
|
}
|
|
@@ -14321,7 +14353,7 @@ function registerRunCommand(cmd) {
|
|
|
14321
14353
|
if (!opts.resumeSession) pullIfConfigured();
|
|
14322
14354
|
await run2(id, {
|
|
14323
14355
|
allowEdits: opts.write !== false,
|
|
14324
|
-
harness:
|
|
14356
|
+
harness: resolveHarness2(opts.harness),
|
|
14325
14357
|
resumeSessionId: opts.resumeSession
|
|
14326
14358
|
});
|
|
14327
14359
|
}
|
|
@@ -15937,9 +15969,9 @@ var __dirname4 = dirname23(__filename3);
|
|
|
15937
15969
|
function packageRoot() {
|
|
15938
15970
|
return __dirname4;
|
|
15939
15971
|
}
|
|
15940
|
-
function readLines(
|
|
15941
|
-
if (!existsSync32(
|
|
15942
|
-
return readFileSync25(
|
|
15972
|
+
function readLines(path73) {
|
|
15973
|
+
if (!existsSync32(path73)) return [];
|
|
15974
|
+
return readFileSync25(path73, "utf8").split("\n").filter((line) => line.trim() !== "");
|
|
15943
15975
|
}
|
|
15944
15976
|
var cachedReads;
|
|
15945
15977
|
var cachedWrites;
|
|
@@ -16433,14 +16465,14 @@ function showProgress(p, label2) {
|
|
|
16433
16465
|
const pct = Math.round(p.done / p.total * 100);
|
|
16434
16466
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
16435
16467
|
}
|
|
16436
|
-
async function resolveCommand(cli,
|
|
16437
|
-
showProgress(p,
|
|
16438
|
-
const subHelp = await runHelp([cli, ...
|
|
16468
|
+
async function resolveCommand(cli, path73, description, depth, p) {
|
|
16469
|
+
showProgress(p, path73.join(" "));
|
|
16470
|
+
const subHelp = await runHelp([cli, ...path73]);
|
|
16439
16471
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
16440
|
-
return [{ path:
|
|
16472
|
+
return [{ path: path73, description }];
|
|
16441
16473
|
}
|
|
16442
|
-
const children = await discoverAt(cli,
|
|
16443
|
-
return children.length > 0 ? children : [{ path:
|
|
16474
|
+
const children = await discoverAt(cli, path73, depth + 1, p);
|
|
16475
|
+
return children.length > 0 ? children : [{ path: path73, description }];
|
|
16444
16476
|
}
|
|
16445
16477
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
16446
16478
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -16588,9 +16620,9 @@ function logPath(cli) {
|
|
|
16588
16620
|
return join34(homedir16(), ".assist", `cli-discover-${safeName}.log`);
|
|
16589
16621
|
}
|
|
16590
16622
|
function readCache(cli) {
|
|
16591
|
-
const
|
|
16592
|
-
if (!existsSync34(
|
|
16593
|
-
return readFileSync27(
|
|
16623
|
+
const path73 = logPath(cli);
|
|
16624
|
+
if (!existsSync34(path73)) return void 0;
|
|
16625
|
+
return readFileSync27(path73, "utf8");
|
|
16594
16626
|
}
|
|
16595
16627
|
function writeCache(cli, output) {
|
|
16596
16628
|
const dir = join34(homedir16(), ".assist");
|
|
@@ -16750,9 +16782,9 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
16750
16782
|
}
|
|
16751
16783
|
const cutoff = Date.now() - STALE_AFTER_MS;
|
|
16752
16784
|
for (const entry of entries) {
|
|
16753
|
-
const
|
|
16785
|
+
const path73 = join36(dir, entry);
|
|
16754
16786
|
try {
|
|
16755
|
-
if (statSync5(
|
|
16787
|
+
if (statSync5(path73).mtimeMs < cutoff) unlinkSync7(path73);
|
|
16756
16788
|
} catch {
|
|
16757
16789
|
continue;
|
|
16758
16790
|
}
|
|
@@ -16762,10 +16794,10 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
16762
16794
|
// src/commands/codeComment/readPinState.ts
|
|
16763
16795
|
import { existsSync as existsSync35, readFileSync as readFileSync28 } from "fs";
|
|
16764
16796
|
function readPinState(pin) {
|
|
16765
|
-
const
|
|
16766
|
-
if (!existsSync35(
|
|
16797
|
+
const path73 = getPinStatePath(pin);
|
|
16798
|
+
if (!existsSync35(path73)) return void 0;
|
|
16767
16799
|
try {
|
|
16768
|
-
const state = JSON.parse(readFileSync28(
|
|
16800
|
+
const state = JSON.parse(readFileSync28(path73, "utf8"));
|
|
16769
16801
|
if (state.pin !== pin) return void 0;
|
|
16770
16802
|
return state;
|
|
16771
16803
|
} catch {
|
|
@@ -17850,10 +17882,10 @@ function getMigrationApprovalPath(migrationId) {
|
|
|
17850
17882
|
// src/commands/dbMigration/readMigrationPinState.ts
|
|
17851
17883
|
import { existsSync as existsSync37, readFileSync as readFileSync30 } from "fs";
|
|
17852
17884
|
function readMigrationPinState(pin) {
|
|
17853
|
-
const
|
|
17854
|
-
if (!existsSync37(
|
|
17885
|
+
const path73 = getMigrationPinPath(pin);
|
|
17886
|
+
if (!existsSync37(path73)) return void 0;
|
|
17855
17887
|
try {
|
|
17856
|
-
const state = JSON.parse(readFileSync30(
|
|
17888
|
+
const state = JSON.parse(readFileSync30(path73, "utf8"));
|
|
17857
17889
|
if (state.pin !== pin) return void 0;
|
|
17858
17890
|
if (!Number.isInteger(state.migrationId)) return void 0;
|
|
17859
17891
|
return state;
|
|
@@ -19251,10 +19283,10 @@ function decideCommentGuard(input, existingContent) {
|
|
|
19251
19283
|
import { existsSync as existsSync43, unlinkSync as unlinkSync11 } from "fs";
|
|
19252
19284
|
function consumeMigrationApproval(migrationId) {
|
|
19253
19285
|
sweepRestrictedDir();
|
|
19254
|
-
const
|
|
19255
|
-
if (!existsSync43(
|
|
19286
|
+
const path73 = getMigrationApprovalPath(migrationId);
|
|
19287
|
+
if (!existsSync43(path73)) return false;
|
|
19256
19288
|
try {
|
|
19257
|
-
unlinkSync11(
|
|
19289
|
+
unlinkSync11(path73);
|
|
19258
19290
|
return true;
|
|
19259
19291
|
} catch {
|
|
19260
19292
|
return false;
|
|
@@ -19972,7 +20004,7 @@ function runRefine(id, opts) {
|
|
|
19972
20004
|
return refine(id, {
|
|
19973
20005
|
once: opts.once,
|
|
19974
20006
|
resumeSessionId: opts.resumeSession,
|
|
19975
|
-
harness:
|
|
20007
|
+
harness: resolveHarness2(opts.harness)
|
|
19976
20008
|
});
|
|
19977
20009
|
}
|
|
19978
20010
|
function registerRefineLaunch(program2, resumeFlag) {
|
|
@@ -20061,22 +20093,22 @@ function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
|
|
|
20061
20093
|
const registered = new Set(listWorktreePaths(clone));
|
|
20062
20094
|
const branches = new Set(listLocalBranches(clone));
|
|
20063
20095
|
const isTaken = (candidate) => registered.has(candidate) || existsSync45(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename14(candidate));
|
|
20064
|
-
const
|
|
20096
|
+
const path73 = preferredPath && !isTaken(preferredPath) ? preferredPath : nextWorktreePath(clone, base, isTaken);
|
|
20065
20097
|
const start3 = worktreeStartPoint(clone, strategy.trunk);
|
|
20066
20098
|
gitSync(clone, [
|
|
20067
20099
|
"worktree",
|
|
20068
20100
|
"add",
|
|
20069
20101
|
start3.track ? "--track" : "--no-track",
|
|
20070
20102
|
"-b",
|
|
20071
|
-
basename14(
|
|
20072
|
-
|
|
20103
|
+
basename14(path73),
|
|
20104
|
+
path73,
|
|
20073
20105
|
start3.ref
|
|
20074
20106
|
]);
|
|
20075
|
-
recordWorktree(
|
|
20107
|
+
recordWorktree(path73, clone, getCurrentOrigin(clone));
|
|
20076
20108
|
daemonLog(
|
|
20077
|
-
start3.track ? `worktree allocated ${
|
|
20109
|
+
start3.track ? `worktree allocated ${path73} (branch ${basename14(path73)} tracking ${start3.ref}) for clone ${clone}` : `worktree allocated ${path73} (branch ${basename14(path73)} off ${start3.ref}, no mainline tracking) for clone ${clone}`
|
|
20078
20110
|
);
|
|
20079
|
-
return
|
|
20111
|
+
return path73;
|
|
20080
20112
|
}
|
|
20081
20113
|
|
|
20082
20114
|
// src/commands/sessions/daemon/worktree/treeDurability.ts
|
|
@@ -20188,13 +20220,13 @@ function allocateTree(requestedCwd, boundTreeRoots2, options2 = {}) {
|
|
|
20188
20220
|
if (forcedSpill) daemonLog(forcedSpill);
|
|
20189
20221
|
else if (reusesClone(clone, boundTreeRoots2, reuse))
|
|
20190
20222
|
return { cwd: clone, kind: "primary", created: false, clone };
|
|
20191
|
-
const
|
|
20223
|
+
const path73 = createWorktree(
|
|
20192
20224
|
clone,
|
|
20193
20225
|
{ root: cfg.root, trunk: cfg.trunk },
|
|
20194
20226
|
boundTreeRoots2,
|
|
20195
20227
|
options2.replacesTree
|
|
20196
20228
|
);
|
|
20197
|
-
return { cwd:
|
|
20229
|
+
return { cwd: path73, kind: "worktree", created: true, clone };
|
|
20198
20230
|
}
|
|
20199
20231
|
function keptInPlace(cwd) {
|
|
20200
20232
|
daemonLog(
|
|
@@ -20525,13 +20557,13 @@ function worktreeHoldingBranch(cwd, branch2) {
|
|
|
20525
20557
|
const listing = gitSyncOrNull(cwd, ["worktree", "list", "--porcelain"]);
|
|
20526
20558
|
if (!listing) return null;
|
|
20527
20559
|
const here = gitSyncOrNull(cwd, ["rev-parse", "--show-toplevel"]);
|
|
20528
|
-
let
|
|
20560
|
+
let path73 = null;
|
|
20529
20561
|
for (const line of listing.split("\n")) {
|
|
20530
20562
|
const trimmed = line.trim();
|
|
20531
20563
|
if (trimmed.startsWith("worktree "))
|
|
20532
|
-
|
|
20564
|
+
path73 = trimmed.slice("worktree ".length).trim();
|
|
20533
20565
|
else if (trimmed === `branch refs/heads/${branch2}`)
|
|
20534
|
-
return
|
|
20566
|
+
return path73 && path73 !== here ? path73 : null;
|
|
20535
20567
|
}
|
|
20536
20568
|
return null;
|
|
20537
20569
|
}
|
|
@@ -20988,9 +21020,9 @@ function parseRscRows(flight) {
|
|
|
20988
21020
|
}
|
|
20989
21021
|
function makeRscResolver(rows) {
|
|
20990
21022
|
return (ref) => {
|
|
20991
|
-
const [id, ...
|
|
21023
|
+
const [id, ...path73] = ref.slice(1).replace(/^[L@]/, "").split(":");
|
|
20992
21024
|
let v = rows[id];
|
|
20993
|
-
for (const key of
|
|
21025
|
+
for (const key of path73) {
|
|
20994
21026
|
if (v == null || typeof v !== "object") return void 0;
|
|
20995
21027
|
v = v[key];
|
|
20996
21028
|
}
|
|
@@ -21676,15 +21708,15 @@ function postComment(vars) {
|
|
|
21676
21708
|
const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
|
|
21677
21709
|
assertThreadCreated(stdout);
|
|
21678
21710
|
}
|
|
21679
|
-
function comment2(
|
|
21711
|
+
function comment2(path73, line, body, startLine) {
|
|
21680
21712
|
validateBody(body);
|
|
21681
21713
|
validateLine(line);
|
|
21682
21714
|
if (startLine !== void 0) validateLine(startLine);
|
|
21683
21715
|
try {
|
|
21684
21716
|
const prId = getCurrentPrNodeId();
|
|
21685
|
-
postComment({ prId, body, path:
|
|
21717
|
+
postComment({ prId, body, path: path73, line, startLine });
|
|
21686
21718
|
const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
|
|
21687
|
-
console.log(`Added review comment on ${
|
|
21719
|
+
console.log(`Added review comment on ${path73}:${range}`);
|
|
21688
21720
|
} catch (error) {
|
|
21689
21721
|
if (isGhNotInstalled(error)) {
|
|
21690
21722
|
console.error("Error: GitHub CLI (gh) is not installed.");
|
|
@@ -22939,8 +22971,8 @@ function registerPrs(program2) {
|
|
|
22939
22971
|
prsCommand.command("reply <comment-id> <body>").description("Reply to a comment thread without resolving it").action((commentId, body) => {
|
|
22940
22972
|
reply(Number.parseInt(commentId, 10), body);
|
|
22941
22973
|
});
|
|
22942
|
-
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((
|
|
22943
|
-
comment2(
|
|
22974
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path73, line, body) => {
|
|
22975
|
+
comment2(path73, Number.parseInt(line, 10), body);
|
|
22944
22976
|
});
|
|
22945
22977
|
configHelp(prsCommand, prsConfigHelp);
|
|
22946
22978
|
}
|
|
@@ -23193,10 +23225,10 @@ function resolveOpSecret(reference) {
|
|
|
23193
23225
|
}
|
|
23194
23226
|
|
|
23195
23227
|
// src/commands/ravendb/ravenFetch.ts
|
|
23196
|
-
async function ravenFetch(connection,
|
|
23228
|
+
async function ravenFetch(connection, path73) {
|
|
23197
23229
|
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
23198
23230
|
let accessToken = await getAccessToken(apiKey);
|
|
23199
|
-
const url = `${connection.url}${
|
|
23231
|
+
const url = `${connection.url}${path73}`;
|
|
23200
23232
|
const headers = {
|
|
23201
23233
|
Authorization: `Bearer ${accessToken}`,
|
|
23202
23234
|
"Content-Type": "application/json"
|
|
@@ -23286,16 +23318,16 @@ import chalk182 from "chalk";
|
|
|
23286
23318
|
// src/commands/ravendb/buildQueryPath.ts
|
|
23287
23319
|
function buildQueryPath(opts) {
|
|
23288
23320
|
const db = encodeURIComponent(opts.db);
|
|
23289
|
-
let
|
|
23321
|
+
let path73;
|
|
23290
23322
|
if (opts.collection) {
|
|
23291
|
-
|
|
23323
|
+
path73 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
23292
23324
|
} else {
|
|
23293
|
-
|
|
23325
|
+
path73 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
23294
23326
|
}
|
|
23295
23327
|
if (opts.query) {
|
|
23296
|
-
|
|
23328
|
+
path73 += `&query=${encodeURIComponent(opts.query)}`;
|
|
23297
23329
|
}
|
|
23298
|
-
return
|
|
23330
|
+
return path73;
|
|
23299
23331
|
}
|
|
23300
23332
|
|
|
23301
23333
|
// src/commands/ravendb/fetchAllPages.ts
|
|
@@ -23304,7 +23336,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
23304
23336
|
let start3 = 0;
|
|
23305
23337
|
while (true) {
|
|
23306
23338
|
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
23307
|
-
const
|
|
23339
|
+
const path73 = buildQueryPath({
|
|
23308
23340
|
db: connection.database,
|
|
23309
23341
|
collection: opts.collection,
|
|
23310
23342
|
start: start3,
|
|
@@ -23312,7 +23344,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
23312
23344
|
sort: opts.sort,
|
|
23313
23345
|
query: opts.query
|
|
23314
23346
|
});
|
|
23315
|
-
const data = await ravenFetch(connection,
|
|
23347
|
+
const data = await ravenFetch(connection, path73);
|
|
23316
23348
|
const results = data.Results ?? [];
|
|
23317
23349
|
const totalResults = data.TotalResults ?? 0;
|
|
23318
23350
|
if (results.length === 0) break;
|
|
@@ -24753,8 +24785,8 @@ function findRootParent(file, importedBy, visited) {
|
|
|
24753
24785
|
function clusterFiles(graph) {
|
|
24754
24786
|
const clusters = /* @__PURE__ */ new Map();
|
|
24755
24787
|
for (const file of graph.files) {
|
|
24756
|
-
const
|
|
24757
|
-
if (
|
|
24788
|
+
const basename23 = path52.basename(file, path52.extname(file));
|
|
24789
|
+
if (basename23 === "index") continue;
|
|
24758
24790
|
const importers = graph.importedBy.get(file);
|
|
24759
24791
|
if (!importers || importers.size !== 1) continue;
|
|
24760
24792
|
const parent = [...importers][0];
|
|
@@ -25907,8 +25939,8 @@ async function handlePostSynthesis(synthesisPath, prInfo, options2) {
|
|
|
25907
25939
|
// src/commands/review/prepareReviewDir.ts
|
|
25908
25940
|
import { existsSync as existsSync50, mkdirSync as mkdirSync19, unlinkSync as unlinkSync17, writeFileSync as writeFileSync36 } from "fs";
|
|
25909
25941
|
function clearReviewFiles(paths) {
|
|
25910
|
-
for (const
|
|
25911
|
-
if (existsSync50(
|
|
25942
|
+
for (const path73 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
25943
|
+
if (existsSync50(path73)) unlinkSync17(path73);
|
|
25912
25944
|
}
|
|
25913
25945
|
}
|
|
25914
25946
|
function prepareReviewDir(paths, requestBody, force) {
|
|
@@ -26998,8 +27030,8 @@ import chalk203 from "chalk";
|
|
|
26998
27030
|
|
|
26999
27031
|
// src/commands/seq/fetchSeq.ts
|
|
27000
27032
|
import chalk200 from "chalk";
|
|
27001
|
-
async function fetchSeq(conn,
|
|
27002
|
-
const url = `${conn.url}${
|
|
27033
|
+
async function fetchSeq(conn, path73, params) {
|
|
27034
|
+
const url = `${conn.url}${path73}?${params}`;
|
|
27003
27035
|
const response = await fetch(url, {
|
|
27004
27036
|
headers: {
|
|
27005
27037
|
Accept: "application/json",
|
|
@@ -27548,6 +27580,438 @@ function registerSql(program2) {
|
|
|
27548
27580
|
configHelp(cmd, sqlConfigHelp);
|
|
27549
27581
|
}
|
|
27550
27582
|
|
|
27583
|
+
// src/commands/sync.ts
|
|
27584
|
+
import * as fs43 from "fs";
|
|
27585
|
+
import * as os4 from "os";
|
|
27586
|
+
import * as path68 from "path";
|
|
27587
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
27588
|
+
|
|
27589
|
+
// src/commands/sync/pruneCommands.ts
|
|
27590
|
+
import * as path59 from "path";
|
|
27591
|
+
|
|
27592
|
+
// src/commands/sync/pruneTarget.ts
|
|
27593
|
+
import * as fs35 from "fs";
|
|
27594
|
+
import * as path58 from "path";
|
|
27595
|
+
function pruneTarget(targetDir, keepNames, shape, options2) {
|
|
27596
|
+
const result = {
|
|
27597
|
+
orphans: [],
|
|
27598
|
+
removed: [],
|
|
27599
|
+
skipped: [],
|
|
27600
|
+
unmanaged: []
|
|
27601
|
+
};
|
|
27602
|
+
if (!fs35.existsSync(targetDir)) return result;
|
|
27603
|
+
const keep = new Set(keepNames);
|
|
27604
|
+
for (const entry of fs35.readdirSync(targetDir, { withFileTypes: true })) {
|
|
27605
|
+
const name = shape.nameOf(entry);
|
|
27606
|
+
if (name === void 0) {
|
|
27607
|
+
result.unmanaged.push(entry.name);
|
|
27608
|
+
continue;
|
|
27609
|
+
}
|
|
27610
|
+
if (keep.has(name)) continue;
|
|
27611
|
+
result.orphans.push(entry.name);
|
|
27612
|
+
const entryPath = path58.join(targetDir, entry.name);
|
|
27613
|
+
const reason4 = shape.blockedBy?.(entryPath);
|
|
27614
|
+
if (reason4) {
|
|
27615
|
+
result.skipped.push({ name: entry.name, reason: reason4 });
|
|
27616
|
+
continue;
|
|
27617
|
+
}
|
|
27618
|
+
if (options2.force) {
|
|
27619
|
+
fs35.rmSync(entryPath, { recursive: true });
|
|
27620
|
+
result.removed.push(entry.name);
|
|
27621
|
+
}
|
|
27622
|
+
}
|
|
27623
|
+
return result;
|
|
27624
|
+
}
|
|
27625
|
+
|
|
27626
|
+
// src/commands/sync/pruneCommands.ts
|
|
27627
|
+
function pruneCommands(targetDir, commandNames, options2) {
|
|
27628
|
+
return pruneTarget(
|
|
27629
|
+
targetDir,
|
|
27630
|
+
commandNames,
|
|
27631
|
+
{
|
|
27632
|
+
nameOf: (entry) => entry.isFile() && entry.name.endsWith(".md") ? path59.basename(entry.name, ".md") : void 0
|
|
27633
|
+
},
|
|
27634
|
+
options2
|
|
27635
|
+
);
|
|
27636
|
+
}
|
|
27637
|
+
|
|
27638
|
+
// src/commands/sync/reportPrune.ts
|
|
27639
|
+
function reportPrune(label2, result, force) {
|
|
27640
|
+
if (result.orphans.length === 0) {
|
|
27641
|
+
console.log(`No orphaned commands in ${label2}`);
|
|
27642
|
+
} else if (force) {
|
|
27643
|
+
for (const name of result.removed) {
|
|
27644
|
+
console.log(`Removed ${name} from ${label2}`);
|
|
27645
|
+
}
|
|
27646
|
+
} else {
|
|
27647
|
+
console.log(`Orphaned commands in ${label2} (run with --force to remove):`);
|
|
27648
|
+
for (const name of result.orphans) {
|
|
27649
|
+
console.log(` ${name}`);
|
|
27650
|
+
}
|
|
27651
|
+
}
|
|
27652
|
+
if (result.skipped.length > 0) {
|
|
27653
|
+
console.log(`Left in place in ${label2} (not written by sync):`);
|
|
27654
|
+
for (const { name, reason: reason4 } of result.skipped) {
|
|
27655
|
+
console.log(` ${name} - ${reason4}`);
|
|
27656
|
+
}
|
|
27657
|
+
}
|
|
27658
|
+
if (result.unmanaged.length === 0) return;
|
|
27659
|
+
console.log(`Not managed by sync in ${label2} (never removed):`);
|
|
27660
|
+
for (const name of result.unmanaged) {
|
|
27661
|
+
console.log(` ${name}`);
|
|
27662
|
+
}
|
|
27663
|
+
}
|
|
27664
|
+
|
|
27665
|
+
// src/commands/sync/syncClaudeMd.ts
|
|
27666
|
+
import * as fs36 from "fs";
|
|
27667
|
+
import * as path60 from "path";
|
|
27668
|
+
import chalk210 from "chalk";
|
|
27669
|
+
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
27670
|
+
const source = path60.join(claudeDir, "CLAUDE.md");
|
|
27671
|
+
const target = path60.join(targetBase, "CLAUDE.md");
|
|
27672
|
+
const sourceContent = fs36.readFileSync(source, "utf8");
|
|
27673
|
+
if (fs36.existsSync(target)) {
|
|
27674
|
+
const targetContent = fs36.readFileSync(target, "utf8");
|
|
27675
|
+
if (sourceContent !== targetContent) {
|
|
27676
|
+
console.log(
|
|
27677
|
+
chalk210.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
27678
|
+
);
|
|
27679
|
+
console.log();
|
|
27680
|
+
printDiff(targetContent, sourceContent);
|
|
27681
|
+
if (!options2?.yes) {
|
|
27682
|
+
printAutoConfirmHint();
|
|
27683
|
+
const confirm = await promptConfirm(
|
|
27684
|
+
chalk210.red("Overwrite existing CLAUDE.md?"),
|
|
27685
|
+
false
|
|
27686
|
+
);
|
|
27687
|
+
if (!confirm) {
|
|
27688
|
+
console.log("Skipped CLAUDE.md");
|
|
27689
|
+
return;
|
|
27690
|
+
}
|
|
27691
|
+
}
|
|
27692
|
+
}
|
|
27693
|
+
}
|
|
27694
|
+
fs36.copyFileSync(source, target);
|
|
27695
|
+
console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
|
|
27696
|
+
}
|
|
27697
|
+
|
|
27698
|
+
// src/commands/sync/syncCodex.ts
|
|
27699
|
+
import * as path63 from "path";
|
|
27700
|
+
|
|
27701
|
+
// src/commands/sync/installHarnessCommands.ts
|
|
27702
|
+
import * as fs37 from "fs";
|
|
27703
|
+
import * as path61 from "path";
|
|
27704
|
+
function installHarnessCommands(claudeDir, harness, transform) {
|
|
27705
|
+
const commandsSource = path61.join(claudeDir, "commands");
|
|
27706
|
+
const files = fs37.readdirSync(commandsSource);
|
|
27707
|
+
const names = [];
|
|
27708
|
+
let synced = 0;
|
|
27709
|
+
for (const file of files) {
|
|
27710
|
+
if (!file.endsWith(".md")) continue;
|
|
27711
|
+
const name = file.replace(/\.md$/, "");
|
|
27712
|
+
names.push(name);
|
|
27713
|
+
const content = fs37.readFileSync(path61.join(commandsSource, file), "utf8");
|
|
27714
|
+
const target = path61.join(harness.homeDir, harness.sync.commandDest(name));
|
|
27715
|
+
fs37.mkdirSync(path61.dirname(target), { recursive: true });
|
|
27716
|
+
fs37.writeFileSync(target, transform(name, content));
|
|
27717
|
+
synced++;
|
|
27718
|
+
}
|
|
27719
|
+
const agentsTarget = path61.join(harness.homeDir, harness.sync.agentsFile);
|
|
27720
|
+
fs37.mkdirSync(path61.dirname(agentsTarget), { recursive: true });
|
|
27721
|
+
fs37.copyFileSync(path61.join(claudeDir, "CLAUDE.md"), agentsTarget);
|
|
27722
|
+
return { total: files.length, synced, names };
|
|
27723
|
+
}
|
|
27724
|
+
|
|
27725
|
+
// src/commands/sync/pruneSkills.ts
|
|
27726
|
+
import * as fs38 from "fs";
|
|
27727
|
+
function pruneSkills(targetDir, skillNames, options2) {
|
|
27728
|
+
return pruneTarget(
|
|
27729
|
+
targetDir,
|
|
27730
|
+
skillNames,
|
|
27731
|
+
{
|
|
27732
|
+
nameOf: (entry) => entry.isDirectory() ? entry.name : void 0,
|
|
27733
|
+
blockedBy: unexpectedContent
|
|
27734
|
+
},
|
|
27735
|
+
options2
|
|
27736
|
+
);
|
|
27737
|
+
}
|
|
27738
|
+
function unexpectedContent(skillDir) {
|
|
27739
|
+
const entries = fs38.readdirSync(skillDir);
|
|
27740
|
+
const others = entries.filter((entry) => entry !== "SKILL.md");
|
|
27741
|
+
if (others.length > 0) return `contains ${others.sort().join(", ")}`;
|
|
27742
|
+
return entries.length === 0 ? "no SKILL.md" : void 0;
|
|
27743
|
+
}
|
|
27744
|
+
|
|
27745
|
+
// src/commands/sync/syncCodexHooks.ts
|
|
27746
|
+
import * as fs39 from "fs";
|
|
27747
|
+
import * as path62 from "path";
|
|
27748
|
+
var BEGIN = "# >>> assist codex hooks (managed) \u2014 do not edit >>>";
|
|
27749
|
+
var END = "# <<< assist codex hooks (managed) <<<";
|
|
27750
|
+
function upsertManagedBlock(existing, body) {
|
|
27751
|
+
const block = `${BEGIN}
|
|
27752
|
+
${body.trim()}
|
|
27753
|
+
${END}`;
|
|
27754
|
+
const begin = existing.indexOf(BEGIN);
|
|
27755
|
+
if (begin === -1) {
|
|
27756
|
+
const base = existing.replace(/\s*$/, "");
|
|
27757
|
+
return base ? `${base}
|
|
27758
|
+
|
|
27759
|
+
${block}
|
|
27760
|
+
` : `${block}
|
|
27761
|
+
`;
|
|
27762
|
+
}
|
|
27763
|
+
const endMarker = existing.indexOf(END, begin);
|
|
27764
|
+
const after = endMarker === -1 ? existing.length : endMarker + END.length;
|
|
27765
|
+
const before = existing.slice(0, begin).replace(/\s*$/, "");
|
|
27766
|
+
const rest = existing.slice(after).replace(/^\s*/, "");
|
|
27767
|
+
const head = before ? `${before}
|
|
27768
|
+
|
|
27769
|
+
${block}` : block;
|
|
27770
|
+
return rest ? `${head}
|
|
27771
|
+
|
|
27772
|
+
${rest}
|
|
27773
|
+
` : `${head}
|
|
27774
|
+
`;
|
|
27775
|
+
}
|
|
27776
|
+
function syncCodexHooks(sourcePath) {
|
|
27777
|
+
const body = fs39.readFileSync(sourcePath, "utf8");
|
|
27778
|
+
const configPath = path62.join(harnesses.codex.homeDir, "config.toml");
|
|
27779
|
+
const existing = fs39.existsSync(configPath) ? fs39.readFileSync(configPath, "utf8") : "";
|
|
27780
|
+
fs39.mkdirSync(path62.dirname(configPath), { recursive: true });
|
|
27781
|
+
fs39.writeFileSync(configPath, upsertManagedBlock(existing, body));
|
|
27782
|
+
console.log(
|
|
27783
|
+
"Registered assist codex-hook in ~/.codex/config.toml (PreToolUse, PermissionRequest)"
|
|
27784
|
+
);
|
|
27785
|
+
}
|
|
27786
|
+
|
|
27787
|
+
// src/commands/sync/syncCodex.ts
|
|
27788
|
+
function quoteYaml(value) {
|
|
27789
|
+
return `"${value.replace(/\\/g, String.raw`\\`).replace(/"/g, String.raw`\"`)}"`;
|
|
27790
|
+
}
|
|
27791
|
+
function commandToSkill(name, content) {
|
|
27792
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
27793
|
+
const frontmatter = match ? match[1] : "";
|
|
27794
|
+
const body = match ? content.slice(match[0].length) : content;
|
|
27795
|
+
const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
|
|
27796
|
+
const description = descriptionMatch ? descriptionMatch[1].trim().replace(/^["']|["']$/g, "") : name;
|
|
27797
|
+
const header = `---
|
|
27798
|
+
name: ${name}
|
|
27799
|
+
description: ${quoteYaml(description)}
|
|
27800
|
+
---
|
|
27801
|
+
|
|
27802
|
+
`;
|
|
27803
|
+
return header + body.replace(/^\r?\n+/, "");
|
|
27804
|
+
}
|
|
27805
|
+
function syncCodex(claudeDir, options2) {
|
|
27806
|
+
if (!isHarnessAvailable("codex")) return;
|
|
27807
|
+
const { total, names } = installHarnessCommands(
|
|
27808
|
+
claudeDir,
|
|
27809
|
+
harnesses.codex,
|
|
27810
|
+
commandToSkill
|
|
27811
|
+
);
|
|
27812
|
+
syncCodexHooks(path63.join(claudeDir, "..", "codex", "config.toml"));
|
|
27813
|
+
console.log(
|
|
27814
|
+
`Synced ${total} skill(s) to ~/.codex/skills and CLAUDE.md to ~/.codex/AGENTS.md`
|
|
27815
|
+
);
|
|
27816
|
+
if (!options2?.prune) return;
|
|
27817
|
+
const force = options2.force ?? false;
|
|
27818
|
+
reportPrune(
|
|
27819
|
+
"~/.codex/skills",
|
|
27820
|
+
pruneSkills(path63.join(harnesses.codex.homeDir, "skills"), names, { force }),
|
|
27821
|
+
force
|
|
27822
|
+
);
|
|
27823
|
+
}
|
|
27824
|
+
|
|
27825
|
+
// src/commands/sync/syncDesign.ts
|
|
27826
|
+
import * as fs40 from "fs";
|
|
27827
|
+
import * as path64 from "path";
|
|
27828
|
+
function syncDesign(claudeDir, targetBase) {
|
|
27829
|
+
const systemPromptSource = path64.join(claudeDir, "design-system-prompt.md");
|
|
27830
|
+
const systemPromptTarget = path64.join(targetBase, "design-system-prompt.md");
|
|
27831
|
+
fs40.copyFileSync(systemPromptSource, systemPromptTarget);
|
|
27832
|
+
console.log(
|
|
27833
|
+
"Copied design-system-prompt.md to ~/.claude/design-system-prompt.md"
|
|
27834
|
+
);
|
|
27835
|
+
const skillsSource = path64.join(claudeDir, "skills");
|
|
27836
|
+
const skillsTarget = path64.join(targetBase, "skills");
|
|
27837
|
+
fs40.mkdirSync(skillsTarget, { recursive: true });
|
|
27838
|
+
const files = fs40.readdirSync(skillsSource);
|
|
27839
|
+
for (const file of files) {
|
|
27840
|
+
fs40.copyFileSync(
|
|
27841
|
+
path64.join(skillsSource, file),
|
|
27842
|
+
path64.join(skillsTarget, file)
|
|
27843
|
+
);
|
|
27844
|
+
}
|
|
27845
|
+
console.log(`Synced ${files.length} design skill(s) to ~/.claude/skills`);
|
|
27846
|
+
}
|
|
27847
|
+
|
|
27848
|
+
// src/commands/sync/syncPi.ts
|
|
27849
|
+
import * as path66 from "path";
|
|
27850
|
+
|
|
27851
|
+
// src/commands/sync/syncPiHooks.ts
|
|
27852
|
+
import * as fs41 from "fs";
|
|
27853
|
+
import * as path65 from "path";
|
|
27854
|
+
function piExtensionsDir() {
|
|
27855
|
+
return path65.join(harnesses.pi.homeDir, "extensions");
|
|
27856
|
+
}
|
|
27857
|
+
function syncPiHooks(sourceDir) {
|
|
27858
|
+
const target = piExtensionsDir();
|
|
27859
|
+
fs41.mkdirSync(target, { recursive: true });
|
|
27860
|
+
const files = fs41.readdirSync(sourceDir).filter((f) => f.endsWith(".ts"));
|
|
27861
|
+
for (const file of files) {
|
|
27862
|
+
fs41.copyFileSync(
|
|
27863
|
+
path65.join(sourceDir, file),
|
|
27864
|
+
path65.join(target, `assist-${file}`)
|
|
27865
|
+
);
|
|
27866
|
+
}
|
|
27867
|
+
console.log(
|
|
27868
|
+
`Registered ${files.length} assist extension(s) in ~/.pi/agent/extensions`
|
|
27869
|
+
);
|
|
27870
|
+
}
|
|
27871
|
+
|
|
27872
|
+
// src/commands/sync/syncPi.ts
|
|
27873
|
+
function unquote(value) {
|
|
27874
|
+
return value.trim().replace(/^["']|["']$/g, "");
|
|
27875
|
+
}
|
|
27876
|
+
function commandToPrompt(name, content) {
|
|
27877
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
27878
|
+
const frontmatter = match ? match[1] : "";
|
|
27879
|
+
const body = match ? content.slice(match[0].length) : content;
|
|
27880
|
+
const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
|
|
27881
|
+
const description = descriptionMatch ? unquote(descriptionMatch[1]) : name;
|
|
27882
|
+
const argsMatch = frontmatter.match(/^allowed_args:\s*(.*)$/m);
|
|
27883
|
+
const argumentHint = argsMatch ? unquote(argsMatch[1]) : void 0;
|
|
27884
|
+
const header = [
|
|
27885
|
+
"---",
|
|
27886
|
+
`description: ${description}`,
|
|
27887
|
+
...argumentHint ? [`argument-hint: ${argumentHint}`] : [],
|
|
27888
|
+
"---",
|
|
27889
|
+
"",
|
|
27890
|
+
""
|
|
27891
|
+
].join("\n");
|
|
27892
|
+
return header + body.replace(/^\r?\n+/, "");
|
|
27893
|
+
}
|
|
27894
|
+
function syncPi(claudeDir, options2) {
|
|
27895
|
+
if (!isHarnessAvailable("pi")) return;
|
|
27896
|
+
const { synced, names } = installHarnessCommands(
|
|
27897
|
+
claudeDir,
|
|
27898
|
+
harnesses.pi,
|
|
27899
|
+
commandToPrompt
|
|
27900
|
+
);
|
|
27901
|
+
syncPiHooks(path66.join(claudeDir, "..", "pi"));
|
|
27902
|
+
console.log(
|
|
27903
|
+
`Synced ${synced} prompt(s) to ~/.pi/agent/prompts and CLAUDE.md to ~/.pi/agent/AGENTS.md`
|
|
27904
|
+
);
|
|
27905
|
+
if (!options2?.prune) return;
|
|
27906
|
+
const force = options2.force ?? false;
|
|
27907
|
+
reportPrune(
|
|
27908
|
+
"~/.pi/agent/prompts",
|
|
27909
|
+
pruneCommands(path66.join(harnesses.pi.homeDir, "prompts"), names, { force }),
|
|
27910
|
+
force
|
|
27911
|
+
);
|
|
27912
|
+
}
|
|
27913
|
+
|
|
27914
|
+
// src/commands/sync/syncSettings.ts
|
|
27915
|
+
import * as fs42 from "fs";
|
|
27916
|
+
import * as path67 from "path";
|
|
27917
|
+
import chalk211 from "chalk";
|
|
27918
|
+
async function syncSettings(claudeDir, targetBase, options2) {
|
|
27919
|
+
const source = path67.join(claudeDir, "settings.json");
|
|
27920
|
+
const target = path67.join(targetBase, "settings.json");
|
|
27921
|
+
const sourceContent = fs42.readFileSync(source, "utf8");
|
|
27922
|
+
const sourceSettings = JSON.parse(sourceContent);
|
|
27923
|
+
const targetExists = fs42.existsSync(target);
|
|
27924
|
+
const targetContent = targetExists ? fs42.readFileSync(target, "utf8") : "";
|
|
27925
|
+
const preservedUserSettings = targetExists ? JSON.parse(targetContent) : {};
|
|
27926
|
+
const mergedContent = JSON.stringify(
|
|
27927
|
+
{ ...preservedUserSettings, ...sourceSettings },
|
|
27928
|
+
null,
|
|
27929
|
+
" "
|
|
27930
|
+
);
|
|
27931
|
+
if (targetExists) {
|
|
27932
|
+
const normalizedTarget = JSON.stringify(preservedUserSettings, null, " ");
|
|
27933
|
+
if (mergedContent !== normalizedTarget) {
|
|
27934
|
+
if (!options2?.yes) {
|
|
27935
|
+
console.log(
|
|
27936
|
+
chalk211.yellow(
|
|
27937
|
+
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
27938
|
+
)
|
|
27939
|
+
);
|
|
27940
|
+
console.log();
|
|
27941
|
+
printDiff(targetContent, mergedContent);
|
|
27942
|
+
printAutoConfirmHint();
|
|
27943
|
+
const confirm = await promptConfirm(
|
|
27944
|
+
chalk211.red("Overwrite existing settings.json?"),
|
|
27945
|
+
false
|
|
27946
|
+
);
|
|
27947
|
+
if (!confirm) {
|
|
27948
|
+
console.log("Skipped settings.json");
|
|
27949
|
+
return;
|
|
27950
|
+
}
|
|
27951
|
+
}
|
|
27952
|
+
}
|
|
27953
|
+
}
|
|
27954
|
+
fs42.writeFileSync(target, mergedContent);
|
|
27955
|
+
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
27956
|
+
}
|
|
27957
|
+
|
|
27958
|
+
// src/commands/sync.ts
|
|
27959
|
+
var __filename4 = fileURLToPath7(import.meta.url);
|
|
27960
|
+
var __dirname5 = path68.dirname(__filename4);
|
|
27961
|
+
async function sync(options2) {
|
|
27962
|
+
const config = loadConfig();
|
|
27963
|
+
const yes = options2?.yes ?? config.sync.autoConfirm;
|
|
27964
|
+
const prune = { prune: options2?.prune, force: options2?.force };
|
|
27965
|
+
const claudeDir = path68.join(__dirname5, "..", "claude");
|
|
27966
|
+
const targetBase = path68.join(os4.homedir(), ".claude");
|
|
27967
|
+
const commandFiles = syncCommands(claudeDir, targetBase);
|
|
27968
|
+
syncDesign(claudeDir, targetBase);
|
|
27969
|
+
await syncSettings(claudeDir, targetBase, { yes });
|
|
27970
|
+
await syncClaudeMd(claudeDir, targetBase, { yes });
|
|
27971
|
+
syncCodex(claudeDir, prune);
|
|
27972
|
+
syncPi(claudeDir, prune);
|
|
27973
|
+
if (!options2?.prune) return;
|
|
27974
|
+
const commandNames = commandFiles.filter((file) => file.endsWith(".md")).map((file) => path68.basename(file, ".md"));
|
|
27975
|
+
const force = options2.force ?? false;
|
|
27976
|
+
reportPrune(
|
|
27977
|
+
"~/.claude/commands",
|
|
27978
|
+
pruneCommands(path68.join(targetBase, "commands"), commandNames, { force }),
|
|
27979
|
+
force
|
|
27980
|
+
);
|
|
27981
|
+
}
|
|
27982
|
+
function syncCommands(claudeDir, targetBase) {
|
|
27983
|
+
const sourceDir = path68.join(claudeDir, "commands");
|
|
27984
|
+
const targetDir = path68.join(targetBase, "commands");
|
|
27985
|
+
fs43.mkdirSync(targetDir, { recursive: true });
|
|
27986
|
+
const files = fs43.readdirSync(sourceDir);
|
|
27987
|
+
for (const file of files) {
|
|
27988
|
+
fs43.copyFileSync(path68.join(sourceDir, file), path68.join(targetDir, file));
|
|
27989
|
+
console.log(`Copied ${file} to ${targetDir}`);
|
|
27990
|
+
}
|
|
27991
|
+
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
27992
|
+
return files;
|
|
27993
|
+
}
|
|
27994
|
+
|
|
27995
|
+
// src/commands/registerSync.ts
|
|
27996
|
+
function registerSync(program2) {
|
|
27997
|
+
const syncCommand = program2.command("sync").description(
|
|
27998
|
+
"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. With --prune, also report commands in those target dirs that sync did not write, and with --prune --force remove them"
|
|
27999
|
+
).option("-y, --yes", "Overwrite settings.json without prompting").option(
|
|
28000
|
+
"--prune",
|
|
28001
|
+
"After syncing, list commands in the target dirs whose name is not in the repo's claude/commands/*.md set; subdirectories and non-.md files are listed separately and never removed"
|
|
28002
|
+
).option(
|
|
28003
|
+
"--force",
|
|
28004
|
+
"With --prune, remove the listed orphaned commands; a codex skill directory is removed only when SKILL.md is its sole content. Errors without --prune"
|
|
28005
|
+
).action((options2) => {
|
|
28006
|
+
if (options2.force && !options2.prune) {
|
|
28007
|
+
console.error("--force requires --prune.");
|
|
28008
|
+
process.exit(1);
|
|
28009
|
+
}
|
|
28010
|
+
return sync(options2);
|
|
28011
|
+
});
|
|
28012
|
+
configHelp(syncCommand, rootConfigHelp.sync);
|
|
28013
|
+
}
|
|
28014
|
+
|
|
27551
28015
|
// src/commands/transcript/shared.ts
|
|
27552
28016
|
import * as readline2 from "readline";
|
|
27553
28017
|
function createReadlineInterface() {
|
|
@@ -27619,27 +28083,27 @@ async function configure() {
|
|
|
27619
28083
|
}
|
|
27620
28084
|
|
|
27621
28085
|
// src/commands/transcript/list.ts
|
|
27622
|
-
import { existsSync as
|
|
27623
|
-
import { join as
|
|
28086
|
+
import { existsSync as existsSync57, readdirSync as readdirSync17, statSync as statSync9 } from "fs";
|
|
28087
|
+
import { join as join71 } from "path";
|
|
27624
28088
|
function list4() {
|
|
27625
28089
|
const { vttDir } = getTranscriptConfig();
|
|
27626
|
-
if (!
|
|
27627
|
-
for (const entry of
|
|
28090
|
+
if (!existsSync57(vttDir)) return;
|
|
28091
|
+
for (const entry of readdirSync17(vttDir)) {
|
|
27628
28092
|
if (!entry.endsWith(".vtt")) continue;
|
|
27629
|
-
if (statSync9(
|
|
28093
|
+
if (statSync9(join71(vttDir, entry)).isDirectory()) continue;
|
|
27630
28094
|
console.log(entry);
|
|
27631
28095
|
}
|
|
27632
28096
|
}
|
|
27633
28097
|
|
|
27634
28098
|
// src/commands/transcript/move.ts
|
|
27635
28099
|
import {
|
|
27636
|
-
existsSync as
|
|
27637
|
-
mkdirSync as
|
|
27638
|
-
readFileSync as
|
|
28100
|
+
existsSync as existsSync58,
|
|
28101
|
+
mkdirSync as mkdirSync25,
|
|
28102
|
+
readFileSync as readFileSync47,
|
|
27639
28103
|
renameSync as renameSync2,
|
|
27640
|
-
writeFileSync as
|
|
28104
|
+
writeFileSync as writeFileSync41
|
|
27641
28105
|
} from "fs";
|
|
27642
|
-
import { basename as
|
|
28106
|
+
import { basename as basename19, join as join72 } from "path";
|
|
27643
28107
|
|
|
27644
28108
|
// src/commands/transcript/cleanText.ts
|
|
27645
28109
|
function cleanText(text17) {
|
|
@@ -27847,14 +28311,14 @@ function formatChatLog(messages) {
|
|
|
27847
28311
|
// src/commands/transcript/move.ts
|
|
27848
28312
|
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
27849
28313
|
function convertVttToMarkdown(inputPath) {
|
|
27850
|
-
const cues = parseVtt(
|
|
28314
|
+
const cues = parseVtt(readFileSync47(inputPath, "utf8"));
|
|
27851
28315
|
const messages = cuesToChatMessages(deduplicateCues(cues));
|
|
27852
28316
|
return formatChatLog(messages);
|
|
27853
28317
|
}
|
|
27854
28318
|
function archiveRawVtt(vttDir, sourcePath, filename) {
|
|
27855
|
-
const processedDir =
|
|
27856
|
-
|
|
27857
|
-
renameSync2(sourcePath,
|
|
28319
|
+
const processedDir = join72(vttDir, "processed");
|
|
28320
|
+
mkdirSync25(processedDir, { recursive: true });
|
|
28321
|
+
renameSync2(sourcePath, join72(processedDir, filename));
|
|
27858
28322
|
}
|
|
27859
28323
|
function move(file, options2) {
|
|
27860
28324
|
const { date, client } = options2;
|
|
@@ -27863,20 +28327,20 @@ function move(file, options2) {
|
|
|
27863
28327
|
process.exit(1);
|
|
27864
28328
|
}
|
|
27865
28329
|
const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
27866
|
-
const filename =
|
|
27867
|
-
const sourcePath =
|
|
27868
|
-
if (!
|
|
28330
|
+
const filename = basename19(file);
|
|
28331
|
+
const sourcePath = join72(vttDir, filename);
|
|
28332
|
+
if (!existsSync58(sourcePath)) {
|
|
27869
28333
|
console.error(`Error: VTT file not found: ${sourcePath}`);
|
|
27870
28334
|
process.exit(1);
|
|
27871
28335
|
}
|
|
27872
|
-
const base =
|
|
28336
|
+
const base = basename19(filename, ".vtt").replace(/ Transcription$/, "");
|
|
27873
28337
|
const outputName = `${date} ${base}.md`;
|
|
27874
|
-
const formattedDir =
|
|
27875
|
-
|
|
27876
|
-
const formattedPath =
|
|
27877
|
-
|
|
28338
|
+
const formattedDir = join72(transcriptsDir, client);
|
|
28339
|
+
mkdirSync25(formattedDir, { recursive: true });
|
|
28340
|
+
const formattedPath = join72(formattedDir, outputName);
|
|
28341
|
+
writeFileSync41(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
|
|
27878
28342
|
archiveRawVtt(vttDir, sourcePath, filename);
|
|
27879
|
-
const summaryPath =
|
|
28343
|
+
const summaryPath = join72(summaryDir, client, outputName);
|
|
27880
28344
|
console.log(`Formatted transcript: ${formattedPath}`);
|
|
27881
28345
|
console.log(`Summary target: ${summaryPath}`);
|
|
27882
28346
|
}
|
|
@@ -27958,50 +28422,50 @@ function registerVerify(program2) {
|
|
|
27958
28422
|
|
|
27959
28423
|
// src/commands/voice/devices.ts
|
|
27960
28424
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
27961
|
-
import { join as
|
|
28425
|
+
import { join as join74 } from "path";
|
|
27962
28426
|
|
|
27963
28427
|
// src/commands/voice/shared.ts
|
|
27964
|
-
import { homedir as
|
|
27965
|
-
import { dirname as
|
|
27966
|
-
import { fileURLToPath as
|
|
27967
|
-
var
|
|
27968
|
-
var VOICE_DIR =
|
|
28428
|
+
import { homedir as homedir23 } from "os";
|
|
28429
|
+
import { dirname as dirname34, join as join73 } from "path";
|
|
28430
|
+
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
28431
|
+
var __dirname6 = dirname34(fileURLToPath8(import.meta.url));
|
|
28432
|
+
var VOICE_DIR = join73(homedir23(), ".assist", "voice");
|
|
27969
28433
|
var voicePaths = {
|
|
27970
28434
|
dir: VOICE_DIR,
|
|
27971
|
-
pid:
|
|
27972
|
-
log:
|
|
27973
|
-
venv:
|
|
27974
|
-
lock:
|
|
28435
|
+
pid: join73(VOICE_DIR, "voice.pid"),
|
|
28436
|
+
log: join73(VOICE_DIR, "voice.log"),
|
|
28437
|
+
venv: join73(VOICE_DIR, ".venv"),
|
|
28438
|
+
lock: join73(VOICE_DIR, "voice.lock")
|
|
27975
28439
|
};
|
|
27976
28440
|
function getPythonDir() {
|
|
27977
|
-
return
|
|
28441
|
+
return join73(__dirname6, "commands", "voice", "python");
|
|
27978
28442
|
}
|
|
27979
28443
|
function getVenvPython() {
|
|
27980
|
-
return process.platform === "win32" ?
|
|
28444
|
+
return process.platform === "win32" ? join73(voicePaths.venv, "Scripts", "python.exe") : join73(voicePaths.venv, "bin", "python");
|
|
27981
28445
|
}
|
|
27982
28446
|
function getLockDir() {
|
|
27983
28447
|
const config = loadConfig();
|
|
27984
28448
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
27985
28449
|
}
|
|
27986
28450
|
function getLockFile() {
|
|
27987
|
-
return
|
|
28451
|
+
return join73(getLockDir(), "voice.lock");
|
|
27988
28452
|
}
|
|
27989
28453
|
|
|
27990
28454
|
// src/commands/voice/devices.ts
|
|
27991
28455
|
function devices() {
|
|
27992
|
-
const script =
|
|
28456
|
+
const script = join74(getPythonDir(), "list_devices.py");
|
|
27993
28457
|
spawnSync6(getVenvPython(), [script], { stdio: "inherit" });
|
|
27994
28458
|
}
|
|
27995
28459
|
|
|
27996
28460
|
// src/commands/voice/logs.ts
|
|
27997
|
-
import { existsSync as
|
|
28461
|
+
import { existsSync as existsSync59, readFileSync as readFileSync48 } from "fs";
|
|
27998
28462
|
function logs(options2) {
|
|
27999
|
-
if (!
|
|
28463
|
+
if (!existsSync59(voicePaths.log)) {
|
|
28000
28464
|
console.log("No voice log file found");
|
|
28001
28465
|
return;
|
|
28002
28466
|
}
|
|
28003
28467
|
const count8 = Number.parseInt(options2.lines ?? "150", 10);
|
|
28004
|
-
const content =
|
|
28468
|
+
const content = readFileSync48(voicePaths.log, "utf8").trim();
|
|
28005
28469
|
if (!content) {
|
|
28006
28470
|
console.log("Voice log is empty");
|
|
28007
28471
|
return;
|
|
@@ -28023,13 +28487,13 @@ function logs(options2) {
|
|
|
28023
28487
|
|
|
28024
28488
|
// src/commands/voice/setup.ts
|
|
28025
28489
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
28026
|
-
import { mkdirSync as
|
|
28027
|
-
import { join as
|
|
28490
|
+
import { mkdirSync as mkdirSync27 } from "fs";
|
|
28491
|
+
import { join as join76 } from "path";
|
|
28028
28492
|
|
|
28029
28493
|
// src/commands/voice/checkLockFile.ts
|
|
28030
28494
|
import { execSync as execSync59 } from "child_process";
|
|
28031
|
-
import { existsSync as
|
|
28032
|
-
import { join as
|
|
28495
|
+
import { existsSync as existsSync60, mkdirSync as mkdirSync26, readFileSync as readFileSync49, writeFileSync as writeFileSync42 } from "fs";
|
|
28496
|
+
import { join as join75 } from "path";
|
|
28033
28497
|
function isProcessAlive2(pid) {
|
|
28034
28498
|
try {
|
|
28035
28499
|
process.kill(pid, 0);
|
|
@@ -28040,9 +28504,9 @@ function isProcessAlive2(pid) {
|
|
|
28040
28504
|
}
|
|
28041
28505
|
function checkLockFile() {
|
|
28042
28506
|
const lockFile = getLockFile();
|
|
28043
|
-
if (!
|
|
28507
|
+
if (!existsSync60(lockFile)) return;
|
|
28044
28508
|
try {
|
|
28045
|
-
const lock2 = JSON.parse(
|
|
28509
|
+
const lock2 = JSON.parse(readFileSync49(lockFile, "utf8"));
|
|
28046
28510
|
if (lock2.pid && isProcessAlive2(lock2.pid)) {
|
|
28047
28511
|
console.error(
|
|
28048
28512
|
`Voice daemon already running (PID ${lock2.pid}, env: ${lock2.env}). Stop it first with: assist voice stop`
|
|
@@ -28053,7 +28517,7 @@ function checkLockFile() {
|
|
|
28053
28517
|
}
|
|
28054
28518
|
}
|
|
28055
28519
|
function bootstrapVenv() {
|
|
28056
|
-
if (
|
|
28520
|
+
if (existsSync60(getVenvPython())) return;
|
|
28057
28521
|
console.log("Setting up Python environment...");
|
|
28058
28522
|
const pythonDir = getPythonDir();
|
|
28059
28523
|
execSync59(
|
|
@@ -28066,8 +28530,8 @@ function bootstrapVenv() {
|
|
|
28066
28530
|
}
|
|
28067
28531
|
function writeLockFile(pid) {
|
|
28068
28532
|
const lockFile = getLockFile();
|
|
28069
|
-
|
|
28070
|
-
|
|
28533
|
+
mkdirSync26(join75(lockFile, ".."), { recursive: true });
|
|
28534
|
+
writeFileSync42(
|
|
28071
28535
|
lockFile,
|
|
28072
28536
|
JSON.stringify({
|
|
28073
28537
|
pid,
|
|
@@ -28079,10 +28543,10 @@ function writeLockFile(pid) {
|
|
|
28079
28543
|
|
|
28080
28544
|
// src/commands/voice/setup.ts
|
|
28081
28545
|
function setup() {
|
|
28082
|
-
|
|
28546
|
+
mkdirSync27(voicePaths.dir, { recursive: true });
|
|
28083
28547
|
bootstrapVenv();
|
|
28084
28548
|
console.log("\nDownloading models...\n");
|
|
28085
|
-
const script =
|
|
28549
|
+
const script = join76(getPythonDir(), "setup_models.py");
|
|
28086
28550
|
const result = spawnSync7(getVenvPython(), [script], {
|
|
28087
28551
|
stdio: "inherit",
|
|
28088
28552
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -28095,8 +28559,8 @@ function setup() {
|
|
|
28095
28559
|
|
|
28096
28560
|
// src/commands/voice/start.ts
|
|
28097
28561
|
import { spawn as spawn8 } from "child_process";
|
|
28098
|
-
import { mkdirSync as
|
|
28099
|
-
import { join as
|
|
28562
|
+
import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync43 } from "fs";
|
|
28563
|
+
import { join as join77 } from "path";
|
|
28100
28564
|
|
|
28101
28565
|
// src/commands/voice/buildDaemonEnv.ts
|
|
28102
28566
|
function buildDaemonEnv(options2) {
|
|
@@ -28124,17 +28588,17 @@ function spawnBackground(python, script, env) {
|
|
|
28124
28588
|
console.error("Failed to start voice daemon");
|
|
28125
28589
|
process.exit(1);
|
|
28126
28590
|
}
|
|
28127
|
-
|
|
28591
|
+
writeFileSync43(voicePaths.pid, String(pid));
|
|
28128
28592
|
writeLockFile(pid);
|
|
28129
28593
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
28130
28594
|
}
|
|
28131
28595
|
function start2(options2) {
|
|
28132
|
-
|
|
28596
|
+
mkdirSync28(voicePaths.dir, { recursive: true });
|
|
28133
28597
|
checkLockFile();
|
|
28134
28598
|
bootstrapVenv();
|
|
28135
28599
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
28136
28600
|
const env = buildDaemonEnv({ debug });
|
|
28137
|
-
const script =
|
|
28601
|
+
const script = join77(getPythonDir(), "voice_daemon.py");
|
|
28138
28602
|
const python = getVenvPython();
|
|
28139
28603
|
if (options2.foreground) {
|
|
28140
28604
|
spawnForeground(python, script, env);
|
|
@@ -28144,7 +28608,7 @@ function start2(options2) {
|
|
|
28144
28608
|
}
|
|
28145
28609
|
|
|
28146
28610
|
// src/commands/voice/status.ts
|
|
28147
|
-
import { existsSync as
|
|
28611
|
+
import { existsSync as existsSync61, readFileSync as readFileSync50 } from "fs";
|
|
28148
28612
|
function isProcessAlive3(pid) {
|
|
28149
28613
|
try {
|
|
28150
28614
|
process.kill(pid, 0);
|
|
@@ -28154,16 +28618,16 @@ function isProcessAlive3(pid) {
|
|
|
28154
28618
|
}
|
|
28155
28619
|
}
|
|
28156
28620
|
function readRecentLogs(count8) {
|
|
28157
|
-
if (!
|
|
28158
|
-
const lines2 =
|
|
28621
|
+
if (!existsSync61(voicePaths.log)) return [];
|
|
28622
|
+
const lines2 = readFileSync50(voicePaths.log, "utf8").trim().split("\n");
|
|
28159
28623
|
return lines2.slice(-count8);
|
|
28160
28624
|
}
|
|
28161
28625
|
function status2() {
|
|
28162
|
-
if (!
|
|
28626
|
+
if (!existsSync61(voicePaths.pid)) {
|
|
28163
28627
|
console.log("Voice daemon: not running (no PID file)");
|
|
28164
28628
|
return;
|
|
28165
28629
|
}
|
|
28166
|
-
const pid = Number.parseInt(
|
|
28630
|
+
const pid = Number.parseInt(readFileSync50(voicePaths.pid, "utf8").trim(), 10);
|
|
28167
28631
|
const alive = isProcessAlive3(pid);
|
|
28168
28632
|
console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
|
|
28169
28633
|
const recent = readRecentLogs(5);
|
|
@@ -28182,13 +28646,13 @@ function status2() {
|
|
|
28182
28646
|
}
|
|
28183
28647
|
|
|
28184
28648
|
// src/commands/voice/stop.ts
|
|
28185
|
-
import { existsSync as
|
|
28649
|
+
import { existsSync as existsSync62, readFileSync as readFileSync51, unlinkSync as unlinkSync20 } from "fs";
|
|
28186
28650
|
function stop2() {
|
|
28187
|
-
if (!
|
|
28651
|
+
if (!existsSync62(voicePaths.pid)) {
|
|
28188
28652
|
console.log("Voice daemon is not running (no PID file)");
|
|
28189
28653
|
return;
|
|
28190
28654
|
}
|
|
28191
|
-
const pid = Number.parseInt(
|
|
28655
|
+
const pid = Number.parseInt(readFileSync51(voicePaths.pid, "utf8").trim(), 10);
|
|
28192
28656
|
try {
|
|
28193
28657
|
process.kill(pid, "SIGTERM");
|
|
28194
28658
|
console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
|
|
@@ -28201,7 +28665,7 @@ function stop2() {
|
|
|
28201
28665
|
}
|
|
28202
28666
|
try {
|
|
28203
28667
|
const lockFile = getLockFile();
|
|
28204
|
-
if (
|
|
28668
|
+
if (existsSync62(lockFile)) unlinkSync20(lockFile);
|
|
28205
28669
|
} catch {
|
|
28206
28670
|
}
|
|
28207
28671
|
console.log("Voice daemon stopped");
|
|
@@ -28220,7 +28684,7 @@ function registerVoice(program2) {
|
|
|
28220
28684
|
}
|
|
28221
28685
|
|
|
28222
28686
|
// src/commands/watch/readBuiltVersion.ts
|
|
28223
|
-
import { join as
|
|
28687
|
+
import { join as join78 } from "path";
|
|
28224
28688
|
|
|
28225
28689
|
// src/commands/watch/resolveUpstream.ts
|
|
28226
28690
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
@@ -28266,7 +28730,7 @@ function resolveUpstream(cwd) {
|
|
|
28266
28730
|
function readBuiltVersion(cwd) {
|
|
28267
28731
|
try {
|
|
28268
28732
|
const root = runGit2(["rev-parse", "--show-toplevel"], cwd);
|
|
28269
|
-
return readPackageJson(
|
|
28733
|
+
return readPackageJson(join78(root, "package.json")).version ?? "unknown";
|
|
28270
28734
|
} catch {
|
|
28271
28735
|
return "unknown";
|
|
28272
28736
|
}
|
|
@@ -28318,11 +28782,11 @@ var webUiPrefix = "src/commands/sessions/web/ui/";
|
|
|
28318
28782
|
var sessionsPrefix = "src/commands/sessions/";
|
|
28319
28783
|
var rules = [
|
|
28320
28784
|
{
|
|
28321
|
-
matches: (
|
|
28785
|
+
matches: (path73) => path73.startsWith(webUiPrefix),
|
|
28322
28786
|
advice: "restart the web server, then hard-reload the browser tab"
|
|
28323
28787
|
},
|
|
28324
28788
|
{
|
|
28325
|
-
matches: (
|
|
28789
|
+
matches: (path73) => path73.startsWith(sessionsPrefix) && !path73.startsWith(webUiPrefix),
|
|
28326
28790
|
advice: "restart the daemon"
|
|
28327
28791
|
}
|
|
28328
28792
|
];
|
|
@@ -28564,7 +29028,7 @@ function resolveParams(params, cliArgs) {
|
|
|
28564
29028
|
}
|
|
28565
29029
|
|
|
28566
29030
|
// src/commands/run/resolveRunCwd.ts
|
|
28567
|
-
import { existsSync as
|
|
29031
|
+
import { existsSync as existsSync63 } from "fs";
|
|
28568
29032
|
import { resolve as resolve17 } from "path";
|
|
28569
29033
|
var MissingRunCwdError = class extends Error {
|
|
28570
29034
|
constructor(runName, cwd) {
|
|
@@ -28577,25 +29041,25 @@ var MissingRunCwdError = class extends Error {
|
|
|
28577
29041
|
function resolveRunCwd(config, baseDir = runConfigBaseDir()) {
|
|
28578
29042
|
if (!config.cwd) return void 0;
|
|
28579
29043
|
const cwd = resolve17(baseDir, config.cwd);
|
|
28580
|
-
if (!
|
|
29044
|
+
if (!existsSync63(cwd)) throw new MissingRunCwdError(config.name, cwd);
|
|
28581
29045
|
return cwd;
|
|
28582
29046
|
}
|
|
28583
29047
|
|
|
28584
29048
|
// src/commands/run/runCommandToCompletion.ts
|
|
28585
29049
|
import { spawn as spawn9 } from "child_process";
|
|
28586
|
-
import { existsSync as
|
|
29050
|
+
import { existsSync as existsSync65 } from "fs";
|
|
28587
29051
|
|
|
28588
29052
|
// src/commands/run/resolveCommand.ts
|
|
28589
29053
|
import { execFileSync as execFileSync11 } from "child_process";
|
|
28590
|
-
import { existsSync as
|
|
28591
|
-
import { dirname as
|
|
29054
|
+
import { existsSync as existsSync64 } from "fs";
|
|
29055
|
+
import { dirname as dirname35, join as join79, resolve as resolve18 } from "path";
|
|
28592
29056
|
function resolveCommand2(command) {
|
|
28593
29057
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
28594
29058
|
try {
|
|
28595
29059
|
const gitPath = execFileSync11("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
28596
|
-
const gitRoot = resolve18(
|
|
28597
|
-
const gitBash =
|
|
28598
|
-
if (
|
|
29060
|
+
const gitRoot = resolve18(dirname35(gitPath), "..");
|
|
29061
|
+
const gitBash = join79(gitRoot, "bin", "bash.exe");
|
|
29062
|
+
if (existsSync64(gitBash)) return gitBash;
|
|
28599
29063
|
} catch {
|
|
28600
29064
|
return command;
|
|
28601
29065
|
}
|
|
@@ -28605,7 +29069,7 @@ function resolveCommand2(command) {
|
|
|
28605
29069
|
// src/commands/run/runCommandToCompletion.ts
|
|
28606
29070
|
function runCommandToCompletion(command, args, env, cwd, quiet) {
|
|
28607
29071
|
return new Promise((resolveResult) => {
|
|
28608
|
-
if (cwd && !
|
|
29072
|
+
if (cwd && !existsSync65(cwd)) {
|
|
28609
29073
|
resolveResult({
|
|
28610
29074
|
kind: "failed",
|
|
28611
29075
|
message: `Failed to execute command: cwd ${cwd} does not exist`
|
|
@@ -28835,7 +29299,7 @@ function registerWatch(program2) {
|
|
|
28835
29299
|
|
|
28836
29300
|
// src/commands/roam/auth.ts
|
|
28837
29301
|
import { randomBytes } from "crypto";
|
|
28838
|
-
import
|
|
29302
|
+
import chalk212 from "chalk";
|
|
28839
29303
|
|
|
28840
29304
|
// src/commands/roam/waitForCallback.ts
|
|
28841
29305
|
import { createServer as createServer3 } from "http";
|
|
@@ -28966,13 +29430,13 @@ async function auth() {
|
|
|
28966
29430
|
saveGlobalConfig(config);
|
|
28967
29431
|
const state = randomBytes(16).toString("hex");
|
|
28968
29432
|
console.log(
|
|
28969
|
-
|
|
29433
|
+
chalk212.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
28970
29434
|
);
|
|
28971
|
-
console.log(
|
|
28972
|
-
console.log(
|
|
28973
|
-
console.log(
|
|
29435
|
+
console.log(chalk212.white("http://localhost:14523/callback\n"));
|
|
29436
|
+
console.log(chalk212.blue("Opening browser for authorization..."));
|
|
29437
|
+
console.log(chalk212.dim("Waiting for authorization callback..."));
|
|
28974
29438
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
28975
|
-
console.log(
|
|
29439
|
+
console.log(chalk212.dim("Exchanging code for tokens..."));
|
|
28976
29440
|
const tokens = await exchangeToken({
|
|
28977
29441
|
code,
|
|
28978
29442
|
clientId,
|
|
@@ -28988,25 +29452,25 @@ async function auth() {
|
|
|
28988
29452
|
};
|
|
28989
29453
|
saveGlobalConfig(config);
|
|
28990
29454
|
console.log(
|
|
28991
|
-
|
|
29455
|
+
chalk212.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
28992
29456
|
);
|
|
28993
29457
|
}
|
|
28994
29458
|
|
|
28995
29459
|
// src/commands/roam/postRoamActivity.ts
|
|
28996
29460
|
import { execFileSync as execFileSync13 } from "child_process";
|
|
28997
|
-
import { readdirSync as
|
|
28998
|
-
import { join as
|
|
29461
|
+
import { readdirSync as readdirSync18, readFileSync as readFileSync52, statSync as statSync10 } from "fs";
|
|
29462
|
+
import { join as join80 } from "path";
|
|
28999
29463
|
function findPortFile(roamDir) {
|
|
29000
29464
|
let entries;
|
|
29001
29465
|
try {
|
|
29002
|
-
entries =
|
|
29466
|
+
entries = readdirSync18(roamDir);
|
|
29003
29467
|
} catch {
|
|
29004
29468
|
return void 0;
|
|
29005
29469
|
}
|
|
29006
29470
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
29007
|
-
const
|
|
29471
|
+
const path73 = join80(roamDir, name);
|
|
29008
29472
|
try {
|
|
29009
|
-
return { path:
|
|
29473
|
+
return { path: path73, mtimeMs: statSync10(path73).mtimeMs };
|
|
29010
29474
|
} catch {
|
|
29011
29475
|
return void 0;
|
|
29012
29476
|
}
|
|
@@ -29016,11 +29480,11 @@ function findPortFile(roamDir) {
|
|
|
29016
29480
|
function postRoamActivity(app, event) {
|
|
29017
29481
|
const appData = process.env.APPDATA;
|
|
29018
29482
|
if (!appData) return;
|
|
29019
|
-
const portFile = findPortFile(
|
|
29483
|
+
const portFile = findPortFile(join80(appData, "Roam"));
|
|
29020
29484
|
if (!portFile) return;
|
|
29021
29485
|
let port;
|
|
29022
29486
|
try {
|
|
29023
|
-
port =
|
|
29487
|
+
port = readFileSync52(portFile, "utf8").trim();
|
|
29024
29488
|
} catch {
|
|
29025
29489
|
return;
|
|
29026
29490
|
}
|
|
@@ -29148,8 +29612,8 @@ async function run3(name, args) {
|
|
|
29148
29612
|
}
|
|
29149
29613
|
|
|
29150
29614
|
// src/commands/run/add.ts
|
|
29151
|
-
import { mkdirSync as
|
|
29152
|
-
import { join as
|
|
29615
|
+
import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync44 } from "fs";
|
|
29616
|
+
import { join as join81 } from "path";
|
|
29153
29617
|
|
|
29154
29618
|
// src/commands/run/extractOption.ts
|
|
29155
29619
|
function extractOption(args, flag) {
|
|
@@ -29210,16 +29674,16 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
29210
29674
|
saveConfig(config);
|
|
29211
29675
|
}
|
|
29212
29676
|
function createCommandFile(name) {
|
|
29213
|
-
const dir =
|
|
29214
|
-
|
|
29677
|
+
const dir = join81(".claude", "commands");
|
|
29678
|
+
mkdirSync29(dir, { recursive: true });
|
|
29215
29679
|
const content = `---
|
|
29216
29680
|
description: Run ${name}
|
|
29217
29681
|
---
|
|
29218
29682
|
|
|
29219
29683
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
29220
29684
|
`;
|
|
29221
|
-
const filePath =
|
|
29222
|
-
|
|
29685
|
+
const filePath = join81(dir, `${name}.md`);
|
|
29686
|
+
writeFileSync44(filePath, content);
|
|
29223
29687
|
console.log(`Created command file: ${filePath}`);
|
|
29224
29688
|
}
|
|
29225
29689
|
function add3() {
|
|
@@ -29242,11 +29706,11 @@ function findLinkIndex() {
|
|
|
29242
29706
|
function parseLinkArgs() {
|
|
29243
29707
|
const idx = findLinkIndex();
|
|
29244
29708
|
if (idx === -1) return null;
|
|
29245
|
-
const
|
|
29709
|
+
const path73 = process.argv[idx + 1];
|
|
29246
29710
|
const rest = process.argv.slice(idx + 2);
|
|
29247
29711
|
const { value: prefix2 } = extractOption(rest, "--prefix");
|
|
29248
29712
|
if (!prefix2) return null;
|
|
29249
|
-
return { path:
|
|
29713
|
+
return { path: path73, prefix: prefix2 };
|
|
29250
29714
|
}
|
|
29251
29715
|
function hasDuplicateLink(runList, linkPath) {
|
|
29252
29716
|
return runList.some(
|
|
@@ -29274,8 +29738,8 @@ function link2() {
|
|
|
29274
29738
|
}
|
|
29275
29739
|
|
|
29276
29740
|
// src/commands/run/remove.ts
|
|
29277
|
-
import { existsSync as
|
|
29278
|
-
import { join as
|
|
29741
|
+
import { existsSync as existsSync66, unlinkSync as unlinkSync21 } from "fs";
|
|
29742
|
+
import { join as join82 } from "path";
|
|
29279
29743
|
function findRemoveIndex() {
|
|
29280
29744
|
const idx = process.argv.indexOf("remove");
|
|
29281
29745
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -29290,8 +29754,8 @@ function parseRemoveName() {
|
|
|
29290
29754
|
return process.argv[idx + 1];
|
|
29291
29755
|
}
|
|
29292
29756
|
function deleteCommandFile(name) {
|
|
29293
|
-
const filePath =
|
|
29294
|
-
if (
|
|
29757
|
+
const filePath = join82(".claude", "commands", `${name}.md`);
|
|
29758
|
+
if (existsSync66(filePath)) {
|
|
29295
29759
|
unlinkSync21(filePath);
|
|
29296
29760
|
console.log(`Deleted command file: ${filePath}`);
|
|
29297
29761
|
}
|
|
@@ -29336,10 +29800,10 @@ function registerRun(program2) {
|
|
|
29336
29800
|
|
|
29337
29801
|
// src/commands/screenshot/index.ts
|
|
29338
29802
|
import { execSync as execSync61 } from "child_process";
|
|
29339
|
-
import { existsSync as
|
|
29803
|
+
import { existsSync as existsSync67, mkdirSync as mkdirSync30, unlinkSync as unlinkSync22, writeFileSync as writeFileSync45 } from "fs";
|
|
29340
29804
|
import { tmpdir as tmpdir8 } from "os";
|
|
29341
|
-
import { join as
|
|
29342
|
-
import
|
|
29805
|
+
import { join as join83, resolve as resolve19 } from "path";
|
|
29806
|
+
import chalk213 from "chalk";
|
|
29343
29807
|
|
|
29344
29808
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
29345
29809
|
var captureWindowPs1 = `
|
|
@@ -29468,15 +29932,15 @@ Write-Output $OutputPath
|
|
|
29468
29932
|
|
|
29469
29933
|
// src/commands/screenshot/index.ts
|
|
29470
29934
|
function buildOutputPath(outputDir, processName) {
|
|
29471
|
-
if (!
|
|
29472
|
-
|
|
29935
|
+
if (!existsSync67(outputDir)) {
|
|
29936
|
+
mkdirSync30(outputDir, { recursive: true });
|
|
29473
29937
|
}
|
|
29474
29938
|
const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
29475
29939
|
return resolve19(outputDir, `${processName}-${timestamp6}.png`);
|
|
29476
29940
|
}
|
|
29477
29941
|
function runPowerShellScript(processName, outputPath) {
|
|
29478
|
-
const scriptPath =
|
|
29479
|
-
|
|
29942
|
+
const scriptPath = join83(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
|
|
29943
|
+
writeFileSync45(scriptPath, captureWindowPs1, "utf8");
|
|
29480
29944
|
try {
|
|
29481
29945
|
execSync61(
|
|
29482
29946
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
@@ -29490,13 +29954,13 @@ function screenshot(processName) {
|
|
|
29490
29954
|
const config = loadConfig();
|
|
29491
29955
|
const outputDir = resolve19(config.screenshot.outputDir);
|
|
29492
29956
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
29493
|
-
console.log(
|
|
29957
|
+
console.log(chalk213.gray(`Capturing window for process "${processName}" ...`));
|
|
29494
29958
|
try {
|
|
29495
29959
|
runPowerShellScript(processName, outputPath);
|
|
29496
|
-
console.log(
|
|
29960
|
+
console.log(chalk213.green(`Screenshot saved: ${outputPath}`));
|
|
29497
29961
|
} catch (error) {
|
|
29498
29962
|
const msg = error instanceof Error ? error.message : String(error);
|
|
29499
|
-
console.error(
|
|
29963
|
+
console.error(chalk213.red(`Failed to capture screenshot: ${msg}`));
|
|
29500
29964
|
process.exit(1);
|
|
29501
29965
|
}
|
|
29502
29966
|
}
|
|
@@ -29552,7 +30016,7 @@ function applyLine(result, pending, line) {
|
|
|
29552
30016
|
}
|
|
29553
30017
|
|
|
29554
30018
|
// src/commands/sessions/daemon/reportStolenSocket.ts
|
|
29555
|
-
import { readFileSync as
|
|
30019
|
+
import { readFileSync as readFileSync53 } from "fs";
|
|
29556
30020
|
function reportStolenSocket(socketPid) {
|
|
29557
30021
|
if (!socketPid) return;
|
|
29558
30022
|
const filePid = readPidFile();
|
|
@@ -29564,7 +30028,7 @@ function reportStolenSocket(socketPid) {
|
|
|
29564
30028
|
function readPidFile() {
|
|
29565
30029
|
try {
|
|
29566
30030
|
const pid = Number.parseInt(
|
|
29567
|
-
|
|
30031
|
+
readFileSync53(daemonPaths.pid, "utf8").trim(),
|
|
29568
30032
|
10
|
|
29569
30033
|
);
|
|
29570
30034
|
return Number.isInteger(pid) ? pid : void 0;
|
|
@@ -29699,7 +30163,7 @@ function requestDrain(socket, lines2) {
|
|
|
29699
30163
|
}
|
|
29700
30164
|
|
|
29701
30165
|
// src/commands/sessions/daemon/runDaemon.ts
|
|
29702
|
-
import { mkdirSync as
|
|
30166
|
+
import { mkdirSync as mkdirSync34 } from "fs";
|
|
29703
30167
|
|
|
29704
30168
|
// src/commands/sessions/daemon/createAutoExit.ts
|
|
29705
30169
|
var DEFAULT_GRACE_MS = 6e4;
|
|
@@ -29962,42 +30426,42 @@ function serverRunMeta(runName, cwd) {
|
|
|
29962
30426
|
}
|
|
29963
30427
|
|
|
29964
30428
|
// src/commands/sessions/daemon/readDesignSystemPrompt.ts
|
|
29965
|
-
import * as
|
|
29966
|
-
import * as
|
|
29967
|
-
import { fileURLToPath as
|
|
29968
|
-
var
|
|
29969
|
-
var
|
|
30429
|
+
import * as fs44 from "fs";
|
|
30430
|
+
import * as path69 from "path";
|
|
30431
|
+
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
30432
|
+
var __filename5 = fileURLToPath9(import.meta.url);
|
|
30433
|
+
var __dirname7 = path69.dirname(__filename5);
|
|
29970
30434
|
function readDesignSystemPrompt() {
|
|
29971
|
-
const promptPath =
|
|
29972
|
-
|
|
30435
|
+
const promptPath = path69.join(
|
|
30436
|
+
__dirname7,
|
|
29973
30437
|
"..",
|
|
29974
30438
|
"claude",
|
|
29975
30439
|
"design-system-prompt.md"
|
|
29976
30440
|
);
|
|
29977
|
-
return
|
|
30441
|
+
return fs44.readFileSync(promptPath, "utf8");
|
|
29978
30442
|
}
|
|
29979
30443
|
|
|
29980
30444
|
// src/commands/sessions/daemon/spawnPty.ts
|
|
29981
|
-
import { existsSync as
|
|
30445
|
+
import { existsSync as existsSync69 } from "fs";
|
|
29982
30446
|
import * as pty from "node-pty";
|
|
29983
30447
|
|
|
29984
30448
|
// src/commands/sessions/daemon/ensureSpawnHelperExecutable.ts
|
|
29985
|
-
import { chmodSync, existsSync as
|
|
30449
|
+
import { chmodSync, existsSync as existsSync68, statSync as statSync11 } from "fs";
|
|
29986
30450
|
import { createRequire as createRequire3 } from "module";
|
|
29987
|
-
import
|
|
30451
|
+
import path70 from "path";
|
|
29988
30452
|
var require4 = createRequire3(import.meta.url);
|
|
29989
30453
|
var ensured = false;
|
|
29990
30454
|
function ensureSpawnHelperExecutable() {
|
|
29991
30455
|
if (ensured || process.platform !== "darwin") return;
|
|
29992
30456
|
ensured = true;
|
|
29993
|
-
const ptyRoot =
|
|
29994
|
-
const helper =
|
|
30457
|
+
const ptyRoot = path70.join(path70.dirname(require4.resolve("node-pty")), "..");
|
|
30458
|
+
const helper = path70.join(
|
|
29995
30459
|
ptyRoot,
|
|
29996
30460
|
"prebuilds",
|
|
29997
30461
|
`${process.platform}-${process.arch}`,
|
|
29998
30462
|
"spawn-helper"
|
|
29999
30463
|
);
|
|
30000
|
-
if (!
|
|
30464
|
+
if (!existsSync68(helper)) return;
|
|
30001
30465
|
const mode = statSync11(helper).mode;
|
|
30002
30466
|
if ((mode & 73) === 0) chmodSync(helper, mode | 493);
|
|
30003
30467
|
}
|
|
@@ -30033,7 +30497,7 @@ function spawnPty(args, cwd, sessionId, extraEnv) {
|
|
|
30033
30497
|
});
|
|
30034
30498
|
}
|
|
30035
30499
|
function refuseMissingCwd(cwd, sessionId) {
|
|
30036
|
-
if (!cwd ||
|
|
30500
|
+
if (!cwd || existsSync69(cwd)) return;
|
|
30037
30501
|
daemonLog(
|
|
30038
30502
|
`${sessionId ? `session ${sessionId}` : "pty"} not spawned: working directory ${cwd} no longer exists`
|
|
30039
30503
|
);
|
|
@@ -30164,17 +30628,17 @@ function setStatus2(session, newStatus) {
|
|
|
30164
30628
|
}
|
|
30165
30629
|
|
|
30166
30630
|
// src/commands/sessions/daemon/worktree/reapWorktree.ts
|
|
30167
|
-
import { existsSync as
|
|
30168
|
-
import { basename as
|
|
30631
|
+
import { existsSync as existsSync71 } from "fs";
|
|
30632
|
+
import { basename as basename20 } from "path";
|
|
30169
30633
|
|
|
30170
30634
|
// src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
|
|
30171
|
-
import { existsSync as
|
|
30172
|
-
import { join as
|
|
30635
|
+
import { existsSync as existsSync70 } from "fs";
|
|
30636
|
+
import { join as join86 } from "path";
|
|
30173
30637
|
|
|
30174
30638
|
// src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
|
|
30175
30639
|
import { statSync as statSync12 } from "fs";
|
|
30176
30640
|
import { rm as rm2 } from "fs/promises";
|
|
30177
|
-
import { join as
|
|
30641
|
+
import { join as join85 } from "path";
|
|
30178
30642
|
async function deleteTreeDirectly(clone, worktreePath, why) {
|
|
30179
30643
|
if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
|
|
30180
30644
|
const refusal = "it is a clone of its own, not a linked worktree";
|
|
@@ -30202,7 +30666,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
|
|
|
30202
30666
|
return { removed: true };
|
|
30203
30667
|
}
|
|
30204
30668
|
function holdsAGitDirectoryRatherThanALink(worktreePath) {
|
|
30205
|
-
return statSync12(
|
|
30669
|
+
return statSync12(join85(worktreePath, ".git"), {
|
|
30206
30670
|
throwIfNoEntry: false
|
|
30207
30671
|
})?.isDirectory() === true;
|
|
30208
30672
|
}
|
|
@@ -30238,7 +30702,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
|
|
|
30238
30702
|
);
|
|
30239
30703
|
}
|
|
30240
30704
|
function strandedReason(worktreePath, cause) {
|
|
30241
|
-
if (!
|
|
30705
|
+
if (!existsSync70(join86(worktreePath, ".git")))
|
|
30242
30706
|
return "its .git link is already gone";
|
|
30243
30707
|
if (/not a working tree|not a git repository/i.test(reason2(cause)))
|
|
30244
30708
|
return "git no longer recognises it as a working tree";
|
|
@@ -30290,7 +30754,7 @@ function reason3(error) {
|
|
|
30290
30754
|
|
|
30291
30755
|
// src/commands/sessions/daemon/worktree/reapWorktree.ts
|
|
30292
30756
|
async function reapWorktree(worktreePath, force = false) {
|
|
30293
|
-
if (!
|
|
30757
|
+
if (!existsSync71(worktreePath)) {
|
|
30294
30758
|
forgetWorktree(worktreePath);
|
|
30295
30759
|
daemonLog(
|
|
30296
30760
|
`worktree ${worktreePath} already gone; its record was forgotten`
|
|
@@ -30308,14 +30772,14 @@ async function reapWorktree(worktreePath, force = false) {
|
|
|
30308
30772
|
const clone = owningClone(worktreePath);
|
|
30309
30773
|
const removal = await removeTree(clone, worktreePath, force);
|
|
30310
30774
|
if (!removal.removed) return removal;
|
|
30311
|
-
await deleteWorktreeBranch(clone,
|
|
30775
|
+
await deleteWorktreeBranch(clone, basename20(worktreePath));
|
|
30312
30776
|
forgetWorktree(worktreePath);
|
|
30313
30777
|
daemonLog(`worktree ${worktreePath} reaped${force ? " (forced)" : ""}`);
|
|
30314
30778
|
return removal;
|
|
30315
30779
|
}
|
|
30316
30780
|
function owningClone(worktreePath) {
|
|
30317
30781
|
const recorded = worktreeAttributionIncludingReaped(worktreePath)?.clone;
|
|
30318
|
-
if (recorded &&
|
|
30782
|
+
if (recorded && existsSync71(recorded)) return recorded;
|
|
30319
30783
|
const detected = mainWorktree(worktreePath);
|
|
30320
30784
|
if (detected) return detected;
|
|
30321
30785
|
daemonLog(
|
|
@@ -30443,12 +30907,12 @@ function closeGateApplies(sessions, session) {
|
|
|
30443
30907
|
}
|
|
30444
30908
|
|
|
30445
30909
|
// src/commands/sessions/daemon/worktree/watchGitState.ts
|
|
30446
|
-
import { existsSync as
|
|
30910
|
+
import { existsSync as existsSync72, watch } from "fs";
|
|
30447
30911
|
var DEBOUNCE_MS = 500;
|
|
30448
30912
|
var POLL_MS = 3e4;
|
|
30449
30913
|
function watchGitState(cwd, onChange) {
|
|
30450
30914
|
const common = gitCommonDir(cwd);
|
|
30451
|
-
if (!common || !
|
|
30915
|
+
if (!common || !existsSync72(common)) return void 0;
|
|
30452
30916
|
const watchers = [
|
|
30453
30917
|
watchGitDir(common, onChange),
|
|
30454
30918
|
pollGitState(cwd, onChange)
|
|
@@ -30893,10 +31357,10 @@ function emitSessionOutput(session, clients, data) {
|
|
|
30893
31357
|
}
|
|
30894
31358
|
|
|
30895
31359
|
// src/commands/sessions/daemon/exitReason.ts
|
|
30896
|
-
import { existsSync as
|
|
31360
|
+
import { existsSync as existsSync73 } from "fs";
|
|
30897
31361
|
import { resolve as resolve20 } from "path";
|
|
30898
31362
|
function exitDetail(session) {
|
|
30899
|
-
if (session.cwd && !
|
|
31363
|
+
if (session.cwd && !existsSync73(session.cwd))
|
|
30900
31364
|
return `working directory ${session.cwd} no longer exists`;
|
|
30901
31365
|
return missingRunConfigCwd(session);
|
|
30902
31366
|
}
|
|
@@ -30910,7 +31374,7 @@ function missingRunConfigCwd(session) {
|
|
|
30910
31374
|
const config = resolveRunConfig(session.runName, dir);
|
|
30911
31375
|
if (!config?.cwd) return void 0;
|
|
30912
31376
|
const configured = resolve20(runConfigBaseDirFrom(dir), config.cwd);
|
|
30913
|
-
if (
|
|
31377
|
+
if (existsSync73(configured)) return void 0;
|
|
30914
31378
|
return `run config "${config.name}": cwd ${configured} does not exist`;
|
|
30915
31379
|
}
|
|
30916
31380
|
|
|
@@ -30927,8 +31391,16 @@ function handleFailedResume(session, exitCode, onStatusChange) {
|
|
|
30927
31391
|
}
|
|
30928
31392
|
|
|
30929
31393
|
// src/commands/sessions/daemon/watchActivity.ts
|
|
30930
|
-
import { existsSync as
|
|
30931
|
-
import { dirname as
|
|
31394
|
+
import { existsSync as existsSync74, mkdirSync as mkdirSync31, watch as watch2 } from "fs";
|
|
31395
|
+
import { dirname as dirname37 } from "path";
|
|
31396
|
+
|
|
31397
|
+
// src/commands/sessions/daemon/applyActivityToSession.ts
|
|
31398
|
+
function applyActivityToSession(session, activity2) {
|
|
31399
|
+
session.activity = activity2;
|
|
31400
|
+
if (activity2.harness) session.harness = activity2.harness;
|
|
31401
|
+
if (activity2.claudeSessionId)
|
|
31402
|
+
session.claudeSessionId = activity2.claudeSessionId;
|
|
31403
|
+
}
|
|
30932
31404
|
|
|
30933
31405
|
// src/commands/sessions/daemon/applyReviewPause.ts
|
|
30934
31406
|
function applyReviewPause(session, activity2) {
|
|
@@ -30981,10 +31453,10 @@ async function seedRunningMsFromUsage(session, notify2) {
|
|
|
30981
31453
|
var DEBOUNCE_MS2 = 50;
|
|
30982
31454
|
function watchActivity(session, notify2, onClaudeSessionId) {
|
|
30983
31455
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
30984
|
-
const
|
|
30985
|
-
const dir =
|
|
31456
|
+
const path73 = activityPath(session.id);
|
|
31457
|
+
const dir = dirname37(path73);
|
|
30986
31458
|
try {
|
|
30987
|
-
|
|
31459
|
+
mkdirSync31(dir, { recursive: true });
|
|
30988
31460
|
} catch {
|
|
30989
31461
|
return;
|
|
30990
31462
|
}
|
|
@@ -30992,31 +31464,26 @@ function watchActivity(session, notify2, onClaudeSessionId) {
|
|
|
30992
31464
|
let timer = null;
|
|
30993
31465
|
const read = () => {
|
|
30994
31466
|
timer = null;
|
|
30995
|
-
const activity2 = readActivity(
|
|
31467
|
+
const activity2 = readActivity(path73);
|
|
30996
31468
|
if (!activity2) return;
|
|
30997
|
-
session
|
|
30998
|
-
if (activity2.claudeSessionId)
|
|
30999
|
-
session.claudeSessionId = activity2.claudeSessionId;
|
|
31000
|
-
onClaudeSessionId?.(session);
|
|
31001
|
-
}
|
|
31469
|
+
applyActivityToSession(session, activity2);
|
|
31470
|
+
if (activity2.claudeSessionId) onClaudeSessionId?.(session);
|
|
31002
31471
|
applyReviewPause(session, activity2);
|
|
31003
31472
|
void seedRunningMsFromUsage(session, notify2);
|
|
31004
31473
|
notify2();
|
|
31005
31474
|
};
|
|
31006
31475
|
session.activityWatcher = watch2(dir, (_event, filename) => {
|
|
31007
|
-
if (filename && !
|
|
31476
|
+
if (filename && !path73.endsWith(filename)) return;
|
|
31008
31477
|
if (timer) clearTimeout(timer);
|
|
31009
31478
|
timer = setTimeout(read, DEBOUNCE_MS2);
|
|
31010
31479
|
});
|
|
31011
|
-
if (
|
|
31480
|
+
if (existsSync74(path73)) read();
|
|
31012
31481
|
}
|
|
31013
31482
|
function refreshActivity(session) {
|
|
31014
31483
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
31015
31484
|
const activity2 = readActivity(activityPath(session.id));
|
|
31016
31485
|
if (!activity2) return;
|
|
31017
|
-
session
|
|
31018
|
-
if (activity2.claudeSessionId)
|
|
31019
|
-
session.claudeSessionId = activity2.claudeSessionId;
|
|
31486
|
+
applyActivityToSession(session, activity2);
|
|
31020
31487
|
}
|
|
31021
31488
|
|
|
31022
31489
|
// src/commands/sessions/daemon/handleStoppedExit.ts
|
|
@@ -31097,56 +31564,56 @@ function reportSilentFailure(session, clients) {
|
|
|
31097
31564
|
import { watch as watch3 } from "fs";
|
|
31098
31565
|
|
|
31099
31566
|
// src/commands/sessions/shared/findTranscriptPathSync.ts
|
|
31100
|
-
import * as
|
|
31101
|
-
import * as
|
|
31102
|
-
import * as
|
|
31567
|
+
import * as fs45 from "fs";
|
|
31568
|
+
import * as os5 from "os";
|
|
31569
|
+
import * as path71 from "path";
|
|
31103
31570
|
function projectDirForCwd(cwd) {
|
|
31104
|
-
return
|
|
31105
|
-
|
|
31571
|
+
return path71.join(
|
|
31572
|
+
os5.homedir(),
|
|
31106
31573
|
".claude",
|
|
31107
31574
|
"projects",
|
|
31108
31575
|
cwd.replace(/[^a-zA-Z0-9]/g, "-")
|
|
31109
31576
|
);
|
|
31110
31577
|
}
|
|
31111
31578
|
function transcriptPathFor(cwd, claudeSessionId) {
|
|
31112
|
-
return
|
|
31579
|
+
return path71.join(projectDirForCwd(cwd), `${claudeSessionId}.jsonl`);
|
|
31113
31580
|
}
|
|
31114
31581
|
function findTranscriptPathSync(cwd, claudeSessionId) {
|
|
31115
31582
|
const direct = transcriptPathFor(cwd, claudeSessionId);
|
|
31116
|
-
if (
|
|
31583
|
+
if (fs45.existsSync(direct)) return direct;
|
|
31117
31584
|
const dir = projectDirForCwd(cwd);
|
|
31118
31585
|
let files;
|
|
31119
31586
|
try {
|
|
31120
|
-
files =
|
|
31587
|
+
files = fs45.readdirSync(dir);
|
|
31121
31588
|
} catch {
|
|
31122
31589
|
return null;
|
|
31123
31590
|
}
|
|
31124
31591
|
for (const file of files) {
|
|
31125
31592
|
if (!file.endsWith(".jsonl")) continue;
|
|
31126
|
-
if (headContainsSessionId(
|
|
31127
|
-
return
|
|
31593
|
+
if (headContainsSessionId(path71.join(dir, file), claudeSessionId))
|
|
31594
|
+
return path71.join(dir, file);
|
|
31128
31595
|
}
|
|
31129
31596
|
return null;
|
|
31130
31597
|
}
|
|
31131
31598
|
function headContainsSessionId(filePath, claudeSessionId) {
|
|
31132
31599
|
let fd;
|
|
31133
31600
|
try {
|
|
31134
|
-
fd =
|
|
31601
|
+
fd = fs45.openSync(filePath, "r");
|
|
31135
31602
|
const buf = Buffer.alloc(16384);
|
|
31136
|
-
const bytesRead =
|
|
31603
|
+
const bytesRead = fs45.readSync(fd, buf, 0, buf.length, 0);
|
|
31137
31604
|
return buf.toString("utf8", 0, bytesRead).includes(claudeSessionId);
|
|
31138
31605
|
} catch {
|
|
31139
31606
|
return false;
|
|
31140
31607
|
} finally {
|
|
31141
|
-
if (fd !== void 0)
|
|
31608
|
+
if (fd !== void 0) fs45.closeSync(fd);
|
|
31142
31609
|
}
|
|
31143
31610
|
}
|
|
31144
31611
|
|
|
31145
31612
|
// src/commands/sessions/daemon/ensureProjectDirExists.ts
|
|
31146
|
-
import { mkdirSync as
|
|
31613
|
+
import { mkdirSync as mkdirSync32 } from "fs";
|
|
31147
31614
|
function ensureProjectDirExists(dir, sessionId) {
|
|
31148
31615
|
try {
|
|
31149
|
-
|
|
31616
|
+
mkdirSync32(dir, { recursive: true });
|
|
31150
31617
|
return true;
|
|
31151
31618
|
} catch (error) {
|
|
31152
31619
|
daemonLog(
|
|
@@ -31253,7 +31720,7 @@ function resolvedToolUseIds(events, afterIdx) {
|
|
|
31253
31720
|
}
|
|
31254
31721
|
|
|
31255
31722
|
// src/commands/sessions/shared/readTranscriptTail.ts
|
|
31256
|
-
import * as
|
|
31723
|
+
import * as fs46 from "fs";
|
|
31257
31724
|
var DEFAULT_MAX_BYTES = 256 * 1024;
|
|
31258
31725
|
function parseTailEntries(raw) {
|
|
31259
31726
|
const entries = [];
|
|
@@ -31277,7 +31744,7 @@ function dropPartialFirstLine(raw, sliced) {
|
|
|
31277
31744
|
async function readTranscriptTail(filePath, maxBytes = DEFAULT_MAX_BYTES) {
|
|
31278
31745
|
let handle;
|
|
31279
31746
|
try {
|
|
31280
|
-
handle = await
|
|
31747
|
+
handle = await fs46.promises.open(filePath, "r");
|
|
31281
31748
|
const { size } = await handle.stat();
|
|
31282
31749
|
const start3 = Math.max(0, size - maxBytes);
|
|
31283
31750
|
const length = size - start3;
|
|
@@ -31296,20 +31763,20 @@ async function readTranscriptTail(filePath, maxBytes = DEFAULT_MAX_BYTES) {
|
|
|
31296
31763
|
function readTranscriptTailSync(filePath, maxBytes = DEFAULT_MAX_BYTES) {
|
|
31297
31764
|
let fd;
|
|
31298
31765
|
try {
|
|
31299
|
-
fd =
|
|
31300
|
-
const { size } =
|
|
31766
|
+
fd = fs46.openSync(filePath, "r");
|
|
31767
|
+
const { size } = fs46.fstatSync(fd);
|
|
31301
31768
|
const start3 = Math.max(0, size - maxBytes);
|
|
31302
31769
|
const length = size - start3;
|
|
31303
31770
|
if (length === 0) return [];
|
|
31304
31771
|
const buf = Buffer.alloc(length);
|
|
31305
|
-
|
|
31772
|
+
fs46.readSync(fd, buf, 0, length, start3);
|
|
31306
31773
|
return parseTailEntries(
|
|
31307
31774
|
dropPartialFirstLine(buf.toString("utf8"), start3 > 0)
|
|
31308
31775
|
);
|
|
31309
31776
|
} catch {
|
|
31310
31777
|
return [];
|
|
31311
31778
|
} finally {
|
|
31312
|
-
if (fd !== void 0)
|
|
31779
|
+
if (fd !== void 0) fs46.closeSync(fd);
|
|
31313
31780
|
}
|
|
31314
31781
|
}
|
|
31315
31782
|
|
|
@@ -31674,7 +32141,7 @@ async function recordWindowTokens(db, window, resetsAt, tokensUp, tokensDown) {
|
|
|
31674
32141
|
}
|
|
31675
32142
|
|
|
31676
32143
|
// src/commands/sessions/shared/transcriptUsage.ts
|
|
31677
|
-
import * as
|
|
32144
|
+
import * as fs47 from "fs";
|
|
31678
32145
|
function transcriptUsage(lines2) {
|
|
31679
32146
|
const byId = /* @__PURE__ */ new Map();
|
|
31680
32147
|
for (const line of lines2) {
|
|
@@ -31698,7 +32165,7 @@ function transcriptUsage(lines2) {
|
|
|
31698
32165
|
return [...byId.values()];
|
|
31699
32166
|
}
|
|
31700
32167
|
async function readTranscriptUsage(transcriptPath2) {
|
|
31701
|
-
const content = await
|
|
32168
|
+
const content = await fs47.promises.readFile(transcriptPath2, "utf8");
|
|
31702
32169
|
return transcriptUsage(content.split("\n"));
|
|
31703
32170
|
}
|
|
31704
32171
|
|
|
@@ -31921,8 +32388,15 @@ function respawnSession(session, respawn, status3, clients, onStatusChange) {
|
|
|
31921
32388
|
wirePtyEvents(session, clients, onStatusChange);
|
|
31922
32389
|
}
|
|
31923
32390
|
|
|
31924
|
-
// src/
|
|
31925
|
-
|
|
32391
|
+
// src/shared/harnessResumesConversation.ts
|
|
32392
|
+
var RESUMES_CONVERSATION = {
|
|
32393
|
+
claude: true,
|
|
32394
|
+
codex: false,
|
|
32395
|
+
pi: false
|
|
32396
|
+
};
|
|
32397
|
+
function harnessResumesConversation(harness) {
|
|
32398
|
+
return RESUMES_CONVERSATION[resolveHarness(harness)];
|
|
32399
|
+
}
|
|
31926
32400
|
|
|
31927
32401
|
// src/commands/sessions/daemon/assistResumeArgs.ts
|
|
31928
32402
|
function assistResumeArgs(session) {
|
|
@@ -31930,36 +32404,22 @@ function assistResumeArgs(session) {
|
|
|
31930
32404
|
return session.claudeSessionId ? [...args, "--resume-session", session.claudeSessionId] : args;
|
|
31931
32405
|
}
|
|
31932
32406
|
|
|
31933
|
-
// src/commands/sessions/daemon/
|
|
31934
|
-
|
|
31935
|
-
|
|
31936
|
-
|
|
31937
|
-
|
|
31938
|
-
|
|
31939
|
-
spawn: () => spawnClaude2({
|
|
31940
|
-
resumeSessionId: claudeSessionId,
|
|
31941
|
-
cwd,
|
|
31942
|
-
sessionId: session.id
|
|
31943
|
-
}),
|
|
31944
|
-
status: "waiting"
|
|
31945
|
-
};
|
|
31946
|
-
if (initialPrompt) return freshClaudePlan(session, initialPrompt, cwd);
|
|
31947
|
-
if (cwd && session.harness !== "pi")
|
|
31948
|
-
return freshClaudePlan(session, void 0, cwd);
|
|
31949
|
-
return null;
|
|
31950
|
-
}
|
|
31951
|
-
if (commandType === "assist" && assistArgs) {
|
|
31952
|
-
const idle = session.status === "waiting";
|
|
32407
|
+
// src/commands/sessions/daemon/interactiveRespawnPlan.ts
|
|
32408
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
32409
|
+
function interactiveRespawnPlan(session, resumes) {
|
|
32410
|
+
const { claudeSessionId, cwd, initialPrompt } = session;
|
|
32411
|
+
if (!resumes) return null;
|
|
32412
|
+
if (claudeSessionId)
|
|
31953
32413
|
return {
|
|
31954
|
-
spawn: () =>
|
|
31955
|
-
|
|
32414
|
+
spawn: () => spawnClaude2({
|
|
32415
|
+
resumeSessionId: claudeSessionId,
|
|
31956
32416
|
cwd,
|
|
31957
|
-
session.id
|
|
31958
|
-
|
|
31959
|
-
|
|
31960
|
-
status: idle ? "waiting" : "running"
|
|
32417
|
+
sessionId: session.id
|
|
32418
|
+
}),
|
|
32419
|
+
status: "waiting"
|
|
31961
32420
|
};
|
|
31962
|
-
|
|
32421
|
+
if (initialPrompt) return freshClaudePlan(session, initialPrompt, cwd);
|
|
32422
|
+
if (cwd) return freshClaudePlan(session, void 0, cwd);
|
|
31963
32423
|
return null;
|
|
31964
32424
|
}
|
|
31965
32425
|
function freshClaudePlan(session, prompt, cwd) {
|
|
@@ -31978,6 +32438,29 @@ function freshClaudePlan(session, prompt, cwd) {
|
|
|
31978
32438
|
};
|
|
31979
32439
|
}
|
|
31980
32440
|
|
|
32441
|
+
// src/commands/sessions/daemon/respawnPlan.ts
|
|
32442
|
+
function respawnPlan(session) {
|
|
32443
|
+
const { commandType, claudeSessionId, cwd, assistArgs } = session;
|
|
32444
|
+
const resumes = harnessResumesConversation(session.harness);
|
|
32445
|
+
if (commandType === "claude") return interactiveRespawnPlan(session, resumes);
|
|
32446
|
+
if (commandType === "assist" && assistArgs) {
|
|
32447
|
+
const idle = session.status === "waiting";
|
|
32448
|
+
return {
|
|
32449
|
+
spawn: () => spawnPty(
|
|
32450
|
+
assistResumeArgs({
|
|
32451
|
+
assistArgs,
|
|
32452
|
+
claudeSessionId: resumes ? claudeSessionId : void 0
|
|
32453
|
+
}),
|
|
32454
|
+
cwd,
|
|
32455
|
+
session.id,
|
|
32456
|
+
idle ? { ASSIST_RESUME_IDLE: "1" } : void 0
|
|
32457
|
+
),
|
|
32458
|
+
status: idle ? "waiting" : "running"
|
|
32459
|
+
};
|
|
32460
|
+
}
|
|
32461
|
+
return null;
|
|
32462
|
+
}
|
|
32463
|
+
|
|
31981
32464
|
// src/commands/sessions/daemon/restartSession.ts
|
|
31982
32465
|
function restartSession(session, clients, onStatusChange) {
|
|
31983
32466
|
const plan2 = respawnPlan(session);
|
|
@@ -32187,7 +32670,7 @@ function restoredSession(base, persisted, pty2, status3) {
|
|
|
32187
32670
|
|
|
32188
32671
|
// src/commands/sessions/daemon/restoreInteractiveSession.ts
|
|
32189
32672
|
function restoreInteractiveSession(id, persisted, base, idle) {
|
|
32190
|
-
if (persisted.commandType !== "run" && persisted.claudeSessionId) {
|
|
32673
|
+
if (persisted.commandType !== "run" && persisted.claudeSessionId && harnessResumesConversation(persisted.harness)) {
|
|
32191
32674
|
return resumeViaClaude(id, persisted, base, idle);
|
|
32192
32675
|
}
|
|
32193
32676
|
if (persisted.commandType === "claude") {
|
|
@@ -32211,11 +32694,10 @@ function resumeViaClaude(id, persisted, base, idle) {
|
|
|
32211
32694
|
return idle ? waitingSession(base, persisted, pty2) : runningSession(base, persisted, pty2);
|
|
32212
32695
|
}
|
|
32213
32696
|
function unrecoverableClaude(id, persisted) {
|
|
32214
|
-
return errorSession(
|
|
32215
|
-
|
|
32216
|
-
|
|
32217
|
-
|
|
32218
|
-
);
|
|
32697
|
+
return errorSession(id, persisted, unresumableReason(persisted.harness));
|
|
32698
|
+
}
|
|
32699
|
+
function unresumableReason(harness) {
|
|
32700
|
+
return harnessResumesConversation(harness) ? "no claude session id was recorded before the daemon stopped, so the conversation cannot be resumed" : `${harnessLabel(harness)} sessions cannot be resumed yet, so the conversation cannot be restored`;
|
|
32219
32701
|
}
|
|
32220
32702
|
function notRestoredStub(base, persisted) {
|
|
32221
32703
|
return {
|
|
@@ -32365,8 +32847,8 @@ function rearmStoppedSessions(sessions, notify2) {
|
|
|
32365
32847
|
}
|
|
32366
32848
|
|
|
32367
32849
|
// src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
|
|
32368
|
-
import { existsSync as
|
|
32369
|
-
import { basename as
|
|
32850
|
+
import { existsSync as existsSync77 } from "fs";
|
|
32851
|
+
import { basename as basename22 } from "path";
|
|
32370
32852
|
|
|
32371
32853
|
// src/commands/sessions/daemon/worktree/accountedTrees.ts
|
|
32372
32854
|
function accountedTrees(sessions) {
|
|
@@ -32421,21 +32903,21 @@ function bindResumedWorktree(session, cwd, notify2) {
|
|
|
32421
32903
|
|
|
32422
32904
|
// src/commands/sessions/daemon/worktree/describeHeldWork.ts
|
|
32423
32905
|
var MAX_ITEMS = 20;
|
|
32424
|
-
async function describeHeldWork(
|
|
32425
|
-
if (reason4.startsWith("uncommitted")) return await changedFiles(
|
|
32426
|
-
if (reason4.startsWith("unpushed")) return await unpushedCommits(
|
|
32906
|
+
async function describeHeldWork(path73, reason4) {
|
|
32907
|
+
if (reason4.startsWith("uncommitted")) return await changedFiles(path73);
|
|
32908
|
+
if (reason4.startsWith("unpushed")) return await unpushedCommits(path73, reason4);
|
|
32427
32909
|
return { summary: reason4, items: [] };
|
|
32428
32910
|
}
|
|
32429
|
-
async function changedFiles(
|
|
32430
|
-
const status3 = await gitResult(
|
|
32911
|
+
async function changedFiles(path73) {
|
|
32912
|
+
const status3 = await gitResult(path73, ["status", "--porcelain"]);
|
|
32431
32913
|
const lines2 = status3.ok ? nonEmptyLines(status3.out) : [];
|
|
32432
32914
|
return {
|
|
32433
32915
|
summary: `${lines2.length} uncommitted ${lines2.length === 1 ? "file" : "files"}`,
|
|
32434
32916
|
items: capped(lines2)
|
|
32435
32917
|
};
|
|
32436
32918
|
}
|
|
32437
|
-
async function unpushedCommits(
|
|
32438
|
-
const log2 = await gitResult(
|
|
32919
|
+
async function unpushedCommits(path73, reason4) {
|
|
32920
|
+
const log2 = await gitResult(path73, ["log", "--oneline", "@{upstream}..HEAD"]);
|
|
32439
32921
|
if (!log2.ok) return { summary: reason4, items: [] };
|
|
32440
32922
|
const lines2 = nonEmptyLines(log2.out);
|
|
32441
32923
|
return {
|
|
@@ -32455,18 +32937,18 @@ function capped(lines2) {
|
|
|
32455
32937
|
}
|
|
32456
32938
|
|
|
32457
32939
|
// src/commands/sessions/daemon/worktree/reclaimVanishedWorktrees.ts
|
|
32458
|
-
import { existsSync as
|
|
32940
|
+
import { existsSync as existsSync76 } from "fs";
|
|
32459
32941
|
async function reclaimVanishedWorktrees(clone, paths) {
|
|
32460
|
-
if (!
|
|
32461
|
-
for (const { path:
|
|
32942
|
+
if (!existsSync76(clone)) {
|
|
32943
|
+
for (const { path: path73 } of paths) forgetWorktree(path73);
|
|
32462
32944
|
daemonLog(
|
|
32463
32945
|
`clone ${clone} is gone; forgot ${paths.length} worktree record(s) it owned`
|
|
32464
32946
|
);
|
|
32465
32947
|
return;
|
|
32466
32948
|
}
|
|
32467
32949
|
await pruneBookkeeping2(clone);
|
|
32468
|
-
for (const { path:
|
|
32469
|
-
if (await reclaimBranch(clone, branch2)) forgetWorktree(
|
|
32950
|
+
for (const { path: path73, branch: branch2 } of paths)
|
|
32951
|
+
if (await reclaimBranch(clone, branch2)) forgetWorktree(path73);
|
|
32470
32952
|
}
|
|
32471
32953
|
async function pruneBookkeeping2(clone) {
|
|
32472
32954
|
try {
|
|
@@ -32493,7 +32975,7 @@ async function reclaimBranch(clone, branch2) {
|
|
|
32493
32975
|
}
|
|
32494
32976
|
|
|
32495
32977
|
// src/commands/sessions/daemon/worktree/resurfaceOrphanedWorktree.ts
|
|
32496
|
-
import { basename as
|
|
32978
|
+
import { basename as basename21 } from "path";
|
|
32497
32979
|
function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
|
|
32498
32980
|
const { orphan, reason: reason4, held } = recovered;
|
|
32499
32981
|
let id;
|
|
@@ -32516,7 +32998,7 @@ function orphanedSession(id, recovered) {
|
|
|
32516
32998
|
const { orphan, reason: reason4, held } = recovered;
|
|
32517
32999
|
return {
|
|
32518
33000
|
...sessionBase(id, "stopped"),
|
|
32519
|
-
name: `recovered ${
|
|
33001
|
+
name: `recovered ${basename21(orphan.path)}`,
|
|
32520
33002
|
subtitle: `${held.summary} in ${orphan.path}`,
|
|
32521
33003
|
commandType: "claude",
|
|
32522
33004
|
pty: null,
|
|
@@ -32541,17 +33023,17 @@ function recoveryNotice({ orphan, held }) {
|
|
|
32541
33023
|
}
|
|
32542
33024
|
|
|
32543
33025
|
// src/commands/sessions/daemon/worktree/logVanishedTree.ts
|
|
32544
|
-
function logVanishedTree(sessions,
|
|
33026
|
+
function logVanishedTree(sessions, path73) {
|
|
32545
33027
|
const claimants = [...sessions.values()].filter(
|
|
32546
|
-
(s) => s.cwd ===
|
|
33028
|
+
(s) => s.cwd === path73 || s.worktree?.path === path73
|
|
32547
33029
|
);
|
|
32548
33030
|
if (claimants.length === 0) {
|
|
32549
|
-
daemonLog(`worktree ${
|
|
33031
|
+
daemonLog(`worktree ${path73} gone from disk and unclaimed; reclaiming it`);
|
|
32550
33032
|
return;
|
|
32551
33033
|
}
|
|
32552
33034
|
for (const s of claimants)
|
|
32553
33035
|
daemonLog(
|
|
32554
|
-
`session ${s.id} ("${s.name}") claims worktree ${
|
|
33036
|
+
`session ${s.id} ("${s.name}") claims worktree ${path73}, which is gone from disk; reclaiming it`
|
|
32555
33037
|
);
|
|
32556
33038
|
}
|
|
32557
33039
|
|
|
@@ -32563,17 +33045,17 @@ function reconcileWorktreesOnRestore(sessions, spawnWith, notify2) {
|
|
|
32563
33045
|
async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
|
|
32564
33046
|
const accounted = accountedTrees(sessions);
|
|
32565
33047
|
const vanished = /* @__PURE__ */ new Map();
|
|
32566
|
-
for (const { path:
|
|
32567
|
-
if (!
|
|
32568
|
-
logVanishedTree(sessions,
|
|
33048
|
+
for (const { path: path73, clone } of readWorktreeRegistry()) {
|
|
33049
|
+
if (!existsSync77(path73)) {
|
|
33050
|
+
logVanishedTree(sessions, path73);
|
|
32569
33051
|
vanished.set(clone, [
|
|
32570
33052
|
...vanished.get(clone) ?? [],
|
|
32571
|
-
{ path:
|
|
33053
|
+
{ path: path73, branch: basename22(path73) }
|
|
32572
33054
|
]);
|
|
32573
33055
|
continue;
|
|
32574
33056
|
}
|
|
32575
|
-
if (accounted.has(
|
|
32576
|
-
await recoverOrphan(sessions, spawnWith, { path:
|
|
33057
|
+
if (accounted.has(path73)) continue;
|
|
33058
|
+
await recoverOrphan(sessions, spawnWith, { path: path73, clone }, notify2);
|
|
32577
33059
|
}
|
|
32578
33060
|
for (const [clone, paths] of vanished)
|
|
32579
33061
|
await reclaimVanishedWorktrees(clone, paths);
|
|
@@ -33152,14 +33634,14 @@ async function defaultConnect() {
|
|
|
33152
33634
|
}
|
|
33153
33635
|
|
|
33154
33636
|
// src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
|
|
33155
|
-
import { existsSync as
|
|
33637
|
+
import { existsSync as existsSync78, readFileSync as readFileSync55 } from "fs";
|
|
33156
33638
|
import { posix } from "path";
|
|
33157
33639
|
function hasPersistedWindowsSessions() {
|
|
33158
33640
|
const sessionsFile = windowsSessionsFileFromWsl();
|
|
33159
33641
|
if (!sessionsFile) return false;
|
|
33160
33642
|
try {
|
|
33161
|
-
if (!
|
|
33162
|
-
const data = JSON.parse(
|
|
33643
|
+
if (!existsSync78(sessionsFile)) return false;
|
|
33644
|
+
const data = JSON.parse(readFileSync55(sessionsFile, "utf8"));
|
|
33163
33645
|
return Array.isArray(data) && data.length > 0;
|
|
33164
33646
|
} catch (error) {
|
|
33165
33647
|
const message3 = error instanceof Error ? error.message : String(error);
|
|
@@ -33737,7 +34219,7 @@ function addAgentToStream(ctx, targetId, prompt, harness) {
|
|
|
33737
34219
|
}
|
|
33738
34220
|
|
|
33739
34221
|
// src/commands/sessions/daemon/worktree/spawnInTree.ts
|
|
33740
|
-
import { existsSync as
|
|
34222
|
+
import { existsSync as existsSync81 } from "fs";
|
|
33741
34223
|
|
|
33742
34224
|
// src/commands/sessions/daemon/createAssistSession.ts
|
|
33743
34225
|
function createAssistSession(id, assistArgs, cwd, meta, holdPty) {
|
|
@@ -33790,11 +34272,11 @@ function resumeSession(id, sessionId, cwd, name, holdPty) {
|
|
|
33790
34272
|
}
|
|
33791
34273
|
|
|
33792
34274
|
// src/commands/sessions/daemon/worktree/resumeInReplacementTree.ts
|
|
33793
|
-
import { existsSync as
|
|
34275
|
+
import { existsSync as existsSync80 } from "fs";
|
|
33794
34276
|
|
|
33795
34277
|
// src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
|
|
33796
|
-
import { copyFileSync as
|
|
33797
|
-
import { join as
|
|
34278
|
+
import { copyFileSync as copyFileSync7, existsSync as existsSync79, mkdirSync as mkdirSync33 } from "fs";
|
|
34279
|
+
import { join as join88 } from "path";
|
|
33798
34280
|
function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
|
|
33799
34281
|
const dir = projectDirForCwd(toCwd);
|
|
33800
34282
|
if (dir === projectDirForCwd(fromCwd)) {
|
|
@@ -33803,8 +34285,8 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
|
|
|
33803
34285
|
);
|
|
33804
34286
|
return;
|
|
33805
34287
|
}
|
|
33806
|
-
const dest =
|
|
33807
|
-
if (
|
|
34288
|
+
const dest = join88(dir, `${claudeSessionId}.jsonl`);
|
|
34289
|
+
if (existsSync79(dest)) {
|
|
33808
34290
|
daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
|
|
33809
34291
|
return;
|
|
33810
34292
|
}
|
|
@@ -33816,8 +34298,8 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
|
|
|
33816
34298
|
return;
|
|
33817
34299
|
}
|
|
33818
34300
|
try {
|
|
33819
|
-
|
|
33820
|
-
|
|
34301
|
+
mkdirSync33(dir, { recursive: true });
|
|
34302
|
+
copyFileSync7(source, dest);
|
|
33821
34303
|
daemonLog(
|
|
33822
34304
|
`transcript ${source} copied to ${dest} so ${toCwd} can resume it`
|
|
33823
34305
|
);
|
|
@@ -33848,7 +34330,7 @@ function resumeInReplacementTree(ctx, claudeSessionId, missingCwd, name) {
|
|
|
33848
34330
|
}
|
|
33849
34331
|
function cloneForReapedTree(missingCwd) {
|
|
33850
34332
|
const clone = worktreeAttributionIncludingReaped(missingCwd)?.clone;
|
|
33851
|
-
if (!clone || !
|
|
34333
|
+
if (!clone || !existsSync80(clone))
|
|
33852
34334
|
throw new Error(
|
|
33853
34335
|
`working directory no longer exists and no clone is recorded to re-allocate from: ${missingCwd}`
|
|
33854
34336
|
);
|
|
@@ -33880,7 +34362,7 @@ function spawnAssistInTree(ctx, assistArgs, cwd, meta) {
|
|
|
33880
34362
|
return id;
|
|
33881
34363
|
}
|
|
33882
34364
|
function resumeInTree(ctx, sessionId, cwd, name) {
|
|
33883
|
-
if (!
|
|
34365
|
+
if (!existsSync81(cwd))
|
|
33884
34366
|
return resumeInReplacementTree(ctx, sessionId, cwd, name);
|
|
33885
34367
|
const id = ctx.spawnWith((sid) => resumeSession(sid, sessionId, cwd, name));
|
|
33886
34368
|
daemonLog(`session ${id} resuming ${sessionId} in ${cwd}`);
|
|
@@ -34172,12 +34654,12 @@ function handleSetStatus(client, m, d) {
|
|
|
34172
34654
|
}
|
|
34173
34655
|
|
|
34174
34656
|
// src/commands/sessions/shared/parseTranscript.ts
|
|
34175
|
-
import * as
|
|
34657
|
+
import * as fs48 from "fs";
|
|
34176
34658
|
async function parseTranscript(sessionId) {
|
|
34177
34659
|
const filePath = await findSessionJsonlPath(sessionId);
|
|
34178
34660
|
if (!filePath) return [];
|
|
34179
34661
|
try {
|
|
34180
|
-
const raw = await
|
|
34662
|
+
const raw = await fs48.promises.readFile(filePath, "utf8");
|
|
34181
34663
|
return parseTranscriptLines(raw.split("\n"));
|
|
34182
34664
|
} catch {
|
|
34183
34665
|
return [];
|
|
@@ -34201,9 +34683,9 @@ function safeParse2(line) {
|
|
|
34201
34683
|
}
|
|
34202
34684
|
|
|
34203
34685
|
// src/commands/sessions/daemon/repoDirExists.ts
|
|
34204
|
-
import { existsSync as
|
|
34686
|
+
import { existsSync as existsSync82 } from "fs";
|
|
34205
34687
|
function repoDirExists(cwd) {
|
|
34206
|
-
return
|
|
34688
|
+
return existsSync82(toGitCwd(cwd));
|
|
34207
34689
|
}
|
|
34208
34690
|
|
|
34209
34691
|
// src/commands/sessions/daemon/withRepoGroups.ts
|
|
@@ -34404,10 +34886,10 @@ function handleConnection(socket, manager) {
|
|
|
34404
34886
|
}
|
|
34405
34887
|
|
|
34406
34888
|
// src/commands/sessions/daemon/onListening.ts
|
|
34407
|
-
import { unlinkSync as unlinkSync23, writeFileSync as
|
|
34889
|
+
import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync46 } from "fs";
|
|
34408
34890
|
|
|
34409
34891
|
// src/commands/sessions/daemon/startPidFileWatchdog.ts
|
|
34410
|
-
import { readFileSync as
|
|
34892
|
+
import { readFileSync as readFileSync56 } from "fs";
|
|
34411
34893
|
var WATCHDOG_INTERVAL_MS = 5e3;
|
|
34412
34894
|
function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
34413
34895
|
const timer = setInterval(() => {
|
|
@@ -34418,7 +34900,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
|
34418
34900
|
}
|
|
34419
34901
|
function ownsPidFile() {
|
|
34420
34902
|
try {
|
|
34421
|
-
return
|
|
34903
|
+
return readFileSync56(daemonPaths.pid, "utf8").trim() === String(process.pid);
|
|
34422
34904
|
} catch {
|
|
34423
34905
|
return false;
|
|
34424
34906
|
}
|
|
@@ -34426,7 +34908,7 @@ function ownsPidFile() {
|
|
|
34426
34908
|
|
|
34427
34909
|
// src/commands/sessions/daemon/onListening.ts
|
|
34428
34910
|
function onListening(manager, checkAutoExit) {
|
|
34429
|
-
|
|
34911
|
+
writeFileSync46(daemonPaths.pid, String(process.pid));
|
|
34430
34912
|
startPidFileWatchdog(() => {
|
|
34431
34913
|
daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
|
|
34432
34914
|
void manager.flushActiveMs().finally(() => {
|
|
@@ -34508,7 +34990,7 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
|
|
|
34508
34990
|
|
|
34509
34991
|
// src/commands/sessions/daemon/runDaemon.ts
|
|
34510
34992
|
async function runDaemon() {
|
|
34511
|
-
|
|
34993
|
+
mkdirSync34(daemonPaths.dir, { recursive: true });
|
|
34512
34994
|
daemonLog(
|
|
34513
34995
|
`starting (reason: ${process.env.ASSIST_DAEMON_SPAWN_REASON ?? "manual"})`
|
|
34514
34996
|
);
|
|
@@ -34562,17 +35044,17 @@ function registerSetStatusCommand(cmd) {
|
|
|
34562
35044
|
}
|
|
34563
35045
|
|
|
34564
35046
|
// src/commands/sessions/summarise/index.ts
|
|
34565
|
-
import * as
|
|
34566
|
-
import
|
|
35047
|
+
import * as fs50 from "fs";
|
|
35048
|
+
import chalk214 from "chalk";
|
|
34567
35049
|
|
|
34568
35050
|
// src/commands/sessions/summarise/shared.ts
|
|
34569
|
-
import * as
|
|
35051
|
+
import * as fs49 from "fs";
|
|
34570
35052
|
function writeSummary(jsonlPath2, summary) {
|
|
34571
|
-
|
|
35053
|
+
fs49.writeFileSync(summaryPathFor(jsonlPath2), `${summary.trim()}
|
|
34572
35054
|
`, "utf8");
|
|
34573
35055
|
}
|
|
34574
35056
|
function hasSummary(jsonlPath2) {
|
|
34575
|
-
return
|
|
35057
|
+
return fs49.existsSync(summaryPathFor(jsonlPath2));
|
|
34576
35058
|
}
|
|
34577
35059
|
function summaryPathFor(jsonlPath2) {
|
|
34578
35060
|
return jsonlPath2.replace(/\.jsonl$/, ".summary");
|
|
@@ -34622,29 +35104,29 @@ ${firstMessage}`);
|
|
|
34622
35104
|
async function summarise2(options2) {
|
|
34623
35105
|
const files = await discoverSessionFiles();
|
|
34624
35106
|
if (files.length === 0) {
|
|
34625
|
-
console.log(
|
|
35107
|
+
console.log(chalk214.yellow("No sessions found."));
|
|
34626
35108
|
return;
|
|
34627
35109
|
}
|
|
34628
35110
|
const toProcess = selectCandidates(files, options2);
|
|
34629
35111
|
if (toProcess.length === 0) {
|
|
34630
|
-
console.log(
|
|
35112
|
+
console.log(chalk214.green("All sessions already summarised."));
|
|
34631
35113
|
return;
|
|
34632
35114
|
}
|
|
34633
35115
|
console.log(
|
|
34634
|
-
|
|
35116
|
+
chalk214.cyan(
|
|
34635
35117
|
`Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
|
|
34636
35118
|
)
|
|
34637
35119
|
);
|
|
34638
35120
|
const { succeeded, failed: failed2 } = processSessions(toProcess);
|
|
34639
35121
|
console.log(
|
|
34640
|
-
|
|
35122
|
+
chalk214.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk214.yellow(`, ${failed2} skipped`) : "")
|
|
34641
35123
|
);
|
|
34642
35124
|
}
|
|
34643
35125
|
function selectCandidates(files, options2) {
|
|
34644
35126
|
const candidates = options2.force ? files : files.filter((f) => !hasSummary(f));
|
|
34645
35127
|
candidates.sort((a, b) => {
|
|
34646
35128
|
try {
|
|
34647
|
-
return
|
|
35129
|
+
return fs50.statSync(b).mtimeMs - fs50.statSync(a).mtimeMs;
|
|
34648
35130
|
} catch {
|
|
34649
35131
|
return 0;
|
|
34650
35132
|
}
|
|
@@ -34657,16 +35139,16 @@ function processSessions(files) {
|
|
|
34657
35139
|
let failed2 = 0;
|
|
34658
35140
|
for (let i = 0; i < files.length; i++) {
|
|
34659
35141
|
const file = files[i];
|
|
34660
|
-
process.stdout.write(
|
|
35142
|
+
process.stdout.write(chalk214.dim(` [${i + 1}/${files.length}] `));
|
|
34661
35143
|
const summary = summariseSession(file);
|
|
34662
35144
|
if (summary) {
|
|
34663
35145
|
writeSummary(file, summary);
|
|
34664
35146
|
succeeded++;
|
|
34665
|
-
process.stdout.write(`${
|
|
35147
|
+
process.stdout.write(`${chalk214.green("\u2713")} ${summary}
|
|
34666
35148
|
`);
|
|
34667
35149
|
} else {
|
|
34668
35150
|
failed2++;
|
|
34669
|
-
process.stdout.write(` ${
|
|
35151
|
+
process.stdout.write(` ${chalk214.yellow("skip")}
|
|
34670
35152
|
`);
|
|
34671
35153
|
}
|
|
34672
35154
|
}
|
|
@@ -34687,7 +35169,7 @@ function registerSessions(program2) {
|
|
|
34687
35169
|
}
|
|
34688
35170
|
|
|
34689
35171
|
// src/commands/statusLine.ts
|
|
34690
|
-
import
|
|
35172
|
+
import chalk216 from "chalk";
|
|
34691
35173
|
|
|
34692
35174
|
// src/shared/contextLevel.ts
|
|
34693
35175
|
function contextLevel(pct) {
|
|
@@ -34697,7 +35179,7 @@ function contextLevel(pct) {
|
|
|
34697
35179
|
}
|
|
34698
35180
|
|
|
34699
35181
|
// src/commands/buildLimitsSegment.ts
|
|
34700
|
-
import
|
|
35182
|
+
import chalk215 from "chalk";
|
|
34701
35183
|
|
|
34702
35184
|
// src/shared/rateLimitLevel.ts
|
|
34703
35185
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
@@ -34733,9 +35215,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
|
|
|
34733
35215
|
|
|
34734
35216
|
// src/commands/buildLimitsSegment.ts
|
|
34735
35217
|
var LEVEL_COLOR = {
|
|
34736
|
-
ok:
|
|
34737
|
-
warn:
|
|
34738
|
-
over:
|
|
35218
|
+
ok: chalk215.green,
|
|
35219
|
+
warn: chalk215.yellow,
|
|
35220
|
+
over: chalk215.red
|
|
34739
35221
|
};
|
|
34740
35222
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
|
|
34741
35223
|
const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
|
|
@@ -34766,10 +35248,10 @@ function buildLimitsSegment(rateLimits) {
|
|
|
34766
35248
|
}
|
|
34767
35249
|
|
|
34768
35250
|
// src/commands/readGitBranch.ts
|
|
34769
|
-
import { readFileSync as
|
|
34770
|
-
import { isAbsolute as isAbsolute4, join as
|
|
35251
|
+
import { readFileSync as readFileSync58, statSync as statSync14 } from "fs";
|
|
35252
|
+
import { isAbsolute as isAbsolute4, join as join89, resolve as resolve21 } from "path";
|
|
34771
35253
|
function resolveGitDir(cwd) {
|
|
34772
|
-
const dotGit =
|
|
35254
|
+
const dotGit = join89(cwd, ".git");
|
|
34773
35255
|
let stat4;
|
|
34774
35256
|
try {
|
|
34775
35257
|
stat4 = statSync14(dotGit);
|
|
@@ -34781,7 +35263,7 @@ function resolveGitDir(cwd) {
|
|
|
34781
35263
|
}
|
|
34782
35264
|
let contents;
|
|
34783
35265
|
try {
|
|
34784
|
-
contents =
|
|
35266
|
+
contents = readFileSync58(dotGit, "utf8");
|
|
34785
35267
|
} catch {
|
|
34786
35268
|
return null;
|
|
34787
35269
|
}
|
|
@@ -34799,7 +35281,7 @@ function readGitBranch(cwd) {
|
|
|
34799
35281
|
}
|
|
34800
35282
|
let head;
|
|
34801
35283
|
try {
|
|
34802
|
-
head =
|
|
35284
|
+
head = readFileSync58(join89(gitDir, "HEAD"), "utf8");
|
|
34803
35285
|
} catch {
|
|
34804
35286
|
return null;
|
|
34805
35287
|
}
|
|
@@ -34831,7 +35313,7 @@ async function relayUsage(claudeSessionId, transcriptPath2, usedPct) {
|
|
|
34831
35313
|
}
|
|
34832
35314
|
|
|
34833
35315
|
// src/commands/statusLine.ts
|
|
34834
|
-
|
|
35316
|
+
chalk216.level = 3;
|
|
34835
35317
|
function formatNumber(num) {
|
|
34836
35318
|
return num.toLocaleString("en-US");
|
|
34837
35319
|
}
|
|
@@ -34839,9 +35321,9 @@ function colorizePercent(pct) {
|
|
|
34839
35321
|
const label2 = `${Math.round(pct)}%`;
|
|
34840
35322
|
switch (contextLevel(pct)) {
|
|
34841
35323
|
case "red":
|
|
34842
|
-
return
|
|
35324
|
+
return chalk216.red(label2);
|
|
34843
35325
|
case "yellow":
|
|
34844
|
-
return
|
|
35326
|
+
return chalk216.yellow(label2);
|
|
34845
35327
|
default:
|
|
34846
35328
|
return label2;
|
|
34847
35329
|
}
|
|
@@ -34854,7 +35336,7 @@ async function statusLine() {
|
|
|
34854
35336
|
const usedPct = data.context_window.used_percentage ?? 0;
|
|
34855
35337
|
const dir = data.workspace?.current_dir ?? data.cwd;
|
|
34856
35338
|
const branch2 = dir ? readGitBranch(toGitCwd(dir)) : null;
|
|
34857
|
-
const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${
|
|
35339
|
+
const branchSegment = branch2 ? `\u{1F33F}\uFE0F ${chalk216.cyan(branch2)} | ` : "";
|
|
34858
35340
|
console.log(
|
|
34859
35341
|
`${branchSegment}${model} | Tokens - ${formatNumber(totalIn)} \u2191 : ${formatNumber(totalOut)} \u2193 | Context - ${colorizePercent(usedPct)}${buildLimitsSegment(data.rate_limits)}`
|
|
34860
35342
|
);
|
|
@@ -34866,299 +35348,9 @@ async function statusLine() {
|
|
|
34866
35348
|
);
|
|
34867
35349
|
}
|
|
34868
35350
|
|
|
34869
|
-
// src/commands/sync.ts
|
|
34870
|
-
import * as fs48 from "fs";
|
|
34871
|
-
import * as os5 from "os";
|
|
34872
|
-
import * as path69 from "path";
|
|
34873
|
-
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
34874
|
-
|
|
34875
|
-
// src/commands/sync/syncClaudeMd.ts
|
|
34876
|
-
import * as fs42 from "fs";
|
|
34877
|
-
import * as path61 from "path";
|
|
34878
|
-
import chalk215 from "chalk";
|
|
34879
|
-
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
34880
|
-
const source = path61.join(claudeDir, "CLAUDE.md");
|
|
34881
|
-
const target = path61.join(targetBase, "CLAUDE.md");
|
|
34882
|
-
const sourceContent = fs42.readFileSync(source, "utf8");
|
|
34883
|
-
if (fs42.existsSync(target)) {
|
|
34884
|
-
const targetContent = fs42.readFileSync(target, "utf8");
|
|
34885
|
-
if (sourceContent !== targetContent) {
|
|
34886
|
-
console.log(
|
|
34887
|
-
chalk215.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
34888
|
-
);
|
|
34889
|
-
console.log();
|
|
34890
|
-
printDiff(targetContent, sourceContent);
|
|
34891
|
-
if (!options2?.yes) {
|
|
34892
|
-
printAutoConfirmHint();
|
|
34893
|
-
const confirm = await promptConfirm(
|
|
34894
|
-
chalk215.red("Overwrite existing CLAUDE.md?"),
|
|
34895
|
-
false
|
|
34896
|
-
);
|
|
34897
|
-
if (!confirm) {
|
|
34898
|
-
console.log("Skipped CLAUDE.md");
|
|
34899
|
-
return;
|
|
34900
|
-
}
|
|
34901
|
-
}
|
|
34902
|
-
}
|
|
34903
|
-
}
|
|
34904
|
-
fs42.copyFileSync(source, target);
|
|
34905
|
-
console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
|
|
34906
|
-
}
|
|
34907
|
-
|
|
34908
|
-
// src/commands/sync/syncCodex.ts
|
|
34909
|
-
import * as path64 from "path";
|
|
34910
|
-
|
|
34911
|
-
// src/commands/sync/installHarnessCommands.ts
|
|
34912
|
-
import * as fs43 from "fs";
|
|
34913
|
-
import * as path62 from "path";
|
|
34914
|
-
function installHarnessCommands(claudeDir, harness, transform) {
|
|
34915
|
-
const commandsSource = path62.join(claudeDir, "commands");
|
|
34916
|
-
const files = fs43.readdirSync(commandsSource);
|
|
34917
|
-
let synced = 0;
|
|
34918
|
-
for (const file of files) {
|
|
34919
|
-
if (!file.endsWith(".md")) continue;
|
|
34920
|
-
const name = file.replace(/\.md$/, "");
|
|
34921
|
-
const content = fs43.readFileSync(path62.join(commandsSource, file), "utf8");
|
|
34922
|
-
const target = path62.join(harness.homeDir, harness.sync.commandDest(name));
|
|
34923
|
-
fs43.mkdirSync(path62.dirname(target), { recursive: true });
|
|
34924
|
-
fs43.writeFileSync(target, transform(name, content));
|
|
34925
|
-
synced++;
|
|
34926
|
-
}
|
|
34927
|
-
const agentsTarget = path62.join(harness.homeDir, harness.sync.agentsFile);
|
|
34928
|
-
fs43.mkdirSync(path62.dirname(agentsTarget), { recursive: true });
|
|
34929
|
-
fs43.copyFileSync(path62.join(claudeDir, "CLAUDE.md"), agentsTarget);
|
|
34930
|
-
return { total: files.length, synced };
|
|
34931
|
-
}
|
|
34932
|
-
|
|
34933
|
-
// src/commands/sync/syncCodexHooks.ts
|
|
34934
|
-
import * as fs44 from "fs";
|
|
34935
|
-
import * as path63 from "path";
|
|
34936
|
-
var BEGIN = "# >>> assist codex hooks (managed) \u2014 do not edit >>>";
|
|
34937
|
-
var END = "# <<< assist codex hooks (managed) <<<";
|
|
34938
|
-
function upsertManagedBlock(existing, body) {
|
|
34939
|
-
const block = `${BEGIN}
|
|
34940
|
-
${body.trim()}
|
|
34941
|
-
${END}`;
|
|
34942
|
-
const begin = existing.indexOf(BEGIN);
|
|
34943
|
-
if (begin === -1) {
|
|
34944
|
-
const base = existing.replace(/\s*$/, "");
|
|
34945
|
-
return base ? `${base}
|
|
34946
|
-
|
|
34947
|
-
${block}
|
|
34948
|
-
` : `${block}
|
|
34949
|
-
`;
|
|
34950
|
-
}
|
|
34951
|
-
const endMarker = existing.indexOf(END, begin);
|
|
34952
|
-
const after = endMarker === -1 ? existing.length : endMarker + END.length;
|
|
34953
|
-
const before = existing.slice(0, begin).replace(/\s*$/, "");
|
|
34954
|
-
const rest = existing.slice(after).replace(/^\s*/, "");
|
|
34955
|
-
const head = before ? `${before}
|
|
34956
|
-
|
|
34957
|
-
${block}` : block;
|
|
34958
|
-
return rest ? `${head}
|
|
34959
|
-
|
|
34960
|
-
${rest}
|
|
34961
|
-
` : `${head}
|
|
34962
|
-
`;
|
|
34963
|
-
}
|
|
34964
|
-
function syncCodexHooks(sourcePath) {
|
|
34965
|
-
const body = fs44.readFileSync(sourcePath, "utf8");
|
|
34966
|
-
const configPath = path63.join(harnesses.codex.homeDir, "config.toml");
|
|
34967
|
-
const existing = fs44.existsSync(configPath) ? fs44.readFileSync(configPath, "utf8") : "";
|
|
34968
|
-
fs44.mkdirSync(path63.dirname(configPath), { recursive: true });
|
|
34969
|
-
fs44.writeFileSync(configPath, upsertManagedBlock(existing, body));
|
|
34970
|
-
console.log(
|
|
34971
|
-
"Registered assist codex-hook in ~/.codex/config.toml (PreToolUse, PermissionRequest)"
|
|
34972
|
-
);
|
|
34973
|
-
}
|
|
34974
|
-
|
|
34975
|
-
// src/commands/sync/syncCodex.ts
|
|
34976
|
-
function quoteYaml(value) {
|
|
34977
|
-
return `"${value.replace(/\\/g, String.raw`\\`).replace(/"/g, String.raw`\"`)}"`;
|
|
34978
|
-
}
|
|
34979
|
-
function commandToSkill(name, content) {
|
|
34980
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
34981
|
-
const frontmatter = match ? match[1] : "";
|
|
34982
|
-
const body = match ? content.slice(match[0].length) : content;
|
|
34983
|
-
const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
|
|
34984
|
-
const description = descriptionMatch ? descriptionMatch[1].trim().replace(/^["']|["']$/g, "") : name;
|
|
34985
|
-
const header = `---
|
|
34986
|
-
name: ${name}
|
|
34987
|
-
description: ${quoteYaml(description)}
|
|
34988
|
-
---
|
|
34989
|
-
|
|
34990
|
-
`;
|
|
34991
|
-
return header + body.replace(/^\r?\n+/, "");
|
|
34992
|
-
}
|
|
34993
|
-
function syncCodex(claudeDir) {
|
|
34994
|
-
if (!isHarnessAvailable("codex")) return;
|
|
34995
|
-
const { total } = installHarnessCommands(
|
|
34996
|
-
claudeDir,
|
|
34997
|
-
harnesses.codex,
|
|
34998
|
-
commandToSkill
|
|
34999
|
-
);
|
|
35000
|
-
syncCodexHooks(path64.join(claudeDir, "..", "codex", "config.toml"));
|
|
35001
|
-
console.log(
|
|
35002
|
-
`Synced ${total} skill(s) to ~/.codex/skills and CLAUDE.md to ~/.codex/AGENTS.md`
|
|
35003
|
-
);
|
|
35004
|
-
}
|
|
35005
|
-
|
|
35006
|
-
// src/commands/sync/syncDesign.ts
|
|
35007
|
-
import * as fs45 from "fs";
|
|
35008
|
-
import * as path65 from "path";
|
|
35009
|
-
function syncDesign(claudeDir, targetBase) {
|
|
35010
|
-
const systemPromptSource = path65.join(claudeDir, "design-system-prompt.md");
|
|
35011
|
-
const systemPromptTarget = path65.join(targetBase, "design-system-prompt.md");
|
|
35012
|
-
fs45.copyFileSync(systemPromptSource, systemPromptTarget);
|
|
35013
|
-
console.log(
|
|
35014
|
-
"Copied design-system-prompt.md to ~/.claude/design-system-prompt.md"
|
|
35015
|
-
);
|
|
35016
|
-
const skillsSource = path65.join(claudeDir, "skills");
|
|
35017
|
-
const skillsTarget = path65.join(targetBase, "skills");
|
|
35018
|
-
fs45.mkdirSync(skillsTarget, { recursive: true });
|
|
35019
|
-
const files = fs45.readdirSync(skillsSource);
|
|
35020
|
-
for (const file of files) {
|
|
35021
|
-
fs45.copyFileSync(
|
|
35022
|
-
path65.join(skillsSource, file),
|
|
35023
|
-
path65.join(skillsTarget, file)
|
|
35024
|
-
);
|
|
35025
|
-
}
|
|
35026
|
-
console.log(`Synced ${files.length} design skill(s) to ~/.claude/skills`);
|
|
35027
|
-
}
|
|
35028
|
-
|
|
35029
|
-
// src/commands/sync/syncPi.ts
|
|
35030
|
-
import * as path67 from "path";
|
|
35031
|
-
|
|
35032
|
-
// src/commands/sync/syncPiHooks.ts
|
|
35033
|
-
import * as fs46 from "fs";
|
|
35034
|
-
import * as path66 from "path";
|
|
35035
|
-
function piExtensionsDir() {
|
|
35036
|
-
return path66.join(harnesses.pi.homeDir, "extensions");
|
|
35037
|
-
}
|
|
35038
|
-
function syncPiHooks(sourceDir) {
|
|
35039
|
-
const target = piExtensionsDir();
|
|
35040
|
-
fs46.mkdirSync(target, { recursive: true });
|
|
35041
|
-
const files = fs46.readdirSync(sourceDir).filter((f) => f.endsWith(".ts"));
|
|
35042
|
-
for (const file of files) {
|
|
35043
|
-
fs46.copyFileSync(
|
|
35044
|
-
path66.join(sourceDir, file),
|
|
35045
|
-
path66.join(target, `assist-${file}`)
|
|
35046
|
-
);
|
|
35047
|
-
}
|
|
35048
|
-
console.log(
|
|
35049
|
-
`Registered ${files.length} assist extension(s) in ~/.pi/agent/extensions`
|
|
35050
|
-
);
|
|
35051
|
-
}
|
|
35052
|
-
|
|
35053
|
-
// src/commands/sync/syncPi.ts
|
|
35054
|
-
function unquote(value) {
|
|
35055
|
-
return value.trim().replace(/^["']|["']$/g, "");
|
|
35056
|
-
}
|
|
35057
|
-
function commandToPrompt(name, content) {
|
|
35058
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
35059
|
-
const frontmatter = match ? match[1] : "";
|
|
35060
|
-
const body = match ? content.slice(match[0].length) : content;
|
|
35061
|
-
const descriptionMatch = frontmatter.match(/^description:\s*(.*)$/m);
|
|
35062
|
-
const description = descriptionMatch ? unquote(descriptionMatch[1]) : name;
|
|
35063
|
-
const argsMatch = frontmatter.match(/^allowed_args:\s*(.*)$/m);
|
|
35064
|
-
const argumentHint = argsMatch ? unquote(argsMatch[1]) : void 0;
|
|
35065
|
-
const header = [
|
|
35066
|
-
"---",
|
|
35067
|
-
`description: ${description}`,
|
|
35068
|
-
...argumentHint ? [`argument-hint: ${argumentHint}`] : [],
|
|
35069
|
-
"---",
|
|
35070
|
-
"",
|
|
35071
|
-
""
|
|
35072
|
-
].join("\n");
|
|
35073
|
-
return header + body.replace(/^\r?\n+/, "");
|
|
35074
|
-
}
|
|
35075
|
-
function syncPi(claudeDir) {
|
|
35076
|
-
if (!isHarnessAvailable("pi")) return;
|
|
35077
|
-
const { synced } = installHarnessCommands(
|
|
35078
|
-
claudeDir,
|
|
35079
|
-
harnesses.pi,
|
|
35080
|
-
commandToPrompt
|
|
35081
|
-
);
|
|
35082
|
-
syncPiHooks(path67.join(claudeDir, "..", "pi"));
|
|
35083
|
-
console.log(
|
|
35084
|
-
`Synced ${synced} prompt(s) to ~/.pi/agent/prompts and CLAUDE.md to ~/.pi/agent/AGENTS.md`
|
|
35085
|
-
);
|
|
35086
|
-
}
|
|
35087
|
-
|
|
35088
|
-
// src/commands/sync/syncSettings.ts
|
|
35089
|
-
import * as fs47 from "fs";
|
|
35090
|
-
import * as path68 from "path";
|
|
35091
|
-
import chalk216 from "chalk";
|
|
35092
|
-
async function syncSettings(claudeDir, targetBase, options2) {
|
|
35093
|
-
const source = path68.join(claudeDir, "settings.json");
|
|
35094
|
-
const target = path68.join(targetBase, "settings.json");
|
|
35095
|
-
const sourceContent = fs47.readFileSync(source, "utf8");
|
|
35096
|
-
const sourceSettings = JSON.parse(sourceContent);
|
|
35097
|
-
const targetExists = fs47.existsSync(target);
|
|
35098
|
-
const targetContent = targetExists ? fs47.readFileSync(target, "utf8") : "";
|
|
35099
|
-
const preservedUserSettings = targetExists ? JSON.parse(targetContent) : {};
|
|
35100
|
-
const mergedContent = JSON.stringify(
|
|
35101
|
-
{ ...preservedUserSettings, ...sourceSettings },
|
|
35102
|
-
null,
|
|
35103
|
-
" "
|
|
35104
|
-
);
|
|
35105
|
-
if (targetExists) {
|
|
35106
|
-
const normalizedTarget = JSON.stringify(preservedUserSettings, null, " ");
|
|
35107
|
-
if (mergedContent !== normalizedTarget) {
|
|
35108
|
-
if (!options2?.yes) {
|
|
35109
|
-
console.log(
|
|
35110
|
-
chalk216.yellow(
|
|
35111
|
-
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
35112
|
-
)
|
|
35113
|
-
);
|
|
35114
|
-
console.log();
|
|
35115
|
-
printDiff(targetContent, mergedContent);
|
|
35116
|
-
printAutoConfirmHint();
|
|
35117
|
-
const confirm = await promptConfirm(
|
|
35118
|
-
chalk216.red("Overwrite existing settings.json?"),
|
|
35119
|
-
false
|
|
35120
|
-
);
|
|
35121
|
-
if (!confirm) {
|
|
35122
|
-
console.log("Skipped settings.json");
|
|
35123
|
-
return;
|
|
35124
|
-
}
|
|
35125
|
-
}
|
|
35126
|
-
}
|
|
35127
|
-
}
|
|
35128
|
-
fs47.writeFileSync(target, mergedContent);
|
|
35129
|
-
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
35130
|
-
}
|
|
35131
|
-
|
|
35132
|
-
// src/commands/sync.ts
|
|
35133
|
-
var __filename5 = fileURLToPath9(import.meta.url);
|
|
35134
|
-
var __dirname7 = path69.dirname(__filename5);
|
|
35135
|
-
async function sync(options2) {
|
|
35136
|
-
const config = loadConfig();
|
|
35137
|
-
const yes = options2?.yes ?? config.sync.autoConfirm;
|
|
35138
|
-
const claudeDir = path69.join(__dirname7, "..", "claude");
|
|
35139
|
-
const targetBase = path69.join(os5.homedir(), ".claude");
|
|
35140
|
-
syncCommands(claudeDir, targetBase);
|
|
35141
|
-
syncDesign(claudeDir, targetBase);
|
|
35142
|
-
await syncSettings(claudeDir, targetBase, { yes });
|
|
35143
|
-
await syncClaudeMd(claudeDir, targetBase, { yes });
|
|
35144
|
-
syncCodex(claudeDir);
|
|
35145
|
-
syncPi(claudeDir);
|
|
35146
|
-
}
|
|
35147
|
-
function syncCommands(claudeDir, targetBase) {
|
|
35148
|
-
const sourceDir = path69.join(claudeDir, "commands");
|
|
35149
|
-
const targetDir = path69.join(targetBase, "commands");
|
|
35150
|
-
fs48.mkdirSync(targetDir, { recursive: true });
|
|
35151
|
-
const files = fs48.readdirSync(sourceDir);
|
|
35152
|
-
for (const file of files) {
|
|
35153
|
-
fs48.copyFileSync(path69.join(sourceDir, file), path69.join(targetDir, file));
|
|
35154
|
-
console.log(`Copied ${file} to ${targetDir}`);
|
|
35155
|
-
}
|
|
35156
|
-
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
35157
|
-
}
|
|
35158
|
-
|
|
35159
35351
|
// src/commands/update.ts
|
|
35160
35352
|
import { execSync as execSync62 } from "child_process";
|
|
35161
|
-
import * as
|
|
35353
|
+
import * as path72 from "path";
|
|
35162
35354
|
|
|
35163
35355
|
// src/commands/restartDaemonAfterUpdate.ts
|
|
35164
35356
|
async function restartDaemonAfterUpdate() {
|
|
@@ -35177,12 +35369,12 @@ async function restartDaemonAfterUpdate() {
|
|
|
35177
35369
|
// src/commands/update.ts
|
|
35178
35370
|
function isGlobalNpmInstall(dir) {
|
|
35179
35371
|
try {
|
|
35180
|
-
const resolved =
|
|
35181
|
-
if (resolved.split(
|
|
35372
|
+
const resolved = path72.resolve(dir);
|
|
35373
|
+
if (resolved.split(path72.sep).includes("node_modules")) {
|
|
35182
35374
|
return true;
|
|
35183
35375
|
}
|
|
35184
35376
|
const globalPrefix = execSync62("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
35185
|
-
return resolved.toLowerCase().startsWith(
|
|
35377
|
+
return resolved.toLowerCase().startsWith(path72.resolve(globalPrefix).toLowerCase());
|
|
35186
35378
|
} catch {
|
|
35187
35379
|
return false;
|
|
35188
35380
|
}
|
|
@@ -35227,10 +35419,7 @@ function reportCliError(error) {
|
|
|
35227
35419
|
// src/index.ts
|
|
35228
35420
|
var program = new Command();
|
|
35229
35421
|
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 }));
|
|
35230
|
-
|
|
35231
|
-
"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"
|
|
35232
|
-
).option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
|
|
35233
|
-
configHelp(syncCommand, rootConfigHelp.sync);
|
|
35422
|
+
registerSync(program);
|
|
35234
35423
|
program.command("init").description("Initialize VS Code and verify configurations").action(init5);
|
|
35235
35424
|
var commitCommand = program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <message> [files...]").action(commit);
|
|
35236
35425
|
configHelp(commitCommand, rootConfigHelp.commit);
|