elanous 0.2.38 → 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/{RrjXTwz-urRAbChP1bX02 → HjeK7zONHfR7op1hKXp4k}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{7954.4f7a8832663ee979.js → 1060.014f1f01a17aec26.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8911.bf5e712acb25fb6c.js → 1281.d81877e35b9068f4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2104.70e086d5174a4736.js → 1350.59f40e39e02d91b1.js} +1 -1
- 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/2047.8f23e210995d4548.js +2 -0
- package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1632.7d87f998e714bede.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/{8019.21ca554a821dad01.js → 2177.df8547f9d7215c4e.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3528.e4b8ab70d339f965.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/{6493.27ad77de7aac7966.js → 2499.02fbfd18126c10c0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7628.6b16863ac3972333.js → 2522.f2766b76d22c8bdf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3086.fb14b60ce98b53d3.js → 2566.beaffc3a5e1fcd2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9299.24e2a7d9b6d1f91b.js → 261.0d471e8aded799f3.js} +3 -3
- 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/2774-719820e3f5b2a3eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2829-734fe8bf2eee7347.js +1 -0
- 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/{7524.ce973525d30b3d52.js → 3330.7443183b7e6fdbdf.js} +1 -1
- 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/{3124-561f7f037943cde2.js → 3746-f80a78f220bf37b5.js} +1 -1
- 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/{bb6987f9.3647e1a23b0e3217.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/{8994d93e.33ba491f95345fc2.js → 409c787b.e48c5bec8ec10456.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5041-5aada92ca215ffdd.js → 413-24c8284bda08241d.js} +1 -1
- 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/{5638.107314dc479e2f37.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/{8487.291666583bebe640.js → 4769.9fd582071301f382.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8509.3a54d4e61893d7cb.js → 483.725e4a61be922788.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9fe1b809.738da85c8b17e3fb.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/{8879.ac06755bcf3e44a1.js → 5383.bdfa5d886e39a826.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6142.913b44e260a3f925.js → 5436.fdf6fa8ae3e9588d.js} +1 -1
- 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/{7161-8f22db3ec5ed005e.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/{3291.f6c1005387d514bd.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/{5203.51e5d8b5f1dcfe53.js → 6749.0744ce6eb08d40e9.js} +3 -3
- 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/{1938.0e6c60ee91c4d7f5.js → 6908.06008c67f6380ea9.js} +2 -2
- 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/{de8b930d.d94c0f42acf807fc.js → 6cc1d1d6.9a98dd4622f1afc6.js} +1 -1
- 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/{1026-44010f405704050c.js → 8272-025653884f9645d2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5307.d7328020227880c2.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/{4199-f7c6eb40cd0322f8.js → 8639-92c11d069792429e.js} +1 -1
- 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/9175.2de5209a5ce6f68a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9184.45afbf44fec87574.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{eaad0cba.771200940c529df7.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-866aac5ff226a7f3.js → page-ba957ff875a026a0.js} +1 -1
- 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-4edb8df90f4537ce.js +1 -0
- 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-fca2e59a81744d9e.js +1 -0
- 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-139d722de1dcd6c1.js +1 -0
- 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-ccde99f07aaf71f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b7478fef.5917716286213fcc.js → b84cad00.594027ebe0531fe2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/c696986b.5dc8bb1143af16d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b7459770.6539b11860eb8a9c.js → ca3702f8.2913182e73889fa2.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/{3f0de3de-2340c532c00395db.js → d5d3cefc-373c4eb722ed848b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{89d6c04f-6b8ab341748e468a.js → d8de0de2-dd0f4ac8e5ab1832.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-4b12a946f352cee2.js → framework-002b472a66935d31.js} +1 -1
- 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/video/explainer-line.yaml +4 -1
- package/package.json +1 -1
- package/scripts/dead-code/report.ts +169 -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/public-export.ts +15 -7
- package/scripts/release-loop/export-check-node.ts +21 -3
- package/scripts/release-loop/gate-node.ts +379 -48
- 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-release.ts +20 -5
- package/scripts/release-loop/resume.ts +48 -0
- package/scripts/release-loop/version-node.ts +7 -2
- 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/src/acp/core-turn-bridge.ts +8 -0
- 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/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 +75 -6
- 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/self-review-cli.ts +226 -17
- 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 +22 -3
- package/src/auto-research/research-turn.ts +350 -17
- package/src/autopilot/agent-loop.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/budget/llm-cost.ts +44 -5
- package/src/budget/unified-usage.ts +17 -1
- package/src/capture/tui-self-report.ts +14 -0
- package/src/chat/index.ts +33 -7
- package/src/cli/agent-cli.ts +43 -8
- package/src/cli/intake-cli.ts +22 -1
- package/src/cli/lesson-cli.ts +19 -3
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/pod-cli.ts +17 -2
- package/src/cli/pty-takeover-cli.ts +67 -7
- package/src/cli/release-cli.ts +52 -6
- package/src/cli/repo-cli.ts +2 -1
- package/src/cli/tasks-cli.ts +36 -9
- package/src/control-plane/ledger.ts +21 -4
- package/src/core-turn/run-core-turn.ts +44 -3
- package/src/core-turn/run-goal-loop.ts +152 -8
- package/src/core-turn/types.ts +9 -0
- package/src/dashboard/chat/acp-chat.ts +2 -2
- package/src/dashboard/classic-sigquit.ts +16 -0
- package/src/dashboard/index.ts +321 -27
- 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/sidetab-runtime.ts +228 -0
- package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -8
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
- package/src/dashboard/term-slash-runtime.ts +16 -18
- package/src/dashboard/turn-preamble.ts +2 -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/graph-runner/graph-cli.ts +6 -4
- package/src/graph-runner/runner.ts +31 -9
- 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 +5 -0
- 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/index.ts +18 -4
- package/src/input/external-input-queue.ts +10 -0
- package/src/intake-plane/collect-telegram-saved.ts +36 -1
- package/src/intake-plane/intake-to-tasks.ts +246 -3
- 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.ts +431 -76
- package/src/loops/orchestrator/tick.ts +8 -0
- package/src/nexus/api/harness-api.ts +2 -1
- package/src/pty/snapshot.py +132 -0
- package/src/pty-shell/pty-control-ipc.ts +29 -2
- package/src/pty-shell/pty-manifest.ts +59 -3
- 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/merged-pr-checklist.ts +25 -2
- package/src/release-loop/rehearsal-shard-plan.ts +6 -1
- package/src/release-loop/rehearsal.ts +27 -0
- package/src/research/edge-decision.ts +124 -15
- 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/plugin-discovery.ts +242 -0
- package/src/research-bridge/invoke.ts +4 -2
- package/src/research-bridge/types.ts +2 -0
- package/src/self-dev/ask-launch-flow.ts +34 -106
- package/src/self-dev/dev-cli.ts +2 -0
- package/src/self-dev/dev-pipeline.ts +8 -4
- 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/run-supervisor.ts +19 -0
- package/src/self-implement/device-first.ts +8 -2
- package/src/self-implement/doctor-visit.ts +76 -58
- package/src/self-implement/gate-artifacts.ts +3 -0
- package/src/self-implement/gate-baseline.ts +75 -4
- package/src/self-implement/gate-cli.ts +317 -9
- package/src/self-implement/gate-receipt-registry.ts +180 -0
- package/src/self-implement/gate-remote.ts +145 -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 +9 -5
- 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 +189 -10
- package/src/self-implement/off-diff-evidence.ts +124 -0
- package/src/self-implement/orchestrator.ts +85 -7
- package/src/self-implement/run-ledger.ts +46 -8
- package/src/self-implement/run-stop.ts +12 -0
- package/src/self-implement/seams.ts +6 -3
- package/src/self-implement/self-implement-cli.ts +4 -2
- package/src/session/chat.ts +89 -15
- 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/tools/schedule-wakeup.ts +23 -1
- package/src/skills/tools/shell.ts +51 -5
- package/src/steward/directive-audit.ts +354 -0
- package/src/surface/child-process.ts +31 -0
- package/src/surface/tui-stderr-owner.ts +48 -0
- package/src/task-agent/cover.ts +30 -12
- package/src/task-agent/judge.ts +56 -0
- 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 +1 -1
- package/src/task-agent/task-hand.ts +129 -24
- package/src/task-agent/tier-split.ts +105 -21
- 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 +27 -2
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
- 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 +186 -33
- package/src/tool-runtime/skill-exec-runtime.ts +95 -5
- package/src/tui/entry.ts +15 -2
- package/src/tui/inline-choice.ts +188 -0
- package/src/tui/sidetab/list.ts +2 -176
- package/src/tui/slash/term.ts +12 -1
- package/src/tui-client/dashboard-session.ts +7 -1
- package/src/user-config.ts +34 -4
- 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/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 +8 -13
- 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/1118.a8a74ea29aac3e46.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +0 -93
- package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/2415.738b777642a02233.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +0 -24
- package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +0 -287
- package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +0 -32
- package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +0 -90
- package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +0 -79
- package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +0 -286
- package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +0 -1
- package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +0 -8
- package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +0 -62
- package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7488.966b116789f3d41a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +0 -77
- package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +0 -1
- package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +0 -149
- package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +0 -41
- package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +0 -24
- package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +0 -2
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +0 -1
- /package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → HjeK7zONHfR7op1hKXp4k}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import type { UserConfig } from '../../user-config.js';
|
|
3
|
+
|
|
4
|
+
type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };
|
|
5
|
+
type JsonObject = { [key: string]: JsonValue };
|
|
6
|
+
type SnapshotSource = 'host-effective' | 'runtime';
|
|
7
|
+
type Allowlist = { readonly [key: string]: true | Allowlist };
|
|
8
|
+
|
|
9
|
+
const ROLE = { provider: true, tier: true, model: true, effort: true } as const;
|
|
10
|
+
/** Adding a setting requires naming its path here. Arbitrary host config never reaches a Pod. */
|
|
11
|
+
const POD_CONFIG_ALLOWLIST = {
|
|
12
|
+
llm: {
|
|
13
|
+
provider: true, model: true, streamIdleTimeoutMs: true,
|
|
14
|
+
codexAccountRotation: true, codexQuotaPolicy: true, codexCreditReserve: true,
|
|
15
|
+
grokWeeklyCapPct: true, fallbackChain: true,
|
|
16
|
+
zaiCodingPlan: { overage: true, maxConcurrent: true },
|
|
17
|
+
openrouter: { fallbackModel: true },
|
|
18
|
+
},
|
|
19
|
+
roleLlm: { implement: ROLE, review: ROLE, research: ROLE, planning: ROLE, audit: ROLE, classify: ROLE },
|
|
20
|
+
harness: { worktreeAddTimeoutSec: true, knowhowChildInjection: true, authorGrade: true,
|
|
21
|
+
exposeGate: true, difficultyPlacement: true, substrate: true, authorOnPod: true },
|
|
22
|
+
tools: { selfImplement: { childInstanceMode: true, observeOnly: true, fabricDecompose: true,
|
|
23
|
+
autoOpenPr: true } },
|
|
24
|
+
loops: { orchestrator: { enabled: true, mode: true, trafficMode: true, idleRequest: true,
|
|
25
|
+
finishGate: true, handToTaskAgent: true, degradationSignal: true, maxDelegatePerTick: true,
|
|
26
|
+
dispatch: { podTarget: true, localLane: true } } },
|
|
27
|
+
} as const satisfies Allowlist;
|
|
28
|
+
|
|
29
|
+
function scalar(value: unknown): JsonValue | undefined {
|
|
30
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean') return value;
|
|
31
|
+
if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
const items = value.map(scalar);
|
|
34
|
+
return items.every((item) => item !== undefined) ? items as JsonValue[] : undefined;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function allowed(value: unknown, schema: true | Allowlist): JsonValue | undefined {
|
|
40
|
+
if (schema === true) return scalar(value);
|
|
41
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
|
|
42
|
+
const out: JsonObject = {};
|
|
43
|
+
for (const key of Object.keys(schema).sort()) {
|
|
44
|
+
const item = allowed((value as Record<string, unknown>)[key], schema[key]!);
|
|
45
|
+
if (item !== undefined) out[key] = item;
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function objectAt(value: unknown): JsonObject {
|
|
51
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value as JsonObject : {};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function canonical(value: JsonValue): JsonValue {
|
|
55
|
+
if (Array.isArray(value)) return value.map(canonical);
|
|
56
|
+
if (value && typeof value === 'object') {
|
|
57
|
+
const out: JsonObject = {};
|
|
58
|
+
for (const key of Object.keys(value).sort()) {
|
|
59
|
+
const item = canonical(value[key]!);
|
|
60
|
+
if (typeof item !== 'object' || item === null || Array.isArray(item) || Object.keys(item).length > 0) out[key] = item;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function sourcesOf(value: JsonValue, path: string, sources: Record<string, SnapshotSource>): void {
|
|
68
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
69
|
+
for (const key of Object.keys(value).sort()) sourcesOf(value[key]!, path ? `${path}.${key}` : key, sources);
|
|
70
|
+
} else sources[path] = 'host-effective';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** A Pod receives only these effective, non-credential settings. The envelope is evidence;
|
|
74
|
+
* configJson is the plain config consumed by the child. Neither contains host credentials. */
|
|
75
|
+
export function buildPodConfigSnapshot(config: UserConfig, runtime: {
|
|
76
|
+
steps: readonly string[];
|
|
77
|
+
overage: 'stop' | 'balance' | 'openrouter';
|
|
78
|
+
worktreeAddTimeoutSec: number;
|
|
79
|
+
}): {
|
|
80
|
+
version: 1;
|
|
81
|
+
keys: JsonObject & { llm: JsonObject; harness: JsonObject };
|
|
82
|
+
sources: Record<string, SnapshotSource>;
|
|
83
|
+
hash: string;
|
|
84
|
+
envelopeJson: string;
|
|
85
|
+
configJson: string;
|
|
86
|
+
keyCount: number;
|
|
87
|
+
} {
|
|
88
|
+
const host = config as unknown as Record<string, unknown>;
|
|
89
|
+
const selected = objectAt(allowed(host, POD_CONFIG_ALLOWLIST));
|
|
90
|
+
const tools = objectAt(selected.tools);
|
|
91
|
+
const loops = objectAt(selected.loops);
|
|
92
|
+
const keys = {
|
|
93
|
+
harness: objectAt(selected.harness),
|
|
94
|
+
llm: objectAt(selected.llm),
|
|
95
|
+
loops: { orchestrator: objectAt(loops.orchestrator) },
|
|
96
|
+
roleLlm: objectAt(selected.roleLlm),
|
|
97
|
+
tools: { selfImplement: objectAt(tools.selfImplement) },
|
|
98
|
+
};
|
|
99
|
+
const rawDefault = objectAt(host.tools).selfImplement;
|
|
100
|
+
const preference = objectAt(rawDefault).podChildDefault;
|
|
101
|
+
if (preference === 'off' || preference === false) keys.tools.selfImplement.podChildDefault = 'off';
|
|
102
|
+
else if (preference && typeof preference === 'object' && !Array.isArray(preference)) {
|
|
103
|
+
const raw = preference as Record<string, unknown>;
|
|
104
|
+
const provider = typeof raw.provider === 'string' ? raw.provider.trim() : '';
|
|
105
|
+
const model = typeof raw.model === 'string' ? raw.model.trim() : '';
|
|
106
|
+
if (provider) keys.tools.selfImplement.podChildDefault = { provider, ...(model ? { model } : {}) };
|
|
107
|
+
}
|
|
108
|
+
keys.llm.fallbackChain = [...runtime.steps];
|
|
109
|
+
const zai = objectAt(keys.llm.zaiCodingPlan);
|
|
110
|
+
zai.overage = runtime.overage;
|
|
111
|
+
keys.llm.zaiCodingPlan = zai;
|
|
112
|
+
keys.harness.worktreeAddTimeoutSec = runtime.worktreeAddTimeoutSec;
|
|
113
|
+
const canonicalKeys = canonical(keys) as JsonObject & { llm: JsonObject; harness: JsonObject };
|
|
114
|
+
const sources: Record<string, SnapshotSource> = {};
|
|
115
|
+
sourcesOf(canonicalKeys, '', sources);
|
|
116
|
+
sources['llm.fallbackChain'] = 'runtime';
|
|
117
|
+
sources['llm.zaiCodingPlan.overage'] = 'runtime';
|
|
118
|
+
sources['harness.worktreeAddTimeoutSec'] = 'runtime';
|
|
119
|
+
const version = 1 as const;
|
|
120
|
+
const body = { version, keys: canonicalKeys, sources };
|
|
121
|
+
const hash = createHash('sha256').update(JSON.stringify(body)).digest('hex');
|
|
122
|
+
return { ...body, hash, envelopeJson: JSON.stringify({ ...body, hash }), configJson: JSON.stringify(canonicalKeys), keyCount: Object.keys(sources).length };
|
|
123
|
+
}
|
|
@@ -42,7 +42,32 @@ function ledgerString(value: unknown): string {
|
|
|
42
42
|
return typeof value === 'string' && value.trim().length > 0 ? value : '';
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
type PreflightCheck = { reasonCode: string; checkName: string; targetPath?: string };
|
|
45
|
+
export type PreflightCheck = { reasonCode: string; checkName: string; targetPath?: string };
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A Pod failure's structured ledger axes: the rejection's own reason code, check name and *untruncated* target
|
|
49
|
+
* path, kept apart from the human-readable reason text — and, separately from all of them, whether the child's
|
|
50
|
+
* terminal result line was absent at all.
|
|
51
|
+
*/
|
|
52
|
+
export interface PodFailureLedgerAxes {
|
|
53
|
+
readonly reasonCode?: string;
|
|
54
|
+
readonly checkName?: string;
|
|
55
|
+
readonly targetPath?: string;
|
|
56
|
+
readonly preflightChecks?: readonly PreflightCheck[];
|
|
57
|
+
/** `true` = the child wrote no terminal result line. Absence is never folded into the rejection reason. */
|
|
58
|
+
readonly noResultLine?: true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Keep the failure's structured facts as their own ledger fields; absent facts stay omitted (never `''`). */
|
|
62
|
+
export function podFailureLedgerAxes(exit: PodFailureLedgerAxes): PodFailureLedgerAxes {
|
|
63
|
+
return {
|
|
64
|
+
...(exit.reasonCode ? { reasonCode: exit.reasonCode } : {}),
|
|
65
|
+
...(exit.checkName ? { checkName: exit.checkName } : {}),
|
|
66
|
+
...(exit.targetPath ? { targetPath: exit.targetPath } : {}),
|
|
67
|
+
...(exit.preflightChecks?.length ? { preflightChecks: exit.preflightChecks } : {}),
|
|
68
|
+
...(exit.noResultLine ? { noResultLine: true as const } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
46
71
|
|
|
47
72
|
/** Keep each structured check paired with its own path; legacy blockers retain their name/detail diagnostic. */
|
|
48
73
|
function preflightBlockerText(blockers: unknown): { error: string; preflightChecks: PreflightCheck[] } {
|
|
@@ -341,7 +366,7 @@ export interface PodTermination {
|
|
|
341
366
|
}
|
|
342
367
|
|
|
343
368
|
/** FailureTarget can precede Failed at the deadline. Read both in the same Job snapshot. */
|
|
344
|
-
export const POD_TERMINATION_JOB_JSONPATH = '{.status.conditions[?(@.type=="Failed")].reason}{"|"}{.status.conditions[?(@.type=="FailureTarget")].reason}{"\\t"}{.spec.activeDeadlineSeconds}{"\\t"}{.metadata.uid}';
|
|
369
|
+
export const POD_TERMINATION_JOB_JSONPATH = '{.status.conditions[?(@.type=="Failed")].reason}{"|"}{.status.conditions[?(@.type=="FailureTarget")].reason}{"\\t"}{.spec.activeDeadlineSeconds}{"\\t"}{.metadata.uid}{"\\t"}{.metadata.creationTimestamp}{"\\t"}{.status.completionTime}';
|
|
345
370
|
|
|
346
371
|
export function podJobConditionReason(value: string | undefined): string {
|
|
347
372
|
const [failed, target] = (value ?? '').split('|');
|
|
@@ -78,24 +78,27 @@ export function seedMirrorOnce(o: { host: string; commit: string; cwd: string; p
|
|
|
78
78
|
* one sha when it does not — objects only, no ref is moved). Never throws: a miss returns `reason` and the caller skips
|
|
79
79
|
* the seed (best effort — the Job keeps its GitHub path).
|
|
80
80
|
*/
|
|
81
|
-
export async function resolveDefaultSourceHead(o: { repoUrl: string; base?: string; cwd: string; git?: Push; limitMs?: number }): Promise<{ sha?: string; reason?: string }> {
|
|
81
|
+
export async function resolveDefaultSourceHead(o: { repoUrl: string; base?: string; cwd: string; git?: Push; limitMs?: number }): Promise<{ sha?: string; reason?: string; originCalls?: number }> {
|
|
82
82
|
const git = o.git ?? gitWithin;
|
|
83
83
|
const limitMs = o.limitMs ?? 30_000;
|
|
84
84
|
const base = o.base || 'main';
|
|
85
|
-
if (base.startsWith('-') || !/^[\w./-]+$/.test(base) || o.repoUrl.startsWith('-')) return { reason: 'invalid-ref' };
|
|
85
|
+
if (base.startsWith('-') || !/^[\w./-]+$/.test(base) || o.repoUrl.startsWith('-')) return { reason: 'invalid-ref', originCalls: 0 };
|
|
86
|
+
let originCalls = 0;
|
|
86
87
|
try {
|
|
88
|
+
originCalls += 1;
|
|
87
89
|
const listed = await git(['ls-remote', '--', o.repoUrl, `refs/heads/${base}`], o.cwd, limitMs);
|
|
88
|
-
if (listed.rc !== 0) return { reason: 'ls-remote-failed' };
|
|
90
|
+
if (listed.rc !== 0) return { reason: 'ls-remote-failed', originCalls };
|
|
89
91
|
// Only the exact ref asked for — never the first `refs/heads/*` line (a branch named `a/refs/heads/main` must not pass).
|
|
90
92
|
const want = `refs/heads/${base}`;
|
|
91
93
|
const sha = listed.output.split(/\r?\n/).map((line) => line.split('\t')).find(([hash, ref]) => ref === want && /^[0-9a-f]{40}$/.test(hash ?? ''))?.[0];
|
|
92
|
-
if (!sha) return { reason: 'ls-remote-no-sha' };
|
|
93
|
-
if ((await git(['cat-file', '-e', `${sha}^{commit}`], o.cwd, limitMs)).rc === 0) return { sha };
|
|
94
|
+
if (!sha) return { reason: 'ls-remote-no-sha', originCalls };
|
|
95
|
+
if ((await git(['cat-file', '-e', `${sha}^{commit}`], o.cwd, limitMs)).rc === 0) return { sha, originCalls };
|
|
96
|
+
originCalls += 1;
|
|
94
97
|
const fetched = await git(['fetch', '--quiet', '--no-write-fetch-head', '--', o.repoUrl, sha], o.cwd, GATE_MIRROR_SEED_LIMIT_MS);
|
|
95
|
-
if (fetched.rc !== 0) return { reason: 'commit-fetch-failed' };
|
|
96
|
-
return (await git(['cat-file', '-e', `${sha}^{commit}`], o.cwd, limitMs)).rc === 0 ? { sha } : { reason: 'commit-not-local' };
|
|
98
|
+
if (fetched.rc !== 0) return { reason: 'commit-fetch-failed', originCalls };
|
|
99
|
+
return (await git(['cat-file', '-e', `${sha}^{commit}`], o.cwd, limitMs)).rc === 0 ? { sha, originCalls } : { reason: 'commit-not-local', originCalls };
|
|
97
100
|
} catch {
|
|
98
|
-
return { reason: 'resolve-threw' };
|
|
101
|
+
return { reason: 'resolve-threw', originCalls };
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
|
|
@@ -103,7 +103,7 @@ export function parseSiWarmCommand(raw: unknown): SiWarmCommand | null {
|
|
|
103
103
|
|| !digest(row.executionKey) || !str(row.sourceSha) || !SHA.test(row.sourceSha)
|
|
104
104
|
|| !token(row.podUid) || !integer(row.generation) || row.generation < 1
|
|
105
105
|
|| !validKey(row.key) || row.envProfile !== 'si-standard-v1'
|
|
106
|
-
|| !finite(row.deadlineAt) || !digest(row.payloadSha256)
|
|
106
|
+
|| !finite(row.deadlineAt) || row.deadlineAt <= 0 || !digest(row.payloadSha256)
|
|
107
107
|
|| !digest(row.credentialBundleSha256)) return null;
|
|
108
108
|
return raw as SiWarmCommand;
|
|
109
109
|
}
|
|
@@ -5,7 +5,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
5
5
|
import { siTaskPodStageShell } from './pod-lifecycle-stages.js';
|
|
6
6
|
|
|
7
7
|
export type PodSource =
|
|
8
|
-
| { kind: 'default'; base?: string }
|
|
8
|
+
| { kind: 'default'; base?: string; baseSha?: string }
|
|
9
9
|
| { kind: 'commit'; sha: string }
|
|
10
10
|
| { kind: 'pr'; number: number }
|
|
11
11
|
| { kind: 'bundle'; bundlePath: string; sha256: string; sizeBytes: number; headCommit: string };
|
|
@@ -64,6 +64,24 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
64
64
|
const quotedCommitFile = `'${(options.imageCommitFile ?? '/opt/elanous-source-commit').replace(/'/g, `'\\''`)}'`;
|
|
65
65
|
const quotedImageGitDir = `'${(options.imageGitDir ?? '/opt/elanous-pin.git').replace(/'/g, `'\\''`)}'`;
|
|
66
66
|
const clone = `git clone -q --depth 50 ${quotedUrl} repo`;
|
|
67
|
+
// First observation slice: count source checkout work without changing its routing.
|
|
68
|
+
const ioStart = [
|
|
69
|
+
// Count calls performed by this Pod source stage. Branch validation via
|
|
70
|
+
// assertRemoteBase runs on the host before Job creation and is outside it.
|
|
71
|
+
'pod_source_io_origin_calls=0',
|
|
72
|
+
'pod_source_io_started=$(date +%s)',
|
|
73
|
+
'pod_source_io_reported=0',
|
|
74
|
+
'pod_source_io_measured=0',
|
|
75
|
+
'pod_source_io_measure() { pod_source_io_files=$(git ls-files -z | tr -cd "\\000" | wc -c | tr -d " "); pod_source_io_seconds=$(( $(date +%s) - pod_source_io_started )); pod_source_io_measured=1; }',
|
|
76
|
+
'pod_source_io_emit() {',
|
|
77
|
+
' [ "$pod_source_io_reported" -eq 0 ] || return 0; pod_source_io_reported=1',
|
|
78
|
+
' [ -n "${pod_source_io_seconds:-}" ] || pod_source_io_seconds=$(( $(date +%s) - pod_source_io_started ))',
|
|
79
|
+
' [ -n "${pod_source_io_files:-}" ] || pod_source_io_files=null',
|
|
80
|
+
' pod_source_io_status=incomplete; if [ "$pod_source_io_measured" -eq 1 ]; then pod_source_io_status=complete; fi',
|
|
81
|
+
' printf \'ELANOUS_POD_SOURCE_IO {"originCalls":%s,"checkoutFiles":%s,"sourceVia":"%s","sourceSeconds":%s,"sourceStatus":"%s","pushCalls":null,"installRan":null,"installSeconds":null}\\n\' "$pod_source_io_origin_calls" "$pod_source_io_files" "${source_via:-unknown}" "$pod_source_io_seconds" "$pod_source_io_status"',
|
|
82
|
+
'}',
|
|
83
|
+
'trap pod_source_io_emit EXIT',
|
|
84
|
+
];
|
|
67
85
|
const start = [
|
|
68
86
|
'if [ -e repo ]; then exit 5; fi',
|
|
69
87
|
// POD-MIRROR-IO: the image's pinned tree is a shared read-only lower layer.
|
|
@@ -113,7 +131,11 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
113
131
|
'else',
|
|
114
132
|
" printf 'ELANOUS_POD_SOURCE_MIRROR_SKIP %s\\n' \"$mirror_skip\"",
|
|
115
133
|
' if [ -e repo ]; then rm -r -- repo || exit 5; fi',
|
|
116
|
-
|
|
134
|
+
...(source.kind === 'default' && source.baseSha ? [] : [' pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))']),
|
|
135
|
+
...(source.kind === 'default' && source.baseSha ? [
|
|
136
|
+
` printf 'ELANOUS_POD_SOURCE_BASE_SHA_UNAVAILABLE %s\\n' '${source.baseSha}'`,
|
|
137
|
+
' exit 5',
|
|
138
|
+
] : [` ${clone} || exit 5`]),
|
|
117
139
|
' source_via=github',
|
|
118
140
|
'fi',
|
|
119
141
|
'fi',
|
|
@@ -121,22 +143,50 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
121
143
|
'cd repo || exit 5',
|
|
122
144
|
];
|
|
123
145
|
if (source.kind === 'default') {
|
|
146
|
+
if (source.baseSha) {
|
|
147
|
+
const sha = assertSha(source.baseSha, 'base sha');
|
|
148
|
+
const base = source.base ?? 'main';
|
|
149
|
+
if (base.startsWith('-') || !/^[\w./-]+$/.test(base)) throw new Error(`invalid Pod base ref: ${base}`);
|
|
150
|
+
const quote = (value: string) => `'${value.replace(/'/g, `'\\''`)}'`;
|
|
151
|
+
const quotedBase = quote(base);
|
|
152
|
+
const quotedTrackingRef = quote(`refs/remotes/origin/${base}`);
|
|
153
|
+
const quotedUpstream = quote(`origin/${base}`);
|
|
154
|
+
return [
|
|
155
|
+
...ioStart,
|
|
156
|
+
...start,
|
|
157
|
+
`if ! git cat-file -e '${sha}^{commit}' 2>/dev/null; then git fetch --quiet --no-write-fetch-head ${quotedMirror} '${sha}' || { printf 'ELANOUS_POD_SOURCE_BASE_SHA_UNAVAILABLE %s\\n' '${sha}'; exit 5; }; fi`,
|
|
158
|
+
`git checkout -q -B ${quotedBase} '${sha}' || exit 5`,
|
|
159
|
+
`git update-ref ${quotedTrackingRef} '${sha}' || exit 5`,
|
|
160
|
+
`git symbolic-ref refs/remotes/origin/HEAD ${quotedTrackingRef} || exit 5`,
|
|
161
|
+
`git branch --set-upstream-to=${quotedUpstream} ${quotedBase} >/dev/null || exit 5`,
|
|
162
|
+
'head=$(git rev-parse HEAD)',
|
|
163
|
+
'pod_source_io_measure',
|
|
164
|
+
"printf 'ELANOUS_POD_SOURCE default %s\\n' \"$head\"",
|
|
165
|
+
'pod_source_io_emit',
|
|
166
|
+
].join('\n');
|
|
167
|
+
}
|
|
124
168
|
if (source.base && source.base !== 'main') {
|
|
125
169
|
assertRemoteBase(repoUrl, source.base);
|
|
126
170
|
const base = source.base;
|
|
127
171
|
const quote = (value: string) => `'${value.replace(/'/g, `'\\''`)}'`;
|
|
128
172
|
const quotedTrackingRef = quote(`refs/remotes/origin/${base}`);
|
|
129
173
|
return [
|
|
174
|
+
...ioStart,
|
|
130
175
|
...start,
|
|
176
|
+
'pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))',
|
|
131
177
|
`git fetch --depth 50 origin ${quote(`+refs/heads/${base}:refs/remotes/origin/${base}`)} || exit 5`,
|
|
132
178
|
`git checkout -q -B ${quote(base)} ${quotedTrackingRef} || exit 5`,
|
|
133
179
|
'head=$(git rev-parse HEAD)',
|
|
180
|
+
'pod_source_io_measure',
|
|
134
181
|
"printf 'ELANOUS_POD_SOURCE default %s\\n' \"$head\"",
|
|
182
|
+
'pod_source_io_emit',
|
|
135
183
|
].join('\n');
|
|
136
184
|
}
|
|
137
185
|
return [
|
|
186
|
+
...ioStart,
|
|
138
187
|
...start,
|
|
139
188
|
'if [ "$source_via" != github ]; then',
|
|
189
|
+
' pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))',
|
|
140
190
|
' remote_info=$(git ls-remote --symref origin HEAD) || exit 5',
|
|
141
191
|
` remote_head=$(printf '%s\\n' "$remote_info" | awk '$2=="HEAD" && $1!="ref:" {print $1}')`,
|
|
142
192
|
` remote_branch=$(printf '%s\\n' "$remote_info" | awk '$1=="ref:" && $3=="HEAD" && $2 ~ /^refs\\/heads\\// {sub(/^refs\\/heads\\//, "", $2); print $2}')`,
|
|
@@ -146,6 +196,7 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
146
196
|
' git reset --hard "$remote_head" || exit 5',
|
|
147
197
|
" printf 'ELANOUS_POD_SOURCE_DELTA mirror\\n'",
|
|
148
198
|
' else',
|
|
199
|
+
' pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))',
|
|
149
200
|
' git fetch --depth 50 origin HEAD && git reset --hard FETCH_HEAD || exit 5',
|
|
150
201
|
" printf 'ELANOUS_POD_SOURCE_DELTA origin\\n'",
|
|
151
202
|
' fi',
|
|
@@ -158,53 +209,68 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
158
209
|
' git branch --set-upstream-to="origin/$remote_branch" "$remote_branch" >/dev/null || exit 5',
|
|
159
210
|
'fi',
|
|
160
211
|
'head=$(git rev-parse HEAD)',
|
|
212
|
+
'pod_source_io_measure',
|
|
161
213
|
"printf 'ELANOUS_POD_SOURCE default %s\\n' \"$head\"",
|
|
214
|
+
'pod_source_io_emit',
|
|
162
215
|
].join('\n');
|
|
163
216
|
}
|
|
164
217
|
if (source.kind === 'commit') {
|
|
165
218
|
const sha = assertSha(source.sha, 'sha');
|
|
166
219
|
return [
|
|
220
|
+
...ioStart,
|
|
167
221
|
...start,
|
|
168
|
-
`if ! git cat-file -e '${sha}^{commit}' 2>/dev/null; then git fetch --depth 1 origin ${sha} || exit 5; fi`,
|
|
222
|
+
`if ! git cat-file -e '${sha}^{commit}' 2>/dev/null; then pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1)); git fetch --depth 1 origin ${sha} || exit 5; fi`,
|
|
169
223
|
`git checkout --detach ${sha} || exit 5`,
|
|
170
224
|
'head=$(git rev-parse HEAD)',
|
|
225
|
+
'pod_source_io_measure',
|
|
171
226
|
"printf 'ELANOUS_POD_SOURCE commit %s\\n' \"$head\"",
|
|
227
|
+
'pod_source_io_emit',
|
|
172
228
|
].join('\n');
|
|
173
229
|
}
|
|
174
230
|
if (source.kind === 'pr') {
|
|
175
231
|
const n = assertPositiveInt(source.number);
|
|
176
232
|
return [
|
|
233
|
+
...ioStart,
|
|
177
234
|
...start,
|
|
235
|
+
'pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))',
|
|
178
236
|
`pr_sha=$(git ls-remote origin refs/pull/${n}/head | cut -f1) || exit 5`,
|
|
179
237
|
'if ! [[ "$pr_sha" =~ ^[0-9a-f]{40}$ ]]; then exit 5; fi',
|
|
180
|
-
`if ! git cat-file -e "$pr_sha^{commit}" 2>/dev/null; then git fetch --depth 50 origin pull/${n}/head || exit 5; fi`,
|
|
238
|
+
`if ! git cat-file -e "$pr_sha^{commit}" 2>/dev/null; then pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1)); git fetch --depth 50 origin pull/${n}/head || exit 5; fi`,
|
|
181
239
|
`git checkout -B pr-${n} "$pr_sha" || exit 5`,
|
|
182
240
|
// A pinned image starts at one shallow main commit. Fetching a PR tip at
|
|
183
241
|
// depth 50 can leave that pin and the PR in disconnected shallow spans.
|
|
184
242
|
// Deepen only after merge-base fails; the gate still reports unavailable
|
|
185
243
|
// if ancestry cannot be obtained.
|
|
244
|
+
'pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))',
|
|
186
245
|
'remote_info=$(git ls-remote --symref origin HEAD 2>/dev/null) || { printf \'ELANOUS_POD_COMPARISON_BASE unavailable\\n\'; exit 5; }',
|
|
187
246
|
`base_branch=$(printf '%s\\n' "$remote_info" | awk '$1=="ref:" && $3=="HEAD" && $2 ~ /^refs\\/heads\\// {sub(/^refs\\/heads\\//, "", $2); print $2}')`,
|
|
188
247
|
'if [ -n "$base_branch" ] && git check-ref-format --branch "$base_branch" >/dev/null 2>&1; then',
|
|
189
248
|
' base_ref="refs/remotes/origin/$base_branch"',
|
|
249
|
+
' pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))',
|
|
190
250
|
' git fetch --depth 50 origin "+refs/heads/$base_branch:$base_ref" || { printf \'ELANOUS_POD_COMPARISON_BASE unavailable\\n\'; exit 5; }',
|
|
191
251
|
' git symbolic-ref refs/remotes/origin/HEAD "$base_ref" || exit 5',
|
|
192
252
|
' if ! git merge-base HEAD "$base_ref" >/dev/null 2>&1 && [ "$(git rev-parse --is-shallow-repository)" = true ]; then',
|
|
253
|
+
' pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))',
|
|
193
254
|
` git fetch --deepen=100 origin "+refs/heads/$base_branch:$base_ref" +refs/pull/${n}/head:refs/remotes/origin/pr-${n}-head || printf 'ELANOUS_POD_COMPARISON_BASE deepen-failed\\n'`,
|
|
194
255
|
' fi',
|
|
195
256
|
' if ! git merge-base HEAD "$base_ref" >/dev/null 2>&1 && [ "$(git rev-parse --is-shallow-repository)" = true ]; then',
|
|
257
|
+
' pod_source_io_origin_calls=$((pod_source_io_origin_calls + 1))',
|
|
196
258
|
` git fetch --unshallow origin "+refs/heads/$base_branch:$base_ref" +refs/pull/${n}/head:refs/remotes/origin/pr-${n}-head || { printf 'ELANOUS_POD_COMPARISON_BASE unavailable\\n'; exit 5; }`,
|
|
197
259
|
' fi',
|
|
198
260
|
" if ! git merge-base HEAD \"$base_ref\" >/dev/null 2>&1; then printf 'ELANOUS_POD_COMPARISON_BASE unavailable\\n'; fi",
|
|
199
261
|
"else printf 'ELANOUS_POD_COMPARISON_BASE unavailable\\n'; exit 5; fi",
|
|
200
262
|
'head=$(git rev-parse HEAD)',
|
|
263
|
+
'pod_source_io_measure',
|
|
201
264
|
"printf 'ELANOUS_POD_SOURCE pr %s\\n' \"$head\"",
|
|
265
|
+
'pod_source_io_emit',
|
|
202
266
|
].join('\n');
|
|
203
267
|
}
|
|
204
268
|
const sha256 = assertSha256(source.sha256);
|
|
205
269
|
const sizeBytes = assertSize(source.sizeBytes);
|
|
206
270
|
const headCommit = assertSha(source.headCommit, 'headCommit');
|
|
207
271
|
return [
|
|
272
|
+
...ioStart,
|
|
273
|
+
'source_via=bundle',
|
|
208
274
|
'ready=0',
|
|
209
275
|
'for i in $(seq 1 300); do',
|
|
210
276
|
' if [ -f /tmp/source.ready ]; then ready=1; break; fi',
|
|
@@ -242,8 +308,10 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
242
308
|
' git -C repo fetch /tmp/source.bundle "refs/elanous/pod-source/*:refs/remotes/bundle/*" || exit 5',
|
|
243
309
|
'fi',
|
|
244
310
|
`git -C repo checkout --detach ${headCommit} || exit 5`,
|
|
245
|
-
'head=$(git -C repo rev-parse HEAD) || exit 5',
|
|
246
|
-
"printf 'ELANOUS_POD_SOURCE bundle %s\\n' \"$head\"",
|
|
247
311
|
'cd repo || exit 5',
|
|
312
|
+
'head=$(git rev-parse HEAD) || exit 5',
|
|
313
|
+
'pod_source_io_measure',
|
|
314
|
+
"printf 'ELANOUS_POD_SOURCE bundle %s\\n' \"$head\"",
|
|
315
|
+
'pod_source_io_emit',
|
|
248
316
|
].join('\n');
|
|
249
317
|
}
|
|
@@ -389,6 +389,7 @@ export class WarmPodTransport {
|
|
|
389
389
|
|| command.workerId !== this.spec.workerId || command.cutSha !== this.spec.cutSha
|
|
390
390
|
|| !equalKey(command.key, this.spec.key)
|
|
391
391
|
|| ![command.runId, command.attemptId, command.leaseId, command.workerId].every(value => TOKEN.test(value))
|
|
392
|
+
|| typeof command.podUid !== 'string' || !command.podUid
|
|
392
393
|
|| !Number.isSafeInteger(command.generation) || command.generation < 1) return fallback('key-drift');
|
|
393
394
|
const prefix = ['--context', this.spec.kubectlContext, '-n', this.spec.namespace];
|
|
394
395
|
const observed = this.kubectl([...prefix, 'get', 'pod', this.spec.name, '-o', 'json']);
|
|
@@ -425,7 +426,7 @@ export class WarmPodTransport {
|
|
|
425
426
|
try { nodeArch = node.status === 0 ? JSON.parse(node.stdout)?.metadata?.labels?.['kubernetes.io/arch'] : null; }
|
|
426
427
|
catch { nodeArch = null; }
|
|
427
428
|
if (nodeArch !== this.spec.key.architecture) return fallback('pod-unready');
|
|
428
|
-
if (
|
|
429
|
+
if (uid !== command.podUid || (this.podUid !== null && uid !== this.podUid)) {
|
|
429
430
|
this.quarantined = true; return fallback('pod-replaced');
|
|
430
431
|
}
|
|
431
432
|
this.podUid = uid;
|
|
@@ -44,6 +44,8 @@ function waitForPrepareRetry(signal?: AbortSignal): Promise<void> {
|
|
|
44
44
|
export type WarmReplayInput = Omit<WarmWorkerCommand, 'leaseId' | 'generation' | 'workerId' | 'key'>;
|
|
45
45
|
export interface WarmReplayResult { command: WarmWorkerCommand | null; transport: WarmPodTransportResult }
|
|
46
46
|
export interface WarmWorkerCandidate { host: string; tier: WarmPoolTier; spec: WarmPodSpec }
|
|
47
|
+
/** The OS `flock(fd, operation)` binding the prepare lease waits on. */
|
|
48
|
+
export type WarmPrepareFlock = (fd: number, operation: number) => number;
|
|
47
49
|
export interface WarmPodProviderOptions {
|
|
48
50
|
candidates: readonly WarmWorkerCandidate[];
|
|
49
51
|
/** One pinned template per host/tier. Each expands to the measured profile quota. */
|
|
@@ -64,6 +66,8 @@ export interface WarmPodProviderOptions {
|
|
|
64
66
|
prepareLockDirectory?: string;
|
|
65
67
|
/** Cancels a prepare waiting for another process to finish the same host/worker slot. */
|
|
66
68
|
prepareAbortSignal?: AbortSignal;
|
|
69
|
+
/** Injects the prepare-lease flock binding. Omitted keeps this platform's binding; null/false declares it unsupported. */
|
|
70
|
+
prepareFlock?: WarmPrepareFlock | null | false;
|
|
67
71
|
/** Gate file this pool serves, used to bind cold prepare legs to their 1-file gate measurement key. */
|
|
68
72
|
pairingGateFile?: string;
|
|
69
73
|
}
|
|
@@ -164,7 +168,7 @@ const prepareLockLib = process.platform === 'linux' || process.platform === 'dar
|
|
|
164
168
|
flock: { args: ['int', 'int'], returns: 'int' },
|
|
165
169
|
[process.platform === 'linux' ? '__errno_location' : '__error']: { args: [], returns: 'ptr' },
|
|
166
170
|
}) : null;
|
|
167
|
-
const prepareFlock = prepareLockLib?.symbols.flock ?? null;
|
|
171
|
+
const prepareFlock: WarmPrepareFlock | null = prepareLockLib?.symbols.flock ?? null;
|
|
168
172
|
const prepareErrnoLocation = prepareLockLib?.symbols[process.platform === 'linux' ? '__errno_location' : '__error'];
|
|
169
173
|
const readPrepareErrno = (): number => (prepareErrnoLocation ? read.i32(prepareErrnoLocation() as Pointer) : -1);
|
|
170
174
|
const LOCK_EX = 2;
|
|
@@ -173,7 +177,7 @@ const LOCK_UN = 8;
|
|
|
173
177
|
const PREPARE_LOCK_WAIT_MS = (POD_READY_WAIT_SECONDS * 1_000) + 30_000;
|
|
174
178
|
|
|
175
179
|
async function withPrepareLease<T>(candidate: WarmWorkerCandidate, directory: string | undefined,
|
|
176
|
-
work: () => Promise<T>, signal?: AbortSignal): Promise<T | null> {
|
|
180
|
+
work: () => Promise<T>, signal?: AbortSignal, flock?: WarmPrepareFlock | null): Promise<T | null> {
|
|
177
181
|
const uid = typeof process.getuid === 'function' ? process.getuid() : userInfo().uid;
|
|
178
182
|
const root = directory ?? join(tmpdir(), `elanous-warm-prepare-${uid}`);
|
|
179
183
|
const identity = createHash('sha256').update(`${candidate.host}/${candidate.spec.workerId}`).digest('hex');
|
|
@@ -186,11 +190,11 @@ async function withPrepareLease<T>(candidate: WarmWorkerCandidate, directory: st
|
|
|
186
190
|
const info = lstatSync(lock);
|
|
187
191
|
if (!info.isFile() || info.isSymbolicLink() || info.uid !== uid || (info.mode & 0o077) !== 0)
|
|
188
192
|
throw new Error('unsafe warm prepare lock file');
|
|
189
|
-
if (!
|
|
193
|
+
if (!flock) throw new Error('warm prepare OS locks are unavailable on this platform');
|
|
190
194
|
const lockDeadline = performance.now() + PREPARE_LOCK_WAIT_MS;
|
|
191
195
|
while (!acquired) {
|
|
192
196
|
if (signal?.aborted) throw new Error('warm prepare lock wait cancelled');
|
|
193
|
-
if (
|
|
197
|
+
if (flock(fd, LOCK_EX | LOCK_NB) === 0) { acquired = true; break; }
|
|
194
198
|
const errno = readPrepareErrno();
|
|
195
199
|
// EWOULDBLOCK/EAGAIN: Linux 11, Darwin 35. EINTR is safe to retry.
|
|
196
200
|
if (errno !== 11 && errno !== 35 && errno !== 4)
|
|
@@ -209,7 +213,7 @@ async function withPrepareLease<T>(candidate: WarmWorkerCandidate, directory: st
|
|
|
209
213
|
workerId: candidate.spec.workerId, reason: error instanceof Error ? error.message : String(error) }, { level: 'warn' });
|
|
210
214
|
throw error;
|
|
211
215
|
} finally {
|
|
212
|
-
if (acquired && fd !== undefined)
|
|
216
|
+
if (acquired && fd !== undefined) flock?.(fd, LOCK_UN);
|
|
213
217
|
if (fd !== undefined) closeSync(fd);
|
|
214
218
|
}
|
|
215
219
|
}
|
|
@@ -223,7 +227,14 @@ export class WarmPodProvider {
|
|
|
223
227
|
private readonly legs: WarmReuseTimeLegRow[] = [];
|
|
224
228
|
/** One terminal transition per fenced lease, including concurrent callers. Failed transitions remain retryable. */
|
|
225
229
|
private readonly terminalLeases = new Map<string, Promise<'sanitized' | 'quarantined'>>();
|
|
230
|
+
/** A gate fallback supersedes an in-flight sanitize even if its control reply is late. */
|
|
231
|
+
private readonly quarantineRequested = new Set<string>();
|
|
232
|
+
private readonly terminalEndLogged = new Set<string>();
|
|
233
|
+
/** While quarantine is settling, reject only that Pod incarnation after acquisition. */
|
|
234
|
+
private readonly quarantiningPods = new Set<string>();
|
|
226
235
|
private readonly standingWorkers = new Map<string, Promise<boolean>>();
|
|
236
|
+
/** This instance's prepare-lease flock binding; null means the platform cannot lock and every slot fails. */
|
|
237
|
+
private readonly prepareFlock: WarmPrepareFlock | null;
|
|
227
238
|
constructor(private readonly options: WarmPodProviderOptions) {
|
|
228
239
|
const url = new URL(options.controlUrl);
|
|
229
240
|
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash
|
|
@@ -266,6 +277,9 @@ export class WarmPodProvider {
|
|
|
266
277
|
}
|
|
267
278
|
this.fetcher = options.fetch ?? fetch;
|
|
268
279
|
this.now = options.now ?? Date.now;
|
|
280
|
+
// An omitted option keeps the platform binding; an explicit false/null declares flock unsupported.
|
|
281
|
+
this.prepareFlock = options.prepareFlock === undefined ? prepareFlock
|
|
282
|
+
: options.prepareFlock === false ? null : options.prepareFlock;
|
|
269
283
|
}
|
|
270
284
|
|
|
271
285
|
private async control(path: string, credential: string, body?: Record<string, unknown>): Promise<{ status: number; value: any }> {
|
|
@@ -347,7 +361,8 @@ export class WarmPodProvider {
|
|
|
347
361
|
const inFlight = this.standingWorkers.get(key);
|
|
348
362
|
if (inFlight) return inFlight;
|
|
349
363
|
const preparation = withPrepareLease(configured, this.options.prepareLockDirectory,
|
|
350
|
-
() => this.prepareStandingWorker(configured, this.options.prepareAbortSignal), this.options.prepareAbortSignal
|
|
364
|
+
() => this.prepareStandingWorker(configured, this.options.prepareAbortSignal), this.options.prepareAbortSignal,
|
|
365
|
+
this.prepareFlock)
|
|
351
366
|
.then(result => result === true);
|
|
352
367
|
this.standingWorkers.set(key, preparation);
|
|
353
368
|
try { return await preparation; }
|
|
@@ -626,6 +641,12 @@ export class WarmPodProvider {
|
|
|
626
641
|
podName: leasedCandidate.spec.name, podContext: leasedCandidate.spec.kubectlContext, image: leasedCandidate.spec.image,
|
|
627
642
|
requestedAt: new Date(this.now()).toISOString(),
|
|
628
643
|
workerId: row.name, key: leasedCandidate.spec.key };
|
|
644
|
+
// Acquisition is by pool key. A healthy sibling or replacement Pod must remain eligible.
|
|
645
|
+
// Never run transport on the old Pod while its previous lease is being quarantined.
|
|
646
|
+
if (this.quarantiningPods.has(JSON.stringify([command.workerId, command.podUid]))) {
|
|
647
|
+
await this.quarantine(command, 'prior-lease-quarantine-pending', false);
|
|
648
|
+
return fallback('lease-unavailable');
|
|
649
|
+
}
|
|
629
650
|
const admitted = patchWarmLeaseMetadata(leasedCandidate.spec, command, 'leased', this.options.kubectl);
|
|
630
651
|
if (!admitted.ok) {
|
|
631
652
|
debug.log('pod.provenance', 'lease-patch-refused', { pod: leasedCandidate.spec.name,
|
|
@@ -685,7 +706,7 @@ export class WarmPodProvider {
|
|
|
685
706
|
let outcome: 'sanitized' | 'quarantined';
|
|
686
707
|
try { outcome = await terminal; }
|
|
687
708
|
catch (error) { if (this.terminalLeases.get(key) === terminal) this.terminalLeases.delete(key); throw error; }
|
|
688
|
-
if (outcome === 'quarantined') throw new Error('warm sanitize unavailable');
|
|
709
|
+
if (outcome === 'quarantined' || this.quarantineRequested.has(key)) throw new Error('warm sanitize unavailable');
|
|
689
710
|
}
|
|
690
711
|
|
|
691
712
|
private async finalizeOnce(command: WarmWorkerCommand): Promise<'sanitized' | 'quarantined'> {
|
|
@@ -702,25 +723,39 @@ export class WarmPodProvider {
|
|
|
702
723
|
await this.quarantineOnce(command, 'sanitize-unavailable', true);
|
|
703
724
|
return 'quarantined';
|
|
704
725
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
726
|
+
const key = JSON.stringify([command.workerId, command.leaseId, command.generation, command.podUid]);
|
|
727
|
+
if (!this.quarantineRequested.has(key)) {
|
|
728
|
+
debug.log('pod.provenance', 'lease-end', { pod: candidate.spec.name, podUid: command.podUid,
|
|
729
|
+
leaseId: command.leaseId, runId: command.runId, attemptId: command.attemptId,
|
|
730
|
+
releasedAt: new Date(this.now()).toISOString(), result: 'sanitized' });
|
|
731
|
+
this.terminalEndLogged.add(key);
|
|
732
|
+
}
|
|
708
733
|
return 'sanitized';
|
|
709
734
|
}
|
|
710
735
|
|
|
711
736
|
/** `leaseStarted=false` marks a refusal before `lease-start`, so start/end history stays paired. */
|
|
712
737
|
async quarantine(command: WarmWorkerCommand, reason: string, leaseStarted = true): Promise<void> {
|
|
713
738
|
const key = JSON.stringify([command.workerId, command.leaseId, command.generation, command.podUid]);
|
|
739
|
+
const podKey = JSON.stringify([command.workerId, command.podUid]);
|
|
740
|
+
this.quarantiningPods.add(podKey);
|
|
714
741
|
const prior = this.terminalLeases.get(key);
|
|
715
742
|
if (prior) {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
743
|
+
this.quarantineRequested.add(key);
|
|
744
|
+
const terminal = prior.then(async outcome => {
|
|
745
|
+
if (outcome === 'sanitized') {
|
|
746
|
+
await this.quarantineOnce(command, reason, leaseStarted);
|
|
747
|
+
return 'quarantined' as const;
|
|
748
|
+
}
|
|
749
|
+
return outcome;
|
|
750
|
+
});
|
|
751
|
+
this.terminalLeases.set(key, terminal);
|
|
752
|
+
try { await terminal; this.quarantiningPods.delete(podKey); }
|
|
753
|
+
catch (error) { if (this.terminalLeases.get(key) === terminal) this.terminalLeases.delete(key); throw error; }
|
|
719
754
|
return;
|
|
720
755
|
}
|
|
721
756
|
const terminal = this.quarantineOnce(command, reason, leaseStarted).then(() => 'quarantined' as const);
|
|
722
757
|
this.terminalLeases.set(key, terminal);
|
|
723
|
-
try { await terminal; }
|
|
758
|
+
try { await terminal; this.quarantiningPods.delete(podKey); }
|
|
724
759
|
catch (error) { if (this.terminalLeases.get(key) === terminal) this.terminalLeases.delete(key); throw error; }
|
|
725
760
|
}
|
|
726
761
|
|
|
@@ -734,9 +769,11 @@ export class WarmPodProvider {
|
|
|
734
769
|
if (!cleared.ok && reason !== 'provenance-unavailable') debug.log('pod.provenance', 'lease-patch-refused', { pod: candidate.spec.name,
|
|
735
770
|
podUid: command.podUid, leaseId: command.leaseId, reason: cleared.reason }, { level: 'warn' });
|
|
736
771
|
}
|
|
737
|
-
|
|
772
|
+
const key = JSON.stringify([command.workerId, command.leaseId, command.generation, command.podUid]);
|
|
773
|
+
debug.log('pod.provenance', this.terminalEndLogged.has(key) ? 'lease-late-quarantine' : leaseStarted ? 'lease-end' : 'lease-refused', { podUid: command.podUid,
|
|
738
774
|
leaseId: command.leaseId, runId: command.runId, attemptId: command.attemptId, leaseStarted,
|
|
739
775
|
releasedAt: new Date(this.now()).toISOString(), result: 'quarantined', reason });
|
|
776
|
+
this.terminalEndLogged.add(key);
|
|
740
777
|
}
|
|
741
778
|
|
|
742
779
|
|
|
@@ -751,6 +788,10 @@ export function loadWarmPodProvider(path: string, pairingGateFile?: string): War
|
|
|
751
788
|
const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'));
|
|
752
789
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid warm provider config');
|
|
753
790
|
const options = parsed as WarmPodProviderOptions;
|
|
791
|
+
// JSON cannot carry a real OS binding: only the unsupported-platform declaration is meaningful here.
|
|
792
|
+
// Omitting the field keeps this platform's dlopen binding (undefined), so the default path is unchanged.
|
|
793
|
+
if (options.prepareFlock !== undefined && options.prepareFlock !== null && options.prepareFlock !== false)
|
|
794
|
+
throw new Error('invalid warm provider prepare flock');
|
|
754
795
|
// The production entry points (--prepare/--reconcile/--serve) bind the 1-file gate key here.
|
|
755
796
|
if (pairingGateFile !== undefined) {
|
|
756
797
|
if (!pairingGateFile.trim()) throw new Error('warm provider pairing gate file must not be empty');
|