@band-app/server 0.54.4 → 0.56.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.
Files changed (73) hide show
  1. package/dist/client/_shell.html +0 -0
  2. package/dist/client/assets/{TerminalPanel-CxzXrgZc.js → TerminalPanel-Wv-LbAcs.js} +1 -1
  3. package/dist/client/assets/{_basePickBy-ESHGoJr1.js → _basePickBy-CgvoOFSS.js} +1 -1
  4. package/dist/client/assets/{_baseUniq-Caza5c4E.js → _baseUniq-DF-p-6fY.js} +1 -1
  5. package/dist/client/assets/{arc-DaZonhJY.js → arc-ukMuAfYV.js} +1 -1
  6. package/dist/client/assets/{architectureDiagram-VXUJARFQ-Cq7YbAnJ.js → architectureDiagram-VXUJARFQ-BHOsjgJ7.js} +1 -1
  7. package/dist/client/assets/{blockDiagram-VD42YOAC-C8s0ghb3.js → blockDiagram-VD42YOAC-V0Q-tFQE.js} +1 -1
  8. package/dist/client/assets/{c4Diagram-YG6GDRKO-DIBhFHGh.js → c4Diagram-YG6GDRKO-BK1nC-Zr.js} +1 -1
  9. package/dist/client/assets/channel-C1UOZUKN.js +1 -0
  10. package/dist/client/assets/{chunk-4BX2VUAB-D3SZ3P8V.js → chunk-4BX2VUAB-Cc2lXQih.js} +1 -1
  11. package/dist/client/assets/{chunk-55IACEB6-BfA-9jtI.js → chunk-55IACEB6-ByQepK2K.js} +1 -1
  12. package/dist/client/assets/{chunk-B4BG7PRW-DAygCOyX.js → chunk-B4BG7PRW-BQQywZlE.js} +1 -1
  13. package/dist/client/assets/{chunk-DI55MBZ5-CuikvpNq.js → chunk-DI55MBZ5-C0Q1yI7a.js} +1 -1
  14. package/dist/client/assets/{chunk-FMBD7UC4-JCmcJDsw.js → chunk-FMBD7UC4-G_Ta25S5.js} +1 -1
  15. package/dist/client/assets/{chunk-QN33PNHL-3o6_7ioT.js → chunk-QN33PNHL-vrj5lpjf.js} +1 -1
  16. package/dist/client/assets/{chunk-QZHKN3VN-5B8nia1f.js → chunk-QZHKN3VN-DIoJiZ6Q.js} +1 -1
  17. package/dist/client/assets/{chunk-TZMSLE5B-stQp3cfp.js → chunk-TZMSLE5B-DbF2At2q.js} +1 -1
  18. package/dist/client/assets/classDiagram-2ON5EDUG-CBwXamAz.js +1 -0
  19. package/dist/client/assets/classDiagram-v2-WZHVMYZB-CBwXamAz.js +1 -0
  20. package/dist/client/assets/clone-CnowCdRV.js +1 -0
  21. package/dist/client/assets/{cose-bilkent-S5V4N54A-CVQzgyKs.js → cose-bilkent-S5V4N54A-DmniYlnr.js} +1 -1
  22. package/dist/client/assets/{dagre-6UL2VRFP-C95ZZlB4.js → dagre-6UL2VRFP-xNi8WScD.js} +1 -1
  23. package/dist/client/assets/{diagram-PSM6KHXK-Sb4x5piz.js → diagram-PSM6KHXK-CL4dq7uj.js} +1 -1
  24. package/dist/client/assets/{diagram-QEK2KX5R-TTDYZins.js → diagram-QEK2KX5R-C7WQ7eoU.js} +1 -1
  25. package/dist/client/assets/{diagram-S2PKOQOG-C8joLdiY.js → diagram-S2PKOQOG-Cl6jL5JB.js} +1 -1
  26. package/dist/client/assets/{erDiagram-Q2GNP2WA-HXkzVcZE.js → erDiagram-Q2GNP2WA-DOCd-FW1.js} +1 -1
  27. package/dist/client/assets/{flowDiagram-NV44I4VS-BPzPMXG7.js → flowDiagram-NV44I4VS-BcjVCXzs.js} +1 -1
  28. package/dist/client/assets/{ganttDiagram-JELNMOA3-5JGkIYiO.js → ganttDiagram-JELNMOA3-Cp5IVV1X.js} +1 -1
  29. package/dist/client/assets/{gitGraphDiagram-V2S2FVAM-CDCkC2dq.js → gitGraphDiagram-V2S2FVAM-D81a2lqP.js} +1 -1
  30. package/dist/client/assets/{graph-CQ3VI3Kb.js → graph-DAQsyN1O.js} +1 -1
  31. package/dist/client/assets/{highlighted-body-B3W2YXNL-jA7b7ztt.js → highlighted-body-B3W2YXNL-BHdTpazT.js} +1 -1
  32. package/dist/client/assets/{index-C7Xj47iO.js → index-4wTCyGVZ.js} +1 -1
  33. package/dist/client/assets/{index-0DuoTbku.js → index-BIBgEJc_.js} +1 -1
  34. package/dist/client/assets/{index-F2GbFYex.js → index-BbUBghw-.js} +1 -1
  35. package/dist/client/assets/{index-BedjQBXV.js → index-C69wUmqS.js} +1 -1
  36. package/dist/client/assets/{index-CZqDBAUL.js → index-CKC2JTdn.js} +1 -1
  37. package/dist/client/assets/{index-DWepK3T1.js → index-CYW-8-2k.js} +1 -1
  38. package/dist/client/assets/{index-SjDPUTbU.js → index-CzW0lrV1.js} +1 -1
  39. package/dist/client/assets/{index-xEgVFQfI.js → index-D6mUuQso.js} +1 -1
  40. package/dist/client/assets/{index-B6FlIvZu.js → index-DCOA8K1E.js} +1 -1
  41. package/dist/client/assets/{index-Ce8SticC.js → index-DFnmEpf1.js} +1 -1
  42. package/dist/client/assets/{index-sTT9joMB.js → index-DcgU8Py3.js} +1 -1
  43. package/dist/client/assets/{index-Bcr3D2nL.js → index-DdbCWPks.js} +1 -1
  44. package/dist/client/assets/{index-Dt3jdJaQ.js → index-U7nQzvUZ.js} +1 -1
  45. package/dist/client/assets/{infoDiagram-HS3SLOUP-DXlzs7_8.js → infoDiagram-HS3SLOUP-Cm5s9O89.js} +1 -1
  46. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-B7mdzrEf.js → journeyDiagram-XKPGCS4Q-BEmfY1L5.js} +1 -1
  47. package/dist/client/assets/{kanban-definition-3W4ZIXB7-C3yAE4ky.js → kanban-definition-3W4ZIXB7-BR4wUQUP.js} +1 -1
  48. package/dist/client/assets/{layout-BpyKMBbb.js → layout-eg8UUTsn.js} +1 -1
  49. package/dist/client/assets/main-BxvTwvKU.css +1 -0
  50. package/dist/client/assets/{main-B169v3Mr.js → main-lic-ksql.js} +339 -339
  51. package/dist/client/assets/{mindmap-definition-VGOIOE7T-BV1ylQ_o.js → mindmap-definition-VGOIOE7T-aO87fIIJ.js} +1 -1
  52. package/dist/client/assets/{pieDiagram-ADFJNKIX-C68Mdt_x.js → pieDiagram-ADFJNKIX-D1-R_4cR.js} +1 -1
  53. package/dist/client/assets/{quadrantDiagram-AYHSOK5B-5wmdYa_y.js → quadrantDiagram-AYHSOK5B-DG_jZYS7.js} +1 -1
  54. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-CXCtBgk5.js → requirementDiagram-UZGBJVZJ-BtxpIvi0.js} +1 -1
  55. package/dist/client/assets/{sankeyDiagram-TZEHDZUN-CwuKYu6l.js → sankeyDiagram-TZEHDZUN-CEZw5ngO.js} +1 -1
  56. package/dist/client/assets/{sequenceDiagram-WL72ISMW-BwFU-IAs.js → sequenceDiagram-WL72ISMW-Da7IJD8T.js} +1 -1
  57. package/dist/client/assets/{stateDiagram-FKZM4ZOC-B46B2gqH.js → stateDiagram-FKZM4ZOC-D9MZaz-Z.js} +1 -1
  58. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-BZauII8k.js +1 -0
  59. package/dist/client/assets/{timeline-definition-IT6M3QCI-DHJrxfmL.js → timeline-definition-IT6M3QCI-Dpy1CJBt.js} +1 -1
  60. package/dist/client/assets/{treemap-GDKQZRPO-Bn3yodwG.js → treemap-GDKQZRPO-CwxFs7qg.js} +1 -1
  61. package/dist/client/assets/{worktree._worktreeId-7oupLNxr.js → worktree._worktreeId-BrMMD4KZ.js} +1 -1
  62. package/dist/client/assets/{worktree._worktreeId-MU4bksud.js → worktree._worktreeId-D8tRL5dj.js} +1 -1
  63. package/dist/client/assets/{xychartDiagram-PRI3JC2R-DUqpx4dY.js → xychartDiagram-PRI3JC2R-C42Fu89p.js} +1 -1
  64. package/dist/openapi.json +1192 -40
  65. package/dist/start-server.mjs +61895 -59586
  66. package/dist/terminal-daemon.mjs +301 -283
  67. package/package.json +10 -9
  68. package/dist/client/assets/channel-D_oNvIqF.js +0 -1
  69. package/dist/client/assets/classDiagram-2ON5EDUG-C8EJzaAq.js +0 -1
  70. package/dist/client/assets/classDiagram-v2-WZHVMYZB-C8EJzaAq.js +0 -1
  71. package/dist/client/assets/clone-BhU1fGlA.js +0 -1
  72. package/dist/client/assets/main-DWmz5QXO.css +0 -1
  73. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-BvDRMNEQ.js +0 -1
@@ -8929,11 +8929,268 @@ function createLogger(name) {
8929
8929
  }
8930
8930
 
8931
8931
  // ../../packages/host-local/src/terminals/daemon/daemon-server.ts
8932
- import { randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
8933
- import { chmodSync as chmodSync2, lstatSync as lstatSync2, readFileSync as readFileSync3, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
8932
+ import { randomBytes as randomBytes3 } from "node:crypto";
8933
+ import { chmodSync as chmodSync2, lstatSync as lstatSync2 } from "node:fs";
8934
8934
  import { createServer } from "node:net";
8935
8935
  import { dirname as dirname4, join as join7 } from "node:path";
8936
8936
 
8937
+ // ../../packages/host-local/src/daemon-kit/endpoint.ts
8938
+ import { randomBytes } from "node:crypto";
8939
+ import {
8940
+ chmodSync,
8941
+ linkSync,
8942
+ lstatSync,
8943
+ mkdirSync as mkdirSync2,
8944
+ renameSync as renameSync2,
8945
+ statSync as statSync2,
8946
+ unlinkSync
8947
+ } from "node:fs";
8948
+ import { connect } from "node:net";
8949
+ import { dirname as dirname2, join } from "node:path";
8950
+ var PROBE_TIMEOUT_MS = 500;
8951
+ var PUBLISH_ATTEMPTS = 3;
8952
+ function isProvenDead(outcome) {
8953
+ return outcome === "missing" || outcome === "refused";
8954
+ }
8955
+ function probeEndpoint(socketPath) {
8956
+ let occupied = false;
8957
+ try {
8958
+ lstatSync(socketPath);
8959
+ occupied = true;
8960
+ } catch (err) {
8961
+ return Promise.resolve(errorCode(err) === "ENOENT" ? "missing" : "unknown");
8962
+ }
8963
+ return new Promise((resolve) => {
8964
+ const socket = connect({ path: socketPath });
8965
+ let settled = false;
8966
+ const settle = (outcome) => {
8967
+ if (settled) return;
8968
+ settled = true;
8969
+ clearTimeout(timer);
8970
+ socket.destroy();
8971
+ resolve(outcome);
8972
+ };
8973
+ const timer = setTimeout(() => settle("unknown"), PROBE_TIMEOUT_MS);
8974
+ socket.once("connect", () => settle("connected"));
8975
+ socket.once("error", (err) => {
8976
+ const code = errorCode(err);
8977
+ if (code === "ECONNREFUSED" || code === "ENOTSOCK") settle("refused");
8978
+ else if (code === "ENOENT") settle(occupied ? "refused" : "missing");
8979
+ else settle("unknown");
8980
+ });
8981
+ });
8982
+ }
8983
+ function privateBindPath(socketPath) {
8984
+ return join(dirname2(socketPath), `.p${randomBytes(5).toString("hex")}`);
8985
+ }
8986
+ async function publishEndpoint(boundPath, canonicalPath, supersede) {
8987
+ const identity = entryIdentity(boundPath, statSync2);
8988
+ if (!identity) throw new Error(`Cannot stat the bound daemon socket at ${boundPath}`);
8989
+ for (let attempt = 0; attempt < PUBLISH_ATTEMPTS; attempt++) {
8990
+ try {
8991
+ linkSync(boundPath, canonicalPath);
8992
+ } catch (err) {
8993
+ if (errorCode(err) !== "EEXIST") throw err;
8994
+ if (supersede && retireIncumbent(canonicalPath, supersede)) {
8995
+ renameSync2(boundPath, canonicalPath);
8996
+ return confirmPublished(canonicalPath, identity, true);
8997
+ }
8998
+ const replaced = await replaceProvenDead(boundPath, canonicalPath);
8999
+ if (replaced === "stale") continue;
9000
+ if (replaced !== "renamed") return replaced;
9001
+ return confirmPublished(canonicalPath, identity, false);
9002
+ }
9003
+ try {
9004
+ unlinkSync(boundPath);
9005
+ } catch {
9006
+ }
9007
+ return confirmPublished(canonicalPath, identity, false);
9008
+ }
9009
+ return { status: "inconclusive" };
9010
+ }
9011
+ async function replaceProvenDead(boundPath, canonicalPath) {
9012
+ const proven = entryIdentity(canonicalPath, lstatSync);
9013
+ const first = await probeEndpoint(canonicalPath);
9014
+ if (first === "connected") return { status: "occupied" };
9015
+ if (!isProvenDead(first)) return { status: "inconclusive" };
9016
+ const now = entryIdentity(canonicalPath, lstatSync);
9017
+ if (!proven || !now || proven.dev !== now.dev || proven.ino !== now.ino) return "stale";
9018
+ const second = await probeEndpoint(canonicalPath);
9019
+ if (second === "connected") return { status: "occupied" };
9020
+ if (!isProvenDead(second)) return { status: "inconclusive" };
9021
+ renameSync2(boundPath, canonicalPath);
9022
+ return "renamed";
9023
+ }
9024
+ function retireIncumbent(canonicalPath, supersede) {
9025
+ if (!sameEntry(entryIdentity(canonicalPath, lstatSync), supersede.incumbent)) return false;
9026
+ try {
9027
+ linkSync(canonicalPath, supersede.retiredPath);
9028
+ } catch {
9029
+ return false;
9030
+ }
9031
+ if (sameEntry(entryIdentity(supersede.retiredPath, lstatSync), supersede.incumbent)) return true;
9032
+ try {
9033
+ unlinkSync(supersede.retiredPath);
9034
+ } catch {
9035
+ }
9036
+ return false;
9037
+ }
9038
+ function sameEntry(a, b) {
9039
+ return a !== null && a.dev === b.dev && a.ino === b.ino;
9040
+ }
9041
+ function confirmPublished(canonicalPath, identity, superseded) {
9042
+ let published;
9043
+ try {
9044
+ const stats = statSync2(canonicalPath, { bigint: true });
9045
+ published = { dev: stats.dev, ino: stats.ino };
9046
+ } catch (err) {
9047
+ return errorCode(err) === "ENOENT" ? { status: "lost" } : { status: "inconclusive" };
9048
+ }
9049
+ return published.dev === identity.dev && published.ino === identity.ino ? { status: "published", identity: published, superseded } : { status: "lost" };
9050
+ }
9051
+ function endpointOwnership(canonicalPath, owned) {
9052
+ try {
9053
+ const stats = statSync2(canonicalPath, { bigint: true });
9054
+ return stats.dev === owned.dev && stats.ino === owned.ino ? "owned" : "lost";
9055
+ } catch (err) {
9056
+ return errorCode(err) === "ENOENT" ? "lost" : "indeterminate";
9057
+ }
9058
+ }
9059
+ function ensurePrivateDir(dir) {
9060
+ mkdirSync2(dir, { recursive: true, mode: 448 });
9061
+ const stats = lstatSync(dir);
9062
+ const uid = process.getuid?.();
9063
+ if (!stats.isDirectory()) throw new Error(`${dir} is not a directory`);
9064
+ if (uid !== void 0 && stats.uid !== uid) throw new Error(`${dir} is owned by another user`);
9065
+ if ((stats.mode & 63) !== 0) chmodSync(dir, 448);
9066
+ }
9067
+ function entryIdentity(path, stat) {
9068
+ try {
9069
+ const stats = stat(path, { bigint: true });
9070
+ return { dev: stats.dev, ino: stats.ino };
9071
+ } catch {
9072
+ return null;
9073
+ }
9074
+ }
9075
+ function errorCode(err) {
9076
+ return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
9077
+ }
9078
+
9079
+ // ../../packages/host-local/src/daemon-kit/private-files.ts
9080
+ import { randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
9081
+ import { readFileSync, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
9082
+ function writePrivateFile(path, content) {
9083
+ const tmp = `${path}.${randomBytes2(4).toString("hex")}.tmp`;
9084
+ writeFileSync(tmp, content, { mode: 384 });
9085
+ renameSync3(tmp, path);
9086
+ }
9087
+ function copyPrivateFile(from, to) {
9088
+ let content;
9089
+ try {
9090
+ content = readFileSync(from, "utf8");
9091
+ } catch {
9092
+ return;
9093
+ }
9094
+ writePrivateFile(to, content);
9095
+ }
9096
+ function removeRetiredFiles(retired) {
9097
+ for (const path of [retired.socket, retired.token, retired.pid]) {
9098
+ try {
9099
+ unlinkSync2(path);
9100
+ } catch {
9101
+ }
9102
+ }
9103
+ }
9104
+ function tokenMatches(expected, candidate) {
9105
+ const a = Buffer.from(expected);
9106
+ const b = Buffer.from(candidate);
9107
+ return a.length === b.length && timingSafeEqual(a, b);
9108
+ }
9109
+
9110
+ // ../../packages/host-local/src/daemon-kit/protocol.ts
9111
+ import { createHash } from "node:crypto";
9112
+ import { basename, dirname as dirname3, join as join2 } from "node:path";
9113
+ var EXIT_ENDPOINT_OCCUPIED = 20;
9114
+ var EXIT_ENDPOINT_UNAVAILABLE = 21;
9115
+ var MAX_SOCKET_PATH_BYTES = 103;
9116
+ function daemonPathsFor(spec) {
9117
+ const { runDir, name, shortPrefix, version } = spec;
9118
+ const inRunDir = join2(runDir, `${name}-v${version}.sock`);
9119
+ const socket = Buffer.byteLength(inRunDir) <= MAX_SOCKET_PATH_BYTES ? inRunDir : join2(
9120
+ shortSocketDir(),
9121
+ `${shortPrefix}-${createHash("sha256").update(runDir).digest("hex").slice(0, 16)}-v${version}.sock`
9122
+ );
9123
+ return {
9124
+ runDir,
9125
+ socket,
9126
+ token: join2(runDir, `${name}-v${version}.token`),
9127
+ pid: join2(runDir, `${name}-v${version}.pid`),
9128
+ log: join2(runDir, `${name}.log`)
9129
+ };
9130
+ }
9131
+ function retiredDaemonPaths(paths, tag) {
9132
+ return {
9133
+ ...paths,
9134
+ socket: join2(dirname3(paths.socket), `.r${tag}`),
9135
+ token: paths.token.replace(/\.token$/, `.retired-${tag}.token`),
9136
+ pid: paths.pid.replace(/\.pid$/, `.retired-${tag}.pid`)
9137
+ };
9138
+ }
9139
+ function shortSocketDir() {
9140
+ return join2("/tmp", `band-${process.getuid?.() ?? "user"}`);
9141
+ }
9142
+ function parseHello(frame) {
9143
+ if (typeof frame !== "object" || frame === null) return null;
9144
+ const hello = frame;
9145
+ if (hello.t !== "hello" || typeof hello.protocol !== "number" || typeof hello.token !== "string" || hello.role !== "control" && hello.role !== "stream" || typeof hello.clientId !== "string" || typeof hello.buildId !== "string") {
9146
+ return null;
9147
+ }
9148
+ return hello;
9149
+ }
9150
+ function writeFrame(socket, message) {
9151
+ socket.write(`${JSON.stringify(message)}
9152
+ `);
9153
+ }
9154
+ function readFrames(socket, onFrame, maxLineBytes = 64 * 1024 * 1024) {
9155
+ let chunks = [];
9156
+ let pendingBytes = 0;
9157
+ socket.setEncoding("utf8");
9158
+ socket.on("data", (chunk) => {
9159
+ if (!chunk.includes("\n")) {
9160
+ chunks.push(chunk);
9161
+ pendingBytes += chunk.length;
9162
+ if (pendingBytes > maxLineBytes) socket.destroy(new Error("Frame too large"));
9163
+ return;
9164
+ }
9165
+ chunks.push(chunk);
9166
+ let buffer = chunks.length === 1 ? chunk : chunks.join("");
9167
+ chunks = [];
9168
+ pendingBytes = 0;
9169
+ let newline = buffer.indexOf("\n");
9170
+ while (newline !== -1) {
9171
+ const line = buffer.slice(0, newline);
9172
+ buffer = buffer.slice(newline + 1);
9173
+ if (line.length > 0) {
9174
+ let frame;
9175
+ try {
9176
+ frame = JSON.parse(line);
9177
+ } catch {
9178
+ socket.destroy(new Error("Malformed frame"));
9179
+ return;
9180
+ }
9181
+ onFrame(frame);
9182
+ if (socket.destroyed) return;
9183
+ }
9184
+ newline = buffer.indexOf("\n");
9185
+ }
9186
+ if (buffer.length > 0) {
9187
+ chunks.push(buffer);
9188
+ pendingBytes = buffer.length;
9189
+ if (pendingBytes > maxLineBytes) socket.destroy(new Error("Frame too large"));
9190
+ }
9191
+ });
9192
+ }
9193
+
8937
9194
  // ../../packages/host-local/src/terminals/node-pty-loader.ts
8938
9195
  var cachedImport;
8939
9196
  function preloadNodePty() {
@@ -8943,9 +9200,9 @@ function preloadNodePty() {
8943
9200
 
8944
9201
  // ../../packages/host-local/src/terminals/terminal-pool.ts
8945
9202
  import { randomUUID } from "node:crypto";
8946
- import { existsSync as existsSync3, unlinkSync, writeFileSync } from "node:fs";
9203
+ import { existsSync as existsSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
8947
9204
  import { tmpdir } from "node:os";
8948
- import { join as join3, sep } from "node:path";
9205
+ import { join as join5, sep } from "node:path";
8949
9206
 
8950
9207
  // ../../packages/host-local/src/process/path.ts
8951
9208
  import { execFile } from "node:child_process";
@@ -9008,9 +9265,9 @@ async function shellPath() {
9008
9265
  }
9009
9266
 
9010
9267
  // ../../packages/host-local/src/terminals/claude-resume.ts
9011
- import { readdirSync, statSync as statSync2 } from "node:fs";
9268
+ import { readdirSync, statSync as statSync3 } from "node:fs";
9012
9269
  import { homedir } from "node:os";
9013
- import { join } from "node:path";
9270
+ import { join as join3 } from "node:path";
9014
9271
 
9015
9272
  // ../../packages/shared/src/claude-session.ts
9016
9273
  function claudeProjectSlug(cwd) {
@@ -9027,7 +9284,7 @@ function isResumableClaudeCommand(command) {
9027
9284
  return CLAUDE_COMMAND_PATTERN.test(trimmed) && !CLAUDE_RESUME_FLAG_PATTERN.test(trimmed);
9028
9285
  }
9029
9286
  function claudeProjectDir(cwd) {
9030
- return join(homedir(), ".claude", "projects", claudeProjectSlug(cwd));
9287
+ return join3(homedir(), ".claude", "projects", claudeProjectSlug(cwd));
9031
9288
  }
9032
9289
  function findLatestClaudeSessionId(cwd) {
9033
9290
  const dir = claudeProjectDir(cwd);
@@ -9041,7 +9298,7 @@ function findLatestClaudeSessionId(cwd) {
9041
9298
  for (const name of names) {
9042
9299
  let mtimeMs;
9043
9300
  try {
9044
- mtimeMs = statSync2(join(dir, name)).mtimeMs;
9301
+ mtimeMs = statSync3(join3(dir, name)).mtimeMs;
9045
9302
  } catch {
9046
9303
  continue;
9047
9304
  }
@@ -9071,9 +9328,9 @@ function hintForPtySpawnError(err) {
9071
9328
  }
9072
9329
 
9073
9330
  // ../../packages/host-local/src/terminals/terminal-history.ts
9074
- import { readdirSync as readdirSync2, readFileSync, rmSync as rmSync2 } from "node:fs";
9331
+ import { readdirSync as readdirSync2, readFileSync as readFileSync2, rmSync as rmSync2 } from "node:fs";
9075
9332
  import { mkdir, rename, writeFile } from "node:fs/promises";
9076
- import { join as join2 } from "node:path";
9333
+ import { join as join4 } from "node:path";
9077
9334
  var log = createLogger("terminal-history");
9078
9335
  var CHECKPOINT_MAX_BYTES = 5 * 1024 * 1024;
9079
9336
  var TerminalHistoryManager = class {
@@ -9081,14 +9338,14 @@ var TerminalHistoryManager = class {
9081
9338
  this.historyDir = historyDir;
9082
9339
  }
9083
9340
  sessionDir(terminalId) {
9084
- return join2(this.historyDir, encodeURIComponent(terminalId));
9341
+ return join4(this.historyDir, encodeURIComponent(terminalId));
9085
9342
  }
9086
9343
  readMeta(terminalId) {
9087
- return readJson(join2(this.sessionDir(terminalId), "meta.json"));
9344
+ return readJson(join4(this.sessionDir(terminalId), "meta.json"));
9088
9345
  }
9089
9346
  readCheckpoint(terminalId) {
9090
9347
  return readJson(
9091
- join2(this.sessionDir(terminalId), "checkpoint.json")
9348
+ join4(this.sessionDir(terminalId), "checkpoint.json")
9092
9349
  );
9093
9350
  }
9094
9351
  /**
@@ -9134,8 +9391,8 @@ var TerminalHistoryManager = class {
9134
9391
  return;
9135
9392
  }
9136
9393
  for (const name of names) {
9137
- const dir = join2(this.historyDir, name);
9138
- const meta = readJson(join2(dir, "meta.json"));
9394
+ const dir = join4(this.historyDir, name);
9395
+ const meta = readJson(join4(dir, "meta.json"));
9139
9396
  if (meta?.worktreeId !== worktreeId) continue;
9140
9397
  try {
9141
9398
  rmSync2(dir, { recursive: true, force: true });
@@ -9147,7 +9404,7 @@ var TerminalHistoryManager = class {
9147
9404
  };
9148
9405
  function readJson(path) {
9149
9406
  try {
9150
- return JSON.parse(readFileSync(path, "utf8"));
9407
+ return JSON.parse(readFileSync2(path, "utf8"));
9151
9408
  } catch {
9152
9409
  return null;
9153
9410
  }
@@ -9155,7 +9412,7 @@ function readJson(path) {
9155
9412
  async function writeJson(dir, name, value, serialized) {
9156
9413
  try {
9157
9414
  await mkdir(dir, { recursive: true, mode: 448 });
9158
- const path = join2(dir, name);
9415
+ const path = join4(dir, name);
9159
9416
  const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
9160
9417
  await writeFile(tmp, serialized ?? JSON.stringify(value), { mode: 384 });
9161
9418
  await rename(tmp, path);
@@ -9303,7 +9560,7 @@ var TerminalPool = class {
9303
9560
  env.BAND_WORKTREE_ID = worktreeId;
9304
9561
  let cwd = worktreeRoot;
9305
9562
  if (options?.cwd) {
9306
- cwd = resolveSafeCwd(join3(worktreeRoot, options.cwd), worktreeRoot, "cwd", options.cwd) ?? cwd;
9563
+ cwd = resolveSafeCwd(join5(worktreeRoot, options.cwd), worktreeRoot, "cwd", options.cwd) ?? cwd;
9307
9564
  } else if (checkpoint?.cwd) {
9308
9565
  cwd = resolveSafeCwd(
9309
9566
  checkpoint.cwd,
@@ -9434,7 +9691,7 @@ var TerminalPool = class {
9434
9691
  }
9435
9692
  if (session.autoRunFile) {
9436
9693
  try {
9437
- unlinkSync(session.autoRunFile);
9694
+ unlinkSync3(session.autoRunFile);
9438
9695
  } catch {
9439
9696
  }
9440
9697
  }
@@ -9568,8 +9825,8 @@ var TerminalPool = class {
9568
9825
  const pty = session.pty;
9569
9826
  let cmdFile;
9570
9827
  try {
9571
- cmdFile = join3(tmpdir(), `band-autorun-${randomUUID()}.sh`);
9572
- writeFileSync(cmdFile, `${command}
9828
+ cmdFile = join5(tmpdir(), `band-autorun-${randomUUID()}.sh`);
9829
+ writeFileSync2(cmdFile, `${command}
9573
9830
  `, { encoding: "utf-8", mode: 384, flag: "wx" });
9574
9831
  session.autoRunFile = cmdFile;
9575
9832
  } catch (err) {
@@ -9972,247 +10229,40 @@ function resolveSafeCwd(candidate, worktreeRoot, label, original) {
9972
10229
  return candidate;
9973
10230
  }
9974
10231
 
9975
- // ../../packages/host-local/src/terminals/daemon/endpoint.ts
9976
- import { randomBytes } from "node:crypto";
9977
- import {
9978
- chmodSync,
9979
- linkSync,
9980
- lstatSync,
9981
- mkdirSync as mkdirSync2,
9982
- renameSync as renameSync2,
9983
- statSync as statSync3,
9984
- unlinkSync as unlinkSync2
9985
- } from "node:fs";
9986
- import { connect } from "node:net";
9987
- import { dirname as dirname2, join as join4 } from "node:path";
9988
- var PROBE_TIMEOUT_MS = 500;
9989
- var PUBLISH_ATTEMPTS = 3;
9990
- function isProvenDead(outcome) {
9991
- return outcome === "missing" || outcome === "refused";
9992
- }
9993
- function probeEndpoint(socketPath) {
9994
- let occupied = false;
9995
- try {
9996
- lstatSync(socketPath);
9997
- occupied = true;
9998
- } catch (err) {
9999
- return Promise.resolve(errorCode(err) === "ENOENT" ? "missing" : "unknown");
10000
- }
10001
- return new Promise((resolve) => {
10002
- const socket = connect({ path: socketPath });
10003
- let settled = false;
10004
- const settle = (outcome) => {
10005
- if (settled) return;
10006
- settled = true;
10007
- clearTimeout(timer);
10008
- socket.destroy();
10009
- resolve(outcome);
10010
- };
10011
- const timer = setTimeout(() => settle("unknown"), PROBE_TIMEOUT_MS);
10012
- socket.once("connect", () => settle("connected"));
10013
- socket.once("error", (err) => {
10014
- const code = errorCode(err);
10015
- if (code === "ECONNREFUSED" || code === "ENOTSOCK") settle("refused");
10016
- else if (code === "ENOENT") settle(occupied ? "refused" : "missing");
10017
- else settle("unknown");
10018
- });
10019
- });
10020
- }
10021
- function privateBindPath(socketPath) {
10022
- return join4(dirname2(socketPath), `.p${randomBytes(5).toString("hex")}`);
10023
- }
10024
- async function publishEndpoint(boundPath, canonicalPath, supersede) {
10025
- const identity = entryIdentity(boundPath, statSync3);
10026
- if (!identity) throw new Error(`Cannot stat the bound daemon socket at ${boundPath}`);
10027
- for (let attempt = 0; attempt < PUBLISH_ATTEMPTS; attempt++) {
10028
- try {
10029
- linkSync(boundPath, canonicalPath);
10030
- } catch (err) {
10031
- if (errorCode(err) !== "EEXIST") throw err;
10032
- if (supersede && retireIncumbent(canonicalPath, supersede)) {
10033
- renameSync2(boundPath, canonicalPath);
10034
- return confirmPublished(canonicalPath, identity, true);
10035
- }
10036
- const replaced = await replaceProvenDead(boundPath, canonicalPath);
10037
- if (replaced === "stale") continue;
10038
- if (replaced !== "renamed") return replaced;
10039
- return confirmPublished(canonicalPath, identity, false);
10040
- }
10041
- try {
10042
- unlinkSync2(boundPath);
10043
- } catch {
10044
- }
10045
- return confirmPublished(canonicalPath, identity, false);
10046
- }
10047
- return { status: "inconclusive" };
10048
- }
10049
- async function replaceProvenDead(boundPath, canonicalPath) {
10050
- const proven = entryIdentity(canonicalPath, lstatSync);
10051
- const first = await probeEndpoint(canonicalPath);
10052
- if (first === "connected") return { status: "occupied" };
10053
- if (!isProvenDead(first)) return { status: "inconclusive" };
10054
- const now = entryIdentity(canonicalPath, lstatSync);
10055
- if (!proven || !now || proven.dev !== now.dev || proven.ino !== now.ino) return "stale";
10056
- const second = await probeEndpoint(canonicalPath);
10057
- if (second === "connected") return { status: "occupied" };
10058
- if (!isProvenDead(second)) return { status: "inconclusive" };
10059
- renameSync2(boundPath, canonicalPath);
10060
- return "renamed";
10061
- }
10062
- function retireIncumbent(canonicalPath, supersede) {
10063
- if (!sameEntry(entryIdentity(canonicalPath, lstatSync), supersede.incumbent)) return false;
10064
- try {
10065
- linkSync(canonicalPath, supersede.retiredPath);
10066
- } catch {
10067
- return false;
10068
- }
10069
- if (sameEntry(entryIdentity(supersede.retiredPath, lstatSync), supersede.incumbent)) return true;
10070
- try {
10071
- unlinkSync2(supersede.retiredPath);
10072
- } catch {
10073
- }
10074
- return false;
10075
- }
10076
- function sameEntry(a, b) {
10077
- return a !== null && a.dev === b.dev && a.ino === b.ino;
10078
- }
10079
- function confirmPublished(canonicalPath, identity, superseded) {
10080
- let published;
10081
- try {
10082
- const stats = statSync3(canonicalPath, { bigint: true });
10083
- published = { dev: stats.dev, ino: stats.ino };
10084
- } catch (err) {
10085
- return errorCode(err) === "ENOENT" ? { status: "lost" } : { status: "inconclusive" };
10086
- }
10087
- return published.dev === identity.dev && published.ino === identity.ino ? { status: "published", identity: published, superseded } : { status: "lost" };
10088
- }
10089
- function endpointOwnership(canonicalPath, owned) {
10090
- try {
10091
- const stats = statSync3(canonicalPath, { bigint: true });
10092
- return stats.dev === owned.dev && stats.ino === owned.ino ? "owned" : "lost";
10093
- } catch (err) {
10094
- return errorCode(err) === "ENOENT" ? "lost" : "indeterminate";
10095
- }
10096
- }
10097
- function ensurePrivateDir(dir) {
10098
- mkdirSync2(dir, { recursive: true, mode: 448 });
10099
- const stats = lstatSync(dir);
10100
- const uid = process.getuid?.();
10101
- if (!stats.isDirectory()) throw new Error(`${dir} is not a directory`);
10102
- if (uid !== void 0 && stats.uid !== uid) throw new Error(`${dir} is owned by another user`);
10103
- if ((stats.mode & 63) !== 0) chmodSync(dir, 448);
10104
- }
10105
- function entryIdentity(path, stat) {
10106
- try {
10107
- const stats = stat(path, { bigint: true });
10108
- return { dev: stats.dev, ino: stats.ino };
10109
- } catch {
10110
- return null;
10111
- }
10112
- }
10113
- function errorCode(err) {
10114
- return typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0;
10115
- }
10116
-
10117
- // ../../packages/host-local/src/terminals/daemon/exit-records.ts
10232
+ // ../../packages/host-local/src/daemon-kit/exit-records.ts
10118
10233
  import {
10119
10234
  mkdirSync as mkdirSync3,
10120
10235
  readdirSync as readdirSync3,
10121
- readFileSync as readFileSync2,
10122
- renameSync as renameSync3,
10123
- unlinkSync as unlinkSync3,
10124
- writeFileSync as writeFileSync2
10236
+ readFileSync as readFileSync3,
10237
+ renameSync as renameSync4,
10238
+ unlinkSync as unlinkSync4,
10239
+ writeFileSync as writeFileSync3
10125
10240
  } from "node:fs";
10126
- import { join as join5 } from "node:path";
10241
+ import { join as join6 } from "node:path";
10127
10242
  var EXITS_DIR = "exits";
10128
10243
  function exitsDir(runDir) {
10129
- return join5(runDir, EXITS_DIR);
10244
+ return join6(runDir, EXITS_DIR);
10130
10245
  }
10131
- function writeExitRecord(runDir, event) {
10246
+ function writeExitRecord(runDir, key, record) {
10132
10247
  const dir = exitsDir(runDir);
10133
10248
  mkdirSync3(dir, { recursive: true, mode: 448 });
10134
- const file2 = join5(dir, `${encodeURIComponent(event.terminalId)}.json`);
10249
+ const file2 = join6(dir, `${encodeURIComponent(key)}.json`);
10135
10250
  const tmp = `${file2}.tmp`;
10136
- writeFileSync2(tmp, JSON.stringify(event), { mode: 384 });
10137
- renameSync3(tmp, file2);
10251
+ writeFileSync3(tmp, JSON.stringify(record), { mode: 384 });
10252
+ renameSync4(tmp, file2);
10253
+ }
10254
+
10255
+ // ../../packages/host-local/src/terminals/daemon/exit-records.ts
10256
+ function writeExitRecord2(runDir, event) {
10257
+ writeExitRecord(runDir, event.terminalId, event);
10138
10258
  }
10139
10259
 
10140
10260
  // ../../packages/host-local/src/terminals/daemon/protocol.ts
10141
- import { createHash } from "node:crypto";
10142
- import { basename, dirname as dirname3, join as join6 } from "node:path";
10143
10261
  var PROTOCOL_VERSION = 3;
10144
- var EXIT_ENDPOINT_OCCUPIED = 20;
10145
- var EXIT_ENDPOINT_UNAVAILABLE = 21;
10146
10262
  var EXIT_NODE_PTY_UNAVAILABLE = 22;
10147
10263
  var ENDPOINT_LOST_ERROR = "Terminal daemon no longer owns its endpoint";
10148
- var MAX_SOCKET_PATH_BYTES = 103;
10149
10264
  function daemonPaths(runDir, version = PROTOCOL_VERSION) {
10150
- const inRunDir = join6(runDir, `terminal-daemon-v${version}.sock`);
10151
- const socket = Buffer.byteLength(inRunDir) <= MAX_SOCKET_PATH_BYTES ? inRunDir : join6(
10152
- shortSocketDir(),
10153
- `td-${createHash("sha256").update(runDir).digest("hex").slice(0, 16)}-v${version}.sock`
10154
- );
10155
- return {
10156
- runDir,
10157
- socket,
10158
- token: join6(runDir, `terminal-daemon-v${version}.token`),
10159
- pid: join6(runDir, `terminal-daemon-v${version}.pid`),
10160
- log: join6(runDir, "terminal-daemon.log")
10161
- };
10162
- }
10163
- function retiredDaemonPaths(paths, tag) {
10164
- return {
10165
- ...paths,
10166
- socket: join6(dirname3(paths.socket), `.r${tag}`),
10167
- token: paths.token.replace(/\.token$/, `.retired-${tag}.token`),
10168
- pid: paths.pid.replace(/\.pid$/, `.retired-${tag}.pid`)
10169
- };
10170
- }
10171
- function shortSocketDir() {
10172
- return join6("/tmp", `band-${process.getuid?.() ?? "user"}`);
10173
- }
10174
- function writeFrame(socket, message) {
10175
- socket.write(`${JSON.stringify(message)}
10176
- `);
10177
- }
10178
- function readFrames(socket, onFrame, maxLineBytes = 64 * 1024 * 1024) {
10179
- let chunks = [];
10180
- let pendingBytes = 0;
10181
- socket.setEncoding("utf8");
10182
- socket.on("data", (chunk) => {
10183
- if (!chunk.includes("\n")) {
10184
- chunks.push(chunk);
10185
- pendingBytes += chunk.length;
10186
- if (pendingBytes > maxLineBytes) socket.destroy(new Error("Frame too large"));
10187
- return;
10188
- }
10189
- chunks.push(chunk);
10190
- let buffer = chunks.length === 1 ? chunk : chunks.join("");
10191
- chunks = [];
10192
- pendingBytes = 0;
10193
- let newline = buffer.indexOf("\n");
10194
- while (newline !== -1) {
10195
- const line = buffer.slice(0, newline);
10196
- buffer = buffer.slice(newline + 1);
10197
- if (line.length > 0) {
10198
- let frame;
10199
- try {
10200
- frame = JSON.parse(line);
10201
- } catch {
10202
- socket.destroy(new Error("Malformed frame"));
10203
- return;
10204
- }
10205
- onFrame(frame);
10206
- if (socket.destroyed) return;
10207
- }
10208
- newline = buffer.indexOf("\n");
10209
- }
10210
- if (buffer.length > 0) {
10211
- chunks.push(buffer);
10212
- pendingBytes = buffer.length;
10213
- if (pendingBytes > maxLineBytes) socket.destroy(new Error("Frame too large"));
10214
- }
10215
- });
10265
+ return daemonPathsFor({ runDir, name: "terminal-daemon", shortPrefix: "td", version });
10216
10266
  }
10217
10267
 
10218
10268
  // ../../packages/host-local/src/terminals/daemon/daemon-server.ts
@@ -10234,7 +10284,7 @@ async function runDaemon(options) {
10234
10284
  }
10235
10285
  ensurePrivateDir(paths.runDir);
10236
10286
  ensurePrivateDir(dirname4(paths.socket));
10237
- const token = randomBytes2(32).toString("hex");
10287
+ const token = randomBytes3(32).toString("hex");
10238
10288
  const pool = new TerminalPool({ historyDir: join7(dirname4(paths.runDir), "terminal-history") });
10239
10289
  const clients = /* @__PURE__ */ new Map();
10240
10290
  let shuttingDown = false;
@@ -10252,7 +10302,7 @@ async function runDaemon(options) {
10252
10302
  });
10253
10303
  });
10254
10304
  chmodSync2(bindPath, 384);
10255
- let retired = supersede ? retiredDaemonPaths(paths, randomBytes2(4).toString("hex")) : null;
10305
+ let retired = supersede ? retiredDaemonPaths(paths, randomBytes3(4).toString("hex")) : null;
10256
10306
  if (retired) {
10257
10307
  copyPrivateFile(paths.token, retired.token);
10258
10308
  copyPrivateFile(paths.pid, retired.pid);
@@ -10290,7 +10340,7 @@ async function runDaemon(options) {
10290
10340
  pool.onExit((event) => {
10291
10341
  if (options.recordExits && !event.killed && clients.size === 0) {
10292
10342
  try {
10293
- writeExitRecord(paths.runDir, event);
10343
+ writeExitRecord2(paths.runDir, event);
10294
10344
  } catch (err) {
10295
10345
  log3.warn({ err, terminalId: event.terminalId }, "could not record a terminal exit");
10296
10346
  }
@@ -10390,7 +10440,7 @@ async function runDaemon(options) {
10390
10440
  if (!role && !mismatched) {
10391
10441
  clearTimeout(helloTimer);
10392
10442
  const hello = parseHello(frame);
10393
- if (!hello || !tokenMatches(hello.token)) {
10443
+ if (!hello || !tokenMatches2(hello.token)) {
10394
10444
  writeFrame(socket, { t: "rejected", reason: "bad hello" });
10395
10445
  socket.end();
10396
10446
  return;
@@ -10613,10 +10663,8 @@ async function runDaemon(options) {
10613
10663
  cleanupOnExit: entry.cleanupOnExit
10614
10664
  };
10615
10665
  }
10616
- function tokenMatches(candidate) {
10617
- const expected = Buffer.from(token);
10618
- const actual = Buffer.from(candidate);
10619
- return actual.length === expected.length && timingSafeEqual(actual, expected);
10666
+ function tokenMatches2(candidate) {
10667
+ return tokenMatches(token, candidate);
10620
10668
  }
10621
10669
  }
10622
10670
  function hasValidIds(message) {
@@ -10631,36 +10679,6 @@ function hasValidIds(message) {
10631
10679
  }
10632
10680
  return true;
10633
10681
  }
10634
- function parseHello(frame) {
10635
- if (typeof frame !== "object" || frame === null) return null;
10636
- const hello = frame;
10637
- if (hello.t !== "hello" || typeof hello.protocol !== "number" || typeof hello.token !== "string" || hello.role !== "control" && hello.role !== "stream" || typeof hello.clientId !== "string" || typeof hello.buildId !== "string") {
10638
- return null;
10639
- }
10640
- return hello;
10641
- }
10642
- function writePrivateFile(path, content) {
10643
- const tmp = `${path}.${randomBytes2(4).toString("hex")}.tmp`;
10644
- writeFileSync3(tmp, content, { mode: 384 });
10645
- renameSync4(tmp, path);
10646
- }
10647
- function copyPrivateFile(from, to) {
10648
- let content;
10649
- try {
10650
- content = readFileSync3(from, "utf8");
10651
- } catch {
10652
- return;
10653
- }
10654
- writePrivateFile(to, content);
10655
- }
10656
- function removeRetiredFiles(retired) {
10657
- for (const path of [retired.socket, retired.token, retired.pid]) {
10658
- try {
10659
- unlinkSync4(path);
10660
- } catch {
10661
- }
10662
- }
10663
- }
10664
10682
  function exists(path) {
10665
10683
  try {
10666
10684
  lstatSync2(path);