@staff0rd/assist 0.774.0 → 0.775.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/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.775.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -546,6 +546,13 @@ var LEGACY_SESSIONS_KEYS = [
|
|
|
546
546
|
"windowsDaemonPort",
|
|
547
547
|
"windowsVersionCheck"
|
|
548
548
|
];
|
|
549
|
+
var LEGACY_WORKTREE_KEYS = ["watcher"];
|
|
550
|
+
function withoutKeys(value, keys) {
|
|
551
|
+
if (!value || typeof value !== "object") return value;
|
|
552
|
+
const rest = { ...value };
|
|
553
|
+
for (const key of keys) delete rest[key];
|
|
554
|
+
return rest;
|
|
555
|
+
}
|
|
549
556
|
function stripLegacyConfigKeys(config) {
|
|
550
557
|
const stripped = { ...config };
|
|
551
558
|
const news = stripped.news;
|
|
@@ -553,12 +560,10 @@ function stripLegacyConfigKeys(config) {
|
|
|
553
560
|
const { feeds: _feeds, ...rest } = news;
|
|
554
561
|
stripped.news = rest;
|
|
555
562
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
stripped.sessions = rest;
|
|
561
|
-
}
|
|
563
|
+
if (stripped.sessions)
|
|
564
|
+
stripped.sessions = withoutKeys(stripped.sessions, LEGACY_SESSIONS_KEYS);
|
|
565
|
+
if (stripped.worktree)
|
|
566
|
+
stripped.worktree = withoutKeys(stripped.worktree, LEGACY_WORKTREE_KEYS);
|
|
562
567
|
return stripped;
|
|
563
568
|
}
|
|
564
569
|
|
|
@@ -906,9 +911,11 @@ var assistConfigShape = {
|
|
|
906
911
|
})
|
|
907
912
|
).default([])
|
|
908
913
|
}).optional(),
|
|
914
|
+
autoUpdate: z5.strictObject({
|
|
915
|
+
enabled: z5.boolean().default(true)
|
|
916
|
+
}).optional(),
|
|
909
917
|
worktree: z5.strictObject({
|
|
910
918
|
enabled: z5.boolean().default(false),
|
|
911
|
-
watcher: z5.boolean().default(false),
|
|
912
919
|
trunk: z5.boolean().default(false),
|
|
913
920
|
includeDrafts: z5.boolean().default(false),
|
|
914
921
|
root: z5.string().optional(),
|
|
@@ -10936,209 +10943,11 @@ function delay(ms) {
|
|
|
10936
10943
|
return new Promise((resolve28) => setTimeout(resolve28, ms));
|
|
10937
10944
|
}
|
|
10938
10945
|
|
|
10939
|
-
// src/commands/sessions/daemon/originForCwd.ts
|
|
10940
|
-
var cache = /* @__PURE__ */ new Map();
|
|
10941
|
-
function originResolutionForCwd(cwd) {
|
|
10942
|
-
if (!cwd) return void 0;
|
|
10943
|
-
const cached = cache.get(cwd);
|
|
10944
|
-
if (cached !== void 0) return { origin: cached, stable: true };
|
|
10945
|
-
const resolved = resolveCurrentOrigin(cwd);
|
|
10946
|
-
if (resolved.stable) cache.set(cwd, resolved.origin);
|
|
10947
|
-
return resolved;
|
|
10948
|
-
}
|
|
10949
|
-
function originForCwd(cwd) {
|
|
10950
|
-
return originResolutionForCwd(cwd)?.origin;
|
|
10951
|
-
}
|
|
10952
|
-
|
|
10953
|
-
// src/commands/sessions/daemon/repoDirExists.ts
|
|
10954
|
-
import { existsSync as existsSync31 } from "fs";
|
|
10955
|
-
function repoDirExists(cwd) {
|
|
10956
|
-
return existsSync31(cwd);
|
|
10957
|
-
}
|
|
10958
|
-
|
|
10959
|
-
// src/commands/sessions/daemon/worktree/git.ts
|
|
10960
|
-
import { execFile as execFile2, execFileSync as execFileSync2 } from "child_process";
|
|
10961
|
-
function isWindowsPath(cwd) {
|
|
10962
|
-
return /^[A-Za-z]:[\\/]/.test(cwd);
|
|
10963
|
-
}
|
|
10964
|
-
function gitInvocation(cwd, args) {
|
|
10965
|
-
const windows = isWindowsPath(cwd);
|
|
10966
|
-
return {
|
|
10967
|
-
file: windows ? "git.exe" : "git",
|
|
10968
|
-
argv: windows ? ["-C", cwd, ...args] : args,
|
|
10969
|
-
options: {
|
|
10970
|
-
encoding: "utf8",
|
|
10971
|
-
windowsHide: true,
|
|
10972
|
-
...windows ? {} : { cwd }
|
|
10973
|
-
}
|
|
10974
|
-
};
|
|
10975
|
-
}
|
|
10976
|
-
function git(cwd, args) {
|
|
10977
|
-
const { file, argv, options: options2 } = gitInvocation(cwd, args);
|
|
10978
|
-
return new Promise((resolve28, reject) => {
|
|
10979
|
-
execFile2(file, argv, options2, (error, stdout) => {
|
|
10980
|
-
if (error) reject(error);
|
|
10981
|
-
else resolve28(stdout.toString());
|
|
10982
|
-
});
|
|
10983
|
-
});
|
|
10984
|
-
}
|
|
10985
|
-
async function gitOrNull(cwd, args) {
|
|
10986
|
-
try {
|
|
10987
|
-
return (await git(cwd, args)).trim() || null;
|
|
10988
|
-
} catch {
|
|
10989
|
-
return null;
|
|
10990
|
-
}
|
|
10991
|
-
}
|
|
10992
|
-
async function gitResult(cwd, args) {
|
|
10993
|
-
try {
|
|
10994
|
-
return { ok: true, out: (await git(cwd, args)).trim() };
|
|
10995
|
-
} catch (error) {
|
|
10996
|
-
return {
|
|
10997
|
-
ok: false,
|
|
10998
|
-
error: error instanceof Error ? error.message : String(error)
|
|
10999
|
-
};
|
|
11000
|
-
}
|
|
11001
|
-
}
|
|
11002
|
-
function gitSyncResult(cwd, args) {
|
|
11003
|
-
try {
|
|
11004
|
-
return { ok: true, out: gitSync(cwd, args).trim() };
|
|
11005
|
-
} catch (error) {
|
|
11006
|
-
return {
|
|
11007
|
-
ok: false,
|
|
11008
|
-
error: error instanceof Error ? error.message : String(error)
|
|
11009
|
-
};
|
|
11010
|
-
}
|
|
11011
|
-
}
|
|
11012
|
-
function gitSync(cwd, args) {
|
|
11013
|
-
const { file, argv, options: options2 } = gitInvocation(cwd, args);
|
|
11014
|
-
return execFileSync2(file, argv, {
|
|
11015
|
-
...options2,
|
|
11016
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
11017
|
-
}).toString();
|
|
11018
|
-
}
|
|
11019
|
-
function gitSyncOrNull(cwd, args) {
|
|
11020
|
-
try {
|
|
11021
|
-
return gitSync(cwd, args).trim() || null;
|
|
11022
|
-
} catch {
|
|
11023
|
-
return null;
|
|
11024
|
-
}
|
|
11025
|
-
}
|
|
11026
|
-
|
|
11027
|
-
// src/commands/sessions/daemon/worktree/listWorktreePaths.ts
|
|
11028
|
-
function listWorktreePaths(cwd) {
|
|
11029
|
-
const out = gitSyncOrNull(cwd, ["worktree", "list", "--porcelain"]);
|
|
11030
|
-
if (!out) return [];
|
|
11031
|
-
return out.split("\n").filter((line) => line.startsWith("worktree ")).map((line) => line.slice("worktree ".length).trim());
|
|
11032
|
-
}
|
|
11033
|
-
function mainWorktree(cwd) {
|
|
11034
|
-
return listWorktreePaths(cwd)[0] ?? null;
|
|
11035
|
-
}
|
|
11036
|
-
function listLocalBranches(cwd) {
|
|
11037
|
-
const out = gitSyncOrNull(cwd, [
|
|
11038
|
-
"for-each-ref",
|
|
11039
|
-
"--format=%(refname:short)",
|
|
11040
|
-
"refs/heads"
|
|
11041
|
-
]);
|
|
11042
|
-
return out ? out.split("\n").map((line) => line.trim()) : [];
|
|
11043
|
-
}
|
|
11044
|
-
function gitCommonDir(cwd) {
|
|
11045
|
-
return gitSyncOrNull(cwd, [
|
|
11046
|
-
"rev-parse",
|
|
11047
|
-
"--path-format=absolute",
|
|
11048
|
-
"--git-common-dir"
|
|
11049
|
-
]);
|
|
11050
|
-
}
|
|
11051
|
-
|
|
11052
|
-
// src/shared/loadJson.ts
|
|
11053
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync11, readFileSync as readFileSync20, writeFileSync as writeFileSync21 } from "fs";
|
|
11054
|
-
import { homedir as homedir14 } from "os";
|
|
11055
|
-
import { join as join36 } from "path";
|
|
11056
|
-
function getStoreDir() {
|
|
11057
|
-
return process.env.ASSIST_STORE_DIR || join36(homedir14(), ".assist");
|
|
11058
|
-
}
|
|
11059
|
-
function getStorePath(filename) {
|
|
11060
|
-
return join36(getStoreDir(), filename);
|
|
11061
|
-
}
|
|
11062
|
-
function loadJson(filename) {
|
|
11063
|
-
const path106 = getStorePath(filename);
|
|
11064
|
-
if (existsSync32(path106)) {
|
|
11065
|
-
try {
|
|
11066
|
-
return JSON.parse(readFileSync20(path106, "utf8"));
|
|
11067
|
-
} catch {
|
|
11068
|
-
return {};
|
|
11069
|
-
}
|
|
11070
|
-
}
|
|
11071
|
-
return {};
|
|
11072
|
-
}
|
|
11073
|
-
function saveJson(filename, data) {
|
|
11074
|
-
const dir = getStoreDir();
|
|
11075
|
-
if (!existsSync32(dir)) {
|
|
11076
|
-
mkdirSync11(dir, { recursive: true });
|
|
11077
|
-
}
|
|
11078
|
-
writeFileSync21(getStorePath(filename), JSON.stringify(data, null, 2));
|
|
11079
|
-
}
|
|
11080
|
-
|
|
11081
|
-
// src/commands/sessions/daemon/worktree/readWorktreeRegistry.ts
|
|
11082
|
-
var REGISTRY_FILE = "worktrees.json";
|
|
11083
|
-
function readWorktreeRegistry() {
|
|
11084
|
-
const data = loadJson(REGISTRY_FILE);
|
|
11085
|
-
return Object.entries(data).filter(([, record]) => !record.reaped).map(([path106, record]) => ({ path: path106, ...record }));
|
|
11086
|
-
}
|
|
11087
|
-
function worktreeAttributionIncludingReaped(path106) {
|
|
11088
|
-
const record = loadJson(REGISTRY_FILE)[path106];
|
|
11089
|
-
return record ? { clone: record.clone, origin: record.origin } : void 0;
|
|
11090
|
-
}
|
|
11091
|
-
function recordWorktree(path106, clone, origin) {
|
|
11092
|
-
const data = loadJson(REGISTRY_FILE);
|
|
11093
|
-
data[path106] = { clone, origin };
|
|
11094
|
-
saveJson(REGISTRY_FILE, data);
|
|
11095
|
-
}
|
|
11096
|
-
function forgetWorktree(path106) {
|
|
11097
|
-
const data = loadJson(REGISTRY_FILE);
|
|
11098
|
-
const record = data[path106];
|
|
11099
|
-
if (!record || record.reaped) return;
|
|
11100
|
-
data[path106] = { ...record, reaped: true };
|
|
11101
|
-
saveJson(REGISTRY_FILE, data);
|
|
11102
|
-
}
|
|
11103
|
-
|
|
11104
|
-
// src/commands/sessions/daemon/repoGroupForCwd.ts
|
|
11105
|
-
var cache2 = /* @__PURE__ */ new Map();
|
|
11106
|
-
function repoGroupForCwd(cwd) {
|
|
11107
|
-
if (!cwd) return void 0;
|
|
11108
|
-
if (cache2.has(cwd)) return cache2.get(cwd);
|
|
11109
|
-
const { group, stable } = resolveRepoGroup(cwd);
|
|
11110
|
-
if (stable) cache2.set(cwd, group);
|
|
11111
|
-
return group;
|
|
11112
|
-
}
|
|
11113
|
-
function resolveRepoGroup(cwd) {
|
|
11114
|
-
const clone = mainWorktree(cwd);
|
|
11115
|
-
const origin = clone ? originResolutionForCwd(clone) : void 0;
|
|
11116
|
-
if (clone && origin)
|
|
11117
|
-
return {
|
|
11118
|
-
group: hostedGroup(origin.origin, clone),
|
|
11119
|
-
stable: origin.stable
|
|
11120
|
-
};
|
|
11121
|
-
const reaped = worktreeAttributionIncludingReaped(cwd);
|
|
11122
|
-
if (!reaped) return { group: void 0, stable: repoDirExists(cwd) };
|
|
11123
|
-
const current = currentOriginOfClone(reaped.clone);
|
|
11124
|
-
return {
|
|
11125
|
-
group: hostedGroup(current?.origin ?? reaped.origin, reaped.clone),
|
|
11126
|
-
stable: current?.stable === true
|
|
11127
|
-
};
|
|
11128
|
-
}
|
|
11129
|
-
function currentOriginOfClone(clone) {
|
|
11130
|
-
const main = mainWorktree(clone);
|
|
11131
|
-
return main ? originResolutionForCwd(main) : void 0;
|
|
11132
|
-
}
|
|
11133
|
-
function hostedGroup(origin, clone) {
|
|
11134
|
-
return { origin, clone };
|
|
11135
|
-
}
|
|
11136
|
-
|
|
11137
10946
|
// src/commands/sessions/nodes/tailscaleStatus.ts
|
|
11138
|
-
import { execFile as
|
|
11139
|
-
import { existsSync as
|
|
10947
|
+
import { execFile as execFile2 } from "child_process";
|
|
10948
|
+
import { existsSync as existsSync31 } from "fs";
|
|
11140
10949
|
import { promisify as promisify2 } from "util";
|
|
11141
|
-
var execFileAsync2 = promisify2(
|
|
10950
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
11142
10951
|
var STATUS_TIMEOUT_MS = 1e4;
|
|
11143
10952
|
var INSTALLED_CLI = {
|
|
11144
10953
|
wsl: "/mnt/c/Program Files/Tailscale/tailscale.exe",
|
|
@@ -11148,7 +10957,7 @@ var INSTALLED_CLI = {
|
|
|
11148
10957
|
function tailscaleCli() {
|
|
11149
10958
|
const platform = detectPlatform();
|
|
11150
10959
|
const installed = INSTALLED_CLI[platform];
|
|
11151
|
-
if (installed &&
|
|
10960
|
+
if (installed && existsSync31(installed)) return installed;
|
|
11152
10961
|
return platform === "wsl" ? "tailscale.exe" : "tailscale";
|
|
11153
10962
|
}
|
|
11154
10963
|
async function tailscaleStatus() {
|
|
@@ -11207,9 +11016,9 @@ async function runningStatus(status2) {
|
|
|
11207
11016
|
}
|
|
11208
11017
|
|
|
11209
11018
|
// src/commands/sessions/nodes/runTailscale.ts
|
|
11210
|
-
import { execFile as
|
|
11019
|
+
import { execFile as execFile3 } from "child_process";
|
|
11211
11020
|
import { promisify as promisify3 } from "util";
|
|
11212
|
-
var execFileAsync3 = promisify3(
|
|
11021
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
11213
11022
|
async function runTailscale(args) {
|
|
11214
11023
|
const { stdout } = await execFileAsync3(tailscaleCli(), args, {
|
|
11215
11024
|
encoding: "utf8",
|
|
@@ -11241,7 +11050,7 @@ var defaultDeps = {
|
|
|
11241
11050
|
httpsPort: tailnetHttpsPort
|
|
11242
11051
|
};
|
|
11243
11052
|
async function ensureTailscaleServe(port, deps2 = {}) {
|
|
11244
|
-
const { enabled, status: status2, serveStatus, serve, sleep:
|
|
11053
|
+
const { enabled, status: status2, serveStatus, serve, sleep: sleep3, httpsPort } = {
|
|
11245
11054
|
...defaultDeps,
|
|
11246
11055
|
...deps2
|
|
11247
11056
|
};
|
|
@@ -11256,7 +11065,7 @@ async function ensureTailscaleServe(port, deps2 = {}) {
|
|
|
11256
11065
|
return `serving ${plan2.target} at ${plan2.url}`;
|
|
11257
11066
|
} catch (error) {
|
|
11258
11067
|
if (attempt >= SERVE_WRITE_ATTEMPTS) throw error;
|
|
11259
|
-
await
|
|
11068
|
+
await sleep3(attempt * 500 + Math.random() * 500);
|
|
11260
11069
|
}
|
|
11261
11070
|
}
|
|
11262
11071
|
}
|
|
@@ -11426,16 +11235,16 @@ function attachSessionSocket(server, ctx) {
|
|
|
11426
11235
|
|
|
11427
11236
|
// src/shared/createBundleHandler.ts
|
|
11428
11237
|
import { createHash } from "crypto";
|
|
11429
|
-
import { readFileSync as
|
|
11430
|
-
import { dirname as dirname21, join as
|
|
11238
|
+
import { readFileSync as readFileSync20, statSync as statSync5 } from "fs";
|
|
11239
|
+
import { dirname as dirname21, join as join36 } from "path";
|
|
11431
11240
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
11432
11241
|
function createBundleHandler(importMetaUrl, bundlePath, contentType = "application/javascript") {
|
|
11433
|
-
const file =
|
|
11242
|
+
const file = join36(dirname21(fileURLToPath4(importMetaUrl)), bundlePath);
|
|
11434
11243
|
let cache6;
|
|
11435
11244
|
return (req, res) => {
|
|
11436
11245
|
const mtimeMs = statSync5(file).mtimeMs;
|
|
11437
11246
|
if (cache6?.mtimeMs !== mtimeMs) {
|
|
11438
|
-
const body =
|
|
11247
|
+
const body = readFileSync20(file, "utf8");
|
|
11439
11248
|
const etag = `"${createHash("sha256").update(body).digest("hex").slice(0, 16)}"`;
|
|
11440
11249
|
cache6 = { body, etag, mtimeMs };
|
|
11441
11250
|
}
|
|
@@ -11475,12 +11284,12 @@ function createFallbackHandler(routes3, htmlHandler2, extra) {
|
|
|
11475
11284
|
}
|
|
11476
11285
|
|
|
11477
11286
|
// src/commands/backlog/resolveRepoLocation.ts
|
|
11478
|
-
import { existsSync as
|
|
11287
|
+
import { existsSync as existsSync32 } from "fs";
|
|
11479
11288
|
function resolveRepoLocation(origin, knownCwd, baseDir) {
|
|
11480
11289
|
if (knownCwd) return { cwd: knownCwd };
|
|
11481
11290
|
const target = cloneTargetDir(origin, baseDir);
|
|
11482
11291
|
if (!target) return {};
|
|
11483
|
-
if (
|
|
11292
|
+
if (existsSync32(target) && getCurrentOrigin(target) === origin)
|
|
11484
11293
|
return { cwd: target };
|
|
11485
11294
|
return { cloneTarget: target };
|
|
11486
11295
|
}
|
|
@@ -11889,9 +11698,9 @@ function getSessionParam(req) {
|
|
|
11889
11698
|
}
|
|
11890
11699
|
|
|
11891
11700
|
// src/commands/sessions/web/execGit.ts
|
|
11892
|
-
import { execFile as
|
|
11701
|
+
import { execFile as execFile4 } from "child_process";
|
|
11893
11702
|
import { promisify as promisify4 } from "util";
|
|
11894
|
-
var execFileAsync4 = promisify4(
|
|
11703
|
+
var execFileAsync4 = promisify4(execFile4);
|
|
11895
11704
|
async function execGit(cwd, args, opts = {}) {
|
|
11896
11705
|
const { maxBuffer, allowFailure } = opts;
|
|
11897
11706
|
const { file, argv } = /^[A-Za-z]:[\\/]/.test(cwd) ? { file: "git.exe", argv: ["-C", cwd, ...args] } : { file: "git", argv: args };
|
|
@@ -12080,17 +11889,17 @@ async function commitPaths(cwd, sha) {
|
|
|
12080
11889
|
}
|
|
12081
11890
|
|
|
12082
11891
|
// src/commands/sessions/web/committedPaths.ts
|
|
12083
|
-
var
|
|
11892
|
+
var cache = /* @__PURE__ */ new Map();
|
|
12084
11893
|
var inFlight = /* @__PURE__ */ new Map();
|
|
12085
11894
|
var CACHE_TTL_MS = 1e4;
|
|
12086
11895
|
async function committedPaths(cwd, sessionId) {
|
|
12087
11896
|
const key = `${cwd} ${sessionId}`;
|
|
12088
|
-
const cached =
|
|
11897
|
+
const cached = cache.get(key);
|
|
12089
11898
|
if (cached && cached.expiresAt > Date.now()) return cached.value;
|
|
12090
11899
|
const pending = inFlight.get(key);
|
|
12091
11900
|
if (pending) return pending;
|
|
12092
11901
|
const lookup = loadCommittedPaths(cwd, sessionId).then((value) => {
|
|
12093
|
-
|
|
11902
|
+
cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
12094
11903
|
return value;
|
|
12095
11904
|
}).finally(() => inFlight.delete(key));
|
|
12096
11905
|
inFlight.set(key, lookup);
|
|
@@ -12786,6 +12595,15 @@ var harnessConfigHelp = [
|
|
|
12786
12595
|
}
|
|
12787
12596
|
];
|
|
12788
12597
|
|
|
12598
|
+
// src/commands/sessions/daemon/autoUpdateConfigHelp.ts
|
|
12599
|
+
var autoUpdateConfigHelp = [
|
|
12600
|
+
{
|
|
12601
|
+
key: "autoUpdate.enabled",
|
|
12602
|
+
setter: "assist config set autoUpdate.enabled false -g",
|
|
12603
|
+
note: "when this install is a git clone, the daemon pulls and builds it in the background as origin moves (assist watch wait --pull --build), logging each lap to ~/.assist/watchers/; a branch that cannot fast-forward starts a claude session to reconcile it and the loop resumes once it closes. Set false to stop it (default on)"
|
|
12604
|
+
}
|
|
12605
|
+
];
|
|
12606
|
+
|
|
12789
12607
|
// src/commands/branch/branchConfigHelp.ts
|
|
12790
12608
|
var branchConfigHelp = [
|
|
12791
12609
|
{
|
|
@@ -13279,11 +13097,6 @@ var sessionsConfigHelp = [
|
|
|
13279
13097
|
setter: "assist config set worktree.enabled true -g --repo",
|
|
13280
13098
|
note: "opt in per repo: spill concurrent sessions into adjacent <clone>-N worktrees (default off)"
|
|
13281
13099
|
},
|
|
13282
|
-
{
|
|
13283
|
-
key: "worktree.watcher",
|
|
13284
|
-
setter: "assist config set worktree.watcher true -g --repo",
|
|
13285
|
-
note: "a backlog run also starts one starred console session in the clone running assist watch loop (no claude, relaunched after a daemon restart), so the built version stays current while the run works in its worktree; requires worktree.enabled and an auto-build run entry (default off)"
|
|
13286
|
-
},
|
|
13287
13100
|
{
|
|
13288
13101
|
key: "worktree.trunk",
|
|
13289
13102
|
setter: "assist config set worktree.trunk true -g --repo",
|
|
@@ -13390,6 +13203,7 @@ var verifyConfigHelp = [
|
|
|
13390
13203
|
var configHelpEntries = [
|
|
13391
13204
|
...Object.values(rootConfigHelp).flat(),
|
|
13392
13205
|
...adviceConfigHelp,
|
|
13206
|
+
...autoUpdateConfigHelp,
|
|
13393
13207
|
...backlogConfigHelp,
|
|
13394
13208
|
...backupConfigHelp,
|
|
13395
13209
|
...branchConfigHelp,
|
|
@@ -13537,26 +13351,26 @@ function handleServerRuns(req, res) {
|
|
|
13537
13351
|
}
|
|
13538
13352
|
|
|
13539
13353
|
// src/commands/sessions/web/getReviewSynthesis.ts
|
|
13540
|
-
import { execFile as
|
|
13541
|
-
import { readFileSync as
|
|
13542
|
-
import { homedir as
|
|
13543
|
-
import { basename as basename11, join as
|
|
13354
|
+
import { execFile as execFile5 } from "child_process";
|
|
13355
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
13356
|
+
import { homedir as homedir14 } from "os";
|
|
13357
|
+
import { basename as basename11, join as join38 } from "path";
|
|
13544
13358
|
import { promisify as promisify5 } from "util";
|
|
13545
13359
|
|
|
13546
13360
|
// src/commands/sessions/web/findSynthesisForBranch.ts
|
|
13547
|
-
import { existsSync as
|
|
13548
|
-
import { basename as basename10, dirname as dirname22, join as
|
|
13361
|
+
import { existsSync as existsSync33, readdirSync as readdirSync5, statSync as statSync6 } from "fs";
|
|
13362
|
+
import { basename as basename10, dirname as dirname22, join as join37 } from "path";
|
|
13549
13363
|
function findSynthesisForBranch(repoReviewsDir, branch2) {
|
|
13550
|
-
const branchKeyPath =
|
|
13364
|
+
const branchKeyPath = join37(repoReviewsDir, `${branch2}-`);
|
|
13551
13365
|
const parent = dirname22(branchKeyPath);
|
|
13552
13366
|
const branchPrefix = basename10(branchKeyPath);
|
|
13553
|
-
if (!
|
|
13554
|
-
const synthesisFiles = readdirSync5(parent).filter((name) => name.startsWith(branchPrefix)).map((name) =>
|
|
13367
|
+
if (!existsSync33(parent)) return null;
|
|
13368
|
+
const synthesisFiles = readdirSync5(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join37(parent, name, "synthesis.md")).filter((path106) => existsSync33(path106)).map((path106) => ({ path: path106, mtime: statSync6(path106).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
13555
13369
|
return synthesisFiles[0]?.path ?? null;
|
|
13556
13370
|
}
|
|
13557
13371
|
|
|
13558
13372
|
// src/commands/sessions/web/getReviewSynthesis.ts
|
|
13559
|
-
var execFileAsync5 = promisify5(
|
|
13373
|
+
var execFileAsync5 = promisify5(execFile5);
|
|
13560
13374
|
function runGit2(cwd, args) {
|
|
13561
13375
|
return execFileAsync5("git", args, {
|
|
13562
13376
|
encoding: "utf8",
|
|
@@ -13569,8 +13383,8 @@ async function resolveSynthesisPath(cwd) {
|
|
|
13569
13383
|
runGit2(cwd, ["rev-parse", "--show-toplevel"]),
|
|
13570
13384
|
runGit2(cwd, ["rev-parse", "--abbrev-ref", "HEAD"])
|
|
13571
13385
|
]);
|
|
13572
|
-
const repoReviewsDir =
|
|
13573
|
-
|
|
13386
|
+
const repoReviewsDir = join38(
|
|
13387
|
+
homedir14(),
|
|
13574
13388
|
".assist",
|
|
13575
13389
|
"reviews",
|
|
13576
13390
|
basename11(repoRoot2)
|
|
@@ -13586,7 +13400,7 @@ async function getReviewSynthesis(req, res) {
|
|
|
13586
13400
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
13587
13401
|
return;
|
|
13588
13402
|
}
|
|
13589
|
-
respondJson(res, 200, { synthesis:
|
|
13403
|
+
respondJson(res, 200, { synthesis: readFileSync21(path106, "utf8") });
|
|
13590
13404
|
} catch {
|
|
13591
13405
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
13592
13406
|
}
|
|
@@ -13609,7 +13423,7 @@ var EMPTY = {
|
|
|
13609
13423
|
defaultBranch: null,
|
|
13610
13424
|
onDefaultBranch: false
|
|
13611
13425
|
};
|
|
13612
|
-
var
|
|
13426
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
13613
13427
|
async function currentBranch2(cwd) {
|
|
13614
13428
|
try {
|
|
13615
13429
|
const branch2 = (await execGit(cwd, ["rev-parse", "--abbrev-ref", "HEAD"])).trim();
|
|
@@ -13632,7 +13446,7 @@ async function resolve11(cwd) {
|
|
|
13632
13446
|
}
|
|
13633
13447
|
async function gitBranchInfo(cwd) {
|
|
13634
13448
|
const now = Date.now();
|
|
13635
|
-
const cached =
|
|
13449
|
+
const cached = cache2.get(cwd);
|
|
13636
13450
|
if (cached && cached.expires > now) return cached.value;
|
|
13637
13451
|
let value = EMPTY;
|
|
13638
13452
|
try {
|
|
@@ -13640,7 +13454,7 @@ async function gitBranchInfo(cwd) {
|
|
|
13640
13454
|
} catch {
|
|
13641
13455
|
value = EMPTY;
|
|
13642
13456
|
}
|
|
13643
|
-
|
|
13457
|
+
cache2.set(cwd, { value, expires: now + CACHE_TTL_MS2 });
|
|
13644
13458
|
return value;
|
|
13645
13459
|
}
|
|
13646
13460
|
|
|
@@ -13796,10 +13610,10 @@ function protocolMismatched(msg) {
|
|
|
13796
13610
|
return typeof msg.protocol === "number" && msg.protocol !== PROTOCOL_VERSION;
|
|
13797
13611
|
}
|
|
13798
13612
|
|
|
13799
|
-
// src/commands/sessions/
|
|
13613
|
+
// src/commands/sessions/daemon/requestDaemonReply.ts
|
|
13800
13614
|
import { createInterface as createInterface5 } from "readline";
|
|
13801
13615
|
var QUERY_TIMEOUT_MS = 3e3;
|
|
13802
|
-
async function
|
|
13616
|
+
async function requestDaemonReply(request, replyType) {
|
|
13803
13617
|
let socket;
|
|
13804
13618
|
try {
|
|
13805
13619
|
socket = await connectToDaemon();
|
|
@@ -13819,16 +13633,21 @@ async function queryNodes() {
|
|
|
13819
13633
|
lines2.on("line", (line) => {
|
|
13820
13634
|
try {
|
|
13821
13635
|
const data = JSON.parse(line);
|
|
13822
|
-
if (data.type ===
|
|
13636
|
+
if (data.type === replyType) finish2(data);
|
|
13823
13637
|
} catch {
|
|
13824
13638
|
}
|
|
13825
13639
|
});
|
|
13826
13640
|
socket.on("error", () => finish2(void 0));
|
|
13827
|
-
socket.write(`${JSON.stringify(
|
|
13641
|
+
socket.write(`${JSON.stringify(request)}
|
|
13828
13642
|
`);
|
|
13829
13643
|
});
|
|
13830
13644
|
}
|
|
13831
13645
|
|
|
13646
|
+
// src/commands/sessions/nodes/queryNodes.ts
|
|
13647
|
+
function queryNodes() {
|
|
13648
|
+
return requestDaemonReply({ type: "nodes" }, "nodes");
|
|
13649
|
+
}
|
|
13650
|
+
|
|
13832
13651
|
// src/commands/sessions/web/health.ts
|
|
13833
13652
|
async function health(_req, res) {
|
|
13834
13653
|
const [reachable, nodes] = await Promise.all([
|
|
@@ -13859,6 +13678,35 @@ function hotkeyBindings(_req, res) {
|
|
|
13859
13678
|
respondJson(res, 200, resolveHotkeys(loadConfig().sessions?.hotkeys));
|
|
13860
13679
|
}
|
|
13861
13680
|
|
|
13681
|
+
// src/shared/loadJson.ts
|
|
13682
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync21 } from "fs";
|
|
13683
|
+
import { homedir as homedir15 } from "os";
|
|
13684
|
+
import { join as join39 } from "path";
|
|
13685
|
+
function getStoreDir() {
|
|
13686
|
+
return process.env.ASSIST_STORE_DIR || join39(homedir15(), ".assist");
|
|
13687
|
+
}
|
|
13688
|
+
function getStorePath(filename) {
|
|
13689
|
+
return join39(getStoreDir(), filename);
|
|
13690
|
+
}
|
|
13691
|
+
function loadJson(filename) {
|
|
13692
|
+
const path106 = getStorePath(filename);
|
|
13693
|
+
if (existsSync34(path106)) {
|
|
13694
|
+
try {
|
|
13695
|
+
return JSON.parse(readFileSync22(path106, "utf8"));
|
|
13696
|
+
} catch {
|
|
13697
|
+
return {};
|
|
13698
|
+
}
|
|
13699
|
+
}
|
|
13700
|
+
return {};
|
|
13701
|
+
}
|
|
13702
|
+
function saveJson(filename, data) {
|
|
13703
|
+
const dir = getStoreDir();
|
|
13704
|
+
if (!existsSync34(dir)) {
|
|
13705
|
+
mkdirSync11(dir, { recursive: true });
|
|
13706
|
+
}
|
|
13707
|
+
writeFileSync21(getStorePath(filename), JSON.stringify(data, null, 2));
|
|
13708
|
+
}
|
|
13709
|
+
|
|
13862
13710
|
// src/commands/sessions/web/jiraSite.ts
|
|
13863
13711
|
function jiraSite(_req, res) {
|
|
13864
13712
|
const config = loadJson("jira.json");
|
|
@@ -14074,11 +13922,11 @@ function newsNavConfig(_req, res) {
|
|
|
14074
13922
|
}
|
|
14075
13923
|
|
|
14076
13924
|
// src/commands/sessions/web/releases/ghJson.ts
|
|
14077
|
-
import { execFile as
|
|
13925
|
+
import { execFile as execFile6 } from "child_process";
|
|
14078
13926
|
import { promisify as promisify6 } from "util";
|
|
14079
|
-
var execFileAsync6 = promisify6(
|
|
13927
|
+
var execFileAsync6 = promisify6(execFile6);
|
|
14080
13928
|
var CACHE_TTL_MS4 = 3e4;
|
|
14081
|
-
var
|
|
13929
|
+
var cache3 = /* @__PURE__ */ new Map();
|
|
14082
13930
|
function partialGraphqlData(error) {
|
|
14083
13931
|
const stdout = error.stdout;
|
|
14084
13932
|
if (typeof stdout !== "string") return null;
|
|
@@ -14106,12 +13954,12 @@ async function runGh(cwd, args) {
|
|
|
14106
13954
|
}
|
|
14107
13955
|
function ghJson(cwd, args) {
|
|
14108
13956
|
const key = [cwd, ...args].join("\0");
|
|
14109
|
-
const hit =
|
|
13957
|
+
const hit = cache3.get(key);
|
|
14110
13958
|
if (hit && Date.now() - hit.at < CACHE_TTL_MS4)
|
|
14111
13959
|
return hit.result;
|
|
14112
13960
|
const result = runGh(cwd, args);
|
|
14113
|
-
|
|
14114
|
-
result.catch(() =>
|
|
13961
|
+
cache3.set(key, { at: Date.now(), result });
|
|
13962
|
+
result.catch(() => cache3.delete(key));
|
|
14115
13963
|
return result;
|
|
14116
13964
|
}
|
|
14117
13965
|
|
|
@@ -14637,7 +14485,7 @@ function assertProjectScope() {
|
|
|
14637
14485
|
}
|
|
14638
14486
|
|
|
14639
14487
|
// src/commands/github/issue/assignIssueToSelf.ts
|
|
14640
|
-
import { execFileSync as
|
|
14488
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
14641
14489
|
function assignIssueToSelf(number, repo) {
|
|
14642
14490
|
const args = [
|
|
14643
14491
|
"issue",
|
|
@@ -14649,7 +14497,7 @@ function assignIssueToSelf(number, repo) {
|
|
|
14649
14497
|
"@me"
|
|
14650
14498
|
];
|
|
14651
14499
|
try {
|
|
14652
|
-
|
|
14500
|
+
execFileSync2("gh", args, {
|
|
14653
14501
|
stdio: ["ignore", "ignore", "pipe"],
|
|
14654
14502
|
encoding: "utf8"
|
|
14655
14503
|
});
|
|
@@ -14819,7 +14667,7 @@ async function nextPickup(req, res) {
|
|
|
14819
14667
|
import path27 from "path";
|
|
14820
14668
|
|
|
14821
14669
|
// src/commands/rules/readScopedRules.ts
|
|
14822
|
-
import { existsSync as
|
|
14670
|
+
import { existsSync as existsSync36, readFileSync as readFileSync23 } from "fs";
|
|
14823
14671
|
import path26 from "path";
|
|
14824
14672
|
|
|
14825
14673
|
// src/commands/rules/rulesSectionRange.ts
|
|
@@ -14855,24 +14703,24 @@ function parseRulesSection(content) {
|
|
|
14855
14703
|
const lines2 = content.split(/\r?\n/);
|
|
14856
14704
|
const range = rulesSectionRange(lines2);
|
|
14857
14705
|
if (!range) return [];
|
|
14858
|
-
const
|
|
14706
|
+
const rules2 = [];
|
|
14859
14707
|
for (const line of lines2.slice(range.start + 1, range.end)) {
|
|
14860
14708
|
const match = RULE_BULLET.exec(line);
|
|
14861
14709
|
if (!match) continue;
|
|
14862
14710
|
const code = match[1].trim();
|
|
14863
14711
|
const rest = match[2].trim();
|
|
14864
14712
|
if (code === "" || rest === "") continue;
|
|
14865
|
-
|
|
14713
|
+
rules2.push({ code, ...splitTitle(rest) });
|
|
14866
14714
|
}
|
|
14867
|
-
return
|
|
14715
|
+
return rules2;
|
|
14868
14716
|
}
|
|
14869
14717
|
|
|
14870
14718
|
// src/commands/rules/scopeDirectory.ts
|
|
14871
|
-
import { existsSync as
|
|
14719
|
+
import { existsSync as existsSync35, statSync as statSync7 } from "fs";
|
|
14872
14720
|
import path25 from "path";
|
|
14873
14721
|
function scopeDirectory(target) {
|
|
14874
14722
|
const resolved = path25.resolve(target);
|
|
14875
|
-
return
|
|
14723
|
+
return existsSync35(resolved) && statSync7(resolved).isDirectory() ? resolved : path25.dirname(resolved);
|
|
14876
14724
|
}
|
|
14877
14725
|
|
|
14878
14726
|
// src/commands/rules/readScopedRules.ts
|
|
@@ -14883,7 +14731,7 @@ function scopedClaudeFiles(target) {
|
|
|
14883
14731
|
let current = startDir;
|
|
14884
14732
|
while (true) {
|
|
14885
14733
|
const candidate = path26.join(current, "CLAUDE.md");
|
|
14886
|
-
if (
|
|
14734
|
+
if (existsSync36(candidate)) files.push(candidate);
|
|
14887
14735
|
if (current === root2 || current === path26.dirname(current)) break;
|
|
14888
14736
|
current = path26.dirname(current);
|
|
14889
14737
|
}
|
|
@@ -15194,9 +15042,9 @@ async function openInCode(req, res) {
|
|
|
15194
15042
|
}
|
|
15195
15043
|
|
|
15196
15044
|
// src/commands/sessions/web/createCachedGhJson.ts
|
|
15197
|
-
import { execFile as
|
|
15045
|
+
import { execFile as execFile7 } from "child_process";
|
|
15198
15046
|
import { promisify as promisify8 } from "util";
|
|
15199
|
-
var execFileAsync7 = promisify8(
|
|
15047
|
+
var execFileAsync7 = promisify8(execFile7);
|
|
15200
15048
|
var CACHE_TTL_MS5 = 3e4;
|
|
15201
15049
|
function createCachedGhJson(args, parse5, fallback, options2 = {}) {
|
|
15202
15050
|
const { cacheFallback = true } = options2;
|
|
@@ -15294,7 +15142,7 @@ function peerTimeoutFor(pathname) {
|
|
|
15294
15142
|
}
|
|
15295
15143
|
|
|
15296
15144
|
// src/commands/sessions/web/isQuietPoll.ts
|
|
15297
|
-
var POLLED_PATHS = /* @__PURE__ */ new Set(["/api/git-status"]);
|
|
15145
|
+
var POLLED_PATHS = /* @__PURE__ */ new Set(["/api/git-status", "/api/updates"]);
|
|
15298
15146
|
function isQuietPoll(pathname, status2) {
|
|
15299
15147
|
return POLLED_PATHS.has(pathname) && status2 >= 200 && status2 < 300;
|
|
15300
15148
|
}
|
|
@@ -15447,9 +15295,9 @@ async function previewImage(req, res) {
|
|
|
15447
15295
|
}
|
|
15448
15296
|
|
|
15449
15297
|
// src/commands/sessions/web/prStatus.ts
|
|
15450
|
-
import { execFile as
|
|
15298
|
+
import { execFile as execFile8 } from "child_process";
|
|
15451
15299
|
import { promisify as promisify9 } from "util";
|
|
15452
|
-
var execFileAsync8 = promisify9(
|
|
15300
|
+
var execFileAsync8 = promisify9(execFile8);
|
|
15453
15301
|
function toPrSummary(parsed) {
|
|
15454
15302
|
if (typeof parsed.number !== "number") return null;
|
|
15455
15303
|
return {
|
|
@@ -16058,19 +15906,19 @@ async function revertDiffFile(req, res) {
|
|
|
16058
15906
|
|
|
16059
15907
|
// src/commands/run/runCommandToCompletion.ts
|
|
16060
15908
|
import { spawn as spawn4 } from "child_process";
|
|
16061
|
-
import { existsSync as
|
|
15909
|
+
import { existsSync as existsSync38 } from "fs";
|
|
16062
15910
|
|
|
16063
15911
|
// src/commands/run/resolveCommand.ts
|
|
16064
|
-
import { execFileSync as
|
|
16065
|
-
import { existsSync as
|
|
15912
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
15913
|
+
import { existsSync as existsSync37 } from "fs";
|
|
16066
15914
|
import { dirname as dirname23, join as join40, resolve as resolve13 } from "path";
|
|
16067
15915
|
function resolveCommand(command) {
|
|
16068
15916
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
16069
15917
|
try {
|
|
16070
|
-
const gitPath =
|
|
15918
|
+
const gitPath = execFileSync3("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
16071
15919
|
const gitRoot = resolve13(dirname23(gitPath), "..");
|
|
16072
15920
|
const gitBash = join40(gitRoot, "bin", "bash.exe");
|
|
16073
|
-
if (
|
|
15921
|
+
if (existsSync37(gitBash)) return gitBash;
|
|
16074
15922
|
} catch {
|
|
16075
15923
|
return command;
|
|
16076
15924
|
}
|
|
@@ -16080,7 +15928,7 @@ function resolveCommand(command) {
|
|
|
16080
15928
|
// src/commands/run/runCommandToCompletion.ts
|
|
16081
15929
|
function runCommandToCompletion(command, args, env, cwd, quiet) {
|
|
16082
15930
|
return new Promise((resolveResult) => {
|
|
16083
|
-
if (cwd && !
|
|
15931
|
+
if (cwd && !existsSync38(cwd)) {
|
|
16084
15932
|
resolveResult({
|
|
16085
15933
|
kind: "failed",
|
|
16086
15934
|
message: `Failed to execute command: cwd ${cwd} does not exist`
|
|
@@ -17152,6 +17000,194 @@ function unsetConfig(req, res) {
|
|
|
17152
17000
|
});
|
|
17153
17001
|
}
|
|
17154
17002
|
|
|
17003
|
+
// src/commands/watch/resolveUpstream.ts
|
|
17004
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
17005
|
+
function runGit3(args, cwd) {
|
|
17006
|
+
return execFileSync4("git", args, {
|
|
17007
|
+
encoding: "utf8",
|
|
17008
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
17009
|
+
cwd
|
|
17010
|
+
}).trim();
|
|
17011
|
+
}
|
|
17012
|
+
function resolveUpstream(cwd) {
|
|
17013
|
+
try {
|
|
17014
|
+
runGit3(["rev-parse", "--is-inside-work-tree"], cwd);
|
|
17015
|
+
} catch {
|
|
17016
|
+
throw new Error(
|
|
17017
|
+
"not a git repository \u2014 run assist watch wait from inside a repo"
|
|
17018
|
+
);
|
|
17019
|
+
}
|
|
17020
|
+
let branch2;
|
|
17021
|
+
try {
|
|
17022
|
+
branch2 = runGit3(["symbolic-ref", "--quiet", "--short", "HEAD"], cwd);
|
|
17023
|
+
} catch {
|
|
17024
|
+
throw new Error(
|
|
17025
|
+
"HEAD is detached \u2014 check out a branch before waiting on its upstream"
|
|
17026
|
+
);
|
|
17027
|
+
}
|
|
17028
|
+
try {
|
|
17029
|
+
return {
|
|
17030
|
+
branch: branch2,
|
|
17031
|
+
upstream: runGit3(
|
|
17032
|
+
["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
|
|
17033
|
+
cwd
|
|
17034
|
+
)
|
|
17035
|
+
};
|
|
17036
|
+
} catch {
|
|
17037
|
+
throw new Error(
|
|
17038
|
+
`branch "${branch2}" has no upstream \u2014 set one with: git push -u origin ${branch2}`
|
|
17039
|
+
);
|
|
17040
|
+
}
|
|
17041
|
+
}
|
|
17042
|
+
|
|
17043
|
+
// src/commands/watch/changedPaths.ts
|
|
17044
|
+
function changedPaths(from, cwd) {
|
|
17045
|
+
return runGit3(["diff", "--name-only", `${from}..HEAD`], cwd).split("\n").filter((line) => line.length > 0);
|
|
17046
|
+
}
|
|
17047
|
+
|
|
17048
|
+
// src/commands/watch/readBuiltVersion.ts
|
|
17049
|
+
import { join as join41 } from "path";
|
|
17050
|
+
function readBuiltVersion(cwd) {
|
|
17051
|
+
try {
|
|
17052
|
+
const root2 = runGit3(["rev-parse", "--show-toplevel"], cwd);
|
|
17053
|
+
return readPackageJson(join41(root2, "package.json")).version ?? "unknown";
|
|
17054
|
+
} catch {
|
|
17055
|
+
return "unknown";
|
|
17056
|
+
}
|
|
17057
|
+
}
|
|
17058
|
+
|
|
17059
|
+
// src/commands/watch/restartRules.ts
|
|
17060
|
+
var webUiPrefix = "src/commands/sessions/web/ui/";
|
|
17061
|
+
var sessionsPrefix = "src/commands/sessions/";
|
|
17062
|
+
var restartRules = [
|
|
17063
|
+
{
|
|
17064
|
+
target: "webserver",
|
|
17065
|
+
matches: (path106) => path106.startsWith(webUiPrefix),
|
|
17066
|
+
advice: "restart the web server, then hard-reload the browser tab"
|
|
17067
|
+
},
|
|
17068
|
+
{
|
|
17069
|
+
target: "daemon",
|
|
17070
|
+
matches: (path106) => path106.startsWith(sessionsPrefix) && !path106.startsWith(webUiPrefix),
|
|
17071
|
+
advice: "restart the daemon"
|
|
17072
|
+
}
|
|
17073
|
+
];
|
|
17074
|
+
|
|
17075
|
+
// src/commands/watch/restartTargets.ts
|
|
17076
|
+
function restartTargets(paths) {
|
|
17077
|
+
return restartRules.filter((rule) => paths.some(rule.matches)).map((rule) => rule.target);
|
|
17078
|
+
}
|
|
17079
|
+
|
|
17080
|
+
// src/commands/sessions/web/updates/pendingRestarts.ts
|
|
17081
|
+
function targetsSince(commit2, target, changedSince2) {
|
|
17082
|
+
return commit2 !== void 0 && restartTargets(changedSince2(commit2)).includes(target);
|
|
17083
|
+
}
|
|
17084
|
+
function pendingRestarts(input) {
|
|
17085
|
+
const { daemonVersion, built, changedSince: changedSince2 } = input;
|
|
17086
|
+
const daemon = daemonVersion !== void 0 && (built !== "unknown" && daemonVersion !== built || targetsSince(input.daemonStartCommit, "daemon", changedSince2));
|
|
17087
|
+
const web3 = targetsSince(input.webStartCommit, "webserver", changedSince2);
|
|
17088
|
+
return [
|
|
17089
|
+
...daemon ? ["daemon"] : [],
|
|
17090
|
+
...web3 ? ["webserver"] : []
|
|
17091
|
+
];
|
|
17092
|
+
}
|
|
17093
|
+
|
|
17094
|
+
// src/shared/stripAnsi.ts
|
|
17095
|
+
var ANSI = new RegExp(
|
|
17096
|
+
`${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`,
|
|
17097
|
+
"g"
|
|
17098
|
+
);
|
|
17099
|
+
function stripAnsi(text17) {
|
|
17100
|
+
return text17.replace(ANSI, "");
|
|
17101
|
+
}
|
|
17102
|
+
|
|
17103
|
+
// src/commands/sessions/daemon/worktree/watcherLogPath.ts
|
|
17104
|
+
import { createHash as createHash2 } from "crypto";
|
|
17105
|
+
import { homedir as homedir16 } from "os";
|
|
17106
|
+
import { basename as basename12, join as join42 } from "path";
|
|
17107
|
+
|
|
17108
|
+
// src/commands/sessions/daemon/worktree/canonicalTreePath.ts
|
|
17109
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
17110
|
+
import { resolve as resolve14 } from "path";
|
|
17111
|
+
function canonicalTreePath(path106) {
|
|
17112
|
+
try {
|
|
17113
|
+
return realpathSync2(path106);
|
|
17114
|
+
} catch {
|
|
17115
|
+
return resolve14(path106);
|
|
17116
|
+
}
|
|
17117
|
+
}
|
|
17118
|
+
|
|
17119
|
+
// src/commands/sessions/daemon/worktree/watcherLogPath.ts
|
|
17120
|
+
function watcherLogPath(cwd) {
|
|
17121
|
+
const clone = canonicalTreePath(cwd);
|
|
17122
|
+
const key = createHash2("sha1").update(clone).digest("hex").slice(0, 8);
|
|
17123
|
+
const dir = process.env.ASSIST_WATCHER_LOG_DIR ?? join42(homedir16(), ".assist", "watchers");
|
|
17124
|
+
return join42(dir, `${basename12(clone) || "root"}-${key}.log`);
|
|
17125
|
+
}
|
|
17126
|
+
|
|
17127
|
+
// src/commands/sessions/web/updates/readUpdateHistory.ts
|
|
17128
|
+
var HISTORY_LINES = 200;
|
|
17129
|
+
function readUpdateHistory(installDir) {
|
|
17130
|
+
return readLogTail(watcherLogPath(installDir), HISTORY_LINES * 2).flatMap((line) => line.split("\r")).map((line) => stripAnsi(line).trimEnd()).filter((line) => line.trim().length > 0).slice(-HISTORY_LINES);
|
|
17131
|
+
}
|
|
17132
|
+
|
|
17133
|
+
// src/commands/watch/headCommit.ts
|
|
17134
|
+
function headCommit3(cwd) {
|
|
17135
|
+
try {
|
|
17136
|
+
return runGit3(["rev-parse", "HEAD"], cwd);
|
|
17137
|
+
} catch {
|
|
17138
|
+
return void 0;
|
|
17139
|
+
}
|
|
17140
|
+
}
|
|
17141
|
+
|
|
17142
|
+
// src/commands/sessions/web/updates/webStartCommit.ts
|
|
17143
|
+
var captured;
|
|
17144
|
+
var webStartCommit = {
|
|
17145
|
+
capture: () => {
|
|
17146
|
+
captured = headCommit3(getInstallDir());
|
|
17147
|
+
},
|
|
17148
|
+
value: () => captured
|
|
17149
|
+
};
|
|
17150
|
+
|
|
17151
|
+
// src/commands/sessions/web/updates/updates.ts
|
|
17152
|
+
function changedSince(installDir) {
|
|
17153
|
+
return (commit2) => {
|
|
17154
|
+
try {
|
|
17155
|
+
return changedPaths(commit2, installDir);
|
|
17156
|
+
} catch {
|
|
17157
|
+
return [];
|
|
17158
|
+
}
|
|
17159
|
+
};
|
|
17160
|
+
}
|
|
17161
|
+
async function updates(_req, res) {
|
|
17162
|
+
const installDir = getInstallDir();
|
|
17163
|
+
const reply2 = await requestDaemonReply(
|
|
17164
|
+
{ type: "auto-update" },
|
|
17165
|
+
"auto-update"
|
|
17166
|
+
);
|
|
17167
|
+
const built = readBuiltVersion(installDir);
|
|
17168
|
+
const status2 = {
|
|
17169
|
+
nodeName: resolveNodeName(),
|
|
17170
|
+
installDir,
|
|
17171
|
+
running: reply2?.version ?? ASSIST_VERSION,
|
|
17172
|
+
built,
|
|
17173
|
+
restart: pendingRestarts({
|
|
17174
|
+
daemonVersion: reply2?.version,
|
|
17175
|
+
daemonStartCommit: reply2?.startCommit,
|
|
17176
|
+
webStartCommit: webStartCommit.value(),
|
|
17177
|
+
built,
|
|
17178
|
+
changedSince: changedSince(installDir)
|
|
17179
|
+
}),
|
|
17180
|
+
daemonReachable: reply2 !== void 0,
|
|
17181
|
+
loop: reply2?.loop ?? {
|
|
17182
|
+
phase: "off",
|
|
17183
|
+
since: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17184
|
+
reason: "daemon not reachable"
|
|
17185
|
+
},
|
|
17186
|
+
history: readUpdateHistory(installDir)
|
|
17187
|
+
};
|
|
17188
|
+
respondJson(res, 200, status2);
|
|
17189
|
+
}
|
|
17190
|
+
|
|
17155
17191
|
// src/commands/sessions/web/readRequestBuffer.ts
|
|
17156
17192
|
async function readRequestBuffer(req, limit) {
|
|
17157
17193
|
const chunks = [];
|
|
@@ -17173,7 +17209,7 @@ async function readRequestBuffer(req, limit) {
|
|
|
17173
17209
|
|
|
17174
17210
|
// src/commands/sessions/web/stageAttachment.ts
|
|
17175
17211
|
import { mkdir as mkdir4, mkdtemp, writeFile as writeFile2 } from "fs/promises";
|
|
17176
|
-
import { extname as extname2, join as
|
|
17212
|
+
import { extname as extname2, join as join43 } from "path";
|
|
17177
17213
|
function extensionFromMime(contentType) {
|
|
17178
17214
|
const mime = contentType.split(";")[0].trim().toLowerCase();
|
|
17179
17215
|
const known = attachmentMimeTypes[mime];
|
|
@@ -17201,9 +17237,9 @@ function safeBaseName(name) {
|
|
|
17201
17237
|
async function stageAttachment(name, contentType, body) {
|
|
17202
17238
|
const ext = pickExtension(name, contentType);
|
|
17203
17239
|
await mkdir4(stagedAttachmentsDir, { recursive: true });
|
|
17204
|
-
const dir = await mkdtemp(
|
|
17240
|
+
const dir = await mkdtemp(join43(stagedAttachmentsDir, "upload-"));
|
|
17205
17241
|
const alt = safeBaseName(name);
|
|
17206
|
-
const filePath =
|
|
17242
|
+
const filePath = join43(dir, `${alt}.${ext}`);
|
|
17207
17243
|
await writeFile2(filePath, body);
|
|
17208
17244
|
return { dir, filePath, alt };
|
|
17209
17245
|
}
|
|
@@ -17251,17 +17287,17 @@ async function uploadPrImage(req, res) {
|
|
|
17251
17287
|
import { readFile as readFile3, stat as stat4, writeFile as writeFile3 } from "fs/promises";
|
|
17252
17288
|
|
|
17253
17289
|
// src/commands/sessions/web/formatWithOxfmt.ts
|
|
17254
|
-
import { execFile as
|
|
17255
|
-
import { existsSync as
|
|
17256
|
-
import { dirname as dirname24, join as
|
|
17290
|
+
import { execFile as execFile9 } from "child_process";
|
|
17291
|
+
import { existsSync as existsSync39 } from "fs";
|
|
17292
|
+
import { dirname as dirname24, join as join44 } from "path";
|
|
17257
17293
|
import { promisify as promisify10 } from "util";
|
|
17258
|
-
var execFileAsync9 = promisify10(
|
|
17294
|
+
var execFileAsync9 = promisify10(execFile9);
|
|
17259
17295
|
var TIMEOUT_MS = 15e3;
|
|
17260
17296
|
function findOxfmtScript(root2) {
|
|
17261
17297
|
let dir = root2;
|
|
17262
17298
|
for (; ; ) {
|
|
17263
|
-
const candidate =
|
|
17264
|
-
if (
|
|
17299
|
+
const candidate = join44(dir, "node_modules", "oxfmt", "bin", "oxfmt");
|
|
17300
|
+
if (existsSync39(candidate)) return candidate;
|
|
17265
17301
|
const parent = dirname24(dir);
|
|
17266
17302
|
if (parent === dir) return void 0;
|
|
17267
17303
|
dir = parent;
|
|
@@ -17331,7 +17367,7 @@ async function writeFileContent(req, res) {
|
|
|
17331
17367
|
}
|
|
17332
17368
|
|
|
17333
17369
|
// src/commands/sessions/web/createCssHandler.ts
|
|
17334
|
-
import { createHash as
|
|
17370
|
+
import { createHash as createHash3 } from "crypto";
|
|
17335
17371
|
import { readFileSync as readFileSync24 } from "fs";
|
|
17336
17372
|
import { createRequire } from "module";
|
|
17337
17373
|
var require2 = createRequire(import.meta.url);
|
|
@@ -17341,7 +17377,7 @@ function createCssHandler(packageEntry) {
|
|
|
17341
17377
|
if (!cache6) {
|
|
17342
17378
|
const resolved = require2.resolve(packageEntry);
|
|
17343
17379
|
const body = readFileSync24(resolved, "utf8");
|
|
17344
|
-
const etag = `"${
|
|
17380
|
+
const etag = `"${createHash3("sha256").update(body).digest("hex").slice(0, 16)}"`;
|
|
17345
17381
|
cache6 = { body, etag };
|
|
17346
17382
|
}
|
|
17347
17383
|
const headers = { ETag: cache6.etag, "Cache-Control": "no-cache" };
|
|
@@ -17424,7 +17460,8 @@ var routes2 = {
|
|
|
17424
17460
|
"GET /api/config": getConfig,
|
|
17425
17461
|
"POST /api/config/set": setConfig,
|
|
17426
17462
|
"POST /api/config/unset": unsetConfig,
|
|
17427
|
-
"GET /api/review/synthesis": getReviewSynthesis
|
|
17463
|
+
"GET /api/review/synthesis": getReviewSynthesis,
|
|
17464
|
+
"GET /api/updates": updates
|
|
17428
17465
|
};
|
|
17429
17466
|
var handleRequest = createFallbackHandler(
|
|
17430
17467
|
routes2,
|
|
@@ -17693,11 +17730,183 @@ function scheduleReconnect() {
|
|
|
17693
17730
|
setTimeout(() => void connect2(), RECONNECT_MS).unref();
|
|
17694
17731
|
}
|
|
17695
17732
|
|
|
17696
|
-
// src/commands/sessions/
|
|
17733
|
+
// src/commands/sessions/daemon/originForCwd.ts
|
|
17734
|
+
var cache4 = /* @__PURE__ */ new Map();
|
|
17735
|
+
function originResolutionForCwd(cwd) {
|
|
17736
|
+
if (!cwd) return void 0;
|
|
17737
|
+
const cached = cache4.get(cwd);
|
|
17738
|
+
if (cached !== void 0) return { origin: cached, stable: true };
|
|
17739
|
+
const resolved = resolveCurrentOrigin(cwd);
|
|
17740
|
+
if (resolved.stable) cache4.set(cwd, resolved.origin);
|
|
17741
|
+
return resolved;
|
|
17742
|
+
}
|
|
17743
|
+
function originForCwd(cwd) {
|
|
17744
|
+
return originResolutionForCwd(cwd)?.origin;
|
|
17745
|
+
}
|
|
17746
|
+
|
|
17747
|
+
// src/commands/sessions/daemon/repoDirExists.ts
|
|
17748
|
+
import { existsSync as existsSync40 } from "fs";
|
|
17749
|
+
function repoDirExists(cwd) {
|
|
17750
|
+
return existsSync40(cwd);
|
|
17751
|
+
}
|
|
17752
|
+
|
|
17753
|
+
// src/commands/sessions/daemon/worktree/git.ts
|
|
17754
|
+
import { execFile as execFile10, execFileSync as execFileSync5 } from "child_process";
|
|
17755
|
+
function isWindowsPath(cwd) {
|
|
17756
|
+
return /^[A-Za-z]:[\\/]/.test(cwd);
|
|
17757
|
+
}
|
|
17758
|
+
function gitInvocation(cwd, args) {
|
|
17759
|
+
const windows = isWindowsPath(cwd);
|
|
17760
|
+
return {
|
|
17761
|
+
file: windows ? "git.exe" : "git",
|
|
17762
|
+
argv: windows ? ["-C", cwd, ...args] : args,
|
|
17763
|
+
options: {
|
|
17764
|
+
encoding: "utf8",
|
|
17765
|
+
windowsHide: true,
|
|
17766
|
+
...windows ? {} : { cwd }
|
|
17767
|
+
}
|
|
17768
|
+
};
|
|
17769
|
+
}
|
|
17770
|
+
function git(cwd, args) {
|
|
17771
|
+
const { file, argv, options: options2 } = gitInvocation(cwd, args);
|
|
17772
|
+
return new Promise((resolve28, reject) => {
|
|
17773
|
+
execFile10(file, argv, options2, (error, stdout) => {
|
|
17774
|
+
if (error) reject(error);
|
|
17775
|
+
else resolve28(stdout.toString());
|
|
17776
|
+
});
|
|
17777
|
+
});
|
|
17778
|
+
}
|
|
17779
|
+
async function gitOrNull(cwd, args) {
|
|
17780
|
+
try {
|
|
17781
|
+
return (await git(cwd, args)).trim() || null;
|
|
17782
|
+
} catch {
|
|
17783
|
+
return null;
|
|
17784
|
+
}
|
|
17785
|
+
}
|
|
17786
|
+
async function gitResult(cwd, args) {
|
|
17787
|
+
try {
|
|
17788
|
+
return { ok: true, out: (await git(cwd, args)).trim() };
|
|
17789
|
+
} catch (error) {
|
|
17790
|
+
return {
|
|
17791
|
+
ok: false,
|
|
17792
|
+
error: error instanceof Error ? error.message : String(error)
|
|
17793
|
+
};
|
|
17794
|
+
}
|
|
17795
|
+
}
|
|
17796
|
+
function gitSyncResult(cwd, args) {
|
|
17797
|
+
try {
|
|
17798
|
+
return { ok: true, out: gitSync(cwd, args).trim() };
|
|
17799
|
+
} catch (error) {
|
|
17800
|
+
return {
|
|
17801
|
+
ok: false,
|
|
17802
|
+
error: error instanceof Error ? error.message : String(error)
|
|
17803
|
+
};
|
|
17804
|
+
}
|
|
17805
|
+
}
|
|
17806
|
+
function gitSync(cwd, args) {
|
|
17807
|
+
const { file, argv, options: options2 } = gitInvocation(cwd, args);
|
|
17808
|
+
return execFileSync5(file, argv, {
|
|
17809
|
+
...options2,
|
|
17810
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
17811
|
+
}).toString();
|
|
17812
|
+
}
|
|
17813
|
+
function gitSyncOrNull(cwd, args) {
|
|
17814
|
+
try {
|
|
17815
|
+
return gitSync(cwd, args).trim() || null;
|
|
17816
|
+
} catch {
|
|
17817
|
+
return null;
|
|
17818
|
+
}
|
|
17819
|
+
}
|
|
17820
|
+
|
|
17821
|
+
// src/commands/sessions/daemon/worktree/listWorktreePaths.ts
|
|
17822
|
+
function listWorktreePaths(cwd) {
|
|
17823
|
+
const out = gitSyncOrNull(cwd, ["worktree", "list", "--porcelain"]);
|
|
17824
|
+
if (!out) return [];
|
|
17825
|
+
return out.split("\n").filter((line) => line.startsWith("worktree ")).map((line) => line.slice("worktree ".length).trim());
|
|
17826
|
+
}
|
|
17827
|
+
function mainWorktree(cwd) {
|
|
17828
|
+
return listWorktreePaths(cwd)[0] ?? null;
|
|
17829
|
+
}
|
|
17830
|
+
function listLocalBranches(cwd) {
|
|
17831
|
+
const out = gitSyncOrNull(cwd, [
|
|
17832
|
+
"for-each-ref",
|
|
17833
|
+
"--format=%(refname:short)",
|
|
17834
|
+
"refs/heads"
|
|
17835
|
+
]);
|
|
17836
|
+
return out ? out.split("\n").map((line) => line.trim()) : [];
|
|
17837
|
+
}
|
|
17838
|
+
function gitCommonDir(cwd) {
|
|
17839
|
+
return gitSyncOrNull(cwd, [
|
|
17840
|
+
"rev-parse",
|
|
17841
|
+
"--path-format=absolute",
|
|
17842
|
+
"--git-common-dir"
|
|
17843
|
+
]);
|
|
17844
|
+
}
|
|
17845
|
+
|
|
17846
|
+
// src/commands/sessions/daemon/worktree/readWorktreeRegistry.ts
|
|
17847
|
+
var REGISTRY_FILE = "worktrees.json";
|
|
17848
|
+
function readWorktreeRegistry() {
|
|
17849
|
+
const data = loadJson(REGISTRY_FILE);
|
|
17850
|
+
return Object.entries(data).filter(([, record]) => !record.reaped).map(([path106, record]) => ({ path: path106, ...record }));
|
|
17851
|
+
}
|
|
17852
|
+
function worktreeAttributionIncludingReaped(path106) {
|
|
17853
|
+
const record = loadJson(REGISTRY_FILE)[path106];
|
|
17854
|
+
return record ? { clone: record.clone, origin: record.origin } : void 0;
|
|
17855
|
+
}
|
|
17856
|
+
function recordWorktree(path106, clone, origin) {
|
|
17857
|
+
const data = loadJson(REGISTRY_FILE);
|
|
17858
|
+
data[path106] = { clone, origin };
|
|
17859
|
+
saveJson(REGISTRY_FILE, data);
|
|
17860
|
+
}
|
|
17861
|
+
function forgetWorktree(path106) {
|
|
17862
|
+
const data = loadJson(REGISTRY_FILE);
|
|
17863
|
+
const record = data[path106];
|
|
17864
|
+
if (!record || record.reaped) return;
|
|
17865
|
+
data[path106] = { ...record, reaped: true };
|
|
17866
|
+
saveJson(REGISTRY_FILE, data);
|
|
17867
|
+
}
|
|
17868
|
+
|
|
17869
|
+
// src/commands/sessions/daemon/repoGroupForCwd.ts
|
|
17870
|
+
var cache5 = /* @__PURE__ */ new Map();
|
|
17871
|
+
function repoGroupForCwd(cwd) {
|
|
17872
|
+
if (!cwd) return void 0;
|
|
17873
|
+
if (cache5.has(cwd)) return cache5.get(cwd);
|
|
17874
|
+
const { group, stable } = resolveRepoGroup(cwd);
|
|
17875
|
+
if (stable) cache5.set(cwd, group);
|
|
17876
|
+
return group;
|
|
17877
|
+
}
|
|
17878
|
+
function resolveRepoGroup(cwd) {
|
|
17879
|
+
const clone = mainWorktree(cwd);
|
|
17880
|
+
const origin = clone ? originResolutionForCwd(clone) : void 0;
|
|
17881
|
+
if (clone && origin)
|
|
17882
|
+
return {
|
|
17883
|
+
group: hostedGroup(origin.origin, clone),
|
|
17884
|
+
stable: origin.stable
|
|
17885
|
+
};
|
|
17886
|
+
const reaped = worktreeAttributionIncludingReaped(cwd);
|
|
17887
|
+
if (!reaped) return { group: void 0, stable: repoDirExists(cwd) };
|
|
17888
|
+
const current = currentOriginOfClone(reaped.clone);
|
|
17889
|
+
return {
|
|
17890
|
+
group: hostedGroup(current?.origin ?? reaped.origin, reaped.clone),
|
|
17891
|
+
stable: current?.stable === true
|
|
17892
|
+
};
|
|
17893
|
+
}
|
|
17894
|
+
function currentOriginOfClone(clone) {
|
|
17895
|
+
const main = mainWorktree(clone);
|
|
17896
|
+
return main ? originResolutionForCwd(main) : void 0;
|
|
17897
|
+
}
|
|
17898
|
+
function hostedGroup(origin, clone) {
|
|
17899
|
+
return { origin, clone };
|
|
17900
|
+
}
|
|
17901
|
+
|
|
17902
|
+
// src/commands/sessions/repoEntryCwd.ts
|
|
17697
17903
|
function repoEntryCwd(serverCwd) {
|
|
17698
17904
|
return repoGroupForCwd(serverCwd)?.clone ?? serverCwd;
|
|
17699
17905
|
}
|
|
17906
|
+
|
|
17907
|
+
// src/commands/sessions/web.ts
|
|
17700
17908
|
async function web(options2) {
|
|
17909
|
+
webStartCommit.capture();
|
|
17701
17910
|
const port = Number.parseInt(options2.port, 10);
|
|
17702
17911
|
const server = startWebServer(
|
|
17703
17912
|
"Assist",
|
|
@@ -18103,7 +18312,7 @@ function registerBranch(program2) {
|
|
|
18103
18312
|
}
|
|
18104
18313
|
|
|
18105
18314
|
// src/commands/cliHook.ts
|
|
18106
|
-
import { basename as
|
|
18315
|
+
import { basename as basename13 } from "path";
|
|
18107
18316
|
|
|
18108
18317
|
// src/shared/splitCompound.ts
|
|
18109
18318
|
import { parse } from "shell-quote";
|
|
@@ -18679,7 +18888,7 @@ function findTruncatedReadDenyRaw(rawCommand) {
|
|
|
18679
18888
|
}
|
|
18680
18889
|
|
|
18681
18890
|
// src/shared/isApprovedRead.ts
|
|
18682
|
-
import { resolve as
|
|
18891
|
+
import { resolve as resolve16, sep as sep2 } from "path";
|
|
18683
18892
|
|
|
18684
18893
|
// src/shared/appliesFixStructure.ts
|
|
18685
18894
|
var APPLY_RE = /^assist\s+github\s+issue\s+fix-structure\b.*\s--apply\b/;
|
|
@@ -18733,7 +18942,7 @@ function extractGraphqlQuery(args) {
|
|
|
18733
18942
|
|
|
18734
18943
|
// src/shared/loadCliReads.ts
|
|
18735
18944
|
import { existsSync as existsSync41, readFileSync as readFileSync26, writeFileSync as writeFileSync22 } from "fs";
|
|
18736
|
-
import { dirname as dirname25, resolve as
|
|
18945
|
+
import { dirname as dirname25, resolve as resolve15 } from "path";
|
|
18737
18946
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
18738
18947
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
18739
18948
|
var __dirname4 = dirname25(__filename3);
|
|
@@ -18748,13 +18957,13 @@ var cachedReads;
|
|
|
18748
18957
|
var cachedWrites;
|
|
18749
18958
|
function getCliReadsLines() {
|
|
18750
18959
|
if (!cachedReads) {
|
|
18751
|
-
cachedReads = readLines(
|
|
18960
|
+
cachedReads = readLines(resolve15(packageRoot(), "allowed.cli-reads"));
|
|
18752
18961
|
}
|
|
18753
18962
|
return cachedReads;
|
|
18754
18963
|
}
|
|
18755
18964
|
function getCliWritesLines() {
|
|
18756
18965
|
if (!cachedWrites) {
|
|
18757
|
-
cachedWrites = readLines(
|
|
18966
|
+
cachedWrites = readLines(resolve15(packageRoot(), "allowed.cli-writes"));
|
|
18758
18967
|
}
|
|
18759
18968
|
return cachedWrites;
|
|
18760
18969
|
}
|
|
@@ -18763,7 +18972,7 @@ function loadCliReads() {
|
|
|
18763
18972
|
}
|
|
18764
18973
|
function saveCliReads(commands) {
|
|
18765
18974
|
writeFileSync22(
|
|
18766
|
-
|
|
18975
|
+
resolve15(packageRoot(), "allowed.cli-reads"),
|
|
18767
18976
|
`${commands.join("\n")}
|
|
18768
18977
|
`
|
|
18769
18978
|
);
|
|
@@ -18789,13 +18998,13 @@ function findCliWrite(command) {
|
|
|
18789
18998
|
|
|
18790
18999
|
// src/shared/readSettingsPerms.ts
|
|
18791
19000
|
import { existsSync as existsSync42, readFileSync as readFileSync27 } from "fs";
|
|
18792
|
-
import { homedir as
|
|
18793
|
-
import { join as
|
|
19001
|
+
import { homedir as homedir17 } from "os";
|
|
19002
|
+
import { join as join45 } from "path";
|
|
18794
19003
|
function readSettingsPerms(key) {
|
|
18795
19004
|
const paths = [
|
|
18796
|
-
|
|
18797
|
-
|
|
18798
|
-
|
|
19005
|
+
join45(homedir17(), ".claude", "settings.json"),
|
|
19006
|
+
join45(process.cwd(), ".claude", "settings.json"),
|
|
19007
|
+
join45(process.cwd(), ".claude", "settings.local.json")
|
|
18799
19008
|
];
|
|
18800
19009
|
const entries = [];
|
|
18801
19010
|
for (const p of paths) {
|
|
@@ -18901,19 +19110,19 @@ function isCdToCwd(command) {
|
|
|
18901
19110
|
const parts = command.split(/\s+/);
|
|
18902
19111
|
if (parts[0] !== "cd" || parts.length > 2) return false;
|
|
18903
19112
|
if (parts.length === 1) return false;
|
|
18904
|
-
const resolved =
|
|
18905
|
-
return resolved ===
|
|
19113
|
+
const resolved = resolve16(normalizeMsysPath(parts[1]));
|
|
19114
|
+
return resolved === resolve16(process.cwd());
|
|
18906
19115
|
}
|
|
18907
19116
|
function isCdToReadAllowedDir(command) {
|
|
18908
19117
|
const parts = command.split(/\s+/);
|
|
18909
19118
|
if (parts[0] !== "cd" || parts.length !== 2) return void 0;
|
|
18910
|
-
const target =
|
|
19119
|
+
const target = resolve16(normalizeMsysPath(parts[1]));
|
|
18911
19120
|
for (const entry of readSettingsPerms("allow")) {
|
|
18912
19121
|
const m = entry.match(READ_RE);
|
|
18913
19122
|
if (!m) continue;
|
|
18914
19123
|
const base = globBaseDir(m[1]);
|
|
18915
19124
|
if (!base) continue;
|
|
18916
|
-
const resolved =
|
|
19125
|
+
const resolved = resolve16(normalizeMsysPath(base));
|
|
18917
19126
|
if (target === resolved || target.startsWith(resolved + sep2)) {
|
|
18918
19127
|
return `cd to Read-allowed directory: ${entry}`;
|
|
18919
19128
|
}
|
|
@@ -19018,12 +19227,12 @@ function decideCommand(toolName, rawCommand) {
|
|
|
19018
19227
|
|
|
19019
19228
|
// src/commands/cliHook/logDeniedToolCall.ts
|
|
19020
19229
|
import { mkdirSync as mkdirSync12 } from "fs";
|
|
19021
|
-
import { homedir as
|
|
19022
|
-
import { join as
|
|
19230
|
+
import { homedir as homedir18 } from "os";
|
|
19231
|
+
import { join as join46 } from "path";
|
|
19023
19232
|
import Database from "better-sqlite3";
|
|
19024
19233
|
var _db;
|
|
19025
19234
|
function getDbDir() {
|
|
19026
|
-
return
|
|
19235
|
+
return join46(homedir18(), ".assist");
|
|
19027
19236
|
}
|
|
19028
19237
|
function initSchema(db) {
|
|
19029
19238
|
db.exec(`
|
|
@@ -19042,7 +19251,7 @@ function openPromptsDb(dir) {
|
|
|
19042
19251
|
if (_db) return _db;
|
|
19043
19252
|
const dbDir = dir ?? getDbDir();
|
|
19044
19253
|
mkdirSync12(dbDir, { recursive: true });
|
|
19045
|
-
const db = new Database(
|
|
19254
|
+
const db = new Database(join46(dbDir, "assist.db"));
|
|
19046
19255
|
db.pragma("journal_mode = WAL");
|
|
19047
19256
|
initSchema(db);
|
|
19048
19257
|
_db = db;
|
|
@@ -19113,7 +19322,7 @@ async function cliHook() {
|
|
|
19113
19322
|
logDeniedToolCall({
|
|
19114
19323
|
tool: input.toolName,
|
|
19115
19324
|
command: input.command,
|
|
19116
|
-
repo:
|
|
19325
|
+
repo: basename13(process.cwd()),
|
|
19117
19326
|
sessionId: process.env.CLAUDE_SESSION_ID,
|
|
19118
19327
|
denyReason: decision.permissionDecisionReason
|
|
19119
19328
|
});
|
|
@@ -19162,8 +19371,8 @@ ${reasons.join("\n")}`);
|
|
|
19162
19371
|
|
|
19163
19372
|
// src/commands/permitCliReads.ts
|
|
19164
19373
|
import { existsSync as existsSync43, mkdirSync as mkdirSync13, readFileSync as readFileSync28, writeFileSync as writeFileSync23 } from "fs";
|
|
19165
|
-
import { homedir as
|
|
19166
|
-
import { join as
|
|
19374
|
+
import { homedir as homedir19 } from "os";
|
|
19375
|
+
import { join as join47 } from "path";
|
|
19167
19376
|
|
|
19168
19377
|
// src/commands/permitCliReads/assertCliExists.ts
|
|
19169
19378
|
function assertCliExists(cli) {
|
|
@@ -19426,7 +19635,7 @@ function updateSettings(cli, commands) {
|
|
|
19426
19635
|
// src/commands/permitCliReads.ts
|
|
19427
19636
|
function logPath(cli) {
|
|
19428
19637
|
const safeName = cli.replace(/\s+/g, "-");
|
|
19429
|
-
return
|
|
19638
|
+
return join47(homedir19(), ".assist", `cli-discover-${safeName}.log`);
|
|
19430
19639
|
}
|
|
19431
19640
|
function readCache(cli) {
|
|
19432
19641
|
const path106 = logPath(cli);
|
|
@@ -19434,7 +19643,7 @@ function readCache(cli) {
|
|
|
19434
19643
|
return readFileSync28(path106, "utf8");
|
|
19435
19644
|
}
|
|
19436
19645
|
function writeCache(cli, output) {
|
|
19437
|
-
const dir =
|
|
19646
|
+
const dir = join47(homedir19(), ".assist");
|
|
19438
19647
|
mkdirSync13(dir, { recursive: true });
|
|
19439
19648
|
writeFileSync23(logPath(cli), output);
|
|
19440
19649
|
}
|
|
@@ -19598,18 +19807,18 @@ function isHashCommentFile(filePath) {
|
|
|
19598
19807
|
}
|
|
19599
19808
|
|
|
19600
19809
|
// src/commands/codeComment/getRestrictedDir.ts
|
|
19601
|
-
import { homedir as
|
|
19602
|
-
import { join as
|
|
19810
|
+
import { homedir as homedir20 } from "os";
|
|
19811
|
+
import { join as join48 } from "path";
|
|
19603
19812
|
function getRestrictedDir() {
|
|
19604
|
-
return
|
|
19813
|
+
return join48(homedir20(), ".assist", "restricted");
|
|
19605
19814
|
}
|
|
19606
19815
|
function getPinStatePath(pin2) {
|
|
19607
|
-
return
|
|
19816
|
+
return join48(getRestrictedDir(), `code-comment-${pin2}.json`);
|
|
19608
19817
|
}
|
|
19609
19818
|
|
|
19610
19819
|
// src/commands/codeComment/sweepRestrictedDir.ts
|
|
19611
19820
|
import { readdirSync as readdirSync6, statSync as statSync8, unlinkSync as unlinkSync7 } from "fs";
|
|
19612
|
-
import { join as
|
|
19821
|
+
import { join as join49 } from "path";
|
|
19613
19822
|
var STALE_AFTER_MS = 30 * 60 * 1e3;
|
|
19614
19823
|
function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
19615
19824
|
let entries;
|
|
@@ -19620,7 +19829,7 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
19620
19829
|
}
|
|
19621
19830
|
const cutoff = Date.now() - STALE_AFTER_MS;
|
|
19622
19831
|
for (const entry of entries) {
|
|
19623
|
-
const path106 =
|
|
19832
|
+
const path106 = join49(dir, entry);
|
|
19624
19833
|
try {
|
|
19625
19834
|
if (statSync8(path106).mtimeMs < cutoff) unlinkSync7(path106);
|
|
19626
19835
|
} catch {
|
|
@@ -21274,18 +21483,18 @@ import chalk137 from "chalk";
|
|
|
21274
21483
|
|
|
21275
21484
|
// src/commands/criteriaExtension/criteriaExtensionDir.ts
|
|
21276
21485
|
import { existsSync as existsSync46 } from "fs";
|
|
21277
|
-
import { dirname as dirname26, join as
|
|
21486
|
+
import { dirname as dirname26, join as join50 } from "path";
|
|
21278
21487
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
21279
21488
|
var moduleDir = dirname26(fileURLToPath6(import.meta.url));
|
|
21280
21489
|
function criteriaExtensionDir() {
|
|
21281
|
-
const bundled =
|
|
21490
|
+
const bundled = join50(
|
|
21282
21491
|
moduleDir,
|
|
21283
21492
|
"commands",
|
|
21284
21493
|
"criteriaExtension",
|
|
21285
21494
|
"criteria-extension"
|
|
21286
21495
|
);
|
|
21287
21496
|
if (existsSync46(bundled)) return bundled;
|
|
21288
|
-
return
|
|
21497
|
+
return join50(moduleDir, "..", "..", "..", "criteria-extension");
|
|
21289
21498
|
}
|
|
21290
21499
|
|
|
21291
21500
|
// src/commands/criteriaExtension/criteriaExtension.ts
|
|
@@ -21313,24 +21522,24 @@ async function criteriaExtension() {
|
|
|
21313
21522
|
|
|
21314
21523
|
// src/commands/criteriaExtension/printCriteriaExtensionUrl.ts
|
|
21315
21524
|
import { readFile as readFile4 } from "fs/promises";
|
|
21316
|
-
import { join as
|
|
21525
|
+
import { join as join51 } from "path";
|
|
21317
21526
|
import chalk138 from "chalk";
|
|
21318
21527
|
|
|
21319
21528
|
// src/commands/criteriaExtension/latestUpdate.ts
|
|
21320
|
-
function latestUpdate(manifest,
|
|
21529
|
+
function latestUpdate(manifest, updates2) {
|
|
21321
21530
|
const { id } = JSON.parse(manifest).browser_specific_settings.gecko;
|
|
21322
|
-
return JSON.parse(
|
|
21531
|
+
return JSON.parse(updates2).addons[id]?.updates.at(-1);
|
|
21323
21532
|
}
|
|
21324
21533
|
|
|
21325
21534
|
// src/commands/criteriaExtension/latestUpdateLink.ts
|
|
21326
|
-
function latestUpdateLink(manifest,
|
|
21327
|
-
return latestUpdate(manifest,
|
|
21535
|
+
function latestUpdateLink(manifest, updates2) {
|
|
21536
|
+
return latestUpdate(manifest, updates2)?.update_link;
|
|
21328
21537
|
}
|
|
21329
21538
|
|
|
21330
21539
|
// src/commands/criteriaExtension/printCriteriaExtensionUrl.ts
|
|
21331
21540
|
async function printCriteriaExtensionUrl() {
|
|
21332
21541
|
const manifest = await readFile4(
|
|
21333
|
-
|
|
21542
|
+
join51(criteriaExtensionDir(), "manifest.json"),
|
|
21334
21543
|
"utf8"
|
|
21335
21544
|
);
|
|
21336
21545
|
const { update_url } = JSON.parse(manifest).browser_specific_settings.gecko;
|
|
@@ -21346,16 +21555,16 @@ async function printCriteriaExtensionUrl() {
|
|
|
21346
21555
|
|
|
21347
21556
|
// src/commands/criteriaExtension/signCriteriaExtension.ts
|
|
21348
21557
|
import { rm as rm2 } from "fs/promises";
|
|
21349
|
-
import { homedir as
|
|
21350
|
-
import { join as
|
|
21558
|
+
import { homedir as homedir21, tmpdir as tmpdir3 } from "os";
|
|
21559
|
+
import { join as join57 } from "path";
|
|
21351
21560
|
import chalk140 from "chalk";
|
|
21352
21561
|
|
|
21353
21562
|
// src/commands/criteriaExtension/copySignedXpi.ts
|
|
21354
21563
|
import { copyFile } from "fs/promises";
|
|
21355
|
-
import { join as
|
|
21564
|
+
import { join as join52 } from "path";
|
|
21356
21565
|
var SIGNED_XPI_NAME = "criteria-extension.xpi";
|
|
21357
21566
|
async function copySignedXpi(xpi, dir) {
|
|
21358
|
-
const fixed2 =
|
|
21567
|
+
const fixed2 = join52(dir, SIGNED_XPI_NAME);
|
|
21359
21568
|
if (fixed2 === xpi) return fixed2;
|
|
21360
21569
|
await copyFile(xpi, fixed2);
|
|
21361
21570
|
return fixed2;
|
|
@@ -21364,11 +21573,11 @@ async function copySignedXpi(xpi, dir) {
|
|
|
21364
21573
|
// src/commands/criteriaExtension/findSignedXpi.ts
|
|
21365
21574
|
import { existsSync as existsSync47 } from "fs";
|
|
21366
21575
|
import { readdir } from "fs/promises";
|
|
21367
|
-
import { join as
|
|
21576
|
+
import { join as join53 } from "path";
|
|
21368
21577
|
async function findSignedXpi(dir) {
|
|
21369
21578
|
if (!existsSync47(dir)) return null;
|
|
21370
21579
|
const name = (await readdir(dir)).find((entry) => entry.endsWith(".xpi"));
|
|
21371
|
-
return name ?
|
|
21580
|
+
return name ? join53(dir, name) : null;
|
|
21372
21581
|
}
|
|
21373
21582
|
|
|
21374
21583
|
// src/commands/criteriaExtension/signedAddonInstallPath.ts
|
|
@@ -21391,10 +21600,10 @@ async function signedAddonInstallPath(xpi) {
|
|
|
21391
21600
|
|
|
21392
21601
|
// src/commands/criteriaExtension/signPreflightProblem.ts
|
|
21393
21602
|
import { existsSync as existsSync48 } from "fs";
|
|
21394
|
-
import { join as
|
|
21603
|
+
import { join as join54 } from "path";
|
|
21395
21604
|
var KEY_URL = "https://addons.mozilla.org/en-US/developers/addon/api/key/";
|
|
21396
21605
|
function signPreflightProblem(source) {
|
|
21397
|
-
if (!existsSync48(
|
|
21606
|
+
if (!existsSync48(join54(source, "content.js")))
|
|
21398
21607
|
return {
|
|
21399
21608
|
message: `no content.js in ${source}`,
|
|
21400
21609
|
hint: "run npm run build to bundle the content script"
|
|
@@ -21409,7 +21618,7 @@ function signPreflightProblem(source) {
|
|
|
21409
21618
|
|
|
21410
21619
|
// src/commands/criteriaExtension/stageCriteriaExtension.ts
|
|
21411
21620
|
import { cp as cp3, mkdir as mkdir5, readFile as readFile5, rm, writeFile as writeFile4 } from "fs/promises";
|
|
21412
|
-
import { basename as
|
|
21621
|
+
import { basename as basename14, join as join55 } from "path";
|
|
21413
21622
|
|
|
21414
21623
|
// src/commands/criteriaExtension/stampManifestVersion.ts
|
|
21415
21624
|
function stampManifestVersion(manifest, version2) {
|
|
@@ -21424,9 +21633,9 @@ async function stageCriteriaExtension(source, staging, version2) {
|
|
|
21424
21633
|
await mkdir5(staging, { recursive: true });
|
|
21425
21634
|
await cp3(source, staging, {
|
|
21426
21635
|
recursive: true,
|
|
21427
|
-
filter: (path106) =>
|
|
21636
|
+
filter: (path106) => basename14(path106) !== "updates.json"
|
|
21428
21637
|
});
|
|
21429
|
-
const manifest =
|
|
21638
|
+
const manifest = join55(staging, "manifest.json");
|
|
21430
21639
|
const stamped = stampManifestVersion(
|
|
21431
21640
|
await readFile5(manifest, "utf8"),
|
|
21432
21641
|
version2
|
|
@@ -21436,13 +21645,13 @@ async function stageCriteriaExtension(source, staging, version2) {
|
|
|
21436
21645
|
|
|
21437
21646
|
// src/commands/criteriaExtension/writeUpdateManifest.ts
|
|
21438
21647
|
import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
21439
|
-
import { join as
|
|
21648
|
+
import { join as join56 } from "path";
|
|
21440
21649
|
|
|
21441
21650
|
// src/commands/criteriaExtension/buildUpdateManifest.ts
|
|
21442
21651
|
var RELEASE_DOWNLOAD_URL = "https://github.com/staff0rd/assist/releases/download";
|
|
21443
21652
|
function buildUpdateManifest(manifest, version2) {
|
|
21444
21653
|
const { id } = JSON.parse(manifest).browser_specific_settings.gecko;
|
|
21445
|
-
const
|
|
21654
|
+
const updates2 = {
|
|
21446
21655
|
addons: {
|
|
21447
21656
|
[id]: {
|
|
21448
21657
|
updates: [
|
|
@@ -21454,24 +21663,24 @@ function buildUpdateManifest(manifest, version2) {
|
|
|
21454
21663
|
}
|
|
21455
21664
|
}
|
|
21456
21665
|
};
|
|
21457
|
-
return `${JSON.stringify(
|
|
21666
|
+
return `${JSON.stringify(updates2, null, " ")}
|
|
21458
21667
|
`;
|
|
21459
21668
|
}
|
|
21460
21669
|
|
|
21461
21670
|
// src/commands/criteriaExtension/writeUpdateManifest.ts
|
|
21462
21671
|
async function writeUpdateManifest(source, dir, version2) {
|
|
21463
21672
|
await writeFile5(
|
|
21464
|
-
|
|
21673
|
+
join56(dir, "updates.json"),
|
|
21465
21674
|
buildUpdateManifest(
|
|
21466
|
-
await readFile6(
|
|
21675
|
+
await readFile6(join56(source, "manifest.json"), "utf8"),
|
|
21467
21676
|
version2
|
|
21468
21677
|
)
|
|
21469
21678
|
);
|
|
21470
21679
|
}
|
|
21471
21680
|
|
|
21472
21681
|
// src/commands/criteriaExtension/signCriteriaExtension.ts
|
|
21473
|
-
var ARTIFACTS_DIR =
|
|
21474
|
-
var STAGING_DIR =
|
|
21682
|
+
var ARTIFACTS_DIR = join57(homedir21(), ".assist", "criteria-extension");
|
|
21683
|
+
var STAGING_DIR = join57(tmpdir3(), "assist-criteria-extension");
|
|
21475
21684
|
async function signCriteriaExtension() {
|
|
21476
21685
|
const source = criteriaExtensionDir();
|
|
21477
21686
|
const problem = signPreflightProblem(source);
|
|
@@ -21659,12 +21868,12 @@ import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync26 } from "fs"
|
|
|
21659
21868
|
import chalk143 from "chalk";
|
|
21660
21869
|
|
|
21661
21870
|
// src/commands/dbMigration/getMigrationPinPath.ts
|
|
21662
|
-
import { join as
|
|
21871
|
+
import { join as join58 } from "path";
|
|
21663
21872
|
function getMigrationPinPath(pin2) {
|
|
21664
|
-
return
|
|
21873
|
+
return join58(getRestrictedDir(), `db-migration-pin-${pin2}.json`);
|
|
21665
21874
|
}
|
|
21666
21875
|
function getMigrationApprovalPath(migrationId) {
|
|
21667
|
-
return
|
|
21876
|
+
return join58(getRestrictedDir(), `db-migration-approval-${migrationId}.json`);
|
|
21668
21877
|
}
|
|
21669
21878
|
|
|
21670
21879
|
// src/commands/dbMigration/readMigrationPinState.ts
|
|
@@ -21797,15 +22006,15 @@ function registerDeploy(program2) {
|
|
|
21797
22006
|
}
|
|
21798
22007
|
|
|
21799
22008
|
// src/commands/devlog/list.ts
|
|
21800
|
-
import { execFileSync as
|
|
21801
|
-
import { basename as
|
|
22009
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
22010
|
+
import { basename as basename16 } from "path";
|
|
21802
22011
|
|
|
21803
22012
|
// src/commands/devlog/loadBlogSkipDays.ts
|
|
21804
|
-
import { homedir as
|
|
21805
|
-
import { join as
|
|
21806
|
-
var BLOG_REPO_ROOT =
|
|
22013
|
+
import { homedir as homedir22 } from "os";
|
|
22014
|
+
import { join as join59 } from "path";
|
|
22015
|
+
var BLOG_REPO_ROOT = join59(homedir22(), "git/blog");
|
|
21807
22016
|
function loadBlogSkipDays(repoName) {
|
|
21808
|
-
const config = loadRawYaml(
|
|
22017
|
+
const config = loadRawYaml(join59(BLOG_REPO_ROOT, "assist.yml"));
|
|
21809
22018
|
const devlog = config.devlog;
|
|
21810
22019
|
const skip2 = devlog?.skip;
|
|
21811
22020
|
return new Set(skip2?.[repoName]);
|
|
@@ -21817,13 +22026,13 @@ import chalk146 from "chalk";
|
|
|
21817
22026
|
|
|
21818
22027
|
// src/shared/getRepoName.ts
|
|
21819
22028
|
import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
|
|
21820
|
-
import { basename as
|
|
22029
|
+
import { basename as basename15, join as join60 } from "path";
|
|
21821
22030
|
function getRepoName() {
|
|
21822
22031
|
const config = loadConfig();
|
|
21823
22032
|
if (config.devlog?.name) {
|
|
21824
22033
|
return config.devlog.name;
|
|
21825
22034
|
}
|
|
21826
|
-
const packageJsonPath =
|
|
22035
|
+
const packageJsonPath = join60(process.cwd(), "package.json");
|
|
21827
22036
|
if (existsSync51(packageJsonPath)) {
|
|
21828
22037
|
try {
|
|
21829
22038
|
const content = readFileSync33(packageJsonPath, "utf8");
|
|
@@ -21834,13 +22043,13 @@ function getRepoName() {
|
|
|
21834
22043
|
} catch {
|
|
21835
22044
|
}
|
|
21836
22045
|
}
|
|
21837
|
-
return
|
|
22046
|
+
return basename15(process.cwd());
|
|
21838
22047
|
}
|
|
21839
22048
|
|
|
21840
22049
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
21841
22050
|
import { readdirSync as readdirSync7, readFileSync as readFileSync34 } from "fs";
|
|
21842
|
-
import { join as
|
|
21843
|
-
var DEVLOG_DIR =
|
|
22051
|
+
import { join as join61 } from "path";
|
|
22052
|
+
var DEVLOG_DIR = join61(BLOG_REPO_ROOT, "src/content/devlog");
|
|
21844
22053
|
function extractFrontmatter(content) {
|
|
21845
22054
|
const fm = content.match(/^---\n([\s\S]*?)\n---/);
|
|
21846
22055
|
return fm?.[1] ?? null;
|
|
@@ -21868,7 +22077,7 @@ function readDevlogFiles(callback) {
|
|
|
21868
22077
|
try {
|
|
21869
22078
|
const files = readdirSync7(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
|
|
21870
22079
|
for (const file of files) {
|
|
21871
|
-
const content = readFileSync34(
|
|
22080
|
+
const content = readFileSync34(join61(DEVLOG_DIR, file), "utf8");
|
|
21872
22081
|
const parsed = parseFrontmatter(content, file);
|
|
21873
22082
|
if (parsed) callback(parsed);
|
|
21874
22083
|
}
|
|
@@ -21970,14 +22179,14 @@ function list2(options2) {
|
|
|
21970
22179
|
const config = loadConfig();
|
|
21971
22180
|
const days = options2.days ?? 30;
|
|
21972
22181
|
const ignore3 = options2.ignore ?? config.devlog?.ignore ?? [];
|
|
21973
|
-
const repoName =
|
|
22182
|
+
const repoName = basename16(process.cwd());
|
|
21974
22183
|
const skipDays = loadBlogSkipDays(repoName);
|
|
21975
22184
|
const devlogEntries = loadDevlogEntries(repoName);
|
|
21976
22185
|
const args = ["log"];
|
|
21977
22186
|
if (options2.reverse) args.push("--reverse");
|
|
21978
22187
|
else args.push("-n", "500");
|
|
21979
22188
|
args.push("--pretty=format:%ad|%h|%s", "--date=short");
|
|
21980
|
-
const output =
|
|
22189
|
+
const output = execFileSync6("git", args, { encoding: "utf8" });
|
|
21981
22190
|
const commitsByDate = parseGitLogCommits(output, ignore3);
|
|
21982
22191
|
let dateCount = 0;
|
|
21983
22192
|
let isFirst = true;
|
|
@@ -22000,7 +22209,7 @@ function list2(options2) {
|
|
|
22000
22209
|
}
|
|
22001
22210
|
|
|
22002
22211
|
// src/commands/devlog/getLastVersionInfo.ts
|
|
22003
|
-
import { execFileSync as
|
|
22212
|
+
import { execFileSync as execFileSync7, execSync as execSync32 } from "child_process";
|
|
22004
22213
|
import semver from "semver";
|
|
22005
22214
|
function getVersionAtCommit(hash) {
|
|
22006
22215
|
try {
|
|
@@ -22019,7 +22228,7 @@ function stripToMinor(version2) {
|
|
|
22019
22228
|
}
|
|
22020
22229
|
function getLastVersionInfoFromGit() {
|
|
22021
22230
|
try {
|
|
22022
|
-
const output =
|
|
22231
|
+
const output = execFileSync7(
|
|
22023
22232
|
"git",
|
|
22024
22233
|
["log", "-1", "--pretty=format:%ad|%h", "--date=short"],
|
|
22025
22234
|
{
|
|
@@ -22064,7 +22273,7 @@ function bumpVersion(version2, type) {
|
|
|
22064
22273
|
}
|
|
22065
22274
|
|
|
22066
22275
|
// src/commands/devlog/next/displayNextEntry.ts
|
|
22067
|
-
import { execFileSync as
|
|
22276
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
22068
22277
|
import chalk149 from "chalk";
|
|
22069
22278
|
|
|
22070
22279
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
@@ -22098,7 +22307,7 @@ function findTargetDate(commitsByDate, skipDays) {
|
|
|
22098
22307
|
return Array.from(commitsByDate.keys()).filter((d) => !skipDays.has(d)).sort()[0];
|
|
22099
22308
|
}
|
|
22100
22309
|
function fetchCommitsByDate(ignore3, lastDate) {
|
|
22101
|
-
const output =
|
|
22310
|
+
const output = execFileSync8(
|
|
22102
22311
|
"git",
|
|
22103
22312
|
["log", "--pretty=format:%ad|%h|%s", "--date=short", "-n", "500"],
|
|
22104
22313
|
{ encoding: "utf8" }
|
|
@@ -22256,11 +22465,11 @@ function repos(options2) {
|
|
|
22256
22465
|
|
|
22257
22466
|
// src/commands/devlog/skip.ts
|
|
22258
22467
|
import { writeFileSync as writeFileSync29 } from "fs";
|
|
22259
|
-
import { join as
|
|
22468
|
+
import { join as join62 } from "path";
|
|
22260
22469
|
import chalk151 from "chalk";
|
|
22261
22470
|
import { stringify as stringifyYaml3 } from "yaml";
|
|
22262
22471
|
function getBlogConfigPath() {
|
|
22263
|
-
return
|
|
22472
|
+
return join62(BLOG_REPO_ROOT, "assist.yml");
|
|
22264
22473
|
}
|
|
22265
22474
|
function skip(date) {
|
|
22266
22475
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
@@ -22322,7 +22531,7 @@ function registerDevlog(program2) {
|
|
|
22322
22531
|
|
|
22323
22532
|
// src/commands/dotnet/checkBuildLocks.ts
|
|
22324
22533
|
import { closeSync as closeSync4, openSync as openSync5, readdirSync as readdirSync8 } from "fs";
|
|
22325
|
-
import { join as
|
|
22534
|
+
import { join as join63 } from "path";
|
|
22326
22535
|
import chalk153 from "chalk";
|
|
22327
22536
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "packages"]);
|
|
22328
22537
|
function isLockedDll(debugDir) {
|
|
@@ -22334,7 +22543,7 @@ function isLockedDll(debugDir) {
|
|
|
22334
22543
|
}
|
|
22335
22544
|
for (const file of files) {
|
|
22336
22545
|
if (!file.toLowerCase().endsWith(".dll")) continue;
|
|
22337
|
-
const dllPath =
|
|
22546
|
+
const dllPath = join63(debugDir, file);
|
|
22338
22547
|
try {
|
|
22339
22548
|
const fd = openSync5(dllPath, "r+");
|
|
22340
22549
|
closeSync4(fd);
|
|
@@ -22352,13 +22561,13 @@ function findFirstLockedDll(dir) {
|
|
|
22352
22561
|
return null;
|
|
22353
22562
|
}
|
|
22354
22563
|
if (entries.includes("bin")) {
|
|
22355
|
-
const locked = isLockedDll(
|
|
22564
|
+
const locked = isLockedDll(join63(dir, "bin", "Debug"));
|
|
22356
22565
|
if (locked) return locked;
|
|
22357
22566
|
}
|
|
22358
22567
|
for (const entry of entries) {
|
|
22359
22568
|
if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
|
|
22360
22569
|
continue;
|
|
22361
|
-
const found = findFirstLockedDll(
|
|
22570
|
+
const found = findFirstLockedDll(join63(dir, entry));
|
|
22362
22571
|
if (found) return found;
|
|
22363
22572
|
}
|
|
22364
22573
|
return null;
|
|
@@ -22705,11 +22914,11 @@ import chalk159 from "chalk";
|
|
|
22705
22914
|
|
|
22706
22915
|
// src/commands/dotnet/findSolution.ts
|
|
22707
22916
|
import { readdirSync as readdirSync10 } from "fs";
|
|
22708
|
-
import { dirname as dirname27, join as
|
|
22917
|
+
import { dirname as dirname27, join as join64 } from "path";
|
|
22709
22918
|
import chalk158 from "chalk";
|
|
22710
22919
|
function findSlnInDir(dir) {
|
|
22711
22920
|
try {
|
|
22712
|
-
return readdirSync10(dir).filter((f) => f.endsWith(".sln")).map((f) =>
|
|
22921
|
+
return readdirSync10(dir).filter((f) => f.endsWith(".sln")).map((f) => join64(dir, f));
|
|
22713
22922
|
} catch {
|
|
22714
22923
|
return [];
|
|
22715
22924
|
}
|
|
@@ -23704,7 +23913,7 @@ function aggregateCommitters(authorLists) {
|
|
|
23704
23913
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
23705
23914
|
import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync30 } from "fs";
|
|
23706
23915
|
import { tmpdir as tmpdir5 } from "os";
|
|
23707
|
-
import { join as
|
|
23916
|
+
import { join as join65 } from "path";
|
|
23708
23917
|
function buildArgs2(queryFile, vars) {
|
|
23709
23918
|
const args = ["api", "graphql", "-F", `query=@${queryFile}`];
|
|
23710
23919
|
for (const [key, value] of Object.entries(vars)) {
|
|
@@ -23714,7 +23923,7 @@ function buildArgs2(queryFile, vars) {
|
|
|
23714
23923
|
return args;
|
|
23715
23924
|
}
|
|
23716
23925
|
function runGhGraphql(mutation, vars) {
|
|
23717
|
-
const queryFile =
|
|
23926
|
+
const queryFile = join65(tmpdir5(), `gh-query-${Date.now()}.graphql`);
|
|
23718
23927
|
writeFileSync30(queryFile, mutation);
|
|
23719
23928
|
try {
|
|
23720
23929
|
const result = spawnSync6("gh", buildArgs2(queryFile, vars), {
|
|
@@ -24427,7 +24636,7 @@ Anything nested below the leaf level fails the run before a single write, naming
|
|
|
24427
24636
|
}
|
|
24428
24637
|
|
|
24429
24638
|
// src/commands/github/issue/commentIssue.ts
|
|
24430
|
-
import { execFileSync as
|
|
24639
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
24431
24640
|
|
|
24432
24641
|
// src/shared/validateProposedContent.ts
|
|
24433
24642
|
function validateProposedContent(labels, title, body) {
|
|
@@ -24488,7 +24697,7 @@ async function commentIssue(numberArg, options2) {
|
|
|
24488
24697
|
const args = ["issue", "comment", String(number), "--body", body];
|
|
24489
24698
|
if (options2.repo) args.push("--repo", options2.repo);
|
|
24490
24699
|
try {
|
|
24491
|
-
|
|
24700
|
+
execFileSync9("gh", args, { stdio: "inherit" });
|
|
24492
24701
|
} catch {
|
|
24493
24702
|
process.exit(1);
|
|
24494
24703
|
}
|
|
@@ -24891,8 +25100,8 @@ function attachArgs(attachments) {
|
|
|
24891
25100
|
}
|
|
24892
25101
|
|
|
24893
25102
|
// src/commands/prs/runGhWithAttachments.ts
|
|
24894
|
-
import { execFileSync as
|
|
24895
|
-
import { basename as
|
|
25103
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
25104
|
+
import { basename as basename17 } from "path";
|
|
24896
25105
|
|
|
24897
25106
|
// src/shared/removeStagedAttachments.ts
|
|
24898
25107
|
import { rmSync as rmSync4 } from "fs";
|
|
@@ -24909,7 +25118,7 @@ function removeStagedAttachments(attachments) {
|
|
|
24909
25118
|
var PLACED_URL = /https:\/\/\S+\/(pull|issues)\/\d+/;
|
|
24910
25119
|
function reportPartialFailure(attachments, stderr) {
|
|
24911
25120
|
const failed3 = attachments.filter(
|
|
24912
|
-
({ path: path106 }) => stderr.includes(path106) || stderr.includes(
|
|
25121
|
+
({ path: path106 }) => stderr.includes(path106) || stderr.includes(basename17(path106))
|
|
24913
25122
|
);
|
|
24914
25123
|
const named = failed3.length > 0 ? failed3 : attachments;
|
|
24915
25124
|
console.error(
|
|
@@ -24919,7 +25128,7 @@ function reportPartialFailure(attachments, stderr) {
|
|
|
24919
25128
|
function runGhWithAttachments(args, attachments) {
|
|
24920
25129
|
const attaching = attachments.length > 0;
|
|
24921
25130
|
try {
|
|
24922
|
-
const stdout =
|
|
25131
|
+
const stdout = execFileSync10("gh", args, {
|
|
24923
25132
|
encoding: "utf8",
|
|
24924
25133
|
stdio: ["inherit", "pipe", attaching ? "pipe" : "inherit"]
|
|
24925
25134
|
});
|
|
@@ -25030,7 +25239,7 @@ function inWebSession() {
|
|
|
25030
25239
|
}
|
|
25031
25240
|
|
|
25032
25241
|
// src/commands/github/issue/fetchIssue.ts
|
|
25033
|
-
import { execFileSync as
|
|
25242
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
25034
25243
|
function fetchIssue2(number, repo) {
|
|
25035
25244
|
const args = [
|
|
25036
25245
|
"issue",
|
|
@@ -25042,7 +25251,7 @@ function fetchIssue2(number, repo) {
|
|
|
25042
25251
|
if (repo) args.push("--repo", repo);
|
|
25043
25252
|
let raw;
|
|
25044
25253
|
try {
|
|
25045
|
-
raw =
|
|
25254
|
+
raw = execFileSync11("gh", args, { encoding: "utf8" });
|
|
25046
25255
|
} catch {
|
|
25047
25256
|
console.error(`Could not fetch issue #${number} with gh issue view`);
|
|
25048
25257
|
process.exit(1);
|
|
@@ -25059,14 +25268,14 @@ function fetchIssue2(number, repo) {
|
|
|
25059
25268
|
import { existsSync as existsSync56, readFileSync as readFileSync38 } from "fs";
|
|
25060
25269
|
|
|
25061
25270
|
// src/commands/github/issue/issueWorkingFile.ts
|
|
25062
|
-
import { join as
|
|
25271
|
+
import { join as join66 } from "path";
|
|
25063
25272
|
function issueWorkingFile(slug2, number) {
|
|
25064
25273
|
const [owner = "unknown", repo = "unknown"] = slug2.split("/");
|
|
25065
|
-
const dir =
|
|
25274
|
+
const dir = join66(getStoreDir(), "github-issues", owner, repo);
|
|
25066
25275
|
return {
|
|
25067
25276
|
dir,
|
|
25068
|
-
bodyPath:
|
|
25069
|
-
metaPath:
|
|
25277
|
+
bodyPath: join66(dir, `${number}.md`),
|
|
25278
|
+
metaPath: join66(dir, `${number}.json`)
|
|
25070
25279
|
};
|
|
25071
25280
|
}
|
|
25072
25281
|
|
|
@@ -25133,12 +25342,12 @@ function prepareIssueEdit(number, repo, fresh) {
|
|
|
25133
25342
|
}
|
|
25134
25343
|
|
|
25135
25344
|
// src/commands/github/issue/pushIssueBody.ts
|
|
25136
|
-
import { execFileSync as
|
|
25345
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
25137
25346
|
function pushIssueBody(number, repo, bodyPath) {
|
|
25138
25347
|
const args = ["issue", "edit", String(number), "--body-file", bodyPath];
|
|
25139
25348
|
if (repo) args.push("--repo", repo);
|
|
25140
25349
|
try {
|
|
25141
|
-
|
|
25350
|
+
execFileSync12("gh", args, { stdio: "inherit" });
|
|
25142
25351
|
} catch {
|
|
25143
25352
|
process.exit(1);
|
|
25144
25353
|
}
|
|
@@ -25198,12 +25407,12 @@ function setIssueParent(number, repo, parentArg) {
|
|
|
25198
25407
|
}
|
|
25199
25408
|
|
|
25200
25409
|
// src/commands/github/issue/viewIssue.ts
|
|
25201
|
-
import { execFileSync as
|
|
25410
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
25202
25411
|
function viewIssue(number, repo) {
|
|
25203
25412
|
const args = ["issue", "view", String(number)];
|
|
25204
25413
|
if (repo) args.push("--repo", repo);
|
|
25205
25414
|
try {
|
|
25206
|
-
|
|
25415
|
+
execFileSync13("gh", args, { stdio: "inherit" });
|
|
25207
25416
|
} catch {
|
|
25208
25417
|
process.exit(1);
|
|
25209
25418
|
}
|
|
@@ -25259,7 +25468,7 @@ function registerEditIssue(issueCommand) {
|
|
|
25259
25468
|
}
|
|
25260
25469
|
|
|
25261
25470
|
// src/commands/github/issue/editIssueComment.ts
|
|
25262
|
-
import { execFileSync as
|
|
25471
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
25263
25472
|
var USAGE4 = "Usage: assist github issue edit-comment <comment-id> --body <body> [-R <owner>/<repo>]";
|
|
25264
25473
|
async function editIssueComment(commentIdArg, options2) {
|
|
25265
25474
|
const commentId = Number.parseInt(commentIdArg, 10);
|
|
@@ -25286,7 +25495,7 @@ async function editIssueComment(commentIdArg, options2) {
|
|
|
25286
25495
|
];
|
|
25287
25496
|
let raw;
|
|
25288
25497
|
try {
|
|
25289
|
-
raw =
|
|
25498
|
+
raw = execFileSync14("gh", args, {
|
|
25290
25499
|
input: JSON.stringify({ body }),
|
|
25291
25500
|
encoding: "utf8"
|
|
25292
25501
|
});
|
|
@@ -25667,7 +25876,7 @@ function registerRefineLaunch(program2, resumeFlag) {
|
|
|
25667
25876
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
25668
25877
|
|
|
25669
25878
|
// src/commands/review/checkoutPr.ts
|
|
25670
|
-
import { execFileSync as
|
|
25879
|
+
import { execFileSync as execFileSync16 } from "child_process";
|
|
25671
25880
|
import chalk170 from "chalk";
|
|
25672
25881
|
|
|
25673
25882
|
// src/commands/sessions/daemon/daemonLog.ts
|
|
@@ -25693,30 +25902,19 @@ function recentDaemonLogLines(includeRelayed = true) {
|
|
|
25693
25902
|
return ring.filter((entry) => includeRelayed || !entry.relayed).map((entry) => entry.line);
|
|
25694
25903
|
}
|
|
25695
25904
|
|
|
25696
|
-
// src/commands/sessions/daemon/worktree/canonicalTreePath.ts
|
|
25697
|
-
import { realpathSync as realpathSync2 } from "fs";
|
|
25698
|
-
import { resolve as resolve16 } from "path";
|
|
25699
|
-
function canonicalTreePath(path106) {
|
|
25700
|
-
try {
|
|
25701
|
-
return realpathSync2(path106);
|
|
25702
|
-
} catch {
|
|
25703
|
-
return resolve16(path106);
|
|
25704
|
-
}
|
|
25705
|
-
}
|
|
25706
|
-
|
|
25707
25905
|
// src/commands/sessions/daemon/worktree/createWorktree.ts
|
|
25708
25906
|
import { existsSync as existsSync57 } from "fs";
|
|
25709
|
-
import { basename as
|
|
25907
|
+
import { basename as basename19, dirname as dirname29 } from "path";
|
|
25710
25908
|
|
|
25711
25909
|
// src/commands/sessions/daemon/worktree/planAllocation.ts
|
|
25712
|
-
import { basename as
|
|
25910
|
+
import { basename as basename18, join as join67 } from "path";
|
|
25713
25911
|
function planAllocation(clone, boundTreeRoots2) {
|
|
25714
25912
|
return boundTreeRoots2.has(clone) ? "spill" : "primary";
|
|
25715
25913
|
}
|
|
25716
25914
|
function nextWorktreePath(clone, base, isTaken) {
|
|
25717
|
-
const name =
|
|
25915
|
+
const name = basename18(clone);
|
|
25718
25916
|
for (let n = 2; n < 1e3; n++) {
|
|
25719
|
-
const candidate =
|
|
25917
|
+
const candidate = join67(base, `${name}-${n}`);
|
|
25720
25918
|
if (!isTaken(candidate)) return candidate;
|
|
25721
25919
|
}
|
|
25722
25920
|
throw new Error(`no free worktree suffix for ${clone}`);
|
|
@@ -25752,7 +25950,7 @@ function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
|
|
|
25752
25950
|
const base = strategy.root ? expandTilde2(strategy.root) : dirname29(clone);
|
|
25753
25951
|
const registered = new Set(listWorktreePaths(clone));
|
|
25754
25952
|
const branches = new Set(listLocalBranches(clone));
|
|
25755
|
-
const isTaken = (candidate) => registered.has(candidate) || existsSync57(candidate) || boundTreeRoots2.has(candidate) || branches.has(
|
|
25953
|
+
const isTaken = (candidate) => registered.has(candidate) || existsSync57(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename19(candidate));
|
|
25756
25954
|
const path106 = preferredPath && !isTaken(preferredPath) ? preferredPath : nextWorktreePath(clone, base, isTaken);
|
|
25757
25955
|
const start2 = worktreeStartPoint(clone, strategy.trunk);
|
|
25758
25956
|
gitSync(clone, [
|
|
@@ -25760,13 +25958,13 @@ function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
|
|
|
25760
25958
|
"add",
|
|
25761
25959
|
start2.track ? "--track" : "--no-track",
|
|
25762
25960
|
"-b",
|
|
25763
|
-
|
|
25961
|
+
basename19(path106),
|
|
25764
25962
|
path106,
|
|
25765
25963
|
start2.ref
|
|
25766
25964
|
]);
|
|
25767
25965
|
recordWorktree(path106, clone, getCurrentOrigin(clone));
|
|
25768
25966
|
daemonLog(
|
|
25769
|
-
start2.track ? `worktree allocated ${path106} (branch ${
|
|
25967
|
+
start2.track ? `worktree allocated ${path106} (branch ${basename19(path106)} tracking ${start2.ref}) for clone ${clone}` : `worktree allocated ${path106} (branch ${basename19(path106)} off ${start2.ref}, no mainline tracking) for clone ${clone}`
|
|
25770
25968
|
);
|
|
25771
25969
|
return path106;
|
|
25772
25970
|
}
|
|
@@ -25861,7 +26059,6 @@ function wouldDisturbWorkInProgress(clone, forCheckout) {
|
|
|
25861
26059
|
// src/commands/sessions/daemon/worktree/worktreeConfigFor.ts
|
|
25862
26060
|
var DISABLED = {
|
|
25863
26061
|
enabled: false,
|
|
25864
|
-
watcher: false,
|
|
25865
26062
|
trunk: false,
|
|
25866
26063
|
includeDrafts: false,
|
|
25867
26064
|
install: true,
|
|
@@ -25994,7 +26191,6 @@ function toPersistedSession(session) {
|
|
|
25994
26191
|
assistArgs: session.assistArgs,
|
|
25995
26192
|
activity: session.activity,
|
|
25996
26193
|
starred: session.starred,
|
|
25997
|
-
watcher: session.watcher,
|
|
25998
26194
|
divergenceEscalation: session.divergenceEscalation,
|
|
25999
26195
|
design: session.design,
|
|
26000
26196
|
auto: session.auto,
|
|
@@ -26070,19 +26266,19 @@ function persistedTreeRoots() {
|
|
|
26070
26266
|
|
|
26071
26267
|
// src/commands/sessions/daemon/worktree/seedWorktree.ts
|
|
26072
26268
|
import { copyFileSync, existsSync as existsSync60, mkdirSync as mkdirSync17 } from "fs";
|
|
26073
|
-
import { dirname as dirname30, join as
|
|
26269
|
+
import { dirname as dirname30, join as join69 } from "path";
|
|
26074
26270
|
|
|
26075
26271
|
// src/commands/sessions/daemon/worktree/runInstall.ts
|
|
26076
26272
|
import { resolve as resolve17 } from "path";
|
|
26077
26273
|
|
|
26078
26274
|
// src/commands/sessions/daemon/worktree/detectInstallCommand.ts
|
|
26079
26275
|
import { existsSync as existsSync59 } from "fs";
|
|
26080
|
-
import { join as
|
|
26276
|
+
import { join as join68 } from "path";
|
|
26081
26277
|
function detectInstallCommand(dir) {
|
|
26082
|
-
if (!existsSync59(
|
|
26083
|
-
if (existsSync59(
|
|
26084
|
-
if (existsSync59(
|
|
26085
|
-
if (existsSync59(
|
|
26278
|
+
if (!existsSync59(join68(dir, "package.json"))) return null;
|
|
26279
|
+
if (existsSync59(join68(dir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
26280
|
+
if (existsSync59(join68(dir, "yarn.lock"))) return "yarn install";
|
|
26281
|
+
if (existsSync59(join68(dir, "bun.lockb"))) return "bun install";
|
|
26086
26282
|
return "npm install";
|
|
26087
26283
|
}
|
|
26088
26284
|
|
|
@@ -26244,9 +26440,9 @@ function seedWorktree(worktreePath, clone, onSeeded = () => {
|
|
|
26244
26440
|
}
|
|
26245
26441
|
function copyConfigFiles(worktreePath, clone, copy) {
|
|
26246
26442
|
for (const rel of copy) {
|
|
26247
|
-
const src =
|
|
26443
|
+
const src = join69(clone, rel);
|
|
26248
26444
|
if (!existsSync60(src)) continue;
|
|
26249
|
-
const dest =
|
|
26445
|
+
const dest = join69(worktreePath, rel);
|
|
26250
26446
|
try {
|
|
26251
26447
|
mkdirSync17(dirname30(dest), { recursive: true });
|
|
26252
26448
|
copyFileSync(src, dest);
|
|
@@ -26287,10 +26483,10 @@ async function moveToPrCheckoutTree() {
|
|
|
26287
26483
|
}
|
|
26288
26484
|
|
|
26289
26485
|
// src/commands/review/prHeadBranch.ts
|
|
26290
|
-
import { execFileSync as
|
|
26486
|
+
import { execFileSync as execFileSync15 } from "child_process";
|
|
26291
26487
|
function prHeadBranch(number) {
|
|
26292
26488
|
try {
|
|
26293
|
-
const out =
|
|
26489
|
+
const out = execFileSync15(
|
|
26294
26490
|
"gh",
|
|
26295
26491
|
["pr", "view", number, "--json", "headRefName", "-q", ".headRefName"],
|
|
26296
26492
|
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
|
|
@@ -26352,7 +26548,7 @@ async function checkoutPr(number) {
|
|
|
26352
26548
|
if (headRef && await moveToExistingCheckout(number, headRef)) return;
|
|
26353
26549
|
await moveToPrCheckoutTree();
|
|
26354
26550
|
try {
|
|
26355
|
-
|
|
26551
|
+
execFileSync16("gh", ["pr", "checkout", number], { stdio: "inherit" });
|
|
26356
26552
|
} catch {
|
|
26357
26553
|
console.error(chalk170.red(`gh pr checkout ${number} failed; aborting.`));
|
|
26358
26554
|
process.exit(1);
|
|
@@ -26556,7 +26752,7 @@ import chalk175 from "chalk";
|
|
|
26556
26752
|
|
|
26557
26753
|
// src/commands/mermaid/exportFile.ts
|
|
26558
26754
|
import { readFileSync as readFileSync39, writeFileSync as writeFileSync32 } from "fs";
|
|
26559
|
-
import { basename as
|
|
26755
|
+
import { basename as basename20, extname as extname3, resolve as resolve18 } from "path";
|
|
26560
26756
|
import chalk174 from "chalk";
|
|
26561
26757
|
|
|
26562
26758
|
// src/commands/mermaid/renderBlock.ts
|
|
@@ -26583,7 +26779,7 @@ async function renderBlock(krokiUrl, source) {
|
|
|
26583
26779
|
async function exportFile(file, outDir, krokiUrl, onlyIndex) {
|
|
26584
26780
|
const content = readFileSync39(file, "utf8");
|
|
26585
26781
|
const blocks = extractMermaidBlocks(content);
|
|
26586
|
-
const stem =
|
|
26782
|
+
const stem = basename20(file, extname3(file));
|
|
26587
26783
|
if (onlyIndex !== void 0) {
|
|
26588
26784
|
if (onlyIndex < 1 || onlyIndex > blocks.length) {
|
|
26589
26785
|
console.error(
|
|
@@ -27280,15 +27476,15 @@ function createNetcapHandler(options2) {
|
|
|
27280
27476
|
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
27281
27477
|
import { cp as cp4, readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
27282
27478
|
import { networkInterfaces } from "os";
|
|
27283
|
-
import { join as
|
|
27479
|
+
import { join as join71 } from "path";
|
|
27284
27480
|
import chalk178 from "chalk";
|
|
27285
27481
|
|
|
27286
27482
|
// src/commands/netcap/netcapExtensionDir.ts
|
|
27287
|
-
import { dirname as dirname32, join as
|
|
27483
|
+
import { dirname as dirname32, join as join70 } from "path";
|
|
27288
27484
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
27289
27485
|
var moduleDir2 = dirname32(fileURLToPath7(import.meta.url));
|
|
27290
27486
|
function netcapExtensionDir() {
|
|
27291
|
-
return
|
|
27487
|
+
return join70(moduleDir2, "commands", "netcap", "netcap-extension");
|
|
27292
27488
|
}
|
|
27293
27489
|
|
|
27294
27490
|
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
@@ -27303,7 +27499,7 @@ function lanIPv4() {
|
|
|
27303
27499
|
return void 0;
|
|
27304
27500
|
}
|
|
27305
27501
|
async function configureBackground(dir, host, port, filter) {
|
|
27306
|
-
const file =
|
|
27502
|
+
const file = join71(dir, "background.js");
|
|
27307
27503
|
const source = await readFile7(file, "utf8");
|
|
27308
27504
|
await writeFile6(
|
|
27309
27505
|
file,
|
|
@@ -27343,20 +27539,20 @@ async function prepareExtensionForLoad(port, filter = "") {
|
|
|
27343
27539
|
}
|
|
27344
27540
|
|
|
27345
27541
|
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
27346
|
-
import { isAbsolute as isAbsolute5, join as
|
|
27542
|
+
import { isAbsolute as isAbsolute5, join as join73, resolve as resolve21 } from "path";
|
|
27347
27543
|
|
|
27348
27544
|
// src/commands/netcap/defaultCapturePath.ts
|
|
27349
|
-
import { homedir as
|
|
27350
|
-
import { join as
|
|
27545
|
+
import { homedir as homedir23 } from "os";
|
|
27546
|
+
import { join as join72 } from "path";
|
|
27351
27547
|
function defaultCapturePath() {
|
|
27352
|
-
return
|
|
27548
|
+
return join72(homedir23(), ".assist", "netcap", "capture.jsonl");
|
|
27353
27549
|
}
|
|
27354
27550
|
|
|
27355
27551
|
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
27356
27552
|
function resolveNetcapOutPath(out) {
|
|
27357
27553
|
if (!out) return defaultCapturePath();
|
|
27358
27554
|
const dir = isAbsolute5(out) ? out : resolve21(process.cwd(), out);
|
|
27359
|
-
return
|
|
27555
|
+
return join73(dir, "capture.jsonl");
|
|
27360
27556
|
}
|
|
27361
27557
|
|
|
27362
27558
|
// src/commands/netcap/netcap.ts
|
|
@@ -27403,7 +27599,7 @@ netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} t
|
|
|
27403
27599
|
|
|
27404
27600
|
// src/commands/netcap/netcapExtract.ts
|
|
27405
27601
|
import { writeFileSync as writeFileSync34 } from "fs";
|
|
27406
|
-
import { join as
|
|
27602
|
+
import { join as join74 } from "path";
|
|
27407
27603
|
import chalk180 from "chalk";
|
|
27408
27604
|
|
|
27409
27605
|
// src/commands/netcap/extractPostsFromCapture.ts
|
|
@@ -27848,7 +28044,7 @@ function extractPostsFromCapture(captureFile) {
|
|
|
27848
28044
|
function netcapExtract(file) {
|
|
27849
28045
|
const captureFile = file ?? defaultCapturePath();
|
|
27850
28046
|
const posts = extractPostsFromCapture(captureFile);
|
|
27851
|
-
const outFile =
|
|
28047
|
+
const outFile = join74(captureFile, "..", "posts.json");
|
|
27852
28048
|
writeFileSync34(outFile, `${JSON.stringify(posts, null, 2)}
|
|
27853
28049
|
`);
|
|
27854
28050
|
console.log(
|
|
@@ -28211,18 +28407,18 @@ import { execSync as execSync41 } from "child_process";
|
|
|
28211
28407
|
import { execSync as execSync40 } from "child_process";
|
|
28212
28408
|
import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync35 } from "fs";
|
|
28213
28409
|
import { tmpdir as tmpdir6 } from "os";
|
|
28214
|
-
import { join as
|
|
28410
|
+
import { join as join76 } from "path";
|
|
28215
28411
|
|
|
28216
28412
|
// src/commands/prs/loadCommentsCache.ts
|
|
28217
28413
|
import { existsSync as existsSync62, readFileSync as readFileSync43, unlinkSync as unlinkSync13 } from "fs";
|
|
28218
28414
|
import { parse as parse3 } from "yaml";
|
|
28219
28415
|
|
|
28220
28416
|
// src/commands/prs/commentsCachePath.ts
|
|
28221
|
-
import { homedir as
|
|
28222
|
-
import { join as
|
|
28417
|
+
import { homedir as homedir24 } from "os";
|
|
28418
|
+
import { join as join75 } from "path";
|
|
28223
28419
|
function commentsCachePath(org, repo, prNumber) {
|
|
28224
|
-
return
|
|
28225
|
-
|
|
28420
|
+
return join75(
|
|
28421
|
+
homedir24(),
|
|
28226
28422
|
".assist",
|
|
28227
28423
|
"pr-comments",
|
|
28228
28424
|
org,
|
|
@@ -28270,7 +28466,7 @@ function replyToComment(org, repo, prNumber, commentId, message3) {
|
|
|
28270
28466
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
28271
28467
|
function resolveThread(threadId) {
|
|
28272
28468
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
28273
|
-
const queryFile =
|
|
28469
|
+
const queryFile = join76(tmpdir6(), `gh-mutation-${Date.now()}.graphql`);
|
|
28274
28470
|
writeFileSync35(queryFile, mutation);
|
|
28275
28471
|
try {
|
|
28276
28472
|
execSync40(
|
|
@@ -28355,10 +28551,10 @@ function fixed(commentId, sha) {
|
|
|
28355
28551
|
import { execSync as execSync42 } from "child_process";
|
|
28356
28552
|
import { unlinkSync as unlinkSync15, writeFileSync as writeFileSync36 } from "fs";
|
|
28357
28553
|
import { tmpdir as tmpdir7 } from "os";
|
|
28358
|
-
import { join as
|
|
28554
|
+
import { join as join77 } from "path";
|
|
28359
28555
|
var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
|
|
28360
28556
|
function fetchThreadIds(org, repo, prNumber) {
|
|
28361
|
-
const queryFile =
|
|
28557
|
+
const queryFile = join77(tmpdir7(), `gh-query-${Date.now()}.graphql`);
|
|
28362
28558
|
writeFileSync36(queryFile, THREAD_QUERY);
|
|
28363
28559
|
try {
|
|
28364
28560
|
const result = execSync42(
|
|
@@ -28433,10 +28629,10 @@ import { stringify as stringify3 } from "yaml";
|
|
|
28433
28629
|
|
|
28434
28630
|
// src/commands/prs/removeStaleCommentsCaches.ts
|
|
28435
28631
|
import { readdirSync as readdirSync12, unlinkSync as unlinkSync16 } from "fs";
|
|
28436
|
-
import { join as
|
|
28632
|
+
import { join as join78 } from "path";
|
|
28437
28633
|
var STALE_PATTERN = /^pr-\d+-comments\.yaml$/;
|
|
28438
28634
|
function removeStaleCommentsCaches(cwd = process.cwd()) {
|
|
28439
|
-
const dir =
|
|
28635
|
+
const dir = join78(cwd, ".assist");
|
|
28440
28636
|
let entries;
|
|
28441
28637
|
try {
|
|
28442
28638
|
entries = readdirSync12(dir);
|
|
@@ -28444,7 +28640,7 @@ function removeStaleCommentsCaches(cwd = process.cwd()) {
|
|
|
28444
28640
|
return;
|
|
28445
28641
|
}
|
|
28446
28642
|
for (const entry of entries.filter((e) => STALE_PATTERN.test(e))) {
|
|
28447
|
-
unlinkSync16(
|
|
28643
|
+
unlinkSync16(join78(dir, entry));
|
|
28448
28644
|
}
|
|
28449
28645
|
}
|
|
28450
28646
|
|
|
@@ -29078,7 +29274,7 @@ function buildValidatedBody(options2, usage) {
|
|
|
29078
29274
|
}
|
|
29079
29275
|
|
|
29080
29276
|
// src/commands/prs/placePr.ts
|
|
29081
|
-
import { execFileSync as
|
|
29277
|
+
import { execFileSync as execFileSync17 } from "child_process";
|
|
29082
29278
|
|
|
29083
29279
|
// src/commands/prs/buildCreateArgs.ts
|
|
29084
29280
|
function buildCreateArgs(title, body, options2, attachments = []) {
|
|
@@ -29164,7 +29360,7 @@ function buildEditArgs(number, title, body, attachments = []) {
|
|
|
29164
29360
|
// src/commands/prs/placePr.ts
|
|
29165
29361
|
function hasUpstream2() {
|
|
29166
29362
|
try {
|
|
29167
|
-
|
|
29363
|
+
execFileSync17(
|
|
29168
29364
|
"git",
|
|
29169
29365
|
["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
|
|
29170
29366
|
{ stdio: "pipe" }
|
|
@@ -29176,7 +29372,7 @@ function hasUpstream2() {
|
|
|
29176
29372
|
}
|
|
29177
29373
|
function ensureBranchPushed() {
|
|
29178
29374
|
const args = hasUpstream2() ? ["push"] : ["push", "--set-upstream", "origin", "HEAD"];
|
|
29179
|
-
|
|
29375
|
+
execFileSync17("git", args, { stdio: "inherit" });
|
|
29180
29376
|
}
|
|
29181
29377
|
async function placePr(prNumber, title, body, options2, attachments = []) {
|
|
29182
29378
|
const args = prNumber !== null ? buildEditArgs(prNumber, title, body, attachments) : buildCreateArgs(title, body, options2, attachments);
|
|
@@ -29322,10 +29518,10 @@ function warn(reason4) {
|
|
|
29322
29518
|
}
|
|
29323
29519
|
|
|
29324
29520
|
// src/commands/prs/enableAutoMerge.ts
|
|
29325
|
-
import { execFileSync as
|
|
29521
|
+
import { execFileSync as execFileSync18 } from "child_process";
|
|
29326
29522
|
function enableAutoMerge() {
|
|
29327
29523
|
try {
|
|
29328
|
-
|
|
29524
|
+
execFileSync18(
|
|
29329
29525
|
"gh",
|
|
29330
29526
|
["pr", "merge", getCurrentBranch2(), "--auto", "--squash"],
|
|
29331
29527
|
{ stdio: "inherit" }
|
|
@@ -31083,7 +31279,7 @@ async function notify() {
|
|
|
31083
31279
|
import { execSync as execSync52 } from "child_process";
|
|
31084
31280
|
import { existsSync as existsSync63, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync38 } from "fs";
|
|
31085
31281
|
import { tmpdir as tmpdir8 } from "os";
|
|
31086
|
-
import { join as
|
|
31282
|
+
import { join as join79, resolve as resolve22 } from "path";
|
|
31087
31283
|
import chalk205 from "chalk";
|
|
31088
31284
|
|
|
31089
31285
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
@@ -31220,7 +31416,7 @@ function buildOutputPath(outputDir, processName) {
|
|
|
31220
31416
|
return resolve22(outputDir, `${processName}-${timestamp5}.png`);
|
|
31221
31417
|
}
|
|
31222
31418
|
function runPowerShellScript(processName, outputPath) {
|
|
31223
|
-
const scriptPath =
|
|
31419
|
+
const scriptPath = join79(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
|
|
31224
31420
|
writeFileSync38(scriptPath, captureWindowPs1, "utf8");
|
|
31225
31421
|
try {
|
|
31226
31422
|
execSync52(
|
|
@@ -31335,9 +31531,9 @@ function buildLimitsSegment(rateLimits) {
|
|
|
31335
31531
|
|
|
31336
31532
|
// src/commands/readGitBranch.ts
|
|
31337
31533
|
import { readFileSync as readFileSync46, statSync as statSync10 } from "fs";
|
|
31338
|
-
import { isAbsolute as isAbsolute6, join as
|
|
31534
|
+
import { isAbsolute as isAbsolute6, join as join80, resolve as resolve23 } from "path";
|
|
31339
31535
|
function resolveGitDir(cwd) {
|
|
31340
|
-
const dotGit =
|
|
31536
|
+
const dotGit = join80(cwd, ".git");
|
|
31341
31537
|
let stat5;
|
|
31342
31538
|
try {
|
|
31343
31539
|
stat5 = statSync10(dotGit);
|
|
@@ -31367,7 +31563,7 @@ function readGitBranch(cwd) {
|
|
|
31367
31563
|
}
|
|
31368
31564
|
let head;
|
|
31369
31565
|
try {
|
|
31370
|
-
head = readFileSync46(
|
|
31566
|
+
head = readFileSync46(join80(gitDir, "HEAD"), "utf8");
|
|
31371
31567
|
} catch {
|
|
31372
31568
|
return null;
|
|
31373
31569
|
}
|
|
@@ -33788,7 +33984,7 @@ function exitWith(message3) {
|
|
|
33788
33984
|
}
|
|
33789
33985
|
|
|
33790
33986
|
// src/commands/review/highLevel/proposeHighLevelGlobs.ts
|
|
33791
|
-
import { execFileSync as
|
|
33987
|
+
import { execFileSync as execFileSync20 } from "child_process";
|
|
33792
33988
|
import chalk228 from "chalk";
|
|
33793
33989
|
|
|
33794
33990
|
// src/commands/review/highLevel/buildGlobProposalPrompt.ts
|
|
@@ -33836,7 +34032,7 @@ function readGlobs(value) {
|
|
|
33836
34032
|
}
|
|
33837
34033
|
|
|
33838
34034
|
// src/commands/review/highLevel/summariseRepoTree.ts
|
|
33839
|
-
import { execFileSync as
|
|
34035
|
+
import { execFileSync as execFileSync19 } from "child_process";
|
|
33840
34036
|
import { dirname as dirname36, extname as extname4 } from "path";
|
|
33841
34037
|
var MAX_DIRECTORIES = 200;
|
|
33842
34038
|
var MAX_EXTENSIONS_PER_DIRECTORY = 6;
|
|
@@ -33852,7 +34048,7 @@ function summariseRepoTree(cwd = process.cwd()) {
|
|
|
33852
34048
|
}
|
|
33853
34049
|
function listTrackedFiles(cwd) {
|
|
33854
34050
|
try {
|
|
33855
|
-
return
|
|
34051
|
+
return execFileSync19("git", ["ls-files"], {
|
|
33856
34052
|
cwd,
|
|
33857
34053
|
encoding: "utf8",
|
|
33858
34054
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -33897,7 +34093,7 @@ function proposeHighLevelGlobs(cwd = process.cwd()) {
|
|
|
33897
34093
|
}
|
|
33898
34094
|
function askClaude(prompt, cwd) {
|
|
33899
34095
|
try {
|
|
33900
|
-
return
|
|
34096
|
+
return execFileSync20("claude", ["-p", "--model", "sonnet", prompt], {
|
|
33901
34097
|
cwd,
|
|
33902
34098
|
encoding: "utf8",
|
|
33903
34099
|
timeout: 12e4,
|
|
@@ -33990,7 +34186,7 @@ function groupFilesByDirectory(files) {
|
|
|
33990
34186
|
}
|
|
33991
34187
|
|
|
33992
34188
|
// src/commands/review/highLevel/buildHighLevelTree.ts
|
|
33993
|
-
function
|
|
34189
|
+
function basename21(path106) {
|
|
33994
34190
|
return path106.slice(path106.lastIndexOf("/") + 1);
|
|
33995
34191
|
}
|
|
33996
34192
|
function sum(nodes, key) {
|
|
@@ -34006,7 +34202,7 @@ function nodesOf(at2, prefix2) {
|
|
|
34006
34202
|
const files = at2.files.map(
|
|
34007
34203
|
(file) => ({
|
|
34008
34204
|
kind: "file",
|
|
34009
|
-
name:
|
|
34205
|
+
name: basename21(file.path),
|
|
34010
34206
|
...file
|
|
34011
34207
|
})
|
|
34012
34208
|
);
|
|
@@ -34277,7 +34473,7 @@ function evaluateHighLevelChecks(subject) {
|
|
|
34277
34473
|
|
|
34278
34474
|
// src/commands/review/highLevel/fetchHighLevelFiles.ts
|
|
34279
34475
|
import { execSync as execSync55 } from "child_process";
|
|
34280
|
-
import { createHash as
|
|
34476
|
+
import { createHash as createHash4 } from "crypto";
|
|
34281
34477
|
var JQ = ".[] | {filename,status,additions,deletions,patch} | @json";
|
|
34282
34478
|
function toStatus(status2) {
|
|
34283
34479
|
if (status2 === "added") return "added";
|
|
@@ -34285,7 +34481,7 @@ function toStatus(status2) {
|
|
|
34285
34481
|
return "modified";
|
|
34286
34482
|
}
|
|
34287
34483
|
function diffUrl(repo, prNumber, path106) {
|
|
34288
|
-
const anchor =
|
|
34484
|
+
const anchor = createHash4("sha256").update(path106).digest("hex");
|
|
34289
34485
|
return `https://github.com/${repo}/pull/${prNumber}/files#diff-${anchor}`;
|
|
34290
34486
|
}
|
|
34291
34487
|
function fetchHighLevelFiles(prNumber, repo) {
|
|
@@ -34326,12 +34522,12 @@ function fetchHighLevelPr(prNumber, repo) {
|
|
|
34326
34522
|
import { existsSync as existsSync64, readFileSync as readFileSync47 } from "fs";
|
|
34327
34523
|
|
|
34328
34524
|
// src/commands/review/highLevel/highLevelReviewPath.ts
|
|
34329
|
-
import { join as
|
|
34525
|
+
import { join as join81 } from "path";
|
|
34330
34526
|
function slug(value) {
|
|
34331
34527
|
return value.replace(/[^\w.-]+/g, "-");
|
|
34332
34528
|
}
|
|
34333
34529
|
function highLevelReviewPath(repo, headRef, headSha) {
|
|
34334
|
-
return
|
|
34530
|
+
return join81(
|
|
34335
34531
|
getStoreDir(),
|
|
34336
34532
|
"high-level-reviews",
|
|
34337
34533
|
slug(repo),
|
|
@@ -35407,18 +35603,7 @@ import { format } from "util";
|
|
|
35407
35603
|
|
|
35408
35604
|
// src/commands/review/createReviewLogSink.ts
|
|
35409
35605
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync23 } from "fs";
|
|
35410
|
-
import { join as
|
|
35411
|
-
|
|
35412
|
-
// src/shared/stripAnsi.ts
|
|
35413
|
-
var ANSI = new RegExp(
|
|
35414
|
-
`${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`,
|
|
35415
|
-
"g"
|
|
35416
|
-
);
|
|
35417
|
-
function stripAnsi(text17) {
|
|
35418
|
-
return text17.replace(ANSI, "");
|
|
35419
|
-
}
|
|
35420
|
-
|
|
35421
|
-
// src/commands/review/createReviewLogSink.ts
|
|
35606
|
+
import { join as join82 } from "path";
|
|
35422
35607
|
var LOG_FILE = "review.log";
|
|
35423
35608
|
function createReviewLogSink() {
|
|
35424
35609
|
let logPath2;
|
|
@@ -35435,7 +35620,7 @@ function createReviewLogSink() {
|
|
|
35435
35620
|
},
|
|
35436
35621
|
attach(reviewDir) {
|
|
35437
35622
|
mkdirSync23(reviewDir, { recursive: true });
|
|
35438
|
-
logPath2 =
|
|
35623
|
+
logPath2 = join82(reviewDir, LOG_FILE);
|
|
35439
35624
|
const lines2 = [
|
|
35440
35625
|
"",
|
|
35441
35626
|
`=== ${(/* @__PURE__ */ new Date()).toISOString()} ===`,
|
|
@@ -36516,22 +36701,22 @@ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
|
|
|
36516
36701
|
}
|
|
36517
36702
|
|
|
36518
36703
|
// src/commands/review/buildReviewPaths.ts
|
|
36519
|
-
import { homedir as
|
|
36520
|
-
import { basename as
|
|
36704
|
+
import { homedir as homedir25 } from "os";
|
|
36705
|
+
import { basename as basename22, join as join83 } from "path";
|
|
36521
36706
|
function buildReviewPaths(repoRoot2, key) {
|
|
36522
|
-
const reviewDir =
|
|
36523
|
-
|
|
36707
|
+
const reviewDir = join83(
|
|
36708
|
+
homedir25(),
|
|
36524
36709
|
".assist",
|
|
36525
36710
|
"reviews",
|
|
36526
|
-
|
|
36711
|
+
basename22(repoRoot2),
|
|
36527
36712
|
key
|
|
36528
36713
|
);
|
|
36529
36714
|
return {
|
|
36530
36715
|
reviewDir,
|
|
36531
|
-
requestPath:
|
|
36532
|
-
claudePath:
|
|
36533
|
-
codexPath:
|
|
36534
|
-
synthesisPath:
|
|
36716
|
+
requestPath: join83(reviewDir, "request.md"),
|
|
36717
|
+
claudePath: join83(reviewDir, "claude.md"),
|
|
36718
|
+
codexPath: join83(reviewDir, "codex.md"),
|
|
36719
|
+
synthesisPath: join83(reviewDir, "synthesis.md")
|
|
36535
36720
|
};
|
|
36536
36721
|
}
|
|
36537
36722
|
|
|
@@ -36985,16 +37170,16 @@ import path87 from "path";
|
|
|
36985
37170
|
import chalk239 from "chalk";
|
|
36986
37171
|
function listRules(target, options2 = {}) {
|
|
36987
37172
|
const resolved = path87.resolve(target ?? process.cwd());
|
|
36988
|
-
const
|
|
36989
|
-
if (
|
|
37173
|
+
const rules2 = readScopedRules(resolved);
|
|
37174
|
+
if (rules2.length === 0) {
|
|
36990
37175
|
const label2 = path87.relative(process.cwd(), resolved) || ".";
|
|
36991
37176
|
console.log(chalk239.gray(`No rules in scope for ${label2}`));
|
|
36992
37177
|
return;
|
|
36993
37178
|
}
|
|
36994
37179
|
const base = findRepoRoot(scopeDirectory(resolved));
|
|
36995
|
-
const width = Math.max(...
|
|
37180
|
+
const width = Math.max(...rules2.map((rule) => rule.code.length));
|
|
36996
37181
|
let shown;
|
|
36997
|
-
for (const rule of
|
|
37182
|
+
for (const rule of rules2) {
|
|
36998
37183
|
if (rule.source !== shown) {
|
|
36999
37184
|
shown = rule.source;
|
|
37000
37185
|
console.log(
|
|
@@ -37512,12 +37697,12 @@ async function reviewProposedSlackMessage(target, body, workingPath) {
|
|
|
37512
37697
|
}
|
|
37513
37698
|
|
|
37514
37699
|
// src/commands/slack/slackWorkingFile.ts
|
|
37515
|
-
import { join as
|
|
37700
|
+
import { join as join84 } from "path";
|
|
37516
37701
|
function slackWorkingFile(channel, partIndex) {
|
|
37517
37702
|
const slug2 = channel.replace(/^[#@]/, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
|
|
37518
|
-
const dir =
|
|
37703
|
+
const dir = join84(getStoreDir(), "slack");
|
|
37519
37704
|
const name = partIndex === void 0 ? slug2 : `${slug2}-${partIndex}`;
|
|
37520
|
-
return { dir, bodyPath:
|
|
37705
|
+
return { dir, bodyPath: join84(dir, `${name}.md`) };
|
|
37521
37706
|
}
|
|
37522
37707
|
|
|
37523
37708
|
// src/commands/slack/previewSlackThreadParts.ts
|
|
@@ -38697,20 +38882,20 @@ async function configure() {
|
|
|
38697
38882
|
|
|
38698
38883
|
// src/commands/transcript/list.ts
|
|
38699
38884
|
import { existsSync as existsSync76, readdirSync as readdirSync20, statSync as statSync12 } from "fs";
|
|
38700
|
-
import { join as
|
|
38885
|
+
import { join as join96 } from "path";
|
|
38701
38886
|
function list3() {
|
|
38702
38887
|
const { vttDir } = getTranscriptConfig();
|
|
38703
38888
|
if (!existsSync76(vttDir)) return;
|
|
38704
38889
|
for (const entry of readdirSync20(vttDir)) {
|
|
38705
38890
|
if (!entry.endsWith(".vtt")) continue;
|
|
38706
|
-
if (statSync12(
|
|
38891
|
+
if (statSync12(join96(vttDir, entry)).isDirectory()) continue;
|
|
38707
38892
|
console.log(entry);
|
|
38708
38893
|
}
|
|
38709
38894
|
}
|
|
38710
38895
|
|
|
38711
38896
|
// src/commands/transcript/move.ts
|
|
38712
38897
|
import { existsSync as existsSync77, mkdirSync as mkdirSync32, renameSync as renameSync2, writeFileSync as writeFileSync50 } from "fs";
|
|
38713
|
-
import { basename as
|
|
38898
|
+
import { basename as basename26, join as join97 } from "path";
|
|
38714
38899
|
|
|
38715
38900
|
// src/commands/transcript/convertVttToMarkdown.ts
|
|
38716
38901
|
function convertVttToMarkdown(inputPath) {
|
|
@@ -38720,9 +38905,9 @@ function convertVttToMarkdown(inputPath) {
|
|
|
38720
38905
|
// src/commands/transcript/move.ts
|
|
38721
38906
|
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
38722
38907
|
function archiveRawVtt(vttDir, sourcePath, filename) {
|
|
38723
|
-
const processedDir =
|
|
38908
|
+
const processedDir = join97(vttDir, "processed");
|
|
38724
38909
|
mkdirSync32(processedDir, { recursive: true });
|
|
38725
|
-
renameSync2(sourcePath,
|
|
38910
|
+
renameSync2(sourcePath, join97(processedDir, filename));
|
|
38726
38911
|
}
|
|
38727
38912
|
function move(file, options2) {
|
|
38728
38913
|
const { date, client } = options2;
|
|
@@ -38731,27 +38916,27 @@ function move(file, options2) {
|
|
|
38731
38916
|
process.exit(1);
|
|
38732
38917
|
}
|
|
38733
38918
|
const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
38734
|
-
const filename =
|
|
38735
|
-
const sourcePath =
|
|
38919
|
+
const filename = basename26(file);
|
|
38920
|
+
const sourcePath = join97(vttDir, filename);
|
|
38736
38921
|
if (!existsSync77(sourcePath)) {
|
|
38737
38922
|
console.error(`Error: VTT file not found: ${sourcePath}`);
|
|
38738
38923
|
process.exit(1);
|
|
38739
38924
|
}
|
|
38740
|
-
const base =
|
|
38925
|
+
const base = basename26(filename, ".vtt").replace(/ Transcription$/, "");
|
|
38741
38926
|
const outputName = `${date} ${base}.md`;
|
|
38742
|
-
const formattedDir =
|
|
38927
|
+
const formattedDir = join97(transcriptsDir, client);
|
|
38743
38928
|
mkdirSync32(formattedDir, { recursive: true });
|
|
38744
|
-
const formattedPath =
|
|
38929
|
+
const formattedPath = join97(formattedDir, outputName);
|
|
38745
38930
|
writeFileSync50(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
|
|
38746
38931
|
archiveRawVtt(vttDir, sourcePath, filename);
|
|
38747
|
-
const summaryPath =
|
|
38932
|
+
const summaryPath = join97(summaryDir, client, outputName);
|
|
38748
38933
|
console.log(`Formatted transcript: ${formattedPath}`);
|
|
38749
38934
|
console.log(`Summary target: ${summaryPath}`);
|
|
38750
38935
|
}
|
|
38751
38936
|
|
|
38752
38937
|
// src/commands/transcript/merge.ts
|
|
38753
38938
|
import { existsSync as existsSync78, writeFileSync as writeFileSync51 } from "fs";
|
|
38754
|
-
import { basename as
|
|
38939
|
+
import { basename as basename27 } from "path";
|
|
38755
38940
|
|
|
38756
38941
|
// src/commands/transcript/failTranscript.ts
|
|
38757
38942
|
function failTranscript(message3) {
|
|
@@ -38897,7 +39082,7 @@ function readSource3(file) {
|
|
|
38897
39082
|
if (!existsSync78(file)) failTranscript(`VTT file not found: ${file}`);
|
|
38898
39083
|
const cues = readCleanedCues(file);
|
|
38899
39084
|
if (cues.length === 0) failTranscript(`no cues found in: ${file}`);
|
|
38900
|
-
return { path: file, name:
|
|
39085
|
+
return { path: file, name: basename27(file), cues };
|
|
38901
39086
|
}
|
|
38902
39087
|
function wholePassages(sources) {
|
|
38903
39088
|
return sources.map((source) => ({
|
|
@@ -39388,14 +39573,14 @@ function findRuleViolations(data, rule) {
|
|
|
39388
39573
|
}
|
|
39389
39574
|
return violations;
|
|
39390
39575
|
}
|
|
39391
|
-
function findForbiddenStrings(
|
|
39392
|
-
return
|
|
39576
|
+
function findForbiddenStrings(rules2, readJson) {
|
|
39577
|
+
return rules2.flatMap((rule) => findRuleViolations(readJson(rule.file), rule));
|
|
39393
39578
|
}
|
|
39394
39579
|
|
|
39395
39580
|
// src/commands/verify/forbiddenStrings.ts
|
|
39396
39581
|
function forbiddenStrings() {
|
|
39397
|
-
const
|
|
39398
|
-
if (
|
|
39582
|
+
const rules2 = loadConfig().forbiddenStrings ?? [];
|
|
39583
|
+
if (rules2.length === 0) {
|
|
39399
39584
|
console.log("No forbidden-strings rules configured.");
|
|
39400
39585
|
process.exit(0);
|
|
39401
39586
|
}
|
|
@@ -39416,7 +39601,7 @@ function forbiddenStrings() {
|
|
|
39416
39601
|
cache6.set(file, parsed);
|
|
39417
39602
|
return parsed;
|
|
39418
39603
|
};
|
|
39419
|
-
const violations = findForbiddenStrings(
|
|
39604
|
+
const violations = findForbiddenStrings(rules2, readJson);
|
|
39420
39605
|
if (violations.length === 0) {
|
|
39421
39606
|
console.log("No forbidden strings found.");
|
|
39422
39607
|
process.exit(0);
|
|
@@ -39558,7 +39743,7 @@ function listMigrationFiles(dir) {
|
|
|
39558
39743
|
|
|
39559
39744
|
// src/commands/verify/migrations/readBaselineMigrations.ts
|
|
39560
39745
|
import { execSync as execSync63 } from "child_process";
|
|
39561
|
-
import { basename as
|
|
39746
|
+
import { basename as basename28 } from "path";
|
|
39562
39747
|
var MIGRATION_FILE3 = /^migration\d+[A-Za-z0-9]*\.ts$/;
|
|
39563
39748
|
function readBaselineMigrations(repoRelativeDir, ref) {
|
|
39564
39749
|
const baseline = /* @__PURE__ */ new Map();
|
|
@@ -39571,7 +39756,7 @@ function readBaselineMigrations(repoRelativeDir, ref) {
|
|
|
39571
39756
|
} catch {
|
|
39572
39757
|
return baseline;
|
|
39573
39758
|
}
|
|
39574
|
-
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path106) => MIGRATION_FILE3.test(
|
|
39759
|
+
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path106) => MIGRATION_FILE3.test(basename28(path106)));
|
|
39575
39760
|
for (const path106 of paths) {
|
|
39576
39761
|
try {
|
|
39577
39762
|
const content = execSync63(`git show "${ref}:${path106}"`, {
|
|
@@ -39579,7 +39764,7 @@ function readBaselineMigrations(repoRelativeDir, ref) {
|
|
|
39579
39764
|
maxBuffer: 16 * 1024 * 1024,
|
|
39580
39765
|
stdio: ["pipe", "pipe", "pipe"]
|
|
39581
39766
|
});
|
|
39582
|
-
baseline.set(
|
|
39767
|
+
baseline.set(basename28(path106), content);
|
|
39583
39768
|
} catch {
|
|
39584
39769
|
}
|
|
39585
39770
|
}
|
|
@@ -39792,46 +39977,6 @@ function gitFailureReason(error) {
|
|
|
39792
39977
|
return message3.trim() || "git failed without reporting a reason";
|
|
39793
39978
|
}
|
|
39794
39979
|
|
|
39795
|
-
// src/commands/watch/resolveUpstream.ts
|
|
39796
|
-
import { execFileSync as execFileSync20 } from "child_process";
|
|
39797
|
-
function runGit3(args, cwd) {
|
|
39798
|
-
return execFileSync20("git", args, {
|
|
39799
|
-
encoding: "utf8",
|
|
39800
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
39801
|
-
cwd
|
|
39802
|
-
}).trim();
|
|
39803
|
-
}
|
|
39804
|
-
function resolveUpstream(cwd) {
|
|
39805
|
-
try {
|
|
39806
|
-
runGit3(["rev-parse", "--is-inside-work-tree"], cwd);
|
|
39807
|
-
} catch {
|
|
39808
|
-
throw new Error(
|
|
39809
|
-
"not a git repository \u2014 run assist watch wait from inside a repo"
|
|
39810
|
-
);
|
|
39811
|
-
}
|
|
39812
|
-
let branch2;
|
|
39813
|
-
try {
|
|
39814
|
-
branch2 = runGit3(["symbolic-ref", "--quiet", "--short", "HEAD"], cwd);
|
|
39815
|
-
} catch {
|
|
39816
|
-
throw new Error(
|
|
39817
|
-
"HEAD is detached \u2014 check out a branch before waiting on its upstream"
|
|
39818
|
-
);
|
|
39819
|
-
}
|
|
39820
|
-
try {
|
|
39821
|
-
return {
|
|
39822
|
-
branch: branch2,
|
|
39823
|
-
upstream: runGit3(
|
|
39824
|
-
["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
|
|
39825
|
-
cwd
|
|
39826
|
-
)
|
|
39827
|
-
};
|
|
39828
|
-
} catch {
|
|
39829
|
-
throw new Error(
|
|
39830
|
-
`branch "${branch2}" has no upstream \u2014 set one with: git push -u origin ${branch2}`
|
|
39831
|
-
);
|
|
39832
|
-
}
|
|
39833
|
-
}
|
|
39834
|
-
|
|
39835
39980
|
// src/commands/watch/simulatedDivergencePath.ts
|
|
39836
39981
|
import { resolve as resolve25 } from "path";
|
|
39837
39982
|
function simulatedDivergencePath(cwd) {
|
|
@@ -39899,22 +40044,6 @@ async function watchLoop() {
|
|
|
39899
40044
|
}
|
|
39900
40045
|
}
|
|
39901
40046
|
|
|
39902
|
-
// src/commands/watch/changedPaths.ts
|
|
39903
|
-
function changedPaths(from, cwd) {
|
|
39904
|
-
return runGit3(["diff", "--name-only", `${from}..HEAD`], cwd).split("\n").filter((line) => line.length > 0);
|
|
39905
|
-
}
|
|
39906
|
-
|
|
39907
|
-
// src/commands/watch/readBuiltVersion.ts
|
|
39908
|
-
import { join as join96 } from "path";
|
|
39909
|
-
function readBuiltVersion(cwd) {
|
|
39910
|
-
try {
|
|
39911
|
-
const root2 = runGit3(["rev-parse", "--show-toplevel"], cwd);
|
|
39912
|
-
return readPackageJson(join96(root2, "package.json")).version ?? "unknown";
|
|
39913
|
-
} catch {
|
|
39914
|
-
return "unknown";
|
|
39915
|
-
}
|
|
39916
|
-
}
|
|
39917
|
-
|
|
39918
40047
|
// src/commands/watch/readRecentCommits.ts
|
|
39919
40048
|
function readRecentCommits(count8 = 10, cwd) {
|
|
39920
40049
|
const output = runGit3(
|
|
@@ -39962,24 +40091,12 @@ function renderWatchReport({
|
|
|
39962
40091
|
}
|
|
39963
40092
|
|
|
39964
40093
|
// src/commands/watch/restartAdvice.ts
|
|
39965
|
-
var webUiPrefix = "src/commands/sessions/web/ui/";
|
|
39966
|
-
var sessionsPrefix = "src/commands/sessions/";
|
|
39967
|
-
var rules = [
|
|
39968
|
-
{
|
|
39969
|
-
matches: (path106) => path106.startsWith(webUiPrefix),
|
|
39970
|
-
advice: "restart the web server, then hard-reload the browser tab"
|
|
39971
|
-
},
|
|
39972
|
-
{
|
|
39973
|
-
matches: (path106) => path106.startsWith(sessionsPrefix) && !path106.startsWith(webUiPrefix),
|
|
39974
|
-
advice: "restart the daemon"
|
|
39975
|
-
}
|
|
39976
|
-
];
|
|
39977
40094
|
function restartAdvice(paths) {
|
|
39978
|
-
return
|
|
40095
|
+
return restartRules.filter((rule) => paths.some(rule.matches)).map((rule) => rule.advice);
|
|
39979
40096
|
}
|
|
39980
40097
|
|
|
39981
40098
|
// src/commands/watch/syncAdvice.ts
|
|
39982
|
-
var
|
|
40099
|
+
var rules = [
|
|
39983
40100
|
{
|
|
39984
40101
|
matches: (path106) => path106.startsWith("claude/commands/"),
|
|
39985
40102
|
reason: "claude/commands changed"
|
|
@@ -40006,7 +40123,7 @@ var rules2 = [
|
|
|
40006
40123
|
}
|
|
40007
40124
|
];
|
|
40008
40125
|
function syncAdvice(paths) {
|
|
40009
|
-
return
|
|
40126
|
+
return rules.filter((rule) => paths.some(rule.matches)).map((rule) => rule.reason);
|
|
40010
40127
|
}
|
|
40011
40128
|
|
|
40012
40129
|
// src/commands/watch/buildWatchReport.ts
|
|
@@ -40692,7 +40809,7 @@ async function auth() {
|
|
|
40692
40809
|
// src/commands/roam/postRoamActivity.ts
|
|
40693
40810
|
import { execFileSync as execFileSync22 } from "child_process";
|
|
40694
40811
|
import { readdirSync as readdirSync22, readFileSync as readFileSync62, statSync as statSync13 } from "fs";
|
|
40695
|
-
import { join as
|
|
40812
|
+
import { join as join98 } from "path";
|
|
40696
40813
|
function findPortFile(roamDir) {
|
|
40697
40814
|
let entries;
|
|
40698
40815
|
try {
|
|
@@ -40701,7 +40818,7 @@ function findPortFile(roamDir) {
|
|
|
40701
40818
|
return void 0;
|
|
40702
40819
|
}
|
|
40703
40820
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
40704
|
-
const path106 =
|
|
40821
|
+
const path106 = join98(roamDir, name);
|
|
40705
40822
|
try {
|
|
40706
40823
|
return { path: path106, mtimeMs: statSync13(path106).mtimeMs };
|
|
40707
40824
|
} catch {
|
|
@@ -40718,7 +40835,7 @@ var PID_BY_APP = {
|
|
|
40718
40835
|
function postRoamActivity(app, event) {
|
|
40719
40836
|
const appData = process.env.APPDATA;
|
|
40720
40837
|
if (!appData) return;
|
|
40721
|
-
const portFile = findPortFile(
|
|
40838
|
+
const portFile = findPortFile(join98(appData, "Roam"));
|
|
40722
40839
|
if (!portFile) return;
|
|
40723
40840
|
let port;
|
|
40724
40841
|
try {
|
|
@@ -40854,7 +40971,7 @@ async function run3(name, args) {
|
|
|
40854
40971
|
|
|
40855
40972
|
// src/commands/run/add.ts
|
|
40856
40973
|
import { mkdirSync as mkdirSync33, writeFileSync as writeFileSync53 } from "fs";
|
|
40857
|
-
import { join as
|
|
40974
|
+
import { join as join99 } from "path";
|
|
40858
40975
|
|
|
40859
40976
|
// src/commands/run/extractOption.ts
|
|
40860
40977
|
function extractOption(args, flag) {
|
|
@@ -40915,7 +41032,7 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
40915
41032
|
saveConfig(config);
|
|
40916
41033
|
}
|
|
40917
41034
|
function createCommandFile(name) {
|
|
40918
|
-
const dir =
|
|
41035
|
+
const dir = join99(".claude", "commands");
|
|
40919
41036
|
mkdirSync33(dir, { recursive: true });
|
|
40920
41037
|
const content = `---
|
|
40921
41038
|
description: Run ${name}
|
|
@@ -40923,7 +41040,7 @@ description: Run ${name}
|
|
|
40923
41040
|
|
|
40924
41041
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
40925
41042
|
`;
|
|
40926
|
-
const filePath =
|
|
41043
|
+
const filePath = join99(dir, `${name}.md`);
|
|
40927
41044
|
writeFileSync53(filePath, content);
|
|
40928
41045
|
console.log(`Created command file: ${filePath}`);
|
|
40929
41046
|
}
|
|
@@ -40980,7 +41097,7 @@ function link2() {
|
|
|
40980
41097
|
|
|
40981
41098
|
// src/commands/run/remove.ts
|
|
40982
41099
|
import { existsSync as existsSync82, unlinkSync as unlinkSync21 } from "fs";
|
|
40983
|
-
import { join as
|
|
41100
|
+
import { join as join100 } from "path";
|
|
40984
41101
|
function findRemoveIndex() {
|
|
40985
41102
|
const idx = process.argv.indexOf("remove");
|
|
40986
41103
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -40995,7 +41112,7 @@ function parseRemoveName() {
|
|
|
40995
41112
|
return process.argv[idx + 1];
|
|
40996
41113
|
}
|
|
40997
41114
|
function deleteCommandFile(name) {
|
|
40998
|
-
const filePath =
|
|
41115
|
+
const filePath = join100(".claude", "commands", `${name}.md`);
|
|
40999
41116
|
if (existsSync82(filePath)) {
|
|
41000
41117
|
unlinkSync21(filePath);
|
|
41001
41118
|
console.log(`Deleted command file: ${filePath}`);
|
|
@@ -41405,7 +41522,6 @@ function toSessionInfo(session) {
|
|
|
41405
41522
|
autoRun,
|
|
41406
41523
|
autoAdvance,
|
|
41407
41524
|
starred,
|
|
41408
|
-
watcher,
|
|
41409
41525
|
design,
|
|
41410
41526
|
verifying,
|
|
41411
41527
|
pendingPrPreview,
|
|
@@ -41432,7 +41548,6 @@ function toSessionInfo(session) {
|
|
|
41432
41548
|
autoRun,
|
|
41433
41549
|
autoAdvance,
|
|
41434
41550
|
starred,
|
|
41435
|
-
watcher,
|
|
41436
41551
|
design,
|
|
41437
41552
|
verifying,
|
|
41438
41553
|
pendingPrPreview,
|
|
@@ -41988,6 +42103,376 @@ function createRunSession(id, { runName, runArgs, cwd, meta }) {
|
|
|
41988
42103
|
};
|
|
41989
42104
|
}
|
|
41990
42105
|
|
|
42106
|
+
// src/commands/sessions/daemon/autoUpdate/autoUpdateEnabled.ts
|
|
42107
|
+
function autoUpdateEnabled(installDir) {
|
|
42108
|
+
try {
|
|
42109
|
+
return loadConfigFrom(installDir).autoUpdate?.enabled ?? true;
|
|
42110
|
+
} catch (error) {
|
|
42111
|
+
daemonLog(
|
|
42112
|
+
`auto-update: config failed to load, keeping the default (on): ${error instanceof Error ? error.message : String(error)}`
|
|
42113
|
+
);
|
|
42114
|
+
return true;
|
|
42115
|
+
}
|
|
42116
|
+
}
|
|
42117
|
+
|
|
42118
|
+
// src/commands/sessions/daemon/autoUpdate/autoUpdateState.ts
|
|
42119
|
+
var loop = {
|
|
42120
|
+
phase: "off",
|
|
42121
|
+
since: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42122
|
+
reason: "not started"
|
|
42123
|
+
};
|
|
42124
|
+
var startCommit;
|
|
42125
|
+
var autoUpdateState = {
|
|
42126
|
+
loop: () => loop,
|
|
42127
|
+
startCommit: () => startCommit,
|
|
42128
|
+
setStartCommit: (commit2) => {
|
|
42129
|
+
startCommit = commit2;
|
|
42130
|
+
},
|
|
42131
|
+
enter: (phase, extra = {}) => {
|
|
42132
|
+
loop = { phase, since: (/* @__PURE__ */ new Date()).toISOString(), ...extra };
|
|
42133
|
+
}
|
|
42134
|
+
};
|
|
42135
|
+
|
|
42136
|
+
// src/commands/sessions/daemon/autoUpdate/holdForEscalation.ts
|
|
42137
|
+
var ESCALATION_POLL_MS = 5e3;
|
|
42138
|
+
async function holdForEscalation(sessionId, deps2) {
|
|
42139
|
+
deps2.enter("diverged", { escalationId: sessionId });
|
|
42140
|
+
deps2.note(`paused while session ${sessionId} reconciles the divergence`);
|
|
42141
|
+
while (deps2.isLive(sessionId)) await deps2.sleep(ESCALATION_POLL_MS);
|
|
42142
|
+
deps2.note(`session ${sessionId} ended; resuming`);
|
|
42143
|
+
}
|
|
42144
|
+
|
|
42145
|
+
// src/commands/sessions/daemon/autoUpdate/runLapCapturingTail.ts
|
|
42146
|
+
var OUTPUT_TAIL = 16 * 1024;
|
|
42147
|
+
async function runLapCapturingTail(deps2) {
|
|
42148
|
+
let tail = "";
|
|
42149
|
+
const end = await deps2.runLap((text17) => {
|
|
42150
|
+
tail = (tail + text17).slice(-OUTPUT_TAIL);
|
|
42151
|
+
deps2.record(text17);
|
|
42152
|
+
});
|
|
42153
|
+
return { end, tail };
|
|
42154
|
+
}
|
|
42155
|
+
|
|
42156
|
+
// src/commands/sessions/daemon/autoUpdate/runAutoUpdateLoop.ts
|
|
42157
|
+
var DIVERGED_EXIT_CODE = 3;
|
|
42158
|
+
var RETRY_AFTER_FAILURE_MS = 5 * 60 * 1e3;
|
|
42159
|
+
async function runAutoUpdateLoop(deps2, maxLaps = Number.POSITIVE_INFINITY) {
|
|
42160
|
+
let held = deps2.liveEscalation();
|
|
42161
|
+
for (let lap = 1; lap <= maxLaps; lap++) {
|
|
42162
|
+
if (held) await holdForEscalation(held, deps2);
|
|
42163
|
+
held = void 0;
|
|
42164
|
+
deps2.enter("waiting");
|
|
42165
|
+
deps2.note(
|
|
42166
|
+
`lap ${lap} at ${(/* @__PURE__ */ new Date()).toLocaleString()}: assist ${WATCH_LAP_ARGS.join(" ")}`
|
|
42167
|
+
);
|
|
42168
|
+
let result;
|
|
42169
|
+
try {
|
|
42170
|
+
result = await runLapCapturingTail(deps2);
|
|
42171
|
+
} catch (error) {
|
|
42172
|
+
await backOff(
|
|
42173
|
+
`lap ${lap} could not start (${error instanceof Error ? error.message : String(error)})`,
|
|
42174
|
+
deps2
|
|
42175
|
+
);
|
|
42176
|
+
continue;
|
|
42177
|
+
}
|
|
42178
|
+
const { end, tail } = result;
|
|
42179
|
+
const how = end.signal ? `killed by ${end.signal}` : `exited ${end.code}`;
|
|
42180
|
+
if (end.code === DIVERGED_EXIT_CODE) {
|
|
42181
|
+
held = deps2.escalate(tail);
|
|
42182
|
+
deps2.note(`lap ${lap} ${how} (divergence); escalated to session ${held}`);
|
|
42183
|
+
continue;
|
|
42184
|
+
}
|
|
42185
|
+
if (decideLap(end, false).kind === "relaunch") {
|
|
42186
|
+
deps2.note(`lap ${lap} ${how}; relaunching`);
|
|
42187
|
+
continue;
|
|
42188
|
+
}
|
|
42189
|
+
await backOff(`lap ${lap} ${how}`, deps2);
|
|
42190
|
+
}
|
|
42191
|
+
}
|
|
42192
|
+
async function backOff(reason4, deps2) {
|
|
42193
|
+
deps2.enter("retrying", { reason: reason4 });
|
|
42194
|
+
deps2.note(`${reason4}; retrying in ${RETRY_AFTER_FAILURE_MS / 6e4}m`);
|
|
42195
|
+
await deps2.sleep(RETRY_AFTER_FAILURE_MS);
|
|
42196
|
+
}
|
|
42197
|
+
|
|
42198
|
+
// src/commands/sessions/daemon/autoUpdate/trimWatcherLog.ts
|
|
42199
|
+
import { readFileSync as readFileSync65, writeFileSync as writeFileSync54 } from "fs";
|
|
42200
|
+
var KEEP_TAIL = 256 * 1024;
|
|
42201
|
+
var MAX_LOG_SIZE = 4 * 1024 * 1024;
|
|
42202
|
+
function trimWatcherLog(cwd) {
|
|
42203
|
+
const path106 = watcherLogPath(cwd);
|
|
42204
|
+
let log2;
|
|
42205
|
+
try {
|
|
42206
|
+
log2 = readFileSync65(path106, "utf8");
|
|
42207
|
+
} catch {
|
|
42208
|
+
return;
|
|
42209
|
+
}
|
|
42210
|
+
if (log2.length <= MAX_LOG_SIZE) return;
|
|
42211
|
+
writeFileSync54(path106, log2.slice(-KEEP_TAIL));
|
|
42212
|
+
daemonLog(`auto-update: log ${path106} trimmed to its last ${KEEP_TAIL} chars`);
|
|
42213
|
+
}
|
|
42214
|
+
|
|
42215
|
+
// src/commands/sessions/daemon/autoUpdate/loopDeps.ts
|
|
42216
|
+
import { setTimeout as sleep2 } from "timers/promises";
|
|
42217
|
+
|
|
42218
|
+
// src/commands/sessions/daemon/watcherNote.ts
|
|
42219
|
+
function watcherNote(text17) {
|
|
42220
|
+
return `\r
|
|
42221
|
+
\x1B[2m\u2500\u2500 ${text17} \u2500\u2500\x1B[0m\r
|
|
42222
|
+
`;
|
|
42223
|
+
}
|
|
42224
|
+
|
|
42225
|
+
// src/commands/sessions/daemon/worktree/appendWatcherLog.ts
|
|
42226
|
+
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync34 } from "fs";
|
|
42227
|
+
import { dirname as dirname42 } from "path";
|
|
42228
|
+
function appendWatcherLog(cwd, data) {
|
|
42229
|
+
try {
|
|
42230
|
+
const path106 = watcherLogPath(cwd);
|
|
42231
|
+
mkdirSync34(dirname42(path106), { recursive: true });
|
|
42232
|
+
appendFileSync3(path106, data);
|
|
42233
|
+
} catch {
|
|
42234
|
+
}
|
|
42235
|
+
}
|
|
42236
|
+
|
|
42237
|
+
// src/commands/sessions/daemon/worktree/detectExistingWorktree.ts
|
|
42238
|
+
function detectExistingWorktree(cwd) {
|
|
42239
|
+
const repoRoot2 = findRepoRoot(cwd) ?? cwd;
|
|
42240
|
+
if (!worktreeConfigFor(repoRoot2).enabled) return void 0;
|
|
42241
|
+
const clone = mainWorktree(repoRoot2);
|
|
42242
|
+
if (clone && clone !== repoRoot2) return { path: repoRoot2, clone };
|
|
42243
|
+
return void 0;
|
|
42244
|
+
}
|
|
42245
|
+
|
|
42246
|
+
// src/commands/sessions/daemon/worktree/bindNewWorktree.ts
|
|
42247
|
+
function bindNewWorktree(session, alloc, notify2, startHeld = () => {
|
|
42248
|
+
}) {
|
|
42249
|
+
if (alloc.kind !== "worktree" || !alloc.cwd || !alloc.clone || !session)
|
|
42250
|
+
return;
|
|
42251
|
+
session.worktree = { path: alloc.cwd, clone: alloc.clone };
|
|
42252
|
+
if (alloc.created)
|
|
42253
|
+
seedWorktree(alloc.cwd, alloc.clone, () => startHeld(session));
|
|
42254
|
+
notify2();
|
|
42255
|
+
}
|
|
42256
|
+
function bindRestoredWorktrees(sessions) {
|
|
42257
|
+
for (const session of sessions.values()) {
|
|
42258
|
+
if (session.worktree || !session.cwd) continue;
|
|
42259
|
+
const worktree = detectExistingWorktree(session.cwd);
|
|
42260
|
+
if (worktree) session.worktree = worktree;
|
|
42261
|
+
}
|
|
42262
|
+
}
|
|
42263
|
+
function bindResumedWorktree(session, cwd, notify2) {
|
|
42264
|
+
if (!session) return;
|
|
42265
|
+
const worktree = detectExistingWorktree(cwd);
|
|
42266
|
+
if (!worktree) return;
|
|
42267
|
+
session.worktree = worktree;
|
|
42268
|
+
notify2();
|
|
42269
|
+
}
|
|
42270
|
+
|
|
42271
|
+
// src/commands/sessions/daemon/worktree/boundTreeRoots.ts
|
|
42272
|
+
function boundTreeRoots(sessions, exclude) {
|
|
42273
|
+
const roots = /* @__PURE__ */ new Set();
|
|
42274
|
+
for (const session of sessions.values()) {
|
|
42275
|
+
if (session === exclude) continue;
|
|
42276
|
+
const root2 = treeRootOf(session);
|
|
42277
|
+
if (root2 && !roots.has(root2) && holdsTree(session, root2)) roots.add(root2);
|
|
42278
|
+
}
|
|
42279
|
+
return roots;
|
|
42280
|
+
}
|
|
42281
|
+
function treeRootOf(session) {
|
|
42282
|
+
if (!session.cwd) return void 0;
|
|
42283
|
+
return canonicalTreePath(findRepoRoot(session.cwd) ?? session.cwd);
|
|
42284
|
+
}
|
|
42285
|
+
function holdsTree(session, root2) {
|
|
42286
|
+
if (session.closing) return true;
|
|
42287
|
+
if (session.status !== "done" && session.status !== "error") return true;
|
|
42288
|
+
if (!worktreeConfigFor(root2).enabled) return true;
|
|
42289
|
+
const durability = checkDurabilitySync(root2);
|
|
42290
|
+
daemonLog(`tree ${root2} ${releaseReason(durability, session)}`);
|
|
42291
|
+
return !durability.durable;
|
|
42292
|
+
}
|
|
42293
|
+
function releaseReason(durability, session) {
|
|
42294
|
+
if (!durability.durable)
|
|
42295
|
+
return `still held by finished session ${session.id}: ${durability.reason}`;
|
|
42296
|
+
if (durability.gone)
|
|
42297
|
+
return `free for allocation: session ${session.id}'s directory is gone from disk \u2014 nothing to land, not landed work`;
|
|
42298
|
+
return `free for allocation: session ${session.id} finished and its work is landed`;
|
|
42299
|
+
}
|
|
42300
|
+
|
|
42301
|
+
// src/commands/sessions/daemon/worktree/allocateAndBind.ts
|
|
42302
|
+
function allocateAndBind(ctx, cwd, create, options2 = {}, context) {
|
|
42303
|
+
const alloc = allocateTree(cwd, boundTreeRoots(ctx.sessions), options2);
|
|
42304
|
+
const needsSeeding = alloc.kind === "worktree" && alloc.created === true;
|
|
42305
|
+
const id = ctx.spawnWith(
|
|
42306
|
+
(sid) => create(sid, alloc.cwd, needsSeeding),
|
|
42307
|
+
context
|
|
42308
|
+
);
|
|
42309
|
+
bindNewWorktree(ctx.sessions.get(id), alloc, ctx.notify, ctx.startHeld);
|
|
42310
|
+
return id;
|
|
42311
|
+
}
|
|
42312
|
+
|
|
42313
|
+
// src/commands/sessions/daemon/worktree/divergencePrompt.ts
|
|
42314
|
+
var MAX_REASON_LINES = 20;
|
|
42315
|
+
var MAX_REASON_CHARS = 2e3;
|
|
42316
|
+
var RECONCILE_STEPS = [
|
|
42317
|
+
"Reconcile it yourself, without discarding any commits on either side:",
|
|
42318
|
+
"",
|
|
42319
|
+
"1. Inspect `git status`, `git log --oneline @{u}..@` and `git log --oneline @..@{u}`.",
|
|
42320
|
+
'2. Stash any uncommitted work with `git stash push -u -m "assist divergence"`, and restore it with `git stash pop` once the branch is reconciled.',
|
|
42321
|
+
"3. Rebase the local commits onto the upstream with `git rebase @{u}`, resolving conflicts so both sides' changes survive. If the rebase cannot be resolved cleanly, `git rebase --abort` and `git merge @{u}` instead.",
|
|
42322
|
+
"4. Push the result with a plain `git push` so the branch matches its upstream again.",
|
|
42323
|
+
"5. Build the clone with `assist run auto-build`.",
|
|
42324
|
+
"6. Run /close. The daemon resumes its auto-update loop once this session closes.",
|
|
42325
|
+
"",
|
|
42326
|
+
"Never force-push, `git reset`, or otherwise discard commits. If you cannot reconcile the branch without doing so, explain what is blocking it and leave this session open for the user instead of closing it."
|
|
42327
|
+
];
|
|
42328
|
+
var SIMULATED_STEPS = [
|
|
42329
|
+
"This divergence was simulated to test the escalation; there is nothing to reconcile. Run /close now. The daemon resumes its auto-update loop once this session closes."
|
|
42330
|
+
];
|
|
42331
|
+
function divergenceReason(scrollback) {
|
|
42332
|
+
return stripAnsi(scrollback).split(/\r?\n|\r/).map((line) => line.trimEnd()).filter((line) => line.trim().length > 0).slice(-MAX_REASON_LINES).join("\n").slice(-MAX_REASON_CHARS);
|
|
42333
|
+
}
|
|
42334
|
+
function divergencePrompt(clone, scrollback) {
|
|
42335
|
+
const reason4 = divergenceReason(scrollback);
|
|
42336
|
+
return [
|
|
42337
|
+
`The daemon's auto-update loop for the assist install in ${clone} paused because \`assist watch wait --pull --build\` could not fast-forward the branch (exit 3). The tail of its output:`,
|
|
42338
|
+
"",
|
|
42339
|
+
"```",
|
|
42340
|
+
reason4 || "(no output captured)",
|
|
42341
|
+
"```",
|
|
42342
|
+
"",
|
|
42343
|
+
...reason4.includes(simulatedDivergenceNote) ? SIMULATED_STEPS : RECONCILE_STEPS
|
|
42344
|
+
].join("\n");
|
|
42345
|
+
}
|
|
42346
|
+
|
|
42347
|
+
// src/commands/sessions/daemon/worktree/liveEscalationIn.ts
|
|
42348
|
+
var ENDED = ["done", "error"];
|
|
42349
|
+
function liveEscalationIn(sessions, clone) {
|
|
42350
|
+
return [...sessions.values()].find(
|
|
42351
|
+
(s) => s.divergenceEscalation === true && s.cwd !== void 0 && canonicalTreePath(s.cwd) === clone && !ENDED.includes(s.status)
|
|
42352
|
+
);
|
|
42353
|
+
}
|
|
42354
|
+
|
|
42355
|
+
// src/commands/sessions/daemon/worktree/escalateDivergence.ts
|
|
42356
|
+
function escalateDivergence(ctx, cwd, output) {
|
|
42357
|
+
const clone = canonicalTreePath(cwd);
|
|
42358
|
+
const live = liveEscalationIn(ctx.sessions, clone);
|
|
42359
|
+
if (live) {
|
|
42360
|
+
daemonLog(
|
|
42361
|
+
`auto-update diverged in the clone ${clone}: no escalation spawned, session ${live.id} is already diagnosing it (${live.status})`
|
|
42362
|
+
);
|
|
42363
|
+
return live.id;
|
|
42364
|
+
}
|
|
42365
|
+
const prompt = divergencePrompt(clone, output);
|
|
42366
|
+
const id = allocateAndBind(
|
|
42367
|
+
ctx,
|
|
42368
|
+
clone,
|
|
42369
|
+
(sid, resolvedCwd) => ({
|
|
42370
|
+
...createSession(sid, { prompt, cwd: resolvedCwd ?? clone }),
|
|
42371
|
+
divergenceEscalation: true
|
|
42372
|
+
}),
|
|
42373
|
+
{ inPlace: true }
|
|
42374
|
+
);
|
|
42375
|
+
daemonLog(
|
|
42376
|
+
`auto-update diverged in the clone ${clone}: spawned escalation session ${id} to diagnose it`
|
|
42377
|
+
);
|
|
42378
|
+
return id;
|
|
42379
|
+
}
|
|
42380
|
+
|
|
42381
|
+
// src/commands/sessions/daemon/autoUpdate/lineRecorder.ts
|
|
42382
|
+
function lineRecorder(onLine) {
|
|
42383
|
+
let pending = "";
|
|
42384
|
+
return (text17) => {
|
|
42385
|
+
const lines2 = (pending + text17).split(/\r?\n|\r/);
|
|
42386
|
+
pending = lines2.pop() ?? "";
|
|
42387
|
+
for (const line of lines2) {
|
|
42388
|
+
const clean2 = stripAnsi(line).trimEnd();
|
|
42389
|
+
if (clean2.trim()) onLine(clean2);
|
|
42390
|
+
}
|
|
42391
|
+
};
|
|
42392
|
+
}
|
|
42393
|
+
|
|
42394
|
+
// src/commands/sessions/daemon/autoUpdate/runUpdateLap.ts
|
|
42395
|
+
import { spawn as spawn11 } from "child_process";
|
|
42396
|
+
function runUpdateLap(cwd, onOutput) {
|
|
42397
|
+
return new Promise((resolve28, reject) => {
|
|
42398
|
+
const { ASSIST_ACTIVITY_ID: _activity, ...env } = process.env;
|
|
42399
|
+
const child = spawn11(
|
|
42400
|
+
process.execPath,
|
|
42401
|
+
[process.argv[1], ...WATCH_LAP_ARGS],
|
|
42402
|
+
{
|
|
42403
|
+
cwd,
|
|
42404
|
+
env,
|
|
42405
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
42406
|
+
windowsHide: true
|
|
42407
|
+
}
|
|
42408
|
+
);
|
|
42409
|
+
const killWithDaemon = () => {
|
|
42410
|
+
child.kill();
|
|
42411
|
+
};
|
|
42412
|
+
process.on("exit", killWithDaemon);
|
|
42413
|
+
child.stdout.on("data", (chunk) => onOutput(chunk.toString()));
|
|
42414
|
+
child.stderr.on("data", (chunk) => onOutput(chunk.toString()));
|
|
42415
|
+
child.on("close", (code, signal) => {
|
|
42416
|
+
process.off("exit", killWithDaemon);
|
|
42417
|
+
resolve28({ code, signal });
|
|
42418
|
+
});
|
|
42419
|
+
child.on("error", (error) => {
|
|
42420
|
+
process.off("exit", killWithDaemon);
|
|
42421
|
+
reject(error);
|
|
42422
|
+
});
|
|
42423
|
+
});
|
|
42424
|
+
}
|
|
42425
|
+
|
|
42426
|
+
// src/commands/sessions/daemon/autoUpdate/loopDeps.ts
|
|
42427
|
+
function loopDeps(installDir, ctx) {
|
|
42428
|
+
const clone = canonicalTreePath(installDir);
|
|
42429
|
+
const logLine = lineRecorder((line) => daemonLog(`auto-update: ${line}`));
|
|
42430
|
+
return {
|
|
42431
|
+
runLap: (onOutput) => runUpdateLap(installDir, onOutput),
|
|
42432
|
+
record: (text17) => {
|
|
42433
|
+
appendWatcherLog(installDir, text17);
|
|
42434
|
+
logLine(text17);
|
|
42435
|
+
},
|
|
42436
|
+
note: (text17) => {
|
|
42437
|
+
appendWatcherLog(installDir, watcherNote(text17));
|
|
42438
|
+
daemonLog(`auto-update: ${text17}`);
|
|
42439
|
+
},
|
|
42440
|
+
enter: autoUpdateState.enter,
|
|
42441
|
+
liveEscalation: () => liveEscalationIn(ctx().sessions, clone)?.id,
|
|
42442
|
+
escalate: (output) => escalateDivergence(ctx(), installDir, output),
|
|
42443
|
+
isLive: (sessionId) => {
|
|
42444
|
+
const status2 = ctx().sessions.get(sessionId)?.status;
|
|
42445
|
+
return status2 !== void 0 && status2 !== "done" && status2 !== "error";
|
|
42446
|
+
},
|
|
42447
|
+
sleep: (ms) => sleep2(ms)
|
|
42448
|
+
};
|
|
42449
|
+
}
|
|
42450
|
+
|
|
42451
|
+
// src/commands/sessions/daemon/autoUpdate/startAutoUpdate.ts
|
|
42452
|
+
function stayOff(reason4) {
|
|
42453
|
+
autoUpdateState.enter("off", { reason: reason4 });
|
|
42454
|
+
daemonLog(`auto-update: off (${reason4})`);
|
|
42455
|
+
}
|
|
42456
|
+
function startAutoUpdate(ctx) {
|
|
42457
|
+
const installDir = getInstallDir();
|
|
42458
|
+
if (!isGitRepo(installDir)) {
|
|
42459
|
+
stayOff(`${installDir} is not a git clone`);
|
|
42460
|
+
return;
|
|
42461
|
+
}
|
|
42462
|
+
autoUpdateState.setStartCommit(headCommit3(installDir));
|
|
42463
|
+
if (!autoUpdateEnabled(installDir)) {
|
|
42464
|
+
stayOff("autoUpdate.enabled is false");
|
|
42465
|
+
return;
|
|
42466
|
+
}
|
|
42467
|
+
trimWatcherLog(installDir);
|
|
42468
|
+
daemonLog(`auto-update: pulling and building ${installDir} as origin moves`);
|
|
42469
|
+
void runAutoUpdateLoop(loopDeps(installDir, ctx)).catch(
|
|
42470
|
+
(error) => daemonLog(
|
|
42471
|
+
`auto-update: loop stopped: ${error instanceof Error ? error.message : String(error)}`
|
|
42472
|
+
)
|
|
42473
|
+
);
|
|
42474
|
+
}
|
|
42475
|
+
|
|
41991
42476
|
// src/commands/sessions/daemon/setStatus.ts
|
|
41992
42477
|
function setStatus2(session, newStatus) {
|
|
41993
42478
|
const now = Date.now();
|
|
@@ -42010,16 +42495,16 @@ function setStatus2(session, newStatus) {
|
|
|
42010
42495
|
|
|
42011
42496
|
// src/commands/sessions/daemon/worktree/reapWorktree.ts
|
|
42012
42497
|
import { existsSync as existsSync87 } from "fs";
|
|
42013
|
-
import { basename as
|
|
42498
|
+
import { basename as basename29 } from "path";
|
|
42014
42499
|
|
|
42015
42500
|
// src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
|
|
42016
42501
|
import { existsSync as existsSync86 } from "fs";
|
|
42017
|
-
import { join as
|
|
42502
|
+
import { join as join103 } from "path";
|
|
42018
42503
|
|
|
42019
42504
|
// src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
|
|
42020
42505
|
import { statSync as statSync15 } from "fs";
|
|
42021
42506
|
import { rm as rm3 } from "fs/promises";
|
|
42022
|
-
import { join as
|
|
42507
|
+
import { join as join102 } from "path";
|
|
42023
42508
|
async function deleteTreeDirectly(clone, worktreePath, why) {
|
|
42024
42509
|
if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
|
|
42025
42510
|
const refusal = "it is a clone of its own, not a linked worktree";
|
|
@@ -42047,7 +42532,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
|
|
|
42047
42532
|
return { removed: true };
|
|
42048
42533
|
}
|
|
42049
42534
|
function holdsAGitDirectoryRatherThanALink(worktreePath) {
|
|
42050
|
-
return statSync15(
|
|
42535
|
+
return statSync15(join102(worktreePath, ".git"), {
|
|
42051
42536
|
throwIfNoEntry: false
|
|
42052
42537
|
})?.isDirectory() === true;
|
|
42053
42538
|
}
|
|
@@ -42083,7 +42568,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
|
|
|
42083
42568
|
);
|
|
42084
42569
|
}
|
|
42085
42570
|
function strandedReason(worktreePath, cause) {
|
|
42086
|
-
if (!existsSync86(
|
|
42571
|
+
if (!existsSync86(join103(worktreePath, ".git")))
|
|
42087
42572
|
return "its .git link is already gone";
|
|
42088
42573
|
if (/not a working tree|not a git repository/i.test(reason2(cause)))
|
|
42089
42574
|
return "git no longer recognises it as a working tree";
|
|
@@ -42153,7 +42638,7 @@ async function reapWorktree(worktreePath, force = false) {
|
|
|
42153
42638
|
const clone = owningClone(worktreePath);
|
|
42154
42639
|
const removal = await removeTree(clone, worktreePath, force);
|
|
42155
42640
|
if (!removal.removed) return removal;
|
|
42156
|
-
await deleteWorktreeBranch(clone,
|
|
42641
|
+
await deleteWorktreeBranch(clone, basename29(worktreePath));
|
|
42157
42642
|
forgetWorktree(worktreePath);
|
|
42158
42643
|
daemonLog(`worktree ${worktreePath} reaped${force ? " (forced)" : ""}`);
|
|
42159
42644
|
return removal;
|
|
@@ -42227,34 +42712,6 @@ function killPtyTree(pty2) {
|
|
|
42227
42712
|
}
|
|
42228
42713
|
}
|
|
42229
42714
|
|
|
42230
|
-
// src/commands/sessions/daemon/worktree/liveWatcherFor.ts
|
|
42231
|
-
function liveWatcherFor(sessions, clone) {
|
|
42232
|
-
for (const session of sessions.values())
|
|
42233
|
-
if (session.watcher === true && session.cwd !== void 0 && (clone === void 0 || canonicalTreePath(session.cwd) === clone) && session.status !== "stopped" && session.status !== "error")
|
|
42234
|
-
return session;
|
|
42235
|
-
return void 0;
|
|
42236
|
-
}
|
|
42237
|
-
|
|
42238
|
-
// src/commands/sessions/daemon/worktree/resolveClone.ts
|
|
42239
|
-
function resolveClone(cwd) {
|
|
42240
|
-
const repoRoot2 = findRepoRoot(cwd) ?? cwd;
|
|
42241
|
-
return canonicalTreePath(mainWorktree(repoRoot2) ?? repoRoot2);
|
|
42242
|
-
}
|
|
42243
|
-
|
|
42244
|
-
// src/commands/sessions/daemon/worktree/orphanedWatcherFor.ts
|
|
42245
|
-
function orphanedWatcherFor(sessions, dismissed) {
|
|
42246
|
-
if (dismissed.watcher === true || !dismissed.cwd) return void 0;
|
|
42247
|
-
if (!liveWatcherFor(sessions)) return void 0;
|
|
42248
|
-
const known = dismissed.worktree?.clone ?? dismissed.releasedFromClone;
|
|
42249
|
-
const clone = known ? canonicalTreePath(known) : resolveClone(dismissed.cwd);
|
|
42250
|
-
const watcher = liveWatcherFor(sessions, clone);
|
|
42251
|
-
if (!watcher) return void 0;
|
|
42252
|
-
const kept = [...sessions.values()].some(
|
|
42253
|
-
(s) => s.watcher !== true && s.cwd !== void 0 && resolveClone(s.cwd) === clone
|
|
42254
|
-
);
|
|
42255
|
-
return kept ? void 0 : { watcher, clone };
|
|
42256
|
-
}
|
|
42257
|
-
|
|
42258
42715
|
// src/commands/sessions/daemon/worktree/treeUnderClose.ts
|
|
42259
42716
|
function treeUnderClose(session) {
|
|
42260
42717
|
if (session.worktree) return { path: session.worktree.path, removable: true };
|
|
@@ -42285,13 +42742,6 @@ function dismissSession(sessions, id) {
|
|
|
42285
42742
|
if (s.activity?.itemId != null) releaseLock(s.activity.itemId);
|
|
42286
42743
|
sessions.delete(id);
|
|
42287
42744
|
daemonLog(`session ${id} dismissed (${s.name})`);
|
|
42288
|
-
const orphan = orphanedWatcherFor(sessions, s);
|
|
42289
|
-
if (orphan) {
|
|
42290
|
-
daemonLog(
|
|
42291
|
-
`reaping watcher session ${orphan.watcher.id} for the clone ${orphan.clone}: its last session ${id} was dismissed`
|
|
42292
|
-
);
|
|
42293
|
-
dismissSession(sessions, orphan.watcher.id);
|
|
42294
|
-
}
|
|
42295
42745
|
if (!s.worktree) return true;
|
|
42296
42746
|
if (sharedWith.length > 0)
|
|
42297
42747
|
daemonLog(
|
|
@@ -42526,43 +42976,6 @@ function dismissSessionGated(sessions, id, notify2, discard = false) {
|
|
|
42526
42976
|
settle();
|
|
42527
42977
|
}
|
|
42528
42978
|
|
|
42529
|
-
// src/commands/sessions/daemon/worktree/resumeWatcherAfterEscalation.ts
|
|
42530
|
-
var ENDED = ["done", "error"];
|
|
42531
|
-
var endedViaDismissOrExit = /* @__PURE__ */ new WeakSet();
|
|
42532
|
-
function resumeWatcherAfterEscalation(sessions, escalation, restart) {
|
|
42533
|
-
if (escalation.divergenceEscalation !== true || !escalation.cwd) return;
|
|
42534
|
-
if (endedViaDismissOrExit.has(escalation)) return;
|
|
42535
|
-
endedViaDismissOrExit.add(escalation);
|
|
42536
|
-
const clone = canonicalTreePath(escalation.cwd);
|
|
42537
|
-
const watcher = [...sessions.values()].find(
|
|
42538
|
-
(s) => s.watcher === true && s.cwd !== void 0 && canonicalTreePath(s.cwd) === clone
|
|
42539
|
-
);
|
|
42540
|
-
if (!watcher) {
|
|
42541
|
-
daemonLog(
|
|
42542
|
-
`escalation session ${escalation.id} ended: no watcher left in the clone ${clone} to restart`
|
|
42543
|
-
);
|
|
42544
|
-
return;
|
|
42545
|
-
}
|
|
42546
|
-
if (!ENDED.includes(watcher.status)) {
|
|
42547
|
-
daemonLog(
|
|
42548
|
-
`escalation session ${escalation.id} ended: watcher session ${watcher.id} in the clone ${clone} is already ${watcher.status}`
|
|
42549
|
-
);
|
|
42550
|
-
return;
|
|
42551
|
-
}
|
|
42552
|
-
daemonLog(
|
|
42553
|
-
`escalation session ${escalation.id} ended: restarting watcher session ${watcher.id} in the clone ${clone}`
|
|
42554
|
-
);
|
|
42555
|
-
watcher.watcherRestartReason = `after escalation session ${escalation.id} ended`;
|
|
42556
|
-
restart(watcher.id);
|
|
42557
|
-
}
|
|
42558
|
-
|
|
42559
|
-
// src/commands/sessions/daemon/dismissAndResumeWatcher.ts
|
|
42560
|
-
function dismissAndResumeWatcher(sessions, id, notify2, restart) {
|
|
42561
|
-
const session = sessions.get(id);
|
|
42562
|
-
dismissSessionGated(sessions, id, notify2);
|
|
42563
|
-
if (session) resumeWatcherAfterEscalation(sessions, session, restart);
|
|
42564
|
-
}
|
|
42565
|
-
|
|
42566
42979
|
// src/commands/sessions/daemon/drainSessions.ts
|
|
42567
42980
|
function drainSessions(sessions, notify2) {
|
|
42568
42981
|
const drained = [...sessions.values()].map((s) => ({
|
|
@@ -42976,37 +43389,10 @@ function startSessionTitleGeneration(session, notify2) {
|
|
|
42976
43389
|
runSessionTitleGeneration(session, prompt, notify2, singleLineTitle(prompt));
|
|
42977
43390
|
}
|
|
42978
43391
|
|
|
42979
|
-
// src/commands/sessions/daemon/worktree/appendWatcherLog.ts
|
|
42980
|
-
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync34 } from "fs";
|
|
42981
|
-
import { dirname as dirname42 } from "path";
|
|
42982
|
-
|
|
42983
|
-
// src/commands/sessions/daemon/worktree/watcherLogPath.ts
|
|
42984
|
-
import { createHash as createHash4 } from "crypto";
|
|
42985
|
-
import { homedir as homedir26 } from "os";
|
|
42986
|
-
import { basename as basename29, join as join103 } from "path";
|
|
42987
|
-
function watcherLogPath(cwd) {
|
|
42988
|
-
const clone = canonicalTreePath(cwd);
|
|
42989
|
-
const key = createHash4("sha1").update(clone).digest("hex").slice(0, 8);
|
|
42990
|
-
const dir = process.env.ASSIST_WATCHER_LOG_DIR ?? join103(homedir26(), ".assist", "watchers");
|
|
42991
|
-
return join103(dir, `${basename29(clone) || "root"}-${key}.log`);
|
|
42992
|
-
}
|
|
42993
|
-
|
|
42994
|
-
// src/commands/sessions/daemon/worktree/appendWatcherLog.ts
|
|
42995
|
-
function appendWatcherLog(session, data) {
|
|
42996
|
-
if (session.watcher !== true || !session.cwd) return;
|
|
42997
|
-
try {
|
|
42998
|
-
const path106 = watcherLogPath(session.cwd);
|
|
42999
|
-
mkdirSync34(dirname42(path106), { recursive: true });
|
|
43000
|
-
appendFileSync3(path106, data);
|
|
43001
|
-
} catch {
|
|
43002
|
-
}
|
|
43003
|
-
}
|
|
43004
|
-
|
|
43005
43392
|
// src/commands/sessions/daemon/emitSessionOutput.ts
|
|
43006
43393
|
var MAX_SCROLLBACK = 256 * 1024;
|
|
43007
43394
|
function emitSessionOutput(session, clients, data) {
|
|
43008
43395
|
session.scrollback += data;
|
|
43009
|
-
appendWatcherLog(session, data);
|
|
43010
43396
|
if (session.scrollback.length > MAX_SCROLLBACK) {
|
|
43011
43397
|
session.scrollback = session.scrollback.slice(-MAX_SCROLLBACK);
|
|
43012
43398
|
}
|
|
@@ -44077,13 +44463,6 @@ function applyUsageRecord(sessions, windows, notify2, claudeSessionId, transcrip
|
|
|
44077
44463
|
notify2();
|
|
44078
44464
|
}
|
|
44079
44465
|
|
|
44080
|
-
// src/commands/sessions/daemon/watcherNote.ts
|
|
44081
|
-
function watcherNote(text17) {
|
|
44082
|
-
return `\r
|
|
44083
|
-
\x1B[2m\u2500\u2500 ${text17} \u2500\u2500\x1B[0m\r
|
|
44084
|
-
`;
|
|
44085
|
-
}
|
|
44086
|
-
|
|
44087
44466
|
// src/commands/sessions/daemon/shouldAutoRun.ts
|
|
44088
44467
|
function shouldAutoRun(session, status2 = session.status) {
|
|
44089
44468
|
if (!session.autoRun) return { run: false, reason: null };
|
|
@@ -44138,7 +44517,6 @@ function shouldAutoDismiss(session, exitCode) {
|
|
|
44138
44517
|
}
|
|
44139
44518
|
|
|
44140
44519
|
// src/commands/sessions/daemon/finishStatusChange.ts
|
|
44141
|
-
var DIVERGED_EXIT_CODE = 3;
|
|
44142
44520
|
function finishStatusChange(session, status2, exitCode, deps2) {
|
|
44143
44521
|
daemonLog(`session ${session.id} status: ${session.status} -> ${status2}`);
|
|
44144
44522
|
void flushPhaseActiveMs(session);
|
|
@@ -44146,9 +44524,6 @@ function finishStatusChange(session, status2, exitCode, deps2) {
|
|
|
44146
44524
|
if (status2 === "waiting")
|
|
44147
44525
|
startTranscriptTitleGeneration(session, deps2.notify);
|
|
44148
44526
|
if (status2 !== "stopped") session.undurable = void 0;
|
|
44149
|
-
if (session.watcher === true && exitCode === DIVERGED_EXIT_CODE)
|
|
44150
|
-
deps2.escalateDivergence?.(session);
|
|
44151
|
-
if (status2 === "done" || status2 === "error") deps2.resumeWatcher?.(session);
|
|
44152
44527
|
const autoRun = shouldAutoRun(session);
|
|
44153
44528
|
if (autoRun.run) {
|
|
44154
44529
|
deps2.reuseForRun(session, autoRun.itemId);
|
|
@@ -44194,40 +44569,6 @@ function makeStatusChangeHandler(sessions, deps2) {
|
|
|
44194
44569
|
);
|
|
44195
44570
|
}
|
|
44196
44571
|
|
|
44197
|
-
// src/commands/sessions/daemon/worktree/detectExistingWorktree.ts
|
|
44198
|
-
function detectExistingWorktree(cwd) {
|
|
44199
|
-
const repoRoot2 = findRepoRoot(cwd) ?? cwd;
|
|
44200
|
-
if (!worktreeConfigFor(repoRoot2).enabled) return void 0;
|
|
44201
|
-
const clone = mainWorktree(repoRoot2);
|
|
44202
|
-
if (clone && clone !== repoRoot2) return { path: repoRoot2, clone };
|
|
44203
|
-
return void 0;
|
|
44204
|
-
}
|
|
44205
|
-
|
|
44206
|
-
// src/commands/sessions/daemon/worktree/bindNewWorktree.ts
|
|
44207
|
-
function bindNewWorktree(session, alloc, notify2, startHeld = () => {
|
|
44208
|
-
}) {
|
|
44209
|
-
if (alloc.kind !== "worktree" || !alloc.cwd || !alloc.clone || !session)
|
|
44210
|
-
return;
|
|
44211
|
-
session.worktree = { path: alloc.cwd, clone: alloc.clone };
|
|
44212
|
-
if (alloc.created)
|
|
44213
|
-
seedWorktree(alloc.cwd, alloc.clone, () => startHeld(session));
|
|
44214
|
-
notify2();
|
|
44215
|
-
}
|
|
44216
|
-
function bindRestoredWorktrees(sessions) {
|
|
44217
|
-
for (const session of sessions.values()) {
|
|
44218
|
-
if (session.worktree || !session.cwd) continue;
|
|
44219
|
-
const worktree = detectExistingWorktree(session.cwd);
|
|
44220
|
-
if (worktree) session.worktree = worktree;
|
|
44221
|
-
}
|
|
44222
|
-
}
|
|
44223
|
-
function bindResumedWorktree(session, cwd, notify2) {
|
|
44224
|
-
if (!session) return;
|
|
44225
|
-
const worktree = detectExistingWorktree(cwd);
|
|
44226
|
-
if (!worktree) return;
|
|
44227
|
-
session.worktree = worktree;
|
|
44228
|
-
notify2();
|
|
44229
|
-
}
|
|
44230
|
-
|
|
44231
44572
|
// src/commands/sessions/daemon/attachReusedRun.ts
|
|
44232
44573
|
function attachReusedRun(session, alloc, clients, onStatusChange, tree) {
|
|
44233
44574
|
broadcast(clients, { type: "clear", sessionId: session.id });
|
|
@@ -44306,137 +44647,6 @@ function startReusedRunPty(session, assistArgs, itemId2, hold, clients, onStatus
|
|
|
44306
44647
|
return true;
|
|
44307
44648
|
}
|
|
44308
44649
|
|
|
44309
|
-
// src/commands/sessions/daemon/createAssistSession.ts
|
|
44310
|
-
function createAssistSession(id, assistArgs, cwd, meta, holdPty) {
|
|
44311
|
-
const startedAt = Date.now();
|
|
44312
|
-
return {
|
|
44313
|
-
id,
|
|
44314
|
-
name: `assist ${assistArgs.join(" ")}`,
|
|
44315
|
-
title: meta?.title,
|
|
44316
|
-
subtitle: meta?.subtitle,
|
|
44317
|
-
commandType: "assist",
|
|
44318
|
-
status: "running",
|
|
44319
|
-
startedAt,
|
|
44320
|
-
runningMs: 0,
|
|
44321
|
-
runningSince: startedAt,
|
|
44322
|
-
waitingSince: null,
|
|
44323
|
-
...startOrHoldPty(
|
|
44324
|
-
() => spawnPty(["assist", ...assistArgs], cwd, id),
|
|
44325
|
-
holdPty
|
|
44326
|
-
),
|
|
44327
|
-
scrollback: "",
|
|
44328
|
-
assistArgs,
|
|
44329
|
-
cwd
|
|
44330
|
-
};
|
|
44331
|
-
}
|
|
44332
|
-
|
|
44333
|
-
// src/commands/sessions/daemon/worktree/seedWatcherScrollback.ts
|
|
44334
|
-
import { readFileSync as readFileSync65, writeFileSync as writeFileSync54 } from "fs";
|
|
44335
|
-
var SCROLLBACK_TAIL = 256 * 1024;
|
|
44336
|
-
var MAX_LOG_SIZE = 4 * 1024 * 1024;
|
|
44337
|
-
function readLogTail2(path106) {
|
|
44338
|
-
let log2;
|
|
44339
|
-
try {
|
|
44340
|
-
log2 = readFileSync65(path106, "utf8");
|
|
44341
|
-
} catch {
|
|
44342
|
-
return "";
|
|
44343
|
-
}
|
|
44344
|
-
if (log2.length > MAX_LOG_SIZE) {
|
|
44345
|
-
log2 = log2.slice(-SCROLLBACK_TAIL);
|
|
44346
|
-
writeFileSync54(path106, log2);
|
|
44347
|
-
daemonLog(`watcher log ${path106} trimmed to its last ${log2.length} chars`);
|
|
44348
|
-
}
|
|
44349
|
-
return log2.slice(-SCROLLBACK_TAIL);
|
|
44350
|
-
}
|
|
44351
|
-
function seedWatcherScrollback(cwd, event) {
|
|
44352
|
-
const path106 = watcherLogPath(cwd);
|
|
44353
|
-
const history = readLogTail2(path106);
|
|
44354
|
-
const note = watcherNote(`${event} at ${(/* @__PURE__ */ new Date()).toLocaleString()}`);
|
|
44355
|
-
appendWatcherLog({ watcher: true, cwd }, note);
|
|
44356
|
-
daemonLog(
|
|
44357
|
-
`watcher in ${cwd} seeded with ${history.length} chars of history from ${path106} (${event})`
|
|
44358
|
-
);
|
|
44359
|
-
return history + note;
|
|
44360
|
-
}
|
|
44361
|
-
|
|
44362
|
-
// src/commands/sessions/daemon/createWatcherSession.ts
|
|
44363
|
-
var WATCHER_ARGS = ["watch", "loop"];
|
|
44364
|
-
function createWatcherSession(id, cwd) {
|
|
44365
|
-
return {
|
|
44366
|
-
...createAssistSession(id, WATCHER_ARGS, cwd),
|
|
44367
|
-
watcher: true,
|
|
44368
|
-
scrollback: seedWatcherScrollback(cwd, "watcher started")
|
|
44369
|
-
};
|
|
44370
|
-
}
|
|
44371
|
-
|
|
44372
|
-
// src/commands/sessions/daemon/worktree/boundTreeRoots.ts
|
|
44373
|
-
function boundTreeRoots(sessions, exclude) {
|
|
44374
|
-
const roots = /* @__PURE__ */ new Set();
|
|
44375
|
-
for (const session of sessions.values()) {
|
|
44376
|
-
if (session === exclude) continue;
|
|
44377
|
-
const root2 = treeRootOf(session);
|
|
44378
|
-
if (root2 && !roots.has(root2) && holdsTree(session, root2)) roots.add(root2);
|
|
44379
|
-
}
|
|
44380
|
-
return roots;
|
|
44381
|
-
}
|
|
44382
|
-
function treeRootOf(session) {
|
|
44383
|
-
if (!session.cwd) return void 0;
|
|
44384
|
-
return canonicalTreePath(findRepoRoot(session.cwd) ?? session.cwd);
|
|
44385
|
-
}
|
|
44386
|
-
function holdsTree(session, root2) {
|
|
44387
|
-
if (session.closing) return true;
|
|
44388
|
-
if (session.status !== "done" && session.status !== "error") return true;
|
|
44389
|
-
if (!worktreeConfigFor(root2).enabled) return true;
|
|
44390
|
-
const durability = checkDurabilitySync(root2);
|
|
44391
|
-
daemonLog(`tree ${root2} ${releaseReason(durability, session)}`);
|
|
44392
|
-
return !durability.durable;
|
|
44393
|
-
}
|
|
44394
|
-
function releaseReason(durability, session) {
|
|
44395
|
-
if (!durability.durable)
|
|
44396
|
-
return `still held by finished session ${session.id}: ${durability.reason}`;
|
|
44397
|
-
if (durability.gone)
|
|
44398
|
-
return `free for allocation: session ${session.id}'s directory is gone from disk \u2014 nothing to land, not landed work`;
|
|
44399
|
-
return `free for allocation: session ${session.id} finished and its work is landed`;
|
|
44400
|
-
}
|
|
44401
|
-
|
|
44402
|
-
// src/commands/sessions/daemon/worktree/allocateAndBind.ts
|
|
44403
|
-
function allocateAndBind(ctx, cwd, create, options2 = {}, context) {
|
|
44404
|
-
const alloc = allocateTree(cwd, boundTreeRoots(ctx.sessions), options2);
|
|
44405
|
-
const needsSeeding = alloc.kind === "worktree" && alloc.created === true;
|
|
44406
|
-
const id = ctx.spawnWith(
|
|
44407
|
-
(sid) => create(sid, alloc.cwd, needsSeeding),
|
|
44408
|
-
context
|
|
44409
|
-
);
|
|
44410
|
-
bindNewWorktree(ctx.sessions.get(id), alloc, ctx.notify, ctx.startHeld);
|
|
44411
|
-
return id;
|
|
44412
|
-
}
|
|
44413
|
-
|
|
44414
|
-
// src/commands/sessions/daemon/worktree/ensureWatcher.ts
|
|
44415
|
-
function ensureWatcher(ctx, cwd) {
|
|
44416
|
-
if (!cwd) return void 0;
|
|
44417
|
-
const repoRoot2 = findRepoRoot(cwd) ?? cwd;
|
|
44418
|
-
const cfg = worktreeConfigFor(repoRoot2);
|
|
44419
|
-
if (!cfg.enabled || cfg.watcher !== true) return void 0;
|
|
44420
|
-
const clone = resolveClone(repoRoot2);
|
|
44421
|
-
const live = liveWatcherFor(ctx.sessions, clone);
|
|
44422
|
-
if (live) {
|
|
44423
|
-
daemonLog(
|
|
44424
|
-
`no watcher spawned for the clone ${clone}: session ${live.id} is already watching it (${live.status})`
|
|
44425
|
-
);
|
|
44426
|
-
return void 0;
|
|
44427
|
-
}
|
|
44428
|
-
const id = allocateAndBind(
|
|
44429
|
-
ctx,
|
|
44430
|
-
clone,
|
|
44431
|
-
(sid, resolvedCwd) => createWatcherSession(sid, resolvedCwd ?? clone),
|
|
44432
|
-
{ inPlace: true }
|
|
44433
|
-
);
|
|
44434
|
-
daemonLog(
|
|
44435
|
-
`spawned watcher session ${id} running assist ${WATCHER_ARGS.join(" ")} in the clone ${clone}`
|
|
44436
|
-
);
|
|
44437
|
-
return id;
|
|
44438
|
-
}
|
|
44439
|
-
|
|
44440
44650
|
// src/commands/sessions/daemon/worktree/isBacklogRunArgs.ts
|
|
44441
44651
|
var ITEM_ID = /^a?\d+$/;
|
|
44442
44652
|
function isBacklogRunArgs(args) {
|
|
@@ -44500,7 +44710,6 @@ function failChainedRun(session, itemId2, error, clients, tree) {
|
|
|
44500
44710
|
// src/commands/sessions/daemon/reuseSessionForRun.ts
|
|
44501
44711
|
function reuseSessionForRun(session, itemId2, clients, onStatusChange, tree) {
|
|
44502
44712
|
const assistArgs = ["backlog", "run", String(itemId2)];
|
|
44503
|
-
const originCwd = session.cwd;
|
|
44504
44713
|
resetCardForRun(session, assistArgs);
|
|
44505
44714
|
let alloc;
|
|
44506
44715
|
try {
|
|
@@ -44522,13 +44731,71 @@ function reuseSessionForRun(session, itemId2, clients, onStatusChange, tree) {
|
|
|
44522
44731
|
onStatusChange
|
|
44523
44732
|
);
|
|
44524
44733
|
if (!started) return;
|
|
44525
|
-
if (tree) ensureWatcher(tree, originCwd);
|
|
44526
44734
|
attachReusedRun(session, alloc, clients, onStatusChange, tree);
|
|
44527
44735
|
daemonLog(
|
|
44528
44736
|
`session ${session.id} reused for backlog run ${itemId2}: ${session.name}`
|
|
44529
44737
|
);
|
|
44530
44738
|
}
|
|
44531
44739
|
|
|
44740
|
+
// src/commands/sessions/daemon/managerStatusChangeHandler.ts
|
|
44741
|
+
function managerStatusChangeHandler(sessions, clients, dismiss, notify2, treeCtx) {
|
|
44742
|
+
const handler = makeStatusChangeHandler(sessions, {
|
|
44743
|
+
dismiss,
|
|
44744
|
+
notify: notify2,
|
|
44745
|
+
reuseForRun: (session, itemId2) => reuseSessionForRun(session, itemId2, clients, handler, treeCtx())
|
|
44746
|
+
});
|
|
44747
|
+
return handler;
|
|
44748
|
+
}
|
|
44749
|
+
|
|
44750
|
+
// src/commands/sessions/daemon/applySetStatus.ts
|
|
44751
|
+
function applySetStatus(sessions, id, status2, source, onStatusChange, rebind) {
|
|
44752
|
+
const session = sessions.get(id);
|
|
44753
|
+
if (!session) {
|
|
44754
|
+
daemonLog(
|
|
44755
|
+
`set-status for unknown session id=${id} status=${status2} (no live session; ignoring)`
|
|
44756
|
+
);
|
|
44757
|
+
return;
|
|
44758
|
+
}
|
|
44759
|
+
if (session.status === "stopped") {
|
|
44760
|
+
daemonLog(
|
|
44761
|
+
`set-status for stopped session id=${id} status=${status2} (held pending durable close; ignoring)`
|
|
44762
|
+
);
|
|
44763
|
+
return;
|
|
44764
|
+
}
|
|
44765
|
+
rebind?.(session);
|
|
44766
|
+
if (source === "permission") session.permissionActive = true;
|
|
44767
|
+
if (status2 === "running") session.permissionActive = false;
|
|
44768
|
+
onStatusChange(session, status2);
|
|
44769
|
+
}
|
|
44770
|
+
|
|
44771
|
+
// src/commands/sessions/daemon/rebindClaudeSession.ts
|
|
44772
|
+
function rebindClaudeSession(session, claudeSessionId, notify2, onStatusChange) {
|
|
44773
|
+
if (!claudeSessionId) return;
|
|
44774
|
+
if (session.claudeSessionId === claudeSessionId) return;
|
|
44775
|
+
daemonLog(
|
|
44776
|
+
`session ${session.id} claude session moved: ${session.claudeSessionId ?? "none"} -> ${claudeSessionId}`
|
|
44777
|
+
);
|
|
44778
|
+
session.claudeSessionId = claudeSessionId;
|
|
44779
|
+
watchTranscript(session, notify2, onStatusChange);
|
|
44780
|
+
}
|
|
44781
|
+
|
|
44782
|
+
// src/commands/sessions/daemon/setStatusFromHook.ts
|
|
44783
|
+
function setStatusFromHook(sessions, report, notify2, onStatusChange) {
|
|
44784
|
+
applySetStatus(
|
|
44785
|
+
sessions,
|
|
44786
|
+
report.id,
|
|
44787
|
+
report.status,
|
|
44788
|
+
report.source,
|
|
44789
|
+
onStatusChange,
|
|
44790
|
+
(session) => rebindClaudeSession(
|
|
44791
|
+
session,
|
|
44792
|
+
report.claudeSessionId,
|
|
44793
|
+
notify2,
|
|
44794
|
+
onStatusChange
|
|
44795
|
+
)
|
|
44796
|
+
);
|
|
44797
|
+
}
|
|
44798
|
+
|
|
44532
44799
|
// src/commands/sessions/daemon/respawnSession.ts
|
|
44533
44800
|
function respawnSession(session, respawn, status2, clients, onStatusChange) {
|
|
44534
44801
|
session.gitWatcher?.close();
|
|
@@ -44537,8 +44804,7 @@ function respawnSession(session, respawn, status2, clients, onStatusChange) {
|
|
|
44537
44804
|
session.pendingDismiss = void 0;
|
|
44538
44805
|
session.closeGrace?.cancel();
|
|
44539
44806
|
session.closing = void 0;
|
|
44540
|
-
|
|
44541
|
-
if (!keepHistory) session.scrollback = "";
|
|
44807
|
+
session.scrollback = "";
|
|
44542
44808
|
session.startedAt = Date.now();
|
|
44543
44809
|
session.runningMs = 0;
|
|
44544
44810
|
session.runningSince = null;
|
|
@@ -44555,15 +44821,7 @@ function respawnSession(session, respawn, status2, clients, onStatusChange) {
|
|
|
44555
44821
|
session.pty?.resize(session.cols, session.rows);
|
|
44556
44822
|
} catch {
|
|
44557
44823
|
}
|
|
44558
|
-
|
|
44559
|
-
const reason4 = session.watcherRestartReason;
|
|
44560
|
-
session.watcherRestartReason = void 0;
|
|
44561
|
-
emitSessionOutput(
|
|
44562
|
-
session,
|
|
44563
|
-
clients,
|
|
44564
|
-
watcherNote(reason4 ? `watcher restarted ${reason4}` : "watcher restarted")
|
|
44565
|
-
);
|
|
44566
|
-
} else broadcast(clients, { type: "clear", sessionId: session.id });
|
|
44824
|
+
broadcast(clients, { type: "clear", sessionId: session.id });
|
|
44567
44825
|
wirePtyEvents(session, clients, onStatusChange);
|
|
44568
44826
|
}
|
|
44569
44827
|
|
|
@@ -44734,144 +44992,6 @@ function restartManagedSession(sessions, id, clients, onStatusChange) {
|
|
|
44734
44992
|
return { ok: true };
|
|
44735
44993
|
}
|
|
44736
44994
|
|
|
44737
|
-
// src/commands/sessions/daemon/worktree/divergencePrompt.ts
|
|
44738
|
-
var MAX_REASON_LINES = 20;
|
|
44739
|
-
var MAX_REASON_CHARS = 2e3;
|
|
44740
|
-
var RECONCILE_STEPS = [
|
|
44741
|
-
"Reconcile it yourself, without discarding any commits on either side:",
|
|
44742
|
-
"",
|
|
44743
|
-
"1. Inspect `git status`, `git log --oneline @{u}..@` and `git log --oneline @..@{u}`.",
|
|
44744
|
-
'2. Stash any uncommitted work with `git stash push -u -m "assist divergence"`, and restore it with `git stash pop` once the branch is reconciled.',
|
|
44745
|
-
"3. Rebase the local commits onto the upstream with `git rebase @{u}`, resolving conflicts so both sides' changes survive. If the rebase cannot be resolved cleanly, `git rebase --abort` and `git merge @{u}` instead.",
|
|
44746
|
-
"4. Push the result with a plain `git push` so the branch matches its upstream again.",
|
|
44747
|
-
"5. Build the clone with `assist run auto-build`.",
|
|
44748
|
-
"6. Run /close. The daemon restarts the watcher once this session closes.",
|
|
44749
|
-
"",
|
|
44750
|
-
"Never force-push, `git reset`, or otherwise discard commits. If you cannot reconcile the branch without doing so, explain what is blocking it and leave this session open for the user instead of closing it."
|
|
44751
|
-
];
|
|
44752
|
-
var SIMULATED_STEPS = [
|
|
44753
|
-
"This divergence was simulated to test the escalation; there is nothing to reconcile. Run /close now. The daemon restarts the watcher once this session closes."
|
|
44754
|
-
];
|
|
44755
|
-
function divergenceReason(scrollback) {
|
|
44756
|
-
return stripAnsi(scrollback).split(/\r?\n|\r/).map((line) => line.trimEnd()).filter((line) => line.trim().length > 0).slice(-MAX_REASON_LINES).join("\n").slice(-MAX_REASON_CHARS);
|
|
44757
|
-
}
|
|
44758
|
-
function divergencePrompt(clone, scrollback) {
|
|
44759
|
-
const reason4 = divergenceReason(scrollback);
|
|
44760
|
-
return [
|
|
44761
|
-
`The watcher in ${clone} stopped because \`assist watch wait --pull --build\` could not fast-forward the branch (exit 3). The tail of its output:`,
|
|
44762
|
-
"",
|
|
44763
|
-
"```",
|
|
44764
|
-
reason4 || "(no output captured)",
|
|
44765
|
-
"```",
|
|
44766
|
-
"",
|
|
44767
|
-
...reason4.includes(simulatedDivergenceNote) ? SIMULATED_STEPS : RECONCILE_STEPS
|
|
44768
|
-
].join("\n");
|
|
44769
|
-
}
|
|
44770
|
-
|
|
44771
|
-
// src/commands/sessions/daemon/worktree/escalateDivergence.ts
|
|
44772
|
-
var ENDED2 = ["done", "error", "stopped"];
|
|
44773
|
-
function escalateDivergence(ctx, watcher) {
|
|
44774
|
-
if (!watcher.cwd) return void 0;
|
|
44775
|
-
const clone = canonicalTreePath(watcher.cwd);
|
|
44776
|
-
const live = [...ctx.sessions.values()].find(
|
|
44777
|
-
(s) => s.divergenceEscalation === true && s.cwd !== void 0 && canonicalTreePath(s.cwd) === clone && !ENDED2.includes(s.status)
|
|
44778
|
-
);
|
|
44779
|
-
if (live) {
|
|
44780
|
-
daemonLog(
|
|
44781
|
-
`watcher session ${watcher.id} exited 3 (divergence) in the clone ${clone}: no escalation spawned, session ${live.id} is already diagnosing it (${live.status})`
|
|
44782
|
-
);
|
|
44783
|
-
return void 0;
|
|
44784
|
-
}
|
|
44785
|
-
const prompt = divergencePrompt(clone, watcher.scrollback);
|
|
44786
|
-
const id = allocateAndBind(
|
|
44787
|
-
ctx,
|
|
44788
|
-
clone,
|
|
44789
|
-
(sid, resolvedCwd) => ({
|
|
44790
|
-
...createSession(sid, { prompt, cwd: resolvedCwd ?? clone }),
|
|
44791
|
-
divergenceEscalation: true
|
|
44792
|
-
}),
|
|
44793
|
-
{ inPlace: true }
|
|
44794
|
-
);
|
|
44795
|
-
daemonLog(
|
|
44796
|
-
`watcher session ${watcher.id} exited 3 (divergence) in the clone ${clone}: spawned escalation session ${id} to diagnose it`
|
|
44797
|
-
);
|
|
44798
|
-
return id;
|
|
44799
|
-
}
|
|
44800
|
-
|
|
44801
|
-
// src/commands/sessions/daemon/managerStatusChangeHandler.ts
|
|
44802
|
-
function managerStatusChangeHandler(sessions, clients, dismiss, notify2, treeCtx) {
|
|
44803
|
-
const handler = makeStatusChangeHandler(sessions, {
|
|
44804
|
-
dismiss,
|
|
44805
|
-
notify: notify2,
|
|
44806
|
-
reuseForRun: (session, itemId2) => reuseSessionForRun(session, itemId2, clients, handler, treeCtx()),
|
|
44807
|
-
escalateDivergence: (watcher) => {
|
|
44808
|
-
const id = escalateDivergence(treeCtx(), watcher);
|
|
44809
|
-
if (id)
|
|
44810
|
-
emitSessionOutput(
|
|
44811
|
-
watcher,
|
|
44812
|
-
clients,
|
|
44813
|
-
watcherNote(
|
|
44814
|
-
`divergence escalated to session ${id}; the watcher restarts once it ends`
|
|
44815
|
-
)
|
|
44816
|
-
);
|
|
44817
|
-
},
|
|
44818
|
-
resumeWatcher: (escalation) => resumeWatcherAfterEscalation(sessions, escalation, (watcherId) => {
|
|
44819
|
-
if (restartManagedSession(sessions, watcherId, clients, handler).ok)
|
|
44820
|
-
notify2();
|
|
44821
|
-
})
|
|
44822
|
-
});
|
|
44823
|
-
return handler;
|
|
44824
|
-
}
|
|
44825
|
-
|
|
44826
|
-
// src/commands/sessions/daemon/applySetStatus.ts
|
|
44827
|
-
function applySetStatus(sessions, id, status2, source, onStatusChange, rebind) {
|
|
44828
|
-
const session = sessions.get(id);
|
|
44829
|
-
if (!session) {
|
|
44830
|
-
daemonLog(
|
|
44831
|
-
`set-status for unknown session id=${id} status=${status2} (no live session; ignoring)`
|
|
44832
|
-
);
|
|
44833
|
-
return;
|
|
44834
|
-
}
|
|
44835
|
-
if (session.status === "stopped") {
|
|
44836
|
-
daemonLog(
|
|
44837
|
-
`set-status for stopped session id=${id} status=${status2} (held pending durable close; ignoring)`
|
|
44838
|
-
);
|
|
44839
|
-
return;
|
|
44840
|
-
}
|
|
44841
|
-
rebind?.(session);
|
|
44842
|
-
if (source === "permission") session.permissionActive = true;
|
|
44843
|
-
if (status2 === "running") session.permissionActive = false;
|
|
44844
|
-
onStatusChange(session, status2);
|
|
44845
|
-
}
|
|
44846
|
-
|
|
44847
|
-
// src/commands/sessions/daemon/rebindClaudeSession.ts
|
|
44848
|
-
function rebindClaudeSession(session, claudeSessionId, notify2, onStatusChange) {
|
|
44849
|
-
if (!claudeSessionId) return;
|
|
44850
|
-
if (session.claudeSessionId === claudeSessionId) return;
|
|
44851
|
-
daemonLog(
|
|
44852
|
-
`session ${session.id} claude session moved: ${session.claudeSessionId ?? "none"} -> ${claudeSessionId}`
|
|
44853
|
-
);
|
|
44854
|
-
session.claudeSessionId = claudeSessionId;
|
|
44855
|
-
watchTranscript(session, notify2, onStatusChange);
|
|
44856
|
-
}
|
|
44857
|
-
|
|
44858
|
-
// src/commands/sessions/daemon/setStatusFromHook.ts
|
|
44859
|
-
function setStatusFromHook(sessions, report, notify2, onStatusChange) {
|
|
44860
|
-
applySetStatus(
|
|
44861
|
-
sessions,
|
|
44862
|
-
report.id,
|
|
44863
|
-
report.status,
|
|
44864
|
-
report.source,
|
|
44865
|
-
onStatusChange,
|
|
44866
|
-
(session) => rebindClaudeSession(
|
|
44867
|
-
session,
|
|
44868
|
-
report.claudeSessionId,
|
|
44869
|
-
notify2,
|
|
44870
|
-
onStatusChange
|
|
44871
|
-
)
|
|
44872
|
-
);
|
|
44873
|
-
}
|
|
44874
|
-
|
|
44875
44995
|
// src/commands/sessions/daemon/restartAndNotify.ts
|
|
44876
44996
|
function restartAndNotify(sessions, id, clients, onStatusChange, notify2) {
|
|
44877
44997
|
const result = restartManagedSession(sessions, id, clients, onStatusChange);
|
|
@@ -44913,8 +45033,7 @@ function restoreBase(id, persisted) {
|
|
|
44913
45033
|
cwd: persisted.cwd,
|
|
44914
45034
|
assistArgs: persisted.assistArgs,
|
|
44915
45035
|
initialPrompt: persisted.initialPrompt,
|
|
44916
|
-
starred: persisted.
|
|
44917
|
-
watcher: persisted.watcher,
|
|
45036
|
+
starred: persisted.starred,
|
|
44918
45037
|
divergenceEscalation: persisted.divergenceEscalation,
|
|
44919
45038
|
design: persisted.design,
|
|
44920
45039
|
auto: persisted.auto,
|
|
@@ -44974,12 +45093,19 @@ function underTempRoot(path106) {
|
|
|
44974
45093
|
);
|
|
44975
45094
|
}
|
|
44976
45095
|
|
|
44977
|
-
// src/commands/sessions/daemon/
|
|
44978
|
-
function
|
|
45096
|
+
// src/commands/sessions/daemon/dropUnrestorableSessions.ts
|
|
45097
|
+
function droppedReason(entry) {
|
|
45098
|
+
if (underTempRoot(entry.cwd)) return "lies outside any project root";
|
|
45099
|
+
if (entry.watcher === true)
|
|
45100
|
+
return "is a retired watcher session (the daemon now runs the assist auto-update loop itself)";
|
|
45101
|
+
return void 0;
|
|
45102
|
+
}
|
|
45103
|
+
function dropUnrestorableSessions(persisted) {
|
|
44979
45104
|
return persisted.filter((entry) => {
|
|
44980
|
-
|
|
45105
|
+
const reason4 = droppedReason(entry);
|
|
45106
|
+
if (!reason4) return true;
|
|
44981
45107
|
daemonLog(
|
|
44982
|
-
`persisted session ${describePersistedSession(entry)}
|
|
45108
|
+
`persisted session ${describePersistedSession(entry)} ${reason4}; dropped rather than restored`
|
|
44983
45109
|
);
|
|
44984
45110
|
return false;
|
|
44985
45111
|
});
|
|
@@ -45304,25 +45430,6 @@ function isUpdate(persisted) {
|
|
|
45304
45430
|
return persisted.commandType === "assist" && persisted.assistArgs?.[0] === "update";
|
|
45305
45431
|
}
|
|
45306
45432
|
|
|
45307
|
-
// src/commands/sessions/daemon/migrateClaudeWatcher.ts
|
|
45308
|
-
function migrateClaudeWatcher(id, persisted) {
|
|
45309
|
-
if (!persisted.watcher || persisted.commandType !== "claude")
|
|
45310
|
-
return persisted;
|
|
45311
|
-
daemonLog(
|
|
45312
|
-
`migrating claude /watch watcher session ${id} to assist ${WATCHER_ARGS.join(" ")}`
|
|
45313
|
-
);
|
|
45314
|
-
return {
|
|
45315
|
-
...persisted,
|
|
45316
|
-
name: `assist ${WATCHER_ARGS.join(" ")}`,
|
|
45317
|
-
commandType: "assist",
|
|
45318
|
-
assistArgs: WATCHER_ARGS,
|
|
45319
|
-
initialPrompt: void 0,
|
|
45320
|
-
claudeSessionId: void 0,
|
|
45321
|
-
harness: void 0,
|
|
45322
|
-
harnessSessionId: void 0
|
|
45323
|
-
};
|
|
45324
|
-
}
|
|
45325
|
-
|
|
45326
45433
|
// src/commands/sessions/daemon/needsWrapperRelaunch.ts
|
|
45327
45434
|
var LAUNCH_COMMANDS = ["draft", "feat", "bug", "refine"];
|
|
45328
45435
|
function needsWrapperRelaunch(persisted) {
|
|
@@ -45335,36 +45442,11 @@ function isOnceLaunch(persisted) {
|
|
|
45335
45442
|
return persisted.commandType === "assist" && !!persisted.assistArgs && LAUNCH_COMMANDS.includes(persisted.assistArgs[0]) && persisted.assistArgs.includes("--once");
|
|
45336
45443
|
}
|
|
45337
45444
|
|
|
45338
|
-
// src/commands/sessions/daemon/relaunchConsoleWatcher.ts
|
|
45339
|
-
function isConsoleWatcher(persisted) {
|
|
45340
|
-
return persisted.watcher === true && persisted.commandType === "assist" && !!persisted.assistArgs;
|
|
45341
|
-
}
|
|
45342
|
-
function relaunchConsoleWatcher(id, persisted, base) {
|
|
45343
|
-
const command = ["assist", ...persisted.assistArgs];
|
|
45344
|
-
daemonLog(
|
|
45345
|
-
`relaunching watcher session ${id} running ${command.join(" ")} in ${persisted.cwd ?? "(no cwd)"}`
|
|
45346
|
-
);
|
|
45347
|
-
const session = runningSession(
|
|
45348
|
-
base,
|
|
45349
|
-
persisted,
|
|
45350
|
-
spawnPty(command, persisted.cwd, id)
|
|
45351
|
-
);
|
|
45352
|
-
if (persisted.cwd)
|
|
45353
|
-
session.scrollback = seedWatcherScrollback(
|
|
45354
|
-
persisted.cwd,
|
|
45355
|
-
"daemon restarted; watcher relaunched"
|
|
45356
|
-
);
|
|
45357
|
-
return session;
|
|
45358
|
-
}
|
|
45359
|
-
|
|
45360
45445
|
// src/commands/sessions/daemon/restoreSession.ts
|
|
45361
|
-
function restoreSession(id,
|
|
45362
|
-
const persisted = migrateClaudeWatcher(id, stored);
|
|
45446
|
+
function restoreSession(id, persisted) {
|
|
45363
45447
|
const base = restoreBase(id, persisted);
|
|
45364
45448
|
if (persisted.status === "stopped") return stoppedSession(base, persisted);
|
|
45365
45449
|
if (isUpdate(persisted)) return updatedSession(id, persisted);
|
|
45366
|
-
if (isConsoleWatcher(persisted))
|
|
45367
|
-
return relaunchConsoleWatcher(id, persisted, base);
|
|
45368
45450
|
const status2 = deriveRestoreStatus(persisted);
|
|
45369
45451
|
if (needsWrapperRelaunch(persisted)) {
|
|
45370
45452
|
const resumesWrittenConversation = hasTranscriptOnDisk(persisted);
|
|
@@ -45418,7 +45500,7 @@ function logRestoreError(persisted, error) {
|
|
|
45418
45500
|
|
|
45419
45501
|
// src/commands/sessions/daemon/restoreAll.ts
|
|
45420
45502
|
function restoreAll(spawner, sessions) {
|
|
45421
|
-
const persisted =
|
|
45503
|
+
const persisted = dropUnrestorableSessions(loadPersistedSessions());
|
|
45422
45504
|
const cap2 = sessionLimits.maxRestore();
|
|
45423
45505
|
const restoredIds = /* @__PURE__ */ new Map();
|
|
45424
45506
|
const names = persisted.slice(0, cap2).map((entry) => {
|
|
@@ -45674,10 +45756,10 @@ function restoreAllSessions(spawner, sessions, notify2) {
|
|
|
45674
45756
|
|
|
45675
45757
|
// src/commands/sessions/daemon/retrySession.ts
|
|
45676
45758
|
function retrySession(session, clients, onStatusChange) {
|
|
45677
|
-
const
|
|
45678
|
-
if (!
|
|
45759
|
+
const spawn12 = respawnThunk(session);
|
|
45760
|
+
if (!spawn12) return false;
|
|
45679
45761
|
const respawn = () => {
|
|
45680
|
-
respawnSession(session,
|
|
45762
|
+
respawnSession(session, spawn12, "running", clients, onStatusChange);
|
|
45681
45763
|
daemonLog(`session ${session.id} retried: ${session.name}`);
|
|
45682
45764
|
};
|
|
45683
45765
|
const pty2 = session.pty;
|
|
@@ -46706,6 +46788,30 @@ function addAgentToStream(ctx, targetId, request) {
|
|
|
46706
46788
|
};
|
|
46707
46789
|
}
|
|
46708
46790
|
|
|
46791
|
+
// src/commands/sessions/daemon/createAssistSession.ts
|
|
46792
|
+
function createAssistSession(id, assistArgs, cwd, meta, holdPty) {
|
|
46793
|
+
const startedAt = Date.now();
|
|
46794
|
+
return {
|
|
46795
|
+
id,
|
|
46796
|
+
name: `assist ${assistArgs.join(" ")}`,
|
|
46797
|
+
title: meta?.title,
|
|
46798
|
+
subtitle: meta?.subtitle,
|
|
46799
|
+
commandType: "assist",
|
|
46800
|
+
status: "running",
|
|
46801
|
+
startedAt,
|
|
46802
|
+
runningMs: 0,
|
|
46803
|
+
runningSince: startedAt,
|
|
46804
|
+
waitingSince: null,
|
|
46805
|
+
...startOrHoldPty(
|
|
46806
|
+
() => spawnPty(["assist", ...assistArgs], cwd, id),
|
|
46807
|
+
holdPty
|
|
46808
|
+
),
|
|
46809
|
+
scrollback: "",
|
|
46810
|
+
assistArgs,
|
|
46811
|
+
cwd
|
|
46812
|
+
};
|
|
46813
|
+
}
|
|
46814
|
+
|
|
46709
46815
|
// src/commands/sessions/daemon/worktree/spawnInTree.ts
|
|
46710
46816
|
function spawnInTree(ctx, { prompt, cwd, design, auto, harness, inPlace }, context) {
|
|
46711
46817
|
return allocateAndBind(
|
|
@@ -46724,7 +46830,7 @@ function spawnInTree(ctx, { prompt, cwd, design, auto, harness, inPlace }, conte
|
|
|
46724
46830
|
);
|
|
46725
46831
|
}
|
|
46726
46832
|
function spawnAssistInTree(ctx, assistArgs, cwd, meta, context) {
|
|
46727
|
-
|
|
46833
|
+
return allocateAndBind(
|
|
46728
46834
|
ctx,
|
|
46729
46835
|
cwd,
|
|
46730
46836
|
(sid, resolvedCwd, holdUntilSeeded) => createAssistSession(sid, assistArgs, resolvedCwd, meta, holdUntilSeeded),
|
|
@@ -46737,8 +46843,6 @@ function spawnAssistInTree(ctx, assistArgs, cwd, meta, context) {
|
|
|
46737
46843
|
},
|
|
46738
46844
|
context
|
|
46739
46845
|
);
|
|
46740
|
-
if (isBacklogRunArgs(assistArgs)) ensureWatcher(ctx, cwd);
|
|
46741
|
-
return id;
|
|
46742
46846
|
}
|
|
46743
46847
|
|
|
46744
46848
|
// src/commands/sessions/daemon/worktree/resumeInTree.ts
|
|
@@ -46965,13 +47069,11 @@ var SessionManager = class {
|
|
|
46965
47069
|
);
|
|
46966
47070
|
}
|
|
46967
47071
|
dismissSession = (id) => {
|
|
46968
|
-
|
|
46969
|
-
this.sessions,
|
|
46970
|
-
id,
|
|
46971
|
-
this.notify,
|
|
46972
|
-
(watcherId) => this.restart(watcherId)
|
|
46973
|
-
);
|
|
47072
|
+
dismissSessionGated(this.sessions, id, this.notify);
|
|
46974
47073
|
};
|
|
47074
|
+
startAutoUpdate() {
|
|
47075
|
+
startAutoUpdate(() => this.treeCtx());
|
|
47076
|
+
}
|
|
46975
47077
|
discardSession = (id) => {
|
|
46976
47078
|
dismissSessionGated(this.sessions, id, this.notify, true);
|
|
46977
47079
|
};
|
|
@@ -47036,6 +47138,16 @@ function exitAfterFlush(code) {
|
|
|
47036
47138
|
// src/commands/sessions/daemon/handleConnection.ts
|
|
47037
47139
|
import { createInterface as createInterface10 } from "readline";
|
|
47038
47140
|
|
|
47141
|
+
// src/commands/sessions/daemon/autoUpdate/autoUpdateReply.ts
|
|
47142
|
+
function autoUpdateReply() {
|
|
47143
|
+
return {
|
|
47144
|
+
type: "auto-update",
|
|
47145
|
+
version: ASSIST_VERSION,
|
|
47146
|
+
startCommit: autoUpdateState.startCommit(),
|
|
47147
|
+
loop: autoUpdateState.loop()
|
|
47148
|
+
};
|
|
47149
|
+
}
|
|
47150
|
+
|
|
47039
47151
|
// src/commands/sessions/daemon/handleHelloRequest.ts
|
|
47040
47152
|
var handleHelloRequest = (client, m, d) => {
|
|
47041
47153
|
sendTo(client, buildHello());
|
|
@@ -47049,10 +47161,10 @@ var handleHelloRequest = (client, m, d) => {
|
|
|
47049
47161
|
};
|
|
47050
47162
|
|
|
47051
47163
|
// src/commands/sessions/daemon/creator.ts
|
|
47052
|
-
function creator(isNew,
|
|
47164
|
+
function creator(isNew, spawn12) {
|
|
47053
47165
|
return (client, m, d) => {
|
|
47054
47166
|
if (m.links.route(client, d)) return;
|
|
47055
|
-
const result =
|
|
47167
|
+
const result = spawn12(m, d);
|
|
47056
47168
|
if (typeof result !== "string") {
|
|
47057
47169
|
sendTo(client, { type: "error", message: result.error });
|
|
47058
47170
|
return;
|
|
@@ -47561,6 +47673,7 @@ var messageHandlers = {
|
|
|
47561
47673
|
hello: handleHelloRequest,
|
|
47562
47674
|
output: handleOutputRequest,
|
|
47563
47675
|
nodes: (client, m) => m.links.sendNodes(client),
|
|
47676
|
+
"auto-update": (client) => sendTo(client, autoUpdateReply()),
|
|
47564
47677
|
"reload-links": (client, m) => {
|
|
47565
47678
|
daemonLog("reload-links received");
|
|
47566
47679
|
m.links.reload();
|
|
@@ -47718,6 +47831,7 @@ function onListening(manager, checkAutoExit) {
|
|
|
47718
47831
|
);
|
|
47719
47832
|
daemonLog(`listening on ${daemonPaths.socket}`);
|
|
47720
47833
|
manager.links.reload();
|
|
47834
|
+
manager.startAutoUpdate();
|
|
47721
47835
|
checkAutoExit(manager.isIdle());
|
|
47722
47836
|
}
|
|
47723
47837
|
function cleanupOwnedFiles() {
|
|
@@ -47820,6 +47934,7 @@ function registerDaemon(program2) {
|
|
|
47820
47934
|
cmd.command("drain").description(
|
|
47821
47935
|
"Remove all sessions from the local daemon for a clean slate (does not affect the Windows daemon); prompts before closing live sessions, and a session holding unpushed work is stopped, not removed"
|
|
47822
47936
|
).option("--yes", "Close live sessions without confirming").action((options2) => drainDaemon(options2));
|
|
47937
|
+
configHelp(cmd, autoUpdateConfigHelp);
|
|
47823
47938
|
}
|
|
47824
47939
|
|
|
47825
47940
|
// src/commands/sessions/closeSession.ts
|
|
@@ -48080,14 +48195,14 @@ async function linkStatus(name, query = queryNodes) {
|
|
|
48080
48195
|
return (await query())?.links.find((l) => l.name === name);
|
|
48081
48196
|
}
|
|
48082
48197
|
async function awaitLinkReturn(name, options2, deps2 = {}) {
|
|
48083
|
-
const { query = queryNodes, sleep:
|
|
48198
|
+
const { query = queryNodes, sleep: sleep3 = wait, now = Date.now } = deps2;
|
|
48084
48199
|
const deadline = now() + options2.timeoutMs;
|
|
48085
48200
|
let sawDown = options2.sawDown;
|
|
48086
48201
|
while (now() < deadline) {
|
|
48087
48202
|
const link3 = await linkStatus(name, query);
|
|
48088
48203
|
if (link3?.state !== "connected") sawDown = true;
|
|
48089
48204
|
else if (sawDown) return link3;
|
|
48090
|
-
await
|
|
48205
|
+
await sleep3(POLL_MS4);
|
|
48091
48206
|
}
|
|
48092
48207
|
return void 0;
|
|
48093
48208
|
}
|