@band-app/server 0.32.0 → 0.33.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/client/assets/{TerminalPanel-CSIo5ni0.js → TerminalPanel-CyltRZLD.js} +1 -1
- package/dist/client/assets/{_basePickBy-CdaZY6mI.js → _basePickBy-Dl99bUuK.js} +1 -1
- package/dist/client/assets/{_baseUniq-Cbf2JylA.js → _baseUniq-xYPKjKRI.js} +1 -1
- package/dist/client/assets/{arc-93kXHiVA.js → arc-L0FqLNvl.js} +1 -1
- package/dist/client/assets/{architectureDiagram-VXUJARFQ-mXd7ilfO.js → architectureDiagram-VXUJARFQ-sxFQR6t8.js} +1 -1
- package/dist/client/assets/{blockDiagram-VD42YOAC-DpjfCZDe.js → blockDiagram-VD42YOAC-CKyryScy.js} +1 -1
- package/dist/client/assets/{c4Diagram-YG6GDRKO-D17zktyo.js → c4Diagram-YG6GDRKO-CKkLibM6.js} +1 -1
- package/dist/client/assets/channel-CnUqAM2K.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-UK3Q89L4.js → chunk-4BX2VUAB-B2Q5eiyh.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DOnNiKCE.js → chunk-55IACEB6-Bx7ppH1E.js} +1 -1
- package/dist/client/assets/{chunk-B4BG7PRW-RuY3pvrs.js → chunk-B4BG7PRW-z63abbDt.js} +1 -1
- package/dist/client/assets/{chunk-DI55MBZ5-CLkaHQD0.js → chunk-DI55MBZ5-CVuxJX-G.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-B2_FpfY1.js → chunk-FMBD7UC4-C4mR-Kqh.js} +1 -1
- package/dist/client/assets/{chunk-QN33PNHL-BJ5cRImN.js → chunk-QN33PNHL-DC9EuvVO.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-DWhBc9Ty.js → chunk-QZHKN3VN-BVfYPmR6.js} +1 -1
- package/dist/client/assets/{chunk-TZMSLE5B-C6dn9jrV.js → chunk-TZMSLE5B-BERfyjOQ.js} +1 -1
- package/dist/client/assets/classDiagram-2ON5EDUG-Bl2ARqSW.js +1 -0
- package/dist/client/assets/classDiagram-v2-WZHVMYZB-Bl2ARqSW.js +1 -0
- package/dist/client/assets/clone-DoC0Yowh.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-CApk1lUu.js → cose-bilkent-S5V4N54A-CKYh86Nn.js} +1 -1
- package/dist/client/assets/{dagre-6UL2VRFP-BmLALXZu.js → dagre-6UL2VRFP-CHXYsbsT.js} +1 -1
- package/dist/client/assets/{diagram-PSM6KHXK-C2cPLLkQ.js → diagram-PSM6KHXK-BgTabbUt.js} +1 -1
- package/dist/client/assets/{diagram-QEK2KX5R-vmbBSzsB.js → diagram-QEK2KX5R-DGko5nSx.js} +1 -1
- package/dist/client/assets/{diagram-S2PKOQOG-RgcJYL9S.js → diagram-S2PKOQOG-CE06Gb7p.js} +1 -1
- package/dist/client/assets/{erDiagram-Q2GNP2WA-CpoxBAoy.js → erDiagram-Q2GNP2WA-DRAdXF3c.js} +1 -1
- package/dist/client/assets/{flowDiagram-NV44I4VS-DxnlkHRY.js → flowDiagram-NV44I4VS-DMdYos4M.js} +1 -1
- package/dist/client/assets/{ganttDiagram-JELNMOA3-DsnoA6Bi.js → ganttDiagram-JELNMOA3-B1hq9zyH.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-V2S2FVAM-CRGiaUIP.js → gitGraphDiagram-V2S2FVAM-BX_eqyqV.js} +1 -1
- package/dist/client/assets/{graph-B0pjD7JO.js → graph-B1pXNJmu.js} +1 -1
- package/dist/client/assets/{highlighted-body-B3W2YXNL-B-sBG2bX.js → highlighted-body-B3W2YXNL-xpTIV5H4.js} +1 -1
- package/dist/client/assets/{index-C08rV2E6.js → index-61SgNErm.js} +1 -1
- package/dist/client/assets/{index-TNsDOp6e.js → index-67ml7mn1.js} +1 -1
- package/dist/client/assets/{index-DoBYcXmW.js → index-BAlyKPeT.js} +1 -1
- package/dist/client/assets/{index-BuhLC7zE.js → index-BD37kyMP.js} +1 -1
- package/dist/client/assets/{index-CrCMXmx8.js → index-BHygUCeT.js} +1 -1
- package/dist/client/assets/{index-ftqQmu5s.js → index-BYm6dlG5.js} +1 -1
- package/dist/client/assets/{index-U5JB6u6d.js → index-CWczZ7eS.js} +1 -1
- package/dist/client/assets/{index-DHizjwkP.js → index-CoSFZPv4.js} +1 -1
- package/dist/client/assets/{index-2xKJ9Khi.js → index-DNX82GPp.js} +1 -1
- package/dist/client/assets/{index-C5lac708.js → index-DUaIvPpT.js} +1 -1
- package/dist/client/assets/{index-THSuS9sd.js → index-Dm9xRcT9.js} +1 -1
- package/dist/client/assets/{index-sHvOWbSE.js → index-Do4DO4E-.js} +1 -1
- package/dist/client/assets/{index-Ct8NuxSL.js → index-Mpl66MhJ.js} +1 -1
- package/dist/client/assets/{infoDiagram-HS3SLOUP-CRp6iT8d.js → infoDiagram-HS3SLOUP-DHAIDbZu.js} +1 -1
- package/dist/client/assets/{journeyDiagram-XKPGCS4Q-BQ2WA6b4.js → journeyDiagram-XKPGCS4Q-BJHZIWhu.js} +1 -1
- package/dist/client/assets/{kanban-definition-3W4ZIXB7-D-VXNhIi.js → kanban-definition-3W4ZIXB7-_qzn6_ii.js} +1 -1
- package/dist/client/assets/{layout-DqRyDMTL.js → layout-CksxJldr.js} +1 -1
- package/dist/client/assets/main-D4u0xEOA.css +1 -0
- package/dist/client/assets/{main-CsKfm_iE.js → main-FnYu011V.js} +239 -236
- package/dist/client/assets/{mindmap-definition-VGOIOE7T-DF_KVmYJ.js → mindmap-definition-VGOIOE7T-Deop3o-V.js} +1 -1
- package/dist/client/assets/{pieDiagram-ADFJNKIX-X9Gpsupa.js → pieDiagram-ADFJNKIX-d4k56ZYA.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-AYHSOK5B-Dv43A6Kl.js → quadrantDiagram-AYHSOK5B-CBA2J09q.js} +1 -1
- package/dist/client/assets/{requirementDiagram-UZGBJVZJ-Bsm1ID8v.js → requirementDiagram-UZGBJVZJ-C6Nnujg6.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-TZEHDZUN-C89ZzNUa.js → sankeyDiagram-TZEHDZUN-CPfLLuk9.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-WL72ISMW-DCEzHjMR.js → sequenceDiagram-WL72ISMW-C_OY-5TF.js} +1 -1
- package/dist/client/assets/{stateDiagram-FKZM4ZOC-DL_-FpOq.js → stateDiagram-FKZM4ZOC-CeuP4CjM.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-4FDKWEC3-B9BH2TF6.js +1 -0
- package/dist/client/assets/{timeline-definition-IT6M3QCI-BklAlKxM.js → timeline-definition-IT6M3QCI-CL_Rmapn.js} +1 -1
- package/dist/client/assets/{treemap-GDKQZRPO-DugwR-ad.js → treemap-GDKQZRPO-2uvsx2LQ.js} +1 -1
- package/dist/client/assets/workspace._workspaceId-D3mRY9_6.js +1 -0
- package/dist/client/assets/{workspace._workspaceId-CvpowXC8.js → workspace._workspaceId-DF3JNMRG.js} +1 -1
- package/dist/client/assets/{xychartDiagram-PRI3JC2R-DEyS0s6m.js → xychartDiagram-PRI3JC2R-5Pzm62mv.js} +1 -1
- package/dist/migrations/20260927123820_agent_sessions/migration.sql +16 -0
- package/dist/migrations/20260927123820_agent_sessions/snapshot.json +1675 -0
- package/dist/openapi.json +823 -213
- package/dist/server/assets/{TerminalPanel-BVyQf1VK.js → TerminalPanel-DMTU2FMX.js} +1 -1
- package/dist/server/assets/{_basePickBy-DRh75DZA.js → _basePickBy-CMTHAoTW.js} +2 -2
- package/dist/server/assets/{_baseUniq-DxwDPh9u.js → _baseUniq-DkG_FLLk.js} +1 -1
- package/dist/server/assets/_tanstack-start-manifest_v-cBOqdEgL.js +4 -0
- package/dist/server/assets/{arc-d221pGej.js → arc-CSj375cS.js} +1 -1
- package/dist/server/assets/{architecture-7HQA4BMR-CDuqFHS1.js → architecture-7HQA4BMR-MwhJw22a.js} +6 -6
- package/dist/server/assets/{architectureDiagram-VXUJARFQ-LivVdR2U.js → architectureDiagram-VXUJARFQ-DyVVxp88.js} +6 -6
- package/dist/server/assets/{blockDiagram-VD42YOAC-Cpsga8jz.js → blockDiagram-VD42YOAC-aGbi3Kv_.js} +6 -6
- package/dist/server/assets/{c4Diagram-YG6GDRKO-CR3dewU0.js → c4Diagram-YG6GDRKO-DhyUvqPs.js} +2 -2
- package/dist/server/assets/{channel-CznEvUJx.js → channel-CJthnbp1.js} +1 -1
- package/dist/server/assets/{chunk-4BX2VUAB-2XGKksov.js → chunk-4BX2VUAB-Ch7bkquC.js} +1 -1
- package/dist/server/assets/{chunk-55IACEB6-D_sfF6RU.js → chunk-55IACEB6-CLKopZj8.js} +1 -1
- package/dist/server/assets/{chunk-B4BG7PRW-DE9YZpuI.js → chunk-B4BG7PRW-BVv_KeWC.js} +4 -4
- package/dist/server/assets/{chunk-DI55MBZ5-1WmBcjv0.js → chunk-DI55MBZ5-C0_HSk1s.js} +3 -3
- package/dist/server/assets/{chunk-FMBD7UC4-0hzwdviV.js → chunk-FMBD7UC4-3fy4TSVt.js} +1 -1
- package/dist/server/assets/{chunk-QN33PNHL-sglY-9R6.js → chunk-QN33PNHL-QdSQZPQz.js} +1 -1
- package/dist/server/assets/{chunk-QZHKN3VN-BL0yO15_.js → chunk-QZHKN3VN-Dak-YXr5.js} +1 -1
- package/dist/server/assets/{chunk-TZMSLE5B-CRCOAzqG.js → chunk-TZMSLE5B-ThSW8afd.js} +1 -1
- package/dist/server/assets/{classDiagram-v2-WZHVMYZB-GVVGcmAY.js → classDiagram-2ON5EDUG-Cmkciu-2.js} +5 -5
- package/dist/server/assets/{classDiagram-2ON5EDUG-GVVGcmAY.js → classDiagram-v2-WZHVMYZB-Cmkciu-2.js} +5 -5
- package/dist/server/assets/{clone-Cw9PiOA8.js → clone-ciZ96ZK2.js} +1 -1
- package/dist/server/assets/{cose-bilkent-S5V4N54A-xdF6iXS1.js → cose-bilkent-S5V4N54A-CP20--8W.js} +1 -1
- package/dist/server/assets/{dagre-6UL2VRFP-ZMimZN6M.js → dagre-6UL2VRFP-D9LrmNJH.js} +6 -6
- package/dist/server/assets/{diagram-PSM6KHXK-AtdXKese.js → diagram-PSM6KHXK-l3xztHYH.js} +7 -7
- package/dist/server/assets/{diagram-QEK2KX5R-to1VE7Ky.js → diagram-QEK2KX5R-i9twZ5aj.js} +6 -6
- package/dist/server/assets/{diagram-S2PKOQOG-lJFLwEPR.js → diagram-S2PKOQOG-DIHmhvbo.js} +6 -6
- package/dist/server/assets/{erDiagram-Q2GNP2WA-CbevyytQ.js → erDiagram-Q2GNP2WA-fMWrL8ta.js} +4 -4
- package/dist/server/assets/{flowDiagram-NV44I4VS-DTd0gkkY.js → flowDiagram-NV44I4VS-BqKFb2gL.js} +5 -5
- package/dist/server/assets/{ganttDiagram-JELNMOA3-YwmrEI5N.js → ganttDiagram-JELNMOA3-XwScweUm.js} +1 -1
- package/dist/server/assets/{gitGraph-G5XIXVHT-BArDd0OC.js → gitGraph-G5XIXVHT-DDO_mRkl.js} +6 -6
- package/dist/server/assets/{gitGraphDiagram-V2S2FVAM-BTThcyM8.js → gitGraphDiagram-V2S2FVAM-B2e2LaZt.js} +7 -7
- package/dist/server/assets/{graph-BOO01qmU.js → graph-DqF0fiyC.js} +2 -2
- package/dist/server/assets/{highlighted-body-B3W2YXNL-Cym8kCCk.js → highlighted-body-B3W2YXNL-B9lH9lqG.js} +1 -1
- package/dist/server/assets/{index-CsHpsK-4.js → index-BFzH6uNZ.js} +1 -1
- package/dist/server/assets/{index-3bt1s3HG.js → index-BRPRiIzs.js} +1 -1
- package/dist/server/assets/{index-CaFux-EA.js → index-BZSpvQ87.js} +1 -1
- package/dist/server/assets/{index-DX1Ugorr.js → index-BuxMoI9R.js} +1 -1
- package/dist/server/assets/{index-Z7BJHwYS.js → index-C0T5sHCj.js} +1 -1
- package/dist/server/assets/{index-DZfyQWn7.js → index-C35Eg9Oe.js} +1 -1
- package/dist/server/assets/{index-DVBTKosE.js → index-C4LlK8zq.js} +1 -1
- package/dist/server/assets/{index-caXQk3Nh.js → index-Cz3ed2GU.js} +1 -1
- package/dist/server/assets/{index-CQd5Q7Kt.js → index-Oepbj3Cu.js} +1 -1
- package/dist/server/assets/{index-BQaiSrqT.js → index-QY-ciJ02.js} +1 -1
- package/dist/server/assets/{index-Ckc3EtXO.js → index-dOV5Jyvk.js} +1 -1
- package/dist/server/assets/{index-7I7gBKIT.js → index-iLqcyvvo.js} +1 -1
- package/dist/server/assets/{index-CBT9vLeO.js → index-ihiIN7Vo.js} +1 -1
- package/dist/server/assets/{info-VBDWY6EO-D4lcUmb_.js → info-VBDWY6EO-BSfwYSKN.js} +6 -6
- package/dist/server/assets/{infoDiagram-HS3SLOUP-C1ai--xt.js → infoDiagram-HS3SLOUP-BcPNSucE.js} +5 -5
- package/dist/server/assets/{journeyDiagram-XKPGCS4Q-qel6lxPz.js → journeyDiagram-XKPGCS4Q-B_JljIi2.js} +4 -4
- package/dist/server/assets/{kanban-definition-3W4ZIXB7-BQPKgoP_.js → kanban-definition-3W4ZIXB7-B5aPUZvg.js} +2 -2
- package/dist/server/assets/{layout-D_wAQ9pE.js → layout-Cv2BYqNX.js} +4 -4
- package/dist/server/assets/{mermaid-3ZIDBTTL-CtNgetEO.js → mermaid-3ZIDBTTL-D_akVRms.js} +1 -1
- package/dist/server/assets/{mermaid-parser.core-BwjOeEsU.js → mermaid-parser.core-uDeqwrPN.js} +11 -11
- package/dist/server/assets/{mindmap-definition-VGOIOE7T-DYdatMwP.js → mindmap-definition-VGOIOE7T-C9LF9XTT.js} +3 -3
- package/dist/server/assets/{packet-DYOGHKS2-_TbN3RWI.js → packet-DYOGHKS2-lRBX1T35.js} +6 -6
- package/dist/server/assets/{pie-VRWISCQL-D9Z5k3qi.js → pie-VRWISCQL-BCZ9vmsj.js} +6 -6
- package/dist/server/assets/{pieDiagram-ADFJNKIX-COmj-G7F.js → pieDiagram-ADFJNKIX-HYsm0km8.js} +7 -7
- package/dist/server/assets/{quadrantDiagram-AYHSOK5B-BajsyCAd.js → quadrantDiagram-AYHSOK5B-Fdzz2j2T.js} +1 -1
- package/dist/server/assets/{radar-ZZBFDIW7-DLipfn_u.js → radar-ZZBFDIW7-iZ-6xOx9.js} +6 -6
- package/dist/server/assets/{requirementDiagram-UZGBJVZJ-BGEkpdbY.js → requirementDiagram-UZGBJVZJ-CeHGAs1A.js} +3 -3
- package/dist/server/assets/{router-Dpb0Z442.js → router-A58OKuIG.js} +16058 -13883
- package/dist/server/assets/{sankeyDiagram-TZEHDZUN-CWd3AEju.js → sankeyDiagram-TZEHDZUN-DXgjoM9B.js} +1 -1
- package/dist/server/assets/{sequenceDiagram-WL72ISMW-BMTkK0JQ.js → sequenceDiagram-WL72ISMW-BK24aHRm.js} +3 -3
- package/dist/server/assets/{stateDiagram-FKZM4ZOC-CpBXq11c.js → stateDiagram-FKZM4ZOC-uW8qduwY.js} +8 -8
- package/dist/server/assets/{stateDiagram-v2-4FDKWEC3-DNuppjf9.js → stateDiagram-v2-4FDKWEC3-O0D8F8J2.js} +4 -4
- package/dist/server/assets/{timeline-definition-IT6M3QCI-YTyqSIDt.js → timeline-definition-IT6M3QCI-BaSl1O8h.js} +2 -2
- package/dist/server/assets/{treemap-GDKQZRPO-BeWiYXRR.js → treemap-GDKQZRPO-DqxwR6w-.js} +6 -6
- package/dist/server/assets/{workspace._workspaceId-Ce_eap6T.js → workspace._workspaceId-B09dwAP5.js} +1 -1
- package/dist/server/assets/{workspace._workspaceId-t0HaEyN5.js → workspace._workspaceId-CZZSeH-P.js} +88 -71
- package/dist/server/assets/{xychartDiagram-PRI3JC2R-Dlgz7zKK.js → xychartDiagram-PRI3JC2R-Du3l-FcL.js} +1 -1
- package/dist/server/server.js +2 -2
- package/dist/start-server.mjs +23238 -20533
- package/dist/terminal-daemon.mjs +406 -102
- package/package.json +4 -4
- package/dist/client/assets/channel-C4GiEGw4.js +0 -1
- package/dist/client/assets/classDiagram-2ON5EDUG-y6v_VfOs.js +0 -1
- package/dist/client/assets/classDiagram-v2-WZHVMYZB-y6v_VfOs.js +0 -1
- package/dist/client/assets/clone-B_3XeJsO.js +0 -1
- package/dist/client/assets/main-CmUn6n9o.css +0 -1
- package/dist/client/assets/stateDiagram-v2-4FDKWEC3-D5laPTLF.js +0 -1
- package/dist/client/assets/workspace._workspaceId-CdoxJFsY.js +0 -1
- package/dist/server/assets/_tanstack-start-manifest_v-CfuLu7F9.js +0 -4
package/dist/terminal-daemon.mjs
CHANGED
|
@@ -1283,7 +1283,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1283
1283
|
if (!(this instanceof SonicBoom)) {
|
|
1284
1284
|
return new SonicBoom(opts);
|
|
1285
1285
|
}
|
|
1286
|
-
let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append = true, mkdir, retryEAGAIN, fsync, contentMode, mode } = opts || {};
|
|
1286
|
+
let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append = true, mkdir: mkdir2, retryEAGAIN, fsync, contentMode, mode } = opts || {};
|
|
1287
1287
|
fd = fd || dest;
|
|
1288
1288
|
this._len = 0;
|
|
1289
1289
|
this.fd = -1;
|
|
@@ -1308,7 +1308,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1308
1308
|
this.append = append || false;
|
|
1309
1309
|
this.mode = mode;
|
|
1310
1310
|
this.retryEAGAIN = retryEAGAIN || (() => true);
|
|
1311
|
-
this.mkdir =
|
|
1311
|
+
this.mkdir = mkdir2 || false;
|
|
1312
1312
|
let fsWriteSync;
|
|
1313
1313
|
let fsWrite;
|
|
1314
1314
|
if (contentMode === kContentModeBuffer) {
|
|
@@ -2024,7 +2024,7 @@ var require_thread_stream = __commonJS({
|
|
|
2024
2024
|
var { version } = require_package();
|
|
2025
2025
|
var { EventEmitter } = __require("events");
|
|
2026
2026
|
var { Worker } = __require("worker_threads");
|
|
2027
|
-
var { join:
|
|
2027
|
+
var { join: join7 } = __require("path");
|
|
2028
2028
|
var { pathToFileURL } = __require("url");
|
|
2029
2029
|
var { wait } = require_wait();
|
|
2030
2030
|
var {
|
|
@@ -2060,7 +2060,7 @@ var require_thread_stream = __commonJS({
|
|
|
2060
2060
|
function createWorker(stream, opts) {
|
|
2061
2061
|
const { filename, workerData } = opts;
|
|
2062
2062
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
2063
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
2063
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join7(__dirname, "lib", "worker.js");
|
|
2064
2064
|
const worker = new Worker(toExecute, {
|
|
2065
2065
|
...opts.workerOpts,
|
|
2066
2066
|
trackUnmanagedFds: false,
|
|
@@ -2446,7 +2446,7 @@ var require_transport = __commonJS({
|
|
|
2446
2446
|
"use strict";
|
|
2447
2447
|
var { createRequire } = __require("module");
|
|
2448
2448
|
var getCallers = require_caller();
|
|
2449
|
-
var { join:
|
|
2449
|
+
var { join: join7, isAbsolute, sep: sep2 } = __require("node:path");
|
|
2450
2450
|
var sleep = require_atomic_sleep();
|
|
2451
2451
|
var onExit = require_on_exit_leak_free();
|
|
2452
2452
|
var ThreadStream = require_thread_stream();
|
|
@@ -2509,7 +2509,7 @@ var require_transport = __commonJS({
|
|
|
2509
2509
|
throw new Error("only one of target or targets can be specified");
|
|
2510
2510
|
}
|
|
2511
2511
|
if (targets) {
|
|
2512
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
2512
|
+
target = bundlerOverrides["pino-worker"] || join7(__dirname, "worker.js");
|
|
2513
2513
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
2514
2514
|
return {
|
|
2515
2515
|
...dest,
|
|
@@ -2527,7 +2527,7 @@ var require_transport = __commonJS({
|
|
|
2527
2527
|
});
|
|
2528
2528
|
});
|
|
2529
2529
|
} else if (pipeline) {
|
|
2530
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
2530
|
+
target = bundlerOverrides["pino-worker"] || join7(__dirname, "worker.js");
|
|
2531
2531
|
options.pipelines = [pipeline.map((dest) => {
|
|
2532
2532
|
return {
|
|
2533
2533
|
...dest,
|
|
@@ -2549,7 +2549,7 @@ var require_transport = __commonJS({
|
|
|
2549
2549
|
return origin;
|
|
2550
2550
|
}
|
|
2551
2551
|
if (origin === "pino/file") {
|
|
2552
|
-
return
|
|
2552
|
+
return join7(__dirname, "..", "file.js");
|
|
2553
2553
|
}
|
|
2554
2554
|
let fixTarget2;
|
|
2555
2555
|
for (const filePath of callers) {
|
|
@@ -2877,11 +2877,11 @@ var require_tools = __commonJS({
|
|
|
2877
2877
|
}
|
|
2878
2878
|
}
|
|
2879
2879
|
}
|
|
2880
|
-
function buildFormatters(level, bindings,
|
|
2880
|
+
function buildFormatters(level, bindings, log5) {
|
|
2881
2881
|
return {
|
|
2882
2882
|
level,
|
|
2883
2883
|
bindings,
|
|
2884
|
-
log:
|
|
2884
|
+
log: log5
|
|
2885
2885
|
};
|
|
2886
2886
|
}
|
|
2887
2887
|
function normalizeDestFileDescriptor(destination) {
|
|
@@ -3264,11 +3264,11 @@ var require_proto = __commonJS({
|
|
|
3264
3264
|
}
|
|
3265
3265
|
} else instance[serializersSym] = serializers;
|
|
3266
3266
|
if (options.hasOwnProperty("formatters")) {
|
|
3267
|
-
const { level, bindings: chindings, log:
|
|
3267
|
+
const { level, bindings: chindings, log: log5 } = options.formatters;
|
|
3268
3268
|
instance[formattersSym] = buildFormatters(
|
|
3269
3269
|
level || formatters.level,
|
|
3270
3270
|
chindings || resetChildingsFormatter,
|
|
3271
|
-
|
|
3271
|
+
log5 || formatters.log
|
|
3272
3272
|
);
|
|
3273
3273
|
} else {
|
|
3274
3274
|
instance[formattersSym] = buildFormatters(
|
|
@@ -3538,7 +3538,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
3538
3538
|
return circularValue;
|
|
3539
3539
|
}
|
|
3540
3540
|
let res = "";
|
|
3541
|
-
let
|
|
3541
|
+
let join7 = ",";
|
|
3542
3542
|
const originalIndentation = indentation;
|
|
3543
3543
|
if (Array.isArray(value)) {
|
|
3544
3544
|
if (value.length === 0) {
|
|
@@ -3552,7 +3552,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
3552
3552
|
indentation += spacer;
|
|
3553
3553
|
res += `
|
|
3554
3554
|
${indentation}`;
|
|
3555
|
-
|
|
3555
|
+
join7 = `,
|
|
3556
3556
|
${indentation}`;
|
|
3557
3557
|
}
|
|
3558
3558
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -3560,13 +3560,13 @@ ${indentation}`;
|
|
|
3560
3560
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3561
3561
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
3562
3562
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
3563
|
-
res +=
|
|
3563
|
+
res += join7;
|
|
3564
3564
|
}
|
|
3565
3565
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
3566
3566
|
res += tmp !== void 0 ? tmp : "null";
|
|
3567
3567
|
if (value.length - 1 > maximumBreadth) {
|
|
3568
3568
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3569
|
-
res += `${
|
|
3569
|
+
res += `${join7}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3570
3570
|
}
|
|
3571
3571
|
if (spacer !== "") {
|
|
3572
3572
|
res += `
|
|
@@ -3587,7 +3587,7 @@ ${originalIndentation}`;
|
|
|
3587
3587
|
let separator = "";
|
|
3588
3588
|
if (spacer !== "") {
|
|
3589
3589
|
indentation += spacer;
|
|
3590
|
-
|
|
3590
|
+
join7 = `,
|
|
3591
3591
|
${indentation}`;
|
|
3592
3592
|
whitespace = " ";
|
|
3593
3593
|
}
|
|
@@ -3601,13 +3601,13 @@ ${indentation}`;
|
|
|
3601
3601
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
3602
3602
|
if (tmp !== void 0) {
|
|
3603
3603
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
3604
|
-
separator =
|
|
3604
|
+
separator = join7;
|
|
3605
3605
|
}
|
|
3606
3606
|
}
|
|
3607
3607
|
if (keyLength > maximumBreadth) {
|
|
3608
3608
|
const removedKeys = keyLength - maximumBreadth;
|
|
3609
3609
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
3610
|
-
separator =
|
|
3610
|
+
separator = join7;
|
|
3611
3611
|
}
|
|
3612
3612
|
if (spacer !== "" && separator.length > 1) {
|
|
3613
3613
|
res = `
|
|
@@ -3648,7 +3648,7 @@ ${originalIndentation}`;
|
|
|
3648
3648
|
}
|
|
3649
3649
|
const originalIndentation = indentation;
|
|
3650
3650
|
let res = "";
|
|
3651
|
-
let
|
|
3651
|
+
let join7 = ",";
|
|
3652
3652
|
if (Array.isArray(value)) {
|
|
3653
3653
|
if (value.length === 0) {
|
|
3654
3654
|
return "[]";
|
|
@@ -3661,7 +3661,7 @@ ${originalIndentation}`;
|
|
|
3661
3661
|
indentation += spacer;
|
|
3662
3662
|
res += `
|
|
3663
3663
|
${indentation}`;
|
|
3664
|
-
|
|
3664
|
+
join7 = `,
|
|
3665
3665
|
${indentation}`;
|
|
3666
3666
|
}
|
|
3667
3667
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -3669,13 +3669,13 @@ ${indentation}`;
|
|
|
3669
3669
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3670
3670
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
3671
3671
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
3672
|
-
res +=
|
|
3672
|
+
res += join7;
|
|
3673
3673
|
}
|
|
3674
3674
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
3675
3675
|
res += tmp !== void 0 ? tmp : "null";
|
|
3676
3676
|
if (value.length - 1 > maximumBreadth) {
|
|
3677
3677
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3678
|
-
res += `${
|
|
3678
|
+
res += `${join7}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3679
3679
|
}
|
|
3680
3680
|
if (spacer !== "") {
|
|
3681
3681
|
res += `
|
|
@@ -3688,7 +3688,7 @@ ${originalIndentation}`;
|
|
|
3688
3688
|
let whitespace = "";
|
|
3689
3689
|
if (spacer !== "") {
|
|
3690
3690
|
indentation += spacer;
|
|
3691
|
-
|
|
3691
|
+
join7 = `,
|
|
3692
3692
|
${indentation}`;
|
|
3693
3693
|
whitespace = " ";
|
|
3694
3694
|
}
|
|
@@ -3697,7 +3697,7 @@ ${indentation}`;
|
|
|
3697
3697
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
3698
3698
|
if (tmp !== void 0) {
|
|
3699
3699
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
3700
|
-
separator =
|
|
3700
|
+
separator = join7;
|
|
3701
3701
|
}
|
|
3702
3702
|
}
|
|
3703
3703
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -3755,20 +3755,20 @@ ${originalIndentation}`;
|
|
|
3755
3755
|
indentation += spacer;
|
|
3756
3756
|
let res2 = `
|
|
3757
3757
|
${indentation}`;
|
|
3758
|
-
const
|
|
3758
|
+
const join8 = `,
|
|
3759
3759
|
${indentation}`;
|
|
3760
3760
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
3761
3761
|
let i = 0;
|
|
3762
3762
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3763
3763
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
3764
3764
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
3765
|
-
res2 +=
|
|
3765
|
+
res2 += join8;
|
|
3766
3766
|
}
|
|
3767
3767
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
3768
3768
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
3769
3769
|
if (value.length - 1 > maximumBreadth) {
|
|
3770
3770
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3771
|
-
res2 += `${
|
|
3771
|
+
res2 += `${join8}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3772
3772
|
}
|
|
3773
3773
|
res2 += `
|
|
3774
3774
|
${originalIndentation}`;
|
|
@@ -3784,16 +3784,16 @@ ${originalIndentation}`;
|
|
|
3784
3784
|
return '"[Object]"';
|
|
3785
3785
|
}
|
|
3786
3786
|
indentation += spacer;
|
|
3787
|
-
const
|
|
3787
|
+
const join7 = `,
|
|
3788
3788
|
${indentation}`;
|
|
3789
3789
|
let res = "";
|
|
3790
3790
|
let separator = "";
|
|
3791
3791
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
3792
3792
|
if (isTypedArrayWithEntries(value)) {
|
|
3793
|
-
res += stringifyTypedArray(value,
|
|
3793
|
+
res += stringifyTypedArray(value, join7, maximumBreadth);
|
|
3794
3794
|
keys = keys.slice(value.length);
|
|
3795
3795
|
maximumPropertiesToStringify -= value.length;
|
|
3796
|
-
separator =
|
|
3796
|
+
separator = join7;
|
|
3797
3797
|
}
|
|
3798
3798
|
if (deterministic) {
|
|
3799
3799
|
keys = sort(keys, comparator);
|
|
@@ -3804,13 +3804,13 @@ ${indentation}`;
|
|
|
3804
3804
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
3805
3805
|
if (tmp !== void 0) {
|
|
3806
3806
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
3807
|
-
separator =
|
|
3807
|
+
separator = join7;
|
|
3808
3808
|
}
|
|
3809
3809
|
}
|
|
3810
3810
|
if (keyLength > maximumBreadth) {
|
|
3811
3811
|
const removedKeys = keyLength - maximumBreadth;
|
|
3812
3812
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
3813
|
-
separator =
|
|
3813
|
+
separator = join7;
|
|
3814
3814
|
}
|
|
3815
3815
|
if (separator !== "") {
|
|
3816
3816
|
res = `
|
|
@@ -8855,15 +8855,22 @@ function createLogger(name) {
|
|
|
8855
8855
|
|
|
8856
8856
|
// src/server/infra/terminals/daemon/daemon-server.ts
|
|
8857
8857
|
import { randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
|
|
8858
|
-
import { chmodSync as chmodSync2, lstatSync as lstatSync2, readFileSync, renameSync as renameSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
8858
|
+
import { chmodSync as chmodSync2, lstatSync as lstatSync2, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
8859
8859
|
import { createServer } from "node:net";
|
|
8860
|
-
import { dirname as dirname3 } from "node:path";
|
|
8860
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
8861
|
+
|
|
8862
|
+
// src/server/infra/terminals/node-pty-loader.ts
|
|
8863
|
+
var cachedImport;
|
|
8864
|
+
function preloadNodePty() {
|
|
8865
|
+
cachedImport ??= import("node-pty");
|
|
8866
|
+
return cachedImport;
|
|
8867
|
+
}
|
|
8861
8868
|
|
|
8862
8869
|
// src/server/infra/terminals/terminal-pool.ts
|
|
8863
8870
|
import { randomUUID } from "node:crypto";
|
|
8864
8871
|
import { existsSync as existsSync2, unlinkSync, writeFileSync } from "node:fs";
|
|
8865
8872
|
import { tmpdir } from "node:os";
|
|
8866
|
-
import { join, sep } from "node:path";
|
|
8873
|
+
import { join as join3, sep } from "node:path";
|
|
8867
8874
|
|
|
8868
8875
|
// src/server/infra/process/path.ts
|
|
8869
8876
|
import { execFile } from "node:child_process";
|
|
@@ -8925,12 +8932,163 @@ async function shellPath() {
|
|
|
8925
8932
|
return fallback;
|
|
8926
8933
|
}
|
|
8927
8934
|
|
|
8935
|
+
// src/server/infra/terminals/claude-resume.ts
|
|
8936
|
+
import { readdirSync, statSync } from "node:fs";
|
|
8937
|
+
import { homedir } from "node:os";
|
|
8938
|
+
import { join } from "node:path";
|
|
8939
|
+
var CLAUDE_COMMAND_PATTERN = /^claude(\s|$)/;
|
|
8940
|
+
var CLAUDE_RESUME_FLAG_PATTERN = /(^|\s)(--resume|-r)(\s|$)/;
|
|
8941
|
+
var SESSION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8942
|
+
function isResumableClaudeCommand(command) {
|
|
8943
|
+
if (!command) return false;
|
|
8944
|
+
const trimmed = command.trim();
|
|
8945
|
+
return CLAUDE_COMMAND_PATTERN.test(trimmed) && !CLAUDE_RESUME_FLAG_PATTERN.test(trimmed);
|
|
8946
|
+
}
|
|
8947
|
+
function claudeProjectDir(cwd) {
|
|
8948
|
+
return join(homedir(), ".claude", "projects", cwd.replaceAll("/", "-"));
|
|
8949
|
+
}
|
|
8950
|
+
function findLatestClaudeSessionId(cwd) {
|
|
8951
|
+
const dir = claudeProjectDir(cwd);
|
|
8952
|
+
let names;
|
|
8953
|
+
try {
|
|
8954
|
+
names = readdirSync(dir).filter((name) => name.endsWith(".jsonl"));
|
|
8955
|
+
} catch {
|
|
8956
|
+
return null;
|
|
8957
|
+
}
|
|
8958
|
+
let newest = null;
|
|
8959
|
+
for (const name of names) {
|
|
8960
|
+
let mtimeMs;
|
|
8961
|
+
try {
|
|
8962
|
+
mtimeMs = statSync(join(dir, name)).mtimeMs;
|
|
8963
|
+
} catch {
|
|
8964
|
+
continue;
|
|
8965
|
+
}
|
|
8966
|
+
if (!newest || mtimeMs > newest.mtimeMs) {
|
|
8967
|
+
newest = { id: name.slice(0, -".jsonl".length), mtimeMs };
|
|
8968
|
+
}
|
|
8969
|
+
}
|
|
8970
|
+
if (!newest || !SESSION_ID_PATTERN.test(newest.id)) return null;
|
|
8971
|
+
return newest.id;
|
|
8972
|
+
}
|
|
8973
|
+
function buildClaudeResumeCommand(originalCommand, sessionId) {
|
|
8974
|
+
return `${originalCommand.trim()} --resume ${sessionId}`;
|
|
8975
|
+
}
|
|
8976
|
+
|
|
8977
|
+
// src/server/infra/terminals/pty-error-hints.ts
|
|
8978
|
+
var MODULE_LOAD_PATTERN = /Cannot find module|MODULE_NOT_FOUND|pty\.node/i;
|
|
8979
|
+
var RESOURCE_EXHAUSTION_PATTERN = /\b(EMFILE|ENFILE|ENOMEM|EAGAIN)\b/;
|
|
8980
|
+
function hintForPtySpawnError(err) {
|
|
8981
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8982
|
+
if (MODULE_LOAD_PATTERN.test(message)) {
|
|
8983
|
+
return "The terminal service could not load its native module. Restart the terminal service from Settings.";
|
|
8984
|
+
}
|
|
8985
|
+
if (RESOURCE_EXHAUSTION_PATTERN.test(message)) {
|
|
8986
|
+
return "Your system cannot start another terminal process. Close unused terminals and try again.";
|
|
8987
|
+
}
|
|
8988
|
+
return "Failed to start the terminal shell.";
|
|
8989
|
+
}
|
|
8990
|
+
|
|
8991
|
+
// src/server/infra/terminals/terminal-history.ts
|
|
8992
|
+
import { readdirSync as readdirSync2, readFileSync, rmSync } from "node:fs";
|
|
8993
|
+
import { mkdir, rename, writeFile } from "node:fs/promises";
|
|
8994
|
+
import { join as join2 } from "node:path";
|
|
8995
|
+
var log = createLogger("terminal-history");
|
|
8996
|
+
var CHECKPOINT_MAX_BYTES = 5 * 1024 * 1024;
|
|
8997
|
+
var TerminalHistoryManager = class {
|
|
8998
|
+
constructor(historyDir) {
|
|
8999
|
+
this.historyDir = historyDir;
|
|
9000
|
+
}
|
|
9001
|
+
sessionDir(terminalId) {
|
|
9002
|
+
return join2(this.historyDir, encodeURIComponent(terminalId));
|
|
9003
|
+
}
|
|
9004
|
+
readMeta(terminalId) {
|
|
9005
|
+
return readJson(join2(this.sessionDir(terminalId), "meta.json"));
|
|
9006
|
+
}
|
|
9007
|
+
readCheckpoint(terminalId) {
|
|
9008
|
+
return readJson(
|
|
9009
|
+
join2(this.sessionDir(terminalId), "checkpoint.json")
|
|
9010
|
+
);
|
|
9011
|
+
}
|
|
9012
|
+
/**
|
|
9013
|
+
* Async: called from the PTY output hot path (`TerminalPool.onData`), so
|
|
9014
|
+
* this must never block the daemon's single event loop the way the
|
|
9015
|
+
* synchronous `fs` calls it replaced (`writeFileSync`/`renameSync`) would —
|
|
9016
|
+
* a slow or networked filesystem could otherwise delay every other
|
|
9017
|
+
* terminal's output delivery, the exact regression issue #676 fixed for a
|
|
9018
|
+
* different code path.
|
|
9019
|
+
*/
|
|
9020
|
+
async writeMeta(terminalId, meta) {
|
|
9021
|
+
await writeJson(this.sessionDir(terminalId), "meta.json", meta);
|
|
9022
|
+
}
|
|
9023
|
+
async writeCheckpoint(terminalId, checkpoint) {
|
|
9024
|
+
const serialized = JSON.stringify(checkpoint);
|
|
9025
|
+
const bytes = Buffer.byteLength(serialized);
|
|
9026
|
+
if (bytes > CHECKPOINT_MAX_BYTES) {
|
|
9027
|
+
log.warn({ terminalId, bytes }, "terminal history checkpoint too large; skipping this write");
|
|
9028
|
+
return;
|
|
9029
|
+
}
|
|
9030
|
+
await writeJson(this.sessionDir(terminalId), "checkpoint.json", checkpoint, serialized);
|
|
9031
|
+
}
|
|
9032
|
+
/** Drop a terminal's saved history: its tab or workspace was actually closed or deleted. */
|
|
9033
|
+
removeSession(terminalId) {
|
|
9034
|
+
try {
|
|
9035
|
+
rmSync(this.sessionDir(terminalId), { recursive: true, force: true });
|
|
9036
|
+
} catch (err) {
|
|
9037
|
+
log.warn({ err, terminalId }, "failed to remove terminal history directory");
|
|
9038
|
+
}
|
|
9039
|
+
}
|
|
9040
|
+
/**
|
|
9041
|
+
* Drop every saved session whose last known `workspaceId` is `workspaceId`
|
|
9042
|
+
* — used when a workspace is deleted. Scans the whole history directory
|
|
9043
|
+
* rather than the pool's live reverse index, which by then may already be
|
|
9044
|
+
* missing terminals that exited (and were never explicitly killed) before
|
|
9045
|
+
* the workspace was removed.
|
|
9046
|
+
*/
|
|
9047
|
+
removeSessionsForWorkspace(workspaceId) {
|
|
9048
|
+
let names;
|
|
9049
|
+
try {
|
|
9050
|
+
names = readdirSync2(this.historyDir);
|
|
9051
|
+
} catch {
|
|
9052
|
+
return;
|
|
9053
|
+
}
|
|
9054
|
+
for (const name of names) {
|
|
9055
|
+
const dir = join2(this.historyDir, name);
|
|
9056
|
+
const meta = readJson(join2(dir, "meta.json"));
|
|
9057
|
+
if (meta?.workspaceId !== workspaceId) continue;
|
|
9058
|
+
try {
|
|
9059
|
+
rmSync(dir, { recursive: true, force: true });
|
|
9060
|
+
} catch (err) {
|
|
9061
|
+
log.warn({ err, dir }, "failed to remove terminal history directory");
|
|
9062
|
+
}
|
|
9063
|
+
}
|
|
9064
|
+
}
|
|
9065
|
+
};
|
|
9066
|
+
function readJson(path) {
|
|
9067
|
+
try {
|
|
9068
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
9069
|
+
} catch {
|
|
9070
|
+
return null;
|
|
9071
|
+
}
|
|
9072
|
+
}
|
|
9073
|
+
async function writeJson(dir, name, value, serialized) {
|
|
9074
|
+
try {
|
|
9075
|
+
await mkdir(dir, { recursive: true, mode: 448 });
|
|
9076
|
+
const path = join2(dir, name);
|
|
9077
|
+
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
9078
|
+
await writeFile(tmp, serialized ?? JSON.stringify(value), { mode: 384 });
|
|
9079
|
+
await rename(tmp, path);
|
|
9080
|
+
} catch (err) {
|
|
9081
|
+
log.warn({ err, dir, name }, "failed to write terminal history file");
|
|
9082
|
+
}
|
|
9083
|
+
}
|
|
9084
|
+
|
|
8928
9085
|
// src/server/infra/terminals/terminal-pool.ts
|
|
8929
|
-
var
|
|
9086
|
+
var log2 = createLogger("terminal-pool");
|
|
8930
9087
|
var MAX_SCROLLBACK_SIZE = 1e5;
|
|
8931
9088
|
var HEADLESS_SCROLLBACK_LINES = 1e4;
|
|
8932
9089
|
var MAX_COLS = 1e3;
|
|
8933
9090
|
var MAX_ROWS = 1e3;
|
|
9091
|
+
var HISTORY_CHECKPOINT_INTERVAL_MS = 1e4;
|
|
8934
9092
|
var OutputTail = class {
|
|
8935
9093
|
constructor(max) {
|
|
8936
9094
|
this.max = max;
|
|
@@ -8964,6 +9122,22 @@ var OutputTail = class {
|
|
|
8964
9122
|
}
|
|
8965
9123
|
};
|
|
8966
9124
|
var TerminalPool = class {
|
|
9125
|
+
historyStore;
|
|
9126
|
+
/**
|
|
9127
|
+
* terminalIds whose next `onExit` should prune (not checkpoint) their
|
|
9128
|
+
* history: set by an explicit `kill` / `killWorkspace`, i.e. the tab or
|
|
9129
|
+
* workspace is actually being closed or deleted. `killAll` (daemon
|
|
9130
|
+
* shutdown/restart) deliberately never adds to this set, so those sessions
|
|
9131
|
+
* stay cold-restorable.
|
|
9132
|
+
*/
|
|
9133
|
+
pruneHistoryOnExit = /* @__PURE__ */ new Set();
|
|
9134
|
+
/**
|
|
9135
|
+
* In-flight history checkpoint writes (see {@link checkpointHistoryNow}).
|
|
9136
|
+
* `hasPendingHistoryWrites` lets the daemon's shutdown wait for these
|
|
9137
|
+
* before exiting, since they are async and no longer complete before
|
|
9138
|
+
* `onExit` returns.
|
|
9139
|
+
*/
|
|
9140
|
+
pendingHistoryWrites = /* @__PURE__ */ new Set();
|
|
8967
9141
|
/** terminalId -> session */
|
|
8968
9142
|
terminals = /* @__PURE__ */ new Map();
|
|
8969
9143
|
/** workspaceId -> Set<terminalId> (reverse index for workspace-level cleanup) */
|
|
@@ -8988,6 +9162,9 @@ var TerminalPool = class {
|
|
|
8988
9162
|
/** terminalIds with a shrink-and-restore nudge in flight (see
|
|
8989
9163
|
* {@link nudgeResize} for why concurrent nudges must not compound). */
|
|
8990
9164
|
nudging = /* @__PURE__ */ new Set();
|
|
9165
|
+
constructor(options) {
|
|
9166
|
+
this.historyStore = options?.historyDir ? new TerminalHistoryManager(options.historyDir) : null;
|
|
9167
|
+
}
|
|
8991
9168
|
/**
|
|
8992
9169
|
* Spawn (or return the already-spawning/spawned) PTY for a terminalId.
|
|
8993
9170
|
*
|
|
@@ -9014,6 +9191,8 @@ var TerminalPool = class {
|
|
|
9014
9191
|
async spawnNew(workspaceId, terminalId, workspaceRoot, options, extras) {
|
|
9015
9192
|
const shell = defaultShell();
|
|
9016
9193
|
const resolvedPath = await shellPath();
|
|
9194
|
+
const historyMeta = this.historyStore?.readMeta(terminalId) ?? null;
|
|
9195
|
+
const checkpoint = historyMeta?.workspaceId === workspaceId ? this.historyStore?.readCheckpoint(terminalId) ?? null : null;
|
|
9017
9196
|
const env = {};
|
|
9018
9197
|
for (const [key, value] of Object.entries(extras?.baseEnv ?? process.env)) {
|
|
9019
9198
|
if (value != null) {
|
|
@@ -9034,18 +9213,14 @@ var TerminalPool = class {
|
|
|
9034
9213
|
env.BAND_DISPATCH = "terminal";
|
|
9035
9214
|
let cwd = workspaceRoot;
|
|
9036
9215
|
if (options?.cwd) {
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
cwd = resolved;
|
|
9046
|
-
} else {
|
|
9047
|
-
log.warn("Ignoring cwd %s \u2014 directory does not exist", options.cwd);
|
|
9048
|
-
}
|
|
9216
|
+
cwd = resolveSafeCwd(join3(workspaceRoot, options.cwd), workspaceRoot, "cwd", options.cwd) ?? cwd;
|
|
9217
|
+
} else if (checkpoint?.cwd) {
|
|
9218
|
+
cwd = resolveSafeCwd(
|
|
9219
|
+
checkpoint.cwd,
|
|
9220
|
+
workspaceRoot,
|
|
9221
|
+
"saved terminal history cwd",
|
|
9222
|
+
checkpoint.cwd
|
|
9223
|
+
) ?? cwd;
|
|
9049
9224
|
}
|
|
9050
9225
|
if (!existsSync2(cwd)) {
|
|
9051
9226
|
throw new Error(`Workspace directory does not exist: ${cwd}`);
|
|
@@ -9053,16 +9228,16 @@ var TerminalPool = class {
|
|
|
9053
9228
|
if (!existsSync2(shell)) {
|
|
9054
9229
|
throw new Error(`Shell not found: ${shell}`);
|
|
9055
9230
|
}
|
|
9056
|
-
|
|
9231
|
+
log2.debug(
|
|
9057
9232
|
"Spawning shell %s in %s for terminal %s (PATH=%s)",
|
|
9058
9233
|
shell,
|
|
9059
9234
|
cwd,
|
|
9060
9235
|
terminalId,
|
|
9061
9236
|
resolvedPath.slice(0, 200)
|
|
9062
9237
|
);
|
|
9063
|
-
const nodePty = await import("node-pty");
|
|
9064
9238
|
let ptyProcess;
|
|
9065
9239
|
try {
|
|
9240
|
+
const nodePty = await preloadNodePty();
|
|
9066
9241
|
ptyProcess = nodePty.spawn(shell, [], {
|
|
9067
9242
|
name: "xterm-256color",
|
|
9068
9243
|
cols: 80,
|
|
@@ -9072,8 +9247,8 @@ var TerminalPool = class {
|
|
|
9072
9247
|
});
|
|
9073
9248
|
} catch (err) {
|
|
9074
9249
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9075
|
-
|
|
9076
|
-
throw err;
|
|
9250
|
+
log2.error("pty.spawn failed: %s (shell=%s, cwd=%s)", msg, shell, cwd);
|
|
9251
|
+
throw new Error(hintForPtySpawnError(err));
|
|
9077
9252
|
}
|
|
9078
9253
|
let headless;
|
|
9079
9254
|
let serializeAddon;
|
|
@@ -9099,7 +9274,7 @@ var TerminalPool = class {
|
|
|
9099
9274
|
} catch (err) {
|
|
9100
9275
|
ptyProcess.kill();
|
|
9101
9276
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9102
|
-
|
|
9277
|
+
log2.error("headless mirror setup failed for terminal %s: %s", terminalId, msg);
|
|
9103
9278
|
throw err;
|
|
9104
9279
|
}
|
|
9105
9280
|
const session = {
|
|
@@ -9110,11 +9285,25 @@ var TerminalPool = class {
|
|
|
9110
9285
|
workspaceId,
|
|
9111
9286
|
seq: 0,
|
|
9112
9287
|
holds: 0,
|
|
9113
|
-
cleanupOnExit: extras?.cleanupOnExit ?? false
|
|
9288
|
+
cleanupOnExit: extras?.cleanupOnExit ?? false,
|
|
9289
|
+
history: this.historyStore ? {
|
|
9290
|
+
cwd,
|
|
9291
|
+
startedAt: historyMeta?.startedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
9292
|
+
sessionCommand: options?.command ?? historyMeta?.sessionCommand,
|
|
9293
|
+
lastCheckpointAt: 0
|
|
9294
|
+
} : void 0
|
|
9114
9295
|
};
|
|
9115
9296
|
this.terminals.set(terminalId, session);
|
|
9116
|
-
if (
|
|
9117
|
-
|
|
9297
|
+
if (checkpoint) {
|
|
9298
|
+
const restored = `${checkpoint.scrollback}\r
|
|
9299
|
+
\x1B[90m--- session restored ---\x1B[0m\r
|
|
9300
|
+
`;
|
|
9301
|
+
session.scrollback.append(restored);
|
|
9302
|
+
session.headless.write(restored);
|
|
9303
|
+
}
|
|
9304
|
+
const commandToRun = options?.command ?? this.claudeResumeCommand(checkpoint, historyMeta, cwd);
|
|
9305
|
+
if (commandToRun) {
|
|
9306
|
+
this.autoRunCommand(session, commandToRun);
|
|
9118
9307
|
}
|
|
9119
9308
|
let ids = this.workspaceTerminals.get(workspaceId);
|
|
9120
9309
|
if (!ids) {
|
|
@@ -9136,9 +9325,10 @@ var TerminalPool = class {
|
|
|
9136
9325
|
}
|
|
9137
9326
|
}
|
|
9138
9327
|
}
|
|
9328
|
+
this.maybeCheckpointHistory(terminalId, session);
|
|
9139
9329
|
});
|
|
9140
9330
|
ptyProcess.onExit(({ exitCode: exitCode2 }) => {
|
|
9141
|
-
|
|
9331
|
+
log2.debug("Terminal exited: %s (workspace %s)", terminalId, workspaceId);
|
|
9142
9332
|
const explicitlyKilled = !this.terminals.has(terminalId);
|
|
9143
9333
|
this.terminals.delete(terminalId);
|
|
9144
9334
|
this.outputListeners.delete(terminalId);
|
|
@@ -9155,6 +9345,13 @@ var TerminalPool = class {
|
|
|
9155
9345
|
} catch {
|
|
9156
9346
|
}
|
|
9157
9347
|
}
|
|
9348
|
+
if (this.historyStore) {
|
|
9349
|
+
if (this.pruneHistoryOnExit.delete(terminalId)) {
|
|
9350
|
+
this.historyStore.removeSession(terminalId);
|
|
9351
|
+
} else if (session.history) {
|
|
9352
|
+
this.checkpointHistoryNow(terminalId, session);
|
|
9353
|
+
}
|
|
9354
|
+
}
|
|
9158
9355
|
session.headless.dispose();
|
|
9159
9356
|
const event = {
|
|
9160
9357
|
terminalId,
|
|
@@ -9167,12 +9364,86 @@ var TerminalPool = class {
|
|
|
9167
9364
|
try {
|
|
9168
9365
|
listener(event);
|
|
9169
9366
|
} catch (err) {
|
|
9170
|
-
|
|
9367
|
+
log2.warn("exit listener threw for terminal %s: %s", terminalId, err);
|
|
9171
9368
|
}
|
|
9172
9369
|
}
|
|
9173
9370
|
});
|
|
9174
9371
|
return session;
|
|
9175
9372
|
}
|
|
9373
|
+
/**
|
|
9374
|
+
* A resumable Claude Code command for a cold-restored terminal, or
|
|
9375
|
+
* `undefined` if this isn't one: the checkpoint's saved command must look
|
|
9376
|
+
* like a plain `claude` invocation (see `claude-resume.ts`) and there must
|
|
9377
|
+
* be a Claude Code session transcript for `cwd`. Scoped to Claude Code
|
|
9378
|
+
* only — its on-disk session layout is documented and stable; other
|
|
9379
|
+
* agents' formats weren't verified for this feature.
|
|
9380
|
+
*
|
|
9381
|
+
* Takes the already boundary-checked `cwd` the new shell is actually
|
|
9382
|
+
* spawning in, not the checkpoint's raw saved cwd: if that saved cwd fell
|
|
9383
|
+
* outside the workspace root and `cwd` fell back to `workspaceRoot`, the
|
|
9384
|
+
* resume lookup must follow, not probe a directory the spawn itself
|
|
9385
|
+
* decided not to trust.
|
|
9386
|
+
*/
|
|
9387
|
+
claudeResumeCommand(checkpoint, meta, cwd) {
|
|
9388
|
+
const command = meta?.sessionCommand;
|
|
9389
|
+
if (!checkpoint || !command || !isResumableClaudeCommand(command)) return void 0;
|
|
9390
|
+
const sessionId = findLatestClaudeSessionId(cwd);
|
|
9391
|
+
return sessionId ? buildClaudeResumeCommand(command, sessionId) : void 0;
|
|
9392
|
+
}
|
|
9393
|
+
/**
|
|
9394
|
+
* Checkpoint at most every `HISTORY_CHECKPOINT_INTERVAL_MS`, driven by
|
|
9395
|
+
* output arriving. Deferred off the PTY-output hot path via `setImmediate`:
|
|
9396
|
+
* `serialize()` is synchronous CPU work proportional to the scrollback
|
|
9397
|
+
* size, and running it inline in `onData` would delay delivering this (and
|
|
9398
|
+
* every other terminal's already-pending) output on the daemon's single
|
|
9399
|
+
* event loop — the class of regression issue #676 fixed for a different
|
|
9400
|
+
* code path.
|
|
9401
|
+
*/
|
|
9402
|
+
maybeCheckpointHistory(terminalId, session) {
|
|
9403
|
+
if (!this.historyStore || !session.history) return;
|
|
9404
|
+
const now = Date.now();
|
|
9405
|
+
if (now - session.history.lastCheckpointAt < HISTORY_CHECKPOINT_INTERVAL_MS) return;
|
|
9406
|
+
session.history.lastCheckpointAt = now;
|
|
9407
|
+
setImmediate(() => {
|
|
9408
|
+
if (this.terminals.get(terminalId) === session) {
|
|
9409
|
+
this.checkpointHistoryNow(terminalId, session);
|
|
9410
|
+
}
|
|
9411
|
+
});
|
|
9412
|
+
}
|
|
9413
|
+
/**
|
|
9414
|
+
* Serializes the current screen synchronously — the only part of a
|
|
9415
|
+
* checkpoint that must be, since it must run before `headless.dispose()` on
|
|
9416
|
+
* exit — then hands the actual write off to `TerminalHistoryManager`'s async,
|
|
9417
|
+
* non-blocking I/O. The write is tracked in {@link pendingHistoryWrites} so
|
|
9418
|
+
* a daemon shutdown can wait for it rather than exiting mid-write and
|
|
9419
|
+
* losing a session's last checkpoint; `TerminalHistoryManager` logs its own
|
|
9420
|
+
* failures and never rejects, so there is nothing for this method's caller
|
|
9421
|
+
* to await or catch.
|
|
9422
|
+
*/
|
|
9423
|
+
checkpointHistoryNow(terminalId, session) {
|
|
9424
|
+
if (!this.historyStore || !session.history) return;
|
|
9425
|
+
const { cols, rows } = session.headless;
|
|
9426
|
+
const { cwd, startedAt, sessionCommand } = session.history;
|
|
9427
|
+
const pending = Promise.all([
|
|
9428
|
+
this.historyStore.writeCheckpoint(terminalId, {
|
|
9429
|
+
scrollback: session.serializeAddon.serialize(),
|
|
9430
|
+
cwd,
|
|
9431
|
+
cols,
|
|
9432
|
+
rows
|
|
9433
|
+
}),
|
|
9434
|
+
this.historyStore.writeMeta(terminalId, {
|
|
9435
|
+
workspaceId: session.workspaceId,
|
|
9436
|
+
cwd,
|
|
9437
|
+
cols,
|
|
9438
|
+
rows,
|
|
9439
|
+
startedAt,
|
|
9440
|
+
checkpointedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9441
|
+
sessionCommand
|
|
9442
|
+
})
|
|
9443
|
+
]);
|
|
9444
|
+
this.pendingHistoryWrites.add(pending);
|
|
9445
|
+
void pending.finally(() => this.pendingHistoryWrites.delete(pending));
|
|
9446
|
+
}
|
|
9176
9447
|
/**
|
|
9177
9448
|
* Auto-run the workspace's initial command inside a freshly spawned PTY,
|
|
9178
9449
|
* robustly.
|
|
@@ -9204,12 +9475,12 @@ var TerminalPool = class {
|
|
|
9204
9475
|
const pty = session.pty;
|
|
9205
9476
|
let cmdFile;
|
|
9206
9477
|
try {
|
|
9207
|
-
cmdFile =
|
|
9478
|
+
cmdFile = join3(tmpdir(), `band-autorun-${randomUUID()}.sh`);
|
|
9208
9479
|
writeFileSync(cmdFile, `${command}
|
|
9209
9480
|
`, { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
9210
9481
|
session.autoRunFile = cmdFile;
|
|
9211
9482
|
} catch (err) {
|
|
9212
|
-
|
|
9483
|
+
log2.warn(
|
|
9213
9484
|
"autoRunCommand: temp-file staging failed (%s); writing command directly",
|
|
9214
9485
|
err instanceof Error ? err.message : String(err)
|
|
9215
9486
|
);
|
|
@@ -9227,7 +9498,7 @@ var TerminalPool = class {
|
|
|
9227
9498
|
try {
|
|
9228
9499
|
pty.write(sourceLine);
|
|
9229
9500
|
} catch (err) {
|
|
9230
|
-
|
|
9501
|
+
log2.warn("autoRunCommand: failed to inject command line (%s)", err);
|
|
9231
9502
|
}
|
|
9232
9503
|
};
|
|
9233
9504
|
let dataDisposed = false;
|
|
@@ -9480,7 +9751,7 @@ var TerminalPool = class {
|
|
|
9480
9751
|
try {
|
|
9481
9752
|
snapshot = await this.serialize(terminalId);
|
|
9482
9753
|
} catch (err) {
|
|
9483
|
-
|
|
9754
|
+
log2.error("Failed to serialize terminal %s for replay: %s", terminalId, err);
|
|
9484
9755
|
snapshot = { data: "", seq: 0 };
|
|
9485
9756
|
}
|
|
9486
9757
|
if (!snapshot) {
|
|
@@ -9523,6 +9794,7 @@ var TerminalPool = class {
|
|
|
9523
9794
|
kill(terminalId) {
|
|
9524
9795
|
const session = this.terminals.get(terminalId);
|
|
9525
9796
|
if (session) {
|
|
9797
|
+
this.pruneHistoryOnExit.add(terminalId);
|
|
9526
9798
|
session.pty.kill();
|
|
9527
9799
|
this.terminals.delete(terminalId);
|
|
9528
9800
|
const set = this.workspaceTerminals.get(session.workspaceId);
|
|
@@ -9532,6 +9804,8 @@ var TerminalPool = class {
|
|
|
9532
9804
|
this.workspaceTerminals.delete(session.workspaceId);
|
|
9533
9805
|
}
|
|
9534
9806
|
}
|
|
9807
|
+
} else {
|
|
9808
|
+
this.historyStore?.removeSession(terminalId);
|
|
9535
9809
|
}
|
|
9536
9810
|
}
|
|
9537
9811
|
/**
|
|
@@ -9539,15 +9813,18 @@ var TerminalPool = class {
|
|
|
9539
9813
|
*/
|
|
9540
9814
|
killWorkspace(workspaceId) {
|
|
9541
9815
|
const ids = this.workspaceTerminals.get(workspaceId);
|
|
9542
|
-
if (
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9816
|
+
if (ids) {
|
|
9817
|
+
for (const terminalId of ids) {
|
|
9818
|
+
const session = this.terminals.get(terminalId);
|
|
9819
|
+
if (session) {
|
|
9820
|
+
this.pruneHistoryOnExit.add(terminalId);
|
|
9821
|
+
session.pty.kill();
|
|
9822
|
+
this.terminals.delete(terminalId);
|
|
9823
|
+
}
|
|
9548
9824
|
}
|
|
9825
|
+
this.workspaceTerminals.delete(workspaceId);
|
|
9549
9826
|
}
|
|
9550
|
-
this.
|
|
9827
|
+
this.historyStore?.removeSessionsForWorkspace(workspaceId);
|
|
9551
9828
|
}
|
|
9552
9829
|
/**
|
|
9553
9830
|
* Kill every tracked PTY (server shutdown path).
|
|
@@ -9560,7 +9837,27 @@ var TerminalPool = class {
|
|
|
9560
9837
|
this.workspaceTerminals.clear();
|
|
9561
9838
|
this.outputListeners.clear();
|
|
9562
9839
|
}
|
|
9840
|
+
/**
|
|
9841
|
+
* True while a history checkpoint write is still in flight. The daemon's
|
|
9842
|
+
* shutdown polls this alongside its shells' liveness so it never exits
|
|
9843
|
+
* mid-write and loses the last checkpoint a dying session's `onExit`
|
|
9844
|
+
* kicked off (see {@link checkpointHistoryNow}).
|
|
9845
|
+
*/
|
|
9846
|
+
hasPendingHistoryWrites() {
|
|
9847
|
+
return this.pendingHistoryWrites.size > 0;
|
|
9848
|
+
}
|
|
9563
9849
|
};
|
|
9850
|
+
function resolveSafeCwd(candidate, workspaceRoot, label, original) {
|
|
9851
|
+
if (candidate !== workspaceRoot && !candidate.startsWith(workspaceRoot + sep)) {
|
|
9852
|
+
log2.warn("Ignoring %s %s \u2014 resolves outside workspace root %s", label, original, workspaceRoot);
|
|
9853
|
+
return null;
|
|
9854
|
+
}
|
|
9855
|
+
if (!existsSync2(candidate)) {
|
|
9856
|
+
log2.warn("Ignoring %s %s \u2014 directory does not exist", label, original);
|
|
9857
|
+
return null;
|
|
9858
|
+
}
|
|
9859
|
+
return candidate;
|
|
9860
|
+
}
|
|
9564
9861
|
|
|
9565
9862
|
// src/server/infra/terminals/daemon/endpoint.ts
|
|
9566
9863
|
import { randomBytes } from "node:crypto";
|
|
@@ -9570,11 +9867,11 @@ import {
|
|
|
9570
9867
|
lstatSync,
|
|
9571
9868
|
mkdirSync,
|
|
9572
9869
|
renameSync,
|
|
9573
|
-
statSync,
|
|
9870
|
+
statSync as statSync2,
|
|
9574
9871
|
unlinkSync as unlinkSync2
|
|
9575
9872
|
} from "node:fs";
|
|
9576
9873
|
import { connect } from "node:net";
|
|
9577
|
-
import { dirname, join as
|
|
9874
|
+
import { dirname, join as join4 } from "node:path";
|
|
9578
9875
|
var PROBE_TIMEOUT_MS = 500;
|
|
9579
9876
|
var PUBLISH_ATTEMPTS = 3;
|
|
9580
9877
|
function isProvenDead(outcome) {
|
|
@@ -9609,10 +9906,10 @@ function probeEndpoint(socketPath) {
|
|
|
9609
9906
|
});
|
|
9610
9907
|
}
|
|
9611
9908
|
function privateBindPath(socketPath) {
|
|
9612
|
-
return
|
|
9909
|
+
return join4(dirname(socketPath), `.p${randomBytes(5).toString("hex")}`);
|
|
9613
9910
|
}
|
|
9614
9911
|
async function publishEndpoint(boundPath, canonicalPath, supersede2) {
|
|
9615
|
-
const identity = entryIdentity(boundPath,
|
|
9912
|
+
const identity = entryIdentity(boundPath, statSync2);
|
|
9616
9913
|
if (!identity) throw new Error(`Cannot stat the bound daemon socket at ${boundPath}`);
|
|
9617
9914
|
for (let attempt = 0; attempt < PUBLISH_ATTEMPTS; attempt++) {
|
|
9618
9915
|
try {
|
|
@@ -9669,7 +9966,7 @@ function sameEntry(a, b) {
|
|
|
9669
9966
|
function confirmPublished(canonicalPath, identity, superseded) {
|
|
9670
9967
|
let published;
|
|
9671
9968
|
try {
|
|
9672
|
-
const stats =
|
|
9969
|
+
const stats = statSync2(canonicalPath, { bigint: true });
|
|
9673
9970
|
published = { dev: stats.dev, ino: stats.ino };
|
|
9674
9971
|
} catch (err) {
|
|
9675
9972
|
return errorCode(err) === "ENOENT" ? { status: "lost" } : { status: "inconclusive" };
|
|
@@ -9678,7 +9975,7 @@ function confirmPublished(canonicalPath, identity, superseded) {
|
|
|
9678
9975
|
}
|
|
9679
9976
|
function endpointOwnership(canonicalPath, owned) {
|
|
9680
9977
|
try {
|
|
9681
|
-
const stats =
|
|
9978
|
+
const stats = statSync2(canonicalPath, { bigint: true });
|
|
9682
9979
|
return stats.dev === owned.dev && stats.ino === owned.ino ? "owned" : "lost";
|
|
9683
9980
|
} catch (err) {
|
|
9684
9981
|
return errorCode(err) === "ENOENT" ? "lost" : "indeterminate";
|
|
@@ -9706,36 +10003,37 @@ function errorCode(err) {
|
|
|
9706
10003
|
|
|
9707
10004
|
// src/server/infra/terminals/daemon/protocol.ts
|
|
9708
10005
|
import { createHash } from "node:crypto";
|
|
9709
|
-
import { basename, dirname as dirname2, join as
|
|
10006
|
+
import { basename, dirname as dirname2, join as join5 } from "node:path";
|
|
9710
10007
|
var PROTOCOL_VERSION = 1;
|
|
9711
10008
|
var EXIT_ENDPOINT_OCCUPIED = 20;
|
|
9712
10009
|
var EXIT_ENDPOINT_UNAVAILABLE = 21;
|
|
10010
|
+
var EXIT_NODE_PTY_UNAVAILABLE = 22;
|
|
9713
10011
|
var ENDPOINT_LOST_ERROR = "Terminal daemon no longer owns its endpoint";
|
|
9714
10012
|
var MAX_SOCKET_PATH_BYTES = 103;
|
|
9715
10013
|
function daemonPaths(runDir2, version = PROTOCOL_VERSION) {
|
|
9716
|
-
const inRunDir =
|
|
9717
|
-
const socket = Buffer.byteLength(inRunDir) <= MAX_SOCKET_PATH_BYTES ? inRunDir :
|
|
10014
|
+
const inRunDir = join5(runDir2, `terminal-daemon-v${version}.sock`);
|
|
10015
|
+
const socket = Buffer.byteLength(inRunDir) <= MAX_SOCKET_PATH_BYTES ? inRunDir : join5(
|
|
9718
10016
|
shortSocketDir(),
|
|
9719
10017
|
`td-${createHash("sha256").update(runDir2).digest("hex").slice(0, 16)}-v${version}.sock`
|
|
9720
10018
|
);
|
|
9721
10019
|
return {
|
|
9722
10020
|
runDir: runDir2,
|
|
9723
10021
|
socket,
|
|
9724
|
-
token:
|
|
9725
|
-
pid:
|
|
9726
|
-
log:
|
|
10022
|
+
token: join5(runDir2, `terminal-daemon-v${version}.token`),
|
|
10023
|
+
pid: join5(runDir2, `terminal-daemon-v${version}.pid`),
|
|
10024
|
+
log: join5(runDir2, "terminal-daemon.log")
|
|
9727
10025
|
};
|
|
9728
10026
|
}
|
|
9729
10027
|
function retiredDaemonPaths(paths, tag) {
|
|
9730
10028
|
return {
|
|
9731
10029
|
...paths,
|
|
9732
|
-
socket:
|
|
10030
|
+
socket: join5(dirname2(paths.socket), `.r${tag}`),
|
|
9733
10031
|
token: paths.token.replace(/\.token$/, `.retired-${tag}.token`),
|
|
9734
10032
|
pid: paths.pid.replace(/\.pid$/, `.retired-${tag}.pid`)
|
|
9735
10033
|
};
|
|
9736
10034
|
}
|
|
9737
10035
|
function shortSocketDir() {
|
|
9738
|
-
return
|
|
10036
|
+
return join5("/tmp", `band-${process.getuid?.() ?? "user"}`);
|
|
9739
10037
|
}
|
|
9740
10038
|
function writeFrame(socket, message) {
|
|
9741
10039
|
socket.write(`${JSON.stringify(message)}
|
|
@@ -9782,7 +10080,7 @@ function readFrames(socket, onFrame, maxLineBytes = 64 * 1024 * 1024) {
|
|
|
9782
10080
|
}
|
|
9783
10081
|
|
|
9784
10082
|
// src/server/infra/terminals/daemon/daemon-server.ts
|
|
9785
|
-
var
|
|
10083
|
+
var log3 = createLogger("terminal-daemon");
|
|
9786
10084
|
var HELLO_TIMEOUT_MS = 5e3;
|
|
9787
10085
|
var WATCHDOG_INTERVAL_MS = 2e3;
|
|
9788
10086
|
var SHUTDOWN_GRACE_MS = 2e3;
|
|
@@ -9792,10 +10090,16 @@ var STREAM_HOLD_BYTES = 128 * 1024;
|
|
|
9792
10090
|
var SMALL_SESSION_CHARS = 4 * 1024;
|
|
9793
10091
|
async function runDaemon(options) {
|
|
9794
10092
|
const { paths, buildId, supersede: supersede2 } = options;
|
|
10093
|
+
try {
|
|
10094
|
+
await preloadNodePty();
|
|
10095
|
+
} catch (err) {
|
|
10096
|
+
log3.error({ err }, "terminal daemon could not load its native module (node-pty); exiting");
|
|
10097
|
+
return EXIT_NODE_PTY_UNAVAILABLE;
|
|
10098
|
+
}
|
|
9795
10099
|
ensurePrivateDir(paths.runDir);
|
|
9796
10100
|
ensurePrivateDir(dirname3(paths.socket));
|
|
9797
10101
|
const token = randomBytes2(32).toString("hex");
|
|
9798
|
-
const pool = new TerminalPool();
|
|
10102
|
+
const pool = new TerminalPool({ historyDir: join6(dirname3(paths.runDir), "terminal-history") });
|
|
9799
10103
|
const clients = /* @__PURE__ */ new Map();
|
|
9800
10104
|
let shuttingDown = false;
|
|
9801
10105
|
let openConnections = 0;
|
|
@@ -9827,13 +10131,13 @@ async function runDaemon(options) {
|
|
|
9827
10131
|
retired = null;
|
|
9828
10132
|
}
|
|
9829
10133
|
if (outcome.status !== "published") {
|
|
9830
|
-
|
|
10134
|
+
log3.warn({ outcome: outcome.status }, "terminal daemon could not publish its endpoint");
|
|
9831
10135
|
await closeServer(server);
|
|
9832
10136
|
return outcome.status === "occupied" ? EXIT_ENDPOINT_OCCUPIED : EXIT_ENDPOINT_UNAVAILABLE;
|
|
9833
10137
|
}
|
|
9834
10138
|
const identity = outcome.identity;
|
|
9835
10139
|
if (retired) {
|
|
9836
|
-
|
|
10140
|
+
log3.info({ retired: retired.socket }, "terminal daemon superseded a daemon of another build");
|
|
9837
10141
|
}
|
|
9838
10142
|
let probingRetired = false;
|
|
9839
10143
|
writePrivateFile(paths.token, token);
|
|
@@ -9846,7 +10150,7 @@ async function runDaemon(options) {
|
|
|
9846
10150
|
entry: options.entry
|
|
9847
10151
|
};
|
|
9848
10152
|
writePrivateFile(paths.pid, JSON.stringify(pidRecord));
|
|
9849
|
-
|
|
10153
|
+
log3.info({ pid: process.pid, socket: paths.socket, buildId }, "terminal daemon ready");
|
|
9850
10154
|
pool.onExit((event) => {
|
|
9851
10155
|
for (const client of clients.values()) {
|
|
9852
10156
|
client.attached.delete(event.terminalId);
|
|
@@ -9862,7 +10166,7 @@ async function runDaemon(options) {
|
|
|
9862
10166
|
}
|
|
9863
10167
|
if (!endpointLost && endpointOwnership(paths.socket, identity) === "lost") {
|
|
9864
10168
|
endpointLost = true;
|
|
9865
|
-
|
|
10169
|
+
log3.warn({ sessions: pool.size }, "terminal daemon lost its endpoint; draining");
|
|
9866
10170
|
reevaluateIdle();
|
|
9867
10171
|
}
|
|
9868
10172
|
if (retired && !probingRetired) {
|
|
@@ -9873,7 +10177,7 @@ async function runDaemon(options) {
|
|
|
9873
10177
|
if (!isProvenDead(probe) || retired !== target) return;
|
|
9874
10178
|
removeRetiredFiles(target);
|
|
9875
10179
|
retired = null;
|
|
9876
|
-
|
|
10180
|
+
log3.info({ retired: target.socket }, "superseded terminal daemon exited");
|
|
9877
10181
|
reevaluateIdle();
|
|
9878
10182
|
});
|
|
9879
10183
|
}
|
|
@@ -9906,9 +10210,9 @@ async function runDaemon(options) {
|
|
|
9906
10210
|
if (shuttingDown) return;
|
|
9907
10211
|
shuttingDown = true;
|
|
9908
10212
|
if (retired) {
|
|
9909
|
-
|
|
10213
|
+
log3.warn({ retired: retired.socket }, "exiting while a superseded daemon is still running");
|
|
9910
10214
|
}
|
|
9911
|
-
|
|
10215
|
+
log3.info({ reason, sessions: pool.size }, "terminal daemon shutting down");
|
|
9912
10216
|
clearInterval(watchdog);
|
|
9913
10217
|
if (adoptionTimer) clearTimeout(adoptionTimer);
|
|
9914
10218
|
const shells = pool.listAll().map((entry) => entry.pid);
|
|
@@ -9919,7 +10223,7 @@ async function runDaemon(options) {
|
|
|
9919
10223
|
}
|
|
9920
10224
|
const deadline = Date.now() + SHUTDOWN_GRACE_MS;
|
|
9921
10225
|
const waitForShells = setInterval(() => {
|
|
9922
|
-
if (Date.now() < deadline && shells.some(isAlive)) return;
|
|
10226
|
+
if (Date.now() < deadline && (shells.some(isAlive) || pool.hasPendingHistoryWrites())) return;
|
|
9923
10227
|
clearInterval(waitForShells);
|
|
9924
10228
|
process.exit(0);
|
|
9925
10229
|
}, 50);
|
|
@@ -9957,7 +10261,7 @@ async function runDaemon(options) {
|
|
|
9957
10261
|
return;
|
|
9958
10262
|
}
|
|
9959
10263
|
if (hello.buildId !== buildId) {
|
|
9960
|
-
|
|
10264
|
+
log3.info({ daemon: buildId, server: hello.buildId }, "server build differs from daemon");
|
|
9961
10265
|
}
|
|
9962
10266
|
role = hello.role;
|
|
9963
10267
|
client = registerClient(hello.clientId, role, socket);
|
|
@@ -10017,7 +10321,7 @@ async function runDaemon(options) {
|
|
|
10017
10321
|
const socket = client[role];
|
|
10018
10322
|
if (!socket || socket.destroyed) return;
|
|
10019
10323
|
if (socket.writableLength > MAX_STREAM_BACKLOG_BYTES) {
|
|
10020
|
-
|
|
10324
|
+
log3.warn({ clientId: client.id }, "server stopped reading; dropping its connection");
|
|
10021
10325
|
dropClient(client);
|
|
10022
10326
|
return;
|
|
10023
10327
|
}
|
|
@@ -10185,7 +10489,7 @@ function writePrivateFile(path, content) {
|
|
|
10185
10489
|
function copyPrivateFile(from, to) {
|
|
10186
10490
|
let content;
|
|
10187
10491
|
try {
|
|
10188
|
-
content =
|
|
10492
|
+
content = readFileSync2(from, "utf8");
|
|
10189
10493
|
} catch {
|
|
10190
10494
|
return;
|
|
10191
10495
|
}
|
|
@@ -10220,12 +10524,12 @@ function closeServer(server) {
|
|
|
10220
10524
|
}
|
|
10221
10525
|
|
|
10222
10526
|
// terminal-daemon.ts
|
|
10223
|
-
var
|
|
10527
|
+
var log4 = createLogger("terminal-daemon");
|
|
10224
10528
|
process.on("uncaughtException", (err) => {
|
|
10225
|
-
|
|
10529
|
+
log4.error({ err }, "uncaught exception in terminal daemon");
|
|
10226
10530
|
});
|
|
10227
10531
|
process.on("unhandledRejection", (err) => {
|
|
10228
|
-
|
|
10532
|
+
log4.error({ err }, "unhandled rejection in terminal daemon");
|
|
10229
10533
|
});
|
|
10230
10534
|
var { values } = parseArgs({
|
|
10231
10535
|
options: {
|
|
@@ -10236,12 +10540,12 @@ var { values } = parseArgs({
|
|
|
10236
10540
|
});
|
|
10237
10541
|
var runDir = values["run-dir"];
|
|
10238
10542
|
if (!runDir) {
|
|
10239
|
-
|
|
10543
|
+
log4.error("terminal daemon needs --run-dir");
|
|
10240
10544
|
process.exit(2);
|
|
10241
10545
|
}
|
|
10242
10546
|
var supersede = values.supersede?.match(/^(\d+):(\d+)$/);
|
|
10243
10547
|
if (values.supersede !== void 0 && !supersede) {
|
|
10244
|
-
|
|
10548
|
+
log4.error({ supersede: values.supersede }, "terminal daemon got a malformed --supersede");
|
|
10245
10549
|
process.exit(2);
|
|
10246
10550
|
}
|
|
10247
10551
|
var exitCode = await runDaemon({
|