elanous 0.2.36 → 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/{uC-N0emedeNOFuaBQFv-I → 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/{4286.b70c4520306817e8.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/{3410.7f9af5ab77cbe65f.js → 1746.3563617ea64023a3.js} +1 -1
- 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/1ed5e8af.cf424815c7c0efad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9250-072df22eaadaa6b5.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/210.90b2cbd64926cf34.js +32 -0
- package/apps/pwa/out/_next/static/chunks/{3727.7949ccaacaa71242.js → 2283.edd9627b7bdfb546.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2318-450e75d07605b8fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4615.8525eb0add35eba6.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/{5711.957b095705c12560.js → 3199.6a1a9b0e6cd01dc6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2986.45d7652e4f13557e.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/{7481.39f7a4654907bf6e.js → 4313.76f232c304a15bde.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4337e36d.f42c3b391b3d8f20.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{6943.c6b24124853a47b2.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/{3757-180308bc61021b05.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/4833-7934c592c5569f00.js +1 -0
- 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/{771.c3cdb6c1f7f47c02.js → 4931.95cc6dbd230774ca.js} +3 -3
- 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/{552.b7d061ad91eeac51.js → 5046.7fd5cbd859299448.js} +2 -2
- 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/{9f31e478.fefcbcd3c388ebc5.js → 58edce7d.f1b0c72acf13b123.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +93 -0
- package/apps/pwa/out/_next/static/chunks/{3136.30aaaa5fa03662a3.js → 5952.294fc574a8625184.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{da5ecc5c-b005ad8cac737d57.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/{3324.a09703033abcbd2f.js → 6252.240578f10952e091.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8904.7d51af2dc033965c.js → 6680.6a693c28aae4cd19.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{275-02ea4c2a33980422.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/{528.38ce20ef8aa251ff.js → 6819.be5c9c4d67f22922.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3a3d9966.cc4d4585a2708e7c.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/{4304.e9b2512834a9e23e.js → 7424.c0fe2a595d4232b5.js} +1 -1
- 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/{2683.c9773a0c589b031b.js → 7867.e8725745ddd1d940.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/{6466-92e65a48490b68a9.js → 7893-e444a1b0809cd1e4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{ccae1c4b-0cf414f5eff1b10d.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/{3840-5825d56d46976a92.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/{873d6c12.09bd499f57171543.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/{575.d929793a53f27c4b.js → 9151.a2c51e93f9156dae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +1 -0
- 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/{190.285c832bd9626f8c.js → 958.53a8dcf4729e6997.js} +1 -1
- 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-e2de2e59111c9aad.js → page-3337c6a1328c2674.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/{page-f2b2e4bf6e981450.js → page-89acd5d68c0bc560.js} +1 -1
- 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-2af16e62c12f22df.js → page-fe986fe79b107546.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-1e5da297557d2354.js +1 -0
- 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-88a1edbff62eaf1d.js +1 -0
- 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-443364c9e4a23b31.js +1 -0
- 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-ac2c1e6169cfce57.js +1 -0
- 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/{053a429e.9a63436527cc751c.js → d9815f84.4918f682a45a8502.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{ceba0382.650712b56b85b582.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/graphs/drafts/recipes.yaml +27 -7
- 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/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/codex-fallback-live-probe.ts +17 -15
- package/scripts/fleet/node-setup.sh +32 -2
- package/scripts/fleet/run-light-worker.sh +9 -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 +140 -0
- package/scripts/release-loop/gate-closure.ts +48 -0
- package/scripts/release-loop/gate-diff.ts +2 -1
- package/scripts/release-loop/known-issues-node.ts +6 -4
- package/scripts/release-loop/notes-repair.ts +216 -0
- package/scripts/release-loop/prepare-node.ts +61 -5
- package/scripts/release-loop/resume-release.ts +114 -4
- package/scripts/release-loop/resume-test-traffic.ts +10 -0
- package/scripts/release-loop/version-node.ts +81 -12
- package/scripts/train/green-leg.ts +176 -0
- package/scripts/tui-continue-real-evidence.ts +47 -0
- package/scripts/ux-sim.ts +1 -1
- package/src/acp/client.ts +31 -5
- package/src/acp/core-turn-bridge.ts +6 -0
- package/src/acp/stderr-summary.ts +49 -0
- package/src/agent/monad-agent-turn.ts +1 -0
- package/src/agent/terminal-surface.ts +217 -0
- package/src/agent-substrate/pr-reviewer.ts +11 -3
- package/src/agent-substrate/self-review-cli.ts +343 -31
- package/src/autopilot/lineage/sources.ts +1 -1
- package/src/autopilot/pr-manager.ts +64 -13
- package/src/boot/daemon-runtime.ts +35 -3
- package/src/boot/daemon-tools/pty-shell.ts +2 -1
- package/src/budget/run-usage-rollup.ts +12 -7
- package/src/budget/unified-usage.ts +20 -0
- package/src/capture/tui-self-report.ts +32 -3
- package/src/cli/autopilot-cli.ts +24 -9
- package/src/cli/decisions-cli.ts +7 -4
- package/src/cli/doctor-cli.ts +116 -7
- package/src/cli/logs-cli.ts +357 -2
- package/src/cli/memory-cli.ts +30 -1
- package/src/cli/msg-cli.ts +15 -11
- package/src/cli/pr-granularity.ts +5 -3
- package/src/cli/release-checklist-read-cli.ts +109 -4
- package/src/cli/release-cli.ts +43 -10
- package/src/cli/self-update.ts +23 -5
- package/src/cli/self-utterances-cli.ts +13 -16
- package/src/cli/tasks-cli.ts +309 -11
- 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-goal-loop.ts +5 -2
- package/src/core-turn/types.ts +2 -0
- package/src/dashboard/chat/acp-chat.ts +9 -0
- package/src/dashboard/index.ts +97 -13
- package/src/dashboard/input/agent-wake.ts +43 -0
- package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
- package/src/dashboard/replay-preview.ts +25 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +17 -8
- package/src/dashboard/synchronized-frame-output.ts +74 -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/surface-events.ts +80 -1
- 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/graph-runner/graph-cli.ts +26 -2
- package/src/graph-runner/graph-run-api.ts +3 -2
- package/src/graph-runner/runner.ts +17 -5
- package/src/graph-wizard/generate.ts +29 -6
- package/src/harness/harness-cli-command.ts +179 -33
- package/src/harness/review-adapter.ts +26 -6
- package/src/index.ts +116 -13
- package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
- 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.ts +123 -11
- 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/orchestrator/anomaly-cluster.ts +243 -0
- package/src/loops/orchestrator/tick.ts +49 -4
- package/src/model-tier/llm-tier-map.ts +12 -17
- package/src/msg/msg-store.ts +17 -0
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/graph-wizard-api.ts +27 -2
- 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/state/state.ts +7 -1
- package/src/oauth/codex-account-store.ts +34 -1
- package/src/ops/loops-map.ts +46 -0
- package/src/ops/overview-cache.ts +22 -4
- package/src/ops/overview.ts +41 -5
- package/src/policy/llm-policy.ts +3 -1
- package/src/prompt-enhance/enhance.ts +4 -4
- package/src/pty-shell/availability.ts +7 -0
- package/src/pty-shell/herdr-agent-report.ts +40 -31
- 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 +187 -18
- package/src/pty-shell/registry.ts +25 -15
- package/src/pty-shell/tui-run-state.ts +235 -1
- package/src/release-loop/checklist.ts +50 -5
- package/src/release-loop/feature-store.ts +9 -9
- package/src/release-loop/landed-but-yellow.ts +93 -12
- package/src/repl/index.ts +8 -0
- 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 +29 -18
- package/src/self-dev/dev-pipeline.ts +29 -7
- package/src/self-dev/draft-sweep.ts +241 -16
- package/src/self-dev/draft-triage-rules.ts +19 -5
- package/src/self-dev/review-provider-fallback.ts +45 -7
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-run.ts +50 -3
- package/src/self-implement/doctor-visit.ts +83 -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.ts +333 -18
- package/src/self-implement/goal-supervisor-fill.ts +75 -26
- package/src/self-implement/importer-test-index.ts +215 -2
- package/src/self-implement/knowhow-pack.ts +5 -5
- package/src/self-implement/orchestrator.ts +318 -25
- package/src/self-implement/review-round-brief.ts +300 -0
- package/src/self-implement/rework-policy.ts +14 -0
- package/src/self-implement/run-ledger.ts +170 -6
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/running-runs.ts +17 -3
- package/src/self-implement/seams.ts +12 -6
- 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/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/skills/tools/pty.ts +5 -0
- package/src/status/metrics.ts +12 -1
- package/src/steward/rejudge-tick.ts +12 -5
- package/src/steward/resync-tick.ts +31 -4
- package/src/task-agent/actions.ts +199 -4
- 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/live-moves.ts +48 -3
- 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/parent-host.ts +21 -11
- package/src/task-agent/rejudge-on-head.ts +72 -5
- package/src/task-agent/repair-cycle.ts +41 -0
- package/src/task-agent/repair-next-move.ts +12 -2
- package/src/task-agent/review-prior-fix.ts +12 -2
- package/src/task-agent/shadow.ts +188 -5
- package/src/task-agent/task-hand.ts +158 -13
- package/src/task-agent/task-parent-role-llm.ts +9 -0
- package/src/task-agent/tier-split.ts +4 -3
- 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-artifact-return.ts +16 -6
- 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-pool.ts +50 -4
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +15 -9
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +217 -36
- package/src/task-orchestrator/surfaces/self-implement.ts +4 -0
- package/src/testing/linux-env.ts +177 -0
- package/src/tui/chat/goal-interim.ts +5 -1
- package/src/tui/entry.ts +258 -4
- package/src/tui/input/at-picker.ts +55 -0
- package/src/tui/slash/resume.ts +35 -12
- 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 +4 -3
- 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 +158 -4
- package/src/ux-sim/fake-gh.ts +174 -0
- package/src/ux-sim/fake-kubectl.ts +142 -0
- package/src/ux-sim/fake-llm.ts +6 -1
- package/src/ux-sim/next-tui-seat-scenarios.ts +124 -6
- 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/task-agent-parent-host-device.ts +264 -0
- package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +0 -287
- package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +0 -36
- package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +0 -149
- package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +0 -24
- package/apps/pwa/out/_next/static/chunks/2812ca6a.3b9f4a7a08885744.js +0 -1
- package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +0 -24
- package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3148-98efd4869d660a87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +0 -226
- package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +0 -8
- package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +0 -32
- package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +0 -286
- package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +0 -1
- package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +0 -148
- package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +0 -93
- package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +0 -122
- package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/599.c39c571b6733f2a2.js +0 -41
- package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +0 -79
- package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +0 -1
- package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +0 -27
- package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6925.562d532110879886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7891.03f910124a737985.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +0 -1
- package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +0 -62
- package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +0 -90
- package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +0 -77
- package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9514.131c52cc75fe6439.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +0 -1
- /package/apps/pwa/out/_next/static/{uC-N0emedeNOFuaBQFv-I → 8kITumG9GAZ1LwT9POrAR}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync, statSync, chmodSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { SPAWN_SYNC_MAX_BUFFER } from '../../src/util/spawn-sync-output.js';
|
|
5
|
+
import { basename, dirname, join, relative, resolve, sep } from 'node:path';
|
|
6
|
+
import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
|
|
7
|
+
import { getProviderForConfig, type LLMMessage } from '../../src/llm.js';
|
|
8
|
+
import { getUserConfig } from '../../src/user-config.js';
|
|
9
|
+
import type { GraphContext } from './node-verdict.js';
|
|
10
|
+
|
|
11
|
+
export const REPAIR_MODEL = 'openrouter/z-ai/glm-5.3';
|
|
12
|
+
export type Translator = (line: string, model: string) => Promise<string>;
|
|
13
|
+
export type RepairResult = { text: string; translatedLines: number[]; error?: string };
|
|
14
|
+
|
|
15
|
+
function koreanProseLines(text: string): Array<{ index: number; line: string }> {
|
|
16
|
+
let fence: { char: string; length: number } | undefined;
|
|
17
|
+
return text.split(/\r?\n/).flatMap((line, index) => {
|
|
18
|
+
const marker = /^ {0,3}(`{3,}|~{3,})/.exec(line)?.[1];
|
|
19
|
+
if (marker) {
|
|
20
|
+
if (!fence) fence = { char: marker[0]!, length: marker.length };
|
|
21
|
+
else if (marker[0] === fence.char && marker.length >= fence.length) fence = undefined;
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
if (fence || !/[가-힣]/.test(line.replace(/(`+)[^`]*?\1/g, ''))) return [];
|
|
25
|
+
return [{ index, line }];
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function repairKoreanMarkdown(text: string, translate: Translator, onlyLines?: ReadonlySet<number>): Promise<RepairResult> {
|
|
30
|
+
const lines = text.split(/\r?\n/);
|
|
31
|
+
const translatedLines: number[] = [];
|
|
32
|
+
for (const item of koreanProseLines(text).filter(({ index }) => !onlyLines || onlyLines.has(index + 1))) {
|
|
33
|
+
try {
|
|
34
|
+
// Keep inline code out of the model's editable surface and restore it byte-for-byte.
|
|
35
|
+
const code: string[] = [];
|
|
36
|
+
const protectedLine = item.line.replace(/(`+)[^`]*?\1/g, (match) => `⟦CODE${code.push(match) - 1}⟧`);
|
|
37
|
+
const value = (await translate(protectedLine, REPAIR_MODEL)).trim();
|
|
38
|
+
if (!value) throw new Error('translator returned empty text');
|
|
39
|
+
for (const [index] of code.entries()) {
|
|
40
|
+
const token = `⟦CODE${index}⟧`;
|
|
41
|
+
if (value.split(token).length !== 2) throw new Error('translator changed protected inline code');
|
|
42
|
+
}
|
|
43
|
+
const restored = value.replace(/⟦CODE(\d+)⟧/g, (_match, rawIndex: string) => {
|
|
44
|
+
const original = code[Number(rawIndex)];
|
|
45
|
+
if (original === undefined) throw new Error('translator changed protected inline code');
|
|
46
|
+
return original;
|
|
47
|
+
});
|
|
48
|
+
if (/[가-힣]/.test(restored.replace(/(`+)[^`]*?\1/g, ''))) throw new Error('translation still contains Korean prose');
|
|
49
|
+
lines[item.index] = restored;
|
|
50
|
+
translatedLines.push(item.index + 1);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return { text, translatedLines: [], error: `line ${item.index + 1}: ${error instanceof Error ? error.message : String(error)}` };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { text: lines.join('\n'), translatedLines };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const glmTranslator: Translator = async (line, model) => {
|
|
59
|
+
if (model !== REPAIR_MODEL) throw new Error(`unexpected translator model: ${model}`);
|
|
60
|
+
const config = getUserConfig();
|
|
61
|
+
const llmConfig = { ...config, llm: { ...config.llm, provider: 'openrouter' as const, model } };
|
|
62
|
+
const provider = getProviderForConfig(llmConfig, model);
|
|
63
|
+
if (provider.name !== 'openrouter' || !provider.available()) throw new Error('OpenRouter credentials unavailable for openrouter/z-ai/glm-5.3');
|
|
64
|
+
const messages: LLMMessage[] = [
|
|
65
|
+
{ role: 'system', content: 'Translate the supplied single public release-note line into concise idiomatic English. Return only the translation. Preserve markdown structure, meaning, punctuation, and every placeholder exactly.' },
|
|
66
|
+
{ role: 'user', content: line },
|
|
67
|
+
];
|
|
68
|
+
let result = '';
|
|
69
|
+
for await (const chunk of provider.chat(messages, { model, temperature: 0, maxTokens: 512, remainingFallbacks: 0, promptCache: false })) result += chunk;
|
|
70
|
+
return result;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export function atomicallyRepairFiles(targets: Array<{ path: string; lines: number[] }>, translate: Translator = glmTranslator): Promise<{ files: string[]; translatedLines: number[]; error?: string }> {
|
|
74
|
+
return (async () => {
|
|
75
|
+
const changed: string[] = [];
|
|
76
|
+
const translatedLines: number[] = [];
|
|
77
|
+
const staged: Array<{ path: string; text: string }> = [];
|
|
78
|
+
for (const { path, lines: selectedLines } of targets) {
|
|
79
|
+
const original = readFileSync(path, 'utf8');
|
|
80
|
+
const result = await repairKoreanMarkdown(original, translate, new Set(selectedLines));
|
|
81
|
+
if (result.error) return { files: changed, translatedLines, error: `${path}: ${result.error}` };
|
|
82
|
+
if (result.text !== original) {
|
|
83
|
+
staged.push({ path, text: result.text });
|
|
84
|
+
changed.push(path);
|
|
85
|
+
translatedLines.push(...result.translatedLines);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const { path, text } of staged) {
|
|
89
|
+
const temp = join(dirname(path), `.${basename(path)}.${randomUUID()}.tmp`);
|
|
90
|
+
try { writeFileSync(temp, text); chmodSync(temp, statSync(path).mode); renameSync(temp, path); }
|
|
91
|
+
finally { if (existsSync(temp)) unlinkSync(temp); }
|
|
92
|
+
}
|
|
93
|
+
return { files: changed, translatedLines };
|
|
94
|
+
})();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
type DocsReceipt = {
|
|
98
|
+
owner: { runId: string; attempt: number };
|
|
99
|
+
branch: string;
|
|
100
|
+
worktree: string;
|
|
101
|
+
outcome: 'pushed';
|
|
102
|
+
head: string;
|
|
103
|
+
result: Record<string, unknown>;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
function git(tree: string, ...args: string[]): string {
|
|
107
|
+
const result = spawnSync('git', args, { cwd: tree, encoding: 'utf8', timeout: 30_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
|
|
108
|
+
if (result.status !== 0) throw new Error(`docs repair git ${args[0]} failed: ${(result.stderr || result.error || '').toString().trim()}`);
|
|
109
|
+
return result.stdout.trim();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function remoteHead(tree: string, branch: string): string {
|
|
113
|
+
const line = git(tree, 'ls-remote', '--heads', 'origin', `refs/heads/${branch}`);
|
|
114
|
+
const match = /^([0-9a-f]{40})\s+refs\/heads\/[^\s]+$/i.exec(line);
|
|
115
|
+
if (!match) throw new Error(`docs repair remote head missing or invalid: ${branch}`);
|
|
116
|
+
return match[1]!;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function publishReceipt(path: string, receipt: DocsReceipt): void {
|
|
120
|
+
const temp = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
121
|
+
try { writeFileSync(temp, JSON.stringify(receipt) + '\n'); renameSync(temp, path); }
|
|
122
|
+
finally { if (existsSync(temp)) unlinkSync(temp); }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function ownedDocsReceipt(context: GraphContext, docs: Record<string, unknown>, tree: string, stateRoot: string,
|
|
126
|
+
approvedPaths: string[]): { path: string; receipt: DocsReceipt } {
|
|
127
|
+
const runId = context.runId;
|
|
128
|
+
const owner = docs.artifactOwner as { runId?: unknown; attempt?: unknown } | undefined;
|
|
129
|
+
const branch = `release-docs/${context.input.version}`;
|
|
130
|
+
if (!runId || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(runId)
|
|
131
|
+
|| !owner || owner.runId !== runId || !Number.isSafeInteger(owner.attempt) || docs.branch !== branch)
|
|
132
|
+
throw new Error('docs repair requires same-run docs branch ownership');
|
|
133
|
+
const path = join(stateRoot, 'release', context.input.version, 'docs-branch-owner.json');
|
|
134
|
+
let receipt = JSON.parse(readFileSync(path, 'utf8')) as DocsReceipt;
|
|
135
|
+
if (receipt?.outcome !== 'pushed' || receipt.owner?.runId !== runId || receipt.owner.attempt !== owner.attempt
|
|
136
|
+
|| receipt.branch !== branch || realpathSync(receipt.worktree) !== tree || !/^[0-9a-f]{40}$/i.test(receipt.head)
|
|
137
|
+
|| receipt.result?.outcome !== 'ok') throw new Error('docs repair ownership receipt does not match this run and attempt');
|
|
138
|
+
if (git(tree, 'branch', '--show-current') !== branch) throw new Error('docs repair branch differs from ownership receipt');
|
|
139
|
+
if (git(tree, 'status', '--porcelain')) throw new Error('docs repair worktree is not clean');
|
|
140
|
+
const local = git(tree, 'rev-parse', 'HEAD');
|
|
141
|
+
const remote = remoteHead(tree, branch);
|
|
142
|
+
if (local !== receipt.head) {
|
|
143
|
+
const parents = git(tree, 'rev-list', '--parents', '-n', '1', 'HEAD').split(' ');
|
|
144
|
+
const message = git(tree, 'log', '-1', '--format=%B', 'HEAD');
|
|
145
|
+
const changed = git(tree, 'diff-tree', '--no-commit-id', '--name-only', '-r', 'HEAD').split('\n').filter(Boolean);
|
|
146
|
+
const approved = approvedPaths.map((file) => relative(tree, realpathSync(file)));
|
|
147
|
+
if (parents.length !== 2 || parents[0] !== local || parents[1] !== receipt.head
|
|
148
|
+
|| !message.split('\n').includes(`Release-Notes-Repair-Run: ${runId}`)
|
|
149
|
+
|| !message.split('\n').includes(`Release-Notes-Repair-Attempt: ${owner.attempt}`)
|
|
150
|
+
|| !changed.length || changed.some((name) => !approved.includes(name))
|
|
151
|
+
|| (remote !== receipt.head && remote !== local))
|
|
152
|
+
throw new Error('docs repair local/remote head differs from ownership receipt');
|
|
153
|
+
if (remote === receipt.head) git(tree, 'push', 'origin', `HEAD:refs/heads/${branch}`);
|
|
154
|
+
if (remoteHead(tree, branch) !== local) throw new Error('docs repair recovery remote head verification failed');
|
|
155
|
+
receipt = { ...receipt, head: local };
|
|
156
|
+
publishReceipt(path, receipt);
|
|
157
|
+
} else if (remote !== receipt.head) throw new Error('docs repair local/remote head differs from ownership receipt');
|
|
158
|
+
return { path, receipt };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function publishDocsRepair(tree: string, files: string[], path: string, receipt: DocsReceipt): string {
|
|
162
|
+
const names = files.map((file) => relative(tree, realpathSync(file)));
|
|
163
|
+
git(tree, 'add', '--', ...names);
|
|
164
|
+
const staged = git(tree, 'diff', '--cached', '--name-only').split('\n').filter(Boolean);
|
|
165
|
+
if (staged.some((name) => !names.includes(name))) throw new Error('docs repair staged a file outside approved B11 targets');
|
|
166
|
+
if (!staged.length) return receipt.head;
|
|
167
|
+
git(tree, 'commit', '-m', `docs: repair release ${receipt.branch.split('/').at(-1)} notes`,
|
|
168
|
+
'-m', `Release-Notes-Repair-Run: ${receipt.owner.runId}\nRelease-Notes-Repair-Attempt: ${receipt.owner.attempt}`);
|
|
169
|
+
const head = git(tree, 'rev-parse', 'HEAD');
|
|
170
|
+
git(tree, 'push', 'origin', `HEAD:refs/heads/${receipt.branch}`);
|
|
171
|
+
if (remoteHead(tree, receipt.branch) !== head) throw new Error('docs repair remote head verification failed');
|
|
172
|
+
publishReceipt(path, { ...receipt, head });
|
|
173
|
+
return head;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function runNotesRepair(context: GraphContext, translate: Translator = glmTranslator,
|
|
177
|
+
deps: { stateRoot?: string } = {}): Promise<{
|
|
178
|
+
outcome: 'ok' | 'fail'; version: string; summary: string; files?: string[]; translatedLines?: number[]; head?: string; error?: string;
|
|
179
|
+
}> {
|
|
180
|
+
try {
|
|
181
|
+
if (context.outputs['notes-repair']) throw new Error('B11 remains after the single permitted translation attempt');
|
|
182
|
+
const docs = context.outputs.docs;
|
|
183
|
+
if (docs?.outcome !== 'ok' || typeof docs.notes !== 'string' || typeof docs.worktree !== 'string') throw new Error('docs output required');
|
|
184
|
+
const findings = context.outputs['notes-check']?.findings;
|
|
185
|
+
if (!Array.isArray(findings)) throw new Error('notes-check findings required');
|
|
186
|
+
const allowed = new Set([docs.notes, ...(Array.isArray(docs.flipped) ? docs.flipped : [])]
|
|
187
|
+
.filter((path): path is string => typeof path === 'string').map((path) => realpathSync(resolve(path))));
|
|
188
|
+
const worktree = realpathSync(resolve(docs.worktree));
|
|
189
|
+
const targets = new Map<string, Set<number>>();
|
|
190
|
+
for (const raw of findings) {
|
|
191
|
+
if (!raw || typeof raw !== 'object') continue;
|
|
192
|
+
const finding = raw as { rule?: unknown; file?: unknown; line?: unknown };
|
|
193
|
+
if (finding.rule !== 'B11' || typeof finding.file !== 'string' || typeof finding.line !== 'number'
|
|
194
|
+
|| !Number.isSafeInteger(finding.line) || finding.line < 1) continue;
|
|
195
|
+
const file = realpathSync(resolve(finding.file));
|
|
196
|
+
if (!file.startsWith(`${worktree}${sep}`) || !allowed.has(file)) throw new Error(`B11 target outside docs output: ${finding.file}`);
|
|
197
|
+
const lines = targets.get(finding.file) ?? new Set<number>();
|
|
198
|
+
lines.add(finding.line);
|
|
199
|
+
targets.set(finding.file, lines);
|
|
200
|
+
}
|
|
201
|
+
if (findings.some((finding) => !finding || typeof finding !== 'object' || (finding as { rule?: string }).rule !== 'B11'))
|
|
202
|
+
throw new Error('notes-check has non-B11 findings; translation cannot repair them');
|
|
203
|
+
if (!targets.size) throw new Error('notes-check failed without repairable B11 findings');
|
|
204
|
+
const files = [...targets].map(([path, lines]) => ({ path, lines: [...lines] }));
|
|
205
|
+
const { path: receiptPath, receipt } = ownedDocsReceipt(context, docs, worktree,
|
|
206
|
+
deps.stateRoot ?? effectiveInstanceRoot(), files.map((file) => file.path));
|
|
207
|
+
const result = await atomicallyRepairFiles(files, translate);
|
|
208
|
+
if (result.error) return { outcome: 'fail', version: context.input.version, summary: result.error, ...result };
|
|
209
|
+
const head = result.files.length ? publishDocsRepair(worktree, result.files, receiptPath, receipt) : receipt.head;
|
|
210
|
+
return { outcome: 'ok', version: context.input.version,
|
|
211
|
+
summary: `translated ${result.translatedLines.length} line(s)`, ...result, head };
|
|
212
|
+
} catch (error) {
|
|
213
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
214
|
+
return { outcome: 'fail', version: context.input.version, summary: message, error: message };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -21,13 +21,43 @@ function readRegularManifest(path: string): Buffer {
|
|
|
21
21
|
} finally { closeSync(fd); }
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
function releaseAttempt(root: string, version: string, runId: string): number {
|
|
25
|
+
const path = join(root, 'release', version, 'resume-attempts', `${runId}.json`);
|
|
26
|
+
if (!existsSync(path)) return 0;
|
|
27
|
+
let value: { version?: unknown; runId?: unknown; attempts?: unknown };
|
|
28
|
+
try { value = JSON.parse(readFileSync(path, 'utf8')) as typeof value; }
|
|
29
|
+
catch { throw new Error(`invalid release resume attempts: ${path}`); }
|
|
30
|
+
if (value.version !== version || value.runId !== runId || !Array.isArray(value.attempts)
|
|
31
|
+
|| value.attempts.some((at) => typeof at !== 'string' || !Number.isFinite(Date.parse(at))))
|
|
32
|
+
throw new Error(`invalid release resume attempts: ${path}`);
|
|
33
|
+
return value.attempts.length;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Old releases predate the owner receipt; their own graph ledger can still prove the prepared output. */
|
|
37
|
+
function preparedByRun(root: string, runId: string, out: string, commit: string): boolean {
|
|
38
|
+
try {
|
|
39
|
+
const ledger = JSON.parse(readFileSync(join(root, 'graph-runs', 'release-loop', `${runId}.json`), 'utf8')) as
|
|
40
|
+
{ runId?: string; graphId?: string; nodes?: Array<{ nodeId?: string; ok?: boolean; output?: string }> };
|
|
41
|
+
if (ledger.runId !== runId || ledger.graphId !== 'release-loop') return false;
|
|
42
|
+
return ledger.nodes?.some((node) => {
|
|
43
|
+
if (node.nodeId !== 'prepare' || !node.ok || typeof node.output !== 'string') return false;
|
|
44
|
+
try {
|
|
45
|
+
const output = JSON.parse(node.output.trim().split('\n').at(-1) ?? '') as { out?: string; commit?: string; outcome?: string };
|
|
46
|
+
return output.outcome === 'ok' && output.out === out && output.commit === commit;
|
|
47
|
+
} catch { return false; }
|
|
48
|
+
}) ?? false;
|
|
49
|
+
} catch { return false; }
|
|
50
|
+
}
|
|
51
|
+
|
|
24
52
|
export function runPrepare(run: CommandRunner = runCommand, move: typeof renameSync = renameSync) {
|
|
25
53
|
const context = readGraphContext();
|
|
26
54
|
const { version, previousVersion } = context.input;
|
|
27
55
|
if (!isReleaseVersion(version)) throw new Error(`invalid release version: ${version}`);
|
|
56
|
+
if (context.runId && !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(context.runId)) throw new Error('invalid release runId');
|
|
28
57
|
const commit = nodeOutput(context, 'version-release', 'commit');
|
|
29
58
|
for (const node of ['gate', 'pwa']) if (context.outputs[node]?.outcome !== 'ok') throw new Error(`${node} did not pass`);
|
|
30
59
|
const root = effectiveInstanceRoot();
|
|
60
|
+
const attempt = context.runId ? releaseAttempt(root, version, context.runId) : undefined;
|
|
31
61
|
const out = join(root, 'release', version, 'prepared');
|
|
32
62
|
if ([join(root, 'release'), join(root, 'release', version)]
|
|
33
63
|
.some((path) => lstatSync(path, { throwIfNoEntry: false })?.isSymbolicLink()))
|
|
@@ -41,22 +71,44 @@ export function runPrepare(run: CommandRunner = runCommand, move: typeof renameS
|
|
|
41
71
|
// archive is left untouched for investigation; never erase it merely because the path is occupied.
|
|
42
72
|
const old = context.outputs['version-release']?.refreshedFrom;
|
|
43
73
|
const manifestPath = join(out, 'release.json');
|
|
44
|
-
if (
|
|
45
|
-
|| !occupied.isDirectory() || !existsSync(manifestPath) || !lstatSync(manifestPath).isFile())
|
|
74
|
+
if (!occupied.isDirectory() || !existsSync(manifestPath) || !lstatSync(manifestPath).isFile())
|
|
46
75
|
throw new Error(`prepare output already exists with unverified source: ${out}`);
|
|
47
76
|
if (realpathSync(out) !== join(realpathSync(root), 'release', version, 'prepared'))
|
|
48
77
|
throw new Error(`prepare output escapes release root: ${out}`);
|
|
49
78
|
let manifest: { version?: unknown; sourceCommit?: unknown };
|
|
50
79
|
try { staleManifestBytes = readRegularManifest(manifestPath); manifest = JSON.parse(staleManifestBytes.toString('utf8')) as typeof manifest; }
|
|
51
80
|
catch { throw new Error(`prepare output already exists with unreadable manifest: ${out}`); }
|
|
52
|
-
|
|
81
|
+
const manifestSource = manifest.sourceCommit;
|
|
82
|
+
if (manifest.version !== version || typeof manifestSource !== 'string' || !/^[0-9a-f]{40}$/i.test(manifestSource)
|
|
83
|
+
|| (manifestSource !== commit && manifestSource !== old))
|
|
53
84
|
throw new Error(`prepare output already exists for another source: ${out}`);
|
|
85
|
+
const ownerPath = join(out, '.release-node-owner.json');
|
|
86
|
+
let owner: { runId?: string; commit?: string } | undefined;
|
|
87
|
+
if (existsSync(ownerPath)) {
|
|
88
|
+
try { owner = JSON.parse(readRegularManifest(ownerPath).toString('utf8')) as typeof owner; }
|
|
89
|
+
catch { throw new Error(`prepare output owner unreadable: ${out}`); }
|
|
90
|
+
}
|
|
91
|
+
const sameRun = !!context.runId && (owner?.runId === context.runId && owner.commit === manifestSource
|
|
92
|
+
|| !owner && preparedByRun(root, context.runId, out, manifestSource));
|
|
93
|
+
if (manifestSource === commit && sameRun) {
|
|
94
|
+
const candidate = join(out, 'dist', 'elanous.tgz');
|
|
95
|
+
if (!existsSync(candidate)) throw new Error(`prepare output incomplete for same run: ${out}`);
|
|
96
|
+
return { outcome: 'ok' as const, verdict: 'pass' as const,
|
|
97
|
+
summary: `prepare ${version} · ${commit.slice(0, 12)} reused`, out, candidate, commit,
|
|
98
|
+
artifactOwner: { runId: context.runId, attempt, reused: true } };
|
|
99
|
+
}
|
|
100
|
+
// A different run's complete archive is never consumed. Without a verified owner, an archive at the
|
|
101
|
+
// current tip remains untouched; a refreshed old tip can still follow the existing guarded quarantine.
|
|
102
|
+
if (manifestSource === commit && !owner?.runId)
|
|
103
|
+
throw new Error(`prepare output already exists with unverified owner: ${out}`);
|
|
104
|
+
if (manifestSource !== commit && (typeof old !== 'string' || !/^[0-9a-f]{40}$/i.test(old) || old === commit))
|
|
105
|
+
throw new Error(`prepare output already exists with unverified source: ${out}`);
|
|
54
106
|
staleParents = [join(root, 'release'), join(root, 'release', version)].map((path) => {
|
|
55
107
|
const stat = lstatSync(path);
|
|
56
108
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error(`prepare output escapes release root: ${out}`);
|
|
57
109
|
return { path, dev: stat.dev, ino: stat.ino, real: realpathSync(path) };
|
|
58
110
|
});
|
|
59
|
-
staleSource =
|
|
111
|
+
staleSource = manifestSource;
|
|
60
112
|
}
|
|
61
113
|
const ref = `v${previousVersion}^{commit}`;
|
|
62
114
|
const prev = run('git', ['rev-parse', '--verify', ref]);
|
|
@@ -119,7 +171,11 @@ export function runPrepare(run: CommandRunner = runCommand, move: typeof renameS
|
|
|
119
171
|
if (command.status !== 0 || manifest?.version !== version || manifest.sourceCommit !== commit || manifest.distDir !== join(out, 'dist')) {
|
|
120
172
|
throw new Error(`prepare incomplete (rc=${command.status}): ${lastResult(command)?.error ?? command.stderr.trim()}`);
|
|
121
173
|
}
|
|
122
|
-
|
|
174
|
+
const artifactOwner = context.runId ? { runId: context.runId, attempt, commit } : undefined;
|
|
175
|
+
if (artifactOwner && existsSync(join(out, 'release.json')))
|
|
176
|
+
writeFileSync(join(out, '.release-node-owner.json'), JSON.stringify(artifactOwner) + '\n', { flag: 'wx', mode: 0o600 });
|
|
177
|
+
return { outcome: 'ok' as const, verdict: 'pass' as const, summary: `prepare ${version} · ${commit.slice(0, 12)}`, out, candidate: join(out, 'dist', 'elanous.tgz'), commit,
|
|
178
|
+
...(artifactOwner ? { artifactOwner } : {}) };
|
|
123
179
|
}
|
|
124
180
|
|
|
125
181
|
if (import.meta.main) {
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// every later node reads the repaired commit without anyone hand-editing the run state.
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
|
-
import { constants, copyFileSync, existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
7
|
-
import { join } from 'node:path';
|
|
6
|
+
import { accessSync, closeSync, constants, copyFileSync, existsSync, fstatSync, openSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { join, resolve } from 'node:path';
|
|
8
8
|
import { debug } from '../../src/debug/log.js';
|
|
9
9
|
import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/resolve.js';
|
|
10
10
|
import { lastJsonObject, runGraph, verifyReleaseCommandRoot, verifyReleaseRecipeSnapshot, type GraphRunState } from '../../src/graph-runner/runner.js';
|
|
@@ -15,6 +15,8 @@ import { changedFilesBetween, clearPartialPlan, planPartialRegate, planStalledSh
|
|
|
15
15
|
import { gitClosureTree, testsReachingChanged, TRACEABLE_RELEASE_JSON, type ClosureTree } from './gate-closure.js';
|
|
16
16
|
import { releaseResumeAcceptedRegressions, releaseResumeGateExecutor, releaseResumeGatePodPool, releaseResumeWaiver, type AcceptedRegression } from './resume.js';
|
|
17
17
|
import { reserveReleaseResumeAttempt } from './resume-cap.js';
|
|
18
|
+
import { releaseLoopConfig } from './unattended-release.js';
|
|
19
|
+
import { trafficOptionsFromConfig } from './traffic-transition.js';
|
|
18
20
|
|
|
19
21
|
const GRAPH = join(import.meta.dir, '../../graphs/release/release-loop.yaml');
|
|
20
22
|
|
|
@@ -37,6 +39,8 @@ export interface ResumeReleaseDeps {
|
|
|
37
39
|
closureTree?: (commit: string) => ClosureTree;
|
|
38
40
|
/** Source observation before the first resumed node. */
|
|
39
41
|
onSource?: (line: string) => void;
|
|
42
|
+
/** Test seam; production resolves this from ELANOUS_RELEASE_TRAFFIC_FILE / release.loop.trafficFile. */
|
|
43
|
+
trafficFile?: string;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
export interface ResumeReleaseOptions {
|
|
@@ -80,7 +84,7 @@ function safeRunId(runId: string): string {
|
|
|
80
84
|
return runId;
|
|
81
85
|
}
|
|
82
86
|
|
|
83
|
-
/**
|
|
87
|
+
/** Lower-level maintenance primitive; the resume entrypoints run verifyResumePreflight before calling it. */
|
|
84
88
|
export function refreshReleaseBranchTip(runId: string, deps: ResumeReleaseDeps = {}, from?: string, waiverCommit?: string): TipRefresh {
|
|
85
89
|
return refreshReleaseBranchTipInternal(runId, deps, from, waiverCommit, false);
|
|
86
90
|
}
|
|
@@ -128,7 +132,7 @@ function refreshReleaseBranchTipInternal(runId: string, deps: ResumeReleaseDeps,
|
|
|
128
132
|
}
|
|
129
133
|
// A repair only appends (`cut-branch --append`): anything but a fast-forward is a different release.
|
|
130
134
|
if (!(deps.isAncestor ?? ancestorRunner(deps.repo ?? process.cwd()))(recorded, to)) {
|
|
131
|
-
throw new Error(`${branch} tip ${to} does not descend from the recorded release commit ${recorded} — refusing to resume`);
|
|
135
|
+
throw new Error(`${branch} tip ${to} does not descend from the recorded release commit ${recorded} — refusing to resume; remedy: inspect both commits and create a new release run from the intended pinned tip`);
|
|
132
136
|
}
|
|
133
137
|
// A new tip invalidates everything built from the old one (gate verdict, prepared archive, …): restart no later
|
|
134
138
|
// than the first node that consumed the commit, so each of them runs again on the new tip.
|
|
@@ -174,6 +178,110 @@ function verifyResumeRecipePin(commandRoot: string, snapshot: GraphRunState['gra
|
|
|
174
178
|
}
|
|
175
179
|
}
|
|
176
180
|
|
|
181
|
+
/** Common read-only gate for dry-run and actual resume. Every rejection includes an operator action. */
|
|
182
|
+
function verifyResumePreflight(run: GraphRunState, opts: ResumeReleaseOptions, deps: ResumeReleaseDeps,
|
|
183
|
+
version: string, recordedCommit: string, currentTip: string, commandRoot: string): void {
|
|
184
|
+
let trafficFile = deps.trafficFile;
|
|
185
|
+
if (trafficFile === undefined) {
|
|
186
|
+
try { trafficFile = trafficOptionsFromConfig(process.env, releaseLoopConfig()).trafficFile; }
|
|
187
|
+
catch (error) { throw new Error(`cannot read release traffic configuration — remedy: repair release.loop.trafficFile in the active config before resuming`, { cause: error }); }
|
|
188
|
+
}
|
|
189
|
+
if (!trafficFile) throw new Error('release.loop.trafficFile is not configured — remedy: set release.loop.trafficFile or ELANOUS_RELEASE_TRAFFIC_FILE before resuming');
|
|
190
|
+
let fd: number | undefined;
|
|
191
|
+
try {
|
|
192
|
+
const path = resolve(trafficFile);
|
|
193
|
+
const info = statSync(path);
|
|
194
|
+
if (!info.isFile() || (info.mode & 0o222) === 0) throw new Error('not a writable regular file');
|
|
195
|
+
fd = openSync(path, constants.O_WRONLY);
|
|
196
|
+
if (!fstatSync(fd).isFile()) throw new Error('not a regular file');
|
|
197
|
+
accessSync(path, constants.R_OK | constants.W_OK);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
throw new Error(`release traffic file is missing or not writable: ${trafficFile} (${error instanceof Error ? error.message : String(error)}) — remedy: create a regular writable traffic file and set release.loop.trafficFile`, { cause: error });
|
|
200
|
+
} finally { if (fd !== undefined) closeSync(fd); }
|
|
201
|
+
|
|
202
|
+
for (const path of [join(commandRoot, 'node_modules'), join(commandRoot, 'apps', 'pwa', 'node_modules')]) {
|
|
203
|
+
try { if (!statSync(path).isDirectory()) throw new Error('not a directory'); }
|
|
204
|
+
catch (error) { throw new Error(`release resume dependencies missing: ${path} — remedy: run bun install --frozen-lockfile at repository root and apps/pwa`, { cause: error }); }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const nodeOutput = (nodeId: string): Record<string, unknown> | undefined => {
|
|
208
|
+
const node = run.nodes.find((entry) => entry.nodeId === nodeId);
|
|
209
|
+
if (!node?.ok || typeof node.output !== 'string') return undefined;
|
|
210
|
+
try { return lastJsonObject(node.output) as Record<string, unknown> | undefined; } catch { return undefined; }
|
|
211
|
+
};
|
|
212
|
+
const recordedNodeOutput = (nodeId: string): Record<string, unknown> | undefined => {
|
|
213
|
+
const node = run.nodes.find((entry) => entry.nodeId === nodeId);
|
|
214
|
+
if (typeof node?.output !== 'string') return undefined;
|
|
215
|
+
try { return lastJsonObject(node.output) as Record<string, unknown> | undefined; } catch { return undefined; }
|
|
216
|
+
};
|
|
217
|
+
const roots = [...new Set([deps.root ?? effectiveInstanceRoot(), deps.ledgerRoot ?? releaseLedgerRoot()])];
|
|
218
|
+
for (const root of roots) {
|
|
219
|
+
const prepared = join(root, 'release', version, 'prepared');
|
|
220
|
+
if (existsSync(prepared)) {
|
|
221
|
+
const record = nodeOutput('prepare');
|
|
222
|
+
const output = record && typeof record.out === 'string' ? record : undefined;
|
|
223
|
+
const manifestPath = join(prepared, 'release.json');
|
|
224
|
+
let manifest: { version?: unknown; sourceCommit?: unknown } | undefined;
|
|
225
|
+
try { manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as typeof manifest; } catch { /* fail closed below */ }
|
|
226
|
+
const ownerPath = join(prepared, '.release-node-owner.json');
|
|
227
|
+
let owner: { runId?: unknown; commit?: unknown } | undefined;
|
|
228
|
+
let ownerReadable = !existsSync(ownerPath);
|
|
229
|
+
try { owner = JSON.parse(readFileSync(ownerPath, 'utf8')) as typeof owner; ownerReadable = true; } catch { /* old artifacts can be owned by the run ledger */ }
|
|
230
|
+
const ledgerOwns = output?.out === prepared && output.commit === currentTip && output.outcome === 'ok';
|
|
231
|
+
const receiptOwns = owner ? owner.runId === opts.runId && owner.commit === currentTip : ownerReadable && ledgerOwns;
|
|
232
|
+
if (!ledgerOwns || manifest?.version !== version || manifest.sourceCommit !== currentTip || !receiptOwns) {
|
|
233
|
+
throw new Error(`prepared artifact is outside the current release run ledger: ${prepared} — remedy: preserve it, compare release.json and .release-node-owner.json with run ${opts.runId}, then resolve ownership before resume`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const receiptPath = join(root, 'release', version, 'docs-branch-owner.json');
|
|
238
|
+
const docsBranch = `release-docs/${version}`;
|
|
239
|
+
let receipt: { owner?: { runId?: unknown; attempt?: unknown }; branch?: unknown; worktree?: unknown; outcome?: unknown; head?: unknown } | undefined;
|
|
240
|
+
try { receipt = JSON.parse(readFileSync(receiptPath, 'utf8')) as typeof receipt; } catch { /* no/invalid receipt is rejected if an artifact exists */ }
|
|
241
|
+
const docsRecord = recordedNodeOutput('docs');
|
|
242
|
+
const worktree = typeof docsRecord?.worktree === 'string' ? docsRecord.worktree : undefined;
|
|
243
|
+
let localBranch: string | undefined;
|
|
244
|
+
try { localBranch = (deps.git ?? gitRunner(deps.repo ?? process.cwd()))(['show-ref', '--verify', '--hash', `refs/heads/${docsBranch}`]).trim(); } catch { /* absent */ }
|
|
245
|
+
let docsWorktrees: string[] = [];
|
|
246
|
+
try {
|
|
247
|
+
const listing = (deps.git ?? gitRunner(deps.repo ?? process.cwd()))(['worktree', 'list', '--porcelain']);
|
|
248
|
+
docsWorktrees = listing.split(/\n\n+/).filter(Boolean).flatMap((entry) => {
|
|
249
|
+
const branch = /^branch (.+)$/m.exec(entry)?.[1];
|
|
250
|
+
const path = /^worktree (.+)$/m.exec(entry)?.[1];
|
|
251
|
+
return branch === `refs/heads/${docsBranch}` && path ? [path] : [];
|
|
252
|
+
});
|
|
253
|
+
} catch (error) {
|
|
254
|
+
throw new Error(`cannot inspect release worktrees for ${docsBranch} — remedy: restore read-only git access and retry resume`, { cause: error });
|
|
255
|
+
}
|
|
256
|
+
let remoteHead: string | undefined;
|
|
257
|
+
try {
|
|
258
|
+
const response = (deps.git ?? gitRunner(deps.repo ?? process.cwd()))(['ls-remote', '--heads', 'origin', `refs/heads/${docsBranch}`]);
|
|
259
|
+
const line = response.split(/\r?\n/).find((candidate) => candidate.trim().endsWith(`refs/heads/${docsBranch}`));
|
|
260
|
+
remoteHead = line?.trim().split(/\s+/)[0];
|
|
261
|
+
} catch (error) {
|
|
262
|
+
throw new Error(`cannot inspect docs branch ${docsBranch} — remedy: restore read-only git access and retry resume`, { cause: error });
|
|
263
|
+
}
|
|
264
|
+
const hasDocsArtifact = existsSync(receiptPath) || !!localBranch || !!remoteHead || docsWorktrees.length > 0;
|
|
265
|
+
const outputOwner = docsRecord?.artifactOwner as { runId?: unknown; attempt?: unknown } | undefined;
|
|
266
|
+
const receiptMatches = receipt?.branch === docsBranch && receipt.owner?.runId === opts.runId
|
|
267
|
+
&& receipt.owner.attempt === outputOwner?.attempt && outputOwner?.runId === opts.runId
|
|
268
|
+
&& typeof receipt.worktree === 'string' && worktree === receipt.worktree && docsWorktrees.includes(receipt.worktree)
|
|
269
|
+
&& existsSync(receipt.worktree);
|
|
270
|
+
if (hasDocsArtifact && !receiptMatches) {
|
|
271
|
+
throw new Error(`docs branch/worktree is outside the current release run ledger: ${docsBranch} — remedy: compare ${receiptPath} with the saved docs node output and resolve ownership before resume`);
|
|
272
|
+
}
|
|
273
|
+
if (receipt?.outcome === 'pushed' && (!/^[0-9a-f]{40}$/i.test(String(receipt.head ?? ''))
|
|
274
|
+
|| remoteHead?.toLowerCase() !== String(receipt.head).toLowerCase())) {
|
|
275
|
+
throw new Error(`docs branch tip differs from the saved ownership receipt: ${docsBranch} — remedy: preserve the branch and worktree, compare the remote tip with ${receiptPath} and the saved docs node output, then resolve ownership before resume`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const recorded = nodeOutput('version-release');
|
|
280
|
+
if (recorded?.branch !== `release/${version}` || recorded.commit !== recordedCommit || !/^[0-9a-f]{40}$/i.test(currentTip)) {
|
|
281
|
+
throw new Error(`release branch tip does not match the saved version-release ledger for ${version} — remedy: inspect the branch and saved run ${opts.runId}, then resume from a node before gate only after resolving the mismatch`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
177
285
|
/** GATE-PARTIAL outcome of a resume — applied (plan written) or the reason it fell back to a full gate. `auto` marks the
|
|
178
286
|
* default plan of `--from gate` (GATE-REUSE-BY-DIFF); `closure` is set when code changes were followed. */
|
|
179
287
|
export type PartialOutcome = { requested: false }
|
|
@@ -355,6 +463,7 @@ async function planResumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: Resu
|
|
|
355
463
|
const tip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, true);
|
|
356
464
|
verifyResumeRecipePin(opts.commandRoot ?? process.cwd(), savedRun.graphSnapshot, tip.version);
|
|
357
465
|
const commandRoot = verifyReleaseCommandRoot(opts.commandRoot ?? process.cwd(), tip.to, deps.git);
|
|
466
|
+
verifyResumePreflight(savedRun, opts, deps, tip.version, tip.from, tip.to, commandRoot);
|
|
358
467
|
const partial = preparePartial(tip, opts, deps, true);
|
|
359
468
|
const fromIndex = savedRun.path.indexOf(opts.from);
|
|
360
469
|
const gateIndex = savedRun.path.indexOf('gate');
|
|
@@ -410,6 +519,7 @@ async function resumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: ResumeRe
|
|
|
410
519
|
const previewTip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, true);
|
|
411
520
|
verifyResumeRecipePin(opts.commandRoot ?? process.cwd(), savedRun.graphSnapshot, previewTip.version);
|
|
412
521
|
const commandRoot = verifyReleaseCommandRoot(opts.commandRoot ?? process.cwd(), previewTip.to, deps.git);
|
|
522
|
+
verifyResumePreflight(savedRun, opts, deps, previewTip.version, previewTip.from, previewTip.to, commandRoot);
|
|
413
523
|
const tip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, false, previewTip.to);
|
|
414
524
|
const partial = preparePartial(tip, opts, deps);
|
|
415
525
|
// A failed preflight does not consume an observed release resume attempt.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Resume tests need the same writable traffic-file prerequisite as the installed release configuration.
|
|
2
|
+
// This module is imported only by test files; the gate process owns and discards this environment.
|
|
3
|
+
import { rmSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
const trafficFile = join(tmpdir(), `elanous-resume-test-traffic-${process.pid}.json`);
|
|
8
|
+
writeFileSync(trafficFile, '{}\n');
|
|
9
|
+
process.env.ELANOUS_RELEASE_TRAFFIC_FILE = trafficFile;
|
|
10
|
+
process.once('exit', () => rmSync(trafficFile, { force: true }));
|