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
package/src/cli/pr-cli.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
1
|
+
import { existsSync, realpathSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
2
2
|
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
3
|
+
import { loadavg } from 'node:os';
|
|
3
4
|
import { createInterface } from 'node:readline';
|
|
4
5
|
import type { Command } from 'commander';
|
|
5
6
|
import {
|
|
@@ -58,7 +59,10 @@ import { parseReleaseNoteSection } from '../release-loop/release-note.js';
|
|
|
58
59
|
import { landingFreezeMessage } from '../release-loop/landing-freeze.js';
|
|
59
60
|
import { admitLandingMerge } from '../self-implement/frozen-merges.js';
|
|
60
61
|
import { verifyAncestorAutoPass, verifyOverlapEvidence } from './pr-land-overlap-evidence.js';
|
|
62
|
+
import { observePrLandRefusal } from './pr-land-refusal.js';
|
|
63
|
+
import { ensurePrLandHeavyRemote, type HeavyRemoteInput, type HeavyRemoteResult } from './pr-land-heavy-remote.js';
|
|
61
64
|
import { taskAgentStatePath } from '../task-agent/task-hand.js';
|
|
65
|
+
import { PR_LABEL_NAMES } from '../github/pr-labels.js';
|
|
62
66
|
import { enqueueL8ShadowQueue, runL8ShadowQueue, shadowPrNumber, statusL8ShadowQueue, type L8ShadowQueueDeps } from '../self-implement/l8-merge-queue.js';
|
|
63
67
|
|
|
64
68
|
export { branchLineageSlug, findSiblingPrs };
|
|
@@ -87,6 +91,8 @@ export interface PrLandOpts {
|
|
|
87
91
|
allowPublicLeak?: boolean;
|
|
88
92
|
/** Pinned landing only: JSON evidence (rebased · re-gated · reviewed head) that replaces the unavailable non-interactive overlap approval. */
|
|
89
93
|
overlapEvidence?: string;
|
|
94
|
+
/** Pinned landing opt-in: run the heavy changed-file gate on node-b at the reviewed head and current main tip. */
|
|
95
|
+
heavyRemote?: boolean;
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
export interface PrGranularityOpts {
|
|
@@ -124,6 +130,8 @@ export interface PrLandDeps {
|
|
|
124
130
|
runPublicLeakGate?: (changedFiles: readonly string[], out: { log: (message: string) => void; error: (message: string) => void }) => number;
|
|
125
131
|
/** Test seam — the post-transform export leak check on changed files. */
|
|
126
132
|
runExportLeakCheck?: (changedFiles: readonly string[], cwd: string) => ExportLeakCheck;
|
|
133
|
+
/** Test seam — local 1-minute and 5-minute load around a heavy remote gate. Default `os.loadavg`. */
|
|
134
|
+
loadavg?: () => readonly [number, number, number];
|
|
127
135
|
/** Test seam — included files must not import a module the public export excludes. */
|
|
128
136
|
runExportImportCheck?: (changedFiles: readonly string[], cwd: string) => ExportImportCheck | Promise<ExportImportCheck>;
|
|
129
137
|
/** 공개 문서의 `elanous …` 호출 ↔ 실제 `--help` 대조(경고 전용) — 바뀐 공개 문서 경로를 받아 어긋남 목록을 돌려준다. */
|
|
@@ -137,6 +145,7 @@ export interface PrLandDeps {
|
|
|
137
145
|
/** iOS 시험 게이트 심(시험 주입용). */
|
|
138
146
|
runIosGate?: (out: { log: (message: string) => void; error: (message: string) => void }, changedFiles: readonly string[]) => boolean;
|
|
139
147
|
runPwaGate?: (out: { log: (message: string) => void; error: (message: string) => void }, changedFiles: readonly string[]) => boolean;
|
|
148
|
+
runHeavyRemote?: (input: HeavyRemoteInput) => HeavyRemoteResult;
|
|
140
149
|
isInteractive?: () => boolean;
|
|
141
150
|
/** Clock for the recent-landings window (test seam · default Date.now). */
|
|
142
151
|
now?: () => number;
|
|
@@ -1143,8 +1152,47 @@ export function runPrGranularity(opts: PrGranularityOpts = {}, deps: PrLandDeps
|
|
|
1143
1152
|
const GITHUB_MERGEABLE = new Set(['MERGEABLE', 'CONFLICTING', 'UNKNOWN']);
|
|
1144
1153
|
const GITHUB_MERGE_STATE = new Set(['BEHIND', 'BLOCKED', 'CLEAN', 'DIRTY', 'DRAFT', 'HAS_HOOKS', 'UNKNOWN', 'UNSTABLE']);
|
|
1145
1154
|
|
|
1155
|
+
/** Read-only identity check shared by pinned landing and its dry-run. Later landing gates still run only on a real landing. */
|
|
1156
|
+
function inspectPinnedPr(run: CmdRunner, cwd: string, pr: number, expectedHead: string, requireMainBase = false) {
|
|
1157
|
+
const viewed = run('gh', ['pr', 'view', String(pr), '--json', 'headRefOid,headRefName,baseRefName,state,isDraft,url'], { cwd });
|
|
1158
|
+
let value: { headRefOid?: string; headRefName?: string; baseRefName?: string; state?: string; isDraft?: boolean; url?: string } = {};
|
|
1159
|
+
try {
|
|
1160
|
+
if (viewed.ok) {
|
|
1161
|
+
const parsed: unknown = JSON.parse(viewed.out);
|
|
1162
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) value = parsed as typeof value;
|
|
1163
|
+
}
|
|
1164
|
+
} catch { /* unreadable is not approval */ }
|
|
1165
|
+
const local = run('git', ['rev-parse', 'HEAD'], { cwd });
|
|
1166
|
+
const dirty = run('git', ['status', '--porcelain'], { cwd });
|
|
1167
|
+
const reasons: string[] = [];
|
|
1168
|
+
if (value.state !== 'OPEN') reasons.push('PR is not OPEN or its state is unavailable');
|
|
1169
|
+
if (value.isDraft !== false) reasons.push(value.isDraft === true ? 'PR is draft' : 'PR ready status is unavailable');
|
|
1170
|
+
if (value.headRefOid?.toLowerCase() !== expectedHead.toLowerCase()) reasons.push('PR head differs from --expected-head or is unavailable');
|
|
1171
|
+
if (!value.url?.endsWith(`/pull/${pr}`) || !value.headRefName) reasons.push('PR identity or head branch is unavailable');
|
|
1172
|
+
// Heavy-remote evidence is an exact head/main pair. A retarget, or an unreadable base, is not that pair.
|
|
1173
|
+
if (requireMainBase && value.baseRefName !== 'main') reasons.push(value.baseRefName ? `PR base is ${value.baseRefName}, not main` : 'PR base is unavailable');
|
|
1174
|
+
if (!local.ok || local.out.trim().toLowerCase() !== expectedHead.toLowerCase()) reasons.push('local HEAD differs from --expected-head or is unavailable');
|
|
1175
|
+
if (!dirty.ok || dirty.out.trim()) reasons.push(dirty.ok ? 'local worktree is dirty' : 'local worktree status is unavailable');
|
|
1176
|
+
return { ok: reasons.length === 0, reasons, branch: value.headRefName, url: value.url, baseRefName: value.baseRefName };
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1146
1179
|
export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): Promise<number> {
|
|
1147
1180
|
const out = deps.out ?? liveOut;
|
|
1181
|
+
const landStartedAt = Date.now();
|
|
1182
|
+
const stage = (name: string, startedAt: number, ok: boolean, extra: Record<string, unknown> = {}): void => {
|
|
1183
|
+
if (!opts.heavyRemote) return;
|
|
1184
|
+
debug.log('pr.land', 'stage-timing', {
|
|
1185
|
+
pr: Number(opts.pr), stage: name, startedAt: new Date(startedAt).toISOString(),
|
|
1186
|
+
endedAt: new Date().toISOString(), elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
1187
|
+
totalElapsedMs: Math.max(0, Date.now() - landStartedAt), ok, ...extra,
|
|
1188
|
+
});
|
|
1189
|
+
};
|
|
1190
|
+
// First slice: observe pinned identity/branch, overlap decision, and GitHub merge refusals.
|
|
1191
|
+
// Option syntax and prerequisite gate errors do not describe a merge recovery edge.
|
|
1192
|
+
const refuse = (message: string, context: { isDraft?: boolean } = {}): void => {
|
|
1193
|
+
out.error(message);
|
|
1194
|
+
observePrLandRefusal(message, context);
|
|
1195
|
+
};
|
|
1148
1196
|
if (opts.title !== undefined && opts.titleFile !== undefined) {
|
|
1149
1197
|
out.error('✗ title: --title과 --title-file은 함께 사용할 수 없습니다.');
|
|
1150
1198
|
return 1;
|
|
@@ -1165,6 +1213,10 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1165
1213
|
out.error('✗ active-run-files: --include-active-run-files와 --exclude-active-run-files는 함께 사용할 수 없습니다.');
|
|
1166
1214
|
return 1;
|
|
1167
1215
|
}
|
|
1216
|
+
if (opts.heavyRemote && (opts.pr === undefined || opts.expectedHead === undefined || opts.hold)) {
|
|
1217
|
+
out.error('✗ heavy-remote: --pr ⊕ --expected-head 머리 고정 착지에서만 쓴다.');
|
|
1218
|
+
return 1;
|
|
1219
|
+
}
|
|
1168
1220
|
|
|
1169
1221
|
const readFile = deps.readFile ?? ((path: string) => readFileSync(path, 'utf8'));
|
|
1170
1222
|
let title = opts.title;
|
|
@@ -1248,6 +1300,31 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1248
1300
|
out.log('- Mutations (ready/edit/create/merge, git commit/push, worktree): NOT RUN');
|
|
1249
1301
|
return 0;
|
|
1250
1302
|
}
|
|
1303
|
+
if (opts.dryRun && pinned) {
|
|
1304
|
+
const pr = Number(opts.pr);
|
|
1305
|
+
if (!/^[1-9]\d*$/.test(opts.pr ?? '') || !Number.isSafeInteger(pr) || !/^[a-f0-9]{40}$/i.test(opts.expectedHead ?? '')) {
|
|
1306
|
+
out.error('✗ expected-head: --pr and --expected-head (full SHA) are required together without --hold');
|
|
1307
|
+
return 1;
|
|
1308
|
+
}
|
|
1309
|
+
if (opts.hold) {
|
|
1310
|
+
out.error('✗ dry-run: --hold 는 머리 고정 읽기 전용 예행과 함께 사용할 수 없습니다.');
|
|
1311
|
+
return 1;
|
|
1312
|
+
}
|
|
1313
|
+
if (opts.overlapEvidence !== undefined) {
|
|
1314
|
+
out.error('✗ dry-run: --overlap-evidence 는 머리 고정 읽기 전용 예행에서 사용할 수 없습니다.');
|
|
1315
|
+
return 1;
|
|
1316
|
+
}
|
|
1317
|
+
const inspected = inspectPinnedPr(run, cwd, pr, opts.expectedHead!);
|
|
1318
|
+
const branch = (deps.currentBranch ?? liveCurrentBranch)(cwd);
|
|
1319
|
+
const reasons = [...inspected.reasons];
|
|
1320
|
+
if (!branch || branch !== inspected.branch) reasons.push('current branch differs from the PR head branch or is unavailable');
|
|
1321
|
+
out.log(`[dry-run] pinned PR #${pr} · expected head ${opts.expectedHead}`);
|
|
1322
|
+
for (const reason of reasons) out.log(`[dry-run] ✗ preflight: ${reason}`);
|
|
1323
|
+
if (reasons.includes('PR is draft')) out.log(`[dry-run] 선행: eln gh pr ready ${pr}`);
|
|
1324
|
+
if (reasons.length === 0) out.log('[dry-run] ✓ preflight: PR OPEN non-draft, matching PR/local HEAD and branch, clean worktree');
|
|
1325
|
+
out.log('[dry-run] Remaining landing gates, freeze, overlap and merge: UNMEASURED; no PR or git state changed.');
|
|
1326
|
+
return reasons.length === 0 ? 0 : 1;
|
|
1327
|
+
}
|
|
1251
1328
|
if (opts.overlapEvidence !== undefined && (!pinned || !opts.overlapEvidence.trim())) {
|
|
1252
1329
|
out.error('✗ overlap-evidence: --overlap-evidence <file> 는 --pr ⊕ --expected-head 머리 고정 착지에서만 쓴다.');
|
|
1253
1330
|
return 1;
|
|
@@ -1256,30 +1333,29 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1256
1333
|
let pinnedUrl: string | undefined;
|
|
1257
1334
|
if (pinned) {
|
|
1258
1335
|
const pr = Number(opts.pr);
|
|
1259
|
-
if (!/^[1-9]\d*$/.test(opts.pr ?? '') || !Number.isSafeInteger(pr) || !/^[a-f0-9]{40}$/i.test(opts.expectedHead ?? '') || opts.hold
|
|
1260
|
-
out.error('✗ expected-head: --pr and --expected-head (full SHA) are required together without --hold
|
|
1336
|
+
if (!/^[1-9]\d*$/.test(opts.pr ?? '') || !Number.isSafeInteger(pr) || !/^[a-f0-9]{40}$/i.test(opts.expectedHead ?? '') || opts.hold) {
|
|
1337
|
+
out.error('✗ expected-head: --pr and --expected-head (full SHA) are required together without --hold');
|
|
1261
1338
|
return 1;
|
|
1262
1339
|
}
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
out.error('✗ expected-head: PR OPEN non-draft, matching local HEAD and clean worktree required');
|
|
1340
|
+
const inspected = inspectPinnedPr(run, cwd, pr, opts.expectedHead!, opts.heavyRemote === true);
|
|
1341
|
+
if (!inspected.ok) {
|
|
1342
|
+
const baseReason = inspected.reasons.find((reason) => reason.startsWith('PR base'));
|
|
1343
|
+
refuse(baseReason
|
|
1344
|
+
? `✗ heavy-remote: ${baseReason} — 재타기팅된 PR은 통과한 head/main 쌍이 아니다. 병합하지 않는다.`
|
|
1345
|
+
: '✗ expected-head: PR OPEN non-draft, matching local HEAD and clean worktree required', {
|
|
1346
|
+
isDraft: inspected.reasons.includes('PR is draft'),
|
|
1347
|
+
});
|
|
1272
1348
|
return 1;
|
|
1273
1349
|
}
|
|
1274
|
-
pinnedBranch =
|
|
1275
|
-
pinnedUrl =
|
|
1350
|
+
pinnedBranch = inspected.branch;
|
|
1351
|
+
pinnedUrl = inspected.url;
|
|
1276
1352
|
}
|
|
1277
1353
|
const resolveBase = deps.resolveBase ?? resolveDeliverableBase;
|
|
1278
1354
|
const branch = (deps.currentBranch ?? liveCurrentBranch)(cwd);
|
|
1279
1355
|
if (!branch || (pinned && branch !== pinnedBranch)) {
|
|
1280
1356
|
const detail = pinned ? 'PR head branch와 현재 브랜치가 다릅니다.' : '현재 브랜치를 해석하지 못했습니다.';
|
|
1281
1357
|
record('branch', false);
|
|
1282
|
-
|
|
1358
|
+
refuse(`✗ branch: ${detail}`);
|
|
1283
1359
|
return 1;
|
|
1284
1360
|
}
|
|
1285
1361
|
record('branch', true);
|
|
@@ -1491,7 +1567,238 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1491
1567
|
}
|
|
1492
1568
|
}
|
|
1493
1569
|
|
|
1494
|
-
const
|
|
1570
|
+
const currentMain = (): string | undefined => {
|
|
1571
|
+
// The landing pair names the remote's current tip, not a possibly stale tracking ref.
|
|
1572
|
+
const fetched = run('git', ['fetch', '--quiet', 'origin', 'main'], { cwd });
|
|
1573
|
+
if (!fetched.ok) return undefined;
|
|
1574
|
+
const tip = run('git', ['rev-parse', '--verify', 'origin/main'], { cwd });
|
|
1575
|
+
return tip.ok && /^[a-f0-9]{40}$/i.test(tip.out.trim()) ? tip.out.trim() : undefined;
|
|
1576
|
+
};
|
|
1577
|
+
const currentPinnedBase = (): string | undefined => {
|
|
1578
|
+
if (opts.heavyRemote) return currentMain();
|
|
1579
|
+
const ref = resolveRemoteBranchRef(run, cwd, base);
|
|
1580
|
+
const fetched = run('git', ['fetch', '--quiet', ref.remote, ref.branch], { cwd });
|
|
1581
|
+
if (!fetched.ok) return undefined;
|
|
1582
|
+
const tip = run('git', ['rev-parse', '--verify', `${ref.remote}/${ref.branch}`], { cwd });
|
|
1583
|
+
return tip.ok && /^[a-f0-9]{40}$/i.test(tip.out.trim()) ? tip.out.trim() : undefined;
|
|
1584
|
+
};
|
|
1585
|
+
let overlapCheckedBase: string | undefined;
|
|
1586
|
+
if (pinned) {
|
|
1587
|
+
overlapCheckedBase = currentPinnedBase();
|
|
1588
|
+
if (!overlapCheckedBase) {
|
|
1589
|
+
out.error(`✗ overlap-preflight: ${base} 최신 SHA를 가져오지 못했다. 겹침 조상을 판정하지 않고 착지하지 않는다.`);
|
|
1590
|
+
return 1;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
// Pinned landings reject a known non-ancestor before local or remote heavy gates.
|
|
1594
|
+
// Unpinned landings keep their existing gate and advisory order.
|
|
1595
|
+
let changedPaths = pinned ? currentChangePaths(run, cwd, staged, base, out) : [];
|
|
1596
|
+
let hold = !!opts.hold;
|
|
1597
|
+
const checkOverlap = async (): Promise<number | undefined> => {
|
|
1598
|
+
const overlappingLandings: string[] = [];
|
|
1599
|
+
const overlapFound = emitLandingOverlapAdvisory(run, cwd, base, changedPaths, out, overlappingLandings);
|
|
1600
|
+
const siblingFound = emitSiblingPrAdvisory(
|
|
1601
|
+
branch,
|
|
1602
|
+
deps.listOpenPrs ?? (() => lookupOpenPrs(run, cwd)),
|
|
1603
|
+
out,
|
|
1604
|
+
);
|
|
1605
|
+
const advisoryShown = recentAdvisoryShown || overlapFound || siblingFound;
|
|
1606
|
+
const reason = opts.landReason;
|
|
1607
|
+
const landReasonNotice = formatLandReasonNotice({ reason, advisoryShown });
|
|
1608
|
+
if (landReasonNotice) out.log(landReasonNotice);
|
|
1609
|
+
record('land-reason', true, {
|
|
1610
|
+
advisoryShown,
|
|
1611
|
+
hasReason: !!reason,
|
|
1612
|
+
reasonLength: reason ? codePointLength(reason) : 0,
|
|
1613
|
+
reasonLengthUnit: 'codepoint',
|
|
1614
|
+
});
|
|
1615
|
+
let overlapDecision: OverlapLandingDecision | undefined;
|
|
1616
|
+
if (overlapFound && !opts.hold && !opts.dryRun) {
|
|
1617
|
+
overlapDecision = await (deps.decideOverlapLanding ?? (() => decideOverlapLanding({
|
|
1618
|
+
isInteractive: deps.isInteractive,
|
|
1619
|
+
requestConfirmation: deps.requestConfirmation,
|
|
1620
|
+
channels: deps.overlapConfirmChannels,
|
|
1621
|
+
timeoutMs: deps.overlapConfirmTimeoutMs,
|
|
1622
|
+
})))();
|
|
1623
|
+
record('overlap-decision', true, {
|
|
1624
|
+
outcome: overlapDecision.outcome,
|
|
1625
|
+
channel: overlapDecision.channel,
|
|
1626
|
+
interactive: overlapDecision.interactive,
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
hold = !!opts.hold || overlapDecision?.outcome === 'user-hold';
|
|
1630
|
+
// TA-LAND-OVERLAP — 비대화형 «승인 불가»만 증거로 대신한다(사람의 hold 는 증거로 뒤집지 않는다) · 증거가 없거나 어긋나면 종전 거부 그대로.
|
|
1631
|
+
let overlapEvidenceAccepted = false;
|
|
1632
|
+
let ancestorResyncNeeded = false;
|
|
1633
|
+
if (pinned && overlapDecision?.outcome === 'unavailable' && opts.overlapEvidence !== undefined) {
|
|
1634
|
+
const ref = resolveRemoteBranchRef(run, cwd, base);
|
|
1635
|
+
const verdict = verifyOverlapEvidence({
|
|
1636
|
+
evidencePath: opts.overlapEvidence, pr: Number(opts.pr), expectedHead: opts.expectedHead!,
|
|
1637
|
+
remote: ref.remote, branch: ref.branch, cwd, run, readFile,
|
|
1638
|
+
reviewResultsDir: deps.reviewResultsDir ?? join(dirname(taskAgentStatePath()), 'review-results'),
|
|
1639
|
+
listDir: (dir) => readdirSync(dir), reviewMtime: (path) => statSync(path).mtimeMs,
|
|
1640
|
+
reviewRealPath: (path) => realpathSync(path), overlappingLandings,
|
|
1641
|
+
});
|
|
1642
|
+
overlapEvidenceAccepted = verdict.ok;
|
|
1643
|
+
if (verdict.ok) {
|
|
1644
|
+
out.log(verdict.mode === 'already-ancestor'
|
|
1645
|
+
? `✓ overlap-evidence: already-ancestor — 겹친 최근 착지 ${overlappingLandings.length}개가 전부 head ${opts.expectedHead!.slice(0, 12)} 의 조상 · review pass must-fix 0 (${verdict.reviewResult})`
|
|
1646
|
+
: verdict.mode === 'base-advanced-disjoint'
|
|
1647
|
+
? `✓ overlap-evidence: base-advanced-disjoint — gate base ${verdict.gateBase.slice(0, 12)} ⊂ head ${opts.expectedHead!.slice(0, 12)} · ${ref.remote}/${ref.branch} ${verdict.baseTip.slice(0, 12)} 까지 ${verdict.windowCommits}개 커밋이 PR 파일을 안 건드린다 · review pass|warn must-fix 0 (${verdict.reviewResult})`
|
|
1648
|
+
: `✓ overlap-evidence: ${ref.remote}/${ref.branch} ${verdict.baseTip.slice(0, 12)} ⊂ head ${opts.expectedHead!.slice(0, 12)} · gate passed on that base · review pass must-fix 0 (${verdict.reviewResult})`);
|
|
1649
|
+
}
|
|
1650
|
+
else refuse(`✗ overlap-evidence: ${verdict.reason}`);
|
|
1651
|
+
} else if (pinned && overlapDecision?.outcome === 'unavailable') {
|
|
1652
|
+
// 증거 파일이 없을 때 — 겹친 착지가 전부 머리의 조상이고 표준 자리의 리뷰가 pass|warn ⊕ must-fix 0 이면 통과(아니면 종전 거부).
|
|
1653
|
+
const verdict = verifyAncestorAutoPass({
|
|
1654
|
+
pr: Number(opts.pr), expectedHead: opts.expectedHead!, cwd, run, readFile, overlappingLandings,
|
|
1655
|
+
reviewResultsDir: deps.reviewResultsDir ?? join(dirname(taskAgentStatePath()), 'review-results'),
|
|
1656
|
+
listDir: (dir) => readdirSync(dir),
|
|
1657
|
+
});
|
|
1658
|
+
overlapEvidenceAccepted = verdict.ok;
|
|
1659
|
+
if (verdict.ok) {
|
|
1660
|
+
out.log(`✓ overlap-evidence: already-ancestor-auto — 겹친 최근 착지 ${overlappingLandings.length}개가 전부 head ${opts.expectedHead!.slice(0, 12)} 의 조상 · review pass|warn must-fix 0 (${verdict.reviewResult})`);
|
|
1661
|
+
}
|
|
1662
|
+
else {
|
|
1663
|
+
refuse(`✗ ancestor-auto: ${verdict.reason}`);
|
|
1664
|
+
ancestorResyncNeeded = verdict.reason.startsWith('ancestor-auto-not-ancestor:');
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
if (pinned && overlapDecision && overlapDecision.outcome !== 'user-merge' && !overlapEvidenceAccepted) {
|
|
1668
|
+
// A clean GitHub PR can still be behind a recently landed overlapping head. Preserve the cue
|
|
1669
|
+
// across hosts; the current steward tick acts only if it can also prove local run ownership.
|
|
1670
|
+
if (ancestorResyncNeeded && !opts.dryRun) {
|
|
1671
|
+
const marked = run('gh', ['pr', 'edit', String(opts.pr), '--add-label', PR_LABEL_NAMES.needsRebase], { cwd });
|
|
1672
|
+
record('resync-marker', marked.ok, { pr: Number(opts.pr), reason: 'ancestor-auto-not-ancestor' });
|
|
1673
|
+
if (!marked.ok) out.error('⚠ resync-marker: needs-rebase 라벨을 남기지 못했습니다');
|
|
1674
|
+
}
|
|
1675
|
+
out.error('✗ expected-head: overlap merge approval unavailable for the reviewed head');
|
|
1676
|
+
return 1;
|
|
1677
|
+
}
|
|
1678
|
+
return undefined;
|
|
1679
|
+
};
|
|
1680
|
+
if (pinned && (await checkOverlap()) !== undefined) return 1;
|
|
1681
|
+
|
|
1682
|
+
|
|
1683
|
+
const readLoad = deps.loadavg ?? loadavg;
|
|
1684
|
+
// gh pr merge pins only the PR head. A long gate — and the UNKNOWN merge wait — can
|
|
1685
|
+
// outlive the base it measured, so re-read origin/main after every gate and rerun until
|
|
1686
|
+
// the pair is stable. The bound fails closed; it is not an atomic base pin GitHub does not expose.
|
|
1687
|
+
const HEAVY_BASE_STABILITY_RETRIES = 3;
|
|
1688
|
+
let heavyInterferenceMeasured: boolean | null = null;
|
|
1689
|
+
let heavyGateHost: string | undefined;
|
|
1690
|
+
const heavyGate = (main: string, phase: 'initial' | 'late-recheck' | 'post-merge'): HeavyRemoteResult | undefined => {
|
|
1691
|
+
const before = readLoad();
|
|
1692
|
+
const started = Date.now();
|
|
1693
|
+
const verdict = (deps.runHeavyRemote ?? ensurePrLandHeavyRemote)({
|
|
1694
|
+
pr: Number(opts.pr), head: opts.expectedHead!, main, repo: cwd,
|
|
1695
|
+
});
|
|
1696
|
+
if (verdict.ok) {
|
|
1697
|
+
heavyGateHost = verdict.host;
|
|
1698
|
+
heavyInterferenceMeasured = verdict.interferenceMeasured ?? null;
|
|
1699
|
+
if (heavyInterferenceMeasured === false) out.error(`⚠ test-interference-gate: ${verdict.host ?? 'remote'} 검사 미측정 — 경고 전용이므로 착지는 계속한다.`);
|
|
1700
|
+
if (heavyInterferenceMeasured === null) out.error(`⚠ test-interference-gate: ${verdict.host ?? 'remote'} 검사 상태 미상 — 경고 전용이므로 착지는 계속한다.`);
|
|
1701
|
+
}
|
|
1702
|
+
const after = readLoad();
|
|
1703
|
+
// One paired observation per gate, including a late rerun after main moved.
|
|
1704
|
+
// These are the local mbp loads around the remote call, not a load sample from the selected host.
|
|
1705
|
+
debug.log('pr.land', 'heavy-remote-load', {
|
|
1706
|
+
pr: Number(opts.pr), head: opts.expectedHead, main, host: verdict.host ?? null, attemptedHost: verdict.attemptedHost ?? null, phase,
|
|
1707
|
+
elapsedMs: Math.max(0, Date.now() - started), gateElapsedMs: verdict.elapsedMs,
|
|
1708
|
+
mbpLoad1Before: before[0], mbpLoad5Before: before[1],
|
|
1709
|
+
mbpLoad1After: after[0], mbpLoad5After: after[1],
|
|
1710
|
+
source: verdict.source, ok: verdict.ok,
|
|
1711
|
+
});
|
|
1712
|
+
record('heavy-remote', verdict.ok, {
|
|
1713
|
+
host: verdict.host ?? null, attemptedHost: verdict.attemptedHost ?? null, head: opts.expectedHead, main, phase, source: verdict.source,
|
|
1714
|
+
elapsedMs: verdict.elapsedMs, reason: verdict.reason, rootPlan: verdict.rootPlan ?? null,
|
|
1715
|
+
});
|
|
1716
|
+
stage(`heavy-remote-${phase}`, started, verdict.ok, { head: opts.expectedHead, main, source: verdict.source });
|
|
1717
|
+
return verdict;
|
|
1718
|
+
};
|
|
1719
|
+
let verifiedHeavyBase: string | undefined;
|
|
1720
|
+
if (opts.heavyRemote) {
|
|
1721
|
+
const main = overlapCheckedBase!;
|
|
1722
|
+
const verdict = heavyGate(main, 'initial');
|
|
1723
|
+
if (!verdict?.ok) { out.error(`✗ heavy-remote: 원격 게이트 ${verdict?.reason ?? 'unmeasured'} — 로컬 게이트로 폴백하지 않는다.`); return 1; }
|
|
1724
|
+
verifiedHeavyBase = main;
|
|
1725
|
+
out.log(`✓ heavy-remote: host=${verdict.host ?? 'unknown'} head=${opts.expectedHead!.slice(0, 12)} main=${main.slice(0, 12)} source=${verdict.source} elapsed=${verdict.elapsedMs}ms`);
|
|
1726
|
+
out.log(`✓ typecheck-roots: ${JSON.stringify(verdict.rootPlan ?? { mode: 'not-applicable', roots: null, promoted: false, reason: 'no-root-plan-in-gate-output' })}`);
|
|
1727
|
+
}
|
|
1728
|
+
// Call immediately before the first mergePrOutcome and again before every UNKNOWN retry.
|
|
1729
|
+
// A move during the wait is the same race as a move during the gate: rerun or fail closed.
|
|
1730
|
+
// gh merge pins the head only. A retargeted PR would land on a branch the heavy gate never measured.
|
|
1731
|
+
// Unreadable baseRefName is not "main". Normal pr land (no --heavy-remote) does not use this check.
|
|
1732
|
+
const confirmHeavyPrBase = (): number | undefined => {
|
|
1733
|
+
if (!opts.heavyRemote) return undefined;
|
|
1734
|
+
const viewed = run('gh', ['pr', 'view', String(opts.pr), '--json', 'baseRefName,url'], { cwd });
|
|
1735
|
+
// JSON only. A bare "main" from another view (tests, --jq) is not this answer; unreadable is not main.
|
|
1736
|
+
let baseName = '';
|
|
1737
|
+
try {
|
|
1738
|
+
if (viewed.ok) {
|
|
1739
|
+
const parsed: unknown = JSON.parse(viewed.out);
|
|
1740
|
+
const name = parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
1741
|
+
? (parsed as { baseRefName?: unknown }).baseRefName : undefined;
|
|
1742
|
+
if (typeof name === 'string') baseName = name.trim();
|
|
1743
|
+
}
|
|
1744
|
+
} catch { /* unreadable is not main */ }
|
|
1745
|
+
if (baseName !== 'main') {
|
|
1746
|
+
record('heavy-remote-pr-base', false, { pr: Number(opts.pr), baseRefName: baseName || null });
|
|
1747
|
+
out.error(`✗ heavy-remote: PR base=${baseName || 'unreadable'} ≠ main — 재타기팅된 PR은 통과한 head/main 쌍이 아니다. 병합하지 않는다.`);
|
|
1748
|
+
return 1;
|
|
1749
|
+
}
|
|
1750
|
+
return undefined;
|
|
1751
|
+
};
|
|
1752
|
+
const recheckOverlapAtBase = async (currentBase: string): Promise<number | undefined> => {
|
|
1753
|
+
if (currentBase === overlapCheckedBase) return undefined;
|
|
1754
|
+
changedPaths = currentChangePaths(run, cwd, staged, base, out);
|
|
1755
|
+
const refused = await checkOverlap();
|
|
1756
|
+
if (refused !== undefined) return refused;
|
|
1757
|
+
overlapCheckedBase = currentBase;
|
|
1758
|
+
return undefined;
|
|
1759
|
+
};
|
|
1760
|
+
const confirmHeavyBaseStable = async (): Promise<number | undefined> => {
|
|
1761
|
+
if (!opts.heavyRemote) return undefined;
|
|
1762
|
+
const retargeted = confirmHeavyPrBase();
|
|
1763
|
+
if (retargeted !== undefined) return retargeted;
|
|
1764
|
+
let stable = false;
|
|
1765
|
+
for (let attempt = 0; attempt <= HEAVY_BASE_STABILITY_RETRIES; attempt += 1) {
|
|
1766
|
+
const main = currentMain();
|
|
1767
|
+
if (!main) { out.error('✗ heavy-remote: 병합 직전 origin/main SHA를 읽지 못했다.'); return 1; }
|
|
1768
|
+
if (main.toLowerCase() === verifiedHeavyBase?.toLowerCase()) { stable = true; break; }
|
|
1769
|
+
if (attempt === HEAVY_BASE_STABILITY_RETRIES) break;
|
|
1770
|
+
// A new overlap can deterministically refuse this head. Check the new base
|
|
1771
|
+
// before spending another remote gate on a pair that cannot land.
|
|
1772
|
+
const staleOverlap = await recheckOverlapAtBase(main);
|
|
1773
|
+
if (staleOverlap !== undefined) return staleOverlap;
|
|
1774
|
+
const verdict = heavyGate(main, 'late-recheck');
|
|
1775
|
+
if (!verdict?.ok) {
|
|
1776
|
+
out.error(`✗ heavy-remote: 병합 직전 원격 게이트 ${verdict?.reason ?? 'unmeasured'} — 로컬 게이트로 폴백하지 않는다.`);
|
|
1777
|
+
return 1;
|
|
1778
|
+
}
|
|
1779
|
+
verifiedHeavyBase = main;
|
|
1780
|
+
out.log(`✓ heavy-remote: merge-pair head=${opts.expectedHead!.slice(0, 12)} main=${main.slice(0, 12)} source=${verdict.source}`);
|
|
1781
|
+
}
|
|
1782
|
+
if (!stable) {
|
|
1783
|
+
out.error('✗ heavy-remote: origin/main 이 게이트 동안 계속 움직여 통과한 head/main 쌍으로 병합할 수 없다.');
|
|
1784
|
+
return 1;
|
|
1785
|
+
}
|
|
1786
|
+
// A late regate can take minutes. Re-read baseRefName after that wait and before success:
|
|
1787
|
+
// the pre-loop check is stale if the PR was retargeted while origin/main was being remeasured.
|
|
1788
|
+
const retargetedAfter = confirmHeavyPrBase();
|
|
1789
|
+
if (retargetedAfter !== undefined) return retargetedAfter;
|
|
1790
|
+
return undefined;
|
|
1791
|
+
};
|
|
1792
|
+
const confirmPinnedOverlapFresh = async (): Promise<number | undefined> => {
|
|
1793
|
+
if (!pinned) return undefined;
|
|
1794
|
+
const currentBase = opts.heavyRemote ? verifiedHeavyBase : currentPinnedBase();
|
|
1795
|
+
if (!currentBase) {
|
|
1796
|
+
out.error(`✗ overlap-preflight: 병합 직전 ${base} 최신 SHA를 가져오지 못했다.`);
|
|
1797
|
+
return 1;
|
|
1798
|
+
}
|
|
1799
|
+
return recheckOverlapAtBase(currentBase);
|
|
1800
|
+
};
|
|
1801
|
+
const typecheckOk = opts.heavyRemote || (deps.runTypecheckGate ?? ((o) => runPrLandTypecheckGate(o, cwd)))(out);
|
|
1495
1802
|
record('typecheck', typecheckOk);
|
|
1496
1803
|
if (!typecheckOk) {
|
|
1497
1804
|
// ⛔⭐ 「왜 막혔나」를 «단정하지 않는다» — 이 게이트는 불리언만 돌려주므로 여기서는 이유를 모른다.
|
|
@@ -1505,7 +1812,9 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1505
1812
|
out.error('✗ typecheck: scripts/ci-typecheck-changed.ts blocked pr land.');
|
|
1506
1813
|
return 1;
|
|
1507
1814
|
}
|
|
1508
|
-
out.log(
|
|
1815
|
+
out.log(opts.heavyRemote
|
|
1816
|
+
? '✓ typecheck: node-b exact-head heavy gate PASS — changed files have no new type errors.'
|
|
1817
|
+
: '✓ typecheck: scripts/ci-typecheck-changed.ts PASS — changed files have no new type errors.');
|
|
1509
1818
|
|
|
1510
1819
|
const isolation = gateVerdict('isolation-gate', deps.runIsolationGate ?? ((o) => runPrLandIsolationGate(o, cwd)), out);
|
|
1511
1820
|
// ⭐ 관측에 «잰 것»과 «못 잰 것»을 다른 값으로 남긴다 — 둘이 같은 모양이면 그 자는 거짓을 낸다.
|
|
@@ -1551,7 +1860,7 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1551
1860
|
out.log('✓ daemon-port-gate: scripts/ci-daemon-port-gate.ts PASS — no new daemon port literals.');
|
|
1552
1861
|
}
|
|
1553
1862
|
|
|
1554
|
-
|
|
1863
|
+
if (!pinned) changedPaths = currentChangePaths(run, cwd, staged, base, out);
|
|
1555
1864
|
nextMdWarning(body ?? '', changedPaths, out);
|
|
1556
1865
|
if (!conflictMarkerBlock(changedPaths, cwd, out)) return 1;
|
|
1557
1866
|
publicLeakWarning(changedPaths, deps.runPublicLeakGate ?? ((files, sink) => runPrLandPublicLeakGate(files, sink, cwd, base)), out);
|
|
@@ -1562,27 +1871,29 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1562
1871
|
const docsRoot = top.ok && top.out.trim() ? top.out.trim() : cwd;
|
|
1563
1872
|
docsCliWarning(publicDocPaths(changedPaths, (f) => existsSync(join(docsRoot, f))), deps.runDocsCliCheck ?? runPrLandDocsCliCheck(docsRoot), out);
|
|
1564
1873
|
}
|
|
1565
|
-
const testInterference =
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1874
|
+
const testInterference = opts.heavyRemote
|
|
1875
|
+
? { measured: heavyInterferenceMeasured }
|
|
1876
|
+
: await testInterferenceGateVerdict(
|
|
1877
|
+
deps.runTestInterferenceGate ?? ((o, files) => runTestInterferenceGate({ args: ['--changed-files', ...files], log: o.log, cwd })),
|
|
1878
|
+
changedPaths,
|
|
1879
|
+
out,
|
|
1880
|
+
);
|
|
1881
|
+
record('test-interference-gate', true, { measured: testInterference.measured, ...(opts.heavyRemote ? { host: heavyGateHost ?? null } : {}) });
|
|
1571
1882
|
// LAND-GLOBAL-CHECKS — 바뀐 파일의 경로 꼴이 부르는 «전역 검사»를 끌어와 돌린다(표 = scripts/land-global-checks.ts).
|
|
1572
|
-
//
|
|
1573
|
-
const landGlobal = gateVerdict(
|
|
1883
|
+
// --heavy-remote 는 같은 head/main 통합 트리에서 이미 측정했다. 원격의 실패·미측정은 heavyGate 가 막는다.
|
|
1884
|
+
const landGlobal = opts.heavyRemote ? { ok: true, measured: true } : gateVerdict(
|
|
1574
1885
|
'land-global-checks',
|
|
1575
1886
|
deps.runLandGlobalChecks
|
|
1576
1887
|
? (o) => deps.runLandGlobalChecks!(o, changedPaths)
|
|
1577
1888
|
: (o) => runLandGlobalChecksGate({ changedFiles: changedPaths, cwd, log: o.log, error: o.error }),
|
|
1578
1889
|
out,
|
|
1579
1890
|
);
|
|
1580
|
-
record('land-global-checks', landGlobal.ok, { measured: landGlobal.measured });
|
|
1891
|
+
record('land-global-checks', landGlobal.ok, { measured: landGlobal.measured, ...(opts.heavyRemote ? { host: heavyGateHost ?? null } : {}) });
|
|
1581
1892
|
if (!landGlobal.ok) {
|
|
1582
1893
|
out.error('✗ land-global-checks: scripts/land-global-checks.ts blocked pr land — 바뀐 파일이 끌어온 전역 시험이 실패했다.');
|
|
1583
1894
|
return 1;
|
|
1584
1895
|
}
|
|
1585
|
-
if (landGlobal.measured && landGlobalChecks(changedPaths).length > 0) {
|
|
1896
|
+
if (!opts.heavyRemote && landGlobal.measured && landGlobalChecks(changedPaths).length > 0) {
|
|
1586
1897
|
out.log(`✓ land-global-checks: scripts/land-global-checks.ts PASS — 끌려온 전역 시험 ${landGlobalChecks(changedPaths).join(' · ')} 실패 0.`);
|
|
1587
1898
|
}
|
|
1588
1899
|
|
|
@@ -1621,7 +1932,7 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1621
1932
|
}
|
|
1622
1933
|
|
|
1623
1934
|
// PWA 는 bun test/tsc 밖의 정적 번들이다. 측정 불가도 착지 불가로 판정한다.
|
|
1624
|
-
const pwaGate = gateVerdict('pwa-gate', deps.runPwaGate
|
|
1935
|
+
const pwaGate = gateVerdict('pwa-gate', opts.heavyRemote ? () => true : deps.runPwaGate
|
|
1625
1936
|
? (o) => deps.runPwaGate!(o, changedPaths)
|
|
1626
1937
|
: (o) => runPwaBuildGate({ args: ['--changed-files', ...changedPaths], cwd, log: o.log, error: o.error }) === 0, out, true);
|
|
1627
1938
|
record('pwa-gate', pwaGate.ok && pwaGate.measured, { measured: pwaGate.measured });
|
|
@@ -1630,72 +1941,8 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1630
1941
|
return 1;
|
|
1631
1942
|
}
|
|
1632
1943
|
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
const siblingFound = emitSiblingPrAdvisory(
|
|
1636
|
-
branch,
|
|
1637
|
-
deps.listOpenPrs ?? (() => lookupOpenPrs(run, cwd)),
|
|
1638
|
-
out,
|
|
1639
|
-
);
|
|
1640
|
-
const advisoryShown = recentAdvisoryShown || overlapFound || siblingFound;
|
|
1641
|
-
const reason = opts.landReason;
|
|
1642
|
-
const landReasonNotice = formatLandReasonNotice({ reason, advisoryShown });
|
|
1643
|
-
if (landReasonNotice) out.log(landReasonNotice);
|
|
1644
|
-
record('land-reason', true, {
|
|
1645
|
-
advisoryShown,
|
|
1646
|
-
hasReason: !!reason,
|
|
1647
|
-
reasonLength: reason ? codePointLength(reason) : 0,
|
|
1648
|
-
reasonLengthUnit: 'codepoint',
|
|
1649
|
-
});
|
|
1650
|
-
let overlapDecision: OverlapLandingDecision | undefined;
|
|
1651
|
-
if (overlapFound && !opts.hold && !opts.dryRun) {
|
|
1652
|
-
overlapDecision = await (deps.decideOverlapLanding ?? (() => decideOverlapLanding({
|
|
1653
|
-
isInteractive: deps.isInteractive,
|
|
1654
|
-
requestConfirmation: deps.requestConfirmation,
|
|
1655
|
-
channels: deps.overlapConfirmChannels,
|
|
1656
|
-
timeoutMs: deps.overlapConfirmTimeoutMs,
|
|
1657
|
-
})))();
|
|
1658
|
-
record('overlap-decision', true, {
|
|
1659
|
-
outcome: overlapDecision.outcome,
|
|
1660
|
-
channel: overlapDecision.channel,
|
|
1661
|
-
interactive: overlapDecision.interactive,
|
|
1662
|
-
});
|
|
1663
|
-
}
|
|
1664
|
-
const hold = !!opts.hold || overlapDecision?.outcome === 'user-hold';
|
|
1665
|
-
// TA-LAND-OVERLAP — 비대화형 «승인 불가»만 증거로 대신한다(사람의 hold 는 증거로 뒤집지 않는다) · 증거가 없거나 어긋나면 종전 거부 그대로.
|
|
1666
|
-
let overlapEvidenceAccepted = false;
|
|
1667
|
-
if (pinned && overlapDecision?.outcome === 'unavailable' && opts.overlapEvidence !== undefined) {
|
|
1668
|
-
const ref = resolveRemoteBranchRef(run, cwd, base);
|
|
1669
|
-
const verdict = verifyOverlapEvidence({
|
|
1670
|
-
evidencePath: opts.overlapEvidence, pr: Number(opts.pr), expectedHead: opts.expectedHead!,
|
|
1671
|
-
remote: ref.remote, branch: ref.branch, cwd, run, readFile, overlappingLandings,
|
|
1672
|
-
});
|
|
1673
|
-
overlapEvidenceAccepted = verdict.ok;
|
|
1674
|
-
if (verdict.ok) {
|
|
1675
|
-
out.log(verdict.mode === 'already-ancestor'
|
|
1676
|
-
? `✓ overlap-evidence: already-ancestor — 겹친 최근 착지 ${overlappingLandings.length}개가 전부 head ${opts.expectedHead!.slice(0, 12)} 의 조상 · review pass must-fix 0 (${verdict.reviewResult})`
|
|
1677
|
-
: verdict.mode === 'base-advanced-disjoint'
|
|
1678
|
-
? `✓ overlap-evidence: base-advanced-disjoint — gate base ${verdict.gateBase.slice(0, 12)} ⊂ head ${opts.expectedHead!.slice(0, 12)} · ${ref.remote}/${ref.branch} ${verdict.baseTip.slice(0, 12)} 까지 ${verdict.windowCommits}개 커밋이 PR 파일을 안 건드린다 · review pass|warn must-fix 0 (${verdict.reviewResult})`
|
|
1679
|
-
: `✓ overlap-evidence: ${ref.remote}/${ref.branch} ${verdict.baseTip.slice(0, 12)} ⊂ head ${opts.expectedHead!.slice(0, 12)} · gate passed on that base · review pass must-fix 0 (${verdict.reviewResult})`);
|
|
1680
|
-
}
|
|
1681
|
-
else out.error(`✗ overlap-evidence: ${verdict.reason}`);
|
|
1682
|
-
} else if (pinned && overlapDecision?.outcome === 'unavailable') {
|
|
1683
|
-
// 증거 파일이 없을 때 — 겹친 착지가 전부 머리의 조상이고 표준 자리의 리뷰가 pass|warn ⊕ must-fix 0 이면 통과(아니면 종전 거부).
|
|
1684
|
-
const verdict = verifyAncestorAutoPass({
|
|
1685
|
-
pr: Number(opts.pr), expectedHead: opts.expectedHead!, cwd, run, readFile, overlappingLandings,
|
|
1686
|
-
reviewResultsDir: deps.reviewResultsDir ?? join(dirname(taskAgentStatePath()), 'review-results'),
|
|
1687
|
-
listDir: (dir) => readdirSync(dir),
|
|
1688
|
-
});
|
|
1689
|
-
overlapEvidenceAccepted = verdict.ok;
|
|
1690
|
-
if (verdict.ok) {
|
|
1691
|
-
out.log(`✓ overlap-evidence: already-ancestor-auto — 겹친 최근 착지 ${overlappingLandings.length}개가 전부 head ${opts.expectedHead!.slice(0, 12)} 의 조상 · review pass|warn must-fix 0 (${verdict.reviewResult})`);
|
|
1692
|
-
}
|
|
1693
|
-
else out.error(`✗ ancestor-auto: ${verdict.reason}`);
|
|
1694
|
-
}
|
|
1695
|
-
if (pinned && overlapDecision && overlapDecision.outcome !== 'user-merge' && !overlapEvidenceAccepted) {
|
|
1696
|
-
out.error('✗ expected-head: overlap merge approval unavailable for the reviewed head');
|
|
1697
|
-
return 1;
|
|
1698
|
-
}
|
|
1944
|
+
|
|
1945
|
+
if (!pinned && (await checkOverlap()) !== undefined) return 1;
|
|
1699
1946
|
|
|
1700
1947
|
const manager = deps.manager ?? makePrManager(run);
|
|
1701
1948
|
const existing = manager.findPrForBranchOutcome(branch, cwd);
|
|
@@ -1753,7 +2000,7 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1753
2000
|
if (opts.hold) {
|
|
1754
2001
|
out.log(`[dry-run] ${existing.url ? '기존 PR을 갱신' : 'PR을 생성'}하고 --hold 로 병합하지 않고 멈춥니다.`);
|
|
1755
2002
|
} else {
|
|
1756
|
-
out.log(`[dry-run] ${existing.url ? '기존 PR을 갱신하고 ready 상태를 보장' : 'PR을 생성하고 ready 상태를 보장'}한 뒤 squash merge 합니다.`);
|
|
2003
|
+
out.log(`[dry-run] 머리 고정 없는 일반 착지: ${existing.url ? '기존 PR을 갱신하고 ready 상태를 보장' : 'PR을 생성하고 ready 상태를 보장'}한 뒤 squash merge 합니다.`);
|
|
1757
2004
|
}
|
|
1758
2005
|
return 0;
|
|
1759
2006
|
}
|
|
@@ -1876,35 +2123,74 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1876
2123
|
}
|
|
1877
2124
|
const landing = admission;
|
|
1878
2125
|
if (pinned) {
|
|
1879
|
-
const view = run('gh', ['pr', 'view', String(opts.pr), '--json', 'headRefOid,state,isDraft'], { cwd });
|
|
1880
|
-
let current: { headRefOid?: string; state?: string; isDraft?: boolean } = {};
|
|
2126
|
+
const view = run('gh', ['pr', 'view', String(opts.pr), '--json', 'headRefOid,state,isDraft,baseRefName'], { cwd });
|
|
2127
|
+
let current: { headRefOid?: string; state?: string; isDraft?: boolean; baseRefName?: string } = {};
|
|
1881
2128
|
try { if (view.ok) current = JSON.parse(view.out) as typeof current; } catch { /* fail closed */ }
|
|
1882
2129
|
const finalHead = run('git', ['rev-parse', 'HEAD'], { cwd });
|
|
1883
2130
|
if (current.headRefOid?.toLowerCase() !== opts.expectedHead!.toLowerCase() || current.state !== 'OPEN' || current.isDraft !== false
|
|
2131
|
+
|| (opts.heavyRemote && current.baseRefName !== 'main')
|
|
1884
2132
|
|| !finalHead.ok || finalHead.out.trim().toLowerCase() !== opts.expectedHead!.toLowerCase()) {
|
|
1885
2133
|
landing.end(false);
|
|
1886
2134
|
out.error('✗ expected-head: PR head/state changed before merge');
|
|
1887
2135
|
return 1;
|
|
1888
2136
|
}
|
|
1889
2137
|
}
|
|
1890
|
-
|
|
2138
|
+
// gh pr merge pins only the PR head (--match-head-commit). It exposes no atomic base
|
|
2139
|
+
// precondition. Re-read origin/main as close as possible to every mergePrOutcome,
|
|
2140
|
+
// including UNKNOWN retries after the wait. The last read and the merge call are
|
|
2141
|
+
// still not one atomic pin; a move inside that gap is caught after merge.
|
|
2142
|
+
{
|
|
2143
|
+
const started = Date.now();
|
|
2144
|
+
const unstable = await confirmHeavyBaseStable();
|
|
2145
|
+
stage('pre-merge-base-check', started, unstable === undefined, { verifiedBase: verifiedHeavyBase ?? null });
|
|
2146
|
+
if (unstable !== undefined) { landing.end(false); return unstable; }
|
|
2147
|
+
const staleOverlap = await confirmPinnedOverlapFresh();
|
|
2148
|
+
if (staleOverlap !== undefined) { landing.end(false); return staleOverlap; }
|
|
2149
|
+
}
|
|
2150
|
+
let merged: ReturnType<typeof manager.mergePrOutcome> | undefined;
|
|
2151
|
+
let heavyRetryRefused = false;
|
|
2152
|
+
let mergeAttempt = 0;
|
|
2153
|
+
const mergeOnce = (): ReturnType<typeof manager.mergePrOutcome> => {
|
|
2154
|
+
const started = Date.now();
|
|
2155
|
+
const attempt = ++mergeAttempt;
|
|
2156
|
+
let outcome: ReturnType<typeof manager.mergePrOutcome> | undefined;
|
|
2157
|
+
try {
|
|
2158
|
+
outcome = manager.mergePrOutcome(upsert.url, pinned ? opts.expectedHead : undefined, pinned ? cwd : undefined);
|
|
2159
|
+
return outcome;
|
|
2160
|
+
} finally {
|
|
2161
|
+
stage('merge', started, outcome?.ok === true, { attempt, verifiedBase: verifiedHeavyBase ?? null });
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
1891
2164
|
try {
|
|
1892
|
-
merged =
|
|
2165
|
+
merged = mergeOnce();
|
|
1893
2166
|
// `GIT-S14` — 병합이 «미완료(OPEN)»로 끝났고 GitHub 가 아직 `mergeable=UNKNOWN`(병합 가능 여부 계산 중)이면
|
|
1894
2167
|
// 짧게 기다렸다 다시 병합한다. 표본 셋(08-25 · 09-24 🅢 #20233 등)이 모두 «같은 명령 재시도에 병합»이었다.
|
|
1895
2168
|
// ⛔ UNKNOWN 일 때만 재시도한다 — CONFLICTING 등 다른 값은 기다려도 안 풀린다(그대로 실패를 낸다).
|
|
1896
2169
|
const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
|
|
1897
2170
|
// pinned 도 재시도한다 — mergePrOutcome 이 머리를 다시 확인하고 --match-head-commit 으로 병합하므로 바뀐 머리로는 안 들어간다.
|
|
2171
|
+
// heavy-remote 는 대기 중 main 이 움직일 수 있으므로 재병합 직전에 같은 안정성 검사를 다시 탄다.
|
|
2172
|
+
// 그 검사가 실패하면 두 번째 병합을 하지 않고, 이미 찍힌 게이트 오류를 유지한 채 반환한다.
|
|
1898
2173
|
for (let attempt = 1; !merged.ok && merged.kind === 'not-merged' && merged.state === 'OPEN' && attempt <= PR_LAND_MERGEABLE_UNKNOWN_RETRIES; attempt += 1) {
|
|
1899
2174
|
const mergeable = run('gh', ['pr', 'view', upsert.url, '--json', 'mergeable', '--jq', '.mergeable'], { cwd });
|
|
1900
2175
|
const value = mergeable.ok ? mergeable.out.trim() : '';
|
|
1901
2176
|
if (value !== 'UNKNOWN') break;
|
|
1902
2177
|
record('merge-retry', true, { attempt, mergeable: value, waitMs: PR_LAND_MERGEABLE_UNKNOWN_WAIT_MS });
|
|
1903
2178
|
out.log(`⏳ merge: mergeable=UNKNOWN — GitHub 가 병합 가능 여부를 아직 계산 중입니다 · ${PR_LAND_MERGEABLE_UNKNOWN_WAIT_MS / 1000}초 뒤 다시 병합 (${attempt}/${PR_LAND_MERGEABLE_UNKNOWN_RETRIES})`);
|
|
2179
|
+
const waitStarted = Date.now();
|
|
1904
2180
|
await sleep(PR_LAND_MERGEABLE_UNKNOWN_WAIT_MS);
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
2181
|
+
stage('merge-retry-wait', waitStarted, true, { attempt });
|
|
2182
|
+
const checkStarted = Date.now();
|
|
2183
|
+
const unstable = await confirmHeavyBaseStable();
|
|
2184
|
+
stage('pre-merge-base-check', checkStarted, unstable === undefined, { attempt, verifiedBase: verifiedHeavyBase ?? null });
|
|
2185
|
+
if (unstable !== undefined) { heavyRetryRefused = true; break; }
|
|
2186
|
+
const staleOverlap = await confirmPinnedOverlapFresh();
|
|
2187
|
+
if (staleOverlap !== undefined) { heavyRetryRefused = true; break; }
|
|
2188
|
+
merged = mergeOnce();
|
|
2189
|
+
}
|
|
2190
|
+
} finally {
|
|
2191
|
+
landing.end(!heavyRetryRefused && merged?.ok === true);
|
|
2192
|
+
}
|
|
2193
|
+
if (heavyRetryRefused || !merged) return 1;
|
|
1908
2194
|
if (!merged.ok) {
|
|
1909
2195
|
// `GIT-S76` — 「미완료(OPEN)」만으로는 «충돌»과 «아직 계산 중»이 안 갈린다. GitHub 의 병합 가능 상태를 같이 싣는다.
|
|
1910
2196
|
// 되읽기에 실패하면 종전 문면 그대로다(못 읽은 것을 「충돌 아님」으로 적지 않는다).
|
|
@@ -1927,7 +2213,7 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1927
2213
|
...(mergeable ? { mergeable } : {}),
|
|
1928
2214
|
...(mergeStateStatus ? { mergeStateStatus } : {}),
|
|
1929
2215
|
});
|
|
1930
|
-
|
|
2216
|
+
refuse(`✗ merge: ${detail}`);
|
|
1931
2217
|
if (mergeable === 'CONFLICTING') {
|
|
1932
2218
|
out.error(' ↳ 충돌 — 이 브랜치가 기준 브랜치의 최근 착지와 같은 줄을 고쳤다. `bun bin/elanous.mjs git fetch origin` → `bun bin/elanous.mjs git rebase origin/<기준>` 로 풀고 다시 pr land.');
|
|
1933
2219
|
}
|
|
@@ -1938,6 +2224,58 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1938
2224
|
if (merged.remoteBranchDeletion) {
|
|
1939
2225
|
out.log(`⚠ remote branch deletion: ${merged.remoteBranchDeletion.detail}`);
|
|
1940
2226
|
}
|
|
2227
|
+
if (opts.heavyRemote && verifiedHeavyBase) {
|
|
2228
|
+
// Squash merge has one parent: the base GitHub actually merged onto. Compare it with the
|
|
2229
|
+
// base that passed the heavy gate. Do not revert a landed commit; a mismatch means the
|
|
2230
|
+
// non-atomic gap between the last re-read and gh merge moved main.
|
|
2231
|
+
const viewed = run('gh', ['pr', 'view', upsert.url, '--json', 'mergeCommit,state'], { cwd });
|
|
2232
|
+
let mergeOid = '';
|
|
2233
|
+
let state = '';
|
|
2234
|
+
try {
|
|
2235
|
+
if (viewed.ok) {
|
|
2236
|
+
const parsed = JSON.parse(viewed.out) as { state?: unknown; mergeCommit?: { oid?: unknown } | null };
|
|
2237
|
+
state = typeof parsed.state === 'string' ? parsed.state : '';
|
|
2238
|
+
mergeOid = typeof parsed.mergeCommit?.oid === 'string' ? parsed.mergeCommit.oid : '';
|
|
2239
|
+
}
|
|
2240
|
+
} catch { /* unreadable is not a match */ }
|
|
2241
|
+
let firstParent = '';
|
|
2242
|
+
if (/^[a-f0-9]{40}$/i.test(mergeOid)) {
|
|
2243
|
+
const fetched = run('git', ['fetch', '--quiet', 'origin', mergeOid], { cwd });
|
|
2244
|
+
if (fetched.ok) {
|
|
2245
|
+
const parent = run('git', ['rev-parse', '--verify', `${mergeOid}^1`], { cwd });
|
|
2246
|
+
if (parent.ok && /^[a-f0-9]{40}$/i.test(parent.out.trim())) firstParent = parent.out.trim();
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
if (state === 'MERGED' && firstParent.toLowerCase() === verifiedHeavyBase.toLowerCase()) {
|
|
2250
|
+
record('heavy-remote-base', true, { verifiedBase: verifiedHeavyBase, mergedOnto: firstParent, mergeCommit: mergeOid });
|
|
2251
|
+
} else {
|
|
2252
|
+
const reason = state !== 'MERGED' ? 'merge-state-unconfirmed'
|
|
2253
|
+
: !firstParent ? 'merge-parent-unreadable' : 'merged-base-mismatch';
|
|
2254
|
+
record('heavy-remote-base', false, {
|
|
2255
|
+
verifiedBase: verifiedHeavyBase, mergedOnto: firstParent || null, mergeCommit: mergeOid || null, state: state || null, reason,
|
|
2256
|
+
});
|
|
2257
|
+
debug.log('pr.land', 'post-merge-gate-required', {
|
|
2258
|
+
pr: Number(opts.pr), head: opts.expectedHead, verifiedBase: verifiedHeavyBase,
|
|
2259
|
+
mergedOnto: firstParent || null, mergeCommit: mergeOid || null, verifiedHost: heavyGateHost ?? null, reason,
|
|
2260
|
+
});
|
|
2261
|
+
out.log(`post-merge gate required: verified=${verifiedHeavyBase.slice(0, 12)} mergedOnto=${firstParent ? firstParent.slice(0, 12) : 'unreadable'} (${reason})`);
|
|
2262
|
+
// A missing first parent must not be gated against the stale verified base — that
|
|
2263
|
+
// would claim coverage of a pair that was never measured. Merge already happened.
|
|
2264
|
+
if (!firstParent) {
|
|
2265
|
+
record('heavy-remote', false, { host: heavyGateHost ?? null, phase: 'post-merge', reason: 'unmeasured', mergedOnto: null });
|
|
2266
|
+
out.error('✗ heavy-remote: post-merge 원격 게이트 unmeasured — squash 첫 부모를 읽지 못해 사후 게이트를 돌리지 않는다. 병합은 되돌리지 않는다.');
|
|
2267
|
+
out.log(`✓ merge: squash ${upsert.url} → ${base}`);
|
|
2268
|
+
return 1;
|
|
2269
|
+
}
|
|
2270
|
+
const post = heavyGate(firstParent, 'post-merge');
|
|
2271
|
+
if (!post?.ok) {
|
|
2272
|
+
out.error(`✗ heavy-remote: post-merge 원격 게이트 ${post?.reason ?? 'unmeasured'} — 병합은 되돌리지 않는다.`);
|
|
2273
|
+
out.log(`✓ merge: squash ${upsert.url} → ${base}`);
|
|
2274
|
+
return 1;
|
|
2275
|
+
}
|
|
2276
|
+
out.log(`✓ heavy-remote: post-merge host=${post.host ?? 'unknown'} head=${opts.expectedHead!.slice(0, 12)} main=${firstParent.slice(0, 12)} source=${post.source}`);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
1941
2279
|
const baseRef = upsert.reused
|
|
1942
2280
|
? run('gh', ['pr', 'view', upsert.url, '--json', 'baseRefName', '--jq', '.baseRefName'], { cwd })
|
|
1943
2281
|
: undefined;
|
|
@@ -1975,6 +2313,7 @@ export function registerPrCommands(program: Command, deps: PrLandDeps = {}, queu
|
|
|
1975
2313
|
.option('--cwd <path>', '작업 트리 경로')
|
|
1976
2314
|
.option('--pr <number>', '기존 PR 번호 고정 (--expected-head 와 함께)')
|
|
1977
2315
|
.option('--expected-head <sha>', '리뷰된 PR 머리 SHA 고정 (--pr 와 함께)')
|
|
2316
|
+
.option('--heavy-remote', '머리 고정 착지의 무거운 게이트를 node-b·node-c 중 빈 호스트에서 실행; head⊕main 증거가 없거나 실패하면 거부(로컬 폴백 없음)')
|
|
1978
2317
|
.option('--dry-run', '변경 없이 landing 계획만 출력')
|
|
1979
2318
|
.option('--hold', 'PR을 생성 또는 갱신한 뒤 병합하지 않고 쌓아 둔다')
|
|
1980
2319
|
.option('--title <title>', 'PR title')
|