seshmux 0.1.4 → 0.1.6
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +6 -6
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/page.js +3 -3
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/pages-manifest.json +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/app/page-6e6c6148c4d1c925.js +1 -0
- package/.next/standalone/.next/static/chunks/{webpack-f60e08036f4baea4.js → webpack-452b158709859445.js} +1 -1
- package/.next/standalone/.next/static/css/{87ea7bb93e0b1326.css → a41d278d539911dd.css} +1 -1
- package/.next/standalone/.next/static/css/{bc53104caace13e7.css → e4d6e5dc25191e2a.css} +1 -1
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/seshmux-server.js +394 -109
- package/README.md +16 -0
- package/bin/seshmux.js +295 -36
- package/daemon/ensure.js +55 -0
- package/daemon/holder.js +248 -0
- package/daemon/index.js +4 -1
- package/daemon/pty-manager.js +341 -29
- package/package.json +1 -1
- package/.next/standalone/.next/static/chunks/app/page-cd707a4bc18d9497.js +0 -1
- /package/.next/standalone/.next/static/{Xjuy0Fy4Y1goqBeK0eRol → z5Dh_tm8C81dOurk7OuAw}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Xjuy0Fy4Y1goqBeK0eRol → z5Dh_tm8C81dOurk7OuAw}/_ssgManifest.js +0 -0
|
@@ -372,7 +372,9 @@ var init_needs_input = __esm({
|
|
|
372
372
|
var workspaces_exports = {};
|
|
373
373
|
__export(workspaces_exports, {
|
|
374
374
|
create: () => create,
|
|
375
|
+
defaultBranch: () => defaultBranch,
|
|
375
376
|
dirtyCount: () => dirtyCount,
|
|
377
|
+
git: () => git,
|
|
376
378
|
list: () => list,
|
|
377
379
|
listAll: () => listAll,
|
|
378
380
|
reconcile: () => reconcile,
|
|
@@ -479,13 +481,24 @@ async function isGitRepo(repoPath) {
|
|
|
479
481
|
}
|
|
480
482
|
}
|
|
481
483
|
async function defaultBranch(repoPath) {
|
|
484
|
+
const localExists = async (name) => {
|
|
485
|
+
try {
|
|
486
|
+
await git(repoPath, ["show-ref", "--verify", "--quiet", `refs/heads/${name}`]);
|
|
487
|
+
return true;
|
|
488
|
+
} catch {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
482
492
|
try {
|
|
483
493
|
const out2 = await git(repoPath, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
|
|
484
494
|
const ref = out2.trim().replace(/^origin\//, "");
|
|
485
|
-
if (ref) return ref
|
|
495
|
+
if (ref) return await localExists(ref) ? ref : `origin/${ref}`;
|
|
486
496
|
} catch {
|
|
487
497
|
}
|
|
488
|
-
const
|
|
498
|
+
for (const name of ["main", "master"]) {
|
|
499
|
+
if (await localExists(name)) return name;
|
|
500
|
+
}
|
|
501
|
+
const out = await git(repoPath, ["rev-parse", "--abbrev-ref", "HEAD"]).catch(() => "");
|
|
489
502
|
return out.trim() || "main";
|
|
490
503
|
}
|
|
491
504
|
function create(repoPath) {
|
|
@@ -753,10 +766,10 @@ function encodeProjectId(cwd) {
|
|
|
753
766
|
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
754
767
|
}
|
|
755
768
|
function decodeProjectDir(dir) {
|
|
756
|
-
const
|
|
757
|
-
const segments =
|
|
769
|
+
const path10 = dir.replace(/-/g, "/");
|
|
770
|
+
const segments = path10.split("/").filter(Boolean);
|
|
758
771
|
const name = segments[segments.length - 1] ?? dir;
|
|
759
|
-
return { path:
|
|
772
|
+
return { path: path10, name };
|
|
760
773
|
}
|
|
761
774
|
function firstUserText(content) {
|
|
762
775
|
if (typeof content === "string") return content;
|
|
@@ -908,28 +921,28 @@ async function computeRootScan(root, provider) {
|
|
|
908
921
|
if (!newestFile || s.st.mtimeMs > newestFile.mtime) newestFile = { path: s.fp, mtime: s.st.mtimeMs };
|
|
909
922
|
}
|
|
910
923
|
if (createdAt === Number.MAX_SAFE_INTEGER) createdAt = updatedAt;
|
|
911
|
-
let
|
|
924
|
+
let path10 = decoded.path;
|
|
912
925
|
let name = decoded.name;
|
|
913
926
|
if (newestFile) {
|
|
914
927
|
const head = await readHead(newestFile.path, Math.floor(newestFile.mtime));
|
|
915
928
|
if (head.cwd) {
|
|
916
|
-
|
|
929
|
+
path10 = head.cwd;
|
|
917
930
|
name = head.cwd.split("/").filter(Boolean).pop() || decoded.name;
|
|
918
931
|
dirCwds.push({ dirPath, cwd: head.cwd });
|
|
919
932
|
}
|
|
920
933
|
}
|
|
921
934
|
let missing = false;
|
|
922
935
|
try {
|
|
923
|
-
missing = !(await (0, import_promises2.stat)(
|
|
936
|
+
missing = !(await (0, import_promises2.stat)(path10)).isDirectory();
|
|
924
937
|
} catch {
|
|
925
938
|
missing = true;
|
|
926
939
|
}
|
|
927
|
-
const parentPath = parentOf.get(
|
|
940
|
+
const parentPath = parentOf.get(path10);
|
|
928
941
|
return {
|
|
929
942
|
id: d.name,
|
|
930
943
|
provider,
|
|
931
944
|
name,
|
|
932
|
-
path: parentPath ??
|
|
945
|
+
path: parentPath ?? path10,
|
|
933
946
|
sessionCount: files.length,
|
|
934
947
|
createdAt,
|
|
935
948
|
updatedAt,
|
|
@@ -1128,8 +1141,8 @@ function rgSearch(root, q, limit) {
|
|
|
1128
1141
|
continue;
|
|
1129
1142
|
}
|
|
1130
1143
|
if (ev.type !== "match") continue;
|
|
1131
|
-
const
|
|
1132
|
-
const m =
|
|
1144
|
+
const path10 = ev.data?.path?.text ?? "";
|
|
1145
|
+
const m = path10.match(/([^/]+)\.jsonl$/);
|
|
1133
1146
|
if (!m) continue;
|
|
1134
1147
|
out.push({ sessionId: m[1], line: ev.data?.lines?.text ?? "" });
|
|
1135
1148
|
if (out.length >= limit) break;
|
|
@@ -1600,9 +1613,9 @@ function nodeFromSources(agentId, s) {
|
|
|
1600
1613
|
jsonlPath
|
|
1601
1614
|
};
|
|
1602
1615
|
}
|
|
1603
|
-
async function readJsonSafe(
|
|
1616
|
+
async function readJsonSafe(path10) {
|
|
1604
1617
|
try {
|
|
1605
|
-
return JSON.parse(await (0, import_promises6.readFile)(
|
|
1618
|
+
return JSON.parse(await (0, import_promises6.readFile)(path10, "utf8"));
|
|
1606
1619
|
} catch {
|
|
1607
1620
|
return null;
|
|
1608
1621
|
}
|
|
@@ -1985,20 +1998,20 @@ function ourVersion(command) {
|
|
|
1985
1998
|
const m = command.match(new RegExp(`${MARKER}_V(\\d+)=1`));
|
|
1986
1999
|
return m ? Number(m[1]) : null;
|
|
1987
2000
|
}
|
|
1988
|
-
async function readJson2(
|
|
2001
|
+
async function readJson2(path10) {
|
|
1989
2002
|
try {
|
|
1990
|
-
const raw = await (0, import_promises8.readFile)(
|
|
2003
|
+
const raw = await (0, import_promises8.readFile)(path10, "utf8");
|
|
1991
2004
|
return JSON.parse(raw);
|
|
1992
2005
|
} catch (err) {
|
|
1993
2006
|
if (err instanceof Error && err.code === "ENOENT") return {};
|
|
1994
2007
|
throw new Error(`settings.json is not valid JSON: ${err.message}`);
|
|
1995
2008
|
}
|
|
1996
2009
|
}
|
|
1997
|
-
async function atomicWrite(
|
|
1998
|
-
await (0, import_promises8.mkdir)((0, import_node_path10.dirname)(
|
|
1999
|
-
const tmp = (0, import_node_path10.join)((0, import_node_path10.dirname)(
|
|
2010
|
+
async function atomicWrite(path10, content) {
|
|
2011
|
+
await (0, import_promises8.mkdir)((0, import_node_path10.dirname)(path10), { recursive: true });
|
|
2012
|
+
const tmp = (0, import_node_path10.join)((0, import_node_path10.dirname)(path10), `.${(0, import_node_crypto3.randomBytes)(6).toString("hex")}.tmp`);
|
|
2000
2013
|
await (0, import_promises8.writeFile)(tmp, content, "utf8");
|
|
2001
|
-
await (0, import_promises8.rename)(tmp,
|
|
2014
|
+
await (0, import_promises8.rename)(tmp, path10);
|
|
2002
2015
|
}
|
|
2003
2016
|
function asHooksObject(cfg) {
|
|
2004
2017
|
const h = cfg.hooks;
|
|
@@ -2687,15 +2700,15 @@ var init_codex2 = __esm({
|
|
|
2687
2700
|
const projects = [];
|
|
2688
2701
|
for (const [id, { cwd, count, createdAt, updatedAt }] of byProject) {
|
|
2689
2702
|
const { name } = decodeProjectDir(id);
|
|
2690
|
-
const
|
|
2703
|
+
const path10 = cwd || id;
|
|
2691
2704
|
const displayName = cwd ? cwd.split("/").filter(Boolean).pop() || name : name;
|
|
2692
2705
|
let missing = false;
|
|
2693
2706
|
try {
|
|
2694
|
-
missing = !(await (0, import_promises11.stat)(
|
|
2707
|
+
missing = !(await (0, import_promises11.stat)(path10)).isDirectory();
|
|
2695
2708
|
} catch {
|
|
2696
2709
|
missing = true;
|
|
2697
2710
|
}
|
|
2698
|
-
projects.push({ id, provider: this.id, name: displayName, path:
|
|
2711
|
+
projects.push({ id, provider: this.id, name: displayName, path: path10, sessionCount: count, createdAt, updatedAt, missing });
|
|
2699
2712
|
}
|
|
2700
2713
|
projects.sort((a, b) => a.name.localeCompare(b.name));
|
|
2701
2714
|
return projects;
|
|
@@ -3032,8 +3045,8 @@ function startWatching(deps) {
|
|
|
3032
3045
|
awaitWriteFinish: { stabilityThreshold: 250 },
|
|
3033
3046
|
ignored: (p, stats) => !!stats?.isFile() && !p.endsWith(".jsonl")
|
|
3034
3047
|
});
|
|
3035
|
-
w.on("add", (
|
|
3036
|
-
w.on("change", (
|
|
3048
|
+
w.on("add", (path10) => schedule(path10, provider, config, "add"));
|
|
3049
|
+
w.on("change", (path10) => schedule(path10, provider, config, "change"));
|
|
3037
3050
|
w.on("error", (err) => console.error(`[watch] ${provider} watcher error:`, err));
|
|
3038
3051
|
return w;
|
|
3039
3052
|
});
|
|
@@ -3486,8 +3499,8 @@ function defaultRun(cmd, args) {
|
|
|
3486
3499
|
async function which(run, bin) {
|
|
3487
3500
|
try {
|
|
3488
3501
|
const { stdout } = await run("which", [bin]);
|
|
3489
|
-
const
|
|
3490
|
-
return
|
|
3502
|
+
const path10 = stdout.trim().split("\n")[0];
|
|
3503
|
+
return path10 || void 0;
|
|
3491
3504
|
} catch {
|
|
3492
3505
|
return void 0;
|
|
3493
3506
|
}
|
|
@@ -3501,10 +3514,10 @@ async function version(run, bin, flag = "--version") {
|
|
|
3501
3514
|
}
|
|
3502
3515
|
}
|
|
3503
3516
|
async function detectTool(run, bin, versionFlag = "--version") {
|
|
3504
|
-
const
|
|
3505
|
-
if (!
|
|
3517
|
+
const path10 = await which(run, bin);
|
|
3518
|
+
if (!path10) return { found: false };
|
|
3506
3519
|
const v = await version(run, bin, versionFlag);
|
|
3507
|
-
return { found: true, path:
|
|
3520
|
+
return { found: true, path: path10, ...v ? { version: v } : {} };
|
|
3508
3521
|
}
|
|
3509
3522
|
async function detectEnv(deps) {
|
|
3510
3523
|
const run = deps?.run ?? defaultRun;
|
|
@@ -3517,8 +3530,8 @@ async function detectEnv(deps) {
|
|
|
3517
3530
|
async function agentEnv(id) {
|
|
3518
3531
|
const provider = byId.get(id);
|
|
3519
3532
|
const bin = provider.commands.fresh("")[0];
|
|
3520
|
-
const
|
|
3521
|
-
const v =
|
|
3533
|
+
const path10 = await which(run, bin);
|
|
3534
|
+
const v = path10 ? await version(run, bin) : void 0;
|
|
3522
3535
|
let store = { found: false, projects: 0, bytes: 0 };
|
|
3523
3536
|
try {
|
|
3524
3537
|
const d = await provider.detect();
|
|
@@ -3526,7 +3539,7 @@ async function detectEnv(deps) {
|
|
|
3526
3539
|
store = { found: projects > 0, projects, bytes: d.store?.bytes ?? 0 };
|
|
3527
3540
|
} catch {
|
|
3528
3541
|
}
|
|
3529
|
-
return { found: !!
|
|
3542
|
+
return { found: !!path10, ...path10 ? { path: path10 } : {}, ...v ? { version: v } : {}, store };
|
|
3530
3543
|
}
|
|
3531
3544
|
const [claude, codex, tmux, rg] = await Promise.all([
|
|
3532
3545
|
agentEnv("claude"),
|
|
@@ -4125,24 +4138,24 @@ function bridgeServerConfig() {
|
|
|
4125
4138
|
if (process.env.SESHMUX_CONFIG_DIR) cfg.env = { SESHMUX_CONFIG_DIR: process.env.SESHMUX_CONFIG_DIR };
|
|
4126
4139
|
return cfg;
|
|
4127
4140
|
}
|
|
4128
|
-
async function atomicWrite2(
|
|
4129
|
-
await (0, import_promises12.mkdir)((0, import_node_path16.dirname)(
|
|
4130
|
-
const tmp = (0, import_node_path16.join)((0, import_node_path16.dirname)(
|
|
4141
|
+
async function atomicWrite2(path10, content) {
|
|
4142
|
+
await (0, import_promises12.mkdir)((0, import_node_path16.dirname)(path10), { recursive: true });
|
|
4143
|
+
const tmp = (0, import_node_path16.join)((0, import_node_path16.dirname)(path10), `.${(0, import_node_crypto5.randomBytes)(6).toString("hex")}.tmp`);
|
|
4131
4144
|
await (0, import_promises12.writeFile)(tmp, content, "utf8");
|
|
4132
|
-
await (0, import_promises12.rename)(tmp,
|
|
4145
|
+
await (0, import_promises12.rename)(tmp, path10);
|
|
4133
4146
|
}
|
|
4134
|
-
async function readJson3(
|
|
4147
|
+
async function readJson3(path10) {
|
|
4135
4148
|
try {
|
|
4136
|
-
const raw = await (0, import_promises12.readFile)(
|
|
4149
|
+
const raw = await (0, import_promises12.readFile)(path10, "utf8");
|
|
4137
4150
|
return JSON.parse(raw);
|
|
4138
4151
|
} catch {
|
|
4139
4152
|
return {};
|
|
4140
4153
|
}
|
|
4141
4154
|
}
|
|
4142
|
-
async function registerClaude(
|
|
4155
|
+
async function registerClaude(path10) {
|
|
4143
4156
|
let cfg = {};
|
|
4144
4157
|
try {
|
|
4145
|
-
const parsed = JSON.parse(await (0, import_promises12.readFile)(
|
|
4158
|
+
const parsed = JSON.parse(await (0, import_promises12.readFile)(path10, "utf8"));
|
|
4146
4159
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
4147
4160
|
throw new Error("top-level JSON is not an object");
|
|
4148
4161
|
}
|
|
@@ -4150,17 +4163,17 @@ async function registerClaude(path9) {
|
|
|
4150
4163
|
} catch (e) {
|
|
4151
4164
|
if (e.code !== "ENOENT") {
|
|
4152
4165
|
throw new Error(
|
|
4153
|
-
`refusing to modify ${
|
|
4166
|
+
`refusing to modify ${path10}: it exists but is not valid JSON (${e.message}) \u2014 fix or move it, then re-register (nothing was written)`
|
|
4154
4167
|
);
|
|
4155
4168
|
}
|
|
4156
4169
|
}
|
|
4157
4170
|
const mcpServers = cfg.mcpServers && typeof cfg.mcpServers === "object" ? cfg.mcpServers : {};
|
|
4158
4171
|
mcpServers["seshmux-bridge"] = bridgeServerConfig();
|
|
4159
4172
|
cfg.mcpServers = mcpServers;
|
|
4160
|
-
await atomicWrite2(
|
|
4173
|
+
await atomicWrite2(path10, JSON.stringify(cfg, null, 2) + "\n");
|
|
4161
4174
|
}
|
|
4162
|
-
async function isClaudeRegistered(
|
|
4163
|
-
const cfg = await readJson3(
|
|
4175
|
+
async function isClaudeRegistered(path10) {
|
|
4176
|
+
const cfg = await readJson3(path10);
|
|
4164
4177
|
const mcpServers = cfg.mcpServers;
|
|
4165
4178
|
return !!(mcpServers && typeof mcpServers === "object" && "seshmux-bridge" in mcpServers);
|
|
4166
4179
|
}
|
|
@@ -4180,10 +4193,10 @@ function codexTomlBlock() {
|
|
|
4180
4193
|
function codexHasBridgeBlock(raw) {
|
|
4181
4194
|
return /^\[mcp_servers\.seshmux-bridge\]/m.test(raw);
|
|
4182
4195
|
}
|
|
4183
|
-
async function registerCodex(
|
|
4196
|
+
async function registerCodex(path10) {
|
|
4184
4197
|
let raw = "";
|
|
4185
4198
|
try {
|
|
4186
|
-
raw = await (0, import_promises12.readFile)(
|
|
4199
|
+
raw = await (0, import_promises12.readFile)(path10, "utf8");
|
|
4187
4200
|
} catch {
|
|
4188
4201
|
raw = "";
|
|
4189
4202
|
}
|
|
@@ -4192,17 +4205,17 @@ async function registerCodex(path9) {
|
|
|
4192
4205
|
/\[mcp_servers\.seshmux-bridge\][\s\S]*?(?=\n\[|$)/,
|
|
4193
4206
|
codexTomlBlock().trimEnd() + "\n"
|
|
4194
4207
|
);
|
|
4195
|
-
if (replaced !== raw) await atomicWrite2(
|
|
4208
|
+
if (replaced !== raw) await atomicWrite2(path10, replaced);
|
|
4196
4209
|
return;
|
|
4197
4210
|
}
|
|
4198
4211
|
const needsSep = raw.length > 0 && !raw.endsWith("\n\n");
|
|
4199
4212
|
const sep = raw.length === 0 ? "" : needsSep ? raw.endsWith("\n") ? "\n" : "\n\n" : "";
|
|
4200
4213
|
const next2 = raw + sep + codexTomlBlock();
|
|
4201
|
-
await atomicWrite2(
|
|
4214
|
+
await atomicWrite2(path10, next2);
|
|
4202
4215
|
}
|
|
4203
|
-
async function isCodexRegistered(
|
|
4216
|
+
async function isCodexRegistered(path10) {
|
|
4204
4217
|
try {
|
|
4205
|
-
const raw = await (0, import_promises12.readFile)(
|
|
4218
|
+
const raw = await (0, import_promises12.readFile)(path10, "utf8");
|
|
4206
4219
|
return codexHasBridgeBlock(raw);
|
|
4207
4220
|
} catch {
|
|
4208
4221
|
return false;
|
|
@@ -4273,28 +4286,28 @@ __export(bridge_exports, {
|
|
|
4273
4286
|
function providerName2(p) {
|
|
4274
4287
|
return p === "codex" ? "Codex" : "Claude";
|
|
4275
4288
|
}
|
|
4276
|
-
async function isDir(
|
|
4289
|
+
async function isDir(path10) {
|
|
4277
4290
|
try {
|
|
4278
|
-
return (await (0, import_promises13.stat)(
|
|
4291
|
+
return (await (0, import_promises13.stat)(path10)).isDirectory();
|
|
4279
4292
|
} catch {
|
|
4280
4293
|
return false;
|
|
4281
4294
|
}
|
|
4282
4295
|
}
|
|
4283
|
-
async function atomicWrite3(
|
|
4284
|
-
const dir = (0, import_node_path17.join)(
|
|
4296
|
+
async function atomicWrite3(path10, content) {
|
|
4297
|
+
const dir = (0, import_node_path17.join)(path10, "..");
|
|
4285
4298
|
await (0, import_promises13.mkdir)(dir, { recursive: true });
|
|
4286
4299
|
const tmp = (0, import_node_path17.join)(dir, `.${(0, import_node_crypto6.randomBytes)(6).toString("hex")}.tmp`);
|
|
4287
4300
|
await (0, import_promises13.writeFile)(tmp, content, "utf8");
|
|
4288
|
-
await (0, import_promises13.rename)(tmp,
|
|
4301
|
+
await (0, import_promises13.rename)(tmp, path10);
|
|
4289
4302
|
}
|
|
4290
4303
|
async function appendScratchpad(repo, text) {
|
|
4291
|
-
const
|
|
4304
|
+
const path10 = (0, import_node_path17.join)(repo, ".seshmux", "handoff.md");
|
|
4292
4305
|
let existing = "";
|
|
4293
4306
|
try {
|
|
4294
|
-
existing = await (0, import_promises13.readFile)(
|
|
4307
|
+
existing = await (0, import_promises13.readFile)(path10, "utf8");
|
|
4295
4308
|
} catch {
|
|
4296
4309
|
}
|
|
4297
|
-
await atomicWrite3(
|
|
4310
|
+
await atomicWrite3(path10, existing + (existing && !existing.endsWith("\n") ? "\n" : "") + text + "\n");
|
|
4298
4311
|
}
|
|
4299
4312
|
async function defaultResolveProvider(projectId, sessionId) {
|
|
4300
4313
|
const providers = await getProviders();
|
|
@@ -4341,7 +4354,7 @@ async function bridgeRoutes(f, deps) {
|
|
|
4341
4354
|
const resolveProvider = deps.resolveSessionProvider ?? defaultResolveProvider;
|
|
4342
4355
|
const brief = deps.composeBrief ? (p, s) => deps.composeBrief(p, s) : (p, s) => composeBrief(p, s);
|
|
4343
4356
|
const review = deps.composeDiffReview ? (p, s) => deps.composeDiffReview(p, s) : (p, s, repo) => composeDiffReview(p, s, {}, repo);
|
|
4344
|
-
const planoff = deps.runPlanoff ?? ((
|
|
4357
|
+
const planoff = deps.runPlanoff ?? ((path10, task) => runPlanoff(path10, task));
|
|
4345
4358
|
const registerBridge2 = deps.registerBridge ?? (() => registerBridge());
|
|
4346
4359
|
const bridgeStatus2 = deps.bridgeStatus ?? (() => bridgeStatus());
|
|
4347
4360
|
const listLivePtys = deps.listLivePtys ?? defaultListLivePtys;
|
|
@@ -4535,8 +4548,8 @@ var projects_exports = {};
|
|
|
4535
4548
|
__export(projects_exports, {
|
|
4536
4549
|
default: () => projectsRoutes
|
|
4537
4550
|
});
|
|
4538
|
-
function isTmpProject(
|
|
4539
|
-
const p =
|
|
4551
|
+
function isTmpProject(path10) {
|
|
4552
|
+
const p = path10.endsWith("/") ? path10 : path10 + "/";
|
|
4540
4553
|
return TMP_ROOTS.some((root) => p.startsWith(root));
|
|
4541
4554
|
}
|
|
4542
4555
|
async function projectsRoutes(f) {
|
|
@@ -4835,14 +4848,17 @@ var env_exports = {};
|
|
|
4835
4848
|
__export(env_exports, {
|
|
4836
4849
|
default: () => envRoutes
|
|
4837
4850
|
});
|
|
4838
|
-
async function
|
|
4851
|
+
async function realDaemonInfo() {
|
|
4839
4852
|
let conn = null;
|
|
4840
4853
|
try {
|
|
4841
4854
|
conn = await dial();
|
|
4842
|
-
const { version: version2 } = await conn.hello();
|
|
4843
|
-
return
|
|
4855
|
+
const [{ version: version2 }, { ptys }] = await Promise.all([conn.hello(), conn.list()]);
|
|
4856
|
+
return {
|
|
4857
|
+
version: version2 || null,
|
|
4858
|
+
plainPtys: ptys.filter((p) => p.alive !== false && !p.tmuxName).length
|
|
4859
|
+
};
|
|
4844
4860
|
} catch {
|
|
4845
|
-
return null;
|
|
4861
|
+
return { version: null, plainPtys: 0 };
|
|
4846
4862
|
} finally {
|
|
4847
4863
|
conn?.close();
|
|
4848
4864
|
}
|
|
@@ -4857,15 +4873,16 @@ function commandPreview(commands) {
|
|
|
4857
4873
|
}
|
|
4858
4874
|
async function envRoutes(f, deps = {}) {
|
|
4859
4875
|
const bridgeStatus2 = deps.bridgeStatus ?? (() => bridgeStatus());
|
|
4860
|
-
const
|
|
4876
|
+
const daemonInfo = deps.daemonInfo ?? realDaemonInfo;
|
|
4861
4877
|
const serverVersion = deps.serverVersion ?? (() => process.env.SESHMUX_VERSION ?? "");
|
|
4862
4878
|
f.get("/api/env", async () => {
|
|
4863
|
-
const [env, bridge, providers,
|
|
4879
|
+
const [env, bridge, providers, dInfo] = await Promise.all([
|
|
4864
4880
|
detectEnv(),
|
|
4865
4881
|
bridgeStatus2().catch(() => ({ claude: false, codex: false })),
|
|
4866
4882
|
getProviders(),
|
|
4867
|
-
|
|
4883
|
+
daemonInfo().catch(() => ({ version: null, plainPtys: 0 }))
|
|
4868
4884
|
]);
|
|
4885
|
+
const dVersion = dInfo.version;
|
|
4869
4886
|
const sVersion = serverVersion();
|
|
4870
4887
|
const commands = {};
|
|
4871
4888
|
const teams = {};
|
|
@@ -4881,12 +4898,14 @@ async function envRoutes(f, deps = {}) {
|
|
|
4881
4898
|
},
|
|
4882
4899
|
commands,
|
|
4883
4900
|
teams,
|
|
4884
|
-
// The daemon outlives server updates by design
|
|
4885
|
-
//
|
|
4901
|
+
// The daemon outlives server updates by design, so it can be older than us. The NEXT update
|
|
4902
|
+
// upgrades it automatically — unless plain (non-tmux) PTYs are live, which a restart would
|
|
4903
|
+
// kill. plainPtys is what lets the UI tell those two states apart.
|
|
4886
4904
|
daemon: {
|
|
4887
4905
|
version: dVersion,
|
|
4888
4906
|
serverVersion: sVersion || null,
|
|
4889
|
-
stale: isDaemonStale(dVersion, sVersion)
|
|
4907
|
+
stale: isDaemonStale(dVersion, sVersion),
|
|
4908
|
+
plainPtys: dInfo.plainPtys
|
|
4890
4909
|
}
|
|
4891
4910
|
};
|
|
4892
4911
|
});
|
|
@@ -5250,10 +5269,10 @@ var workspaces_exports2 = {};
|
|
|
5250
5269
|
__export(workspaces_exports2, {
|
|
5251
5270
|
default: () => workspaceRoutes
|
|
5252
5271
|
});
|
|
5253
|
-
async function isDir2(
|
|
5272
|
+
async function isDir2(path10) {
|
|
5254
5273
|
try {
|
|
5255
|
-
const { stat:
|
|
5256
|
-
return (await
|
|
5274
|
+
const { stat: stat11 } = await import("node:fs/promises");
|
|
5275
|
+
return (await stat11(path10)).isDirectory();
|
|
5257
5276
|
} catch {
|
|
5258
5277
|
return false;
|
|
5259
5278
|
}
|
|
@@ -5367,6 +5386,271 @@ var init_workspaces2 = __esm({
|
|
|
5367
5386
|
}
|
|
5368
5387
|
});
|
|
5369
5388
|
|
|
5389
|
+
// server/lib/git-stats.ts
|
|
5390
|
+
function parseNumstat(out) {
|
|
5391
|
+
if (out.includes("\0")) return parseNumstatZ(out);
|
|
5392
|
+
const rows = [];
|
|
5393
|
+
for (const line of out.split("\n")) {
|
|
5394
|
+
if (!line.trim()) continue;
|
|
5395
|
+
const [a, r, ...rest] = line.split(" ");
|
|
5396
|
+
if (rest.length === 0) continue;
|
|
5397
|
+
rows.push({ path: rest.join(" "), added: num(a), removed: num(r) });
|
|
5398
|
+
}
|
|
5399
|
+
return rows;
|
|
5400
|
+
}
|
|
5401
|
+
function parseNumstatZ(out) {
|
|
5402
|
+
const tokens = out.split("\0");
|
|
5403
|
+
const rows = [];
|
|
5404
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
5405
|
+
const t = tokens[i];
|
|
5406
|
+
if (!t) continue;
|
|
5407
|
+
const tab1 = t.indexOf(" ");
|
|
5408
|
+
const tab2 = t.indexOf(" ", tab1 + 1);
|
|
5409
|
+
if (tab1 === -1 || tab2 === -1) continue;
|
|
5410
|
+
const added = num(t.slice(0, tab1));
|
|
5411
|
+
const removed = num(t.slice(tab1 + 1, tab2));
|
|
5412
|
+
const rest = t.slice(tab2 + 1);
|
|
5413
|
+
if (rest === "") {
|
|
5414
|
+
const oldPath = tokens[++i];
|
|
5415
|
+
const newPath = tokens[++i];
|
|
5416
|
+
if (oldPath && newPath) rows.push({ path: newPath, added, removed, oldPath });
|
|
5417
|
+
} else {
|
|
5418
|
+
rows.push({ path: rest, added, removed });
|
|
5419
|
+
}
|
|
5420
|
+
}
|
|
5421
|
+
return rows;
|
|
5422
|
+
}
|
|
5423
|
+
async function resolveMergeBase(dir, baseRef) {
|
|
5424
|
+
if (!baseRef) return "HEAD";
|
|
5425
|
+
try {
|
|
5426
|
+
return (await git(dir, ["merge-base", baseRef, "HEAD"])).trim() || "HEAD";
|
|
5427
|
+
} catch {
|
|
5428
|
+
return "HEAD";
|
|
5429
|
+
}
|
|
5430
|
+
}
|
|
5431
|
+
async function untrackedLines(abs) {
|
|
5432
|
+
try {
|
|
5433
|
+
const st = await (0, import_promises16.stat)(abs);
|
|
5434
|
+
const hit = lineCache.get(abs);
|
|
5435
|
+
if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size) return hit;
|
|
5436
|
+
let lines = 0;
|
|
5437
|
+
let read = 0;
|
|
5438
|
+
let lastByte = 10;
|
|
5439
|
+
let binary = false;
|
|
5440
|
+
if (st.size > 0) {
|
|
5441
|
+
const fh = await (0, import_promises16.open)(abs, "r");
|
|
5442
|
+
try {
|
|
5443
|
+
const buf = Buffer.alloc(64 * 1024);
|
|
5444
|
+
const limit = Math.min(st.size, LINE_COUNT_CAP);
|
|
5445
|
+
while (read < limit) {
|
|
5446
|
+
const { bytesRead } = await fh.read(buf, 0, buf.length, read);
|
|
5447
|
+
if (bytesRead <= 0) break;
|
|
5448
|
+
if (read === 0 && buf.subarray(0, Math.min(bytesRead, 8192)).includes(0)) {
|
|
5449
|
+
binary = true;
|
|
5450
|
+
break;
|
|
5451
|
+
}
|
|
5452
|
+
for (let i = 0; i < bytesRead; i++) if (buf[i] === 10) lines++;
|
|
5453
|
+
lastByte = buf[bytesRead - 1];
|
|
5454
|
+
read += bytesRead;
|
|
5455
|
+
}
|
|
5456
|
+
} finally {
|
|
5457
|
+
await fh.close();
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5460
|
+
const result = {
|
|
5461
|
+
mtimeMs: st.mtimeMs,
|
|
5462
|
+
size: st.size,
|
|
5463
|
+
lines: binary || st.size === 0 ? 0 : lines + (lastByte !== 10 && read >= st.size ? 1 : 0),
|
|
5464
|
+
approx: !binary && st.size > LINE_COUNT_CAP
|
|
5465
|
+
};
|
|
5466
|
+
if (lineCache.size > 1e4) lineCache.clear();
|
|
5467
|
+
lineCache.set(abs, result);
|
|
5468
|
+
return result;
|
|
5469
|
+
} catch {
|
|
5470
|
+
return { lines: 0, approx: false };
|
|
5471
|
+
}
|
|
5472
|
+
}
|
|
5473
|
+
async function fileDiff(dir, baseRef, relPath) {
|
|
5474
|
+
const empty = { diff: "", truncated: false };
|
|
5475
|
+
try {
|
|
5476
|
+
const abs = import_node_path20.default.resolve(dir, relPath);
|
|
5477
|
+
if (!abs.startsWith(import_node_path20.default.resolve(dir) + import_node_path20.default.sep)) return empty;
|
|
5478
|
+
const base = await resolveMergeBase(dir, baseRef);
|
|
5479
|
+
const tracked = await git(dir, ["diff", "--no-renames", base, "--", relPath]);
|
|
5480
|
+
if (tracked) return truncateDiff(tracked);
|
|
5481
|
+
const untracked = splitZ(await git(dir, ["ls-files", "-o", "--exclude-standard", "-z", "--", relPath]));
|
|
5482
|
+
if (untracked.length === 0) return empty;
|
|
5483
|
+
try {
|
|
5484
|
+
return truncateDiff(await git(dir, ["diff", "--no-index", "--", "/dev/null", abs]));
|
|
5485
|
+
} catch (e) {
|
|
5486
|
+
const out = e.stdout;
|
|
5487
|
+
return typeof out === "string" ? truncateDiff(out) : empty;
|
|
5488
|
+
}
|
|
5489
|
+
} catch {
|
|
5490
|
+
return empty;
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
function truncateDiff(diff) {
|
|
5494
|
+
const lines = diff.split("\n");
|
|
5495
|
+
if (lines.length <= MAX_DIFF_LINES) return { diff, truncated: false };
|
|
5496
|
+
return { diff: lines.slice(0, MAX_DIFF_LINES).join("\n"), truncated: true };
|
|
5497
|
+
}
|
|
5498
|
+
function changes(dir, baseRef, wantTree) {
|
|
5499
|
+
const key = `${dir}\0${baseRef ?? ""}\0${wantTree}`;
|
|
5500
|
+
const hit = changesMemo.get(key);
|
|
5501
|
+
if (hit && Date.now() - hit.at < CHANGES_TTL_MS) return hit.promise;
|
|
5502
|
+
const promise = computeChanges(dir, baseRef, wantTree);
|
|
5503
|
+
if (changesMemo.size > 200) changesMemo.clear();
|
|
5504
|
+
changesMemo.set(key, { at: Date.now(), promise });
|
|
5505
|
+
void promise.then((res) => {
|
|
5506
|
+
if (res.degraded && changesMemo.get(key)?.promise === promise) changesMemo.delete(key);
|
|
5507
|
+
});
|
|
5508
|
+
return promise;
|
|
5509
|
+
}
|
|
5510
|
+
async function computeChanges(dir, baseRef, wantTree) {
|
|
5511
|
+
try {
|
|
5512
|
+
const base = await resolveMergeBase(dir, baseRef);
|
|
5513
|
+
const [numstatOut, nameStatusOut, untrackedOut] = await Promise.all([
|
|
5514
|
+
git(dir, ["diff", "--numstat", "-z", base]),
|
|
5515
|
+
git(dir, ["diff", "--name-status", "-z", base]),
|
|
5516
|
+
git(dir, ["ls-files", "-o", "--exclude-standard", "-z"])
|
|
5517
|
+
]);
|
|
5518
|
+
const statusTokens = splitZ(nameStatusOut);
|
|
5519
|
+
const statusByPath = /* @__PURE__ */ new Map();
|
|
5520
|
+
for (let i = 0; i < statusTokens.length; ) {
|
|
5521
|
+
const code = statusTokens[i++]?.charAt(0);
|
|
5522
|
+
if (!code) continue;
|
|
5523
|
+
if (code === "R" || code === "C") {
|
|
5524
|
+
i++;
|
|
5525
|
+
const newPath = statusTokens[i++];
|
|
5526
|
+
if (newPath) statusByPath.set(newPath, code);
|
|
5527
|
+
} else {
|
|
5528
|
+
const p = statusTokens[i++];
|
|
5529
|
+
if (p) statusByPath.set(p, code);
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5532
|
+
const files = [];
|
|
5533
|
+
for (const f of parseNumstat(numstatOut)) {
|
|
5534
|
+
if (f.oldPath) {
|
|
5535
|
+
const code = statusByPath.get(f.path) ?? "R";
|
|
5536
|
+
files.push({ path: f.path, added: f.added, removed: f.removed, status: code });
|
|
5537
|
+
if (code !== "C") files.push({ path: f.oldPath, added: 0, removed: 0, status: "D" });
|
|
5538
|
+
} else {
|
|
5539
|
+
files.push({ path: f.path, added: f.added, removed: f.removed, status: statusByPath.get(f.path) ?? "M" });
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
const untracked = splitZ(untrackedOut);
|
|
5543
|
+
for (let i = 0; i < untracked.length; i += 16) {
|
|
5544
|
+
const batch = await Promise.all(
|
|
5545
|
+
untracked.slice(i, i + 16).map(async (rel) => {
|
|
5546
|
+
const { lines, approx } = await untrackedLines(import_node_path20.default.join(dir, rel));
|
|
5547
|
+
return { path: rel, added: lines, removed: 0, status: "A", ...approx ? { approx: true } : {} };
|
|
5548
|
+
})
|
|
5549
|
+
);
|
|
5550
|
+
files.push(...batch);
|
|
5551
|
+
}
|
|
5552
|
+
const result = {
|
|
5553
|
+
added: files.reduce((n, f) => n + f.added, 0),
|
|
5554
|
+
removed: files.reduce((n, f) => n + f.removed, 0),
|
|
5555
|
+
files
|
|
5556
|
+
};
|
|
5557
|
+
if (wantTree) {
|
|
5558
|
+
const tracked = splitZ(await git(dir, ["ls-files", "-z"]));
|
|
5559
|
+
result.tree = [.../* @__PURE__ */ new Set([...tracked, ...untracked])].sort();
|
|
5560
|
+
}
|
|
5561
|
+
return result;
|
|
5562
|
+
} catch {
|
|
5563
|
+
return { added: 0, removed: 0, files: [], degraded: true };
|
|
5564
|
+
}
|
|
5565
|
+
}
|
|
5566
|
+
var import_promises16, import_node_path20, num, LINE_COUNT_CAP, lineCache, splitZ, MAX_DIFF_LINES, changesMemo, CHANGES_TTL_MS;
|
|
5567
|
+
var init_git_stats = __esm({
|
|
5568
|
+
"server/lib/git-stats.ts"() {
|
|
5569
|
+
"use strict";
|
|
5570
|
+
import_promises16 = require("node:fs/promises");
|
|
5571
|
+
import_node_path20 = __toESM(require("node:path"));
|
|
5572
|
+
init_workspaces();
|
|
5573
|
+
num = (s) => s === "-" ? 0 : Number(s) || 0;
|
|
5574
|
+
LINE_COUNT_CAP = 10 * 1024 * 1024;
|
|
5575
|
+
lineCache = /* @__PURE__ */ new Map();
|
|
5576
|
+
splitZ = (out) => out.split("\0").filter(Boolean);
|
|
5577
|
+
MAX_DIFF_LINES = 5e3;
|
|
5578
|
+
changesMemo = /* @__PURE__ */ new Map();
|
|
5579
|
+
CHANGES_TTL_MS = 5e3;
|
|
5580
|
+
}
|
|
5581
|
+
});
|
|
5582
|
+
|
|
5583
|
+
// server/routes/git.ts
|
|
5584
|
+
var git_exports = {};
|
|
5585
|
+
__export(git_exports, {
|
|
5586
|
+
default: () => gitRoutes
|
|
5587
|
+
});
|
|
5588
|
+
async function gitRoutes(f, deps = {}) {
|
|
5589
|
+
const resolveRepo = deps.resolveRepo ?? defaultResolveRepo;
|
|
5590
|
+
const listWorkspaces = deps.listWorkspaces ?? list;
|
|
5591
|
+
const repoMemo = /* @__PURE__ */ new Map();
|
|
5592
|
+
const REPO_TTL_MS = 6e4;
|
|
5593
|
+
async function repoFor(projectId) {
|
|
5594
|
+
const hit = repoMemo.get(projectId);
|
|
5595
|
+
if (hit && Date.now() - hit.at < REPO_TTL_MS) return hit.path;
|
|
5596
|
+
const path10 = await resolveRepo(projectId);
|
|
5597
|
+
if (repoMemo.size > 500) repoMemo.clear();
|
|
5598
|
+
if (path10) repoMemo.set(projectId, { at: Date.now(), path: path10 });
|
|
5599
|
+
return path10;
|
|
5600
|
+
}
|
|
5601
|
+
async function resolveTarget(projectId, branch) {
|
|
5602
|
+
const repo = await repoFor(projectId);
|
|
5603
|
+
if (!repo) return null;
|
|
5604
|
+
let dir = repo;
|
|
5605
|
+
if (branch?.startsWith("agent/")) {
|
|
5606
|
+
const rec = (await listWorkspaces(repo).catch(() => [])).find((r) => r.branch === branch);
|
|
5607
|
+
if (rec) dir = rec.dir;
|
|
5608
|
+
}
|
|
5609
|
+
const base = await defaultBranch(repo).catch(() => null);
|
|
5610
|
+
return { dir, base };
|
|
5611
|
+
}
|
|
5612
|
+
f.get(
|
|
5613
|
+
"/api/git/changes",
|
|
5614
|
+
async (req, reply) => {
|
|
5615
|
+
const { project, branch, tree } = req.query;
|
|
5616
|
+
if (!project) {
|
|
5617
|
+
reply.code(400);
|
|
5618
|
+
return { error: "project is required" };
|
|
5619
|
+
}
|
|
5620
|
+
const target = await resolveTarget(project, branch);
|
|
5621
|
+
if (!target) {
|
|
5622
|
+
reply.code(404);
|
|
5623
|
+
return { error: "project not found" };
|
|
5624
|
+
}
|
|
5625
|
+
return changes(target.dir, target.base, tree === "1");
|
|
5626
|
+
}
|
|
5627
|
+
);
|
|
5628
|
+
f.get(
|
|
5629
|
+
"/api/git/changes/file",
|
|
5630
|
+
async (req, reply) => {
|
|
5631
|
+
const { project, branch, path: relPath } = req.query;
|
|
5632
|
+
if (!project || !relPath) {
|
|
5633
|
+
reply.code(400);
|
|
5634
|
+
return { error: "project and path are required" };
|
|
5635
|
+
}
|
|
5636
|
+
const target = await resolveTarget(project, branch);
|
|
5637
|
+
if (!target) {
|
|
5638
|
+
reply.code(404);
|
|
5639
|
+
return { error: "project not found" };
|
|
5640
|
+
}
|
|
5641
|
+
return fileDiff(target.dir, target.base, relPath);
|
|
5642
|
+
}
|
|
5643
|
+
);
|
|
5644
|
+
}
|
|
5645
|
+
var init_git = __esm({
|
|
5646
|
+
"server/routes/git.ts"() {
|
|
5647
|
+
"use strict";
|
|
5648
|
+
init_git_stats();
|
|
5649
|
+
init_workspaces();
|
|
5650
|
+
init_bridge();
|
|
5651
|
+
}
|
|
5652
|
+
});
|
|
5653
|
+
|
|
5370
5654
|
// server/lib/teams.ts
|
|
5371
5655
|
function composeTeamPrompt(t, task) {
|
|
5372
5656
|
const roster = t.members.map((m) => ` - ${oneLine(m.name)} \u2014 ${oneLine(m.role)}${m.model ? ` (${m.model})` : ""}`).join("\n");
|
|
@@ -5380,16 +5664,16 @@ function composeTeamPrompt(t, task) {
|
|
|
5380
5664
|
}
|
|
5381
5665
|
async function readAll2() {
|
|
5382
5666
|
try {
|
|
5383
|
-
return JSON.parse(await (0,
|
|
5667
|
+
return JSON.parse(await (0, import_promises17.readFile)(file(), "utf8"));
|
|
5384
5668
|
} catch {
|
|
5385
5669
|
return [];
|
|
5386
5670
|
}
|
|
5387
5671
|
}
|
|
5388
5672
|
async function writeAll2(list2) {
|
|
5389
|
-
await (0,
|
|
5390
|
-
const tmp =
|
|
5391
|
-
await (0,
|
|
5392
|
-
await (0,
|
|
5673
|
+
await (0, import_promises17.mkdir)(configDir(), { recursive: true });
|
|
5674
|
+
const tmp = import_node_path21.default.join(configDir(), `.${(0, import_node_crypto8.randomBytes)(6).toString("hex")}.tmp`);
|
|
5675
|
+
await (0, import_promises17.writeFile)(tmp, JSON.stringify(list2, null, 2), "utf8");
|
|
5676
|
+
await (0, import_promises17.rename)(tmp, file());
|
|
5393
5677
|
}
|
|
5394
5678
|
function update2(mutate) {
|
|
5395
5679
|
const run = writeChain2.then(async () => {
|
|
@@ -5407,15 +5691,15 @@ async function saveTemplate(t) {
|
|
|
5407
5691
|
async function deleteTemplate(name) {
|
|
5408
5692
|
await update2((list2) => list2.filter((x) => x.name !== name));
|
|
5409
5693
|
}
|
|
5410
|
-
var
|
|
5694
|
+
var import_promises17, import_node_crypto8, import_node_path21, file, oneLine, writeChain2, listTemplates;
|
|
5411
5695
|
var init_teams = __esm({
|
|
5412
5696
|
"server/lib/teams.ts"() {
|
|
5413
5697
|
"use strict";
|
|
5414
|
-
|
|
5698
|
+
import_promises17 = require("node:fs/promises");
|
|
5415
5699
|
import_node_crypto8 = require("node:crypto");
|
|
5416
|
-
|
|
5700
|
+
import_node_path21 = __toESM(require("node:path"));
|
|
5417
5701
|
init_daemon_client();
|
|
5418
|
-
file = () =>
|
|
5702
|
+
file = () => import_node_path21.default.join(configDir(), "teams.json");
|
|
5419
5703
|
oneLine = (s) => s.replace(/[\r\n\t]+/g, " ").replace(/\s{2,}/g, " ").trim();
|
|
5420
5704
|
writeChain2 = Promise.resolve();
|
|
5421
5705
|
listTemplates = readAll2;
|
|
@@ -5427,10 +5711,10 @@ var teams_exports = {};
|
|
|
5427
5711
|
__export(teams_exports, {
|
|
5428
5712
|
default: () => teamRoutes
|
|
5429
5713
|
});
|
|
5430
|
-
async function isDir3(
|
|
5714
|
+
async function isDir3(path10) {
|
|
5431
5715
|
try {
|
|
5432
|
-
const { stat:
|
|
5433
|
-
return (await
|
|
5716
|
+
const { stat: stat11 } = await import("node:fs/promises");
|
|
5717
|
+
return (await stat11(path10)).isDirectory();
|
|
5434
5718
|
} catch {
|
|
5435
5719
|
return false;
|
|
5436
5720
|
}
|
|
@@ -5587,22 +5871,22 @@ var scratchpad_exports = {};
|
|
|
5587
5871
|
__export(scratchpad_exports, {
|
|
5588
5872
|
default: () => scratchpadRoutes
|
|
5589
5873
|
});
|
|
5590
|
-
async function isDir4(
|
|
5874
|
+
async function isDir4(path10) {
|
|
5591
5875
|
try {
|
|
5592
|
-
return (await (0,
|
|
5876
|
+
return (await (0, import_promises18.stat)(path10)).isDirectory();
|
|
5593
5877
|
} catch {
|
|
5594
5878
|
return false;
|
|
5595
5879
|
}
|
|
5596
5880
|
}
|
|
5597
5881
|
function scratchpadPath(repo) {
|
|
5598
|
-
return (0,
|
|
5882
|
+
return (0, import_node_path22.join)(repo, ".seshmux", "handoff.md");
|
|
5599
5883
|
}
|
|
5600
|
-
async function atomicWrite4(
|
|
5601
|
-
const dir = (0,
|
|
5602
|
-
await (0,
|
|
5603
|
-
const tmp = (0,
|
|
5604
|
-
await (0,
|
|
5605
|
-
await (0,
|
|
5884
|
+
async function atomicWrite4(path10, content) {
|
|
5885
|
+
const dir = (0, import_node_path22.join)(path10, "..");
|
|
5886
|
+
await (0, import_promises18.mkdir)(dir, { recursive: true });
|
|
5887
|
+
const tmp = (0, import_node_path22.join)(dir, `.${(0, import_node_crypto9.randomBytes)(6).toString("hex")}.tmp`);
|
|
5888
|
+
await (0, import_promises18.writeFile)(tmp, content, "utf8");
|
|
5889
|
+
await (0, import_promises18.rename)(tmp, path10);
|
|
5606
5890
|
}
|
|
5607
5891
|
async function scratchpadRoutes(f, deps = {}) {
|
|
5608
5892
|
const defaultResolveRepo2 = async (id) => {
|
|
@@ -5628,7 +5912,7 @@ async function scratchpadRoutes(f, deps = {}) {
|
|
|
5628
5912
|
}
|
|
5629
5913
|
deps.onOpen?.(req.params.projectId, repo);
|
|
5630
5914
|
try {
|
|
5631
|
-
const content = await (0,
|
|
5915
|
+
const content = await (0, import_promises18.readFile)(scratchpadPath(repo), "utf8");
|
|
5632
5916
|
return { content };
|
|
5633
5917
|
} catch {
|
|
5634
5918
|
return { content: "" };
|
|
@@ -5642,25 +5926,25 @@ async function scratchpadRoutes(f, deps = {}) {
|
|
|
5642
5926
|
reply.code(404);
|
|
5643
5927
|
return { error: "project not found" };
|
|
5644
5928
|
}
|
|
5645
|
-
const
|
|
5929
|
+
const path10 = scratchpadPath(repo);
|
|
5646
5930
|
let content = typeof req.body?.content === "string" ? req.body.content : "";
|
|
5647
5931
|
try {
|
|
5648
|
-
await (0,
|
|
5932
|
+
await (0, import_promises18.stat)(path10);
|
|
5649
5933
|
} catch {
|
|
5650
5934
|
if (!content.startsWith("# ")) content = TEMPLATE + content;
|
|
5651
5935
|
}
|
|
5652
|
-
await atomicWrite4(
|
|
5936
|
+
await atomicWrite4(path10, content);
|
|
5653
5937
|
return { ok: true, content };
|
|
5654
5938
|
}
|
|
5655
5939
|
);
|
|
5656
5940
|
}
|
|
5657
|
-
var import_node_crypto9,
|
|
5941
|
+
var import_node_crypto9, import_promises18, import_node_path22, TEMPLATE;
|
|
5658
5942
|
var init_scratchpad = __esm({
|
|
5659
5943
|
"server/routes/scratchpad.ts"() {
|
|
5660
5944
|
"use strict";
|
|
5661
5945
|
import_node_crypto9 = require("node:crypto");
|
|
5662
|
-
|
|
5663
|
-
|
|
5946
|
+
import_promises18 = require("node:fs/promises");
|
|
5947
|
+
import_node_path22 = require("node:path");
|
|
5664
5948
|
init_scan();
|
|
5665
5949
|
init_types();
|
|
5666
5950
|
TEMPLATE = `# Shared scratchpad
|
|
@@ -5725,12 +6009,12 @@ __export(notify_exports, {
|
|
|
5725
6009
|
default: () => notifyRoutes
|
|
5726
6010
|
});
|
|
5727
6011
|
function configPath2() {
|
|
5728
|
-
const dir = process.env.SESHMUX_CONFIG_DIR ||
|
|
5729
|
-
return
|
|
6012
|
+
const dir = process.env.SESHMUX_CONFIG_DIR || import_node_path23.default.join(import_node_os10.default.homedir(), ".config", "seshmux");
|
|
6013
|
+
return import_node_path23.default.join(dir, "config.json");
|
|
5730
6014
|
}
|
|
5731
6015
|
async function macNotificationsEnabled() {
|
|
5732
6016
|
try {
|
|
5733
|
-
const raw = await (0,
|
|
6017
|
+
const raw = await (0, import_promises19.readFile)(configPath2(), "utf8");
|
|
5734
6018
|
const cfg = JSON.parse(raw);
|
|
5735
6019
|
return cfg?.settings?.macNotifications !== false;
|
|
5736
6020
|
} catch {
|
|
@@ -5766,13 +6050,13 @@ async function notifyRoutes(f) {
|
|
|
5766
6050
|
return { ok: true, delivered: true };
|
|
5767
6051
|
});
|
|
5768
6052
|
}
|
|
5769
|
-
var import_node_child_process8,
|
|
6053
|
+
var import_node_child_process8, import_promises19, import_node_path23, import_node_os10;
|
|
5770
6054
|
var init_notify = __esm({
|
|
5771
6055
|
"server/routes/notify.ts"() {
|
|
5772
6056
|
"use strict";
|
|
5773
6057
|
import_node_child_process8 = require("node:child_process");
|
|
5774
|
-
|
|
5775
|
-
|
|
6058
|
+
import_promises19 = require("node:fs/promises");
|
|
6059
|
+
import_node_path23 = __toESM(require("node:path"));
|
|
5776
6060
|
import_node_os10 = __toESM(require("node:os"));
|
|
5777
6061
|
}
|
|
5778
6062
|
});
|
|
@@ -5986,6 +6270,7 @@ async function startServer({ port: port2 = 4700, dev = false } = {}) {
|
|
|
5986
6270
|
await (await Promise.resolve().then(() => (init_workspaces(), workspaces_exports))).reconcile().catch(() => {
|
|
5987
6271
|
});
|
|
5988
6272
|
await f.register((await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports2))).default);
|
|
6273
|
+
await f.register((await Promise.resolve().then(() => (init_git(), git_exports))).default);
|
|
5989
6274
|
await f.register((await Promise.resolve().then(() => (init_teams2(), teams_exports))).default, {
|
|
5990
6275
|
onTeamWatch: (teamName, leadSessionId, configPath3) => hub.watchTeam(teamName, leadSessionId, configPath3)
|
|
5991
6276
|
});
|