elanous 0.2.37 → 0.2.40
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/{8kITumG9GAZ1LwT9POrAR → HjeK7zONHfR7op1hKXp4k}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{1746.3563617ea64023a3.js → 1060.014f1f01a17aec26.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9151.a2c51e93f9156dae.js → 1281.d81877e35b9068f4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1350.59f40e39e02d91b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1415.79821ec7ae99acdb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1452.162bb2d9d699e82a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/147.f92f63bbc5e85fa5.js +286 -0
- package/apps/pwa/out/_next/static/chunks/1537-6bb97b5214928ea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1661.fb425a1d8a065b72.js +149 -0
- package/apps/pwa/out/_next/static/chunks/1671-1c22b40b50b208f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1758.0204d3f48783c49d.js +90 -0
- package/apps/pwa/out/_next/static/chunks/1806.027bf78b6a94d340.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{3578.4e9f9948a9a6f2f4.js → 2047.8f23e210995d4548.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7424.c0fe2a595d4232b5.js → 2066.a77257c8c350770a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2096-a938496bc996dcbd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4931.95cc6dbd230774ca.js → 2177.df8547f9d7215c4e.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6680.6a693c28aae4cd19.js → 2226.2cf61ec781827219.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2281-b8cede695c6c650e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2499.02fbfd18126c10c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6252.240578f10952e091.js → 2522.f2766b76d22c8bdf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1262.a89bb27a5b2f844e.js → 2566.beaffc3a5e1fcd2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/261.0d471e8aded799f3.js +226 -0
- package/apps/pwa/out/_next/static/chunks/2615.3c9738153de3ef3f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2727.e703d99ac414916d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2752.7904b8df0254d0ae.js +27 -0
- package/apps/pwa/out/_next/static/chunks/2762-5051a862dfa40e99.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2767-31784bfedf8e245d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2318-450e75d07605b8fe.js → 2774-719820e3f5b2a3eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4725-34bed25720cc326b.js → 2829-734fe8bf2eee7347.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/311-32dcac79970985e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3175-f93f7495cd28253c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3184.8da993f5502d2140.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3231-d7c981db0ff8bdcc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3250.151309c5176d6b4b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3330.7443183b7e6fdbdf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3517.a5aa1797a9dbf2ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3567-45f676877ed9e8a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3746-f80a78f220bf37b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3819.8a1de79b2e8c7298.js +24 -0
- package/apps/pwa/out/_next/static/chunks/39.9b37b0be4c128a83.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{4337e36d.f42c3b391b3d8f20.js → 3b355b3d.6f73c98bf6f9c749.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4023.a19045970a9ce16a.js +36 -0
- package/apps/pwa/out/_next/static/chunks/{58edce7d.f1b0c72acf13b123.js → 409c787b.e48c5bec8ec10456.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/413-24c8284bda08241d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4135.e45d6ebc29e20647.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4283.65502f5d0e6ff6c0.js +287 -0
- package/apps/pwa/out/_next/static/chunks/4305-4e28fa92a7b34a5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4335-50efa61fd7613142.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4351.0f37a6db2b34d50b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5046.7fd5cbd859299448.js → 470.51a72a2348306455.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4720.ecbd1693fa151068.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2375.bf364c85dbb6f085.js → 4769.9fd582071301f382.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/483.725e4a61be922788.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{de8446d3.31b73eb239fecd7b.js → 4864a2ca.1c1c280a7772c5e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4969-4b209d7307410c00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5068-c7f53862f83c0917.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5315.bc96711c24dfefe2.js +74 -0
- package/apps/pwa/out/_next/static/chunks/{4383.18e5c54db3a22c88.js → 5383.bdfa5d886e39a826.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5436.fdf6fa8ae3e9588d.js +64 -0
- package/apps/pwa/out/_next/static/chunks/5542.efbf14f16baed4dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5622.94893f5aea7185d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5644.8f401a25601d05fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5658.35f70eb9871a54bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5721.7bdc0e904c76ab51.js +8 -0
- package/apps/pwa/out/_next/static/chunks/5790-eef0ca20884a6bdf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5802.ef0d8598ca68fe84.js +62 -0
- package/apps/pwa/out/_next/static/chunks/5890.fb974729788dcb71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5924.5ef25cddd36d5dbf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5979-e59c099ebf8d1f35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6020.714cfeada2315e2e.js +94 -0
- package/apps/pwa/out/_next/static/chunks/6027-dfe0349d8c50f698.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6745-5a63492933959dd9.js → 6051-0ae955eedb10adb9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6178.bc4730c86cf74536.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2283.edd9627b7bdfb546.js → 6257.c0037b8949239f5e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6273.d808b0dcb3c2b155.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6292.6ef1df64fa6a4c8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/647-af8dd920ba46533c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541-170dc5c59e135c0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6624.981ef7caeb680560.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6742-a1ad4a94ba7bc37a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6819.be5c9c4d67f22922.js → 6749.0744ce6eb08d40e9.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/6836-493dc55c39187949.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6856-53ac421c06039a18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6908.06008c67f6380ea9.js +148 -0
- package/apps/pwa/out/_next/static/chunks/6915.096931864206f522.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6925.5e181fb7dcf90193.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6cc1d1d6.9a98dd4622f1afc6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7203-800e11037adc41eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7219-15bdd9a80661af8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7279.6170f591105936bb.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7349-373165c7fbdcc3df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7514-a533ba0ca1cae4f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7515.1ad6efe157fa4448.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7521.d919cc1fab80c1d9.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7538.90e97bbdf9178cff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7611.85f045bf232053ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7825-39203196a12579b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7869.5e1a9a12fd70d6c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8086.1ab9103c41be884f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8099.1cccf31c1baa7e1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8179-e61fffbdb70f1152.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8265.bdeb991b34db6a06.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2002-a43a3f380df873ec.js → 8272-025653884f9645d2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7867.e8725745ddd1d940.js → 8357.1aaa713b052a78b1.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/8638-e42615f2166165b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8639-92c11d069792429e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8691.54e22831d5e8ccf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8d173e38.18a2f7b4e1848bdb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9069.657590a84afb8fac.js +41 -0
- package/apps/pwa/out/_next/static/chunks/9125-ae588d88a0293b93.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4313.76f232c304a15bde.js → 9175.2de5209a5ce6f68a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9184.45afbf44fec87574.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8c58d09b.e8724a299658d86f.js → 9189505a.980427ac048c8c60.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9311.f9f641a46a508611.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9371-a6fee8378ebfa3ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9421-3aa9ff4fa7f63d8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9992.07ce73c10bd5e6a1.js +79 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1b948637c37b3abd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-c63400f1bcf3e47c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-95d0957267819586.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ba957ff875a026a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-bb6fd0714879cb87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8f9038520d2acbef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d4b48397e05fce2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-72d5744245dc0c27.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-37625dc8300fa43a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-fbef9d160272dbc1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-58424168df84928e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-72c12ba430ac57c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-d53f3e9ed806d7e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-4d2fbd45feee0829.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-8783dc0ed7590a2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-3706cb390606e930.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-9b0a86598e0111fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-3337c6a1328c2674.js → page-4edb8df90f4537ce.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83d27757e2b8060a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-47398b9ba1cc5e1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-fb86f55cfe2e681d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e22345fc8fd47b1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-1e5da297557d2354.js → page-fca2e59a81744d9e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-6e96bda63100b31e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-4d17ad8e0db8cea4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-121f92766c33beaa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-43f14212c545f92d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ccec2023e7a974ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b04f33f548b89a94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-c8792823c0917021.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-8c0e32782ceef4cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-94bd3922eb230ce8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bca565887bafa03c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ac1dffafe649fc6c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-52374edb5e23e455.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ad4ebca120d43ca7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-718b89ce4b4ae4e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-204eca33eeeaddec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-e58ba9bcdb9ac0f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-98f6dd50bafd7734.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-ac2c1e6169cfce57.js → page-139d722de1dcd6c1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-5a4bdd72bff27057.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-6f6ab17d44f984ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-aabb7bd15fb72da9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e4322319164a4436.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-e9efc0c8f32e2371.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-c1c80e345fa9d6f5.js → page-ccde99f07aaf71f7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d9815f84.4918f682a45a8502.js → b84cad00.594027ebe0531fe2.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/c696986b.5dc8bb1143af16d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{709a918c.4fd3b4e2a32cb4e3.js → ca3702f8.2913182e73889fa2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/d5d3cefc-373c4eb722ed848b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5f6af561-f90b7a67f4f75d13.js → d8de0de2-dd0f4ac8e5ab1832.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-002b472a66935d31.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-49b88d47292c0476.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-fff2549cb10a133f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-32abbbba3f3b76b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-9d9cfef60c60dd7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-cc7f483fa294034a.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
- package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
- package/graphs/demo/persona-marketer/recipes.yaml +19 -0
- package/graphs/release/recipes.yaml +9 -0
- package/graphs/release/release-loop.yaml +26 -18
- package/graphs/video/explainer-line.yaml +4 -1
- package/package.json +1 -1
- package/scripts/ask-op-inbox-once.ts +17 -0
- package/scripts/brand/check.ts +13 -4
- package/scripts/dead-code/report.ts +169 -0
- package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
- package/scripts/gate-0226-failure-census.ts +39 -0
- package/scripts/intake-collect-telegram-saved-stage.ts +48 -0
- package/scripts/lib/morning-report-options.ts +3 -4
- package/scripts/lib/tui-regress-evidence.ts +56 -0
- package/scripts/morning-report.ts +5 -1
- package/scripts/provision-export-redactions.ts +15 -0
- package/scripts/public-copy-lint.ts +122 -0
- package/scripts/public-export.ts +77 -2
- package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
- package/scripts/ratchets/train-side-invariants.sh +7 -1
- package/scripts/release-loop/cut-branch.ts +61 -12
- package/scripts/release-loop/export-check-node.ts +21 -3
- package/scripts/release-loop/gate-node.ts +527 -60
- package/scripts/release-loop/gate-partial.ts +82 -3
- package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
- package/scripts/release-loop/gate-radius-live.ts +4 -2
- package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
- package/scripts/release-loop/gate-shard-receipts.ts +89 -0
- package/scripts/release-loop/gate-wall.ts +5 -5
- package/scripts/release-loop/preflight.ts +6 -2
- package/scripts/release-loop/resume-cap.ts +2 -1
- package/scripts/release-loop/resume-release.ts +317 -13
- package/scripts/release-loop/resume.ts +61 -5
- package/scripts/release-loop/traffic-node.ts +12 -4
- package/scripts/release-loop/traffic-transition.ts +53 -13
- package/scripts/release-loop/version-node.ts +35 -5
- package/scripts/release-story/draft.ts +1 -1
- package/scripts/research-bench/README.md +53 -0
- package/scripts/research-bench/questions.json +66 -0
- package/scripts/research-bench/rubric.md +33 -0
- package/scripts/research-bench/run.ts +523 -0
- package/scripts/tui-regress.ts +85 -10
- package/scripts/ux-sim.ts +1 -1
- package/scripts/video-pipeline.ts +2 -2
- package/src/acp/core-turn-bridge.ts +14 -1
- package/src/agent/autonomous-tools.ts +10 -3
- package/src/agent/monad-agent-turn.ts +4 -1
- package/src/agent/registry.ts +26 -2
- package/src/agent/run-context.ts +1 -1
- package/src/agent/shared-app-tools.ts +1 -1
- package/src/agent/surface-ux/build.ts +12 -3
- package/src/agent/surface-ux/types.ts +1 -1
- package/src/agent/task-notification.ts +78 -7
- package/src/agent/types.ts +3 -0
- package/src/agent-mission/driver.ts +29 -3
- package/src/agent-mission/mission-cli.ts +2 -1
- package/src/agent-substrate/review-context-pack.ts +365 -0
- package/src/agent-substrate/review-observation.ts +10 -0
- package/src/agent-substrate/self-review-cli.ts +419 -42
- package/src/ask-user-question/index.ts +6 -0
- package/src/ask-user-question/inline-resolver.ts +49 -0
- package/src/auto-research/question-ladder-contract.ts +156 -0
- package/src/auto-research/research-turn.ts +467 -0
- package/src/autopilot/agent-loop.ts +1 -1
- package/src/autopilot/discovery/doc-lint.ts +1 -1
- package/src/autopilot/pty-control-loop.ts +8 -1
- package/src/boot/daemon-tools/index.ts +4 -3
- package/src/boot/daemon-tools/self-implement.ts +270 -2
- package/src/boot/daemon-tools/types.ts +2 -0
- package/src/bots/screen-probe.ts +1 -1
- package/src/budget/llm-cost.ts +44 -5
- package/src/budget/unified-usage.ts +17 -1
- package/src/capture/tui-self-report.ts +24 -2
- package/src/chat/index.ts +34 -7
- package/src/chat/tool-render/dispatch.ts +8 -1
- package/src/cli/agent-cli.ts +43 -8
- package/src/cli/guardian-cli.ts +3 -1
- package/src/cli/intake-cli.ts +70 -13
- package/src/cli/lesson-cli.ts +86 -10
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/pod-cli.ts +17 -2
- package/src/cli/pr-land-overlap-evidence.ts +38 -5
- package/src/cli/pr-land-refusal.ts +1 -1
- package/src/cli/pty-takeover-cli.ts +125 -12
- package/src/cli/release-checklist-read-cli.ts +5 -2
- package/src/cli/release-cli.ts +99 -15
- package/src/cli/repo-cli.ts +2 -1
- package/src/cli/review-carry.ts +77 -0
- package/src/cli/self-update.ts +1 -1
- package/src/cli/tasks-card-show.ts +31 -1
- package/src/cli/tasks-cli.ts +98 -32
- package/src/cli/tasks-read-cli.ts +13 -5
- package/src/context-bus/context-now.ts +86 -2
- package/src/control-plane/ledger.ts +21 -4
- package/src/core-turn/run-core-turn.ts +51 -3
- package/src/core-turn/run-goal-loop.ts +152 -8
- package/src/core-turn/types.ts +12 -0
- package/src/dashboard/chat/acp-chat.ts +2 -2
- package/src/dashboard/classic-sigquit.ts +16 -0
- package/src/dashboard/index.ts +339 -44
- package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
- package/src/dashboard/input/chat-main-slash-command.ts +7 -0
- package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
- package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
- package/src/dashboard/input/external-input-host.ts +2 -0
- package/src/dashboard/input/terminal-modal-router.ts +8 -159
- package/src/dashboard/side-basic-runtime.ts +61 -0
- package/src/dashboard/sidetab-runtime.ts +228 -0
- package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +22 -8
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
- package/src/dashboard/term-slash-runtime.ts +18 -18
- package/src/dashboard/turn-preamble.ts +30 -4
- package/src/domains/guardian-tick.ts +9 -0
- package/src/domains/knowledge.ts +1 -1
- package/src/esc-abort-gate.ts +33 -1
- package/src/execution-loop/launch-gate.ts +206 -1
- package/src/git-fs/watcher.ts +27 -22
- package/src/git-fs/worktree.ts +19 -3
- package/src/graph-runner/graph-cli.ts +6 -4
- package/src/graph-runner/graph-grow.ts +37 -9
- package/src/graph-runner/runner.ts +48 -11
- package/src/graph-wizard/generate.ts +16 -7
- package/src/graph-wizard/mission-compose.ts +201 -0
- package/src/grok/agent-search.ts +8 -2
- package/src/grok/credential.ts +112 -36
- package/src/grounding/ref-index.ts +11 -0
- package/src/grounding/ref-vector.ts +61 -0
- package/src/grounding/sources-cli.ts +2 -2
- package/src/grounding/sources.ts +15 -1
- package/src/harness/harness-cli-command.ts +38 -9
- package/src/harness/harness-pod-dispatch.ts +7 -1
- package/src/hq/fence-wrapper.ts +1 -1
- package/src/hq/transfer.ts +1 -1
- package/src/index.ts +60 -16
- package/src/input/external-input-queue.ts +10 -0
- package/src/intake-plane/collect-telegram-saved.ts +90 -6
- package/src/intake-plane/intake-to-tasks.ts +246 -3
- package/src/interactive-terminal-modal.ts +3 -0
- package/src/keybindings.ts +17 -22
- package/src/lessons/friction-ledger.ts +154 -0
- package/src/live-supply/collector.ts +149 -0
- package/src/live-supply/probes.ts +52 -0
- package/src/live-supply/snapshot.ts +40 -0
- package/src/llm/provider-credentials.ts +1 -1
- package/src/llm-tool-schema.ts +20 -0
- package/src/llm.ts +486 -61
- package/src/loops/orchestrator/inbox-once.ts +28 -0
- package/src/loops/orchestrator/inbox.ts +130 -1
- package/src/loops/orchestrator/tick.ts +14 -3
- package/src/maturity/feature-maturity.ts +1 -0
- package/src/nexus/api/channel-ask-op.ts +96 -0
- package/src/nexus/api/discord-trigger-bot.ts +28 -1
- package/src/nexus/api/harness-api.ts +2 -1
- package/src/nexus/api/telegram-trigger-bot.ts +24 -0
- package/src/nexus/api/terminals.ts +28 -6
- package/src/patents/ledger.ts +18 -1
- package/src/preview/terminal.ts +4 -2
- package/src/prompt-cache/anthropic.ts +2 -0
- package/src/prompt-enhance/enhance.ts +5 -0
- package/src/pty/snapshot.py +132 -0
- package/src/pty-shell/pty-control-ipc.ts +29 -2
- package/src/pty-shell/pty-manifest.ts +75 -5
- package/src/pty-shell/registry.ts +2 -0
- package/src/pty-shell/tui-run-state.ts +80 -3
- package/src/release-loop/gate-host-reservation.ts +13 -4
- package/src/release-loop/gate-shard-ledger.ts +68 -0
- package/src/release-loop/gate-shards.ts +61 -0
- package/src/release-loop/light-rc.ts +7 -4
- package/src/release-loop/merged-pr-checklist.ts +25 -2
- package/src/release-loop/rehearsal-shard-plan.ts +6 -1
- package/src/release-loop/rehearsal.ts +28 -1
- package/src/repl/index.ts +10 -0
- package/src/research/axis-fanout.ts +133 -0
- package/src/research/edge-decision.ts +197 -0
- package/src/research/gap-followup.ts +249 -0
- package/src/research/lenses/counter-evidence.ts +100 -0
- package/src/research/lenses/working-backwards.ts +89 -0
- package/src/research/output-router.ts +127 -0
- package/src/research/plugin-discovery.ts +242 -0
- package/src/research-bridge/format.ts +16 -1
- package/src/research-bridge/index.ts +1 -0
- package/src/research-bridge/invoke.ts +45 -7
- package/src/research-bridge/types.ts +2 -0
- package/src/self-dev/ask-launch-flow.ts +34 -106
- package/src/self-dev/decompose.ts +45 -9
- package/src/self-dev/dev-cli.ts +2 -0
- package/src/self-dev/dev-pipeline.ts +8 -4
- package/src/self-dev/draft-residue.ts +221 -2
- package/src/self-dev/draft-sweep.ts +29 -16
- package/src/self-dev/graph-journey-route.ts +10 -2
- package/src/self-dev/launch-preflight-text.ts +2 -2
- package/src/self-dev/launch-preflight.ts +38 -7
- package/src/self-dev/orchestrate-cli.ts +1 -0
- package/src/self-dev/orchestrate.ts +1 -0
- package/src/self-dev/run-supervisor.ts +41 -7
- package/src/self-dev/shard-run.ts +260 -3
- package/src/self-implement/comment-only-source.ts +54 -0
- package/src/self-implement/device-first.ts +8 -2
- package/src/self-implement/doctor-visit.ts +100 -57
- package/src/self-implement/gate-artifacts.ts +5 -2
- package/src/self-implement/gate-baseline.ts +119 -13
- package/src/self-implement/gate-cli.ts +466 -93
- package/src/self-implement/gate-failure-signature.ts +44 -0
- package/src/self-implement/gate-receipt-registry.ts +180 -0
- package/src/self-implement/gate-remote.ts +147 -22
- package/src/self-implement/goal-author-clarification.ts +178 -24
- package/src/self-implement/goal-author-decompose.ts +24 -15
- package/src/self-implement/goal-author.ts +82 -7
- package/src/self-implement/goal-doc/section.ts +22 -0
- package/src/self-implement/goal-supervisor-fill.ts +38 -4
- package/src/self-implement/host-regate.ts +120 -45
- package/src/self-implement/impl-findings-feedback.ts +188 -0
- package/src/self-implement/knowhow-pack.ts +301 -9
- package/src/self-implement/l8-merge-queue.ts +198 -32
- package/src/self-implement/off-diff-evidence.ts +147 -0
- package/src/self-implement/orchestrator.ts +137 -16
- package/src/self-implement/pod-inplace-worktree.ts +82 -0
- package/src/self-implement/pod-warm-pool-profile.ts +2 -2
- package/src/self-implement/premise-review.ts +7 -5
- package/src/self-implement/run-ledger.ts +304 -8
- package/src/self-implement/run-stop.ts +12 -0
- package/src/self-implement/seams.ts +39 -13
- package/src/self-implement/self-implement-cli.ts +30 -4
- package/src/session/channel-ask-op-envelope.ts +36 -0
- package/src/session/channel-op-reply-route.ts +200 -0
- package/src/session/chat.ts +92 -15
- package/src/session/index.ts +2 -0
- package/src/session-runtime/index.ts +9 -22
- package/src/session-runtime/provider-circuit.ts +140 -0
- package/src/shell-runner/file-engine.ts +1 -0
- package/src/shell-runner/types.ts +4 -0
- package/src/sidetab-core/model.ts +176 -0
- package/src/skills/runner.ts +7 -3
- package/src/skills/tools/dev-harness.ts +2 -2
- package/src/skills/tools/schedule-wakeup.ts +24 -7
- package/src/skills/tools/shell.ts +51 -5
- package/src/status/bar.ts +3 -3
- package/src/steward/directive-audit.ts +354 -0
- package/src/storage/file-lock.ts +17 -4
- package/src/surface/child-process.ts +31 -0
- package/src/surface/tui-stderr-owner.ts +48 -0
- package/src/task-agent/adopt-pr.ts +63 -2
- package/src/task-agent/cover.ts +30 -12
- package/src/task-agent/evidence-command-normalize.ts +42 -0
- package/src/task-agent/export-redactions-provision.ts +43 -0
- package/src/task-agent/judge.ts +56 -0
- package/src/task-agent/parent-host.ts +59 -12
- package/src/task-agent/postland-card.ts +35 -2
- package/src/task-agent/rejudge-on-head.ts +46 -2
- package/src/task-agent/repair-cycle.ts +68 -9
- package/src/task-agent/repair-worker.ts +37 -1
- package/src/task-agent/task-hand.ts +226 -33
- package/src/task-agent/tier-split.ts +142 -24
- package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
- package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +57 -5
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
- package/src/task-orchestrator/surfaces/pod-pool.ts +27 -4
- package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +310 -79
- package/src/task-orchestrator/surfaces/self-implement.ts +33 -2
- package/src/terminal/session-registry.ts +1 -0
- package/src/terminal/terminal-modal-router.ts +156 -0
- package/src/tool-hints/gate.ts +6 -4
- package/src/tool-hints/signals.ts +33 -1
- package/src/tool-runtime/skill-exec-runtime.ts +95 -5
- package/src/tui/chat/background-job-status.ts +8 -2
- package/src/tui/entry.ts +483 -32
- package/src/tui/inline-choice.ts +188 -0
- package/src/tui/sidetab/attach.ts +304 -0
- package/src/tui/sidetab/list.ts +2 -0
- package/src/tui/sidetab/nl-tool.ts +136 -0
- package/src/tui/slash/resume-command.ts +23 -0
- package/src/tui/slash/resume.ts +3 -23
- package/src/tui/slash/term-next.ts +2 -1
- package/src/tui/slash/term.ts +12 -1
- package/src/tui-client/dashboard-session.ts +7 -1
- package/src/tui-client/local-chat-turn.ts +29 -8
- package/src/user-config.ts +42 -3
- package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
- package/src/ux-sim/fake-land-queue.ts +88 -0
- package/src/ux-sim/fake-llm.ts +11 -5
- package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
- package/src/ux-sim/goal-interim-trace.ts +24 -0
- package/src/ux-sim/next-tui-seat-scenarios.ts +61 -14
- package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/recipes/explainer.ts +54 -2
- package/src/web-search/grok.ts +32 -6
- package/src/web-search/index.ts +8 -7
- package/src/workflow-runtime/node-catalog.ts +53 -4
- package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +0 -62
- package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +0 -32
- package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +0 -148
- package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +0 -27
- package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3199.6a1a9b0e6cd01dc6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +0 -90
- package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +0 -226
- package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +0 -287
- package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +0 -24
- package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +0 -104
- package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +0 -1
- package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +0 -93
- package/apps/pwa/out/_next/static/chunks/5952.294fc574a8625184.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +0 -74
- package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +0 -149
- package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +0 -41
- package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +0 -1
- package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +0 -1
- package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7c5ed21f-f286708e57cf88f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +0 -8
- package/apps/pwa/out/_next/static/chunks/8080-40d781e7704d3671.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +0 -77
- package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +0 -1
- package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +0 -286
- package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +0 -79
- package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +0 -94
- package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +0 -1
- package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +0 -64
- package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-88a1edbff62eaf1d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +0 -1
- package/scripts/migrate-monad-to-elanous.ts +0 -195
- package/scripts/rebrand-elanous.ts +0 -242
- /package/apps/pwa/out/_next/static/{8kITumG9GAZ1LwT9POrAR → HjeK7zONHfR7op1hKXp4k}/_ssgManifest.js +0 -0
|
@@ -3,23 +3,32 @@
|
|
|
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 { accessSync, closeSync, constants, copyFileSync, existsSync, fstatSync, openSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from 'node:fs';
|
|
7
|
-
import {
|
|
6
|
+
import { accessSync, closeSync, constants, copyFileSync, existsSync, fstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, realpathSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
8
|
+
import { dirname, join, resolve } from 'node:path';
|
|
8
9
|
import { debug } from '../../src/debug/log.js';
|
|
9
10
|
import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/resolve.js';
|
|
10
11
|
import { lastJsonObject, runGraph, verifyReleaseCommandRoot, verifyReleaseRecipeSnapshot, type GraphRunState } from '../../src/graph-runner/runner.js';
|
|
11
12
|
import { withOpSeatFlock } from '../../src/steward/resync-tick.js';
|
|
12
13
|
import { releaseRunUniverse } from './release-universe.js';
|
|
13
14
|
import { isReleaseVersion } from './release-version.js';
|
|
14
|
-
import { changedFilesBetween, clearPartialPlan, planPartialRegate, planStalledShardRecheck, writePartialPlan, writeRecheckPlan } from './gate-partial.js';
|
|
15
|
+
import { changedFilesBetween, clearPartialPlan, collectExecutedPodShardImages, planPartialRegate, planStalledShardRecheck, writePartialPlan, writeRecheckPlan } from './gate-partial.js';
|
|
15
16
|
import { gitClosureTree, testsReachingChanged, TRACEABLE_RELEASE_JSON, type ClosureTree } from './gate-closure.js';
|
|
16
|
-
import { releaseResumeAcceptedRegressions, releaseResumeGateExecutor, releaseResumeGatePodPool, releaseResumeWaiver, type AcceptedRegression } from './resume.js';
|
|
17
|
+
import { assertReleaseResumeApprovalBoundary, releaseResumeAcceptedRegressions, releaseResumeGateExecutor, releaseResumeGatePodPool, releaseResumeGateShardReroute, releaseResumeWaiver, type AcceptedRegression } from './resume.js';
|
|
17
18
|
import { reserveReleaseResumeAttempt } from './resume-cap.js';
|
|
19
|
+
import { cutReleaseBranch } from './cut-branch.js';
|
|
18
20
|
import { releaseLoopConfig } from './unattended-release.js';
|
|
19
21
|
import { trafficOptionsFromConfig } from './traffic-transition.js';
|
|
20
22
|
|
|
21
23
|
const GRAPH = join(import.meta.dir, '../../graphs/release/release-loop.yaml');
|
|
22
24
|
|
|
25
|
+
/** Compare existing artifact paths by filesystem identity so macOS /var and /private/var aliases agree. */
|
|
26
|
+
function sameRealPath(left: unknown, right: unknown): boolean {
|
|
27
|
+
if (typeof left !== 'string' || typeof right !== 'string') return false;
|
|
28
|
+
try { return realpathSync(left) === realpathSync(right); }
|
|
29
|
+
catch { return false; }
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
export interface ResumeReleaseDeps {
|
|
24
33
|
root?: string;
|
|
25
34
|
repo?: string;
|
|
@@ -46,6 +55,7 @@ export interface ResumeReleaseDeps {
|
|
|
46
55
|
export interface ResumeReleaseOptions {
|
|
47
56
|
runId: string; from: string; partial?: boolean; waive?: string; reason?: string;
|
|
48
57
|
acceptedRegressions?: AcceptedRegression[]; gateExecutor?: string; gateHost?: string; gatePodPool?: string;
|
|
58
|
+
rerouteShard?: string; shardHost?: string; shardOs?: 'darwin' | 'linux';
|
|
49
59
|
commandRoot?: string;
|
|
50
60
|
}
|
|
51
61
|
|
|
@@ -227,7 +237,8 @@ function verifyResumePreflight(run: GraphRunState, opts: ResumeReleaseOptions, d
|
|
|
227
237
|
let owner: { runId?: unknown; commit?: unknown } | undefined;
|
|
228
238
|
let ownerReadable = !existsSync(ownerPath);
|
|
229
239
|
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
|
|
240
|
+
const ledgerOwns = output !== undefined && sameRealPath(output.out, prepared)
|
|
241
|
+
&& output.commit === currentTip && output.outcome === 'ok';
|
|
231
242
|
const receiptOwns = owner ? owner.runId === opts.runId && owner.commit === currentTip : ownerReadable && ledgerOwns;
|
|
232
243
|
if (!ledgerOwns || manifest?.version !== version || manifest.sourceCommit !== currentTip || !receiptOwns) {
|
|
233
244
|
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`);
|
|
@@ -265,8 +276,8 @@ function verifyResumePreflight(run: GraphRunState, opts: ResumeReleaseOptions, d
|
|
|
265
276
|
const outputOwner = docsRecord?.artifactOwner as { runId?: unknown; attempt?: unknown } | undefined;
|
|
266
277
|
const receiptMatches = receipt?.branch === docsBranch && receipt.owner?.runId === opts.runId
|
|
267
278
|
&& receipt.owner.attempt === outputOwner?.attempt && outputOwner?.runId === opts.runId
|
|
268
|
-
&& typeof receipt.worktree === 'string' && worktree
|
|
269
|
-
&&
|
|
279
|
+
&& typeof receipt.worktree === 'string' && sameRealPath(worktree, receipt.worktree)
|
|
280
|
+
&& docsWorktrees.some((listedWorktree) => sameRealPath(listedWorktree, receipt.worktree));
|
|
270
281
|
if (hasDocsArtifact && !receiptMatches) {
|
|
271
282
|
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
283
|
}
|
|
@@ -290,7 +301,7 @@ export type PartialOutcome = { requested: false }
|
|
|
290
301
|
|
|
291
302
|
/** Build (or clear) the partial re-gate plan for the new tip. Fail-closed: any doubt leaves a full gate.
|
|
292
303
|
* GATE-REUSE-BY-DIFF: `--from gate` on a moved tip plans by default (`partial: undefined`); `partial: false` opts out. */
|
|
293
|
-
function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean }, deps: ResumeReleaseDeps, dryRun = false): PartialOutcome {
|
|
304
|
+
function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean; gateExecutor?: string }, deps: ResumeReleaseDeps, dryRun = false): PartialOutcome {
|
|
294
305
|
const root = deps.root ?? effectiveInstanceRoot();
|
|
295
306
|
// Any resume starts from no plan: one without a partial plan (from whatever node) never inherits an older plan.
|
|
296
307
|
if (!dryRun) clearPartialPlan(root, tip.version);
|
|
@@ -328,7 +339,7 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
|
|
|
328
339
|
for (const item of stalled) {
|
|
329
340
|
if (!item || typeof item !== 'object' || !Array.isArray((item as { files?: unknown }).files)
|
|
330
341
|
|| !(item as { files: unknown[] }).files.every((file) => typeof file === 'string')
|
|
331
|
-
|| !['incomplete', 'no-output', 'job-failed', 'exit-code', 'unattributed', 'timeout'].includes(String((item as { reason?: unknown }).reason)))
|
|
342
|
+
|| !['incomplete', 'no-output', 'job-failed', 'exit-code', 'unattributed', 'timeout', 'admission-timeout', 'admission-error'].includes(String((item as { reason?: unknown }).reason)))
|
|
332
343
|
return fallback('stalled-shard record is malformed');
|
|
333
344
|
stalledFiles.push(...(item as { files: string[] }).files);
|
|
334
345
|
}
|
|
@@ -387,9 +398,16 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
|
|
|
387
398
|
const jsonClosure = testsReachingChanged(tree, [TRACEABLE_RELEASE_JSON], tests, { cliEntries: CLI_ENTRIES });
|
|
388
399
|
if (!jsonClosure.ok || jsonClosure.reached === 0) return fallback('known-issues JSON reaches no verified test — full gate');
|
|
389
400
|
}
|
|
401
|
+
const priorCutLogs = [...new Set([deps.ledgerRoot ?? releaseLedgerRoot(), root])]
|
|
402
|
+
.map((location) => join(location, 'release', tip.version, 'gate-logs', 'cut'))
|
|
403
|
+
.find((dir) => existsSync(dir));
|
|
404
|
+
const savedInput = saved.input as { gateExecutor?: unknown; gatePodPool?: unknown };
|
|
405
|
+
const podGate = (opts.gateExecutor ?? savedInput.gateExecutor ?? (savedInput.gatePodPool ? 'pod' : undefined)) === 'pod';
|
|
406
|
+
const priorShards = priorCutLogs ? collectExecutedPodShardImages(priorCutLogs, tip.from) : undefined;
|
|
390
407
|
const planned = planPartialRegate({ version: tip.version, priorCommit: tip.from, forCommit: tip.to, changedFiles: changed,
|
|
391
408
|
priorFailures: prior.failures as string[], priorErrors: (prior.errors ?? []) as string[],
|
|
392
409
|
existsAtTip: (file) => tracked.has(file),
|
|
410
|
+
...(podGate ? { priorShards: priorShards ?? [] } : {}),
|
|
393
411
|
closure: (changedCode) => testsReachingChanged(tree, changedCode, tests, { cliEntries: CLI_ENTRIES }) });
|
|
394
412
|
if (!planned.ok) return fallback(planned.reason);
|
|
395
413
|
if (planned.plan.files.length >= tests.length) return fallback(`every test is re-run (${tests.length}) — full gate`);
|
|
@@ -439,12 +457,16 @@ async function planResumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: Resu
|
|
|
439
457
|
const statePath = join(deps.root!, 'graph-runs', 'release-loop', `${safeRunId(opts.runId)}.json`);
|
|
440
458
|
const savedRun = JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState;
|
|
441
459
|
if (savedRun.graphId !== 'release-loop' || savedRun.runId !== opts.runId) throw new Error(`run identity mismatch: ${statePath}`);
|
|
460
|
+
assertReleaseResumeApprovalBoundary({ ...savedRun, statePath }, opts.from);
|
|
442
461
|
if (opts.gateHost !== undefined && opts.gateExecutor === undefined) throw new Error('--gate-host requires --gate-executor host');
|
|
462
|
+
if ((opts.shardHost !== undefined || opts.shardOs !== undefined) && opts.rerouteShard === undefined)
|
|
463
|
+
throw new Error('--shard-host/--shard-os require --reroute-shard');
|
|
443
464
|
const hasOverrides = opts.waive !== undefined || opts.reason !== undefined || opts.acceptedRegressions !== undefined
|
|
444
|
-
|| opts.gateExecutor !== undefined || opts.gatePodPool !== undefined;
|
|
465
|
+
|| opts.gateExecutor !== undefined || opts.gatePodPool !== undefined || opts.rerouteShard !== undefined;
|
|
445
466
|
const original = hasOverrides ? savedRun : undefined;
|
|
446
467
|
if (original && opts.gateExecutor !== undefined) releaseResumeGateExecutor(original, { from: opts.from, executor: opts.gateExecutor, host: opts.gateHost });
|
|
447
468
|
if (original && opts.gatePodPool !== undefined) releaseResumeGatePodPool(original, { from: opts.from, pool: opts.gatePodPool });
|
|
469
|
+
if (original && opts.rerouteShard !== undefined) releaseResumeGateShardReroute(original, { from: opts.from, shard: opts.rerouteShard, host: opts.shardHost, os: opts.shardOs });
|
|
448
470
|
const waiver = original && (opts.waive !== undefined || opts.reason !== undefined) ? releaseResumeWaiver(original, opts) : undefined;
|
|
449
471
|
if (original && opts.acceptedRegressions !== undefined && !waiver)
|
|
450
472
|
releaseResumeAcceptedRegressions(original, opts.acceptedRegressions, opts.from);
|
|
@@ -461,10 +483,11 @@ async function planResumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: Resu
|
|
|
461
483
|
waiverCommit = recorded;
|
|
462
484
|
}
|
|
463
485
|
const tip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, true);
|
|
486
|
+
if (opts.rerouteShard !== undefined && tip.changed) throw new Error('shard reroute requires the original cut head; moved tip needs a full re-gate');
|
|
464
487
|
verifyResumeRecipePin(opts.commandRoot ?? process.cwd(), savedRun.graphSnapshot, tip.version);
|
|
465
488
|
const commandRoot = verifyReleaseCommandRoot(opts.commandRoot ?? process.cwd(), tip.to, deps.git);
|
|
466
489
|
verifyResumePreflight(savedRun, opts, deps, tip.version, tip.from, tip.to, commandRoot);
|
|
467
|
-
const partial = preparePartial(tip, opts, deps, true);
|
|
490
|
+
const partial = preparePartial(tip, opts.rerouteShard !== undefined ? { ...opts, partial: false } : opts, deps, true);
|
|
468
491
|
const fromIndex = savedRun.path.indexOf(opts.from);
|
|
469
492
|
const gateIndex = savedRun.path.indexOf('gate');
|
|
470
493
|
const gateWillRun = fromIndex >= 0 && gateIndex >= fromIndex;
|
|
@@ -481,15 +504,20 @@ async function resumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: ResumeRe
|
|
|
481
504
|
deps = { ...deps, root: releaseRunUniverse({ root: deps.root }) };
|
|
482
505
|
const statePath = join(deps.root!, 'graph-runs', 'release-loop', `${safeRunId(opts.runId)}.json`);
|
|
483
506
|
const savedRun = JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState;
|
|
507
|
+
assertReleaseResumeApprovalBoundary({ ...savedRun, statePath }, opts.from);
|
|
484
508
|
let waiverCommit: string | undefined;
|
|
485
509
|
if (opts.gateHost !== undefined && opts.gateExecutor === undefined) throw new Error('--gate-host requires --gate-executor host');
|
|
486
|
-
|
|
510
|
+
if ((opts.shardHost !== undefined || opts.shardOs !== undefined) && opts.rerouteShard === undefined)
|
|
511
|
+
throw new Error('--shard-host/--shard-os require --reroute-shard');
|
|
512
|
+
const original = opts.waive !== undefined || opts.reason !== undefined || opts.acceptedRegressions !== undefined || opts.gateExecutor !== undefined || opts.gatePodPool !== undefined || opts.rerouteShard !== undefined
|
|
487
513
|
? savedRun : undefined;
|
|
488
514
|
// GATE-HOST-EXECUTOR: checked before the tip refresh writes anything; the runner checks it again under the resume lock.
|
|
489
515
|
const gateExecutor = original && opts.gateExecutor !== undefined
|
|
490
516
|
? releaseResumeGateExecutor(original, { from: opts.from, executor: opts.gateExecutor, host: opts.gateHost }) : undefined;
|
|
491
517
|
const gatePodPool = original && opts.gatePodPool !== undefined
|
|
492
518
|
? releaseResumeGatePodPool(original, { from: opts.from, pool: opts.gatePodPool }) : undefined;
|
|
519
|
+
const shardReroute = original && opts.rerouteShard !== undefined
|
|
520
|
+
? releaseResumeGateShardReroute(original, { from: opts.from, shard: opts.rerouteShard, host: opts.shardHost, os: opts.shardOs }) : undefined;
|
|
493
521
|
if (gateExecutor) debug.log('release-loop.resume', 'gate-executor', { runId: opts.runId, from: opts.from, executor: gateExecutor.set.gateExecutor, host: gateExecutor.set.gateRemote ?? null, previous: gateExecutor.previous });
|
|
494
522
|
if (gatePodPool) debug.log('release-loop.resume', 'gate-pod-pool', {
|
|
495
523
|
runId: opts.runId, from: opts.from, pool: gatePodPool.set.gatePodPool, previous: gatePodPool.previous,
|
|
@@ -517,11 +545,12 @@ async function resumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: ResumeRe
|
|
|
517
545
|
}
|
|
518
546
|
// The read-only tip and recipe pin preflight must pass before fetch or a saved-run rewrite.
|
|
519
547
|
const previewTip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, true);
|
|
548
|
+
if (shardReroute && previewTip.changed) throw new Error('shard reroute requires the original cut head; moved tip needs a full re-gate');
|
|
520
549
|
verifyResumeRecipePin(opts.commandRoot ?? process.cwd(), savedRun.graphSnapshot, previewTip.version);
|
|
521
550
|
const commandRoot = verifyReleaseCommandRoot(opts.commandRoot ?? process.cwd(), previewTip.to, deps.git);
|
|
522
551
|
verifyResumePreflight(savedRun, opts, deps, previewTip.version, previewTip.from, previewTip.to, commandRoot);
|
|
523
552
|
const tip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, false, previewTip.to);
|
|
524
|
-
const partial = preparePartial(tip, opts, deps);
|
|
553
|
+
const partial = preparePartial(tip, shardReroute ? { ...opts, partial: false } : opts, deps);
|
|
525
554
|
// A failed preflight does not consume an observed release resume attempt.
|
|
526
555
|
const attempt = reserveReleaseResumeAttempt(savedRun, deps.root!, { now: deps.now });
|
|
527
556
|
debug.log('release-loop.resume', 'attempt', { runId: opts.runId, attempt: attempt.attempt,
|
|
@@ -536,6 +565,281 @@ async function resumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: ResumeRe
|
|
|
536
565
|
...(acceptedRegressions ? { releaseAcceptedRegressions: { requested: opts.acceptedRegressions!, acceptedRegressions } } : {}),
|
|
537
566
|
...(gateExecutor ? { releaseGateExecutor: { executor: gateExecutor.set.gateExecutor, ...(opts.gateHost !== undefined ? { host: opts.gateHost } : {}) } } : {}),
|
|
538
567
|
...(gatePodPool ? { releaseGatePodPool: gatePodPool.set.gatePodPool } : {}),
|
|
568
|
+
...(shardReroute ? { releaseGateShardReroute: { shard: shardReroute.set.gateRerouteShard,
|
|
569
|
+
...(shardReroute.set.gateShardHost ? { host: shardReroute.set.gateShardHost } : {}),
|
|
570
|
+
...(opts.shardOs ? { os: opts.shardOs } : {}) } } : {}),
|
|
539
571
|
deps: { root: deps.root, ...(deps.runBash ? { runBash: deps.runBash } : {}) } });
|
|
540
572
|
return { tip, partial, state };
|
|
541
573
|
}
|
|
574
|
+
|
|
575
|
+
// RELEASE-RECOVER-ONE-CMD (0.2.36): a failed release run is repaired by three commands that used to be chained by
|
|
576
|
+
// hand (append dry-run → append → resume --from export-check). `release recover` runs them in that order, stops the
|
|
577
|
+
// moment one fails, and leaves every stage's result in the resume-attempts ledger.
|
|
578
|
+
export type RecoverStageName = 'append-dry-run' | 'append' | 'resume';
|
|
579
|
+
const RECOVER_STAGES: readonly RecoverStageName[] = ['append-dry-run', 'append', 'resume'];
|
|
580
|
+
/** The first node that consumes the cut — a moved tip must restart no later than here, so it is the default. */
|
|
581
|
+
const RECOVER_FIRST_NODE = 'export-check';
|
|
582
|
+
|
|
583
|
+
export interface RecoverReleaseOptions {
|
|
584
|
+
runId: string;
|
|
585
|
+
/** main commits that repair the cut — appended to release/<v> as a fast-forward only. */
|
|
586
|
+
pick: string[];
|
|
587
|
+
/** Node the resume restarts at — default `export-check`. */
|
|
588
|
+
from?: string;
|
|
589
|
+
commandRoot?: string;
|
|
590
|
+
partial?: boolean;
|
|
591
|
+
/** The checkout the append runs in (its `origin` remote); default the process cwd. */
|
|
592
|
+
repoRoot?: string;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
export interface RecoverStageRecord {
|
|
596
|
+
stage: RecoverStageName; outcome: 'ok' | 'failed'; at: string; branch?: string; commit?: string | null;
|
|
597
|
+
from?: string; gatePlan?: 'not-run' | 'partial' | 'full'; status?: string; reason?: string;
|
|
598
|
+
/** The `--pick` list this recovery appended — a re-entry skips the append only for the same list. */
|
|
599
|
+
pick?: string[];
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export interface RecoverReleaseResult {
|
|
603
|
+
runId: string; version: string; branch: string; fromNode: string; stages: RecoverStageRecord[];
|
|
604
|
+
resume?: { status: string; tip: TipRefresh; partial: PartialOutcome };
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
export interface RecoverReleaseDeps extends ResumeReleaseDeps {
|
|
608
|
+
/** `release cut-branch --append` — tests record the plan instead of pushing the branch. */
|
|
609
|
+
cutBranch?: typeof cutReleaseBranch;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** A recovery that stopped at a stage: the stages after it never ran, and a human decides the next move. */
|
|
613
|
+
export class ReleaseRecoverStopped extends Error {
|
|
614
|
+
constructor(readonly stage: RecoverStageName, readonly stages: readonly RecoverStageRecord[],
|
|
615
|
+
readonly notRun: readonly RecoverStageName[], reason: string) {
|
|
616
|
+
super(`release recover ${stage} 단계에서 멈췄다: ${reason} — ${notRun.length
|
|
617
|
+
? `${notRun.join(' · ')} 단계는 실행하지 않았다` : '뒤에 실행할 단계가 없다'} · 사람이 판단한다(단계 원장: release/<v>/resume-attempts/<runId>.json)`);
|
|
618
|
+
this.name = 'ReleaseRecoverStopped';
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/** Append one stage result to the resume-attempts ledger. `attempts[]` keeps its shape — the stage results are added. */
|
|
623
|
+
function recordRecoverStage(entry: { root: string; runId: string; version: string; priorCountKnown: boolean; stage: RecoverStageRecord }): void {
|
|
624
|
+
const path = join(entry.root, 'release', entry.version, 'resume-attempts', `${entry.runId}.json`);
|
|
625
|
+
const saved = existsSync(path)
|
|
626
|
+
? JSON.parse(readFileSync(path, 'utf8')) as { attempts?: unknown; recoveries?: unknown; priorCountKnown?: unknown }
|
|
627
|
+
: undefined;
|
|
628
|
+
if (saved !== undefined && (!saved || typeof saved !== 'object' || Array.isArray(saved) || !Array.isArray(saved.attempts)
|
|
629
|
+
|| (saved.recoveries !== undefined && !Array.isArray(saved.recoveries)))) throw new Error('release resume attempts ledger invalid');
|
|
630
|
+
const next = { ...(saved ?? {}), version: entry.version, runId: entry.runId,
|
|
631
|
+
priorCountKnown: saved?.priorCountKnown ?? entry.priorCountKnown,
|
|
632
|
+
attempts: (saved?.attempts ?? []) as string[],
|
|
633
|
+
recoveries: [...((saved?.recoveries ?? []) as RecoverStageRecord[]), entry.stage] };
|
|
634
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
635
|
+
const temporary = `${path}.${process.pid}.recover.tmp`;
|
|
636
|
+
writeFileSync(temporary, `${JSON.stringify(next)}\n`, { mode: 0o600 });
|
|
637
|
+
renameSync(temporary, path);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Repair a failed release run in one command: append dry-run (plan only) → append (fast-forward release/<v> onto the
|
|
642
|
+
* picked repairs) → resume --from export-check (preflight plan, then the graph). A failing stage stops the command:
|
|
643
|
+
* the later stages never run, and the stage results are already in the ledger for the human to read.
|
|
644
|
+
*/
|
|
645
|
+
export async function recoverReleaseRun(opts: RecoverReleaseOptions, deps: RecoverReleaseDeps = {}): Promise<RecoverReleaseResult> {
|
|
646
|
+
if (!Array.isArray(opts.pick) || !opts.pick.length) throw new Error('release recover requires at least one --pick commit');
|
|
647
|
+
const root = releaseRunUniverse({ root: deps.root });
|
|
648
|
+
const statePath = join(root, 'graph-runs', 'release-loop', `${safeRunId(opts.runId)}.json`);
|
|
649
|
+
const savedRun = JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState;
|
|
650
|
+
if (savedRun.graphId !== 'release-loop' || savedRun.runId !== opts.runId) throw new Error(`run identity mismatch: ${statePath}`);
|
|
651
|
+
// The saved version-release record names what to repair: the release branch and the commit the run cut.
|
|
652
|
+
const versionRecord = savedRun.nodes.find((node) => node.nodeId === 'version-release');
|
|
653
|
+
const recorded = lastJsonObject(versionRecord?.output);
|
|
654
|
+
const version = typeof recorded?.version === 'string' ? recorded.version : '';
|
|
655
|
+
// RELEASE-RECOVER-BASE: a first recover that reached the resume left refreshed-tip lines in the
|
|
656
|
+
// version-release output, and `lastJsonObject` names the CURRENT branch tip. The append builds on the
|
|
657
|
+
// commit the run CUT — an ancestor of the picked repairs on origin/main — so walk to the FIRST JSON
|
|
658
|
+
// object of the output for that original cut. Without this, a second recover with a different --pick
|
|
659
|
+
// fails append-dry-run with «base … is not an ancestor of origin/main» and strands the new repair
|
|
660
|
+
// unpushed while the run looks recovered.
|
|
661
|
+
const firstCutObject = (text: unknown): { version?: unknown; commit?: unknown } | undefined => {
|
|
662
|
+
if (typeof text !== 'string') return undefined;
|
|
663
|
+
for (const line of text.split('\n')) {
|
|
664
|
+
const trimmed = line.trim();
|
|
665
|
+
if (!trimmed.startsWith('{')) continue;
|
|
666
|
+
try {
|
|
667
|
+
const parsed: unknown = JSON.parse(trimmed);
|
|
668
|
+
if (parsed && typeof parsed === 'object' && typeof (parsed as { version?: unknown }).version === 'string') {
|
|
669
|
+
return parsed as { version?: unknown; commit?: unknown };
|
|
670
|
+
}
|
|
671
|
+
} catch { /* not a JSON line — keep walking */ }
|
|
672
|
+
}
|
|
673
|
+
return undefined;
|
|
674
|
+
};
|
|
675
|
+
const originalCut = firstCutObject(versionRecord?.output) ?? recorded;
|
|
676
|
+
const base = typeof originalCut?.commit === 'string' ? originalCut.commit : '';
|
|
677
|
+
if (!versionRecord?.ok || !isReleaseVersion(version) || !/^[0-9a-f]{40}$/i.test(base)) {
|
|
678
|
+
throw new Error(`release run ${opts.runId} has no successful version-release record — nothing to repair`);
|
|
679
|
+
}
|
|
680
|
+
const branch = `release/${version}`;
|
|
681
|
+
const fromNode = opts.from ?? RECOVER_FIRST_NODE;
|
|
682
|
+
// RELEASE-RECOVER-PREFLIGHT (MS-02 review): the append pushes release/<v> on origin, and the resume refuses a
|
|
683
|
+
// bad run only after that push. Every read-only resume rejection is checked here FIRST — a run the resume
|
|
684
|
+
// would refuse never moves the branch. command-root mismatch is gone by construction: recover prepares the
|
|
685
|
+
// tip checkout itself below, and a human-provided --command-root is verified by the plan before the graph.
|
|
686
|
+
if (savedRun.status !== 'failed') {
|
|
687
|
+
throw new Error(`release run ${opts.runId} is ${savedRun.status} — only a failed run is recovered; ${branch} was not moved`);
|
|
688
|
+
}
|
|
689
|
+
if (fromNode === 'version-release') {
|
|
690
|
+
throw new Error(`--from version-release would cut again — recover at a later node; ${branch} was not moved`);
|
|
691
|
+
}
|
|
692
|
+
const restartAt = savedRun.path.indexOf(fromNode);
|
|
693
|
+
if (restartAt < 0 || savedRun.path.lastIndexOf(fromNode) !== restartAt) {
|
|
694
|
+
throw new Error(`--from ${fromNode} is not a node on the saved path of ${opts.runId}; ${branch} was not moved`);
|
|
695
|
+
}
|
|
696
|
+
const consumers = ['export-check', 'gate'].map((node) => savedRun.path.indexOf(node)).filter((index) => index >= 0);
|
|
697
|
+
const firstConsumer = consumers.length ? Math.min(...consumers) : -1;
|
|
698
|
+
if (firstConsumer >= 0 && restartAt > firstConsumer) {
|
|
699
|
+
throw new Error(`--from ${fromNode} is later than ${savedRun.path[firstConsumer]!} — later nodes were built from the old tip; ${branch} was not moved`);
|
|
700
|
+
}
|
|
701
|
+
const savedInput = (savedRun.input ?? {}) as { branchCut?: unknown; version?: unknown };
|
|
702
|
+
if (savedInput.branchCut !== true || savedInput.version !== version || recorded?.branch !== branch) {
|
|
703
|
+
throw new Error(`release run ${opts.runId} was not cut as ${branch} (input.branchCut/version or version-release branch differ); ${branch} was not moved`);
|
|
704
|
+
}
|
|
705
|
+
// The attempt ledger is the resume's own read-only gate — a refused recover consumes no attempt.
|
|
706
|
+
reserveReleaseResumeAttempt(savedRun, root, { now: deps.now, checkOnly: true });
|
|
707
|
+
const now = (): string => (deps.now?.() ?? new Date()).toISOString();
|
|
708
|
+
const stages: RecoverStageRecord[] = [];
|
|
709
|
+
const record = (stage: RecoverStageRecord): void => {
|
|
710
|
+
stages.push(stage);
|
|
711
|
+
recordRecoverStage({ root, runId: opts.runId, version, priorCountKnown: !savedRun.resume, stage });
|
|
712
|
+
};
|
|
713
|
+
const stop = (stage: RecoverStageName, error: unknown): never => {
|
|
714
|
+
throw new ReleaseRecoverStopped(stage, stages, RECOVER_STAGES.slice(RECOVER_STAGES.indexOf(stage) + 1),
|
|
715
|
+
error instanceof Error ? error.message : String(error));
|
|
716
|
+
};
|
|
717
|
+
const reason = (error: unknown): string => error instanceof Error ? error.message : String(error);
|
|
718
|
+
const cutBranch = deps.cutBranch ?? cutReleaseBranch;
|
|
719
|
+
const cut = { version, base, pick: opts.pick, append: true, repoRoot: opts.repoRoot, log: deps.onSource };
|
|
720
|
+
const repoRoot = resolve(opts.repoRoot ?? deps.repo ?? process.cwd());
|
|
721
|
+
// RELEASE-RECOVER-REENTRY (MS-02 review): once the append pushed and the resume did not finish, re-running
|
|
722
|
+
// recover with the same --pick is refused by cut-branch with «pick … is already in release/<v>» and dies at
|
|
723
|
+
// stage 1 with no guidance. The ledger recoveries decide: when their append-ok commit is still inside the
|
|
724
|
+
// advertised branch tip AND its recorded pick list is this --pick (an entry with no pick record is «기록 없음»,
|
|
725
|
+
// not an empty list — it falls back to the safe side and appends again), the repair already landed and this
|
|
726
|
+
// recover continues from the resume — the append stages never re-run.
|
|
727
|
+
/** Same pick list, order-insensitive, full 40-hex object ids only — anything else is «no record». */
|
|
728
|
+
const samePickList = (recorded: unknown): boolean => {
|
|
729
|
+
if (!Array.isArray(recorded) || recorded.length !== opts.pick.length) return false;
|
|
730
|
+
const left = recorded.map((sha) => (typeof sha === 'string' ? sha.toLowerCase() : '')).sort();
|
|
731
|
+
const right = [...opts.pick].map((sha) => sha.toLowerCase()).sort();
|
|
732
|
+
return left.every((sha, index) => /^[0-9a-f]{40}$/.test(sha) && sha === right[index]);
|
|
733
|
+
};
|
|
734
|
+
const ledgerPath = join(root, 'release', version, 'resume-attempts', `${opts.runId}.json`);
|
|
735
|
+
const recoveries: RecoverStageRecord[] = existsSync(ledgerPath)
|
|
736
|
+
? ((JSON.parse(readFileSync(ledgerPath, 'utf8')) as { recoveries?: unknown[] }).recoveries ?? []) as RecoverStageRecord[]
|
|
737
|
+
: [];
|
|
738
|
+
let appendedCommit: string | undefined;
|
|
739
|
+
for (let index = recoveries.length - 1; index >= 0; index -= 1) {
|
|
740
|
+
const entry = recoveries[index]!;
|
|
741
|
+
if (entry.stage === 'append' && entry.outcome === 'ok' && typeof entry.commit === 'string' && samePickList(entry.pick)) {
|
|
742
|
+
appendedCommit = entry.commit;
|
|
743
|
+
break;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
let advertised = '';
|
|
747
|
+
try {
|
|
748
|
+
advertised = (deps.git ?? gitRunner(repoRoot))(['ls-remote', '--heads', 'origin', `refs/heads/${branch}`]).split(/\s+/)[0] ?? '';
|
|
749
|
+
} catch {
|
|
750
|
+
advertised = '';
|
|
751
|
+
}
|
|
752
|
+
const isAncestor = deps.isAncestor ?? ancestorRunner(repoRoot);
|
|
753
|
+
const humanResume = `release resume --run ${opts.runId} --from ${fromNode}`;
|
|
754
|
+
const alreadyInGuidance = (cause: string): string =>
|
|
755
|
+
`${cause} — ${branch}가 이미 고른 수선을 담고 있다: 이 recover는 append하지 않았다. 사람이 직접 이어 간다: ${humanResume}`;
|
|
756
|
+
let tip = '';
|
|
757
|
+
if (appendedCommit !== undefined && /^[0-9a-f]{40}$/i.test(advertised) && isAncestor(appendedCommit, advertised)) {
|
|
758
|
+
tip = advertised;
|
|
759
|
+
deps.onSource?.(`· recover 재진입 · 원장의 append-ok(${appendedCommit.slice(0, 12)})이 가지 끝에 그대로 있다 — append를 다시 하지 않고 ${fromNode} resume부터 이어 간다`);
|
|
760
|
+
} else {
|
|
761
|
+
if (/^[0-9a-f]{40}$/i.test(advertised) && opts.pick.every((sha) => isAncestor(sha, advertised))) {
|
|
762
|
+
// The repair is on the branch already (a hand-run append) and the ledger has no append-ok for it: there is
|
|
763
|
+
// nothing to append — the stop error and the ledger record both name the human's next step.
|
|
764
|
+
const guidance = alreadyInGuidance(`pick ${opts.pick.join(' + ')} is already in ${branch}`);
|
|
765
|
+
record({ stage: 'append-dry-run', outcome: 'failed', at: now(), branch, reason: guidance });
|
|
766
|
+
return stop('append-dry-run', new Error(guidance));
|
|
767
|
+
}
|
|
768
|
+
// 1/3 append dry-run — the fast-forward plan only: no worktree, no push, no run-state write.
|
|
769
|
+
try {
|
|
770
|
+
const planned = cutBranch({ ...cut, dryRun: true });
|
|
771
|
+
record({ stage: 'append-dry-run', outcome: 'ok', at: now(), branch: planned.branch, commit: planned.commit });
|
|
772
|
+
deps.onSource?.(`· recover 1/3 append dry-run · ${planned.branch} ← ${opts.pick.join(' + ')} · 가지·push·런 상태 변경 없음`);
|
|
773
|
+
} catch (error) {
|
|
774
|
+
const raw = reason(error);
|
|
775
|
+
if (!/is already in /.test(raw)) {
|
|
776
|
+
record({ stage: 'append-dry-run', outcome: 'failed', at: now(), branch, reason: raw });
|
|
777
|
+
return stop('append-dry-run', error);
|
|
778
|
+
}
|
|
779
|
+
const guided = alreadyInGuidance(raw);
|
|
780
|
+
record({ stage: 'append-dry-run', outcome: 'failed', at: now(), branch, reason: guided });
|
|
781
|
+
return stop('append-dry-run', new Error(guided));
|
|
782
|
+
}
|
|
783
|
+
// 2/3 append — cherry-pick the repairs onto release/<v> and push the fast-forward (never a force push).
|
|
784
|
+
try {
|
|
785
|
+
const appended = cutBranch(cut);
|
|
786
|
+
if (!appended.commit) throw new Error(`${appended.branch} append produced no commit`);
|
|
787
|
+
tip = appended.commit;
|
|
788
|
+
record({ stage: 'append', outcome: 'ok', at: now(), branch: appended.branch, commit: tip, pick: opts.pick });
|
|
789
|
+
deps.onSource?.(`↻ recover 2/3 append · ${appended.branch} ${base.slice(0, 12)} → ${tip.slice(0, 12)} (fast-forward)`);
|
|
790
|
+
} catch (error) {
|
|
791
|
+
const raw = reason(error);
|
|
792
|
+
if (!/is already in /.test(raw)) {
|
|
793
|
+
record({ stage: 'append', outcome: 'failed', at: now(), branch, reason: raw });
|
|
794
|
+
return stop('append', error);
|
|
795
|
+
}
|
|
796
|
+
const guided = alreadyInGuidance(raw);
|
|
797
|
+
record({ stage: 'append', outcome: 'failed', at: now(), branch, reason: guided });
|
|
798
|
+
return stop('append', new Error(guided));
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// 3/3 resume --from export-check — the read-only preflight first (its plan is the record), then the graph run.
|
|
803
|
+
// The append moved only the origin branch tip: the operator checkout is still wherever it was, and the resume
|
|
804
|
+
// preflight (verifyReleaseCommandRoot) demands a checkout whose HEAD is the new tip. So recover prepares that
|
|
805
|
+
// checkout itself — a temporary worktree at the tip. A human-provided --command-root stays a judgment
|
|
806
|
+
// boundary: the plan verifies it against the tip and stops there on a mismatch.
|
|
807
|
+
const resumeOptions: ResumeReleaseOptions = { runId: opts.runId, from: fromNode,
|
|
808
|
+
...(opts.partial === undefined ? {} : { partial: opts.partial }) };
|
|
809
|
+
let preparedRoot: { dir: string; git: (args: string[]) => string } | undefined;
|
|
810
|
+
if (opts.commandRoot !== undefined) resumeOptions.commandRoot = opts.commandRoot;
|
|
811
|
+
else {
|
|
812
|
+
const temp = mkdtempSync(join(tmpdir(), 'release-recover-'));
|
|
813
|
+
const dir = join(temp, 'command-root');
|
|
814
|
+
const worktreeGit = gitRunner(repoRoot);
|
|
815
|
+
try {
|
|
816
|
+
worktreeGit(['worktree', 'add', '--detach', dir, tip]);
|
|
817
|
+
} catch (error) {
|
|
818
|
+
rmSync(temp, { recursive: true, force: true });
|
|
819
|
+
throw error;
|
|
820
|
+
}
|
|
821
|
+
preparedRoot = { dir, git: worktreeGit };
|
|
822
|
+
resumeOptions.commandRoot = dir;
|
|
823
|
+
}
|
|
824
|
+
try {
|
|
825
|
+
const plan = await planResumeReleaseRun(resumeOptions, deps);
|
|
826
|
+
const resumed = await resumeReleaseRun(resumeOptions, deps);
|
|
827
|
+
record({ stage: 'resume', outcome: 'ok', at: now(), from: fromNode, branch: resumed.tip.branch,
|
|
828
|
+
commit: resumed.tip.to, gatePlan: plan.gatePlan.mode, status: resumed.state.status });
|
|
829
|
+
deps.onSource?.(`▶ recover 3/3 resume ${fromNode}부터 · tip ${resumed.tip.to.slice(0, 12)} · gate ${plan.gatePlan.mode} → ${resumed.state.status}`);
|
|
830
|
+
return { runId: opts.runId, version, branch: resumed.tip.branch, fromNode, stages,
|
|
831
|
+
resume: { status: resumed.state.status, tip: resumed.tip, partial: resumed.partial } };
|
|
832
|
+
} catch (error) {
|
|
833
|
+
record({ stage: 'resume', outcome: 'failed', at: now(), from: fromNode, branch, reason: reason(error) });
|
|
834
|
+
return stop('resume', error);
|
|
835
|
+
} finally {
|
|
836
|
+
if (preparedRoot) {
|
|
837
|
+
try {
|
|
838
|
+
preparedRoot.git(['worktree', 'remove', '--force', preparedRoot.dir]);
|
|
839
|
+
} catch {
|
|
840
|
+
try { preparedRoot.git(['worktree', 'prune']); } catch { /* the temp dir below is still removed */ }
|
|
841
|
+
}
|
|
842
|
+
rmSync(dirname(preparedRoot.dir), { recursive: true, force: true });
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
@@ -1,9 +1,31 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
1
2
|
import { lastJsonObject, STOPPED_NODE_ERROR, type GraphRunState } from '../../src/graph-runner/runner.js';
|
|
2
3
|
import { publicWaiverReason } from './known-issues-node.js';
|
|
3
4
|
import { checkGateExecutorChoice, type GateExecutor } from './gate-executor.js';
|
|
4
5
|
|
|
5
6
|
export interface AcceptedRegression { id: string; note: string }
|
|
6
7
|
|
|
8
|
+
/** Match the graph runner's approval boundary before release resume performs tip refresh or writes an attempt. */
|
|
9
|
+
export function assertReleaseResumeApprovalBoundary(state: GraphRunState, from: string): void {
|
|
10
|
+
if (!Array.isArray(state.path)) return;
|
|
11
|
+
const start = state.path.indexOf(from);
|
|
12
|
+
if (start < 0 || state.path.lastIndexOf(from) !== start) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (let index = 0; index < state.nodes.length; index++) {
|
|
16
|
+
const record = state.nodes[index]!;
|
|
17
|
+
if (typeof record.decidedAt !== 'string') continue;
|
|
18
|
+
if (index >= start) throw new Error('cannot restart across an approval decision — start a new release run with the full gate');
|
|
19
|
+
if (!record.ok) throw new Error('cannot preserve a failed predecessor when resuming');
|
|
20
|
+
let decision: { nodeId?: unknown; decision?: unknown; decidedAt?: unknown };
|
|
21
|
+
try { decision = JSON.parse(readFileSync(`${state.statePath}.${index + 1}.decision.json`, 'utf8')); }
|
|
22
|
+
catch { throw new Error(`missing approval decision for ${record.nodeId}`); }
|
|
23
|
+
if (decision.nodeId !== record.nodeId || decision.decision !== 'approved' || decision.decidedAt !== record.decidedAt) {
|
|
24
|
+
throw new Error(`invalid approval decision for ${record.nodeId}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
7
29
|
/** Merge explicit public issues with the saved release input without changing the ledger shape. */
|
|
8
30
|
export function releaseResumeAcceptedRegressions(state: GraphRunState, additions: AcceptedRegression[], from?: string): AcceptedRegression[] {
|
|
9
31
|
if (!Array.isArray(additions) || additions.some((issue) => !issue || typeof issue.id !== 'string' || !issue.id.trim() || typeof issue.note !== 'string' || !issue.note.trim())) {
|
|
@@ -53,12 +75,20 @@ function printedVerdict(output: unknown): boolean {
|
|
|
53
75
|
});
|
|
54
76
|
}
|
|
55
77
|
|
|
56
|
-
/**
|
|
57
|
-
function
|
|
78
|
+
/** A failed release may execute its warning-only traffic restore before the terminal failure. */
|
|
79
|
+
function failedAfterTrafficRestore(state: GraphRunState, index: number): boolean {
|
|
58
80
|
if (state.nodes.length !== state.path.length || state.path.at(-1) !== 'failed' || state.nodes.at(-1)?.nodeId !== 'failed') return false;
|
|
59
81
|
if (index === state.path.length - 2) return true;
|
|
60
|
-
return index === state.path.length - 3 && state.path[index + 1] === '
|
|
61
|
-
&& state.nodes[index + 1]?.nodeId === '
|
|
82
|
+
return index === state.path.length - 3 && state.path[index + 1] === 'traffic-failed-restore'
|
|
83
|
+
&& state.nodes[index + 1]?.nodeId === 'traffic-failed-restore' && state.nodes[index + 1]?.executed === true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Gate may also pass through its executed triage shadow before the traffic restore. */
|
|
87
|
+
function failedAfterGate(state: GraphRunState, index: number): boolean {
|
|
88
|
+
if (failedAfterTrafficRestore(state, index)) return true;
|
|
89
|
+
return state.path[index + 1] === 'gate-triage'
|
|
90
|
+
&& state.nodes[index + 1]?.nodeId === 'gate-triage' && state.nodes[index + 1]?.executed === true
|
|
91
|
+
&& failedAfterTrafficRestore(state, index + 1);
|
|
62
92
|
}
|
|
63
93
|
|
|
64
94
|
export function gateUnmeasuredDetail(state: GraphRunState, index: number): string | undefined {
|
|
@@ -113,7 +143,7 @@ export function releaseResumeWaiver(
|
|
|
113
143
|
}
|
|
114
144
|
if (!unique || state.path.lastIndexOf(opts.waive) !== index || state.nodes[index]?.nodeId !== opts.waive || state.nodes[index]?.ok !== false ||
|
|
115
145
|
state.nodes[index]?.executed !== true || (opts.waive === 'gate' ? !failedAfterGate(state, index)
|
|
116
|
-
:
|
|
146
|
+
: !failedAfterTrafficRestore(state, index))) {
|
|
117
147
|
throw new Error(`--waive ${opts.waive} requires the failed executable node on the saved path`);
|
|
118
148
|
}
|
|
119
149
|
// Only user-visible, non-publication checks can become accepted regressions; build, safety and approval gates stay blocking.
|
|
@@ -146,6 +176,32 @@ export interface GatePodPoolOverride {
|
|
|
146
176
|
previous: { gatePodPool: unknown };
|
|
147
177
|
}
|
|
148
178
|
|
|
179
|
+
/** One shard keeps its component identity while the run-time scheduler chooses a compatible member. */
|
|
180
|
+
export interface GateShardRerouteOverride {
|
|
181
|
+
kind: 'gate-shard-reroute'; at: string; from: string;
|
|
182
|
+
set: { gateRerouteShard: string; gateShardHost?: string; gateShardCapabilities?: Record<string, { os: 'darwin' | 'linux' }> };
|
|
183
|
+
previous: { gateRerouteShard: unknown; gateShardHost: unknown; gateShardCapabilities: unknown };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function releaseResumeGateShardReroute(state: GraphRunState, opts: {
|
|
187
|
+
from: string; shard: unknown; host?: unknown; os?: unknown; at?: string;
|
|
188
|
+
}): GateShardRerouteOverride {
|
|
189
|
+
const input = state.input as Record<string, unknown> | undefined;
|
|
190
|
+
if (!input || typeof input.gatePodPool !== 'string' || !input.gatePodPool.trim())
|
|
191
|
+
throw new Error('shard reroute requires the saved Pod gate pool');
|
|
192
|
+
if (opts.from !== 'gate' || !state.path.includes('gate')) throw new Error('shard reroute requires --from gate');
|
|
193
|
+
if (typeof opts.shard !== 'string' || !/^(?:auto|pod-\d+)$/.test(opts.shard))
|
|
194
|
+
throw new Error('--reroute-shard requires auto or pod-N');
|
|
195
|
+
if (opts.host !== undefined && (typeof opts.host !== 'string' || !opts.host.trim())) throw new Error('--shard-host requires a pool context');
|
|
196
|
+
if (opts.os !== undefined && (opts.shard === 'auto' || opts.os !== 'darwin' && opts.os !== 'linux'))
|
|
197
|
+
throw new Error('--shard-os requires pod-N and darwin or linux');
|
|
198
|
+
return { kind: 'gate-shard-reroute', at: opts.at ?? new Date().toISOString(), from: opts.from,
|
|
199
|
+
set: { gateRerouteShard: opts.shard, ...(opts.host ? { gateShardHost: opts.host.trim() } : {}),
|
|
200
|
+
...(opts.os ? { gateShardCapabilities: { [opts.shard]: { os: opts.os } } } : {}) },
|
|
201
|
+
previous: { gateRerouteShard: input.gateRerouteShard ?? null, gateShardHost: input.gateShardHost ?? null,
|
|
202
|
+
gateShardCapabilities: input.gateShardCapabilities ?? null } };
|
|
203
|
+
}
|
|
204
|
+
|
|
149
205
|
export function releaseResumeGatePodPool(state: GraphRunState, opts: { from: string; pool: unknown; at?: string }): GatePodPoolOverride {
|
|
150
206
|
const input = state.input;
|
|
151
207
|
if (!input || typeof input !== 'object' || Array.isArray(input) || typeof (input as { version?: unknown }).version !== 'string') throw new Error('release run has no input');
|
|
@@ -7,8 +7,11 @@ import { errorResult, finishNode, readGraphContext } from './node-verdict.js';
|
|
|
7
7
|
import { applyReleaseTrafficEvent, trafficOptionsFromConfig, type ReleaseTrafficEvent, type TrafficTransitionOptions } from './traffic-transition.js';
|
|
8
8
|
|
|
9
9
|
const EVENTS: Record<string, ReleaseTrafficEvent> = {
|
|
10
|
+
'traffic-cut-start': 'cut-start',
|
|
10
11
|
'traffic-gate-passed': 'gate-passed',
|
|
12
|
+
'traffic-npm-published': 'npm-published',
|
|
11
13
|
'traffic-verify-complete': 'verify-complete',
|
|
14
|
+
'traffic-failed-restore': 'failed',
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
export interface TrafficNodeDeps {
|
|
@@ -40,12 +43,17 @@ export async function runTrafficNode(node = process.argv[2], env: NodeJS.Process
|
|
|
40
43
|
}
|
|
41
44
|
const result = await applyReleaseTrafficEvent(context, event, options);
|
|
42
45
|
if (!result.applied) {
|
|
43
|
-
const consequence = event === '
|
|
44
|
-
? '
|
|
45
|
-
: '
|
|
46
|
+
const consequence = event === 'failed' && result.reason === 'published-keeps-full'
|
|
47
|
+
? 'npm 발행은 완료됐으므로 전체 트래픽을 유지합니다. 후속 발행 단계 실패를 확인하세요.'
|
|
48
|
+
: event === 'verify-complete' || event === 'npm-published'
|
|
49
|
+
? '발행은 성공했으나 전체 트래픽 전환이 적용되지 않았습니다.'
|
|
50
|
+
: event === 'failed' ? '컷 전 트래픽 복귀가 적용되지 않았습니다.'
|
|
51
|
+
: event === 'cut-start' ? '컷은 시작했으나 gate 모드 전환이 적용되지 않았습니다.'
|
|
52
|
+
: 'gate는 성공했으나 트래픽 감속이 적용되지 않았습니다.';
|
|
46
53
|
(deps.report ?? reportFailure)(`RELEASE-POSTPUB-TRAFFIC ${version} ${runId || 'unknown'} ${node} 무시 — ${result.reason ?? 'traffic state unchanged'}. ${consequence}`);
|
|
47
54
|
}
|
|
48
|
-
return finishNode(node!, version, { outcome: 'ok'
|
|
55
|
+
return finishNode(node!, version, { outcome: result.applied ? 'ok' : 'fail', verdict: result.applied ? 'pass' : 'fail',
|
|
56
|
+
summary: `${event} ${result.applied ? 'applied' : result.reason ?? 'ignored'}` });
|
|
49
57
|
} catch (error) {
|
|
50
58
|
const detail = errorResult(error).summary;
|
|
51
59
|
const isLockTimeout = detail.startsWith('traffic lock timeout:');
|