elanous 0.2.27 → 0.2.29
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/{Ev2jivDMTSoEc-5rIXdcy → cIpv5nU9AycwYWZI9H589}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{ab4d57c2.e90bc2cb31949045.js → 058a98ba.7eb28d5e6dc03565.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4565-67e4c620597965c8.js → 1015-9cba22a5a4554797.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{1516.83dd2c1b86b4e507.js → 1142.65d002789ab3af7d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +34 -0
- package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1516.dfaceff3fd2d0e0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +286 -0
- package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1782-59db1b5aa06df38a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1743.563d3168e95825ef.js → 1852.7f7b53991fcb99ef.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +36 -0
- package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +64 -0
- package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{65ebff95.081daeff622d238e.js → 285adb1a.5654e605dddf86d2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +115 -0
- package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3160-95c96f4d2a21dd26.js +1 -0
- package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +90 -0
- package/apps/pwa/out/_next/static/chunks/328bb3ab-6628a1114fe3fb3b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9917-9e26abc5f7772735.js → 3396-97b97928c49190c9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6196.34d6b229079e9e28.js → 3403.7199205e65124486.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +1 -0
- package/apps/pwa/out/_next/static/chunks/419.736c0d6f426249a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6def8a8e.c81f9ca41028eccf.js → 425cfc4d.fb91158e3971c39f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{16e57f67.3ea19e893461e611.js → 46bd8bea.2f4b4099172fcdb7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5081.a240b63fad28663a.js → 4759.1f76713aefb87db5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +94 -0
- package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +62 -0
- package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +27 -0
- package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{9974.e77b4ff4884557b3.js → 5591.a35e7a217734a8b9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5492-e05e26a033ba80d2.js → 6013-2f769370d8b4c2c6.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +2 -0
- package/apps/pwa/out/_next/static/chunks/{5408.377c8c543635b81f.js → 6534.1ab00f370db7b105.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +148 -0
- package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +149 -0
- package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +79 -0
- package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8578.dff22d988cc2b106.js → 6767.1fcfc9b8be83975f.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/6776.06ff1e3b464cc607.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9311.24c8f5ea793253dd.js → 6853.cc5174a9dee59593.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +287 -0
- package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{94.4cfed21c0b781a06.js → 7375.050ea0d72968e49f.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +77 -0
- package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +74 -0
- package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7725-4f83d5541fbdb81b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8332.6f0f49df772e163b.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{7483.ba01c6c209b81bba.js → 8398.73a19b39715eda04.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2846.d6a433b8663819a5.js → 8471.8d2a8c74f09c36ff.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{5785-ea8d2c633b6688e3.js → 8767-2f6a634f5abeaa01.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +32 -0
- package/apps/pwa/out/_next/static/chunks/8795.32573a185af18c7b.js +41 -0
- package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4593.10f5b9bd702d4a6c.js → 9143.ff14585db1d275ff.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4204.a409ab6250c0f6a8.js → 9907.49be0fcadaf214b5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{973cbf1b.3bbcf2b41548eca7.js → a435ad95.577add051b4facb2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-a5635eba0d73b84e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/{page-ff27902d0b11ef4f.js → page-8aaa6dedc4c10dfb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-25a302273b054fd7.js → page-33bf667a5fb297bf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-29900ed0011b2c83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-87b88f551f421d8b.js → page-9eb56166774eb256.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9f92737b8766009a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f4dfbfc0.a69fb12f854882aa.js → bc324b7c.02a09dd93f6a399b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +1 -0
- package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +122 -0
- package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.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/implement-loop.yaml +38 -1
- package/graphs/release/release-loop.yaml +6 -2
- package/graphs/steward/recipes.yaml +6 -0
- package/graphs/steward/release-day.yaml +23 -0
- package/graphs/steward/steward.yaml +9 -1
- package/graphs/work/code-pr.yaml +23 -0
- package/package.json +1 -1
- package/plugins/agent-team/agents/research.md +1 -0
- package/scripts/browser-observe-cycle.ts +76 -2
- package/scripts/ci-typecheck-changed.ts +53 -19
- package/scripts/coord-channel-watch.sh +26 -6
- package/scripts/coord-role-pack.ts +143 -0
- package/scripts/detect-test-interference.ts +31 -1
- package/scripts/lib/morning-report-options.ts +41 -0
- package/scripts/pr-land-extra-remote-gates.ts +49 -0
- package/scripts/release-loop/docs-node.ts +51 -22
- package/scripts/release-loop/gate-batch-safe.ts +23 -0
- package/scripts/release-loop/gate-history.ts +422 -0
- package/scripts/release-loop/gate-node.ts +336 -39
- package/scripts/release-loop/gate-triage-node.ts +190 -0
- package/scripts/release-loop/node-verdict.ts +3 -1
- package/scripts/release-loop/publish-node.ts +3 -0
- package/scripts/release-loop/spawn-lane.ts +68 -0
- package/scripts/release-loop/tui-node-checks.ts +28 -2
- package/scripts/release-loop/version-node.ts +62 -4
- package/scripts/skills/public-check.ts +5 -2
- package/scripts/test-deterministic.ts +549 -37
- package/scripts/usage-rollup.ts +11 -3
- package/scripts/ux-sim.ts +7 -1
- package/scripts/verify-kpack6-live.ts +230 -0
- package/src/acp/codex-plugins.ts +17 -0
- package/src/acp/core-turn-bridge.ts +98 -22
- package/src/acp/elanous-extensions.ts +2 -0
- package/src/acp/server.ts +2 -0
- package/src/agent/ref-grounding.ts +18 -0
- package/src/agent/task-notification.ts +2 -1
- package/src/agent-mission/in-agent-plugin.ts +8 -3
- package/src/agent-substrate/pr-reviewer.ts +29 -21
- package/src/agent-substrate/self-review-cli.ts +34 -10
- package/src/briefing/brief-items.ts +151 -35
- package/src/budget/llm-cost.ts +25 -2
- package/src/budget/pty-usage-reemit.ts +7 -0
- package/src/budget/run-usage-rollup.ts +9 -0
- package/src/budget/usage-daily-store.ts +98 -0
- package/src/budget/usage-outcomes.ts +32 -0
- package/src/capture/tui-self-report.ts +22 -4
- package/src/chat/index.ts +31 -10
- package/src/chat/pickers/modal-runtime.ts +1 -0
- package/src/chat/pickers/modals.ts +3 -1
- package/src/chat/turn-typeahead.ts +123 -16
- package/src/claims/claims-ledger.ts +23 -0
- package/src/claims/claims-render.ts +22 -2
- package/src/cli/brief-cli.ts +131 -10
- package/src/cli/claims-cli.ts +24 -4
- package/src/cli/dashboard-name-flag.ts +48 -0
- package/src/cli/doctor-cli.ts +80 -0
- package/src/cli/log-event-names.ts +12 -0
- package/src/cli/msg-cli.ts +210 -11
- package/src/cli/plugin-cli.ts +11 -3
- package/src/cli/pr-cli.ts +443 -104
- package/src/cli/pr-land-heavy-remote.ts +233 -0
- package/src/cli/pr-land-overlap-evidence.ts +104 -5
- package/src/cli/pr-land-refusal.ts +20 -0
- package/src/cli/pty-takeover-cli.ts +125 -16
- package/src/cli/release-cli.ts +46 -2
- package/src/cli/remote-resolve.ts +2 -1
- package/src/cli/rfc-cli.ts +24 -0
- package/src/cli/seat-cli.ts +26 -16
- package/src/cli/tailscale-serve.ts +5 -8
- package/src/cli/tasks-cli.ts +400 -27
- package/src/cli/usage-cli.ts +155 -16
- package/src/cli/usage-daily-cli.ts +84 -0
- package/src/context-bus/context-now.ts +82 -5
- package/src/core-turn/auth-rejected-notice.ts +41 -0
- package/src/core-turn/run-core-turn.ts +13 -2
- package/src/core-turn/run-goal-loop.ts +17 -1
- package/src/core-turn/short-question.ts +45 -12
- package/src/core-turn/types.ts +7 -0
- package/src/dashboard/acp-active-model.ts +40 -0
- package/src/dashboard/auto-compact-runtime.ts +2 -0
- package/src/dashboard/boot-banner.ts +80 -0
- package/src/dashboard/dashboard-status-lines.ts +11 -0
- package/src/dashboard/detail-viewer-runtime.ts +15 -2
- package/src/dashboard/event-loop-stall-monitor.ts +4 -0
- package/src/dashboard/first-screen-band.ts +63 -13
- package/src/dashboard/goal-loop-thinking.ts +16 -0
- package/src/dashboard/hitl-boot.ts +9 -4
- package/src/dashboard/index.ts +235 -389
- package/src/dashboard/input/chat-main-entry-runtime.ts +2 -0
- package/src/dashboard/input/chat-main-log-actions.ts +4 -0
- package/src/dashboard/input/chat-main-log-command.ts +12 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +172 -3
- package/src/dashboard/input/chat-main-session.ts +6 -2
- package/src/dashboard/input/chat-main-slash-command.ts +7 -0
- package/src/dashboard/input/chat-main-turn.ts +2 -1
- package/src/dashboard/input/compact-prepass-recovery.ts +97 -0
- package/src/dashboard/input/dashboard-chord-actions.ts +10 -1
- package/src/dashboard/input/dashboard-chord-runtime.ts +2 -0
- package/src/dashboard/input/external-input-host.ts +45 -0
- package/src/dashboard/input/log-fold-binding.ts +18 -0
- package/src/dashboard/input/mouse-wiring.ts +17 -4
- package/src/dashboard/input/turn-steer-bridge.ts +94 -0
- package/src/dashboard/log-click-runtime.ts +5 -3
- package/src/dashboard/running-build-status.ts +74 -0
- package/src/dashboard/seat-boot-preamble.ts +113 -0
- package/src/dashboard/seat-local-instructions.ts +305 -0
- package/src/dashboard/skill-detection-runtime.ts +24 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +100 -28
- package/src/dashboard/slash-runtime/model-choices.ts +35 -0
- package/src/dashboard/term-slash-runtime.ts +15 -0
- package/src/dashboard/turn-preamble.ts +30 -2
- package/src/dashboard/turn-session-layers.ts +176 -0
- package/src/dashboard/turn-stream-formatter.ts +14 -6
- package/src/dashboard/turn-stream-presentation-applier.ts +8 -0
- package/src/domains/morning-report.ts +3 -1
- package/src/domains/release-tool.ts +8 -9
- package/src/domains/surface-events.ts +4 -1
- package/src/domains/watch-default-scheduler.ts +8 -9
- package/src/fold-stack.ts +24 -1
- package/src/git-fs/dirty.ts +32 -4
- package/src/git-fs/index.ts +43 -1
- package/src/github/pr-labels.ts +10 -4
- package/src/graph-runner/runner.ts +102 -14
- package/src/harness/harness-clean.ts +21 -3
- package/src/harness/harness-cli-command.ts +22 -6
- package/src/harness/harness-gc.ts +32 -5
- package/src/harness/harness-pod-dispatch.ts +11 -4
- package/src/hq/seats.ts +17 -3
- package/src/index.ts +48 -6
- package/src/input/external-input-queue.ts +219 -0
- package/src/intelligence-map/model-bench-scores.ts +102 -0
- package/src/interactive-terminal-modal.ts +13 -0
- package/src/llm/route-decision.ts +25 -0
- package/src/llm-stream-retry-display.ts +59 -0
- package/src/llm.ts +253 -55
- package/src/log-entry.ts +3 -3
- package/src/log-pane/search.ts +29 -4
- package/src/loops/agent-reply.ts +256 -0
- package/src/loops/budget.ts +37 -7
- package/src/loops/loop-cli.ts +3 -2
- package/src/loops/msg-address.ts +57 -0
- package/src/loops/msg-wake.ts +282 -0
- package/src/loops/orchestrator/inbox.ts +130 -0
- package/src/loops/orchestrator/resync-shadow.ts +100 -12
- package/src/loops/orchestrator/tick.ts +94 -3
- package/src/loops/registry.ts +42 -4
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/memory.ts +20 -5
- package/src/msg/msg-sse-server.ts +141 -0
- package/src/msg/msg-store.ts +84 -14
- package/src/native-tool-catalog.ts +125 -0
- package/src/nexus/api/http-server.ts +5 -0
- package/src/nexus/api/ops-api.ts +2 -0
- package/src/nexus/api/project-autopsy.ts +127 -0
- package/src/nexus/api/terminals.ts +3 -0
- package/src/nexus/api/workflow-approvals.ts +2 -0
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -2
- package/src/oauth/codex-account-store.ts +15 -3
- package/src/oauth/codex-billing-route.ts +31 -0
- package/src/ops/overview-collect.ts +19 -2
- package/src/panes/log-pane.ts +67 -8
- package/src/patents/ledger.ts +128 -0
- package/src/persona/presets.ts +44 -0
- package/src/plugins/install/market-fetch.ts +32 -1
- package/src/plugins/maker/wizard-generate.ts +6 -4
- package/src/pod-lease/admission.ts +116 -41
- package/src/preview/terminal.ts +14 -1
- package/src/prompt-cache/types.ts +2 -0
- package/src/prompt-enhance/enhance.ts +24 -8
- package/src/prompt-library/universal-preamble.ts +273 -56
- package/src/pty-shell/pty-control-ipc.ts +4 -1
- package/src/pty-shell/pty-manifest.ts +77 -5
- package/src/pty-shell/registry.ts +19 -2
- package/src/pty-shell/tui-run-state.ts +253 -0
- package/src/release-loop/checklist.ts +11 -0
- package/src/release-loop/light-rc.ts +28 -3
- package/src/release-loop/merged-pr-checklist.ts +24 -5
- package/src/release-loop/rehearsal.ts +1 -1
- package/src/release-loop/rubric.ts +70 -0
- package/src/render.ts +5 -1
- package/src/rfc-registry/registry.ts +88 -0
- package/src/seat-dispatch/seat-request-ledger.ts +4 -0
- package/src/seat-loop/knowhow-lint.ts +233 -0
- package/src/seat-loop/seat-pack.ts +16 -4
- package/src/seat-loop/seat-report.ts +42 -2
- package/src/seat-loop/traffic-signal.ts +7 -0
- package/src/self-dev/ask-launch-flow.ts +48 -8
- package/src/self-dev/ask-path-candidates.ts +69 -14
- package/src/self-dev/decompose-proposal.ts +43 -1
- package/src/self-dev/graph-journey-nodes.ts +2 -0
- package/src/self-dev/launch-preflight-text.ts +5 -1
- package/src/self-dev/launch-preflight.ts +143 -10
- package/src/self-dev/run-supervisor.ts +71 -5
- package/src/self-dev/shard-aggregate.ts +2 -0
- package/src/self-dev/shard-run.ts +23 -2
- package/src/self-health/signatures.ts +132 -0
- package/src/self-implement/doctor-visit.ts +118 -0
- package/src/self-implement/gate-cli.ts +17 -4
- package/src/self-implement/goal-author-decompose.ts +80 -16
- package/src/self-implement/goal-author.ts +116 -73
- package/src/self-implement/goal-authoring-grounding.ts +1 -1
- package/src/self-implement/goal-file-name.ts +65 -0
- package/src/self-implement/goal-new-paths.ts +4 -5
- package/src/self-implement/graph-authority.ts +17 -3
- package/src/self-implement/graph-yaml.ts +15 -7
- package/src/self-implement/ground-goal.ts +2 -1
- package/src/self-implement/headless-elanous-driver.ts +16 -1
- package/src/self-implement/host-regate.ts +58 -9
- package/src/self-implement/orchestrator.ts +3 -10
- package/src/self-implement/review-mustfix-class.ts +115 -0
- package/src/self-implement/rework-policy.ts +80 -2
- package/src/self-implement/run-ledger.ts +111 -7
- package/src/self-implement/running-runs.ts +10 -6
- package/src/self-implement/self-implement-runtime.ts +32 -0
- package/src/self-implement/speed-claims.ts +145 -6
- package/src/session/pending-input.ts +62 -11
- package/src/session-runtime/index.ts +7 -1
- package/src/skills/tools/ops-ledger.ts +707 -0
- package/src/skills/tools/persistent-grounding.ts +103 -8
- package/src/skills/tools/shell.ts +196 -2
- package/src/status/bar.ts +32 -2
- package/src/status/status-provider-info.ts +58 -0
- package/src/steward/rejudge-tick.ts +12 -1
- package/src/steward/release-day.ts +158 -0
- package/src/steward/resync-tick.ts +123 -0
- package/src/task-agent/actions.ts +1 -0
- package/src/task-agent/adopt-pr.ts +140 -0
- package/src/task-agent/board.ts +11 -1
- package/src/task-agent/card-evidence.ts +37 -5
- package/src/task-agent/cover.ts +84 -17
- package/src/task-agent/failure-notify.ts +61 -0
- package/src/task-agent/green-sweep.ts +170 -0
- package/src/task-agent/land-worktree.ts +52 -5
- package/src/task-agent/live-move-history.ts +1 -0
- package/src/task-agent/live-moves.ts +43 -12
- package/src/task-agent/parent-host.ts +1 -1
- package/src/task-agent/postland-card.ts +139 -0
- package/src/task-agent/rejudge-on-head.ts +109 -7
- package/src/task-agent/remote-rejudge-bind.ts +91 -0
- package/src/task-agent/repair-branch-cas.ts +182 -0
- package/src/task-agent/repair-cycle.ts +288 -0
- package/src/task-agent/repair-next-move.ts +31 -0
- package/src/task-agent/repair-review.ts +24 -0
- package/src/task-agent/repair-worker.ts +87 -0
- package/src/task-agent/review-result-capture.ts +2 -1
- package/src/task-agent/shadow.ts +13 -7
- package/src/task-agent/task-hand.ts +115 -6
- package/src/task-orchestrator/surfaces/kubectl-transient-retry.ts +51 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +63 -7
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +6 -11
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +76 -0
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +96 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +175 -43
- package/src/telegram.ts +30 -1
- package/src/terminal/session-registry.ts +6 -0
- package/src/thinking-line.ts +12 -3
- package/src/tool-runtime/index.ts +4 -0
- package/src/tool-runtime/ops-ledger-runtimes.ts +84 -0
- package/src/tool-runtime/ref-consult-runtime.ts +17 -2
- package/src/tool-runtime/run-shell-runtime.ts +4 -1
- package/src/tool-runtime/self-cognition-runtimes.ts +5 -1
- package/src/tui.ts +5 -0
- package/src/user-config.ts +62 -7
- package/src/ux-sim/fake-llm.ts +29 -0
- package/src/ux-sim/fault-sqlite-busy.ts +50 -0
- package/src/ux-sim/in-process-cli.ts +175 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +0 -36
- package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +0 -148
- package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1454-a9c338f5bb556f42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +0 -32
- package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +0 -34
- package/apps/pwa/out/_next/static/chunks/3259-86f3be56e43eaf6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +0 -287
- package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4084.15ecaf4240bd9e77.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +0 -8
- package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +0 -149
- package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +0 -1
- package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/599-a914cc0468f56143.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +0 -23
- package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +0 -77
- package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +0 -62
- package/apps/pwa/out/_next/static/chunks/7752.5cbdd0b433c54af9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-1e5fce59500a2cc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +0 -226
- package/apps/pwa/out/_next/static/chunks/83a80514-b897b64df43ce108.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +0 -93
- package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +0 -115
- package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +0 -41
- package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +0 -74
- package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +0 -90
- package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +0 -79
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-a1ce306364f08da9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-07110da72c45e68f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d2d76d4a7eae91bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-30007380f2e2a3c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e5a9302c105725a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-b93c04b5311c97ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-718a49e86bf25f9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-20662900d6b4b455.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f707a509515ac50c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-6a16a48d1aa6e91f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-fcb06e305f515527.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-6acf5ec4e6c6d1af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-39f82acf619cca23.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-7c2c8f81b185f9c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ae7aff07e32676bb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-482c60c1bc540d0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-7cb996c1aa08b6f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-623e08fe4477d606.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-db460cd8aecb8490.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-8397a5c6ca569bf4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1917ea87ea71ab6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-670510eda8b9443f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-d73c3f1e00d93986.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-65caacf54389081e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4bb7556e2e97a750.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-77e04b4f8762c666.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-15c0a4095baddfba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-4eb96fc7241c2456.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-63e272a4cd3b6634.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d64ff212dc55d03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-7f096248993fc2d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e47fc72049149a38.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-f7d808e31e005895.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-5c2b24b5496dad73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-76cdb531668b5191.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-e2b63345bba1a11f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-d376e0c83edc041a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d6db55fe2c04d128.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-dab163b338e3b966.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-08019efef111ed2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-0260ffc7eda50db1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-980ce6fe36ad95eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-99c4e6c7345a9156.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-0ab42e0f05823013.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ad9220422d20ba33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/e117f801.e92bf10242653497.js +0 -1
- package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +0 -122
- package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +0 -1
- package/src/dashboard/bench-slash-runtime.ts +0 -40
- package/src/dashboard/input/search-modal-router.ts +0 -9
- package/src/dashboard/modals/pane-key-router.ts +0 -27
- package/src/dashboard/view-slash-runtime.ts +0 -48
- /package/apps/pwa/out/_next/static/{Ev2jivDMTSoEc-5rIXdcy → cIpv5nU9AycwYWZI9H589}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
// ── 우편 깨움 — 글을 저장한 «뒤» 받는 몸을 한 번 두드린다 ──
|
|
2
|
+
//
|
|
3
|
+
// 주소에 «답할 몸»(replyBody)이 있어도 «깨울 길»이 없으면 죽은 주소다(10-14 grok OP 16분 정지).
|
|
4
|
+
// 종류(`MessageWake`)마다 하는 일:
|
|
5
|
+
// sse — 아무것도 안 한다(구독자가 이미 듣는다)
|
|
6
|
+
// cron — 다음 틱에 읽는다 · `wake-deferred` 로그만
|
|
7
|
+
// pty-inject — elanous TUI(pty 별명 = 자리 소문자)가 턴 idle 일 때만 한 줄 주입
|
|
8
|
+
// herdr — 자리 폴더 `herdr.pane` 의 pane 이 agent_status=idle 일 때만 한 줄 주입
|
|
9
|
+
// none — stderr 경고 한 줄 · 해석 실패는 «모름»으로 남긴다(«없다»로 위장 금지)
|
|
10
|
+
// ⛔ 우편은 입력칸에 넣지 않는다(대표 10-15 01:20) — 기본은 입력칸 주입 0. 10-15 01:10 사고: 대표 가 치던 문장에
|
|
11
|
+
// 깨움 한 줄 ⊕ Enter 가 섞여 제출됐다(«에이전트 idle ≠ 사람이 안 친다»). 자리 폴더에서 푼 대상(pty 별명·
|
|
12
|
+
// pty.ref·herdr.pane)은 `<seat-state>/<자리>/wake-inject` 일반 파일이 있을 때만 주입하고, 없으면
|
|
13
|
+
// `msg.wake skipped{reason}` 만 남긴다.
|
|
14
|
+
// ⚠️ wake-inject 는 «사람이 치지 않는 pane»(무인 에이전트 전용)에만 둔다 — 사람이 치는 pane 에는 켜지 말 것.
|
|
15
|
+
// ⛔ 깨움은 post 의 성패를 바꾸지 않는다 — 실패·시간 초과는 결과 값으로만 돌아온다.
|
|
16
|
+
// ⛔ 시험 우주에서는 실제 pty/herdr 호출 0 — `ELANOUS_MSG_WAKE_LIVE=1` 로만 연다(격리 실물 시험용).
|
|
17
|
+
|
|
18
|
+
import { spawn } from 'node:child_process';
|
|
19
|
+
import { Database } from 'bun:sqlite';
|
|
20
|
+
import { randomUUID } from 'node:crypto';
|
|
21
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync } from 'node:fs';
|
|
22
|
+
import { homedir } from 'node:os';
|
|
23
|
+
import { dirname, join } from 'node:path';
|
|
24
|
+
|
|
25
|
+
import { debug } from '../debug/log.js';
|
|
26
|
+
import { effectiveInstanceRoot, prodInstanceRoot } from '../instance/resolve.js';
|
|
27
|
+
import { listPtyManifestRows } from '../pty-shell/pty-manifest.js';
|
|
28
|
+
import { messageRouteFor, type MessageWake } from './msg-address.js';
|
|
29
|
+
|
|
30
|
+
export const WAKE_DEBOUNCE_MS = 5 * 60_000;
|
|
31
|
+
export const WAKE_TIMEOUT_MS = 3_000;
|
|
32
|
+
/** Seat-folder file that opts a human pane in to wake injection (presence is the switch). */
|
|
33
|
+
const WAKE_OPT_IN_FILE = 'wake-inject';
|
|
34
|
+
|
|
35
|
+
export interface WakeResolution {
|
|
36
|
+
wake: MessageWake;
|
|
37
|
+
/** pty id (pty-inject) or herdr pane id (herdr). */
|
|
38
|
+
target?: string;
|
|
39
|
+
/** Where the answer came from — `unresolved` means «모름», not a measured absence. */
|
|
40
|
+
source: 'loop-table' | 'pty-name' | 'pty.ref' | 'herdr.pane' | 'unresolved';
|
|
41
|
+
reason?: string;
|
|
42
|
+
/** For a seat-folder target: the seat opted in to injection (`<seat>/wake-inject` exists). Absent = not a seat target. */
|
|
43
|
+
optIn?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type WakeResult = 'none-sse' | 'wake-deferred' | 'injected' | 'busy' | 'debounced' | 'skipped' | 'skipped-reply'
|
|
47
|
+
| 'skipped-self' | 'skipped-test-universe' | 'no-wake' | 'failed' | 'timeout';
|
|
48
|
+
|
|
49
|
+
export interface WakeOutcome extends WakeResolution { address: string; msgId: number; result: WakeResult }
|
|
50
|
+
|
|
51
|
+
export interface WakeDeps {
|
|
52
|
+
/** Seat folders (`<root>/<SEAT>/pty.ref` · `herdr.pane`). Prod: ~/elanous-hq/seat-state · test universe: <root>/seat-state. */
|
|
53
|
+
seatStateRoot?: string;
|
|
54
|
+
/** Debounce claims live here (`<stateRoot>/msg/wake-claims.db`). */
|
|
55
|
+
stateRoot?: string;
|
|
56
|
+
now?: () => number;
|
|
57
|
+
/** Real pty/herdr calls are allowed (default: prod universe or ELANOUS_MSG_WAKE_LIVE=1). */
|
|
58
|
+
live?: boolean;
|
|
59
|
+
timeoutMs?: number;
|
|
60
|
+
listPtys?: () => Array<{ id: string; nickname?: string; alive: boolean; turnState?: 'busy' | 'idle' }>;
|
|
61
|
+
/** Reads one seat-folder file (`pty.ref` · `herdr.pane`); null when absent. */
|
|
62
|
+
readPane?: (path: string) => string | null;
|
|
63
|
+
/** Does this seat-folder opt-in file exist (`<seat>/wake-inject`)? */
|
|
64
|
+
hasOptIn?: (path: string) => boolean;
|
|
65
|
+
/** Loads the pty writer (the CLI module is heavy, so it is imported only when a pty wake is due). */
|
|
66
|
+
ptyInjector?: () => Promise<(ptyId: string, line: string) => Promise<void>>;
|
|
67
|
+
herdrStatus?: (paneId: string, signal: AbortSignal) => Promise<string>;
|
|
68
|
+
herdrInject?: (paneId: string, line: string, signal: AbortSignal) => Promise<void>;
|
|
69
|
+
warn?: (line: string) => void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isLive(deps: WakeDeps): boolean {
|
|
73
|
+
if (deps.live !== undefined) return deps.live;
|
|
74
|
+
return effectiveInstanceRoot() === prodInstanceRoot() || process.env.ELANOUS_MSG_WAKE_LIVE === '1';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function seatStateRoot(deps: WakeDeps): string {
|
|
78
|
+
if (deps.seatStateRoot) return deps.seatStateRoot;
|
|
79
|
+
const root = effectiveInstanceRoot();
|
|
80
|
+
return root === prodInstanceRoot() ? join(homedir(), 'elanous-hq', 'seat-state') : join(root, 'seat-state');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The opt-in must be a regular file — a directory, a symlink or anything else at that name does not open injection. */
|
|
84
|
+
function isRegularFile(path: string): boolean {
|
|
85
|
+
// lstat — 링크는 따라가지 않는다(자리 자체의 일반 파일만 opt-in).
|
|
86
|
+
try { return lstatSync(path).isFile(); } catch { return false; }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The seat's own opt-in, read independently of whatever target the seat folder points at now. */
|
|
90
|
+
function seatOptedIn(address: string, deps: WakeDeps): boolean {
|
|
91
|
+
return (deps.hasOptIn ?? isRegularFile)(join(seatStateRoot(deps), address.trim().toUpperCase(), WAKE_OPT_IN_FILE));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readPaneFile(path: string): string | null {
|
|
95
|
+
try { return existsSync(path) ? readFileSync(path, 'utf8').trim() || null : null; }
|
|
96
|
+
catch { return null; }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** How a post to `address` would wake its reader — table first, then a live pty named after the seat, then herdr. */
|
|
100
|
+
export function resolveWake(address: string, deps: WakeDeps = {}): WakeResolution {
|
|
101
|
+
const name = address.trim().toUpperCase();
|
|
102
|
+
if (name === 'ALL') return { wake: 'none', source: 'unresolved', reason: 'topic' };
|
|
103
|
+
const route = messageRouteFor(name);
|
|
104
|
+
if (route?.wake) return { wake: route.wake, source: 'loop-table' };
|
|
105
|
+
// 호스트 해석은 표에 선언된 자리 줄(wakeFrom: 'host')만 — 모르는 주소는 같은 이름의 pty 가 있어도 깨우지 않는다.
|
|
106
|
+
if (route?.wakeFrom !== 'host') return { wake: 'none', source: 'unresolved', reason: 'undeclared-address' };
|
|
107
|
+
// ⭐ 별명은 «정확히» 같은 것만 — pty ref 해석의 부분 일치(op ⊂ opt)로 남의 TUI 에 넣지 않는다.
|
|
108
|
+
const lower = name.toLowerCase();
|
|
109
|
+
let ptys: ReturnType<NonNullable<WakeDeps['listPtys']>> = [];
|
|
110
|
+
try { ptys = (deps.listPtys ?? listPtyManifestRows)(); } catch { ptys = []; }
|
|
111
|
+
const named = ptys.filter(row => row.alive && (row.nickname ?? '').toLowerCase() === lower);
|
|
112
|
+
const optIn = seatOptedIn(name, deps);
|
|
113
|
+
if (named.length === 1) return { wake: 'pty-inject', target: named[0]!.id, source: 'pty-name', optIn };
|
|
114
|
+
// seat-inbox.sh 와 같은 자리 폴더 파일: pty.ref(살아 있는 행의 id·별명과 정확히 같을 때만) → herdr.pane.
|
|
115
|
+
const readSeatFile = deps.readPane ?? readPaneFile;
|
|
116
|
+
const ref = readSeatFile(join(seatStateRoot(deps), name, 'pty.ref'))?.toLowerCase();
|
|
117
|
+
const byRef = ref ? ptys.filter(row => row.alive && (row.id.toLowerCase() === ref || (row.nickname ?? '').toLowerCase() === ref)) : [];
|
|
118
|
+
if (byRef.length === 1) return { wake: 'pty-inject', target: byRef[0]!.id, source: 'pty.ref', optIn };
|
|
119
|
+
const pane = readSeatFile(join(seatStateRoot(deps), name, 'herdr.pane'));
|
|
120
|
+
if (pane) return { wake: 'herdr', target: pane, source: 'herdr.pane', optIn };
|
|
121
|
+
return { wake: 'none', source: 'unresolved', reason: named.length > 1 ? `pty-name-ambiguous:${named.length}` : 'no-pty-name-no-herdr-pane' };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function claimDbPath(deps: WakeDeps): string {
|
|
125
|
+
return join(deps.stateRoot ?? effectiveInstanceRoot(), 'msg', 'wake-claims.db');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
interface WakeClaim { db: string; address: string; token: string }
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Atomically claim the 5-minute wake window for one address. One SQLite upsert decides it under the
|
|
132
|
+
* write lock — the row is replaced only when the held claim is older than the window — so two
|
|
133
|
+
* concurrent `msg post` processes cannot both win, including when both saw an expired claim.
|
|
134
|
+
*/
|
|
135
|
+
export function claimWake(db: string, address: string, now: number): WakeClaim | null {
|
|
136
|
+
mkdirSync(dirname(db), { recursive: true });
|
|
137
|
+
const token = `${now} ${process.pid} ${randomUUID()}`;
|
|
138
|
+
const conn = new Database(db);
|
|
139
|
+
try {
|
|
140
|
+
conn.exec('PRAGMA busy_timeout = 2000');
|
|
141
|
+
conn.exec('CREATE TABLE IF NOT EXISTS wake_claims (address TEXT PRIMARY KEY, at INTEGER NOT NULL, token TEXT NOT NULL)');
|
|
142
|
+
const changed = conn.query(`INSERT INTO wake_claims (address, at, token) VALUES (?1, ?2, ?3)
|
|
143
|
+
ON CONFLICT(address) DO UPDATE SET at = excluded.at, token = excluded.token WHERE wake_claims.at <= ?2 - ?4`)
|
|
144
|
+
.run(address, now, token, WAKE_DEBOUNCE_MS).changes;
|
|
145
|
+
return changed === 1 ? { db, address, token } : null;
|
|
146
|
+
} finally { conn.close(); }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Give the window back when nothing was injected (busy · timeout · failure) — only our own claim. */
|
|
150
|
+
function releaseClaim(claim: WakeClaim): void {
|
|
151
|
+
try {
|
|
152
|
+
const conn = new Database(claim.db);
|
|
153
|
+
try { conn.exec('PRAGMA busy_timeout = 2000'); conn.query('DELETE FROM wake_claims WHERE address = ?1 AND token = ?2').run(claim.address, claim.token); }
|
|
154
|
+
finally { conn.close(); }
|
|
155
|
+
} catch { /* a stale claim only delays the next wake by one window */ }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function run(cmd: string, args: string[], timeoutMs: number, signal: AbortSignal): Promise<string> {
|
|
159
|
+
return new Promise((resolve, reject) => {
|
|
160
|
+
if (signal.aborted) { reject(new Error(`${cmd} aborted`)); return; }
|
|
161
|
+
const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], signal });
|
|
162
|
+
let out = '';
|
|
163
|
+
const timer = setTimeout(() => { child.kill('SIGKILL'); reject(new Error(`${cmd} timeout`)); }, timeoutMs);
|
|
164
|
+
child.stdout.on('data', chunk => { out += String(chunk); });
|
|
165
|
+
child.on('error', error => { clearTimeout(timer); reject(error); });
|
|
166
|
+
child.on('close', code => { clearTimeout(timer); code === 0 ? resolve(out) : reject(new Error(`${cmd} exit ${code}`)); });
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function defaultHerdrStatus(paneId: string, signal: AbortSignal): Promise<string> {
|
|
171
|
+
const parsed = JSON.parse(await run('herdr', ['pane', 'get', paneId], WAKE_TIMEOUT_MS, signal)) as { result?: { pane?: { agent_status?: unknown } } };
|
|
172
|
+
const status = parsed.result?.pane?.agent_status;
|
|
173
|
+
return typeof status === 'string' ? status : 'unknown';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function defaultHerdrInject(paneId: string, line: string, signal: AbortSignal): Promise<void> {
|
|
177
|
+
// `pane run` = send-text ⊕ Enter 한 번에.
|
|
178
|
+
await run('herdr', ['pane', 'run', paneId, line], WAKE_TIMEOUT_MS, signal);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function defaultPtyInjector(): Promise<(ptyId: string, line: string) => Promise<void>> {
|
|
182
|
+
const { runPtyText } = await import('../cli/pty-takeover-cli.js');
|
|
183
|
+
return async (ptyId, line) => {
|
|
184
|
+
const result = await runPtyText(ptyId, line, true);
|
|
185
|
+
if (result.exitCode !== 0) throw new Error(result.message);
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function wakeLine(from: string, address: string, msgId: number): string {
|
|
190
|
+
return `[우편 깨움] ${from} → ${address} #${msgId} — eln msg list --to ${address} 로 읽고 처리`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export const NO_WAKE_NOTICE = '이 주소는 깨울 길이 없다 — 받는 몸이 스스로 읽을 때까지 쌓인다';
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Wake the reader of a just-saved message. Never throws; the caller's post outcome is already final.
|
|
197
|
+
* `message.from`/`kind` decide the skips (a reply or a self-addressed note never wakes anyone).
|
|
198
|
+
*/
|
|
199
|
+
export async function wakeRecipient(address: string, msgId: number, message: { from: string; kind?: string }, deps: WakeDeps = {}): Promise<WakeOutcome> {
|
|
200
|
+
const timeoutMs = deps.timeoutMs ?? WAKE_TIMEOUT_MS;
|
|
201
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
202
|
+
let resolution: WakeResolution = { wake: 'none', source: 'unresolved', reason: 'not-resolved' };
|
|
203
|
+
const controller = new AbortController();
|
|
204
|
+
// 마감은 «진입» 시각 기준 — 동기 작업(claim 잠금 대기 등)이 늦어 타이머가 못 울려도 넘기면 주입하지 않는다.
|
|
205
|
+
const deadline = Date.now() + timeoutMs;
|
|
206
|
+
const expired = () => controller.signal.aborted || Date.now() >= deadline;
|
|
207
|
+
let claim: WakeClaim | null = null;
|
|
208
|
+
let injecting = false;
|
|
209
|
+
const attempt = (async (): Promise<WakeOutcome> => {
|
|
210
|
+
const done = (result: WakeResult, reason?: string): WakeOutcome =>
|
|
211
|
+
({ ...resolution, ...(reason ? { reason } : {}), address, msgId, result });
|
|
212
|
+
if (message.kind === 'reply') return done('skipped-reply', 'kind=reply');
|
|
213
|
+
if (message.from.toUpperCase() === address.toUpperCase()) return done('skipped-self', 'from=to');
|
|
214
|
+
resolution = resolveWake(address, deps);
|
|
215
|
+
if (resolution.wake === 'sse') return done('none-sse');
|
|
216
|
+
if (resolution.wake === 'cron') return done('wake-deferred');
|
|
217
|
+
if (resolution.wake === 'none') return done('no-wake');
|
|
218
|
+
// 사람이 앉는 pane 은 명시 opt-in 이 없으면 주입 0 — 에이전트가 idle 이어도 사람이 치는 중일 수 있다.
|
|
219
|
+
if (resolution.optIn === false) return done('skipped', 'human-pane-no-opt-in');
|
|
220
|
+
if (!isLive(deps)) return done('skipped-test-universe');
|
|
221
|
+
claim = claimWake(claimDbPath(deps), address, (deps.now ?? Date.now)());
|
|
222
|
+
if (!claim) return done('debounced');
|
|
223
|
+
try {
|
|
224
|
+
const line = wakeLine(message.from, address, msgId);
|
|
225
|
+
if (resolution.wake === 'pty-inject') {
|
|
226
|
+
// 모듈을 «먼저» 불러오고, 그 뒤에 턴을 읽는다 — 로드 사이 busy 로 바뀐 TUI 에 넣지 않는다.
|
|
227
|
+
const inject = await (deps.ptyInjector ?? defaultPtyInjector)();
|
|
228
|
+
// turnState 는 TUI 가 스스로 적은 값(#27485) — 살아 있고 idle 이 «기록»돼 있을 때만 넣는다(모름 = 넣지 않음).
|
|
229
|
+
// 로드 사이 별명·pty.ref 가 다른 행으로 옮겨 갔으면 넣지 않는다 — 주소→대상을 다시 푼다.
|
|
230
|
+
const again = resolveWake(address, deps);
|
|
231
|
+
// opt-in 은 주입 직전에 «먼저» 다시 본다 — 기다리는 사이 `wake-inject` 를 지웠으면(대상이 바뀌었어도) 주입 0.
|
|
232
|
+
if (!seatOptedIn(address, deps)) { resolution = { ...resolution, optIn: false }; return done('skipped', 'human-pane-no-opt-in'); }
|
|
233
|
+
if (again.wake !== 'pty-inject' || again.target !== resolution.target) return done('busy', `target-moved:${again.target ?? again.wake}`);
|
|
234
|
+
const row = (deps.listPtys ?? listPtyManifestRows)().find(item => item.id === resolution.target);
|
|
235
|
+
if (!row?.alive || row.turnState !== 'idle') return done('busy', `turn=${row?.alive === false ? 'dead' : row?.turnState ?? 'unknown'}`);
|
|
236
|
+
// ⛔ 마감이 지났으면 새 주입을 시작하지 않는다.
|
|
237
|
+
if (expired()) return done('timeout');
|
|
238
|
+
injecting = true;
|
|
239
|
+
await inject(resolution.target!, line);
|
|
240
|
+
} else {
|
|
241
|
+
const status = await (deps.herdrStatus ?? defaultHerdrStatus)(resolution.target!, controller.signal);
|
|
242
|
+
if (status !== 'idle') return done('busy', `agent_status=${status}`);
|
|
243
|
+
// 조회 사이 자리의 pane 이 바뀌었으면 옛 pane 에 넣지 않는다 — 주소→대상을 다시 푼다.
|
|
244
|
+
const again = resolveWake(address, deps);
|
|
245
|
+
// opt-in 은 주입 직전에 «먼저» 다시 본다 — 기다리는 사이 `wake-inject` 를 지웠으면(대상이 바뀌었어도) 주입 0.
|
|
246
|
+
if (!seatOptedIn(address, deps)) { resolution = { ...resolution, optIn: false }; return done('skipped', 'human-pane-no-opt-in'); }
|
|
247
|
+
if (again.wake !== 'herdr' || again.target !== resolution.target) return done('busy', `target-moved:${again.target ?? again.wake}`);
|
|
248
|
+
// ⛔ 마감은 «주입 바로 앞»에서 — 재해석이 늦어 넘겼어도 새 주입 0.
|
|
249
|
+
if (expired()) return done('timeout');
|
|
250
|
+
injecting = true;
|
|
251
|
+
await (deps.herdrInject ?? defaultHerdrInject)(resolution.target!, line, controller.signal);
|
|
252
|
+
}
|
|
253
|
+
return done('injected');
|
|
254
|
+
} catch (error) {
|
|
255
|
+
// 주입이 «시작»됐다 실패하면 들어갔는지 모른다 — 창을 돌려줘 다음 글이 다시 깨우게 한다.
|
|
256
|
+
injecting = false;
|
|
257
|
+
throw error;
|
|
258
|
+
} finally { if (!injecting && claim) releaseClaim(claim); }
|
|
259
|
+
})();
|
|
260
|
+
let outcome: WakeOutcome;
|
|
261
|
+
try {
|
|
262
|
+
outcome = await Promise.race([attempt, new Promise<WakeOutcome>(resolve => {
|
|
263
|
+
timer = setTimeout(() => {
|
|
264
|
+
controller.abort();
|
|
265
|
+
// 시간 초과면 창을 돌려준다 — 주입 전이면 들어간 것이 없고, 주입 중 멈췄으면 들어갔는지 «모른다».
|
|
266
|
+
// 모를 때는 다음 글이 다시 두드리게 둔다(내용 없는 한 줄의 중복은 무해, 깨움 누락은 16분 정지).
|
|
267
|
+
if (claim) releaseClaim(claim);
|
|
268
|
+
resolve({ ...resolution, address, msgId, result: 'timeout' });
|
|
269
|
+
}, timeoutMs);
|
|
270
|
+
})]);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
outcome = { ...resolution, address, msgId, result: 'failed', reason: error instanceof Error ? error.message : String(error) };
|
|
273
|
+
} finally { clearTimeout(timer); }
|
|
274
|
+
attempt.catch(() => { /* a late failure after timeout is already reported as timeout */ });
|
|
275
|
+
try {
|
|
276
|
+
if (outcome.result === 'no-wake') (deps.warn ?? (line => console.error(line)))(
|
|
277
|
+
outcome.source === 'unresolved' ? `${NO_WAKE_NOTICE} (wake=none · 모름: ${outcome.reason})` : `${NO_WAKE_NOTICE} (wake=none)`);
|
|
278
|
+
debug.log('msg.wake', outcome.result === 'skipped' ? 'skipped' : outcome.wake, { address, msgId, wake: outcome.wake, result: outcome.result, reason: outcome.reason ?? outcome.source,
|
|
279
|
+
...(outcome.target ? { target: outcome.target } : {}) });
|
|
280
|
+
} catch { /* reporting never turns a wake outcome into a throw */ }
|
|
281
|
+
return outcome;
|
|
282
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { openMsgStore, type Message, type MsgStore } from '../../msg/msg-store.js';
|
|
2
|
+
import { classifySeatTrafficProposal } from '../../seat-loop/traffic-signal.js';
|
|
3
|
+
import { debug } from '../../debug/log.js';
|
|
4
|
+
import { LOOP_MESSAGE_ROUTES } from '../msg-address.js';
|
|
5
|
+
import { replyWithAgent, type AgentReplyInput } from '../agent-reply.js';
|
|
6
|
+
import type { RoleLlmSpec } from '../../user-config.js';
|
|
7
|
+
import type { LLMProvider } from '../../llm.js';
|
|
8
|
+
|
|
9
|
+
const RECIPIENT = LOOP_MESSAGE_ROUTES.orchestrator.msgAddress;
|
|
10
|
+
|
|
11
|
+
export interface CoordinatorInboxResult { replied: number; acknowledged: number }
|
|
12
|
+
export interface CoordinatorAgentInboxOptions {
|
|
13
|
+
role: RoleLlmSpec;
|
|
14
|
+
pack: string;
|
|
15
|
+
store?: MsgStore;
|
|
16
|
+
path?: string;
|
|
17
|
+
root?: string;
|
|
18
|
+
limit?: number;
|
|
19
|
+
runAgent?: AgentReplyInput['runAgent'];
|
|
20
|
+
provider?: LLMProvider;
|
|
21
|
+
/** Only the ordered tick scan may advance the durable inbox cursor. */
|
|
22
|
+
acknowledge?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function trafficProposal(request: Message): 'hold' | 'UNHOLD' | null {
|
|
26
|
+
// A question mentioning a signal is not evidence that the signal occurred.
|
|
27
|
+
return request.kind === 'question' || /[??]|되나|됐나|맞나|풀어도|해제해도|확인 요청/.test(request.body)
|
|
28
|
+
? null : classifySeatTrafficProposal(request.body);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** This loop suggests traffic moves; it never changes traffic.json. */
|
|
32
|
+
export function coordinatorReply(request: Message): string {
|
|
33
|
+
const traffic = trafficProposal(request);
|
|
34
|
+
const proposal = traffic === 'hold' ? 'hold 제안' : traffic === 'UNHOLD' ? 'UNHOLD 제안' : '모름 — OP/자리 판단 필요';
|
|
35
|
+
const evidence = traffic === 'hold' ? '자리 메시지에 «손 구현 착수»가 있습니다.'
|
|
36
|
+
: traffic === 'UNHOLD' ? '자리 메시지에 «첫 줄 확정»이 있습니다.'
|
|
37
|
+
: '착수·첫 줄 확정을 확정 진술로 확인하지 못했습니다. 칸·traffic 근거를 사람이 확인해야 합니다.';
|
|
38
|
+
return `re #${request.id}\n제안: ${proposal}\n근거: ${evidence}\n실제 잠금 변경은 수행하지 않았습니다.`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Single reply writer: prefer the durable thread link, while recognizing pre-migration body markers. */
|
|
42
|
+
function writeCoordinatorReply(store: MsgStore, request: Message): { id: number; posted: boolean } {
|
|
43
|
+
const marker = `re #${request.id}`;
|
|
44
|
+
const linked = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
|
|
45
|
+
AND reply_to = ? AND kind = 'reply' ORDER BY id LIMIT 1`).get(RECIPIENT, request.from, request.id) as { id: number } | null;
|
|
46
|
+
if (linked) return { id: linked.id, posted: false };
|
|
47
|
+
const legacy = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
|
|
48
|
+
AND reply_to IS NULL AND kind = 'reply' AND (body = ? OR substr(body, 1, ?) = ?) ORDER BY id LIMIT 1`)
|
|
49
|
+
.get(RECIPIENT, request.from, marker, marker.length + 1, `${marker}\n`) as { id: number } | null;
|
|
50
|
+
if (legacy) return { id: legacy.id, posted: false };
|
|
51
|
+
const reply = store.post({ from: RECIPIENT, to: request.from,
|
|
52
|
+
body: coordinatorReply(request).slice(marker.length + 1), kind: 'reply', replyTo: request.id });
|
|
53
|
+
return { id: reply.id, posted: true };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** One transaction ties a reply to its acknowledgement. A retry finds the durable receipt. */
|
|
57
|
+
export function runCoordinatorInbox(inputStore?: MsgStore, limit = 100, path?: string): CoordinatorInboxResult {
|
|
58
|
+
const store = inputStore ?? openMsgStore(path);
|
|
59
|
+
const ownStore = inputStore === undefined;
|
|
60
|
+
let replied = 0;
|
|
61
|
+
let acknowledged = 0;
|
|
62
|
+
try {
|
|
63
|
+
const requests = store.listByRecipient(RECIPIENT, store.getCursor(RECIPIENT), limit);
|
|
64
|
+
for (const request of requests) {
|
|
65
|
+
// Broadcasts and replies are not new requests. Advancing past them keeps the cursor moving.
|
|
66
|
+
if (request.to !== RECIPIENT || request.from === RECIPIENT ||
|
|
67
|
+
(request.kind !== undefined && request.kind !== 'request' && request.kind !== 'question')) {
|
|
68
|
+
store.ack(RECIPIENT, request.id);
|
|
69
|
+
acknowledged++;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const key = `coord-inbox:${request.id}:${request.from}`;
|
|
73
|
+
const result = store.db.transaction(() => {
|
|
74
|
+
const existing = store.db.query('SELECT message_id FROM msg_provenance WHERE provenance_key = ?')
|
|
75
|
+
.get(key) as { message_id: number } | null;
|
|
76
|
+
const reply = existing ? { id: existing.message_id, posted: false } : writeCoordinatorReply(store, request);
|
|
77
|
+
if (!existing) store.db.query('INSERT INTO msg_provenance(provenance_key, message_id) VALUES (?, ?)').run(key, reply.id);
|
|
78
|
+
store.ack(RECIPIENT, request.id);
|
|
79
|
+
return { posted: reply.posted };
|
|
80
|
+
}).immediate();
|
|
81
|
+
if (result.posted) replied++;
|
|
82
|
+
acknowledged++;
|
|
83
|
+
debug.log('loop.coordinator-inbox', 'reply', { requestId: request.id, recipient: request.from,
|
|
84
|
+
proposal: trafficProposal(request) ?? 'unknown', duplicate: !result.posted });
|
|
85
|
+
}
|
|
86
|
+
debug.log('loop.coordinator-inbox', 'tick', { replied, acknowledged });
|
|
87
|
+
return { replied, acknowledged };
|
|
88
|
+
} finally { if (ownStore) store.close(); }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** One SSE delivery or tick scan uses the same durable handler. At-least-once wake is safe. */
|
|
92
|
+
export async function handleCoordinatorAgentMessage(
|
|
93
|
+
request: Message, input: CoordinatorAgentInboxOptions,
|
|
94
|
+
): Promise<CoordinatorInboxResult> {
|
|
95
|
+
const store = input.store ?? openMsgStore(input.path);
|
|
96
|
+
const ownStore = input.store === undefined;
|
|
97
|
+
const acknowledge = input.acknowledge === true;
|
|
98
|
+
try {
|
|
99
|
+
if (request.to !== RECIPIENT || request.from === RECIPIENT ||
|
|
100
|
+
(request.kind !== undefined && request.kind !== 'request' && request.kind !== 'question')) {
|
|
101
|
+
if (acknowledge) store.ack(RECIPIENT, request.id);
|
|
102
|
+
return { replied: 0, acknowledged: acknowledge ? 1 : 0 };
|
|
103
|
+
}
|
|
104
|
+
// With explicit role selection, every request goes through the agent body.
|
|
105
|
+
const result = await replyWithAgent({ address: RECIPIENT, request, role: input.role,
|
|
106
|
+
pack: input.pack, store, observationRoot: input.root,
|
|
107
|
+
...(input.provider ? { provider: input.provider } : {}),
|
|
108
|
+
...(input.runAgent ? { runAgent: input.runAgent } : {}) });
|
|
109
|
+
if (result.replyId === null) throw new Error(`coordinator agent returned no reply for #${request.id}`);
|
|
110
|
+
if (acknowledge) store.ack(RECIPIENT, request.id);
|
|
111
|
+
return { replied: result.posted ? 1 : 0, acknowledged: acknowledge ? 1 : 0 };
|
|
112
|
+
} finally { if (ownStore) store.close(); }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Configured body path; callers must check the explicit roleLlm opt-in before invoking it. */
|
|
116
|
+
export async function runCoordinatorAgentInbox(input: CoordinatorAgentInboxOptions): Promise<CoordinatorInboxResult> {
|
|
117
|
+
const store = input.store ?? openMsgStore(input.path);
|
|
118
|
+
const ownStore = input.store === undefined;
|
|
119
|
+
const result = { replied: 0, acknowledged: 0 };
|
|
120
|
+
try {
|
|
121
|
+
const requests = store.listByRecipient(RECIPIENT, store.getCursor(RECIPIENT), input.limit ?? 100);
|
|
122
|
+
for (const request of requests) {
|
|
123
|
+
const one = await handleCoordinatorAgentMessage(request, { ...input, store, acknowledge: true });
|
|
124
|
+
result.replied += one.replied;
|
|
125
|
+
result.acknowledged += one.acknowledged;
|
|
126
|
+
}
|
|
127
|
+
debug.log('loop.coordinator-inbox', 'agent-tick', result);
|
|
128
|
+
return result;
|
|
129
|
+
} finally { if (ownStore) store.close(); }
|
|
130
|
+
}
|
|
@@ -5,6 +5,9 @@ import { tmpdir } from 'node:os';
|
|
|
5
5
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
6
6
|
import { debug } from '../../debug/log.js';
|
|
7
7
|
import { effectiveInstanceRoot } from '../../instance/resolve.js';
|
|
8
|
+
import { PR_LABEL_NAMES } from '../../github/pr-labels.js';
|
|
9
|
+
import { listRunLedgers } from '../../self-implement/run-ledger.js';
|
|
10
|
+
import { queryRunningRuns } from '../../self-implement/running-runs.js';
|
|
8
11
|
import {
|
|
9
12
|
defaultGitMergeSeam, defaultLlmResolve, mergeMainWithLlmResolve,
|
|
10
13
|
type LlmMergeOutcome, type MergeGitSeam,
|
|
@@ -16,6 +19,8 @@ interface ResyncShadowEntry {
|
|
|
16
19
|
at: string;
|
|
17
20
|
pr: number;
|
|
18
21
|
head: string;
|
|
22
|
+
beforeHead?: string;
|
|
23
|
+
afterHead?: string;
|
|
19
24
|
mode: ResyncShadowMode;
|
|
20
25
|
pushed: boolean;
|
|
21
26
|
labelRemoved: boolean;
|
|
@@ -27,7 +32,7 @@ interface ResyncShadowEntry {
|
|
|
27
32
|
}
|
|
28
33
|
export interface ResyncShadowSummary { candidates: number; tried: number; saved: number; savedRatio: number | null }
|
|
29
34
|
|
|
30
|
-
type OpenPr = { number: number; headRefName: string; mergeable: string; isDraft: boolean; labels: { name: string }[] };
|
|
35
|
+
type OpenPr = { number: number; headRefName: string; headRefOid?: string; mergeable: string; isDraft: boolean; labels: { name: string }[] };
|
|
31
36
|
export interface ResyncShadowDeps {
|
|
32
37
|
repoRoot?: string;
|
|
33
38
|
instanceRoot?: string;
|
|
@@ -37,6 +42,63 @@ export interface ResyncShadowDeps {
|
|
|
37
42
|
gitSeam?: MergeGitSeam;
|
|
38
43
|
runTests?: (cwd: string, files: string[]) => { ok: boolean; failedTests?: string[]; noTests?: boolean };
|
|
39
44
|
now?: () => Date;
|
|
45
|
+
/** Run ownership is checked before touching a branch; null means the observation failed. */
|
|
46
|
+
activePrNumbers?: (candidatePrs: readonly number[]) => ReadonlySet<number> | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function activePrNumbers(candidatePrs: readonly OpenPr[], repoRoot: string, instanceRoot: string): ReadonlySet<number> | null {
|
|
50
|
+
const owners = new Map<number, { runId: string; branch: string; headCommit: string; terminal: boolean }[]>();
|
|
51
|
+
const branchRuns = new Map<string, Set<string>>();
|
|
52
|
+
const incompleteOwnerPrs = new Set<number>();
|
|
53
|
+
const candidateSet = new Set(candidatePrs.map(pr => pr.number));
|
|
54
|
+
try {
|
|
55
|
+
for (const match of listRunLedgers().matches) {
|
|
56
|
+
const latestStatus = match.entries.filter(entry => entry.event === 'run-status').at(-1)?.data.runStatus;
|
|
57
|
+
const terminal = latestStatus === 'completed' || latestStatus === 'failed' || latestStatus === 'cancelled';
|
|
58
|
+
for (const entry of match.entries) {
|
|
59
|
+
// A competing run can own the branch even when its PR number or worktree event is missing.
|
|
60
|
+
if ((entry.event === 'worktree' || entry.event === 'pr-opened') && typeof entry.data.branch === 'string') {
|
|
61
|
+
const ids = branchRuns.get(entry.data.branch) ?? new Set<string>();
|
|
62
|
+
ids.add(match.runId);
|
|
63
|
+
branchRuns.set(entry.data.branch, ids);
|
|
64
|
+
}
|
|
65
|
+
const number = entry.event === 'pr-opened' ? entry.data.number : undefined;
|
|
66
|
+
if (typeof number !== 'number' || !candidateSet.has(number)) continue;
|
|
67
|
+
const matches = owners.get(number) ?? [];
|
|
68
|
+
if (typeof entry.data.branch !== 'string' || typeof entry.data.headCommit !== 'string')
|
|
69
|
+
incompleteOwnerPrs.add(number);
|
|
70
|
+
else matches.push({ runId: match.runId, branch: entry.data.branch, headCommit: entry.data.headCommit, terminal });
|
|
71
|
+
owners.set(number, matches);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const runIds = [...new Set([...owners.values()].flatMap(rows => rows.map(row => row.runId)))];
|
|
75
|
+
if (runIds.length === 0) return new Set(candidatePrs.map(pr => pr.number));
|
|
76
|
+
const observed = queryRunningRuns({ runIds, caller: 'smart-merge.resync' });
|
|
77
|
+
if (observed.completeness !== 'complete') return null;
|
|
78
|
+
const active = new Set(observed.entries.filter(row => row.status === 'running' || row.status === 'probable-running'
|
|
79
|
+
|| row.status === 'unknown' || row.status === 'ended-unclosed').map(row => row.runId));
|
|
80
|
+
const priorPath = join(instanceRoot, 'orchestrator', 'resync-shadow.jsonl');
|
|
81
|
+
const prior = existsSync(priorPath) ? readFileSync(priorPath, 'utf8').split('\n').filter(Boolean).map(line => JSON.parse(line) as ResyncShadowEntry) : [];
|
|
82
|
+
const excluded = new Set<number>();
|
|
83
|
+
for (const pr of candidatePrs) {
|
|
84
|
+
const matches = owners.get(pr.number) ?? [];
|
|
85
|
+
if (incompleteOwnerPrs.has(pr.number) || matches.length !== 1 || !/^[a-f0-9]{40}$/i.test(pr.headRefOid ?? '')) { excluded.add(pr.number); continue; }
|
|
86
|
+
const owner = matches[0]!;
|
|
87
|
+
if (owner.branch !== pr.headRefName || !owner.terminal || !/^[a-f0-9]{40}$/i.test(owner.headCommit)
|
|
88
|
+
|| active.has(owner.runId) || [...(branchRuns.get(pr.headRefName) ?? [])].some(id => id !== owner.runId)) {
|
|
89
|
+
excluded.add(pr.number); continue;
|
|
90
|
+
}
|
|
91
|
+
const remote = command('git', ['ls-remote', 'origin', `refs/heads/${pr.headRefName}`], repoRoot).trim().split(/\s/)[0];
|
|
92
|
+
if (remote !== pr.headRefOid) { excluded.add(pr.number); continue; }
|
|
93
|
+
let proven = owner.headCommit;
|
|
94
|
+
for (const row of prior.filter(row => row.pr === pr.number && row.head === pr.headRefName && row.pushed)) {
|
|
95
|
+
if (row.beforeHead !== proven || !/^[a-f0-9]{40}$/i.test(row.afterHead ?? '')) { proven = ''; break; }
|
|
96
|
+
proven = row.afterHead!;
|
|
97
|
+
}
|
|
98
|
+
if (proven !== remote) excluded.add(pr.number);
|
|
99
|
+
}
|
|
100
|
+
return excluded;
|
|
101
|
+
} catch { return null; }
|
|
40
102
|
}
|
|
41
103
|
|
|
42
104
|
function command(file: string, args: string[], cwd: string, timeout = 60_000): string {
|
|
@@ -51,6 +113,15 @@ function changedTests(gh: (args: string[]) => string, number: number): string[]
|
|
|
51
113
|
path.endsWith('.test.ts') && !isAbsolute(path) && path !== '' && !path.split('/').some(part => part === '..' || part === '.' || part === '')))];
|
|
52
114
|
}
|
|
53
115
|
|
|
116
|
+
function listOpenPrs(gh: (args: string[]) => string): OpenPr[] {
|
|
117
|
+
const observed: unknown = JSON.parse(gh(['pr', 'list', '--state', 'open', '--json', 'number,headRefName,headRefOid,mergeable,isDraft,labels', '--limit', '1000']));
|
|
118
|
+
if (!Array.isArray(observed) || observed.length >= 1000 || observed.some(pr => !pr || !Number.isSafeInteger(pr.number)
|
|
119
|
+
|| typeof pr.headRefName !== 'string' || typeof pr.mergeable !== 'string' || typeof pr.isDraft !== 'boolean'
|
|
120
|
+
|| !Array.isArray(pr.labels) || pr.labels.some((label: unknown) => !label || typeof label !== 'object' || typeof (label as { name?: unknown }).name !== 'string')))
|
|
121
|
+
throw new Error('incomplete or invalid PR observation');
|
|
122
|
+
return observed as OpenPr[];
|
|
123
|
+
}
|
|
124
|
+
|
|
54
125
|
// A PR test must not inherit credentials, reach the network or write outside its own worktree.
|
|
55
126
|
// If the kernel does not provide the required isolation, fail closed before starting bun.
|
|
56
127
|
const TEST_SANDBOX = `import ctypes, os, sys
|
|
@@ -145,16 +216,16 @@ export async function runResyncShadow(max = 3, deps: ResyncShadowDeps = {}, mode
|
|
|
145
216
|
if (mode !== 'shadow' && mode !== 'live') throw new Error('mode must be shadow or live');
|
|
146
217
|
const repoRoot = deps.repoRoot ?? resolve(import.meta.dir, '../../..');
|
|
147
218
|
const gh = deps.runGh ?? ((args: string[]) => command('gh', args, repoRoot));
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
219
|
+
const eligible = listOpenPrs(gh).filter(pr => pr.headRefName.startsWith('self-impl/')
|
|
220
|
+
&& (mode === 'shadow' ? pr.mergeable === 'CONFLICTING' : pr.mergeable === 'MERGEABLE')
|
|
221
|
+
&& (mode === 'shadow' || pr.labels.some(label => label.name === PR_LABEL_NAMES.needsRebase))
|
|
222
|
+
&& !pr.labels.some(label => label.name === PR_LABEL_NAMES.running)
|
|
223
|
+
&& !pr.labels.some(label => label.name === PR_LABEL_NAMES.stalled || label.name === PR_LABEL_NAMES.superseded));
|
|
224
|
+
const observeActive = deps.activePrNumbers ?? ((numbers: readonly number[]) => activePrNumbers(
|
|
225
|
+
eligible.filter(pr => numbers.includes(pr.number)), repoRoot, deps.instanceRoot ?? effectiveInstanceRoot()));
|
|
226
|
+
const active = mode === 'live' && eligible.length ? observeActive(eligible.map(pr => pr.number)) : new Set<number>();
|
|
227
|
+
if (active === null) throw new Error('active run observation unavailable — resync stays read-only');
|
|
228
|
+
const candidates = eligible.filter(pr => !active.has(pr.number)).sort((a, b) => a.number - b.number).slice(0, max);
|
|
158
229
|
const ledger = join(deps.instanceRoot ?? effectiveInstanceRoot(), 'orchestrator', 'resync-shadow.jsonl');
|
|
159
230
|
let saved = 0;
|
|
160
231
|
let tried = 0;
|
|
@@ -169,6 +240,9 @@ export async function runResyncShadow(max = 3, deps: ResyncShadowDeps = {}, mode
|
|
|
169
240
|
// Explicit destination refspecs make origin/<head> and origin/main fresh even without remote.origin.fetch.
|
|
170
241
|
command('git', ['fetch', 'origin', `+refs/heads/${pr.headRefName}:refs/remotes/origin/${pr.headRefName}`,
|
|
171
242
|
'+refs/heads/main:refs/remotes/origin/main'], repoRoot);
|
|
243
|
+
entry.beforeHead = command('git', ['rev-parse', `origin/${pr.headRefName}`], repoRoot).trim();
|
|
244
|
+
if (mode === 'live' && !deps.activePrNumbers && entry.beforeHead !== pr.headRefOid)
|
|
245
|
+
throw new Error('PR head changed after owner proof — resync stays read-only');
|
|
172
246
|
entry.testFiles = changedTests(gh, pr.number);
|
|
173
247
|
tmp = realpathSync(mkdtempSync(join(tmpdir(), 'resync-shadow-')));
|
|
174
248
|
command('git', ['worktree', 'add', '--detach', tmp, `origin/${pr.headRefName}`], repoRoot);
|
|
@@ -189,10 +263,24 @@ export async function runResyncShadow(max = 3, deps: ResyncShadowDeps = {}, mode
|
|
|
189
263
|
} else entry.verdict = outcome.status === 'conflict-unresolved' || outcome.status === 'up-to-date' ? 'unresolved' : 'error';
|
|
190
264
|
if (mode === 'live' && entry.verdict === 'saved') {
|
|
191
265
|
try {
|
|
266
|
+
const lateActive = observeActive([pr.number]);
|
|
267
|
+
if (lateActive === null || lateActive.has(pr.number))
|
|
268
|
+
throw new Error('PR ownership changed before push — resync stays read-only');
|
|
269
|
+
const current = listOpenPrs(gh).filter(row => row.number === pr.number);
|
|
270
|
+
if (current.length !== 1 || current[0]!.headRefName !== pr.headRefName
|
|
271
|
+
|| current[0]!.headRefOid !== pr.headRefOid || current[0]!.mergeable !== 'MERGEABLE'
|
|
272
|
+
|| !current[0]!.labels.some(label => label.name === PR_LABEL_NAMES.needsRebase)
|
|
273
|
+
|| current[0]!.labels.some(label => label.name === PR_LABEL_NAMES.running
|
|
274
|
+
|| label.name === PR_LABEL_NAMES.stalled || label.name === PR_LABEL_NAMES.superseded))
|
|
275
|
+
throw new Error('PR state changed before push — resync stays read-only');
|
|
276
|
+
const immediateHead = command('git', ['ls-remote', 'origin', `refs/heads/${pr.headRefName}`], repoRoot).trim().split(/\s/)[0];
|
|
277
|
+
if (immediateHead !== entry.beforeHead)
|
|
278
|
+
throw new Error('remote head changed before push — resync stays read-only');
|
|
192
279
|
(deps.runGit ?? (args => { command('git', args, tmp!); }))(
|
|
193
280
|
['push', 'origin', `HEAD:refs/heads/${pr.headRefName}`]);
|
|
194
281
|
entry.pushed = true;
|
|
195
|
-
|
|
282
|
+
entry.afterHead = command('git', ['rev-parse', 'HEAD'], tmp).trim();
|
|
283
|
+
gh(['pr', 'edit', String(pr.number), '--remove-label', PR_LABEL_NAMES.needsRebase]);
|
|
196
284
|
entry.labelRemoved = true;
|
|
197
285
|
} catch (error) {
|
|
198
286
|
const message = error instanceof Error ? error.message : String(error);
|