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
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// codex·elanous 자격 파일은 이 Job 에 없다. 격리 관문(호스트 넥서스에 닿으면 종료)은 기존 Job 과 같다.
|
|
6
6
|
// 명령 인자는 셸 문자열로 이어붙이지 않고 `"$@"` 로 따로 인용한다.
|
|
7
7
|
|
|
8
|
-
import { randomBytes } from 'node:crypto';
|
|
8
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
9
9
|
import { spawnSync } from 'node:child_process';
|
|
10
10
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import { isAbsolute, resolve } from 'node:path';
|
|
@@ -229,12 +229,18 @@ export interface PodCommandJobInput {
|
|
|
229
229
|
/** W5 — emptyDir{medium: Memory} sizeLimit mounted at {@link POD_TMPFS_MOUNT_PATH} ⊕ `TMPDIR` (release gate shards only). Omitted = image `/tmp`. */
|
|
230
230
|
tmpfsSizeLimit?: string;
|
|
231
231
|
source?: PodSource;
|
|
232
|
+
/** Verified producer files, delivered into this Job's own source tree. */
|
|
233
|
+
warmFiles?: readonly string[];
|
|
232
234
|
deadlineSeconds: number;
|
|
233
235
|
runId?: string;
|
|
234
236
|
/** GATE-WARM-BOOT-NO-INIT fallback: the node-side hand-over did not run, so a root init container hands the hostPath dirs to uid 1000. */
|
|
235
237
|
hostDirsInit?: boolean;
|
|
236
238
|
}
|
|
237
239
|
|
|
240
|
+
function warmSourceName(name: string, launch: string): string {
|
|
241
|
+
return `${name.slice(0, 50).replace(/-+$/, '')}-${launch}`;
|
|
242
|
+
}
|
|
243
|
+
|
|
238
244
|
function bashSingleQuote(value: string): string {
|
|
239
245
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
240
246
|
}
|
|
@@ -282,6 +288,10 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
|
|
|
282
288
|
...(o.clone
|
|
283
289
|
? ['export GH_TOKEN="$(cat /creds/gh-token)" && gh auth setup-git', podSourceScript(o.source ?? { kind: 'default' }, o.repoUrl)]
|
|
284
290
|
: ['mkdir -p ~/work && cd ~/work']),
|
|
291
|
+
...(o.warmFiles?.length ? [
|
|
292
|
+
`if [ "$(git rev-parse HEAD)" != ${bashSingleQuote(o.source?.kind === 'commit' ? o.source.sha : '')} ]; then echo '[warm-source] commit mismatch'; exit 5; fi`,
|
|
293
|
+
...o.warmFiles.map((path, i) => `install -m 644 -D /warm-source/file-${i} ${bashSingleQuote(`./${path}`)} || exit 5\nprintf 'ELANOUS_WARM_SOURCE %s %s %s\\n' ${bashSingleQuote(path)} "$(sha256sum ${bashSingleQuote(`./${path}`)} | cut -d ' ' -f1)" "$(git rev-parse HEAD)"`),
|
|
294
|
+
] : []),
|
|
285
295
|
...(hostDirMounts.length ? [podHostDirsCheckScript(hostDirMounts)] : []),
|
|
286
296
|
...(bunCache ? [bunCache.shellPrefix] : []),
|
|
287
297
|
`set -- ${quotedArgs}`,
|
|
@@ -325,14 +335,16 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
|
|
|
325
335
|
...(provenance?.env ?? []),
|
|
326
336
|
...(tmpfs ? [{ name: 'TMPDIR', value: POD_TMPFS_MOUNT_PATH }] : []),
|
|
327
337
|
],
|
|
328
|
-
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumeMounts: [
|
|
338
|
+
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs || o.warmFiles?.length ? { volumeMounts: [
|
|
339
|
+
...(o.warmFiles?.length ? [{ name: 'warm-source', mountPath: '/warm-source', readOnly: true }] : []),
|
|
329
340
|
...(secretKeys ? [{ name: 'creds', mountPath: '/creds', readOnly: true }] : []),
|
|
330
341
|
...(o.hostMirror ? [{ name: 'host-mirror', mountPath: '/host-mirror', readOnly: true }] : []),
|
|
331
342
|
...hostDirMounts,
|
|
332
343
|
...tmpfsMounts,
|
|
333
344
|
] } : {}),
|
|
334
345
|
}],
|
|
335
|
-
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumes: [
|
|
346
|
+
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs || o.warmFiles?.length ? { volumes: [
|
|
347
|
+
...(o.warmFiles?.length ? [{ name: 'warm-source', configMap: { name: warmSourceName(o.name, o.launch ?? 'source') } }] : []),
|
|
336
348
|
...(secretKeys ? [{ name: 'creds', secret: { secretName: `${o.name}-creds`, defaultMode: 0o400 } }] : []),
|
|
337
349
|
...(o.hostMirror ? [{ name: 'host-mirror', hostPath: { path: o.hostMirror, type: 'Directory' } }] : []),
|
|
338
350
|
...(bunCache ? [bunCache.volume] : []),
|
|
@@ -422,6 +434,8 @@ export interface RunPodCommandOptions {
|
|
|
422
434
|
/** POD7: 호출부가 «네트워크 스킬만 쓰는 명령»이라고 말할 때만 lite 이미지 ⊕ 2Gi. */
|
|
423
435
|
lite?: boolean;
|
|
424
436
|
source?: PodSource;
|
|
437
|
+
/** Opt-in handoff from an existing producer Pod in the same namespace. */
|
|
438
|
+
warmProducer?: { pod: string; podUid: string; context: string; image: string; commit: string; files: readonly [string, string] };
|
|
425
439
|
ghToken?: () => string;
|
|
426
440
|
deadlineSeconds?: number;
|
|
427
441
|
namespace?: string;
|
|
@@ -553,6 +567,12 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
553
567
|
const sleep = options.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
|
|
554
568
|
const namespace = options.namespace ?? 'elanous-test';
|
|
555
569
|
const image = options.image ?? podCommandImageFor(skills, options.clone === true, options.lite === true);
|
|
570
|
+
if (options.warmProducer && (!options.clone || options.source?.kind !== 'commit' || options.source.sha !== options.warmProducer.commit || options.image !== options.warmProducer.image || options.imageCommit !== options.warmProducer.commit)) {
|
|
571
|
+
throw new Error('pod warm source: consumer image and source commit must match producer');
|
|
572
|
+
}
|
|
573
|
+
if (options.warmProducer && (!/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(options.warmProducer.pod) || !options.warmProducer.podUid || typeof options.warmProducer.context !== 'string' || !/^[0-9a-f]{40}$/.test(options.warmProducer.commit) || options.warmProducer.files.length !== 2 || options.warmProducer.files.some((path) => !path || path.startsWith('/') || path.split('/').some((part) => !part || part === '.' || part === '..' || !/^[\w.-]+$/.test(part))))) {
|
|
574
|
+
throw new Error('pod warm source: invalid producer identity, commit or file path');
|
|
575
|
+
}
|
|
556
576
|
if (options.shelfImage && (options.image !== options.shelfImage || !options.imageCommit || !options.clone || options.source?.kind !== 'commit' || options.source.sha !== options.imageCommit)) {
|
|
557
577
|
throw new Error('pod shelf: image and source commit must match');
|
|
558
578
|
}
|
|
@@ -615,6 +635,9 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
615
635
|
const kubectlRaw: Kubectl = (args, stdin) => baseKubectl(context ? ['--context', context, ...args] : [...args], stdin);
|
|
616
636
|
const kubectl: Kubectl = (args, stdin) => { ensureLive(); const result = kubectlRaw(args, stdin); ensureLive(); return result; };
|
|
617
637
|
const cleanupSecret = () => { kubectlRaw(['-n', namespace, 'delete', 'secret', '-l', own, '--ignore-not-found']); };
|
|
638
|
+
const cleanupWarmSource = () => {
|
|
639
|
+
if (options.warmProducer) kubectlRaw(['-n', namespace, 'delete', 'configmap', '-l', own, '--ignore-not-found']);
|
|
640
|
+
};
|
|
618
641
|
const artifactRoot = options.artifactsRoot ?? `${effectiveInstanceRoot()}/pod-artifacts`;
|
|
619
642
|
const artifactsDir = `${artifactRoot}/${name}`;
|
|
620
643
|
let jobApplied = false;
|
|
@@ -648,7 +671,11 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
648
671
|
const localSkillsDigest = options.kubectl ? null : image === POD_LITE_IMAGE
|
|
649
672
|
? podSkillsDigest(POD_NETWORK_SKILLS, resolve(import.meta.dir, '../../../skills')).digest
|
|
650
673
|
: podSkillsDigest(resolvePodSkills(env).skills).digest;
|
|
651
|
-
if (options.
|
|
674
|
+
if (options.warmProducer) {
|
|
675
|
+
// The leased producer is already running this immutable image on the selected pool.
|
|
676
|
+
// Do not replace it with the host's independently synchronized commit tag.
|
|
677
|
+
member = { ...member, imageRef: options.warmProducer.image };
|
|
678
|
+
} else if (options.shelfImage) {
|
|
652
679
|
const found = (options.shelfLookup ?? registryImageRef)(member, imageCommit);
|
|
653
680
|
if (found !== options.shelfImage) throw new Error(`pod shelf: selected image unavailable on ${member.context}`);
|
|
654
681
|
member = { ...member, imageRef: found };
|
|
@@ -671,6 +698,33 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
671
698
|
.catch((error: unknown) => ({ host: member!.sshHost!, ok: false, ms: 0, detail: String(error).slice(0, 300) })), options.signal);
|
|
672
699
|
log('pod.command-job', 'mirror-seed', { host: member.sshHost, commit: options.source.sha, ok: seed?.ok ?? false, ms: seed?.ms ?? 0, ...(seed?.detail ? { detail: seed.detail } : {}) });
|
|
673
700
|
}
|
|
701
|
+
// Only a matching, live producer may hand its two source files to this Job; no other Pod's tree is trusted.
|
|
702
|
+
const warmHashes: Record<string, string> = {};
|
|
703
|
+
if (options.warmProducer) {
|
|
704
|
+
const producer = options.warmProducer;
|
|
705
|
+
if (context !== producer.context || (imageRef && imageRef !== producer.image)) throw new Error('pod warm source: selected pool or image differs from producer');
|
|
706
|
+
const got = kubectl(['-n', namespace, 'get', 'pod', producer.pod, '-o', 'json']);
|
|
707
|
+
if (got.status !== 0) throw new Error('pod warm source: producer Pod unavailable');
|
|
708
|
+
let pod: { metadata?: { name?: string; uid?: string }; spec?: { containers?: Array<{ name?: string; image?: string }> } };
|
|
709
|
+
try { pod = JSON.parse(got.stdout); } catch { throw new Error('pod warm source: invalid producer Pod'); }
|
|
710
|
+
if (pod.metadata?.name !== producer.pod || pod.metadata?.uid !== producer.podUid || pod.spec?.containers?.find((container) => container.name === 'child')?.image !== producer.image) {
|
|
711
|
+
throw new Error('pod warm source: producer Pod identity or image mismatch');
|
|
712
|
+
}
|
|
713
|
+
// kubectl exec starts in the image working directory; podSourceScript cloned
|
|
714
|
+
// `repo` there, then changed directory only in the original Job shell.
|
|
715
|
+
const head = kubectl(['-n', namespace, 'exec', producer.pod, '-c', 'child', '--', 'bash', '-c', 'git -C repo rev-parse HEAD']);
|
|
716
|
+
if (head.status !== 0 || head.stdout.trim() !== producer.commit) throw new Error('pod warm source: producer commit mismatch');
|
|
717
|
+
const binaryData: Record<string, string> = {};
|
|
718
|
+
for (const [i, path] of producer.files.entries()) {
|
|
719
|
+
const read = kubectl(['-n', namespace, 'exec', producer.pod, '-c', 'child', '--', 'bash', '-c', `base64 -w0 ${bashSingleQuote(`repo/${path}`)}`]);
|
|
720
|
+
if (read.status !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(read.stdout.trim())) throw new Error(`pod warm source: producer file unavailable: ${path}`);
|
|
721
|
+
binaryData[`file-${i}`] = read.stdout.trim();
|
|
722
|
+
warmHashes[path] = createHash('sha256').update(Buffer.from(binaryData[`file-${i}`]!, 'base64')).digest('hex');
|
|
723
|
+
}
|
|
724
|
+
const config = { apiVersion: 'v1', kind: 'ConfigMap', metadata: { name: warmSourceName(name, launch), namespace, labels: { 'elanous.job': name, 'elanous.launch': launch } }, binaryData };
|
|
725
|
+
const applied = kubectl(['apply', '-f', '-'], JSON.stringify(config));
|
|
726
|
+
if (applied.status !== 0) throw new Error(applied.stderr.trim() || 'pod warm source: ConfigMap apply failed');
|
|
727
|
+
}
|
|
674
728
|
// GATE-WARM-BOOT-NO-INIT (10-15): the hostPath dirs the uid-1000 child writes are handed over on the node itself, once per
|
|
675
729
|
// member·paths in this process (no init container). Best effort: a failure only logs; the child then falls back.
|
|
676
730
|
const hostDirPaths = [...(bunCache ? [bunCache] : []), ...(installSlots ? [installSlots] : [])];
|
|
@@ -701,7 +755,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
701
755
|
provenance: options.provenance, provenanceGate: options.provenanceGate,
|
|
702
756
|
...(imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
|
|
703
757
|
repoUrl, command, skills, ...(options.returnLogs ? { returnLogs: true } : {}), ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
|
|
704
|
-
...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
|
|
758
|
+
...(options.source ? { source: options.source } : {}), ...(options.warmProducer ? { warmFiles: options.warmProducer.files } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
|
|
705
759
|
...(options.runId ? { runId: options.runId } : {}),
|
|
706
760
|
...(hostDirsInit ? { hostDirsInit: true } : {}),
|
|
707
761
|
});
|
|
@@ -718,6 +772,12 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
718
772
|
let markerRc: number | null = null;
|
|
719
773
|
const appliedAt = Date.now();
|
|
720
774
|
for (;;) {
|
|
775
|
+
// PRLAND-SHADOW-HOST-TIMEOUT: a Pending Pod poll never ends by itself — the host wall-clock deadline ends the
|
|
776
|
+
// loop here (before another status read) and leaves exactly one timeout record (deadline time ⊕ final state).
|
|
777
|
+
if (options.hostDeadlineAtMs !== undefined && nowMs() >= options.hostDeadlineAtMs) {
|
|
778
|
+
log('pod.command', 'host-timeout', { job: name, context, hostDeadlineAtMs: options.hostDeadlineAtMs, nowMs: nowMs(), finalState: 'timeout', waitedMs: nowMs() - appliedAt });
|
|
779
|
+
throw new Error('pod shadow: host timeout');
|
|
780
|
+
}
|
|
721
781
|
ensureLive();
|
|
722
782
|
const got = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.status.conditions[*].type}']);
|
|
723
783
|
const finished = jobFinished(got.stdout);
|
|
@@ -744,6 +804,18 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
744
804
|
await awaitPodCommandAbort(sleep(options.pollMs ?? 15_000), options.signal);
|
|
745
805
|
}
|
|
746
806
|
ensureLive();
|
|
807
|
+
if (options.warmProducer) {
|
|
808
|
+
const found = kubectl(['-n', namespace, 'get', 'pods', '-l', `job-name=${name}`, '-o', 'json']);
|
|
809
|
+
let pods: { items?: Array<{ metadata?: { name?: string }; spec?: { containers?: Array<{ name?: string; image?: string }> } }> };
|
|
810
|
+
try { pods = JSON.parse(found.stdout); } catch { throw new Error('pod warm source: consumer Pod unavailable'); }
|
|
811
|
+
// A retried Job can leave an older Pod in the list. Never attribute the
|
|
812
|
+
// warm-source proof to an arbitrary Pod when the consumer is ambiguous.
|
|
813
|
+
const consumer = pods.items?.length === 1 ? pods.items[0] : undefined;
|
|
814
|
+
if (found.status !== 0 || !consumer?.metadata?.name || consumer.metadata.name === options.warmProducer.pod || consumer.spec?.containers?.find((container) => container.name === 'child')?.image !== (imageRef ?? image)) {
|
|
815
|
+
throw new Error('pod warm source: consumer Pod identity or image mismatch');
|
|
816
|
+
}
|
|
817
|
+
log('pod.command-job', 'warm-source-linked', { producerPod: options.warmProducer.pod, consumerPod: consumer.metadata.name, image: imageRef ?? image, commit: options.warmProducer.commit, files: [...options.warmProducer.files] });
|
|
818
|
+
}
|
|
747
819
|
let logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
|
|
748
820
|
// Marker path returns before the Job condition — a full-log read can hit the same transient window the tail read
|
|
749
821
|
// already survived (container log rotation · API hiccup). Retry it a little before calling the artifacts lost.
|
|
@@ -761,6 +833,13 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
761
833
|
}
|
|
762
834
|
const logsFailed = logsResult.status !== 0;
|
|
763
835
|
const logs = logsFailed ? '' : splitPodResultMarker(logsResult.stdout, launch).logs;
|
|
836
|
+
if (options.warmProducer) {
|
|
837
|
+
if (logsFailed) throw new Error(`pod warm source: consumer logs unavailable: ${logsResult.stderr.trim() || logsResult.status}`);
|
|
838
|
+
for (const path of options.warmProducer.files) {
|
|
839
|
+
const marker = `ELANOUS_WARM_SOURCE ${path} ${warmHashes[path]} ${options.warmProducer.commit}`;
|
|
840
|
+
if (logs.split(/\r?\n/).filter((line) => line === marker).length !== 1) throw new Error(`pod warm source: consumer file or commit mismatch: ${path}`);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
764
843
|
const artifactDir = artifactRoot;
|
|
765
844
|
let artifacts: PodArtifactCollection;
|
|
766
845
|
if (logsFailed) {
|
|
@@ -796,6 +875,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
796
875
|
// Marker path: the rc the child printed (the Pod's terminated state may lag like the condition). Condition path: unchanged.
|
|
797
876
|
const exitCode = markerRc ?? exitCodeFromPod(kubectl, namespace, name, state);
|
|
798
877
|
cleanupSecret();
|
|
878
|
+
cleanupWarmSource();
|
|
799
879
|
log('pod.command', 'job-finished', {
|
|
800
880
|
job: name,
|
|
801
881
|
exitCode,
|
|
@@ -815,6 +895,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
815
895
|
catch { /* preserve the cancellation reason */ }
|
|
816
896
|
}
|
|
817
897
|
cleanupSecret();
|
|
898
|
+
cleanupWarmSource();
|
|
818
899
|
throw err;
|
|
819
900
|
} finally {
|
|
820
901
|
if (member && pool) pool.release(member);
|
|
@@ -96,7 +96,7 @@ export function podTerminalRow(row: Record<string, unknown>): {
|
|
|
96
96
|
return nestedPodResult(row);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
export const POD_EXIT_CLASSES = ['oom-killed', 'deadline-exceeded', 'gh-login-failed', 'pod-secret', 'ask-reprompt', 'child-unconverged', 'child-error', 'no-result-line', 'unknown'] as const;
|
|
99
|
+
export const POD_EXIT_CLASSES = ['oom-killed', 'deadline-exceeded', 'gh-login-failed', 'pod-secret', 'ask-reprompt', 'provider-error', 'child-unconverged', 'child-error', 'no-result-line', 'unknown'] as const;
|
|
100
100
|
|
|
101
101
|
export type PodExitClass = typeof POD_EXIT_CLASSES[number];
|
|
102
102
|
|
|
@@ -108,6 +108,51 @@ const isPodErrorLine = (line: string): boolean =>
|
|
|
108
108
|
|
|
109
109
|
const normalizePodLogLine = (line: string): string => line.replace(/\/home\/[^/\s]+\//gu, '~/').slice(0, 240);
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* PROVIDER-ERROR-PRIORITY: 모델 호출 쪽이 죽은 줄(자격증명·쿼터·과부하·업스트림 5xx).
|
|
113
|
+
* 자식이 스스로 수렴 못 한 것과 사유가 다르므로 generic 실패(child-error/unknown)보다 먼저 분류한다.
|
|
114
|
+
*/
|
|
115
|
+
const POD_PROVIDER_ERROR_LINE =
|
|
116
|
+
/\bllm\.[a-z0-9_-]+ (?:credential|response|stream)\b.*\b(?:error|fail(?:ed|ure)?|denied|unavailable|overloaded|exhausted)\b|\b(?:rate[_ -]?limit|quota|credits?)\b.*\b(?:exceeded|exhausted|insufficient|hit)\b|\b(?:provider|upstream)\b.*\b(?:error|overloaded|unavailable|timed? out|5\d\d)\b|(?:프로바이더|제공자|모델)\s*(?:오류|호출 실패|한도 초과)/iu;
|
|
117
|
+
|
|
118
|
+
/** provider error 줄인가 — bookkeeping 줄과 «파싱되는 JSON 줄»은 세지 않는다(classifyPodExit 의 줄 기준과 같다). */
|
|
119
|
+
function isPodProviderErrorLine(line: string): boolean {
|
|
120
|
+
if (!line || isPodBookkeepingLine(line)) return false;
|
|
121
|
+
if (line.startsWith('{')) {
|
|
122
|
+
try {
|
|
123
|
+
const parsed: unknown = JSON.parse(line);
|
|
124
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) return false;
|
|
125
|
+
} catch { /* 일반 줄이 중괄호로 시작할 수 있다. */ }
|
|
126
|
+
}
|
|
127
|
+
return POD_PROVIDER_ERROR_LINE.test(line);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* POD-FAIL-EVIDENCE-CAPTURE-FU — duplicate-cap 귀속: 마지막 «canonical» 자식 terminal 하나에만 실패를 붙인다.
|
|
132
|
+
* canonical 접두(`self`/`external`)가 아닌 lookalike kind 행은 건너뛰고, 마지막 canonical terminal 이 성공이거나
|
|
133
|
+
* 읽을 오류 줄이 bookkeeping 뿐이면 null — 더 오래된(다른 terminal 의) 실패를 재사용하지 않는다.
|
|
134
|
+
*/
|
|
135
|
+
export function podChildFailureAttribution(logs: string): { stage: string; error: string } | null {
|
|
136
|
+
for (const line of logs.split('\n').reverse()) {
|
|
137
|
+
if (!line.trimStart().startsWith('{')) continue;
|
|
138
|
+
let parsed: unknown;
|
|
139
|
+
try { parsed = JSON.parse(line); } catch { continue; }
|
|
140
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;
|
|
141
|
+
const row = parsed as Record<string, unknown>;
|
|
142
|
+
const terminal = podTerminalRow(row);
|
|
143
|
+
if (!terminal) continue;
|
|
144
|
+
if (terminal.ok !== false || typeof terminal.error !== 'string') return null;
|
|
145
|
+
const errorLines = terminal.error.replace(/\/home\/[^/\s]+\//gu, '~/').split(/\r\n|\n|\r/u)
|
|
146
|
+
.map((part) => part.trim())
|
|
147
|
+
.filter((part) => part.length > 0 && !isPodBookkeepingLine(part));
|
|
148
|
+
if (!errorLines.length) return null;
|
|
149
|
+
const first = errorLines[0]!.slice(0, 240);
|
|
150
|
+
const last = errorLines.at(-1)!.slice(0, 240);
|
|
151
|
+
return { stage: terminal.stage, error: first === last ? first : `${first}\n${last}` };
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
111
156
|
/** Classify a failed Pod using its terminal metadata and child output, without side effects. */
|
|
112
157
|
export function classifyPodExit(input: {
|
|
113
158
|
errorCode?: string | null;
|
|
@@ -131,12 +176,19 @@ export function classifyPodExit(input: {
|
|
|
131
176
|
} {
|
|
132
177
|
const logLines = input.logs.split(/\r\n|\n|\r/u).map((line) => line.trim()).filter(Boolean);
|
|
133
178
|
let terminalResult: ReturnType<typeof podTerminalRow> = null;
|
|
134
|
-
|
|
179
|
+
let lastTerminalIndex = -1;
|
|
180
|
+
let previousTerminalIndex = -1;
|
|
181
|
+
for (const [index, line] of logLines.entries()) {
|
|
135
182
|
if (!line.startsWith('{')) continue;
|
|
136
183
|
let parsed: unknown;
|
|
137
184
|
try { parsed = JSON.parse(line); } catch { continue; }
|
|
138
185
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;
|
|
139
|
-
|
|
186
|
+
const terminal = podTerminalRow(parsed as Record<string, unknown>);
|
|
187
|
+
if (!terminal) continue;
|
|
188
|
+
// 마지막 canonical terminal 만 유지 — 앞선 terminal 의 실패를 재사용하지 않는다(duplicate-cap).
|
|
189
|
+
previousTerminalIndex = lastTerminalIndex;
|
|
190
|
+
terminalResult = terminal;
|
|
191
|
+
lastTerminalIndex = index;
|
|
140
192
|
}
|
|
141
193
|
const hasResultLine = terminalResult !== null;
|
|
142
194
|
if (!terminalResult && input.result) terminalResult = podTerminalRow(input.result);
|
|
@@ -148,12 +200,19 @@ export function classifyPodExit(input: {
|
|
|
148
200
|
try { const parsed = JSON.parse(line); return !!parsed && typeof parsed === 'object' && !Array.isArray(parsed); } catch { return false; }
|
|
149
201
|
};
|
|
150
202
|
const hasErrorLine = logLines.some((line) => !isPodBookkeepingLine(line) && !isParsedJsonLine(line) && isPodErrorLine(line));
|
|
203
|
+
// 동일 terminal 직전만: 마지막 canonical terminal 에 딸린 구간(직전 terminal 다음 ~ 마지막 terminal)의 줄만
|
|
204
|
+
// provider error 근거로 쓴다 — 오래된 terminal 의 실패를 재사용하지 않는다(duplicate-cap).
|
|
205
|
+
const attributionLines = lastTerminalIndex === -1
|
|
206
|
+
? logLines
|
|
207
|
+
: logLines.slice(previousTerminalIndex + 1, lastTerminalIndex);
|
|
208
|
+
const providerError = attributionLines.some((line) => isPodProviderErrorLine(line));
|
|
151
209
|
let exitClass: PodExitClass;
|
|
152
210
|
if (input.errorCode === 'pod-secret') exitClass = 'pod-secret';
|
|
153
211
|
else if (input.jobReason === 'DeadlineExceeded') exitClass = 'deadline-exceeded';
|
|
154
212
|
else if (input.containerReason === 'OOMKilled') exitClass = 'oom-killed';
|
|
155
213
|
else if (input.containerExitCode === 7) exitClass = 'gh-login-failed';
|
|
156
214
|
else if (askReprompt) exitClass = 'ask-reprompt';
|
|
215
|
+
else if (providerError) exitClass = 'provider-error';
|
|
157
216
|
else if (terminalResult?.stage && terminalResult.ok === false) exitClass = 'child-unconverged';
|
|
158
217
|
else if (!hasResultLine && hasErrorLine) exitClass = 'child-error';
|
|
159
218
|
else if (!hasResultLine) exitClass = 'no-result-line';
|
|
@@ -245,3 +304,156 @@ export function extractPodFailureReason(input: {
|
|
|
245
304
|
const why = input.logTailReason?.trim() || (input.logs.trim() ? '로그에 읽을 수 있는 오류 줄 없음' : '자식 로그 비어 있음');
|
|
246
305
|
return `사유 못 읽음: ${normalizePodLogLine(why)}`;
|
|
247
306
|
}
|
|
307
|
+
|
|
308
|
+
// JOB-FAILURE-TERMINATION-CAPTURE — the Kubernetes facts of a failed Job, read once at the failure verdict
|
|
309
|
+
// (Job Failed condition · result marker early exit) before GC removes the Job and its Pod. Unobserved stays
|
|
310
|
+
// `unknown` — `no-result-line` is never promoted to OOM or deadline here. Only these scalar fields are kept:
|
|
311
|
+
// no Pod env, Secret, or describe output.
|
|
312
|
+
export type PodTerminationPath = 'job-failed-condition' | 'result-marker';
|
|
313
|
+
export type PodTerminationUnknown = 'unknown';
|
|
314
|
+
|
|
315
|
+
export interface PodTermination {
|
|
316
|
+
job: string;
|
|
317
|
+
path: PodTerminationPath;
|
|
318
|
+
observedAt: string;
|
|
319
|
+
/** `ok` only when the Job read names this launch's uid · `unavailable`: failed (NotFound after GC · API error),
|
|
320
|
+
* a different or missing uid, or no launch uid to attribute it to. */
|
|
321
|
+
jobLookup: 'ok' | 'unavailable';
|
|
322
|
+
/** This launch's Job uid (the attribution key) — `unknown` when the launcher had none, and then nothing is attributed. */
|
|
323
|
+
jobUid: string | PodTerminationUnknown;
|
|
324
|
+
jobConditionReason: string | PodTerminationUnknown;
|
|
325
|
+
/** The Job's configured `spec.activeDeadlineSeconds` — a setting, not evidence the deadline fired. */
|
|
326
|
+
activeDeadlineSeconds: number | PodTerminationUnknown;
|
|
327
|
+
/** From the Job Failed condition reason `DeadlineExceeded` only. */
|
|
328
|
+
deadlineExceeded: boolean | PodTerminationUnknown;
|
|
329
|
+
/** `terminated`: the latest child container of this uid has a terminated state · without one, the Pod phase
|
|
330
|
+
* (`running` · `pending`) or `unknown` (any other or unread phase) · `absent`: no Pod of this uid. */
|
|
331
|
+
podLookup: 'terminated' | 'running' | 'pending' | 'unknown' | 'absent' | 'unavailable';
|
|
332
|
+
containerReason: string | PodTerminationUnknown;
|
|
333
|
+
exitCode: number | PodTerminationUnknown;
|
|
334
|
+
finishedAt: string | PodTerminationUnknown;
|
|
335
|
+
/** From `state.terminated.reason === 'OOMKilled'` only (never from exit code 137). */
|
|
336
|
+
oomKilled: boolean | PodTerminationUnknown;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Job Failed condition reason first: the classification takes column one, the capture all three, from one read. */
|
|
340
|
+
export const POD_TERMINATION_JOB_JSONPATH = '{.status.conditions[?(@.type=="Failed")].reason}{"\\t"}{.spec.activeDeadlineSeconds}{"\\t"}{.metadata.uid}';
|
|
341
|
+
/**
|
|
342
|
+
* One row per Pod of this Job name. The first three columns keep the classification read's layout
|
|
343
|
+
* (`creation · terminated.reason · terminated.exitCode`, empty when the child has no status yet), so the
|
|
344
|
+
* Failed-condition path reads Pods once for both; `finishedAt` follows, then `|phase · owner Job uid`.
|
|
345
|
+
*/
|
|
346
|
+
export const POD_TERMINATION_PODS_JSONPATH = '{range .items[*]}{.metadata.creationTimestamp}{"\\t"}{range .status.containerStatuses[?(@.name=="child")]}{.state.terminated.reason}{"\\t"}{.state.terminated.exitCode}{"\\t"}{.state.terminated.finishedAt}{end}{"\\t"}{"\\t"}{"\\t"}{"|"}{.status.phase}{"\\t"}{.metadata.ownerReferences[?(@.kind=="Job")].uid}{"\\n"}{end}';
|
|
347
|
+
|
|
348
|
+
type PodTerminationKubectl = (args: readonly string[]) => { status: number | null; stdout: string; stderr: string };
|
|
349
|
+
|
|
350
|
+
const POD_TERMINATION_WORD = /^[A-Za-z][A-Za-z0-9_.:-]{0,63}$/;
|
|
351
|
+
const JOB_UID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
|
|
352
|
+
const terminationWord = (value: string | undefined): string => {
|
|
353
|
+
const text = value?.trim() ?? '';
|
|
354
|
+
return POD_TERMINATION_WORD.test(text) ? text : 'unknown';
|
|
355
|
+
};
|
|
356
|
+
const terminationCount = (value: string | undefined): number | PodTerminationUnknown => {
|
|
357
|
+
const text = value?.trim() ?? '';
|
|
358
|
+
return /^\d{1,10}$/.test(text) ? Number(text) : 'unknown';
|
|
359
|
+
};
|
|
360
|
+
const terminationInstant = (value: string | undefined): string => {
|
|
361
|
+
const text = value?.trim() ?? '';
|
|
362
|
+
return /^\d{4}-\d{2}-\d{2}T[\d:.]+Z$/.test(text) && Number.isFinite(Date.parse(text)) ? text : 'unknown';
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/** Two reads (the Job · its Pods), each fail-soft: a failed or thrown read is `unavailable`, never an inferred value. */
|
|
366
|
+
export function readPodTermination(input: { kubectl: PodTerminationKubectl; namespace: string; job: string; path: PodTerminationPath;
|
|
367
|
+
/** This launch's Job uid — the only attribution key. A same-name Job of another round (OOM retry · relaunch)
|
|
368
|
+
* is not this verdict's state; without it every Job/Pod fact stays unobserved. */
|
|
369
|
+
jobUid: string | undefined;
|
|
370
|
+
/** The Failed-condition path's own Job read of `POD_TERMINATION_JOB_JSONPATH` (null: it threw) — not read again,
|
|
371
|
+
* so a GC between the verdict and the capture cannot turn an observed reason into `unknown`. */
|
|
372
|
+
jobRead?: { status: number | null; stdout: string } | null;
|
|
373
|
+
/** The Failed-condition path's own Pods read of `POD_TERMINATION_PODS_JSONPATH` (null: it threw) — not read again. */
|
|
374
|
+
podsRead?: { status: number | null; stdout: string } | null;
|
|
375
|
+
now?: () => Date }): PodTermination {
|
|
376
|
+
const { kubectl, namespace, job, path } = input;
|
|
377
|
+
const read = (args: readonly string[]): { status: number | null; stdout: string } | null => {
|
|
378
|
+
try { return kubectl(args); } catch { return null; }
|
|
379
|
+
};
|
|
380
|
+
const jobRead = 'jobRead' in input ? input.jobRead ?? null
|
|
381
|
+
: read(['-n', namespace, 'get', 'job', job, '-o', `jsonpath=${POD_TERMINATION_JOB_JSONPATH}`]);
|
|
382
|
+
const [reasonText, deadlineText, uidText] = jobRead?.status === 0 ? jobRead.stdout.replace(/\r?\n$/, '').split('\t') : [];
|
|
383
|
+
const readUid = JOB_UID.test(uidText?.trim() ?? '') ? uidText!.trim() : undefined;
|
|
384
|
+
const jobUid = input.jobUid && JOB_UID.test(input.jobUid) ? input.jobUid : undefined;
|
|
385
|
+
// A read without a uid, or with another uid, is not this launch's Job.
|
|
386
|
+
const jobOk = jobRead?.status === 0 && jobUid !== undefined && readUid === jobUid;
|
|
387
|
+
const jobConditionReason = jobOk ? terminationWord(reasonText) : 'unknown';
|
|
388
|
+
const podsRead = 'podsRead' in input ? input.podsRead ?? null
|
|
389
|
+
: read(['-n', namespace, 'get', 'pods', '-l', `job-name=${job}`, '-o', `jsonpath=${POD_TERMINATION_PODS_JSONPATH}`]);
|
|
390
|
+
let podLookup: PodTermination['podLookup'] = 'unavailable';
|
|
391
|
+
let containerReason = 'unknown';
|
|
392
|
+
let exitCode: PodTermination['exitCode'] = 'unknown';
|
|
393
|
+
let finishedAt = 'unknown';
|
|
394
|
+
// Without a uid the rows cannot be attributed to this Job — they stay unread rather than borrowed from another round.
|
|
395
|
+
if (podsRead?.status === 0 && jobUid) {
|
|
396
|
+
// The latest Pod owned by this Job uid only.
|
|
397
|
+
const rows = podsRead.stdout.split('\n').map((line) => {
|
|
398
|
+
const cut = line.lastIndexOf('\t|');
|
|
399
|
+
const [created, reason, exit, finished] = (cut >= 0 ? line.slice(0, cut) : line).split('\t');
|
|
400
|
+
const [phase, owner] = cut >= 0 ? line.slice(cut + 2).split('\t') : [];
|
|
401
|
+
return { created: created ?? '', reason, exit, finished, phase: phase?.trim(), owner: owner?.trim() };
|
|
402
|
+
});
|
|
403
|
+
const owned = rows.filter((row) => row.created && Number.isFinite(Date.parse(row.created)) && row.owner === jobUid)
|
|
404
|
+
.sort((a, b) => Date.parse(b.created) - Date.parse(a.created));
|
|
405
|
+
const latest = owned[0];
|
|
406
|
+
// Two Pods of this uid created at the same instant (a Job retry): which one is «this» failure is not knowable.
|
|
407
|
+
const tied = latest !== undefined && owned.length > 1 && Date.parse(owned[1]!.created) === Date.parse(latest.created);
|
|
408
|
+
if (!latest) podLookup = 'absent';
|
|
409
|
+
else if (tied) podLookup = 'unknown';
|
|
410
|
+
else {
|
|
411
|
+
const { reason, exit, finished, phase } = latest;
|
|
412
|
+
containerReason = terminationWord(reason);
|
|
413
|
+
exitCode = terminationCount(exit);
|
|
414
|
+
finishedAt = terminationInstant(finished);
|
|
415
|
+
podLookup = containerReason !== 'unknown' || exitCode !== 'unknown' ? 'terminated'
|
|
416
|
+
: phase === 'Running' ? 'running' : phase === 'Pending' ? 'pending' : 'unknown';
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
job, path, observedAt: (input.now?.() ?? new Date()).toISOString(),
|
|
421
|
+
jobLookup: jobOk ? 'ok' : 'unavailable',
|
|
422
|
+
jobUid: jobUid ?? 'unknown',
|
|
423
|
+
jobConditionReason,
|
|
424
|
+
activeDeadlineSeconds: jobOk ? terminationCount(deadlineText) : 'unknown',
|
|
425
|
+
deadlineExceeded: jobConditionReason === 'unknown' ? 'unknown' : jobConditionReason === 'DeadlineExceeded',
|
|
426
|
+
podLookup, containerReason, exitCode, finishedAt,
|
|
427
|
+
oomKilled: podLookup === 'terminated' && containerReason !== 'unknown' ? containerReason === 'OOMKilled' : 'unknown',
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** Ledger → incident: only a well-formed record of `job` (the current attempt's Job) is carried; anything else is dropped. */
|
|
432
|
+
export function parsePodTermination(value: unknown, job: string): PodTermination | undefined {
|
|
433
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
|
|
434
|
+
const row = value as Record<string, unknown>;
|
|
435
|
+
const oneOf = (v: unknown, allowed: readonly unknown[]) => allowed.includes(v);
|
|
436
|
+
const wordOrUnknown = (v: unknown) => typeof v === 'string' && (v === 'unknown' || POD_TERMINATION_WORD.test(v));
|
|
437
|
+
const numberOrUnknown = (v: unknown) => v === 'unknown' || (typeof v === 'number' && Number.isSafeInteger(v) && v >= 0);
|
|
438
|
+
const boolOrUnknown = (v: unknown) => v === 'unknown' || typeof v === 'boolean';
|
|
439
|
+
if (row.job !== job || !oneOf(row.path, ['job-failed-condition', 'result-marker'])
|
|
440
|
+
|| typeof row.observedAt !== 'string' || !Number.isFinite(Date.parse(row.observedAt))
|
|
441
|
+
|| !oneOf(row.jobLookup, ['ok', 'unavailable']) || !wordOrUnknown(row.jobConditionReason)
|
|
442
|
+
|| !(row.jobUid === 'unknown' || (typeof row.jobUid === 'string' && JOB_UID.test(row.jobUid)))
|
|
443
|
+
|| !numberOrUnknown(row.activeDeadlineSeconds) || !boolOrUnknown(row.deadlineExceeded)
|
|
444
|
+
|| !oneOf(row.podLookup, ['terminated', 'running', 'pending', 'unknown', 'absent', 'unavailable'])
|
|
445
|
+
|| !wordOrUnknown(row.containerReason) || !numberOrUnknown(row.exitCode)
|
|
446
|
+
|| !(row.finishedAt === 'unknown' || (typeof row.finishedAt === 'string' && terminationInstant(row.finishedAt) !== 'unknown'))
|
|
447
|
+
|| !boolOrUnknown(row.oomKilled)) return undefined;
|
|
448
|
+
// Facts are attributed through the uid only: a record claiming Job or Pod facts without one is contradictory.
|
|
449
|
+
if (row.jobUid === 'unknown' && (row.jobLookup !== 'unavailable' || row.podLookup !== 'unavailable')) return undefined;
|
|
450
|
+
return {
|
|
451
|
+
job, path: row.path as PodTerminationPath, observedAt: row.observedAt,
|
|
452
|
+
jobLookup: row.jobLookup as PodTermination['jobLookup'], jobUid: row.jobUid as string, jobConditionReason: row.jobConditionReason as string,
|
|
453
|
+
activeDeadlineSeconds: row.activeDeadlineSeconds as PodTermination['activeDeadlineSeconds'],
|
|
454
|
+
deadlineExceeded: row.deadlineExceeded as PodTermination['deadlineExceeded'],
|
|
455
|
+
podLookup: row.podLookup as PodTermination['podLookup'], containerReason: row.containerReason as string,
|
|
456
|
+
exitCode: row.exitCode as PodTermination['exitCode'], finishedAt: row.finishedAt as string,
|
|
457
|
+
oomKilled: row.oomKilled as PodTermination['oomKilled'],
|
|
458
|
+
};
|
|
459
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POD-LAUNCH-PROVENANCE slice 2 — TA/harness si-task Jobs.
|
|
3
|
+
*
|
|
4
|
+
* ① `siTaskPodProvenance` fills the shared provenance set (pod-provenance.ts · #29650) for a si-task Job from the
|
|
5
|
+
* launch env the parent already has (owner · seat · task card · checklist slot · entrance stamp). It never builds
|
|
6
|
+
* labels itself — `podProvenanceMetadata` stays the one builder.
|
|
7
|
+
* ② The history is append-only rows on the parent's existing run ledger (`pod-launch-started` when the Job is
|
|
8
|
+
* applied, `pod-launch-finished` at the terminal verdict) — no new store. `readPodLaunchHistory(runId)` answers
|
|
9
|
+
* «who launched which Pod, when and why, and how did it end» from that ledger alone.
|
|
10
|
+
*/
|
|
11
|
+
import { userInfo } from 'node:os';
|
|
12
|
+
import { LAUNCH_SEATS, resolveLaunchStamp } from '../../harness/launch-stamp.js';
|
|
13
|
+
import { loadRunLedger, runLedgerDir, type RunLedgerEntry } from '../../self-implement/run-ledger.js';
|
|
14
|
+
import type { PodProvenance } from './pod-provenance.js';
|
|
15
|
+
import type { PodWorkIdentity } from './pod-pool.js';
|
|
16
|
+
|
|
17
|
+
export const POD_LAUNCH_STARTED_EVENT = 'pod-launch-started';
|
|
18
|
+
export const POD_LAUNCH_FINISHED_EVENT = 'pod-launch-finished';
|
|
19
|
+
|
|
20
|
+
export interface SiTaskProvenanceInput {
|
|
21
|
+
env: NodeJS.ProcessEnv | Readonly<Record<string, string | undefined>>;
|
|
22
|
+
/** The child runId this Job runs as (`ELANOUS_RUN_ID` inside the Pod). */
|
|
23
|
+
runId: string;
|
|
24
|
+
parentRunId?: string;
|
|
25
|
+
workIdentity: PodWorkIdentity;
|
|
26
|
+
/** ISO-8601 UTC. */
|
|
27
|
+
requestedAt: string;
|
|
28
|
+
feature: string;
|
|
29
|
+
launchHost?: string;
|
|
30
|
+
commit?: string | null;
|
|
31
|
+
version?: string;
|
|
32
|
+
memReq?: string;
|
|
33
|
+
shard?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const text = (value: string | undefined | null): string | undefined => {
|
|
37
|
+
const trimmed = value?.trim();
|
|
38
|
+
return trimmed ? trimmed : undefined;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function osUser(): string | undefined {
|
|
42
|
+
try { return text(userInfo().username); } catch { return undefined; }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The si-task identity. Actor order: the Job owner the dispatcher named → the launch stamp actor (seat · session · loop)
|
|
47
|
+
* → the OS user. `pool` is deliberately absent: `ELANOUS_POD_POOL` is read as pool config by the child harness.
|
|
48
|
+
*/
|
|
49
|
+
export function siTaskPodProvenance(input: SiTaskProvenanceInput): Partial<PodProvenance> {
|
|
50
|
+
const env = input.env as NodeJS.ProcessEnv;
|
|
51
|
+
const identity = input.workIdentity;
|
|
52
|
+
const stamp = resolveLaunchStamp({}, env);
|
|
53
|
+
const ownerId = text(identity.ownerId);
|
|
54
|
+
const stampActor = text(stamp.actor);
|
|
55
|
+
const user = text(env.USER) ?? text(env.LOGNAME) ?? osUser();
|
|
56
|
+
const actor = ownerId ?? stampActor ?? user;
|
|
57
|
+
const actorKind = ownerId && identity.ownerKind
|
|
58
|
+
? (identity.ownerKind === 'steward' || identity.ownerKind === 'orchestrator' ? 'loop' : identity.ownerKind)
|
|
59
|
+
: stampActor && (LAUNCH_SEATS as readonly string[]).includes(stampActor) ? 'seat'
|
|
60
|
+
: stampActor && stampActor === text(env.ELANOUS_LOOP_NAME) ? 'loop'
|
|
61
|
+
: actor ? 'human' : undefined;
|
|
62
|
+
const authoring = identity.work === 'authoring';
|
|
63
|
+
const entrance = stamp.entrance !== 'unknown' ? stamp.entrance : identity.taskCard ? 'tasks-hand' : undefined;
|
|
64
|
+
const firstLine = input.feature.split('\n', 1)[0]?.trim().slice(0, 160) ?? '';
|
|
65
|
+
const reason = [identity.taskCard ? `TA ${identity.taskCard}` : undefined, firstLine || undefined].filter(Boolean).join(' · ');
|
|
66
|
+
return {
|
|
67
|
+
...(actorKind ? { actorKind } : {}),
|
|
68
|
+
...(actor ? { actor } : {}),
|
|
69
|
+
kind: 'si-task',
|
|
70
|
+
run: input.runId,
|
|
71
|
+
phase: authoring ? 'authoring' : 'impl',
|
|
72
|
+
requestedAt: input.requestedAt,
|
|
73
|
+
character: identity.taskCard ? 'ta-child' : authoring ? 'author-child' : 'harness-child',
|
|
74
|
+
...(entrance ? { entrance } : {}),
|
|
75
|
+
...(text(identity.slotId) ? { cell: identity.slotId } : {}),
|
|
76
|
+
...(text(input.version) ? { version: input.version } : {}),
|
|
77
|
+
...(text(input.commit) ? { commit: input.commit! } : {}),
|
|
78
|
+
...(text(input.launchHost) ? { launchHost: input.launchHost } : {}),
|
|
79
|
+
...(text(input.shard) ? { shard: input.shard } : {}),
|
|
80
|
+
...(text(input.memReq) ? { memReq: input.memReq } : {}),
|
|
81
|
+
...(text(input.parentRunId) ? { parent: input.parentRunId } : {}),
|
|
82
|
+
...(reason ? { reason } : {}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** `elanous.ai/<key>` annotations → `{ <key>: value }` for the started row (full values, not the 63-char labels). */
|
|
87
|
+
export function provenanceRowFromAnnotations(annotations: Readonly<Record<string, string>>): Record<string, string> {
|
|
88
|
+
const row: Record<string, string> = {};
|
|
89
|
+
for (const [key, value] of Object.entries(annotations)) if (key.startsWith('elanous.ai/')) row[key.slice('elanous.ai/'.length)] = value;
|
|
90
|
+
return row;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface PodLaunchRecord {
|
|
94
|
+
job: string;
|
|
95
|
+
run: string;
|
|
96
|
+
attempt: number | null;
|
|
97
|
+
startedAt: string | null;
|
|
98
|
+
provenance: Record<string, string>;
|
|
99
|
+
finished: { at: string | null; phase: string; exitCode: number | null; reason: string } | null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const str = (value: unknown): string | undefined => (typeof value === 'string' && value ? value : undefined);
|
|
103
|
+
|
|
104
|
+
/** Rebuild launch records from one run ledger. Rows pair on job·run; an unpaired row stays visible (never dropped). */
|
|
105
|
+
export function readPodLaunchHistory(runId: string, dir: string = runLedgerDir()): PodLaunchRecord[] {
|
|
106
|
+
const entries: RunLedgerEntry[] = loadRunLedger(runId, dir) ?? [];
|
|
107
|
+
const records: PodLaunchRecord[] = [];
|
|
108
|
+
const open = new Map<string, PodLaunchRecord>();
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
if (entry.event !== POD_LAUNCH_STARTED_EVENT && entry.event !== POD_LAUNCH_FINISHED_EVENT) continue;
|
|
111
|
+
const job = str(entry.data.job) ?? 'unknown';
|
|
112
|
+
const run = str(entry.data.run) ?? 'unknown';
|
|
113
|
+
const key = `${job}\u0000${run}`;
|
|
114
|
+
if (entry.event === POD_LAUNCH_STARTED_EVENT) {
|
|
115
|
+
const provenance: Record<string, string> = {};
|
|
116
|
+
const raw = entry.data.provenance;
|
|
117
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
118
|
+
for (const [name, value] of Object.entries(raw as Record<string, unknown>)) if (typeof value === 'string') provenance[name] = value;
|
|
119
|
+
}
|
|
120
|
+
const record: PodLaunchRecord = { job, run, attempt: typeof entry.data.attempt === 'number' ? entry.data.attempt : null,
|
|
121
|
+
startedAt: entry.timestamp ?? null, provenance, finished: null };
|
|
122
|
+
records.push(record);
|
|
123
|
+
open.set(key, record);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const finished = { at: entry.timestamp ?? null, phase: str(entry.data.phase) ?? 'unknown',
|
|
127
|
+
exitCode: typeof entry.data.exitCode === 'number' ? entry.data.exitCode : null, reason: str(entry.data.reason) ?? 'unknown' };
|
|
128
|
+
const started = open.get(key);
|
|
129
|
+
if (started && !started.finished) { started.finished = finished; open.delete(key); continue; }
|
|
130
|
+
records.push({ job, run, attempt: typeof entry.data.attempt === 'number' ? entry.data.attempt : null, startedAt: null, provenance: {}, finished });
|
|
131
|
+
}
|
|
132
|
+
return records;
|
|
133
|
+
}
|