elanous 0.2.35 → 0.2.37
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/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → 8kITumG9GAZ1LwT9POrAR}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{9952.5daf5f94063a2b3e.js → 1262.a89bb27a5b2f844e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1746.3563617ea64023a3.js +115 -0
- package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1dc5a567.9b092bfae3d7099b.js → 1ed5e8af.cf424815c7c0efad.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4705-194e64e47ca0fbdb.js → 2002-a43a3f380df873ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{13.02a07436dec15f89.js → 210.90b2cbd64926cf34.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9512.5a76207a730e0491.js → 2283.edd9627b7bdfb546.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{6866-79aa5b4e47cac6aa.js → 2318-450e75d07605b8fe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{938.66ad1ef0e5abae1c.js → 2375.bf364c85dbb6f085.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +148 -0
- package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +27 -0
- package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3199.6a1a9b0e6cd01dc6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9214.63a510d39178e997.js → 3578.4e9f9948a9a6f2f4.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +36 -0
- package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +90 -0
- package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +226 -0
- package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +287 -0
- package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2018.a741297bce759490.js → 4313.76f232c304a15bde.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1165.bad13fc9151a7288.js → 4324.c99ba3e83eb1b691.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3f7c4ee5.3dde54f01a816613.js → 4337e36d.f42c3b391b3d8f20.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7385.50a308a477bdfc21.js → 4383.18e5c54db3a22c88.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8557-e7898769499cd56f.js → 4725-34bed25720cc326b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5483-dd5d7697f6bdb106.js → 4833-7934c592c5569f00.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{8444.4c26b379ca2b9596.js → 4931.95cc6dbd230774ca.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3408.21d1570602f4b6c0.js → 5046.7fd5cbd859299448.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +104 -0
- package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +1 -0
- package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/58edce7d.f1b0c72acf13b123.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5952.294fc574a8625184.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b6705a4f-b9a9047de9eecfd0.js → 5f6af561-f90b7a67f4f75d13.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +74 -0
- package/apps/pwa/out/_next/static/chunks/6252.240578f10952e091.js +34 -0
- package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5101.e32282718f99ed6f.js → 6680.6a693c28aae4cd19.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4718-17d2af636796a330.js → 6745-5a63492933959dd9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +149 -0
- package/apps/pwa/out/_next/static/chunks/{6236.e18cced2d5ba6afb.js → 6819.be5c9c4d67f22922.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2833-0fe47af99ed13c29.js → 6971-fb5f9dc0a2cb5d2d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{da5176c6.6773b6c5994e1d99.js → 709a918c.4fd3b4e2a32cb4e3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +41 -0
- package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7424.c0fe2a595d4232b5.js +23 -0
- package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +1 -0
- package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7644.17e37ba6f1d4226e.js → 7867.e8725745ddd1d940.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{0368f25d-ad84af92fefee68f.js → 7c5ed21f-f286708e57cf88f7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{359-2250789a2d3499e7.js → 8080-40d781e7704d3671.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +77 -0
- package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +1 -0
- package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +286 -0
- package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +79 -0
- package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b2f6ba4d.fb56fdbbf798df33.js → 8c58d09b.e8724a299658d86f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1530.0e612369b6fd7ea0.js → 9151.a2c51e93f9156dae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4441-875b97f5821ed58a.js → 9175-7d383df15a82e2be.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +1 -0
- package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +94 -0
- package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +1 -0
- package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +64 -0
- package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-3337c6a1328c2674.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-47c5d4db587266bd.js → page-1e5da297557d2354.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-1f5a60f70cb4dd0c.js → page-88a1edbff62eaf1d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-bac7dee94e5eae4a.js → page-443364c9e4a23b31.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-dc0a532f5b9196ec.js → page-ac2c1e6169cfce57.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-c1c80e345fa9d6f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d06f9160.a3d9062f95de8ad7.js → d9815f84.4918f682a45a8502.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{cbe38a15.5a032598e39970c6.js → de8446d3.31b73eb239fecd7b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +1 -0
- package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/docs/goal-context/05-authoring-lessons.jsonl +47 -0
- package/docs/goal-context/README.md +3 -0
- package/graphs/default-loop.yaml +6 -1
- package/graphs/drafts/recipes.yaml +27 -7
- package/graphs/implement-loop.yaml +24 -0
- package/graphs/release/recipes.yaml +6 -0
- package/graphs/release/release-loop.yaml +17 -4
- package/graphs/wizard/recipes.yaml +44 -0
- package/graphs/wizard/wizard-loop.yaml +44 -0
- package/graphs/work/draft-close.yaml +54 -0
- package/graphs/work/green-close.yaml +37 -0
- package/graphs/work/recipes.yaml +46 -1
- package/graphs/work/research-report.yaml +2 -0
- package/graphs/work/run-research.yaml +35 -0
- package/package.json +1 -1
- package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
- package/scripts/boundary-proof-mapping-audit.ts +88 -0
- package/scripts/ci-typecheck-changed.ts +139 -5
- package/scripts/codex-fallback-live-probe.ts +17 -15
- package/scripts/coord-role-pack.ts +1 -1
- package/scripts/first10-gate.ts +416 -0
- package/scripts/fleet/node-setup.sh +32 -2
- package/scripts/fleet/run-light-worker.sh +9 -0
- package/scripts/fleet/wsl-node-setup.sh +432 -0
- package/scripts/gate-0226-failure-census.ts +507 -0
- package/scripts/goals/authoring-metrics.ts +258 -0
- package/scripts/graph-units/draft-close-node.ts +222 -0
- package/scripts/hook-order-sweep.ts +7 -4
- package/scripts/land-global-checks.ts +69 -1
- package/scripts/measure-nl-routing-corpus.ts +207 -2
- package/scripts/release-loop/docs-node.ts +344 -8
- package/scripts/release-loop/gate-closure.ts +48 -0
- package/scripts/release-loop/gate-diff.ts +2 -1
- package/scripts/release-loop/gate-node.ts +249 -53
- package/scripts/release-loop/known-issues-node.ts +6 -4
- package/scripts/release-loop/node-verdict.ts +2 -0
- package/scripts/release-loop/notes-repair.ts +216 -0
- package/scripts/release-loop/prepare-node.ts +61 -5
- package/scripts/release-loop/resume-cap.ts +14 -34
- package/scripts/release-loop/resume-release.ts +151 -15
- package/scripts/release-loop/resume-test-traffic.ts +10 -0
- package/scripts/release-loop/traffic-node.ts +59 -0
- package/scripts/release-loop/traffic-transition.ts +159 -0
- package/scripts/release-loop/version-node.ts +81 -12
- package/scripts/rhythm/daily.ts +137 -3
- package/scripts/train/green-leg.ts +176 -0
- package/scripts/tui-continue-real-evidence.ts +47 -0
- package/scripts/ux-sim.ts +53 -0
- package/skills/README.md +1 -0
- package/src/acp/client.ts +31 -5
- package/src/acp/core-turn-bridge.ts +54 -6
- package/src/acp/stderr-summary.ts +49 -0
- package/src/agent/delegate-hint.ts +16 -0
- package/src/agent/monad-agent-turn.ts +1 -0
- package/src/agent/runner.ts +82 -2
- package/src/agent/task-notification.ts +56 -10
- package/src/agent/terminal-surface.ts +217 -0
- package/src/agent/types.ts +4 -0
- package/src/agent-substrate/pr-reviewer.ts +64 -4
- package/src/agent-substrate/review-intent.ts +29 -2
- package/src/agent-substrate/review-observation.ts +3 -0
- package/src/agent-substrate/self-review-cli.ts +490 -26
- package/src/autopilot/lineage/sources.ts +1 -1
- package/src/autopilot/mission-codebase-gate.ts +141 -12
- package/src/autopilot/pr-manager.ts +89 -18
- package/src/boot/daemon-runtime.ts +35 -3
- package/src/boot/daemon-tools/pty-shell.ts +2 -1
- package/src/boot/daemon-tools/self-implement.ts +1 -0
- package/src/budget/run-usage-rollup.ts +12 -7
- package/src/budget/unified-usage.ts +20 -0
- package/src/budget/usage-outcomes.ts +8 -4
- package/src/capture/tui-self-report.ts +132 -1
- package/src/chat/goal-continue-verdict.ts +41 -0
- package/src/chat/index.ts +30 -4
- package/src/chat/internal-turn-origin.ts +1 -0
- package/src/chat/paste-fold.ts +86 -0
- package/src/chat/tool-render/block.ts +32 -0
- package/src/chat/tool-render/dispatch.ts +2 -20
- package/src/chat/tool-render/result-text.ts +98 -0
- package/src/chat/turn-typeahead.ts +70 -7
- package/src/cli/autopilot-cli.ts +24 -9
- package/src/cli/config-audit.ts +119 -0
- package/src/cli/decisions-cli.ts +7 -4
- package/src/cli/doctor-cli.ts +137 -6
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/herdr-cli.ts +34 -0
- package/src/cli/light-entry-route.ts +6 -3
- package/src/cli/log-event-names.ts +2 -0
- package/src/cli/logs-cli.ts +357 -2
- package/src/cli/make-cli.ts +247 -11
- package/src/cli/memory-cli.ts +30 -1
- package/src/cli/msg-cli.ts +132 -14
- package/src/cli/pr-cli.ts +29 -16
- package/src/cli/pr-granularity.ts +5 -3
- package/src/cli/pr-land-base-read.ts +11 -2
- package/src/cli/pr-land-heavy-remote.ts +6 -3
- package/src/cli/pr-land-overlap-evidence.ts +23 -4
- package/src/cli/pr-land-recovery.ts +117 -1
- package/src/cli/pty-takeover-cli.ts +8 -7
- package/src/cli/release-checklist-read-cli.ts +109 -4
- package/src/cli/release-cli.ts +64 -15
- package/src/cli/release-single-flight.ts +1 -1
- package/src/cli/self-update.ts +23 -5
- package/src/cli/self-utterances-cli.ts +13 -16
- package/src/cli/tasks-card-show.ts +162 -0
- package/src/cli/tasks-cli.ts +868 -352
- package/src/cli/tasks-read-cli.ts +197 -0
- package/src/cli/usage-cli.ts +12 -10
- package/src/context-bus/claude-memory-import.ts +99 -0
- package/src/context-bus/long-term-memory.ts +125 -0
- package/src/core-turn/run-core-turn.ts +4 -2
- package/src/core-turn/run-goal-loop.ts +76 -16
- package/src/core-turn/types.ts +8 -1
- package/src/dashboard/chat/acp-chat.ts +9 -0
- package/src/dashboard/context/keys.ts +8 -31
- package/src/dashboard/index.ts +299 -62
- package/src/dashboard/input/agent-wake.ts +50 -1
- package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
- package/src/dashboard/input/chat-main-slash-command.ts +4 -2
- package/src/dashboard/input/goal-continue.ts +210 -0
- package/src/dashboard/input/goal-interim.ts +2 -0
- package/src/dashboard/input/internal-turn.ts +2 -8
- package/src/dashboard/input/seat-autowake.ts +9 -7
- package/src/dashboard/input/turn-autoheal.ts +52 -0
- package/src/dashboard/replay-preview.ts +25 -0
- package/src/dashboard/seat-boot-preamble.ts +132 -5
- package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -10
- package/src/dashboard/slash-runtime/model-choices.ts +15 -0
- package/src/dashboard/stale-install-check.ts +3 -99
- package/src/dashboard/synchronized-frame-output.ts +74 -0
- package/src/debug/batch-queue.ts +119 -0
- package/src/debug/tui-log-tag.ts +67 -0
- package/src/display/agent-surface.ts +7 -0
- package/src/display/coordinator.ts +45 -12
- package/src/display/resize-listener.ts +41 -20
- package/src/display/synchronized-output-region.ts +60 -0
- package/src/domains/standalone-log-sink.ts +15 -2
- package/src/domains/surface-events.ts +80 -1
- package/src/esc-abort-gate.ts +69 -0
- package/src/exec-requests/planner.ts +37 -2
- package/src/execution-loop/launch-gate.ts +4 -3
- package/src/git-fs/cli-stderr.ts +45 -0
- package/src/git-fs/gh-cli.ts +6 -3
- package/src/git-fs/git-cli.ts +11 -5
- package/src/git-fs/worktree.ts +95 -1
- package/src/graph-runner/graph-cli.ts +44 -2
- package/src/graph-runner/graph-run-api.ts +3 -2
- package/src/graph-runner/runner.ts +37 -16
- package/src/graph-wizard/generate.ts +131 -4
- package/src/graph-wizard/steps.ts +15 -0
- package/src/grounding/proactive-ground.ts +86 -0
- package/src/harness/control-inbox.ts +49 -1
- package/src/harness/harness-cli-command.ts +230 -40
- package/src/harness/harness-incidents.ts +52 -1
- package/src/harness/pod-control-send.ts +33 -5
- package/src/harness/review-adapter.ts +26 -6
- package/src/harness/self-send-remote.ts +69 -0
- package/src/harness/self-send-routing-guard.ts +6 -0
- package/src/harness/self-send-target.ts +4 -3
- package/src/index.ts +443 -25
- package/src/input-core/context-key-runtime.ts +21 -0
- package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
- package/src/light-cli.ts +6 -1
- package/src/llm/route-decision.ts +13 -0
- package/src/llm-tool-name.ts +37 -0
- package/src/llm-tool-schema.ts +35 -0
- package/src/llm-wellformed.ts +70 -0
- package/src/llm.ts +158 -15
- package/src/loops/checker.ts +100 -0
- package/src/loops/consensus.ts +26 -2
- package/src/loops/loop-cli.ts +9 -4
- package/src/loops/msg-wake.ts +35 -39
- package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
- package/src/loops/orchestrator/inbox.ts +59 -11
- package/src/loops/orchestrator/knowhow-pack.ts +364 -0
- package/src/loops/orchestrator/tick.ts +54 -5
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/model-tier/llm-tier-map.ts +12 -17
- package/src/models/prompts.ts +17 -2
- package/src/msg/msg-post-office.ts +116 -0
- package/src/msg/msg-store.ts +17 -0
- package/src/mss/logging/log-store.ts +79 -22
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/decisions-route.ts +38 -18
- package/src/nexus/api/graph-wizard-api.ts +46 -3
- package/src/nexus/api/grid.ts +24 -4
- package/src/nexus/api/http-server.ts +1 -1
- package/src/nexus/api/ops-api.ts +14 -6
- package/src/nexus/boot/register-mcp-clients.ts +263 -38
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
- package/src/nexus/state/state.ts +7 -1
- package/src/oauth/codex-account-store.ts +34 -1
- package/src/onboarding/first-run.ts +37 -6
- package/src/onboarding/web-first.ts +43 -11
- package/src/ops/loops-map.ts +46 -0
- package/src/ops/overview-cache.ts +22 -4
- package/src/ops/overview-collect.ts +12 -6
- package/src/ops/overview.ts +44 -8
- package/src/persona/loader.ts +11 -0
- package/src/persona/types.ts +8 -0
- package/src/policy/llm-policy.ts +3 -1
- package/src/prompt-enhance/enhance.ts +4 -4
- package/src/prompt-library/session-guidance.ts +14 -0
- package/src/provider-summary.ts +8 -0
- package/src/pty-shell/availability.ts +7 -0
- package/src/pty-shell/herdr-agent-report.ts +155 -37
- package/src/pty-shell/herdr-prompt.ts +266 -0
- package/src/pty-shell/herdr-prune-stale.ts +17 -0
- package/src/pty-shell/herdr-sequence-lease.ts +60 -0
- package/src/pty-shell/pty-control-ipc.ts +327 -15
- package/src/pty-shell/pty-special-keys.ts +42 -2
- package/src/pty-shell/registry.ts +25 -15
- package/src/pty-shell/stale-install-check.ts +99 -0
- package/src/pty-shell/tui-run-state.ts +249 -3
- package/src/release-loop/auto-start.ts +20 -2
- package/src/release-loop/checklist.ts +126 -9
- package/src/release-loop/feature-store.ts +9 -9
- package/src/release-loop/landed-but-yellow.ts +93 -12
- package/src/release-loop/rehearsal.ts +36 -20
- package/src/repl/index.ts +27 -1
- package/src/seat-loop/knowhow-lint.ts +1 -1
- package/src/seat-loop/seat-report.ts +1 -0
- package/src/self-dev/ask-launch-flow.ts +86 -10
- package/src/self-dev/decompose-proposal.ts +183 -20
- package/src/self-dev/decompose.ts +61 -0
- package/src/self-dev/dev-cli.ts +37 -3
- package/src/self-dev/dev-pipeline.ts +37 -9
- package/src/self-dev/draft-sweep.ts +241 -16
- package/src/self-dev/draft-triage-rules.ts +50 -5
- package/src/self-dev/glm-credential-guard.ts +77 -0
- package/src/self-dev/graph-journey-nodes.ts +1 -0
- package/src/self-dev/graph-journey-route.ts +12 -2
- package/src/self-dev/orchestrate-cli.ts +68 -3
- package/src/self-dev/orchestrate.ts +116 -17
- package/src/self-dev/review-provider-fallback.ts +45 -7
- package/src/self-dev/run-supervisor.ts +55 -2
- package/src/self-dev/run-types.ts +1 -1
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-run.ts +50 -3
- package/src/self-health/autoheal.ts +153 -0
- package/src/self-health/signatures.ts +6 -0
- package/src/self-implement/device-first.ts +116 -0
- package/src/self-implement/doctor-visit.ts +322 -1
- package/src/self-implement/evidence-command-budget.ts +80 -0
- package/src/self-implement/gate-artifacts.ts +6 -2
- package/src/self-implement/gate-baseline.ts +64 -1
- package/src/self-implement/gate-cli.ts +93 -9
- package/src/self-implement/gate-remote.ts +28 -4
- package/src/self-implement/gate-scope.ts +13 -1
- package/src/self-implement/goal-author-cli.ts +1 -0
- package/src/self-implement/goal-author-decompose.ts +265 -4
- package/src/self-implement/goal-author.ts +366 -26
- package/src/self-implement/goal-elaborate.ts +176 -22
- package/src/self-implement/goal-refine.ts +3 -0
- package/src/self-implement/goal-supervisor-fill.ts +75 -26
- package/src/self-implement/graph-variant.ts +40 -6
- package/src/self-implement/headless-elanous-driver.ts +19 -3
- package/src/self-implement/importer-test-index.ts +215 -2
- package/src/self-implement/knowhow-pack.ts +5 -5
- package/src/self-implement/off-diff-evidence.ts +58 -6
- package/src/self-implement/orchestrator.ts +536 -42
- package/src/self-implement/pod-warm-pool-profile.ts +1 -0
- package/src/self-implement/pwa-import-graph.ts +1 -1
- package/src/self-implement/review-round-brief.ts +300 -0
- package/src/self-implement/rework-policy.ts +44 -0
- package/src/self-implement/run-ledger.ts +278 -6
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/run-ttl.ts +38 -24
- package/src/self-implement/running-runs.ts +17 -3
- package/src/self-implement/scope-adjacency.ts +3 -1
- package/src/self-implement/seams.ts +72 -10
- package/src/self-implement/stop-autoheal.ts +1 -0
- package/src/self-implement/test-seams.ts +13 -1
- package/src/self-implement/train-reach-grouping.ts +8 -2
- package/src/self-implement/wiring-check.ts +358 -0
- package/src/session/chat.ts +7 -1
- package/src/session/id-prefix.ts +60 -0
- package/src/session/index.ts +4 -0
- package/src/session-runtime/index.ts +9 -1
- package/src/shell-env-bootstrap.ts +11 -4
- package/src/skills/runner.ts +4 -2
- package/src/skills/tools/agent.ts +290 -48
- package/src/skills/tools/pty.ts +5 -0
- package/src/skills/tools/schedule-wakeup.ts +23 -4
- package/src/skills/tools/shell.ts +61 -6
- package/src/skills/tools/terminal-modal-inject.ts +1 -2
- package/src/skills/tools/terminal-modal.ts +10 -8
- package/src/skills/url-router.ts +41 -1
- package/src/smart-wizard/run.ts +66 -0
- package/src/status/bar.ts +34 -6
- package/src/status/metrics.ts +12 -1
- package/src/status/status-provider-info.ts +37 -6
- package/src/steward/rejudge-tick.ts +22 -7
- package/src/steward/resync-tick.ts +31 -4
- package/src/steward/ta-repair-event-collect.ts +17 -6
- package/src/task-agent/actions.ts +202 -5
- package/src/task-agent/boundary-proof-mapping.ts +12 -0
- package/src/task-agent/boundary-proof-producer.ts +147 -0
- package/src/task-agent/completion-evidence.ts +2 -1
- package/src/task-agent/green-close-recipe.ts +239 -0
- package/src/task-agent/green-sweep.ts +64 -10
- package/src/task-agent/land-queue.ts +21 -8
- package/src/task-agent/live-moves.ts +70 -9
- package/src/task-agent/map-host-adapter.ts +134 -0
- package/src/task-agent/map-reduce.ts +158 -0
- package/src/task-agent/map-run-ledger.ts +226 -0
- package/src/task-agent/mission.ts +30 -0
- package/src/task-agent/parent-host.ts +21 -11
- package/src/task-agent/rejudge-on-head.ts +87 -5
- package/src/task-agent/repair-cycle.ts +179 -32
- package/src/task-agent/repair-next-move.ts +42 -4
- package/src/task-agent/repair-outcomes.ts +29 -0
- package/src/task-agent/repair-worker.ts +14 -4
- package/src/task-agent/review-prior-fix.ts +12 -2
- package/src/task-agent/shadow.ts +229 -8
- package/src/task-agent/task-card-prefix.ts +2 -0
- package/src/task-agent/task-hand.ts +630 -30
- package/src/task-agent/task-parent-role-llm.ts +45 -0
- package/src/task-agent/tier-split.ts +80 -10
- package/src/task-agent/work-order.ts +53 -2
- package/src/task-orchestrator/dispatcher.ts +46 -1
- package/src/task-orchestrator/generator-prompt.ts +6 -0
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +9 -0
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
- package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +86 -5
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
- package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +11 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +126 -8
- package/src/task-orchestrator/surfaces/pod-provenance.ts +8 -2
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
- package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +491 -36
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +612 -54
- package/src/task-orchestrator/surfaces/self-implement.ts +46 -2
- package/src/testing/linux-env.ts +177 -0
- package/src/tool-runtime/index.ts +15 -2
- package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
- package/src/tty-foreground.ts +155 -0
- package/src/tui/chat/goal-interim.ts +177 -0
- package/src/tui/chat/log-view.ts +205 -18
- package/src/tui/chat/self-health-status.ts +232 -0
- package/src/tui/entry.ts +623 -80
- package/src/tui/input/at-picker.ts +55 -0
- package/src/tui/input/composer.ts +8 -1
- package/src/tui/slash/compact-command.ts +7 -0
- package/src/tui/slash/compact.ts +1 -7
- package/src/tui/slash/resume.ts +98 -0
- package/src/tui/slash/signals.ts +114 -0
- package/src/tui/slash/term-next.ts +71 -0
- package/src/tui-client/local-chat-turn.ts +49 -5
- package/src/tui-client/next-dashboard-runtime.ts +8 -0
- package/src/tui-client/next-loop-command.ts +70 -0
- package/src/tui-client/next-wakeup.ts +191 -0
- package/src/tui.ts +37 -0
- package/src/ui/modal-adapter.ts +2 -2
- package/src/user-config.ts +19 -1
- package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
- package/src/ux-sim/classic-tui-seat-scenarios.ts +670 -0
- package/src/ux-sim/cli-config-audit-device.ts +121 -0
- package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
- package/src/ux-sim/event-monkey.ts +3 -2
- package/src/ux-sim/fake-bin.ts +45 -0
- package/src/ux-sim/fake-gh.ts +174 -0
- package/src/ux-sim/fake-herdr.ts +238 -0
- package/src/ux-sim/fake-kubectl.ts +142 -0
- package/src/ux-sim/fake-llm.ts +116 -6
- package/src/ux-sim/fault-glm-no-credential.ts +116 -0
- package/src/ux-sim/fault-nextmove-dispatch.ts +102 -1
- package/src/ux-sim/fault-scope-escape-lift.ts +33 -6
- package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
- package/src/ux-sim/goal-device.ts +619 -0
- package/src/ux-sim/in-process-cli.ts +22 -5
- package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
- package/src/ux-sim/mock-authoring-first-run.ts +97 -0
- package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
- package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
- package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
- package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
- package/src/ux-sim/next-tui-seat-scenarios.ts +749 -0
- package/src/ux-sim/onboarding-first-run-device.ts +269 -0
- package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
- package/src/ux-sim/resume-picker-device.ts +173 -0
- package/src/ux-sim/session-id-seed.ts +60 -0
- package/src/ux-sim/skills-tools-shell-device.ts +156 -0
- package/src/ux-sim/subagent-tools-device.ts +81 -0
- package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
- package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
- package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
- package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +0 -41
- package/apps/pwa/out/_next/static/chunks/1674.2a65fd5668e1cc5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +0 -24
- package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +0 -74
- package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +0 -148
- package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +0 -34
- package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +0 -77
- package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +0 -62
- package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +0 -90
- package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3589.5444a06bcf6e775c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3677-4215f826f6aa68e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +0 -79
- package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4346.8601952e73bf5803.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +0 -24
- package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +0 -23
- package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +0 -94
- package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/56d372f2.681ab4ec4c998fae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +0 -287
- package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +0 -1
- package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +0 -8
- package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +0 -27
- package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +0 -93
- package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +0 -149
- package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +0 -104
- package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +0 -226
- package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +0 -64
- package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8637.47f5b35afcae5e6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +0 -115
- package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +0 -1
- /package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → 8kITumG9GAZ1LwT9POrAR}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface HerdrSeqStore {
|
|
2
|
+
read(): number | undefined;
|
|
3
|
+
write(seq: number): void;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const DEFAULT_SEQ_WINDOW = 65_536;
|
|
7
|
+
|
|
8
|
+
/** Reserve future sequence values before reporting so a SIGKILL restart can advance past the dead process. */
|
|
9
|
+
export class HerdrSequenceLease {
|
|
10
|
+
private seq = 0;
|
|
11
|
+
private end = 0;
|
|
12
|
+
private stored: number | undefined;
|
|
13
|
+
private ready = false;
|
|
14
|
+
private failed = false;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
private readonly store: HerdrSeqStore,
|
|
18
|
+
private readonly now: () => number,
|
|
19
|
+
private readonly onFailure: (error: unknown) => void,
|
|
20
|
+
private readonly seqWindow = DEFAULT_SEQ_WINDOW,
|
|
21
|
+
) {}
|
|
22
|
+
|
|
23
|
+
next(): number {
|
|
24
|
+
this.initialize();
|
|
25
|
+
const clock = Math.floor(this.now());
|
|
26
|
+
let next = Number.isFinite(clock) ? Math.max(this.seq + 1, clock) : this.seq + 1;
|
|
27
|
+
if (this.stored !== undefined) next = Math.max(next, this.stored + 1);
|
|
28
|
+
if (next > this.end) this.reserve(next);
|
|
29
|
+
this.seq = next;
|
|
30
|
+
return next;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private initialize(): void {
|
|
34
|
+
if (this.ready) return;
|
|
35
|
+
try {
|
|
36
|
+
const stored = this.store.read();
|
|
37
|
+
this.stored = typeof stored === 'number' && Number.isSafeInteger(stored) && stored >= 0 ? stored : undefined;
|
|
38
|
+
} catch (error) { this.fail(error); }
|
|
39
|
+
const clock = Math.floor(this.now());
|
|
40
|
+
this.seq = Number.isFinite(clock) ? Math.max(clock + this.seqWindow, this.stored ?? 0) : (this.stored ?? 0);
|
|
41
|
+
this.reserve(this.seq);
|
|
42
|
+
this.ready = true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private reserve(from: number): void {
|
|
46
|
+
const end = from + this.seqWindow;
|
|
47
|
+
try { this.store.write(end); } catch (error) { this.fail(error); }
|
|
48
|
+
this.end = end;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private fail(error: unknown): void {
|
|
52
|
+
if (this.failed) return;
|
|
53
|
+
this.failed = true;
|
|
54
|
+
this.onFailure(error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function staleHerdrReleaseArgs(paneId: string, source: string, agent: string, seq: number): string[] {
|
|
59
|
+
return ['pane', 'release-agent', paneId, '--source', source, '--agent', agent, '--seq', String(seq)];
|
|
60
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { Database } from 'bun:sqlite';
|
|
2
|
-
import { mkdirSync } from 'node:fs';
|
|
3
|
-
import { dirname } from 'node:path';
|
|
4
|
-
import { ptyManifestDbPath, getPtyManifest, markPtyControlled } from './pty-manifest.js';
|
|
2
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { ptyManifestDbPath, getPtyManifest, markPtyControlled, listPtyManifestRows, listPtyManifestRowsAt } from './pty-manifest.js';
|
|
5
5
|
import { getHarnessRunId } from '../harness/harness-space.js';
|
|
6
6
|
import { renamePty, type PtyControlTarget } from './registry.js';
|
|
7
7
|
import { resizePtyWithOutcome, writePtyWithOutcome, writePtyWithOutcomeDetail } from './pty-write-outcome.js';
|
|
8
8
|
import { resetExternalWriteProvenanceForTesting } from './pty-write-provenance.js';
|
|
9
9
|
import { parsePtyWriteActor, resolveRemoteControlActor, type PtyWriteActor } from './pty-write-arbiter.js';
|
|
10
|
-
import { isPtyAccessMode } from './pty-ref.js';
|
|
10
|
+
import { isPtyAccessMode, resolvePtyRef, type PtyRefReason } from './pty-ref.js';
|
|
11
|
+
import { RemotesStore } from '../cli/remotes.js';
|
|
12
|
+
import { bookmarkToElanousRemote } from '../cli/remote-resolve.js';
|
|
11
13
|
import { debug } from '../debug/log.js';
|
|
12
14
|
import { encodeSgrMouse, mouseModeOffReason, type PtyMouseInput } from './pty-mouse.js';
|
|
13
15
|
import { startPtyRecording, stopPtyRecording } from './pty-recording.js';
|
|
@@ -48,6 +50,17 @@ export interface PtyControlRequestOptions {
|
|
|
48
50
|
readonly timeoutMs?: number;
|
|
49
51
|
/** 대상 PTY를 발견한 매니페스트 뿌리. 연합 조회는 이 DB에 제어 요청을 남겨 그 행의 owner가 처리하게 한다. */
|
|
50
52
|
readonly manifestDbPath?: string;
|
|
53
|
+
/** 요청자 poll 루프의 시계(기본 `Date.now`) — deadline·grace 경계를 재는 유일한 시계다.
|
|
54
|
+
* ⛔ 원장 시각(`created_at`/`updated_at`)은 여전히 `Date.now()` 다 — 원장 형식은 이 옵션에 안 흔들린다. */
|
|
55
|
+
readonly now?: () => number;
|
|
56
|
+
/** 요청자 poll 루프의 대기(기본 `Bun.sleep`) — 기본값에서 25ms cadence 계약은 그대로다. */
|
|
57
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
58
|
+
/** 사람 타이핑 세션 — 있으면 재해석·재캡처 없이 이 «고정값»만 쓴다(`beginPtyHumanTypingSession`). */
|
|
59
|
+
readonly typingSession?: PtyHumanTypingSession;
|
|
60
|
+
/** 아직 세션이 없을 때 캡처할 북마크 이름(없으면 remotes.json 의 default · 그것도 없으면 로컬). */
|
|
61
|
+
readonly bookmarkName?: string;
|
|
62
|
+
/** 호출자가 이미 캡처해 둔 북마크 핀 — 재조회하지 않는다. */
|
|
63
|
+
readonly typingBookmark?: PtyTypingBookmarkPin;
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
export interface PtyControlResult {
|
|
@@ -144,6 +157,138 @@ function cleanupStale(d: Database): void {
|
|
|
144
157
|
d.run("DELETE FROM pty_control_requests WHERE created_at < ? AND status = 'processing'", [now - PTY_CONTROL_PROCESSING_STALE_MS]);
|
|
145
158
|
}
|
|
146
159
|
|
|
160
|
+
// ── TUI-IDLE-PTY-DEEP-IDLE-FU (#29694) — owner 큐 재읽기의 깊은 유휴 감속 ⊕ 첫 요청 즉시 깨움 ──
|
|
161
|
+
//
|
|
162
|
+
// owner 프로세스는 `registry.startPtyControlPoller` 가 **25ms 마다** 부르는 `processPtyControlRequests` 로
|
|
163
|
+
// 제어 큐(같은 SQLite 원장)를 다시 읽는다. 사람이 자리를 비운 채 TUI 가 몇 시간 떠 있으면 그 재읽기가
|
|
164
|
+
// 시간당 14만 번씩 DB 를 두드린다 — 제어가 **10분 넘게** 없었으면 재읽기 간격을 1.5s 로 늦춘다.
|
|
165
|
+
// ⛔ 감속만 넣으면 첫 원격 요청이 최대 1.5s 뒤에야 처리돼 25ms 응답 계약이 깨진다. 그래서 요청자는
|
|
166
|
+
// 큐와 «별도»인 깨어움 표식을 남기고(`signalPtyControlWake`), owner 는 tick 마다 그 파일의 존재만
|
|
167
|
+
// 싸게 확인한다(`consumePtyControlWake`). DB 재읽기보다 훨씬 싸고, 그 tick 안에서 즉시 깬다.
|
|
168
|
+
interface ControlCadenceState {
|
|
169
|
+
/** 마지막 **제어 요청 처리** 시각 — `markPtyControlled` 와 같은 사건을 앵커로 쓴다. */
|
|
170
|
+
lastControlAt: number | null;
|
|
171
|
+
/** 마지막으로 큐를 실제로 **다시 읽은** 시각 — 감속 간격의 기준점. */
|
|
172
|
+
lastDbReadAt: number | null;
|
|
173
|
+
/** 이 상태를 마지막으로 관측한 시계 값 — 시계가 뒤로 가면 앵커를 버린다(시계 교체 감지). */
|
|
174
|
+
lastSeenAt: number | null;
|
|
175
|
+
observed: 'active' | 'deep-idle' | null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** 큐 원장 경로마다 따로 센다 — 원장 경로가 바뀌면(시험용 `setPtyManifestDbPathForTesting`) 이전
|
|
179
|
+
* 경로의 유휴 앵커가 새 원장에 얹히지 않는다. ⛔ 열쇠는 **읽는 원장과 같은 경로**여야 한다
|
|
180
|
+
* (`processPtyControlRequestsOnce` 가 여는 `db()` 와 동일: `ptyManifestDbPath()`). */
|
|
181
|
+
const controlCadence = new Map<string, ControlCadenceState>();
|
|
182
|
+
|
|
183
|
+
function cadenceState(dbPath: string): ControlCadenceState {
|
|
184
|
+
const known = controlCadence.get(dbPath);
|
|
185
|
+
if (known) return known;
|
|
186
|
+
const fresh: ControlCadenceState = { lastControlAt: null, lastDbReadAt: null, lastSeenAt: null, observed: null };
|
|
187
|
+
controlCadence.set(dbPath, fresh);
|
|
188
|
+
return fresh;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** 재읽기를 늦추기 시작하는 유휴 길이. 「10분+ 유휴 뒤 1.5s」의 앞 절반. */
|
|
192
|
+
const PTY_CONTROL_DEEP_IDLE_AFTER_MS = 10 * 60_000;
|
|
193
|
+
/** 깊은 유휴에서의 재읽기 간격. 요청 wake 는 이 간격을 «기다리지 않는다». */
|
|
194
|
+
const PTY_CONTROL_DEEP_IDLE_POLL_MS = 1_500;
|
|
195
|
+
|
|
196
|
+
/** 감속 계단의 두 값과 «계측» 훅 — 생산 기본값은 위 상수 ⊕ env override 다. */
|
|
197
|
+
interface ControlCadenceLimits {
|
|
198
|
+
readonly deepIdleAfterMs: number;
|
|
199
|
+
readonly deepIdlePollMs: number;
|
|
200
|
+
/** 큐를 실제로 다시 읽을 때마다 1회 — 감속 계측용(생산 진입점은 넘기지 않는다). */
|
|
201
|
+
readonly onQueueRead?: () => void;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** 생산 폴러는 옵션 없이 호출되므로 env override 뒤 상수 기본값만 사용한다. */
|
|
205
|
+
function resolveCadenceMs(envName: string, fallback: number): number {
|
|
206
|
+
return positiveInteger(Number(process.env[envName])) ?? fallback;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function cadenceLimits(options: PtyControlProcessOptions): ControlCadenceLimits {
|
|
210
|
+
return {
|
|
211
|
+
deepIdleAfterMs: resolveCadenceMs('ELANOUS_PTY_CONTROL_DEEP_IDLE_AFTER_MS', PTY_CONTROL_DEEP_IDLE_AFTER_MS),
|
|
212
|
+
deepIdlePollMs: resolveCadenceMs('ELANOUS_PTY_CONTROL_DEEP_IDLE_POLL_MS', PTY_CONTROL_DEEP_IDLE_POLL_MS),
|
|
213
|
+
...(options.onQueueRead ? { onQueueRead: options.onQueueRead } : {}),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** 깨어움 표식은 큐와 같은 원장 디렉터리에 둔다 — 요청자와 owner 가 같은 원장(`ptyManifestDbPath`)을
|
|
218
|
+
* 볼 때 owner 의 tick 이 곧바로 그 자리를 본다. 연합 큐(`manifestDbPath`)로 남의 원장에 요청하면
|
|
219
|
+
* 표식은 그 원장 자리에 남고 그 owner 는 감속 간격만큼만 늦다(요청 timeout 안쪽 · fail-soft).
|
|
220
|
+
* ⭐ 표식은 **owner 별** 파일이다(`control-wake-<ownerPid>`) — 요청자는 이미 `ownerPid` 를 알고,
|
|
221
|
+
* 같은 `ELANOUS_STATE_DIR` 원장을 공유하는 여러 프로세스의 `startPtyControlPoller` 가 각자 돌아도
|
|
222
|
+
* 비대상 owner 가 대상 owner 의 표식을 가져가 즉시 깨움(25ms)을 훔치지 못하게 한다. */
|
|
223
|
+
function wakeSignalPath(dbPath: string, ownerPid: number): string {
|
|
224
|
+
return join(dirname(dbPath), `control-wake-${ownerPid}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** 구형 요청자가 남기던 공유 표식 — 읽기 «호환 경로»로만 유지한다(새 경로는 owner 별 파일만 쓴다). */
|
|
228
|
+
function legacyWakeSignalPath(dbPath: string): string {
|
|
229
|
+
return join(dirname(dbPath), 'control-wake');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** 요청자가 대상 owner 의 깨움 표식을 남긴다 — owner «별» 파일(`control-wake-<ownerPid>`). */
|
|
233
|
+
export function signalPtyControlWake(dbPath: string, ownerPid: number): void {
|
|
234
|
+
try {
|
|
235
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
236
|
+
writeFileSync(wakeSignalPath(dbPath, ownerPid), '');
|
|
237
|
+
} catch { /* fail-soft — 표식이 없으면 감속 간격만큼만 늦다(timeout 안쪽) */ }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** «자기» `ownerPid` 의 표식이 있으면 지우고 `true` — 요청자는 행을 «넣은 뒤» 그 행의 owner
|
|
241
|
+
* 표식을 남기므로, 그 owner 의 이 tick 재읽기는 그 행을 반드시 본다. 남의 owner 표식과 구형
|
|
242
|
+
* 공유 표식은 잔존 호환으로 «읽기만» 한다(비대상 owner 가 이 표식을 지울 수는 없다). */
|
|
243
|
+
function consumePtyControlWake(dbPath: string): boolean {
|
|
244
|
+
const own = wakeSignalPath(dbPath, process.pid);
|
|
245
|
+
let woke = false;
|
|
246
|
+
if (existsSync(own)) {
|
|
247
|
+
woke = true;
|
|
248
|
+
try { rmSync(own, { force: true }); } catch { /* 다음 tick 이 다시 지운다 */ }
|
|
249
|
+
}
|
|
250
|
+
const legacy = legacyWakeSignalPath(dbPath);
|
|
251
|
+
if (existsSync(legacy)) {
|
|
252
|
+
woke = true;
|
|
253
|
+
try { rmSync(legacy, { force: true }); } catch { /* 다음 tick 이 다시 지운다 */ }
|
|
254
|
+
}
|
|
255
|
+
return woke;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function observeControlCadence(state: ControlCadenceState, mode: 'active' | 'deep-idle', idleMs: number): void {
|
|
259
|
+
if (state.observed === mode) return;
|
|
260
|
+
state.observed = mode;
|
|
261
|
+
debug.log('pty.control', 'poll-cadence', { mode, idleMs });
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** 깊은 유휴 감속 gate — `false` 면 이번 tick 은 큐를 **다시 읽지 않는다**.
|
|
265
|
+
* ⛔ 첫 tick 은 언제나 읽는다(기동 직후 도착한 요청을 감속 뒤에 두지 않는다).
|
|
266
|
+
* ⛔ 감속 시계는 `pollClock`(기본 `Date.now`) 뿐이다 — `now`(takeover TTL 시계)를 섞으면 시험이
|
|
267
|
+
* 주입한 값이 실제 tick 을 감속시키는 회귀가 난다. */
|
|
268
|
+
function shouldReadControlQueue(dbPath: string, nowMs: number, limits: ControlCadenceLimits): boolean {
|
|
269
|
+
const state = cadenceState(dbPath);
|
|
270
|
+
// 시계가 뒤로 갔다 = 이전 관측과 다른 시계다. 그 앵커로는 유휴를 못 재므로 버리고 다시 센다.
|
|
271
|
+
if (state.lastSeenAt !== null && nowMs < state.lastSeenAt) {
|
|
272
|
+
state.lastControlAt = null;
|
|
273
|
+
state.lastDbReadAt = null;
|
|
274
|
+
state.observed = null;
|
|
275
|
+
}
|
|
276
|
+
state.lastSeenAt = nowMs;
|
|
277
|
+
const woke = consumePtyControlWake(dbPath);
|
|
278
|
+
if (state.lastControlAt === null || woke) state.lastControlAt = nowMs;
|
|
279
|
+
const idleMs = nowMs - state.lastControlAt;
|
|
280
|
+
const deepIdle = idleMs >= limits.deepIdleAfterMs;
|
|
281
|
+
const sinceReadMs = state.lastDbReadAt === null ? Number.POSITIVE_INFINITY : nowMs - state.lastDbReadAt;
|
|
282
|
+
if (!woke && deepIdle && sinceReadMs < limits.deepIdlePollMs) {
|
|
283
|
+
observeControlCadence(state, 'deep-idle', idleMs);
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
state.lastDbReadAt = nowMs;
|
|
287
|
+
observeControlCadence(state, deepIdle ? 'deep-idle' : 'active', idleMs);
|
|
288
|
+
limits.onQueueRead?.();
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
147
292
|
export async function requestRemotePtyControlCapabilities(id: string, options: PtyControlRequestOptions = {}): Promise<PtyControlCapabilitiesResult> {
|
|
148
293
|
const result = await requestRemotePtyControl(id, 'capabilities', undefined, options);
|
|
149
294
|
if (result.status === 'success') {
|
|
@@ -156,40 +301,190 @@ export async function requestRemotePtyControlCapabilities(id: string, options: P
|
|
|
156
301
|
return { status: 'owner-result', result };
|
|
157
302
|
}
|
|
158
303
|
|
|
304
|
+
// ── PTY-HUMAN-TYPING-REMOTE (0.2.36 · UX 칸) — 사람 타이핑의 ref 해석·bookmark 캡처는 «한 번» ──
|
|
305
|
+
//
|
|
306
|
+
// `--remote --human` 타이핑은 호출자가 준 ref(alias·nickname)를 그대로 원장에 흘리면 안 된다:
|
|
307
|
+
// 타이핑 도중 nickname 이 바뀌면 같은 입력이 다른 PTY 로 풀리고, 북마크(host·token·url)가 갈라지면
|
|
308
|
+
// «어느 원격에 쓰는가» 자체가 흔들린다. ⇒ 첫 글자를 넣기 前에 한 번 해석·캡처하고 그 값을 세션 전체에
|
|
309
|
+
// 고정한다. 해석이 확정되기 前에는 원장 행을 «쓰지 않는다»(fail-closed).
|
|
310
|
+
//
|
|
311
|
+
// ⛔ 여기서 해석기를 새로 만들지 않는다 — 목록은 `pty-manifest`(listPtyManifestRows/…At),
|
|
312
|
+
// 해석은 `pty-ref`(resolvePtyRef), 북마크는 `cli/remotes`(RemotesStore) 가 정본이다.
|
|
313
|
+
|
|
314
|
+
/** 사람 타이핑 세션이 고정하는 원격 북마크 신원 — 캡처는 세션 시작 때 한 번뿐이다. */
|
|
315
|
+
export interface PtyTypingBookmarkPin {
|
|
316
|
+
readonly name: string;
|
|
317
|
+
readonly host: string;
|
|
318
|
+
readonly url: string;
|
|
319
|
+
readonly token?: string;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** 타이핑 세션의 고정값 — 이 객체가 사는 동안 재해석·재조회가 없다. */
|
|
323
|
+
export interface PtyHumanTypingSession {
|
|
324
|
+
/** 호출자가 준 ref(그대로 보존 — 원장·로그 대조용). */
|
|
325
|
+
readonly ref: string;
|
|
326
|
+
/** 해석된 canonical pty id — 이후 모든 요청이 쓰는 유일한 주소. */
|
|
327
|
+
readonly ptyId: string;
|
|
328
|
+
/** 어느 단계로 확정됐나(`exact-id`·`nickname-exact`·`kind`·`id-prefix`·`nickname-substr`). */
|
|
329
|
+
readonly resolvedBy: PtyRefReason;
|
|
330
|
+
/** 캡처된 원격 북마크(로컬이면 null). */
|
|
331
|
+
readonly bookmark: PtyTypingBookmarkPin | null;
|
|
332
|
+
/** 해석에 쓴 매니페스트 뿌리 — 연합 요청이면 그 원장이다. */
|
|
333
|
+
readonly manifestDbPath?: string;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface PtyHumanTypingOptions {
|
|
337
|
+
/** 해석에 쓸 매니페스트 뿌리 — 없으면 이 프로세스의 원장(`ptyManifestDbPath`). */
|
|
338
|
+
readonly manifestDbPath?: string;
|
|
339
|
+
/** 이미 읽어 둔 핀(호출자가 캡처를 마친 경우) — 재조회하지 않는다. */
|
|
340
|
+
readonly bookmark?: PtyTypingBookmarkPin;
|
|
341
|
+
/** 캡처할 북마크 이름. 없으면 default 북마크, 그것도 없으면 로컬(null). */
|
|
342
|
+
readonly bookmarkName?: string;
|
|
343
|
+
/** remotes.json 저장소 재정의(시험·연합). */
|
|
344
|
+
readonly remotes?: RemotesStore;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export type PtyHumanTypingResolution =
|
|
348
|
+
| { readonly ok: true; readonly session: PtyHumanTypingSession }
|
|
349
|
+
| {
|
|
350
|
+
readonly ok: false;
|
|
351
|
+
readonly status: 'ambiguous-ref' | 'unresolved-ref' | 'unknown-bookmark';
|
|
352
|
+
/** ambiguous 면 후보 canonical id 들(사람이 고를 수 있게). */
|
|
353
|
+
readonly candidates: readonly string[];
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
type BookmarkCapture = { readonly ok: true; readonly pin: PtyTypingBookmarkPin | null } | { readonly ok: false };
|
|
357
|
+
|
|
358
|
+
function captureTypingBookmark(options: PtyHumanTypingOptions): BookmarkCapture {
|
|
359
|
+
if (options.bookmark) return { ok: true, pin: options.bookmark };
|
|
360
|
+
const wanted = options.bookmarkName?.trim() ?? '';
|
|
361
|
+
try {
|
|
362
|
+
const store = options.remotes ?? new RemotesStore();
|
|
363
|
+
const listed = wanted ? undefined : store.listRemotes().find((item) => item.isDefault);
|
|
364
|
+
const entry = wanted ? store.getRemote(wanted) : listed?.entry;
|
|
365
|
+
if (!entry) return wanted ? { ok: false } : { ok: true, pin: null };
|
|
366
|
+
const token = store.readToken(entry);
|
|
367
|
+
return {
|
|
368
|
+
ok: true,
|
|
369
|
+
pin: {
|
|
370
|
+
name: wanted || listed?.name || entry.host,
|
|
371
|
+
host: entry.host,
|
|
372
|
+
url: bookmarkToElanousRemote(entry),
|
|
373
|
+
...(token ? { token } : {}),
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
} catch {
|
|
377
|
+
return { ok: false };
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* ★ 사람 타이핑 세션 시작 — ref(alias·nickname·id)를 canonical id 로 **한 번** 해석하고
|
|
383
|
+
* bookmark host/token/URL 을 **한 번** 캡처한다. 해석이 확정되지 않으면 세션을 만들지 않는다.
|
|
384
|
+
*
|
|
385
|
+
* 목록은 «한 번의 스냅숏»이다(살아 있는 행만) — 해석 도중 목록이 바뀌어도 이 세션은 흔들리지 않는다.
|
|
386
|
+
*/
|
|
387
|
+
export function beginPtyHumanTypingSession(ref: string, options: PtyHumanTypingOptions = {}): PtyHumanTypingResolution {
|
|
388
|
+
const items = (options.manifestDbPath ? listPtyManifestRowsAt(options.manifestDbPath) : listPtyManifestRows())
|
|
389
|
+
.filter((row) => row.alive)
|
|
390
|
+
.map((row) => ({ id: row.id, kind: row.kind, ...(row.nickname ? { nickname: row.nickname } : {}) }));
|
|
391
|
+
const resolution = resolvePtyRef(ref, items);
|
|
392
|
+
if (!resolution.match) {
|
|
393
|
+
const candidates = resolution.candidates.map((item) => item.id);
|
|
394
|
+
debug.log('pty.control', 'typing-ref-unresolved', { ref, reason: resolution.reason, candidates });
|
|
395
|
+
return { ok: false, status: resolution.reason === 'ambiguous' ? 'ambiguous-ref' : 'unresolved-ref', candidates };
|
|
396
|
+
}
|
|
397
|
+
const captured = captureTypingBookmark(options);
|
|
398
|
+
if (!captured.ok) {
|
|
399
|
+
// ⛔ 명시적으로 부른 북마크를 못 읽었으면 fail-closed. (부르지 않은 default 캡처 실패는 로컬로 떨어진다 — 아래)
|
|
400
|
+
if (options.bookmarkName?.trim()) {
|
|
401
|
+
debug.log('pty.control', 'typing-bookmark-unavailable', { ref, bookmark: options.bookmarkName.trim() });
|
|
402
|
+
return { ok: false, status: 'unknown-bookmark', candidates: [] };
|
|
403
|
+
}
|
|
404
|
+
debug.log('pty.control', 'typing-bookmark-skipped', { ref, reason: 'default-bookmark-unreadable' });
|
|
405
|
+
}
|
|
406
|
+
const session: PtyHumanTypingSession = {
|
|
407
|
+
ref,
|
|
408
|
+
ptyId: resolution.match.id,
|
|
409
|
+
resolvedBy: resolution.reason,
|
|
410
|
+
bookmark: captured.ok ? captured.pin : null,
|
|
411
|
+
...(options.manifestDbPath ? { manifestDbPath: options.manifestDbPath } : {}),
|
|
412
|
+
};
|
|
413
|
+
debug.log('pty.control', 'typing-session-pinned', {
|
|
414
|
+
ref: session.ref,
|
|
415
|
+
ptyId: session.ptyId,
|
|
416
|
+
resolvedBy: session.resolvedBy,
|
|
417
|
+
bookmark: session.bookmark?.name ?? 'local',
|
|
418
|
+
});
|
|
419
|
+
return { ok: true, session };
|
|
420
|
+
}
|
|
421
|
+
|
|
159
422
|
export async function requestRemotePtyControl(id: string, action: PtyControlAction, payloadOrTimeout?: PtyControlPayload | number, timeoutOrOptions: PtyControlRequestOptions | number = {}): Promise<PtyControlResult> {
|
|
160
423
|
const payload = typeof payloadOrTimeout === 'number' ? undefined : payloadOrTimeout;
|
|
161
424
|
const options = typeof timeoutOrOptions === 'number' ? { timeoutMs: timeoutOrOptions } : timeoutOrOptions;
|
|
162
425
|
const timeoutMs = typeof payloadOrTimeout === 'number' ? payloadOrTimeout : options.timeoutMs ?? 2_000;
|
|
163
426
|
const actor: PtyWriteActor = options.actor ?? 'human';
|
|
164
|
-
|
|
427
|
+
// 요청자 poll 루프의 시계·대기 — 기본값이면 종전 그대로(`Date.now` ⊕ 25ms `Bun.sleep`)이고,
|
|
428
|
+
// 시험만 가상 시각으로 deadline·grace 경계와 cadence 를 결정론적으로 민다(벽시계 판별 없음).
|
|
429
|
+
const pollNow = options.now ?? Date.now;
|
|
430
|
+
const pollWait = options.sleep ?? ((ms: number): Promise<void> => Bun.sleep(ms));
|
|
431
|
+
// ⭐ 사람 타이핑(input-text/input-key)은 원장에 «쓰기 前» ref 를 canonical id 로 확정한다.
|
|
432
|
+
// 확정 전에는 행을 안 쓴다(fail-closed) — 미해석·모호한 ref 가 남의 PTY 에 닿지 않게.
|
|
433
|
+
const typingAction = action === 'input-text' || action === 'input-key';
|
|
434
|
+
let session = options.typingSession;
|
|
435
|
+
let targetId = id;
|
|
436
|
+
if (typingAction) {
|
|
437
|
+
if (!session) {
|
|
438
|
+
const started = beginPtyHumanTypingSession(id, {
|
|
439
|
+
...(options.manifestDbPath ? { manifestDbPath: options.manifestDbPath } : {}),
|
|
440
|
+
...(options.bookmarkName ? { bookmarkName: options.bookmarkName } : {}),
|
|
441
|
+
...(options.typingBookmark ? { bookmark: options.typingBookmark } : {}),
|
|
442
|
+
});
|
|
443
|
+
if (!started.ok) {
|
|
444
|
+
return started.status === 'ambiguous-ref'
|
|
445
|
+
? { status: 'denied', reason: 'pty-ref-ambiguous' }
|
|
446
|
+
: started.status === 'unknown-bookmark'
|
|
447
|
+
? { status: 'denied', reason: 'typing-bookmark-unavailable' }
|
|
448
|
+
: { status: 'unknown-pty' };
|
|
449
|
+
}
|
|
450
|
+
session = started.session;
|
|
451
|
+
}
|
|
452
|
+
targetId = session.ptyId;
|
|
453
|
+
}
|
|
454
|
+
// 세션 핀이 연합 원장을 정했으면 그 원장을 쓴다(재해석·재조회 없음).
|
|
455
|
+
const queuePath = options.manifestDbPath ?? session?.manifestDbPath;
|
|
456
|
+
const opened = dbAt(queuePath);
|
|
165
457
|
const d = opened.database;
|
|
166
458
|
try {
|
|
167
459
|
cleanupStale(d);
|
|
168
|
-
const target =
|
|
169
|
-
? d.query('SELECT owner_pid, alive FROM pty_manifest WHERE id=?').get(
|
|
170
|
-
: getPtyManifest(
|
|
460
|
+
const target = queuePath
|
|
461
|
+
? d.query('SELECT owner_pid, alive FROM pty_manifest WHERE id=?').get(targetId) as { owner_pid: number; alive: number } | null
|
|
462
|
+
: getPtyManifest(targetId);
|
|
171
463
|
if (!target || !target.alive) return { status: 'unknown-pty' };
|
|
172
464
|
const ownerPid = 'owner_pid' in target ? target.owner_pid : target.ownerPid;
|
|
173
465
|
const requestId = crypto.randomUUID();
|
|
174
466
|
const now = Date.now();
|
|
175
467
|
// ⭐ 요청자의 run anchor 를 요청에 실어 보낸다 — 인가는 **owner 가** 자기 PTY 의 run 과 대조해 내린다
|
|
176
468
|
// (요청자 자기 신고를 그대로 믿지 않는다는 뜻이 아니라, 판정 지점이 자원 소유자라는 뜻).
|
|
177
|
-
d.run(`INSERT INTO pty_control_requests (request_id, pty_id, action, payload_json, actor, requester_run_id, owner_pid, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [requestId,
|
|
469
|
+
d.run(`INSERT INTO pty_control_requests (request_id, pty_id, action, payload_json, actor, requester_run_id, owner_pid, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [requestId, targetId, action, payload ? JSON.stringify(payload) : null, actor, getHarnessRunId(process.env), ownerPid, 'pending', now, now]);
|
|
470
|
+
// ⭐ 깊은 유휴 감속 중인 owner 를 즉시 깨운다 — 행을 넣은 «뒤» 표식을 남기므로 그 재읽기가 이 행을 본다.
|
|
471
|
+
// 표식은 그 행의 `ownerPid` «별» 파일이다 — 같은 원장을 공유하는 다른 owner 가 가져가지 못한다.
|
|
472
|
+
signalPtyControlWake(queuePath ?? ptyManifestDbPath(), ownerPid);
|
|
178
473
|
const readback = (): ControlRow | null => d.query(SELECT_ROW).get(requestId) as ControlRow | null;
|
|
179
474
|
const del = (): void => { d.run('DELETE FROM pty_control_requests WHERE request_id=?', [requestId]); };
|
|
180
|
-
const deadline =
|
|
181
|
-
while (
|
|
475
|
+
const deadline = pollNow() + timeoutMs;
|
|
476
|
+
while (pollNow() < deadline) {
|
|
182
477
|
const row = readback();
|
|
183
478
|
if (row && settled(row.status)) { del(); return resultFrom(row); }
|
|
184
|
-
await
|
|
479
|
+
await pollWait(25);
|
|
185
480
|
}
|
|
186
481
|
if (d.run("DELETE FROM pty_control_requests WHERE request_id=? AND status='pending'", [requestId]).changes > 0) return { status: 'owner-unreachable' };
|
|
187
|
-
const graceDeadline =
|
|
188
|
-
while (
|
|
482
|
+
const graceDeadline = pollNow() + 500;
|
|
483
|
+
while (pollNow() < graceDeadline) {
|
|
189
484
|
const row = readback();
|
|
190
485
|
if (!row) return { status: 'owner-unreachable' };
|
|
191
486
|
if (settled(row.status)) { del(); return resultFrom(row); }
|
|
192
|
-
await
|
|
487
|
+
await pollWait(25);
|
|
193
488
|
}
|
|
194
489
|
const final = readback();
|
|
195
490
|
if (final && settled(final.status)) { del(); return resultFrom(final); }
|
|
@@ -245,6 +540,10 @@ let inFlight: Promise<void> | null = null;
|
|
|
245
540
|
export interface PtyControlProcessOptions {
|
|
246
541
|
readonly now?: () => number;
|
|
247
542
|
readonly takeoverTtlMs?: number;
|
|
543
|
+
/** 깊은 유휴 감속 계단 **전용** 시계(기본 `Date.now`). `now` 는 takeover TTL 시계라 섞지 않는다. */
|
|
544
|
+
readonly pollClock?: () => number;
|
|
545
|
+
/** 큐를 실제로 다시 읽을 때마다 1회 — 감속 계측용. 생산 진입점은 넘기지 않는다. */
|
|
546
|
+
readonly onQueueRead?: () => void;
|
|
248
547
|
}
|
|
249
548
|
|
|
250
549
|
function positiveInteger(value: unknown): number | undefined {
|
|
@@ -281,6 +580,11 @@ function reapExpiredTakeovers(d: Database, getHandle: (id: string) => PtyControl
|
|
|
281
580
|
|
|
282
581
|
export function processPtyControlRequests(getHandle: (id: string) => PtyControlTarget | undefined, takeover: (id: string, actor: 'human') => boolean, options: PtyControlProcessOptions = {}): Promise<void> {
|
|
283
582
|
if (inFlight) return inFlight;
|
|
583
|
+
// 깊은 유휴 감속(#29694) — 이 함수는 `pty-shell/registry.ts:startPtyControlPoller` 가 25ms 마다 부른다.
|
|
584
|
+
// 감속 구간에서는 여기서 «큐를 다시 읽지 않는» 것으로 끝나고, 첫 원격 요청의 표식이 오면 즉시 통과한다.
|
|
585
|
+
// ⛔ 감속 열쇠는 아래 `processPtyControlRequestsOnce` 가 실제로 여는 원장(`db()` = `ptyManifestDbPath()`)과
|
|
586
|
+
// 같은 경로다 — 상태는 한 큐, 읽기는 다른 큐로 갈라지지 않는다.
|
|
587
|
+
if (!shouldReadControlQueue(ptyManifestDbPath(), (options.pollClock ?? Date.now)(), cadenceLimits(options))) return Promise.resolve();
|
|
284
588
|
inFlight = processPtyControlRequestsOnce(getHandle, takeover, options).finally(() => { inFlight = null; });
|
|
285
589
|
return inFlight;
|
|
286
590
|
}
|
|
@@ -290,6 +594,8 @@ async function processPtyControlRequestsOnce(getHandle: (id: string) => PtyContr
|
|
|
290
594
|
const now = options.now ?? Date.now;
|
|
291
595
|
reapExpiredTakeovers(d, getHandle, now(), resolveTakeoverTtlMs(options));
|
|
292
596
|
const rows = d.query(`SELECT ${ROW_COLUMNS} FROM pty_control_requests WHERE owner_pid=? AND status='pending' ORDER BY created_at ASC`).all(process.pid) as ControlRow[];
|
|
597
|
+
// 제어를 «처리했다» = 유휴 앵커를 지금으로 되감는다(`markPtyControlled` 와 같은 사건).
|
|
598
|
+
if (rows.length > 0) cadenceState(ptyManifestDbPath()).lastControlAt = (options.pollClock ?? Date.now)();
|
|
293
599
|
for (const row of rows) {
|
|
294
600
|
if (d.run("UPDATE pty_control_requests SET status='processing', updated_at=? WHERE request_id=? AND status='pending'", [Date.now(), row.request_id]).changes === 0) continue;
|
|
295
601
|
let requested: PtyWriteActor | null = null;
|
|
@@ -434,6 +740,12 @@ async function processPtyControlRequestsOnce(getHandle: (id: string) => PtyContr
|
|
|
434
740
|
|
|
435
741
|
export function resetPtyControlIpcForTesting(): void {
|
|
436
742
|
database?.close(); database = null;
|
|
743
|
+
// 깊은 유휴 감속 상태(#29694)도 «같이» 비운다 — 남으면 다음 시험/기동이 감속 구간에서 시작한다.
|
|
744
|
+
controlCadence.clear();
|
|
745
|
+
try {
|
|
746
|
+
rmSync(wakeSignalPath(ptyManifestDbPath(), process.pid), { force: true });
|
|
747
|
+
rmSync(legacyWakeSignalPath(ptyManifestDbPath()), { force: true });
|
|
748
|
+
} catch { /* 표식이 없으면 그만 */ }
|
|
437
749
|
// ⛔⭐ 쓰기 출처 맵도 «같이» 비운다 — 별도 export 로만 두면 아무도 안 부르고 테스트 사이에 샌다
|
|
438
750
|
// (오늘 `index.ts:65 readStdinLine` 이 정확히 그 형태로 죽어 있었다).
|
|
439
751
|
resetExternalWriteProvenanceForTesting();
|
|
@@ -30,18 +30,58 @@ function resolveControlKey(normalized: string): string | undefined {
|
|
|
30
30
|
type PtySpecialKey = keyof typeof PTY_SPECIAL_KEYS;
|
|
31
31
|
type PtySpecialKeyAlias = keyof typeof PTY_SPECIAL_KEY_ALIASES;
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
// ── 조합 키 (PTY-KEY-MODIFIERS · 0.2.36 · 2026-10-22) ──────────────────────────────────────
|
|
34
|
+
// `shift+enter` · `alt+enter` · `ctrl+enter` · `ctrl+shift+tab` · `alt+up` … 를 TUI 가 켜 두는 두 프로토콜 중
|
|
35
|
+
// 하나로 보낸다 — 기본 xterm modifyOtherKeys `CSI 27;<mod>;<code>~` · `--kitty` 면 kitty `CSI <code>;<mod>u`.
|
|
36
|
+
// 화살표·home/end 는 `CSI 1;<mod><F>` · delete/pageup/pagedown 은 `CSI <n>;<mod>~`(두 프로토콜 공통).
|
|
37
|
+
// mod = 1 + shift(1) + alt(2) + ctrl(4) — src/tui.ts decodeModifier 와 같은 규약(받는 쪽이 이 값을 그대로 푼다).
|
|
38
|
+
// 수식자 없는 키·`ctrl+<글자>` 는 예전 바이트 그대로(호환).
|
|
39
|
+
export type PtyKeyEncoding = 'xterm' | 'kitty';
|
|
40
|
+
const MODIFIER_BITS: Record<string, number> = { shift: 1, alt: 2, option: 2, ctrl: 4, control: 4 };
|
|
41
|
+
const KEYCODES: Record<string, number> = { enter: 13, tab: 9, esc: 27, escape: 27, space: 32, backspace: 127 };
|
|
42
|
+
const CSI_FINAL: Record<string, string> = { up: 'A', down: 'B', right: 'C', left: 'D', home: 'H', end: 'F' };
|
|
43
|
+
const CSI_TILDE: Record<string, number> = { delete: 3, pageup: 5, pagedown: 6 };
|
|
44
|
+
|
|
45
|
+
function resolveModifiedKey(normalized: string, encoding: PtyKeyEncoding): string | undefined {
|
|
46
|
+
if (!normalized.includes('+') || /^(?:ctrl|control)\+[a-z]$/.test(normalized)) return undefined;
|
|
47
|
+
const parts = normalized.split('+').map((p) => p.trim());
|
|
48
|
+
// 조합은 «이름 있는 키» 에만 — 한 글자(ctrl+1 · meta+c)·빈 칸(ctrl++c)·모르는 이름은 예전처럼 거부한다.
|
|
49
|
+
// 표 조회는 자기 속성만(Object.hasOwn) — «constructor+enter» 같은 프로토타입 이름이 새지 않게(r1 must-fix).
|
|
50
|
+
const key = parts.at(-1) ?? '';
|
|
51
|
+
const mods = parts.slice(0, -1);
|
|
52
|
+
if (!key || mods.length === 0 || mods.some((m) => !m || !Object.hasOwn(MODIFIER_BITS, m))) {
|
|
53
|
+
throw new Error(`unknown PTY special key: ${normalized}; modifiers: shift, alt, ctrl + a named key (enter, tab, esc, space, backspace, up, down, left, right, home, end, delete, pageup, pagedown)`);
|
|
54
|
+
}
|
|
55
|
+
let bits = 0;
|
|
56
|
+
for (const m of mods) bits |= MODIFIER_BITS[m]!;
|
|
57
|
+
const mod = 1 + bits;
|
|
58
|
+
if (Object.hasOwn(CSI_FINAL, key)) return `\x1b[1;${mod}${CSI_FINAL[key]}`;
|
|
59
|
+
if (Object.hasOwn(CSI_TILDE, key)) return `\x1b[${CSI_TILDE[key]};${mod}~`;
|
|
60
|
+
if (Object.hasOwn(KEYCODES, key)) {
|
|
61
|
+
const code = KEYCODES[key]!;
|
|
62
|
+
return encoding === 'kitty' ? `\x1b[${code};${mod}u` : `\x1b[27;${mod};${code}~`;
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`unknown PTY special key: ${normalized}; modifiers apply to named keys only (enter, tab, esc, space, backspace, up, down, left, right, home, end, delete, pageup, pagedown)`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function resolvePtySpecialKey(name: string, opts: { encoding?: PtyKeyEncoding } = {}): string {
|
|
34
68
|
const normalized = name.trim().toLowerCase();
|
|
69
|
+
const encoding = opts.encoding ?? 'xterm';
|
|
35
70
|
const controlBytes = resolveControlKey(normalized);
|
|
36
71
|
if (controlBytes) {
|
|
37
72
|
debug.log('pty.special-key', 'resolved', { inputName: name, resolvedName: normalized, control: true });
|
|
38
73
|
return controlBytes;
|
|
39
74
|
}
|
|
75
|
+
const modified = resolveModifiedKey(normalized, encoding);
|
|
76
|
+
if (modified !== undefined) {
|
|
77
|
+
debug.log('pty.special-key', 'resolved', { inputName: name, resolvedName: normalized, modified: true, encoding });
|
|
78
|
+
return modified;
|
|
79
|
+
}
|
|
40
80
|
const alias = PTY_SPECIAL_KEY_ALIASES[normalized as PtySpecialKeyAlias];
|
|
41
81
|
const resolvedName = alias ?? normalized;
|
|
42
82
|
const bytes = PTY_SPECIAL_KEYS[resolvedName as PtySpecialKey];
|
|
43
83
|
if (!bytes) {
|
|
44
|
-
throw new Error(`unknown PTY special key: ${name}; available names: ${[...Object.keys(PTY_SPECIAL_KEYS), ...Object.keys(PTY_SPECIAL_KEY_ALIASES), 'ctrl+a..ctrl+z'].join(', ')}`);
|
|
84
|
+
throw new Error(`unknown PTY special key: ${name}; available names: ${[...Object.keys(PTY_SPECIAL_KEYS), ...Object.keys(PTY_SPECIAL_KEY_ALIASES), 'ctrl+a..ctrl+z', 'shift|alt|ctrl+<key> (e.g. shift+enter)'].join(', ')}`);
|
|
45
85
|
}
|
|
46
86
|
debug.log('pty.special-key', 'resolved', { inputName: name, resolvedName, alias: alias !== undefined });
|
|
47
87
|
return bytes;
|
|
@@ -23,6 +23,8 @@ import { getSessionCwd } from '../session/working-dir.js';
|
|
|
23
23
|
import { buildPtyEnv } from '../agent/identity-env.js';
|
|
24
24
|
import { getCurrentPtyId } from '../agent/pty-identity.js';
|
|
25
25
|
import { bunNativePtyAvailable, bunSpawnPty } from './bun-native-pty.js';
|
|
26
|
+
import { ptyAvailable } from './availability.js';
|
|
27
|
+
export { ptyAvailable } from './availability.js';
|
|
26
28
|
import { resolvePtyRef, canTransitionAccessMode, ptyIdSeparatorIndex, type PtyAccessMode, type PtyTransitionPolicy } from './pty-ref.js';
|
|
27
29
|
import { resolveWriteDecision, resolveTakeover, type PtyWriteActor } from './pty-write-arbiter.js';
|
|
28
30
|
import { addPtyManifestOutputBytes, upsertPtyManifest, updatePtyManifestSnapshot, updatePtyManifestNickname, markPtyManifestClosed, removePtyManifest, touchLivePtyManifest } from './pty-manifest.js';
|
|
@@ -513,7 +515,7 @@ export function startPty(opts: StartOpts): PtyHandle {
|
|
|
513
515
|
set nickname(v: string | undefined) { nickname = v; },
|
|
514
516
|
setNickname(name: string): void {
|
|
515
517
|
nickname = name.trim() || undefined;
|
|
516
|
-
if (
|
|
518
|
+
if (ptyManifestEnabled()) updatePtyManifestNickname(id, nickname, Date.now());
|
|
517
519
|
},
|
|
518
520
|
get accessMode() { return accessMode; },
|
|
519
521
|
set accessMode(v: PtyAccessMode) { accessMode = v; },
|
|
@@ -718,7 +720,7 @@ export function startPty(opts: StartOpts): PtyHandle {
|
|
|
718
720
|
catch (error) { debug.log('pty.record', 'tap-error', { ptyId: id, error: String(error) }); }
|
|
719
721
|
emitPtyEvent({ type: 'output', id, chunk });
|
|
720
722
|
// ★ 크로스-프로세스 관측(2026-07-23) — throttled 스냅샷을 공유 매니페스트에(데몬 PWA 유니온). getter 라 throttle 통과 시에만 snapshot().
|
|
721
|
-
if (
|
|
723
|
+
if (ptyManifestEnabled()) {
|
|
722
724
|
pendingManifestOutputBytes += Buffer.byteLength(chunk, 'utf8');
|
|
723
725
|
const now = Date.now();
|
|
724
726
|
// ⛔⭐ throttle 이 막은 출력도 «반드시» 실린다 — 안 그러면 마지막 버스트 뒤 조용해진 PTY 의
|
|
@@ -741,7 +743,7 @@ export function startPty(opts: StartOpts): PtyHandle {
|
|
|
741
743
|
try { autoStopPtyRecording(id); }
|
|
742
744
|
catch (error) { debug.log('pty.record', 'auto-stop-error', { ptyId: id, error: String(error) }); }
|
|
743
745
|
emitPtyEvent({ type: 'exit', id, exitCode: code, signal });
|
|
744
|
-
if (
|
|
746
|
+
if (ptyManifestEnabled()) {
|
|
745
747
|
const now = Date.now();
|
|
746
748
|
// Manifest closure and output durability are separate: a closed row keeps retrying trailing bytes until committed.
|
|
747
749
|
manifestOutputFlush.close(now);
|
|
@@ -754,7 +756,7 @@ export function startPty(opts: StartOpts): PtyHandle {
|
|
|
754
756
|
// ★ 크로스-프로세스 관측 — startPty 를 공유 매니페스트에 등록(다른 프로세스 데몬이 /v1/terminals 로 봄). fail-soft.
|
|
755
757
|
// ⚠️ 테스트 런(NODE_ENV=test·bun test)은 skip — 테스트가 띄우는 임시 셸(self-implement gate·CI·수동 bun test)이
|
|
756
758
|
// 운영 매니페스트(~/.elanous/pty)로 새어들어 관측소를 오염시키던 근본 차단(격리). 실 세션(NODE_ENV≠test)만 등록.
|
|
757
|
-
if (
|
|
759
|
+
if (ptyManifestEnabled()) {
|
|
758
760
|
const childSpaceId = opts.env?.ELANOUS_HARNESS_SPACE_ID;
|
|
759
761
|
const childParentPtyId = opts.env?.ELANOUS_PARENT_PTY_ID ?? getCurrentPtyId();
|
|
760
762
|
const childController = opts.env?.ELANOUS_CONTROLLER?.trim();
|
|
@@ -800,8 +802,24 @@ export function startPty(opts: StartOpts): PtyHandle {
|
|
|
800
802
|
return handle;
|
|
801
803
|
}
|
|
802
804
|
|
|
803
|
-
/** 공유 PTY 매니페스트 등록 활성 여부 — 테스트 런(bun test=NODE_ENV=test)은 운영 매니페스트 오염 방지 위해 off.
|
|
804
|
-
|
|
805
|
+
/** 공유 PTY 매니페스트 등록 활성 여부 — 테스트 런(bun test=NODE_ENV=test)은 운영 매니페스트 오염 방지 위해 off.
|
|
806
|
+
*
|
|
807
|
+
* ⭐ 자리(seat) 수명주기는 이 기록자에서만 원장에 실린다 — spawned/exited 사건의 seat·
|
|
808
|
+
* 누적 outputBytesTotal·exitCode 를 남기는 곳이 `upsertPtyManifest`/`markPtyManifestClosed` 이기
|
|
809
|
+
* 때문이다. 그런데 NODE_ENV 판정만 있으면 **격리 test 우주에서는 이 경로를 한 번도 지날 수 없어**
|
|
810
|
+
* 자리 수명주기가 실행 증거를 가질 수 없다(합성 manifest 직접 호출만 남는다 — 완료 경계가 금지).
|
|
811
|
+
* ⇒ 판정을 호출 시점 함수로 두고, 격리 우주(전용 `ELANOUS_STATE_DIR`·전용 manifest db)가 **명시적으로**
|
|
812
|
+
* 켤 수 있는 seam 을 둔다. override 가 없으면 종전과 같은 NODE_ENV 판정이라 운영 동작은 불변이다. */
|
|
813
|
+
let _ptyManifestEnabledOverride: boolean | null = null;
|
|
814
|
+
|
|
815
|
+
/** 테스트 전용 seam — 격리 우주에서 생산 기록 경로를 그대로 지나기 위해 켠다. null = NODE_ENV 판정 복귀. */
|
|
816
|
+
export function setPtyManifestEnabledForTesting(enabled: boolean | null): void {
|
|
817
|
+
_ptyManifestEnabledOverride = enabled;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function ptyManifestEnabled(): boolean {
|
|
821
|
+
return _ptyManifestEnabledOverride ?? process.env.NODE_ENV !== 'test';
|
|
822
|
+
}
|
|
805
823
|
|
|
806
824
|
// ★ 라이브 PTY 하트비트(2026-07-23) — 소유 프로세스가 자기 라이브 PTY 의 updated_at 을 주기 갱신해
|
|
807
825
|
// "살아있음"을 증명한다. 데몬의 stale reap 이 하트비트 끊긴 유령만 제거하도록(pid 재활용 견고). unref 로 프로세스 종료 방해 X.
|
|
@@ -904,7 +922,7 @@ export function renamePty(id: string, nickname: string): boolean {
|
|
|
904
922
|
// 별명은 manifest 행에만 산다. 여기서 받지 않으면 IPC rename 이 그 행에 `unknown-pty` 로 진다.
|
|
905
923
|
const target = controlTargets.get(id);
|
|
906
924
|
if (!target || !target.isAlive()) return false;
|
|
907
|
-
if (
|
|
925
|
+
if (ptyManifestEnabled()) updatePtyManifestNickname(id, nickname.trim() || undefined, Date.now());
|
|
908
926
|
debug.log('pty.rename', 'control-target-renamed', { ptyId: id, nickname: nickname.trim() });
|
|
909
927
|
return true;
|
|
910
928
|
}
|
|
@@ -1012,14 +1030,6 @@ export function killNonDetached(): number {
|
|
|
1012
1030
|
return killed;
|
|
1013
1031
|
}
|
|
1014
1032
|
|
|
1015
|
-
/** Probe-compatible. Under Bun the native PTY (Bun.spawn terminal) is
|
|
1016
|
-
* used instead of node-pty, so PTY is available even if node-pty can't
|
|
1017
|
-
* resolve. Under node we still require node-pty. */
|
|
1018
|
-
export function ptyAvailable(): boolean {
|
|
1019
|
-
if (bunNativePtyAvailable()) return true;
|
|
1020
|
-
try { require.resolve('node-pty'); return true; } catch { return false; }
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
1033
|
// ─── Adapter wiring ──────────────────────────────────────────────
|
|
1024
1034
|
|
|
1025
1035
|
let cachedSpawn: ((opts: StartOpts) => PtyAdapter) | null | undefined = undefined;
|