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
|
@@ -6,6 +6,7 @@ import { Database } from 'bun:sqlite';
|
|
|
6
6
|
import { checklistDevVersion, listChecklist, type ChecklistItem } from '../../release-loop/checklist.js';
|
|
7
7
|
import { readTrafficSignal } from '../../seat-loop/traffic-signal.js';
|
|
8
8
|
import { runHoldHygiene, type HygieneCell, type HygieneDeps } from '../../steward/hold-hygiene.js';
|
|
9
|
+
import { runDirectiveAudit, type DirectiveAuditDeps } from '../../steward/directive-audit.js';
|
|
9
10
|
import { effectiveInstanceRoot } from '../../instance/resolve.js';
|
|
10
11
|
import { getUserConfig, ORCHESTRATOR_DEFAULTS, resolveConfiguredAgentRoleLlm, type OrchestratorLoopConfig } from '../../user-config.js';
|
|
11
12
|
import { rubricPriority } from '../../release-loop/rubric.js';
|
|
@@ -70,6 +71,7 @@ export interface TickDeps {
|
|
|
70
71
|
heartbeatIntervalMs?: number;
|
|
71
72
|
hygieneCells?: () => HygieneCell[];
|
|
72
73
|
hygienePaths?: Pick<HygieneDeps, 'trafficPath' | 'metaPath' | 'dispatcherDir'>;
|
|
74
|
+
directiveAudit?: DirectiveAuditDeps;
|
|
73
75
|
cards?: () => TaskCard[]; split?: SplitAdapter; placeCell?: PlaceAdapter;
|
|
74
76
|
degradation?: () => { llm: boolean; board: boolean };
|
|
75
77
|
gridHosts?: readonly GridHost[];
|
|
@@ -960,6 +962,12 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
|
|
|
960
962
|
const sent = runHoldHygiene({ root, now, cells, ...deps.hygienePaths });
|
|
961
963
|
for (const notice of sent) observe('exchange', `hold-hygiene:${notice.key}`, 1, SEAT_LOOP_IDS[notice.to]);
|
|
962
964
|
} catch (error) { observe('hold-hygiene-failed', String(error).slice(0, 160), 0); }
|
|
965
|
+
// COORD-DIRECTIVE-AUDIT — 지시 원장 행마다 로직 점검(원장·로그·config)을 실제로 돌린다.
|
|
966
|
+
try {
|
|
967
|
+
const audit = runDirectiveAudit({ root, now: currentTime, ...deps.directiveAudit });
|
|
968
|
+
if (audit.alerts.length > 0) observe('directive-audit', `alerts:${audit.alerts.length}`, audit.alerts.length);
|
|
969
|
+
for (const proposal of audit.proposals) observe('directive-audit', `repair-proposal:${proposal.id}`, 1);
|
|
970
|
+
} catch (error) { observe('directive-audit-failed', String(error).slice(0, 160), 0); }
|
|
963
971
|
}
|
|
964
972
|
(deps.print ?? console.log)(reportLine(state));
|
|
965
973
|
}
|
|
@@ -9,6 +9,7 @@ import { queryRunScreenKey } from '../../self-implement/run-ledger.js';
|
|
|
9
9
|
import { logsDbPath } from '../../mss/logging/log-store.js';
|
|
10
10
|
import { redactSecretText } from '../../debug/log.js';
|
|
11
11
|
import { runAskLaunchFlow, type AskLaunchFlowResult } from '../../self-dev/ask-launch-flow.js';
|
|
12
|
+
import { defaultGoalAuthorSelfResolve } from '../../self-implement/goal-author-clarification.js';
|
|
12
13
|
import * as askIo from '../../self-dev/ask-launch-io.js';
|
|
13
14
|
import { DAEMON_HARNESS_ASK_ENTRANCE } from '../../self-dev/entrance-registry.js';
|
|
14
15
|
import { prepareAskLaunch } from '../../self-dev/launch-preflight.js';
|
|
@@ -211,12 +212,12 @@ function defaultAskDeps(rows: Awaited<ReturnType<typeof askIo.readAskPreflightLo
|
|
|
211
212
|
print: () => {},
|
|
212
213
|
log: (event: string, data: Record<string, unknown>, level?: 'info' | 'warn' | 'error') => debug.log('harness-http', event, data, { level }),
|
|
213
214
|
readLine: async () => '',
|
|
214
|
-
readClarification: async () => '',
|
|
215
215
|
readFile: (file: string) => readFileSync(file, 'utf8'),
|
|
216
216
|
writeFile: (file: string, data: string) => writeFileSync(file, data, 'utf8'),
|
|
217
217
|
cwd: () => process.cwd(),
|
|
218
218
|
now: () => Date.now(),
|
|
219
219
|
isInteractive: () => false,
|
|
220
|
+
selfResolveClarification: defaultGoalAuthorSelfResolve,
|
|
220
221
|
buildPreflightDeps: askIo.buildAskPreflightDeps,
|
|
221
222
|
priorBlockSamples: () => askIo.priorBlockSamplesFrom(rows),
|
|
222
223
|
recentAuthoringSamples: () => askIo.recentAuthoringSamplesFrom(rows),
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Capture PTY state and retain the live descriptor for replay comparison."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import fcntl
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import re
|
|
9
|
+
import select
|
|
10
|
+
import struct
|
|
11
|
+
import tempfile
|
|
12
|
+
import termios
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
DEFAULT_SNAPSHOT_ID = "pty_dee629e3"
|
|
16
|
+
_SCHEMA = 1
|
|
17
|
+
_LIVE_FDS: dict[str, int] = {}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(eq=True)
|
|
21
|
+
class Snapshot:
|
|
22
|
+
snapshot_id: str
|
|
23
|
+
rows: int
|
|
24
|
+
cols: int
|
|
25
|
+
termios_attributes: list
|
|
26
|
+
output: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(eq=True)
|
|
30
|
+
class ReplayState:
|
|
31
|
+
snapshot: Snapshot
|
|
32
|
+
live_rows: int
|
|
33
|
+
live_cols: int
|
|
34
|
+
live_termios_attributes: list
|
|
35
|
+
matches_live: bool
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _location(snapshot_id: str) -> Path:
|
|
39
|
+
if not isinstance(snapshot_id, str) or not re.fullmatch(r"[A-Za-z0-9_-]+", snapshot_id):
|
|
40
|
+
raise ValueError("invalid snapshot id")
|
|
41
|
+
directory = Path(os.environ.get("ELANOUS_PTY_SNAPSHOT_DIR", tempfile.gettempdir() + "/elanous-pty-snapshots"))
|
|
42
|
+
return directory / (snapshot_id + ".json")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _size(fd: int) -> tuple[int, int]:
|
|
46
|
+
rows, cols, _, _ = struct.unpack("HHHH", fcntl.ioctl(fd, termios.TIOCGWINSZ, b"\0" * 8))
|
|
47
|
+
return rows, cols
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _serialize_attrs(attrs: list) -> list:
|
|
51
|
+
return attrs[:6] + [[
|
|
52
|
+
{"bytes": entry.hex()} if isinstance(entry, bytes) else entry
|
|
53
|
+
for entry in attrs[6]
|
|
54
|
+
]]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _deserialize_attrs(value: object) -> list:
|
|
58
|
+
if not isinstance(value, list) or len(value) != 7 or any(
|
|
59
|
+
type(item) is not int for item in value[:6]
|
|
60
|
+
) or not isinstance(value[6], list):
|
|
61
|
+
raise ValueError("invalid termios attributes")
|
|
62
|
+
controls = []
|
|
63
|
+
for item in value[6]:
|
|
64
|
+
if type(item) is int and 0 <= item <= 255:
|
|
65
|
+
controls.append(item)
|
|
66
|
+
elif isinstance(item, dict) and set(item) == {"bytes"} and isinstance(item["bytes"], str):
|
|
67
|
+
try:
|
|
68
|
+
controls.append(bytes.fromhex(item["bytes"]))
|
|
69
|
+
except ValueError as error:
|
|
70
|
+
raise ValueError("invalid termios control byte") from error
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError("invalid termios control byte")
|
|
73
|
+
return value[:6] + [controls]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def snapshot(pty_fd: int, snapshot_id: str = DEFAULT_SNAPSHOT_ID) -> Snapshot:
|
|
77
|
+
"""Drain currently available output from a PTY master and save its state."""
|
|
78
|
+
path = _location(snapshot_id)
|
|
79
|
+
rows, cols = _size(pty_fd)
|
|
80
|
+
attrs = termios.tcgetattr(pty_fd)
|
|
81
|
+
output = bytearray()
|
|
82
|
+
while select.select([pty_fd], [], [], 0)[0]:
|
|
83
|
+
chunk = os.read(pty_fd, 65536)
|
|
84
|
+
if not chunk:
|
|
85
|
+
break
|
|
86
|
+
output.extend(chunk)
|
|
87
|
+
captured = Snapshot(snapshot_id, rows, cols, attrs, output.decode("utf-8"))
|
|
88
|
+
payload = {
|
|
89
|
+
"schema": _SCHEMA,
|
|
90
|
+
"snapshot_id": snapshot_id,
|
|
91
|
+
"rows": rows,
|
|
92
|
+
"cols": cols,
|
|
93
|
+
"termios_attributes": _serialize_attrs(attrs),
|
|
94
|
+
"output": captured.output,
|
|
95
|
+
}
|
|
96
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
97
|
+
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", dir=path.parent, delete=False) as file:
|
|
98
|
+
temporary = Path(file.name)
|
|
99
|
+
try:
|
|
100
|
+
json.dump(payload, file, ensure_ascii=False)
|
|
101
|
+
except BaseException:
|
|
102
|
+
temporary.unlink(missing_ok=True)
|
|
103
|
+
raise
|
|
104
|
+
temporary.replace(path)
|
|
105
|
+
_LIVE_FDS[snapshot_id] = pty_fd
|
|
106
|
+
return captured
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def restore(snapshot_id: str = DEFAULT_SNAPSHOT_ID) -> ReplayState:
|
|
110
|
+
"""Load a validated snapshot and compare it with its live PTY."""
|
|
111
|
+
path = _location(snapshot_id)
|
|
112
|
+
try:
|
|
113
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
114
|
+
except (json.JSONDecodeError, UnicodeError) as error:
|
|
115
|
+
raise ValueError("invalid snapshot document") from error
|
|
116
|
+
if not isinstance(payload, dict) or set(payload) != {
|
|
117
|
+
"schema", "snapshot_id", "rows", "cols", "termios_attributes", "output"
|
|
118
|
+
} or type(payload["schema"]) is not int or payload["schema"] != _SCHEMA or payload["snapshot_id"] != snapshot_id or any(
|
|
119
|
+
type(payload[field]) is not int or not 0 <= payload[field] <= 65535 for field in ("rows", "cols")
|
|
120
|
+
) or not isinstance(payload["output"], str):
|
|
121
|
+
raise ValueError("snapshot schema or id mismatch")
|
|
122
|
+
attrs = _deserialize_attrs(payload["termios_attributes"])
|
|
123
|
+
saved = Snapshot(snapshot_id, payload["rows"], payload["cols"], attrs, payload["output"])
|
|
124
|
+
if snapshot_id not in _LIVE_FDS:
|
|
125
|
+
raise RuntimeError("no live PTY registered for snapshot")
|
|
126
|
+
fd = _LIVE_FDS[snapshot_id]
|
|
127
|
+
live_rows, live_cols = _size(fd)
|
|
128
|
+
live_attrs = termios.tcgetattr(fd)
|
|
129
|
+
return ReplayState(
|
|
130
|
+
saved, live_rows, live_cols, live_attrs,
|
|
131
|
+
(live_rows, live_cols, live_attrs) == (saved.rows, saved.cols, saved.termios_attributes),
|
|
132
|
+
)
|
|
@@ -15,7 +15,7 @@ import { encodeSgrMouse, mouseModeOffReason, type PtyMouseInput } from './pty-mo
|
|
|
15
15
|
import { startPtyRecording, stopPtyRecording } from './pty-recording.js';
|
|
16
16
|
import { withExternalKeyCommand } from '../input/external-input-queue.js';
|
|
17
17
|
|
|
18
|
-
const OWNER_PTY_CONTROL_ACTIONS = ['takeover', 'release', 'input-text', 'input-key', 'input-mouse', 'resize', 'snapshot', 'rename', 'terminate', 'capabilities', 'record-start', 'record-stop'] as const;
|
|
18
|
+
const OWNER_PTY_CONTROL_ACTIONS = ['takeover', 'release', 'input-text', 'input-key', 'input-mouse', 'resize', 'snapshot', 'rename', 'terminate', 'stop-turn', 'capabilities', 'record-start', 'record-stop'] as const;
|
|
19
19
|
export type PtyControlAction = typeof OWNER_PTY_CONTROL_ACTIONS[number];
|
|
20
20
|
type PtyControlStatus = 'success' | 'unknown-pty' | 'denied' | 'failed' | 'write-failed' | 'owner-unreachable';
|
|
21
21
|
|
|
@@ -42,7 +42,8 @@ export type PtyControlPayload =
|
|
|
42
42
|
| { readonly cols: number; readonly rows: number }
|
|
43
43
|
| { readonly ansi: boolean }
|
|
44
44
|
| { readonly nickname: string }
|
|
45
|
-
| { readonly cols: number; readonly rows: number; readonly title?: string }
|
|
45
|
+
| { readonly cols: number; readonly rows: number; readonly title?: string }
|
|
46
|
+
| { readonly force: true; readonly actorIdentity: string; readonly reason: string };
|
|
46
47
|
|
|
47
48
|
export interface PtyControlRequestOptions {
|
|
48
49
|
/** 요청자가 주장하는 쓰기 주체. `'agent'` 는 run-identity 일치를 요구한다(`resolveRemoteControlActor`). */
|
|
@@ -609,6 +610,19 @@ async function processPtyControlRequestsOnce(getHandle: (id: string) => PtyContr
|
|
|
609
610
|
else if (!isOwnerPtyControlAction(row.action)) result = { status: 'denied', reason: 'unsupported-action' };
|
|
610
611
|
else if (row.action === 'capabilities') result = { status: 'success', actions: OWNER_PTY_CONTROL_ACTIONS };
|
|
611
612
|
else if (row.action === 'terminate') result = await terminatePty(handle);
|
|
613
|
+
else if (row.action === 'stop-turn') {
|
|
614
|
+
const payload = parsePayload(row);
|
|
615
|
+
const targetRunId = getPtyManifest(row.pty_id)?.runId?.trim() ?? '';
|
|
616
|
+
const requesterRunId = row.requester_run_id?.trim() ?? '';
|
|
617
|
+
if (requested === null) result = { status: 'denied', reason: 'invalid-actor' };
|
|
618
|
+
else if (payload === null || typeof payload !== 'object' || Array.isArray(payload) || !('force' in payload) || payload.force !== true) result = { status: 'denied', reason: 'force-required' };
|
|
619
|
+
else if (!('actorIdentity' in payload) || typeof payload.actorIdentity !== 'string' || !payload.actorIdentity.trim()) result = { status: 'denied', reason: 'actor-identity-required' };
|
|
620
|
+
else if (!('reason' in payload) || typeof payload.reason !== 'string' || !payload.reason.trim()) result = { status: 'denied', reason: 'reason-required' };
|
|
621
|
+
else if (!requesterRunId || !targetRunId) result = { status: 'denied', reason: 'run-identity-unavailable' };
|
|
622
|
+
else if (requesterRunId === targetRunId) result = { status: 'denied', reason: 'self-turn-refused' };
|
|
623
|
+
else if (!handle.stopTurn) result = { status: 'denied', reason: 'force-stop-unsupported' };
|
|
624
|
+
else result = handle.stopTurn(true) ? { status: 'success' } : { status: 'denied', reason: 'no-active-turn' };
|
|
625
|
+
}
|
|
612
626
|
else if (row.action === 'record-start' || row.action === 'record-stop') {
|
|
613
627
|
if (requested === null) result = { status: 'denied', reason: 'invalid-actor' };
|
|
614
628
|
else if (row.action === 'record-stop') {
|
|
@@ -733,6 +747,19 @@ async function processPtyControlRequestsOnce(getHandle: (id: string) => PtyContr
|
|
|
733
747
|
result = { status: 'failed', reason: 'control-processing-error' };
|
|
734
748
|
debug.log('pty.takeover', 'control-processing-error', { id: row.pty_id, action: row.action, actor: requested ?? row.actor, error: (error as Error).message });
|
|
735
749
|
}
|
|
750
|
+
if (row.action === 'stop-turn') {
|
|
751
|
+
const payload = parsePayload(row);
|
|
752
|
+
debug.log('pty.turn', 'force-stop-settled', {
|
|
753
|
+
ptyId: row.pty_id,
|
|
754
|
+
actor: requested ?? row.actor ?? 'unknown',
|
|
755
|
+
actorIdentity: payload && 'actorIdentity' in payload && typeof payload.actorIdentity === 'string' ? payload.actorIdentity.trim() || null : null,
|
|
756
|
+
reason: payload && 'reason' in payload && typeof payload.reason === 'string' ? payload.reason.trim() || null : null,
|
|
757
|
+
requesterRunId: row.requester_run_id?.trim() || null,
|
|
758
|
+
targetRunId: getPtyManifest(row.pty_id)?.runId?.trim() || null,
|
|
759
|
+
outcome: result.status,
|
|
760
|
+
refusal: result.reason ?? null,
|
|
761
|
+
});
|
|
762
|
+
}
|
|
736
763
|
d.run("UPDATE pty_control_requests SET status=?, result_json=?, updated_at=? WHERE request_id=? AND status='processing'", [result.status, JSON.stringify(result), Date.now(), row.request_id]);
|
|
737
764
|
debug.log('pty.arbiter', 'control-settled', { id: row.pty_id, action: row.action, actor: requested ?? row.actor, outcome: result.status, reason: result.reason });
|
|
738
765
|
}
|
|
@@ -104,6 +104,10 @@ export interface PtyManifestRow {
|
|
|
104
104
|
/** TUI 턴 상태 — TUI 가 턴 시작·끝에 스스로 적는다(화면 글자 추정 아님). 없으면 기록 안 하는 행/옛 판. */
|
|
105
105
|
turnState?: PtyTurnState;
|
|
106
106
|
turnAt?: number;
|
|
107
|
+
/** 마지막 진전 시각(epoch ms) — 스트림 텍스트·도구 시작/끝·상태 줄에서 갱신(SURVIVAL-PROGRESS-CLOCK). */
|
|
108
|
+
progressAt?: number;
|
|
109
|
+
/** Esc 로 턴 중단을 청한 시각(epoch ms) — 이후 busy 가 지속되면 abort-ignored 판정 재료. */
|
|
110
|
+
abortRequestedAt?: number;
|
|
107
111
|
/** 행 소유 프로세스가 «기동 때» 실은 코드 판 — 트리 HEAD(`codeSha`)와 다른 축이다. */
|
|
108
112
|
build?: PtyBuildIdentity;
|
|
109
113
|
}
|
|
@@ -128,6 +132,7 @@ let _dbFailed = false;
|
|
|
128
132
|
let _dbPathForTesting: string | null = null;
|
|
129
133
|
const _lastSnapshotAt = new Map<string, number>();
|
|
130
134
|
const _lastFrameAt = new Map<string, number>();
|
|
135
|
+
const _lastProgressAt = new Map<string, number>();
|
|
131
136
|
|
|
132
137
|
export function setPtyManifestDbPathForTesting(path: string | null): void {
|
|
133
138
|
_db?.close();
|
|
@@ -136,6 +141,7 @@ export function setPtyManifestDbPathForTesting(path: string | null): void {
|
|
|
136
141
|
_dbPathForTesting = path;
|
|
137
142
|
_lastSnapshotAt.clear();
|
|
138
143
|
_lastFrameAt.clear();
|
|
144
|
+
_lastProgressAt.clear();
|
|
139
145
|
}
|
|
140
146
|
|
|
141
147
|
function db(): Database | null {
|
|
@@ -172,6 +178,11 @@ function db(): Database | null {
|
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
export function migratePtyManifestSchema(d: Database): void {
|
|
181
|
+
// 이행 문장 전체를 한 트랜잭션에 묶는다 — 문장별 autocommit fsync(첫 열기 ~35회)를 없애
|
|
182
|
+
// 매니페스트 DB 를 처음 여는 비용을 크게 줄인다. 이미 트랜잭션 안이면 그대로 진행한다.
|
|
183
|
+
let ownsTxn = false;
|
|
184
|
+
try { d.run('BEGIN'); ownsTxn = true; } catch { /* caller transaction */ }
|
|
185
|
+
try {
|
|
175
186
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN nickname TEXT'); } catch { /* already exists */ }
|
|
176
187
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN purpose TEXT'); } catch { /* already exists */ }
|
|
177
188
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN seat TEXT'); } catch { /* already exists */ }
|
|
@@ -201,12 +212,19 @@ export function migratePtyManifestSchema(d: Database): void {
|
|
|
201
212
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN last_control_at INTEGER'); } catch { /* already exists */ }
|
|
202
213
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN turn_state TEXT'); } catch { /* already exists */ }
|
|
203
214
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN turn_at INTEGER'); } catch { /* already exists */ }
|
|
215
|
+
try { d.run('ALTER TABLE pty_manifest ADD COLUMN progress_at INTEGER'); } catch { /* already exists */ }
|
|
216
|
+
try { d.run('ALTER TABLE pty_manifest ADD COLUMN abort_requested_at INTEGER'); } catch { /* already exists */ }
|
|
204
217
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN build_version TEXT'); } catch { /* already exists */ }
|
|
205
218
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN build_sha TEXT'); } catch { /* already exists */ }
|
|
206
219
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN build_source TEXT'); } catch { /* already exists */ }
|
|
207
220
|
try { d.run('ALTER TABLE pty_manifest ADD COLUMN build_code_root TEXT'); } catch { /* already exists */ }
|
|
208
221
|
try { d.run('ALTER TABLE pty_manifest DROP COLUMN chain_depth'); } catch { /* legacy schema has no duplicate column */ }
|
|
209
222
|
try { d.run('UPDATE pty_manifest SET closed_at=updated_at WHERE alive=0 AND closed_at=0'); } catch { /* fail-soft */ }
|
|
223
|
+
} finally {
|
|
224
|
+
if (ownsTxn) {
|
|
225
|
+
try { d.run('COMMIT'); } catch { try { d.run('ROLLBACK'); } catch { /* fail-soft */ } }
|
|
226
|
+
}
|
|
227
|
+
}
|
|
210
228
|
}
|
|
211
229
|
|
|
212
230
|
function codeShaForWorkdir(workdir: string | undefined): string {
|
|
@@ -290,6 +308,7 @@ export function upsertPtyManifest(row: {
|
|
|
290
308
|
// 행을 (다시) 세우면 snapshot·frame 칸이 비워진다 — 같은 프로세스의 쓰기 스로틀도 비워 다음 쓰기가 바로 닿게 한다.
|
|
291
309
|
_lastSnapshotAt.delete(row.id);
|
|
292
310
|
_lastFrameAt.delete(row.id);
|
|
311
|
+
_lastProgressAt.delete(row.id);
|
|
293
312
|
const d = db(); if (!d) return;
|
|
294
313
|
const runId = getHarnessRunId(process.env);
|
|
295
314
|
const runIdSource = getHarnessRunIdSource();
|
|
@@ -343,7 +362,7 @@ export function upsertPtyManifest(row: {
|
|
|
343
362
|
terminal_origin_reason=excluded.terminal_origin_reason, external_tool_name=excluded.external_tool_name,
|
|
344
363
|
started_at=excluded.started_at, alive=1, exit_code=NULL,
|
|
345
364
|
snapshot='', snapshot_at=0, frame='', frame_at=0, closed_at=0, updated_at=excluded.updated_at,
|
|
346
|
-
turn_state=NULL, turn_at=NULL, build_version=NULL, build_sha=NULL, build_source=NULL, build_code_root=NULL`,
|
|
365
|
+
turn_state=NULL, turn_at=NULL, progress_at=NULL, abort_requested_at=NULL, build_version=NULL, build_sha=NULL, build_source=NULL, build_code_root=NULL`,
|
|
347
366
|
values,
|
|
348
367
|
);
|
|
349
368
|
d.run('COMMIT');
|
|
@@ -434,11 +453,46 @@ export function updatePtyManifestSession(id: string, sessionId: string, now: num
|
|
|
434
453
|
}
|
|
435
454
|
}
|
|
436
455
|
|
|
437
|
-
/** 턴 상태 기록 — 행이 없거나 db 를 못 열면 false(호출자가 관측을 남긴다). */
|
|
456
|
+
/** 턴 상태 기록 — 행이 없거나 db 를 못 열면 false(호출자가 관측을 남긴다). 새 busy 턴은 이전 Esc 청구를 비운다. */
|
|
438
457
|
export function updatePtyManifestTurn(id: string, turn: PtyTurnState, at: number): boolean {
|
|
439
458
|
try {
|
|
440
459
|
const d = db(); if (!d) return false;
|
|
441
|
-
|
|
460
|
+
const result = turn === 'busy'
|
|
461
|
+
? d.run('UPDATE pty_manifest SET turn_state=?, turn_at=?, progress_at=?, abort_requested_at=NULL WHERE id=?', [turn, at, at, id])
|
|
462
|
+
: d.run('UPDATE pty_manifest SET turn_state=?, turn_at=? WHERE id=?', [turn, at, id]);
|
|
463
|
+
if ((result.changes ?? 0) > 0 && turn === 'busy') _lastProgressAt.set(id, at);
|
|
464
|
+
return (result.changes ?? 0) > 0;
|
|
465
|
+
} catch {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/** 진전 기록 스로틀 — 같은 행은 이만큼 안에 다시 쓰지 않는다. */
|
|
471
|
+
export const PTY_MANIFEST_PROGRESS_THROTTLE_MS = 5_000;
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* 마지막 진전 시각 기록(SURVIVAL-PROGRESS-CLOCK). 같은 행을 5초 안에 다시 쓰면 생략하지만
|
|
475
|
+
* «실패가 아니다» — true 를 돌려 호출자의 실패 관측을 일으키지 않는다. 실패(0행·db 오류)만 false.
|
|
476
|
+
*/
|
|
477
|
+
export function updatePtyManifestProgress(id: string, at: number): boolean {
|
|
478
|
+
try {
|
|
479
|
+
const last = _lastProgressAt.get(id);
|
|
480
|
+
if (last !== undefined && at - last < PTY_MANIFEST_PROGRESS_THROTTLE_MS) return true;
|
|
481
|
+
const d = db(); if (!d) return false;
|
|
482
|
+
const result = d.run('UPDATE pty_manifest SET progress_at=?, updated_at=? WHERE id=?', [at, at, id]);
|
|
483
|
+
const ok = (result.changes ?? 0) > 0;
|
|
484
|
+
if (ok) _lastProgressAt.set(id, at);
|
|
485
|
+
return ok;
|
|
486
|
+
} catch {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** Esc 로 턴 중단을 청한 시각 기록 — busy 턴이 이 뒤로 계속되면 abort-ignored 판정 재료가 된다. */
|
|
492
|
+
export function updatePtyManifestAbortRequested(id: string, at: number): boolean {
|
|
493
|
+
try {
|
|
494
|
+
const d = db(); if (!d) return false;
|
|
495
|
+
return (d.run('UPDATE pty_manifest SET abort_requested_at=?, updated_at=? WHERE id=?', [at, at, id]).changes ?? 0) > 0;
|
|
442
496
|
} catch {
|
|
443
497
|
return false;
|
|
444
498
|
}
|
|
@@ -903,6 +957,8 @@ function mapRow(r: Record<string, unknown>): PtyManifestRow {
|
|
|
903
957
|
closedAt: Number(r.closed_at ?? 0),
|
|
904
958
|
codeSha: String(r.code_sha ?? ''),
|
|
905
959
|
...(r.turn_state === 'busy' || r.turn_state === 'idle' ? { turnState: r.turn_state, turnAt: Number(r.turn_at ?? 0) } : {}),
|
|
960
|
+
...(r.progress_at === null || r.progress_at === undefined ? {} : { progressAt: Number(r.progress_at) }),
|
|
961
|
+
...(r.abort_requested_at === null || r.abort_requested_at === undefined ? {} : { abortRequestedAt: Number(r.abort_requested_at) }),
|
|
906
962
|
...(typeof r.build_sha === 'string' ? { build: mapBuild(r) } : {}),
|
|
907
963
|
updatedAt: Number(r.updated_at),
|
|
908
964
|
};
|
|
@@ -180,6 +180,8 @@ export interface PtyControlTarget {
|
|
|
180
180
|
isAlive(): boolean;
|
|
181
181
|
/** Registry-backed PTY targets expose termination; non-PTY control targets omit it. */
|
|
182
182
|
kill?(signal?: NodeJS.Signals): void;
|
|
183
|
+
/** TUI owners may expose an explicit, forceful cancellation of the active turn. */
|
|
184
|
+
stopTurn?(force: true): boolean;
|
|
183
185
|
canWrite(actor?: PtyWriteActor): boolean;
|
|
184
186
|
write(chars: string, actor?: PtyWriteActor): void;
|
|
185
187
|
resize(cols: number, rows: number): void;
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
versionedDashboardInstallDir,
|
|
28
28
|
} from './stale-install-check.js';
|
|
29
29
|
import {
|
|
30
|
-
updatePtyManifestBuild, updatePtyManifestTurn,
|
|
30
|
+
updatePtyManifestAbortRequested, updatePtyManifestBuild, updatePtyManifestProgress, updatePtyManifestTurn,
|
|
31
31
|
type PtyBuildIdentity, type PtyManifestRow, type PtyTurnState,
|
|
32
32
|
} from './pty-manifest.js';
|
|
33
33
|
|
|
@@ -231,6 +231,10 @@ export type PtyTurnView = PtyTurnState | 'unknown';
|
|
|
231
231
|
export interface PtyRunStateView {
|
|
232
232
|
readonly turn: PtyTurnView;
|
|
233
233
|
readonly turnAt?: number;
|
|
234
|
+
/** 마지막 진전 시각(SURVIVAL-PROGRESS-CLOCK) — 기록 없는 행·옛 판은 undefined. */
|
|
235
|
+
readonly progressAt?: number;
|
|
236
|
+
/** Esc 로 턴 중단을 청한 시각 — 이 뒤로 busy 가 지속되면 abort-ignored 판정 재료. */
|
|
237
|
+
readonly abortRequestedAt?: number;
|
|
234
238
|
readonly build: PtyBuildIdentity | null;
|
|
235
239
|
readonly installed: string | null;
|
|
236
240
|
readonly stale: boolean | null;
|
|
@@ -244,7 +248,7 @@ export interface DescribeRunStateDeps {
|
|
|
244
248
|
|
|
245
249
|
/** manifest 행 하나의 턴 ⊕ 판 ⊕ stale. 행이 없거나 죽었으면 턴은 unknown. */
|
|
246
250
|
export function describePtyRunState(
|
|
247
|
-
row: Pick<PtyManifestRow, 'alive' | 'startedAt' | 'kind' | 'turnState' | 'turnAt' | 'build'> | null,
|
|
251
|
+
row: Pick<PtyManifestRow, 'alive' | 'startedAt' | 'kind' | 'turnState' | 'turnAt' | 'progressAt' | 'abortRequestedAt' | 'build'> | null,
|
|
248
252
|
deps: DescribeRunStateDeps = {},
|
|
249
253
|
): PtyRunStateView {
|
|
250
254
|
let installed: InstalledRecord = {};
|
|
@@ -265,6 +269,8 @@ export function describePtyRunState(
|
|
|
265
269
|
const turnView = ptyTurnViewOfRow(row);
|
|
266
270
|
return {
|
|
267
271
|
...turnView,
|
|
272
|
+
...(row?.alive && row.progressAt !== undefined ? { progressAt: row.progressAt } : {}),
|
|
273
|
+
...(row?.alive && row.abortRequestedAt !== undefined ? { abortRequestedAt: row.abortRequestedAt } : {}),
|
|
268
274
|
build: build ?? null,
|
|
269
275
|
installed: installed.sha ?? null,
|
|
270
276
|
stale: staleness.stale,
|
|
@@ -446,6 +452,50 @@ export const spawnTuiRelaunch = (sessionId: string): Promise<void> => {
|
|
|
446
452
|
});
|
|
447
453
|
};
|
|
448
454
|
|
|
455
|
+
// ── SURVIVAL-PROGRESS-CLOCK — «마지막 진전 시각»로 느림·정체·Esc 무시를 가른다 ──
|
|
456
|
+
//
|
|
457
|
+
// `turnAt` 은 턴 값이 «바뀔 때만» 적히므로 busy 경과만으로는 «일하는 중»인지 «죽었다»인지를 못 가른다.
|
|
458
|
+
// 진전 신호(스트림 텍스트·도구 시작/끝·상태 줄)가 `progress_at` 를 계속 올리면 긴 턴도 «느리지만 가는 중»이
|
|
459
|
+
// 되고, 진전이 끊기면 «정체», Esc 청구 뒤에도 busy 가 지속되면 «Esc 무시»로 판정한다.
|
|
460
|
+
|
|
461
|
+
export const DEFAULT_TURN_STALL_MS = 12 * 60 * 1000;
|
|
462
|
+
export const DEFAULT_SLOW_TURN_MS = 20 * 60 * 1000;
|
|
463
|
+
export const DEFAULT_ABORT_IGNORE_MS = 30 * 1000;
|
|
464
|
+
|
|
465
|
+
export type TurnProgressJudgment = 'progressing' | 'slow' | 'stalled' | 'abort-ignored' | 'unknown';
|
|
466
|
+
|
|
467
|
+
export interface TurnProgressInput {
|
|
468
|
+
readonly turn: PtyTurnView;
|
|
469
|
+
readonly turnAt?: number;
|
|
470
|
+
readonly progressAt?: number;
|
|
471
|
+
readonly abortRequestedAt?: number;
|
|
472
|
+
readonly now: number;
|
|
473
|
+
/** 정체 임계 — 진전이 이만큼 끊기면 stalled. 기본 12분. */
|
|
474
|
+
readonly stallMs?: number;
|
|
475
|
+
/** 느린 턴 임계 — 턴 경과가 이만큼이면 slow. 기본 20분. */
|
|
476
|
+
readonly slowTurnMs?: number;
|
|
477
|
+
/** Esc 무시 임계 — 청구 뒤 이만큼 busy 면 abort-ignored. 기본 30초. */
|
|
478
|
+
readonly abortIgnoreMs?: number;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/** 순수 판정: busy 턴의 진전·정체·Esc 무시를 임계로 가른다. 재료가 없으면 unknown(«괜찮다»가 아니다). */
|
|
482
|
+
export function judgeTurnProgress(input: TurnProgressInput): TurnProgressJudgment {
|
|
483
|
+
const { turn, turnAt, progressAt, abortRequestedAt, now } = input;
|
|
484
|
+
if (turn !== 'busy') return 'unknown';
|
|
485
|
+
if (!Number.isFinite(now)) return 'unknown';
|
|
486
|
+
// Esc 청구 뒤에도 busy 가 지속되면 무시 — 정체보다 구체적이므로 먼저 가른다.
|
|
487
|
+
if (abortRequestedAt !== undefined && Number.isFinite(abortRequestedAt)) {
|
|
488
|
+
if (now - abortRequestedAt >= (input.abortIgnoreMs ?? DEFAULT_ABORT_IGNORE_MS)) return 'abort-ignored';
|
|
489
|
+
}
|
|
490
|
+
// 진전 시각이 없으면 턴 시작(turnAt)이 진전의 0초다.
|
|
491
|
+
const since = progressAt !== undefined && Number.isFinite(progressAt) ? progressAt : turnAt;
|
|
492
|
+
if (since === undefined || !Number.isFinite(since)) return 'unknown';
|
|
493
|
+
const elapsed = Math.max(0, now - since);
|
|
494
|
+
if (elapsed >= (input.stallMs ?? DEFAULT_TURN_STALL_MS)) return 'stalled';
|
|
495
|
+
if (turnAt !== undefined && Number.isFinite(turnAt) && now - turnAt >= (input.slowTurnMs ?? DEFAULT_SLOW_TURN_MS)) return 'slow';
|
|
496
|
+
return 'progressing';
|
|
497
|
+
}
|
|
498
|
+
|
|
449
499
|
// ── 기록(TUI) ──
|
|
450
500
|
|
|
451
501
|
export interface TuiRunStateRecorderDeps {
|
|
@@ -453,6 +503,10 @@ export interface TuiRunStateRecorderDeps {
|
|
|
453
503
|
readonly build?: () => PtyBuildIdentity;
|
|
454
504
|
readonly writeBuild?: (id: string, build: PtyBuildIdentity) => boolean;
|
|
455
505
|
readonly writeTurn?: (id: string, turn: PtyTurnState, at: number) => boolean;
|
|
506
|
+
/** 진전 시각 기록 — 생략하면 `updatePtyManifestProgress`(같은 행 5초 스로틀). */
|
|
507
|
+
readonly writeProgress?: (id: string, at: number) => boolean;
|
|
508
|
+
/** Esc 청구 시각 기록 — 생략하면 `updatePtyManifestAbortRequested`. */
|
|
509
|
+
readonly writeAbortRequested?: (id: string, at: number) => boolean;
|
|
456
510
|
readonly log?: (event: string, data: Record<string, unknown>) => void;
|
|
457
511
|
/**
|
|
458
512
|
* herdr pane 신고기. 생략 시: `writeTurn` 을 주입하지 않은 기본 녹음기만
|
|
@@ -476,6 +530,8 @@ interface ActiveRecorder {
|
|
|
476
530
|
readonly surfaceId: string;
|
|
477
531
|
readonly now: () => number;
|
|
478
532
|
readonly writeTurn: (id: string, turn: PtyTurnState, at: number) => boolean;
|
|
533
|
+
readonly writeProgress: (id: string, at: number) => boolean;
|
|
534
|
+
readonly writeAbortRequested: (id: string, at: number) => boolean;
|
|
479
535
|
readonly log: (event: string, data: Record<string, unknown>) => void;
|
|
480
536
|
readonly herdr: HerdrAgentReporterLike | null;
|
|
481
537
|
/** manifest 에 실제로 적힌 마지막 턴. 실패면 안 바뀐다(재시도). */
|
|
@@ -495,6 +551,8 @@ export function startTuiRunStateRecorder(surfaceId: string, deps: TuiRunStateRec
|
|
|
495
551
|
const now = deps.now ?? Date.now;
|
|
496
552
|
const log = deps.log ?? defaultLog;
|
|
497
553
|
const writeTurn = deps.writeTurn ?? updatePtyManifestTurn;
|
|
554
|
+
const writeProgress = deps.writeProgress ?? updatePtyManifestProgress;
|
|
555
|
+
const writeAbortRequested = deps.writeAbortRequested ?? updatePtyManifestAbortRequested;
|
|
498
556
|
// 기본 신고기는 기본 manifest 쓰기와 짝일 때만. writeTurn 주입(시험)은 herdr 를 안 만든다.
|
|
499
557
|
const herdr = deps.herdr !== undefined
|
|
500
558
|
? deps.herdr
|
|
@@ -508,7 +566,7 @@ export function startTuiRunStateRecorder(surfaceId: string, deps: TuiRunStateRec
|
|
|
508
566
|
log(ok ? 'build-recorded' : 'build-write-failed', { ptyId: surfaceId, sha: build.sha, version: build.version, source: build.source });
|
|
509
567
|
}
|
|
510
568
|
// 기동 순서: 판 → manifest 초기 idle → herdr 신고. herdr start 가 idle 을 신고하므로 초기 idle 을 turn 으로 다시 안 보낸다.
|
|
511
|
-
const recorder: ActiveRecorder = { surfaceId, now, writeTurn, log, herdr, herdrLast: herdr ? 'idle' : undefined };
|
|
569
|
+
const recorder: ActiveRecorder = { surfaceId, now, writeTurn, writeProgress, writeAbortRequested, log, herdr, herdrLast: herdr ? 'idle' : undefined };
|
|
512
570
|
active = recorder;
|
|
513
571
|
writeTurnState(recorder, 'idle');
|
|
514
572
|
if (herdr) { try { herdr.start(); } catch { /* 신고 실패가 녹음기를 깨지 않는다 */ } }
|
|
@@ -614,6 +672,25 @@ export function reportTuiTurn(turn: PtyTurnState): void {
|
|
|
614
672
|
writeTurnState(active, turn);
|
|
615
673
|
}
|
|
616
674
|
|
|
675
|
+
/** 진전 신호(스트림 텍스트·도구 시작/끝·상태 줄)에서 부른다 — 마지막 진전 시각을 올린다. 녹음기가 없으면 아무것도 안 한다. */
|
|
676
|
+
export function reportTuiProgress(): void {
|
|
677
|
+
if (!active) return;
|
|
678
|
+
const at = active.now();
|
|
679
|
+
let ok = false;
|
|
680
|
+
try { ok = active.writeProgress(active.surfaceId, at); } catch { ok = false; }
|
|
681
|
+
// 실패(0행·예외)는 관측으로만 남긴다 — 진전 기록이 턴을 막지 않는다. 스로틀 생략(false 아님 실패만)은 조용히 지나간다.
|
|
682
|
+
if (!ok) active.log('progress-write-failed', { ptyId: active.surfaceId, at });
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/** Esc 게이트가 턴 중단을 청할 때 부른다 — 청구 시각을 남긴다(busy 가 지속되면 abort-ignored 판정 재료). */
|
|
686
|
+
export function reportTuiAbortRequested(): void {
|
|
687
|
+
if (!active) return;
|
|
688
|
+
const at = active.now();
|
|
689
|
+
let ok = false;
|
|
690
|
+
try { ok = active.writeAbortRequested(active.surfaceId, at); } catch { ok = false; }
|
|
691
|
+
if (!ok) active.log('abort-requested-write-failed', { ptyId: active.surfaceId, at });
|
|
692
|
+
}
|
|
693
|
+
|
|
617
694
|
function writeTurnState(recorder: ActiveRecorder, turn: PtyTurnState): void {
|
|
618
695
|
const at = recorder.now();
|
|
619
696
|
let ok = false;
|
|
@@ -11,11 +11,13 @@ interface GateHostClaim {
|
|
|
11
11
|
hosts: string[];
|
|
12
12
|
pid: number;
|
|
13
13
|
pidStartedAt: number | null;
|
|
14
|
+
/** Wall-clock claim time. Claims written before this field existed stay readable (optional on read). */
|
|
15
|
+
reservedAt?: number;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export type GateHostReservation =
|
|
17
19
|
| { status: 'free' }
|
|
18
|
-
| { status: 'reserved' | 'unknown'; reason: string; runId?: string };
|
|
20
|
+
| { status: 'reserved' | 'unknown'; reason: string; runId?: string; reservedAt?: number };
|
|
19
21
|
|
|
20
22
|
const hostName = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
21
23
|
const claimsDir = (root: string) => join(root, 'release', 'gate-host-reservations');
|
|
@@ -44,7 +46,7 @@ export function reserveReleaseGateHosts(root: string, runId: string, hosts: read
|
|
|
44
46
|
const token = randomUUID();
|
|
45
47
|
const pidStartedAt = psProcessStartMs(process.pid);
|
|
46
48
|
if (pidStartedAt === null) throw new Error('release gate owner start time unmeasured');
|
|
47
|
-
const claim: GateHostClaim = { token, runId, hosts: unique, pid: process.pid, pidStartedAt };
|
|
49
|
+
const claim: GateHostClaim = { token, runId, hosts: unique, pid: process.pid, pidStartedAt, reservedAt: Date.now() };
|
|
48
50
|
const path = join(dir, `${token}.json`);
|
|
49
51
|
const temp = join(dir, `.${token}.tmp`);
|
|
50
52
|
try {
|
|
@@ -82,7 +84,9 @@ export function inspectReleaseGateHost(root: string, host: string): GateHostRese
|
|
|
82
84
|
|| !Number.isSafeInteger(claim.pid) || claim.pid <= 0 || typeof claim.token !== 'string'
|
|
83
85
|
|| typeof claim.runId !== 'string' || !claim.runId
|
|
84
86
|
|| (claim.pidStartedAt !== null && (!Number.isSafeInteger(claim.pidStartedAt)
|
|
85
|
-
|| claim.pidStartedAt <= 0 || claim.pidStartedAt > Date.now()))
|
|
87
|
+
|| claim.pidStartedAt <= 0 || claim.pidStartedAt > Date.now()))
|
|
88
|
+
|| (claim.reservedAt !== undefined && (!Number.isSafeInteger(claim.reservedAt)
|
|
89
|
+
|| claim.reservedAt <= 0 || claim.reservedAt > Date.now()))) throw new Error('invalid claim');
|
|
86
90
|
} catch (error) { return { status: 'unknown', reason: `reservation unreadable: ${name}: ${String(error)}` }; }
|
|
87
91
|
const live = claimAlive(claim);
|
|
88
92
|
if (live === 'dead') {
|
|
@@ -91,7 +95,12 @@ export function inspectReleaseGateHost(root: string, host: string): GateHostRese
|
|
|
91
95
|
continue;
|
|
92
96
|
}
|
|
93
97
|
if (!claim.hosts.includes(host) && !claim.hosts.includes('*')) continue;
|
|
94
|
-
return {
|
|
98
|
+
return {
|
|
99
|
+
status: live === 'unknown' ? 'unknown' : 'reserved',
|
|
100
|
+
reason: `release gate ${claim.runId} holds ${host}`,
|
|
101
|
+
runId: claim.runId,
|
|
102
|
+
...(claim.reservedAt !== undefined ? { reservedAt: claim.reservedAt } : {}),
|
|
103
|
+
};
|
|
95
104
|
}
|
|
96
105
|
return { status: 'free' };
|
|
97
106
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// One append-only observation per gate shard transition. The live board is a projection, not evidence for reuse.
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { releaseLedgerRoot } from '../instance/resolve.js';
|
|
5
|
+
|
|
6
|
+
export interface GateShardLedgerRow {
|
|
7
|
+
v: 1;
|
|
8
|
+
version: string;
|
|
9
|
+
phase: 'cut' | 'baseline';
|
|
10
|
+
shardId: string;
|
|
11
|
+
files: string[];
|
|
12
|
+
host: string | null;
|
|
13
|
+
executor: 'pod' | 'host';
|
|
14
|
+
imageDigest: string | null;
|
|
15
|
+
commit: string;
|
|
16
|
+
envFingerprint: string;
|
|
17
|
+
startedAt: string | null;
|
|
18
|
+
endedAt: string | null;
|
|
19
|
+
observedAt: string;
|
|
20
|
+
state: 'pending' | 'running' | 'done' | 'retry' | 'timeout' | 'failed';
|
|
21
|
+
rc: number | null;
|
|
22
|
+
pass: number | null;
|
|
23
|
+
fail: number | null;
|
|
24
|
+
errors: number | null;
|
|
25
|
+
ran: number | null;
|
|
26
|
+
failureIds: string[] | null;
|
|
27
|
+
errorIds: string[] | null;
|
|
28
|
+
attribution: 'complete' | 'unmeasured';
|
|
29
|
+
logPath: string | null;
|
|
30
|
+
junitPath: string | null;
|
|
31
|
+
stopReason: string | null;
|
|
32
|
+
attemptId: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function gateShardLedgerPath(version: string, root = releaseLedgerRoot()): string {
|
|
36
|
+
if (!/^\d+\.\d+\.\d+(?:[-.][A-Za-z0-9.-]+)?$/.test(version)) throw new Error('invalid release version');
|
|
37
|
+
return join(root, 'release', version, 'gate-logs', 'shard-ledger.jsonl');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Each newline is a complete event, so an observer can read while the gate is running. */
|
|
41
|
+
export function appendGateShardLedger(path: string, row: GateShardLedgerRow): void {
|
|
42
|
+
if (!/^[a-f0-9]{40}$/i.test(row.commit) || !/^[a-f0-9]{64}$/i.test(row.envFingerprint)) throw new Error('invalid shard ledger identity');
|
|
43
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(row.shardId) || row.files.some((file) => file.startsWith('/') || file.split('/').includes('..'))) throw new Error('invalid shard ledger path');
|
|
44
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
45
|
+
appendFileSync(path, `${JSON.stringify(row)}\n`, { mode: 0o600 });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function readGateShardLedger(path: string): { rows: GateShardLedgerRow[]; malformed: number } | null {
|
|
49
|
+
if (!existsSync(path)) return null;
|
|
50
|
+
const rows: GateShardLedgerRow[] = [];
|
|
51
|
+
let malformed = 0;
|
|
52
|
+
for (const line of readFileSync(path, 'utf8').split('\n')) {
|
|
53
|
+
if (!line.trim()) continue;
|
|
54
|
+
try {
|
|
55
|
+
const row = JSON.parse(line) as GateShardLedgerRow;
|
|
56
|
+
if (row.v !== 1 || typeof row.shardId !== 'string' || !Array.isArray(row.files) || typeof row.observedAt !== 'string') throw new Error('invalid row');
|
|
57
|
+
rows.push(row);
|
|
58
|
+
} catch { malformed++; }
|
|
59
|
+
}
|
|
60
|
+
return { rows, malformed };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** The newest event for each phase/shard. Preserve every attempt in the underlying ledger. */
|
|
64
|
+
export function latestGateShardLedger(rows: readonly GateShardLedgerRow[]): GateShardLedgerRow[] {
|
|
65
|
+
const latest = new Map<string, GateShardLedgerRow>();
|
|
66
|
+
for (const row of rows) latest.set(`${row.phase}:${row.shardId}`, row);
|
|
67
|
+
return [...latest.values()].sort((a, b) => a.phase.localeCompare(b.phase) || a.shardId.localeCompare(b.shardId, undefined, { numeric: true }));
|
|
68
|
+
}
|