elanous 0.2.29 → 0.2.31
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/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{058a98ba.7eb28d5e6dc03565.js → 0bb0ff36.b8d418980951e5ba.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +27 -0
- package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +287 -0
- package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +62 -0
- package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6013-2f769370d8b4c2c6.js → 1335-6731f392c35216eb.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8332.6f0f49df772e163b.js → 1654.32de4b324981a188.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1834-50625904996a8fa8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +149 -0
- package/apps/pwa/out/_next/static/chunks/{8795.32573a185af18c7b.js → 1913.7cc6fb6055b1ed3f.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{419.736c0d6f426249a7.js → 2001.6c7e0fd02190886c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6767.1fcfc9b8be83975f.js → 2213.2ccbada92c33ea0f.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4759.1f76713aefb87db5.js → 2871.0bca6137343b3f76.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6776.06ff1e3b464cc607.js → 2898.fd781bc7cf01a7b7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1782-59db1b5aa06df38a.js → 2940-619bfd8ef337c611.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8471.8d2a8c74f09c36ff.js → 2985.39ccdecd36848b12.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +115 -0
- package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +64 -0
- package/apps/pwa/out/_next/static/chunks/{bc324b7c.02a09dd93f6a399b.js → 3267c0e6.d34854e7b3984a6e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3278.2e5d15b53a4091c8.js +2 -0
- package/apps/pwa/out/_next/static/chunks/{7725-4f83d5541fbdb81b.js → 3541-ce3a5424ed5ad7f1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +34 -0
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{46bd8bea.2f4b4099172fcdb7.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1142.65d002789ab3af7d.js → 4174.92ed04922709ac9e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +36 -0
- package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +286 -0
- package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +77 -0
- package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +226 -0
- package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +79 -0
- package/apps/pwa/out/_next/static/chunks/5173-233188df2f42c626.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +148 -0
- package/apps/pwa/out/_next/static/chunks/5307.60f2209e809bd627.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3396-97b97928c49190c9.js → 5458-16cd7a2b51b74c8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3403.7199205e65124486.js → 5525.86debf231e181813.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9143.ff14585db1d275ff.js → 5543.a438b8ab5a13ea47.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +74 -0
- package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +94 -0
- package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8398.73a19b39715eda04.js → 6092.a7f99e68b188ca66.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5591.a35e7a217734a8b9.js → 6157.0c9af021de4fb31b.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7375.050ea0d72968e49f.js → 6433.fc573af22bbc9ab7.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +90 -0
- package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +104 -0
- package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +93 -0
- package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
- package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
- package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
- package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-a5635eba0d73b84e.js → page-2ebb8fd59b9461f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0a07363b130182a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-521ee23ac8c0abfa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-9f92737b8766009a.js → page-149dc1caba411bb9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
- package/apps/pwa/out/_next/static/css/{72becfd42807b50d.css → 3f5fc6f96e2cf7b2.css} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/bin/elanous.mjs +7 -3
- package/graphs/context/nightly-condense.yaml +1 -0
- package/graphs/intake/intake-daily.yaml +8 -1
- package/graphs/intake/recipes.yaml +5 -0
- package/graphs/lecture/lecture-note.yaml +2 -2
- package/graphs/ops/harness-gc.yaml +1 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +9 -5
- package/graphs/units/recipes.yaml +3 -0
- package/graphs/units/release-gate-recheck.yaml +15 -0
- package/package.json +2 -1
- package/scripts/check-native-tool-wiring.ts +3 -2
- package/scripts/ci-android-unit-tests.ts +16 -0
- package/scripts/ci-typecheck-changed.ts +37 -9
- package/scripts/coord-channel-watch.sh +22 -16
- package/scripts/coord-role-pack.ts +81 -2
- package/scripts/cron-run.ts +96 -3
- package/scripts/detect-test-interference.ts +38 -5
- package/scripts/gate-pr-cache.ts +65 -0
- package/scripts/gh-surface/capture.ts +126 -0
- package/scripts/gh-surface/gh +40 -0
- package/scripts/import-graph-scc.ts +38 -0
- package/scripts/install.ps1 +19 -0
- package/scripts/intake-social.ts +181 -0
- package/scripts/lecture-note/node.ts +71 -4
- package/scripts/lib/android-toolchain.ts +32 -0
- package/scripts/lib/deterministic-env.ts +62 -0
- package/scripts/lib/gate-test-env.ts +19 -0
- package/scripts/measure-goal-grounding-corpus.ts +2 -1
- package/scripts/ratchets/test-interference-patterns.allowlist.txt +257 -0
- package/scripts/ratchets/test-interference-patterns.ts +367 -0
- package/scripts/release-loop/cut-branch.ts +4 -3
- package/scripts/release-loop/export-check-node.ts +0 -1
- package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
- package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
- package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
- package/scripts/release-loop/gate-closure.ts +12 -8
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-host-mirror.ts +66 -0
- package/scripts/release-loop/gate-node.ts +523 -75
- package/scripts/release-loop/gate-partial.ts +106 -9
- package/scripts/release-loop/gate-pr-cache.ts +66 -0
- package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
- package/scripts/release-loop/gate-r2-verdict.ts +189 -0
- package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
- package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
- package/scripts/release-loop/import-graph-scc-run.ts +54 -0
- package/scripts/release-loop/import-graph-scc.ts +215 -0
- package/scripts/release-loop/node-verdict.ts +2 -0
- package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
- package/scripts/release-loop/resume-release.ts +33 -4
- package/scripts/release-loop/resume.ts +13 -5
- package/scripts/release-loop/spawn-lane.ts +2 -19
- package/scripts/release-loop/tui-sim-node.ts +3 -2
- package/scripts/release-loop/unattended-release.ts +16 -0
- package/scripts/test-deterministic.ts +5 -61
- package/scripts/train-reach-grouping.ts +48 -0
- package/scripts/tsc-incremental-cache.ts +86 -0
- package/scripts/tsc-incremental-diagnostics.ts +76 -0
- package/scripts/tsc-main-safety-net.ts +2 -2
- package/src/acp/client.ts +4 -1
- package/src/acp/core-turn-bridge.ts +50 -5
- package/src/ad-pipeline/run.ts +4 -2
- package/src/agent/runner.ts +169 -3
- package/src/agent/subagent-callable.ts +3 -2
- package/src/agent-mission/review-loop.ts +6 -3
- package/src/agent-substrate/acp-implementer.ts +14 -2
- package/src/agent-substrate/pr-reviewer.ts +12 -0
- package/src/agent-substrate/self-review-cli.ts +30 -4
- package/src/autopilot/pr-manager.ts +62 -7
- package/src/briefing/brief-items.ts +24 -22
- package/src/capture/tui-self-report.ts +15 -0
- package/src/chat/chat-cli.ts +10 -2
- package/src/chat/index.ts +77 -11
- package/src/chat/input-control-key.ts +5 -3
- package/src/chat/tool-interrupt-behavior.ts +38 -0
- package/src/chat/tool-render/dispatch.ts +5 -1
- package/src/chat/turn-typeahead.ts +75 -20
- package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
- package/src/cli/agent-cli.ts +41 -13
- package/src/cli/config-audit.ts +123 -0
- package/src/cli/decisions-cli.ts +80 -6
- package/src/cli/log-event-names.ts +7 -0
- package/src/cli/mcp-login.ts +21 -5
- package/src/cli/msg-cli.ts +88 -0
- package/src/cli/pr-cli.ts +214 -57
- package/src/cli/pr-land-heavy-remote.ts +2 -2
- package/src/cli/pr-land-overlap-evidence.ts +63 -9
- package/src/cli/pr-land-pod-shadow-job.ts +83 -0
- package/src/cli/pr-land-pod-shadow.ts +16 -3
- package/src/cli/pr-land-virtual-rebase.ts +108 -0
- package/src/cli/release-cli.ts +80 -14
- package/src/cli/seat-cli.ts +138 -3
- package/src/cli/self-update.ts +5 -2
- package/src/cli/tasks-cli.ts +97 -19
- package/src/context-bus/context-first.ts +13 -0
- package/src/context-bus/context-now.ts +13 -2
- package/src/context-bus/ops-events.ts +75 -0
- package/src/control-plane/lease-holder.ts +12 -8
- package/src/control-plane/ledger.ts +163 -4
- package/src/control-plane/server.ts +91 -11
- package/src/core-turn/run-core-turn.ts +1 -0
- package/src/core-turn/run-goal-loop.ts +222 -3
- package/src/core-turn/seat-turn-cap.ts +79 -0
- package/src/core-turn/short-question.ts +38 -6
- package/src/core-turn/types.ts +3 -0
- package/src/dashboard/acp-boot.ts +3 -0
- package/src/dashboard/index.ts +224 -615
- package/src/dashboard/input/chat-main-entry-runtime.ts +1 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
- package/src/dashboard/input/chat-main-session.ts +8 -1
- package/src/dashboard/input/chat-main-turn.ts +12 -3
- package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
- package/src/dashboard/input/external-input-host.ts +26 -0
- package/src/dashboard/input/internal-turn.ts +261 -0
- package/src/dashboard/input/seat-autowake.ts +318 -0
- package/src/dashboard/input/turn-steer-bridge.ts +70 -0
- package/src/dashboard/loop-scheduler.ts +72 -0
- package/src/dashboard/seat-boot-preamble.ts +18 -0
- package/src/dashboard/skill-runtime.ts +2 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
- package/src/dashboard/slash-runtime/index.ts +13 -0
- package/src/dashboard/turn-busy-teardown.ts +50 -0
- package/src/decisions/decision-ledger.ts +45 -4
- package/src/discord-self-message.ts +4 -4
- package/src/domains/release-tool.ts +18 -1
- package/src/field-note/transcribe.ts +17 -0
- package/src/github/remote-call.ts +81 -0
- package/src/goals/registry.ts +46 -6
- package/src/goals/types.ts +7 -1
- package/src/graph-runner/runner.ts +1 -0
- package/src/grok/credential.ts +26 -0
- package/src/harness/harness-clean.ts +2 -1
- package/src/harness/harness-cli-command.ts +52 -5
- package/src/harness/harness-gc.ts +2 -1
- package/src/harness/harness-incidents.ts +57 -20
- package/src/harness/harness-pod-dispatch.ts +87 -10
- package/src/harness/harness-queue.ts +53 -4
- package/src/harness/harness-stop.ts +4 -3
- package/src/harness/harness-substrate-default.ts +78 -7
- package/src/harness/harness-worktree-auto.ts +2 -1
- package/src/harness/harness-worktrees.ts +3 -2
- package/src/hooks/dispatch.ts +2 -1
- package/src/index.ts +152 -25
- package/src/input/external-input-queue.ts +33 -1
- package/src/intake-plane/slash.ts +14 -3
- package/src/keybindings.ts +4 -1
- package/src/llm/tool-loop-steered-rejection.ts +33 -0
- package/src/llm.ts +138 -19
- package/src/loops/consensus.ts +348 -0
- package/src/loops/msg-wake.ts +206 -4
- package/src/loops/observe.ts +19 -3
- package/src/loops/orchestrator/tick.ts +64 -10
- package/src/loops/orchestrator/traffic.ts +64 -1
- package/src/loops/registry.ts +30 -0
- package/src/market/signed-index.ts +14 -0
- package/src/mcp/mcp-oauth.ts +54 -5
- package/src/models/prompts.ts +28 -0
- package/src/msg/msg-sse-client.ts +223 -0
- package/src/msg/msg-store.ts +86 -2
- package/src/mss/logging/log-store.ts +225 -1
- package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
- package/src/nexus/api/http-server.ts +54 -15
- package/src/nexus/api/loop-resources.ts +19 -3
- package/src/nexus/api/ops-api.ts +11 -0
- package/src/nexus/daemon-thin-inventory.md +37 -0
- package/src/nexus/index.ts +70 -0
- package/src/nexus/state/state.ts +1 -0
- package/src/oauth/store.ts +32 -7
- package/src/onboarding/first-run.ts +28 -3
- package/src/ops/overview-cache.ts +16 -4
- package/src/ops/resources.ts +82 -0
- package/src/plugins/maker/connector-maker.ts +41 -0
- package/src/plugins/maker/skill-maker.ts +42 -0
- package/src/pr-tool/census.ts +288 -0
- package/src/prompt-library/chat-conciseness.ts +13 -0
- package/src/prompt-library/universal-preamble.ts +10 -5
- package/src/release-loop/gate-host-reservation.ts +97 -0
- package/src/release-loop/landing-freeze.ts +5 -0
- package/src/release-loop/light-rc.ts +5 -2
- package/src/release-loop/placement.ts +92 -1
- package/src/release-loop/rehearsal-shard-plan.ts +149 -0
- package/src/release-loop/rehearsal.ts +73 -17
- package/src/repl/index.ts +20 -2
- package/src/seat-loop/seat-knowhow.ts +282 -0
- package/src/seat-loop/seat-loop.ts +41 -2
- package/src/seat-loop/traffic-signal.ts +3 -0
- package/src/self-dev/ask-launch-flow.ts +24 -3
- package/src/self-dev/decompose-compose-graph.ts +28 -27
- package/src/self-dev/decompose-proposal.ts +53 -38
- package/src/self-dev/decompose.ts +17 -0
- package/src/self-dev/dev-pipeline.ts +31 -2
- package/src/self-dev/draft-residue.ts +24 -9
- package/src/self-dev/draft-sweep.ts +59 -4
- package/src/self-dev/external-call-zero.ts +77 -0
- package/src/self-dev/launch-preflight-text.ts +6 -0
- package/src/self-dev/launch-preflight.ts +25 -3
- package/src/self-dev/local-supervisor-judge.ts +185 -0
- package/src/self-dev/run-supervisor.ts +229 -19
- package/src/self-dev/run-types.ts +20 -0
- package/src/self-dev/shard-aggregate.ts +13 -2
- package/src/self-dev/shard-plan.ts +47 -0
- package/src/self-dev/shard-run.ts +112 -10
- package/src/self-dev/spawn-lane-files.ts +19 -0
- package/src/self-implement/app-api-budget.ts +51 -11
- package/src/self-implement/config-gate.ts +2 -1
- package/src/self-implement/expose-gate.ts +2 -1
- package/src/self-implement/gate-artifacts.ts +405 -0
- package/src/self-implement/gate-cli.ts +201 -16
- package/src/self-implement/gate-remote.ts +110 -25
- package/src/self-implement/gate-scenario.ts +85 -0
- package/src/self-implement/goal-author.ts +160 -8
- package/src/self-implement/graph-authority.ts +38 -6
- package/src/self-implement/graph-overlay-condition.ts +92 -1
- package/src/self-implement/heal-triage.ts +79 -0
- package/src/self-implement/host-regate.ts +61 -3
- package/src/self-implement/orchestrator.ts +14 -123
- package/src/self-implement/pr-title.ts +123 -0
- package/src/self-implement/run-checkpoint.ts +235 -0
- package/src/self-implement/run-ledger.ts +155 -10
- package/src/self-implement/run-stop.ts +4 -3
- package/src/self-implement/run-ttl.ts +28 -4
- package/src/self-implement/seams.ts +2 -0
- package/src/self-implement/shadow-stage.ts +7 -6
- package/src/self-implement/stop-autoheal.ts +2 -1
- package/src/self-implement/train-gate-remote.ts +37 -8
- package/src/self-implement/train-reach-grouping.ts +157 -0
- package/src/self-implement/train-scenario-layers.ts +133 -0
- package/src/self-implement/uncommitted-work.ts +2 -0
- package/src/session/pending-input.ts +19 -0
- package/src/session/session-start.ts +224 -0
- package/src/session-runtime/parallel-dispatch.ts +22 -5
- package/src/skills/tools/dev-harness.ts +6 -4
- package/src/skills/tools/shell.ts +1 -1
- package/src/steward/resync-tick.ts +114 -23
- package/src/steward/ta-repair-event-collect.ts +158 -0
- package/src/task-agent/card-evidence.ts +25 -1
- package/src/task-agent/green-sweep.ts +8 -3
- package/src/task-agent/judge.ts +76 -0
- package/src/task-agent/land-queue.ts +79 -0
- package/src/task-agent/live-moves.ts +30 -9
- package/src/task-agent/postland-card.ts +5 -0
- package/src/task-agent/prelaunch-already-done.ts +98 -0
- package/src/task-agent/real-launch-guard.ts +37 -0
- package/src/task-agent/rejudge-on-head.ts +89 -12
- package/src/task-agent/remote-rejudge-bind.ts +28 -8
- package/src/task-agent/repair-cycle.ts +45 -7
- package/src/task-agent/repair-worker.ts +7 -0
- package/src/task-agent/run-identity.ts +200 -0
- package/src/task-agent/shadow.ts +50 -3
- package/src/task-agent/task-hand.ts +158 -5
- package/src/task-agent/train-landing.ts +77 -0
- package/src/task-agent/work-order.ts +104 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +88 -28
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
- package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
- package/src/task-orchestrator/surfaces/pod-lease.ts +20 -6
- package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
- package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
- package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +63 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
- package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
- package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +208 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +132 -15
- package/src/telegram.ts +2 -4
- package/src/tui/input/pickers.ts +732 -0
- package/src/tui/slash/mission.ts +492 -0
- package/src/tui/slash/term.ts +877 -0
- package/src/tui-client/dashboard-session.ts +9 -0
- package/src/tui.ts +48 -0
- package/src/user-config/gemini-server-tools.ts +9 -0
- package/src/user-config.ts +53 -16
- package/src/util/spawn-sync-output.ts +7 -0
- package/src/ux-sim/fake-bin.ts +154 -0
- package/src/ux-sim/fake-clock.ts +36 -0
- package/src/ux-sim/headless-tui.ts +72 -0
- package/src/ux-sim/in-process-cli.ts +2 -1
- package/src/ux-sim/temp-git-remote.ts +82 -0
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/recipes/vlog.ts +25 -7
- package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
- package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
- package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
- package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
- package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
- package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
- package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
- package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
- package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
- package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
- package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
- package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
- package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
- package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
- package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
- package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
- package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
- package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
- package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
- package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
- package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
- package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
- package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
- package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
- package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
- /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, lstatSync, mkdtempSync, readFileSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
2
3
|
import { spawnSync } from 'node:child_process';
|
|
3
4
|
import { join } from 'node:path/posix';
|
|
4
5
|
import { prepareDeterministicChildEnvironment } from '../../scripts/lib/deterministic-env.js';
|
|
6
|
+
import { withGateTestEnv } from '../../scripts/lib/gate-test-env.js';
|
|
5
7
|
import { runIsolationHardcodeGate } from '../../scripts/ci-isolation-hardcode-gate.js';
|
|
6
8
|
import { runModelHardcodeGate } from '../../scripts/ci-model-hardcode-gate.js';
|
|
7
9
|
import { runDaemonPortGate } from '../../scripts/ci-daemon-port-gate.js';
|
|
@@ -24,18 +26,29 @@ import {
|
|
|
24
26
|
overlapWithCurrentChanges,
|
|
25
27
|
} from '../cli/pr-granularity.js';
|
|
26
28
|
import { listWorktrees } from '../git-fs/worktree.js';
|
|
27
|
-
import { runShardedGateTests } from '../self-dev/shard-run.js';
|
|
29
|
+
import { runShardedGateTests, writeShardFailureEvidence } from '../self-dev/shard-run.js';
|
|
30
|
+
import { parseGateScenario, readGateScenarioFile } from './gate-scenario.js';
|
|
31
|
+
import { isGateSpawnLaneFile } from '../self-dev/spawn-lane-files.js';
|
|
32
|
+
import { defaultGateEnvKey, defaultRevResolver, resolveArtifactDir, writeGateArtifacts, type GateArtifactCounts, type GateArtifactsUnavailable, type RevResolver } from './gate-artifacts.js';
|
|
28
33
|
|
|
29
34
|
export interface SelfGateCliOptions {
|
|
30
35
|
base?: string;
|
|
31
36
|
pr?: string;
|
|
32
37
|
shards?: number;
|
|
38
|
+
/** OP FU (LAND-TRAIN-LIVE side) — opt-in with `shards`: sorted round-robin into exactly that N, no RSS pre-measurement.
|
|
39
|
+
* Every other output (shardsDetail · baseline · artifacts · exit) keeps its shape; absent = measured planner unchanged. */
|
|
40
|
+
fixedShardDistribution?: boolean;
|
|
33
41
|
/** LIGHT-RC (0.2.19) — repository-relative test paths run on every call, whatever changed. Existing ones join the
|
|
34
42
|
* run (deduplicated, same introduced/preexisting baseline as the rest); missing ones go to `alwaysIncludeMissing`. */
|
|
35
43
|
alwaysInclude?: readonly string[];
|
|
36
44
|
/** RELEASE-DAILY-LIGHT-RC ② — run every tracked test that imports a changed (non-test) source, past the caller cap
|
|
37
45
|
* (importer index · reason=changed-source-importer). Off by default: the plain `self gate` scope is unchanged. */
|
|
38
46
|
includeImporterTests?: boolean;
|
|
47
|
+
/** Optional v0 scenario JSON. Adds selected tests only after binding base/head/diff. */
|
|
48
|
+
scenario?: unknown;
|
|
49
|
+
scenarioFile?: string;
|
|
50
|
+
/** SIDE-VERIFY — 조각별 지금/기준 JUnit ⊕ summary.json 을 이 디렉토리에 «쓰기만» 한다(판정·exit·기존 줄 불변). */
|
|
51
|
+
artifactDir?: string;
|
|
39
52
|
}
|
|
40
53
|
|
|
41
54
|
interface ProcessResult {
|
|
@@ -81,6 +94,7 @@ export interface DirtyWorktreeClassification {
|
|
|
81
94
|
interface SelfGateCliDeps {
|
|
82
95
|
changedFiles?: (cwd: string, options: SelfGateCliOptions) => ChangedFileSelection;
|
|
83
96
|
exists?: (path: string) => boolean;
|
|
97
|
+
isRegularFile?: (cwd: string, path: string) => boolean;
|
|
84
98
|
runCommand?: (command: string, args: string[], cwd: string) => ProcessResult;
|
|
85
99
|
readFile?: (path: string) => string | undefined;
|
|
86
100
|
runTests?: (cwd: string, files: readonly string[]) => ProcessResult;
|
|
@@ -99,6 +113,45 @@ interface SelfGateCliDeps {
|
|
|
99
113
|
runPwaGate?: (out: GateOutput) => number;
|
|
100
114
|
listPrWorktrees?: (cwd: string) => PrWorktreeListEntry[] | { lookupFailed: string };
|
|
101
115
|
inspectWorktreeDirtiness?: (path: string) => { dirty: boolean } | { lookupFailed: string };
|
|
116
|
+
/** `--artifact-dir` 전용 심 — 커밋 sha 해석(실패 = null) · 환경 키. */
|
|
117
|
+
resolveRev?: RevResolver;
|
|
118
|
+
envKey?: () => string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** `--artifact-dir` 가 쓸 재료 — 판정 경로가 «채우기만» 하고 읽지 않는다. */
|
|
122
|
+
interface GateArtifactCapture {
|
|
123
|
+
baseRef?: string;
|
|
124
|
+
testFiles?: readonly string[];
|
|
125
|
+
sharded?: ReturnType<typeof runShardedGateTests>;
|
|
126
|
+
verdict?: string;
|
|
127
|
+
verdictLine?: string;
|
|
128
|
+
unmeasuredReason?: string;
|
|
129
|
+
unshardedRc?: number | null;
|
|
130
|
+
artifactsUnavailable?: GateArtifactsUnavailable;
|
|
131
|
+
/** `unrun importer tests: N` 의 N — 색인 조회 실패면 null(그 이유가 importerLookupFailed). */
|
|
132
|
+
unrunImporters?: number | null;
|
|
133
|
+
importerLookupFailed?: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** SIDE-VERIFY ③ — summary 정수 칸: 게이트가 이미 낸 `result.baseline` ⊕ `unrunImporterTotal` 을 «옮기기만» 한다.
|
|
137
|
+
* baseline 이 없으면(조각 unmeasured) 넷은 null — 「0」으로 접지 않는다. */
|
|
138
|
+
export function gateArtifactCounts(result: Pick<SelfGateCliResult, 'baseline'>, capture: Pick<GateArtifactCapture, 'unrunImporters' | 'importerLookupFailed' | 'unmeasuredReason'>):
|
|
139
|
+
{ counts: GateArtifactCounts; reason?: string } {
|
|
140
|
+
const baseline = result.baseline;
|
|
141
|
+
const unrunImporters = capture.unrunImporters ?? null;
|
|
142
|
+
const reasons: string[] = [];
|
|
143
|
+
if (!baseline) reasons.push(capture.unmeasuredReason !== undefined ? `shards unmeasured (${capture.unmeasuredReason})` : 'test step produced no measurement');
|
|
144
|
+
if (unrunImporters === null) reasons.push(`importer lookup failed${capture.importerLookupFailed ? ` (${capture.importerLookupFailed})` : ''}`);
|
|
145
|
+
return {
|
|
146
|
+
counts: {
|
|
147
|
+
introduced: baseline?.introduced ?? null,
|
|
148
|
+
preexisting: baseline?.preexisting ?? null,
|
|
149
|
+
unknown: baseline?.unknown ?? null,
|
|
150
|
+
preconditionUnmet: baseline?.preconditionUnmet ?? null,
|
|
151
|
+
unrunImporters,
|
|
152
|
+
},
|
|
153
|
+
...(reasons.length ? { reason: reasons.join('; ') } : {}),
|
|
154
|
+
};
|
|
102
155
|
}
|
|
103
156
|
|
|
104
157
|
interface GateOutput {
|
|
@@ -178,7 +231,7 @@ function defaultRunCommand(command: string, args: string[], cwd: string): Proces
|
|
|
178
231
|
if (command === 'bun' && args[0] === 'test') {
|
|
179
232
|
let isolated: ReturnType<typeof prepareDeterministicChildEnvironment>;
|
|
180
233
|
try {
|
|
181
|
-
isolated = prepareDeterministicChildEnvironment('elanous-gate-cli-test-env-');
|
|
234
|
+
isolated = prepareDeterministicChildEnvironment('elanous-gate-cli-test-env-', { env: withGateTestEnv(process.env) });
|
|
182
235
|
} catch (error) {
|
|
183
236
|
const message = `deterministic environment setup failed: ${String(error)}`;
|
|
184
237
|
return { status: null, stdout: '', stderr: message, error: error instanceof Error ? error : new Error(message) };
|
|
@@ -592,9 +645,10 @@ function logGateCliBaseline(cwd: string, payload: GateCliBaselinePayload): void
|
|
|
592
645
|
}
|
|
593
646
|
}
|
|
594
647
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
648
|
+
type GateSelectionOptions = Pick<SelfGateCliOptions, 'base' | 'pr' | 'alwaysInclude' | 'includeImporterTests' | 'scenario' | 'scenarioFile'>;
|
|
649
|
+
type GateSelectionDeps = Pick<SelfGateCliDeps, 'changedFiles' | 'exists' | 'isRegularFile' | 'runCommand'>;
|
|
650
|
+
|
|
651
|
+
function prepareGateTestSelection(cwd: string, options: GateSelectionOptions, deps: GateSelectionDeps) {
|
|
598
652
|
const selection = (deps.changedFiles ?? ((dir, input) => defaultChangedFiles(dir, input, deps.runCommand)))(cwd, options);
|
|
599
653
|
const exists = deps.exists ?? ((path) => existsSync(`${cwd}/${path}`));
|
|
600
654
|
// Caller: src/release-loop/light-rc.ts runLightRc → runSelfGateCli(dir, { ..., includeImporterTests: true }).
|
|
@@ -607,13 +661,35 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
607
661
|
? buildRouteConsumerTestIndex(cwd, availableIndex.testPaths, selection.files, selection.baseRef) : null;
|
|
608
662
|
const scope = resolveGateScope(selection.files, exists, availableIndex,
|
|
609
663
|
{ routeConsumerTestIndex: routeIndex ?? undefined });
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
664
|
+
return { selection, exists, lookupFailed, availableIndex, routeIndex, scope };
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function finishGateTestSelection(prepared: ReturnType<typeof prepareGateTestSelection>, options: GateSelectionOptions, cwd: string, deps: GateSelectionDeps) {
|
|
668
|
+
const { selection, exists, lookupFailed, availableIndex, routeIndex, scope } = prepared;
|
|
613
669
|
const alwaysInclude = [...new Set((options.alwaysInclude ?? []).map(normalizeGatePath).filter(Boolean))];
|
|
614
670
|
const alwaysIncludeMissing = alwaysInclude.filter((path) => !exists(path));
|
|
615
671
|
const scopedTests = scope.testArgs ?? [];
|
|
616
672
|
const alwaysIncludeExtra = alwaysInclude.filter((path) => exists(path) && !scopedTests.includes(path));
|
|
673
|
+
let scenarioTests: string[] = [];
|
|
674
|
+
if (options.scenario !== undefined || options.scenarioFile !== undefined) {
|
|
675
|
+
if (options.scenario !== undefined && options.scenarioFile !== undefined) throw new Error('choose scenario or scenarioFile');
|
|
676
|
+
const run = deps.runCommand ?? defaultRunCommand;
|
|
677
|
+
const headSha = requireOutput(run, 'git', ['rev-parse', 'HEAD'], cwd).trim();
|
|
678
|
+
const baseSha = options.base
|
|
679
|
+
? requireOutput(run, 'git', ['merge-base', options.base, 'HEAD'], cwd).trim()
|
|
680
|
+
: requireOutput(run, 'git', ['rev-parse', selection.baseRef], cwd).trim();
|
|
681
|
+
const scenario = parseGateScenario(options.scenarioFile === undefined ? options.scenario : readGateScenarioFile(options.scenarioFile), { baseSha, headSha, changedFiles: selection.files });
|
|
682
|
+
scenarioTests = scenario.selectedTests.map(({ path }) => path);
|
|
683
|
+
if (scenarioTests.some((path) => !exists(path))) throw new Error('gate scenario invalid: selected test missing');
|
|
684
|
+
const isRegularFile = deps.isRegularFile ?? ((dir: string, path: string) => {
|
|
685
|
+
try {
|
|
686
|
+
const root = realpathSync(dir);
|
|
687
|
+
const target = join(dir, path);
|
|
688
|
+
return lstatSync(target).isFile() && realpathSync(target).startsWith(`${root}/`);
|
|
689
|
+
} catch { return false; }
|
|
690
|
+
});
|
|
691
|
+
if (scenarioTests.some((path) => !isRegularFile(cwd, path))) throw new Error('gate scenario invalid: selected test is not a regular file');
|
|
692
|
+
}
|
|
617
693
|
// RELEASE-DAILY-LIGHT-RC ② — the scope already runs importer tests as callers, but capped (GATE_CALLER_TEST_LIMIT);
|
|
618
694
|
// a day of landings overflows that cap and source-only regressions went unrun (0.2.24: 20). Opt-in: every importer.
|
|
619
695
|
const changedSources = selection.files.filter((path) => !isTestPath(path));
|
|
@@ -621,14 +697,90 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
621
697
|
? [...new Set(changedSources.flatMap((source) => availableIndex.testsBySource.get(source) ?? []))]
|
|
622
698
|
.filter((path) => exists(path) && !scopedTests.includes(path) && !alwaysIncludeExtra.includes(path)).sort()
|
|
623
699
|
: [];
|
|
624
|
-
const
|
|
625
|
-
const
|
|
626
|
-
const
|
|
700
|
+
const defaultTests = [...scopedTests, ...alwaysIncludeExtra, ...importerTestsAdded];
|
|
701
|
+
const testFiles = scenarioTests.length ? [...new Set([...defaultTests, ...scenarioTests])] : defaultTests;
|
|
702
|
+
const skipTestStep = scope.skipTestStep && alwaysIncludeExtra.length === 0 && importerTestsAdded.length === 0 && scenarioTests.length === 0;
|
|
703
|
+
const importerTestsNotRun = (options.includeImporterTests || scenarioTests.length > 0) && availableIndex
|
|
627
704
|
? importerTestsNotInRunSet(availableIndex, changedSources, testFiles) : scope.importerTestsNotRun;
|
|
628
705
|
const unrunImporterTotal = lookupFailed ? null : (importerTestsNotRun?.total ?? 0);
|
|
629
706
|
// Overflowed callers that ② ran anyway are not «not run».
|
|
630
|
-
const callerTestsOverflow = scope.callerTestsOverflow.filter(({ file }) => !importerTestsAdded.includes(file));
|
|
707
|
+
const callerTestsOverflow = scope.callerTestsOverflow.filter(({ file }) => !importerTestsAdded.includes(file) && !scenarioTests.includes(file));
|
|
631
708
|
const importerLookupFailed = Boolean(lookupFailed);
|
|
709
|
+
return { ...prepared, alwaysInclude, alwaysIncludeMissing, alwaysIncludeExtra, importerTestsAdded, scenarioTests,
|
|
710
|
+
testFiles, skipTestStep, importerTestsNotRun, unrunImporterTotal, callerTestsOverflow, importerLookupFailed };
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/** Read-only preflight for the same changed-file → importer → scope selection used by `self gate`. */
|
|
714
|
+
export function selectGateTestFiles(cwd: string, options: GateSelectionOptions = {}, deps: GateSelectionDeps = {}) {
|
|
715
|
+
if (options.base && options.pr) throw new Error('use either --base <ref> or --pr <number>, not both');
|
|
716
|
+
const picked = finishGateTestSelection(prepareGateTestSelection(cwd, options, deps), options, cwd, deps);
|
|
717
|
+
return {
|
|
718
|
+
changedFiles: picked.selection.files,
|
|
719
|
+
baseRef: picked.selection.baseRef,
|
|
720
|
+
reason: picked.scope.reason,
|
|
721
|
+
testFiles: picked.testFiles,
|
|
722
|
+
skipTestStep: picked.skipTestStep,
|
|
723
|
+
unverified: picked.scope.unverified,
|
|
724
|
+
alwaysIncludeMissing: picked.alwaysIncludeMissing,
|
|
725
|
+
importerTestsAdded: picked.importerTestsAdded,
|
|
726
|
+
importerTestsNotRun: picked.importerTestsNotRun,
|
|
727
|
+
unrunImporterTotal: picked.unrunImporterTotal,
|
|
728
|
+
lookupFailed: picked.lookupFailed,
|
|
729
|
+
routeLookupFailures: picked.routeIndex?.lookupFailures ?? [],
|
|
730
|
+
callerTestsOverflow: picked.callerTestsOverflow,
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, deps: SelfGateCliDeps = {}): SelfGateCliResult {
|
|
735
|
+
const capture: GateArtifactCapture = {};
|
|
736
|
+
const result = runSelfGateCliCore(cwd, options, deps, capture);
|
|
737
|
+
if (options.artifactDir !== undefined) emitGateArtifacts(cwd, options.artifactDir, result, capture, deps);
|
|
738
|
+
return result;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/** 쓰기 실패는 «경고 한 줄»로만 접는다 — 판정·exit 코드는 그대로다. */
|
|
742
|
+
function emitGateArtifacts(cwd: string, artifactDir: string, result: SelfGateCliResult, capture: GateArtifactCapture, deps: SelfGateCliDeps): void {
|
|
743
|
+
if (!artifactDir.trim()) {
|
|
744
|
+
result.lines.push('⚠ artifacts: --artifact-dir 가 빈 경로라 안 썼다 (판정은 그대로다)');
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
const dir = resolveArtifactDir(artifactDir, cwd);
|
|
748
|
+
try {
|
|
749
|
+
const resolveRev = deps.resolveRev ?? defaultRevResolver(cwd);
|
|
750
|
+
const counts = gateArtifactCounts(result, capture);
|
|
751
|
+
const written = writeGateArtifacts({
|
|
752
|
+
dir,
|
|
753
|
+
head40: resolveRev('HEAD'),
|
|
754
|
+
base40: capture.baseRef ? resolveRev(capture.baseRef) : null,
|
|
755
|
+
envKey: (deps.envKey ?? defaultGateEnvKey)(),
|
|
756
|
+
testFiles: capture.testFiles ?? result.testFiles,
|
|
757
|
+
verdict: capture.verdict ?? null,
|
|
758
|
+
...(capture.verdictLine !== undefined ? { verdictLine: capture.verdictLine } : {}),
|
|
759
|
+
exitCode: result.exitCode,
|
|
760
|
+
counts: counts.counts,
|
|
761
|
+
...(counts.reason !== undefined ? { countsUnavailableReason: counts.reason } : {}),
|
|
762
|
+
...(capture.unmeasuredReason !== undefined ? { unmeasuredReason: capture.unmeasuredReason } : {}),
|
|
763
|
+
...(capture.sharded ? { sharded: capture.sharded } : {}),
|
|
764
|
+
...(capture.unshardedRc !== undefined ? { unshardedRc: capture.unshardedRc } : {}),
|
|
765
|
+
...(capture.artifactsUnavailable ? { artifactsUnavailable: capture.artifactsUnavailable } : {}),
|
|
766
|
+
});
|
|
767
|
+
result.lines.push(`artifacts: ${written.summaryPath} (junit ${written.junitFiles.length}${capture.artifactsUnavailable ? ` · unavailable=${capture.artifactsUnavailable}` : ''})`);
|
|
768
|
+
} catch (error) {
|
|
769
|
+
result.lines.push(`⚠ artifacts: ${dir} 에 못 썼다 — ${error instanceof Error ? error.message : String(error)} (판정은 그대로다)`);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: SelfGateCliDeps, capture: GateArtifactCapture): SelfGateCliResult {
|
|
774
|
+
if (options.base && options.pr) throw new Error('use either --base <ref> or --pr <number>, not both');
|
|
775
|
+
if (options.shards !== undefined && (!Number.isSafeInteger(options.shards) || options.shards < 1)) throw new Error('invalid --shards count');
|
|
776
|
+
if (options.fixedShardDistribution && options.shards === undefined) throw new Error('--fixed-shard-distribution requires --shards <n>');
|
|
777
|
+
const prepared = prepareGateTestSelection(cwd, options, deps);
|
|
778
|
+
const { selection, lookupFailed, routeIndex, scope } = prepared;
|
|
779
|
+
const expose = publicExposureFiles(selection.files).length > 0
|
|
780
|
+
? runExposeGate(cwd, selection.files, getUserConfig().harness?.exposeGate === 'strict' ? 'strict' : 'warn', deps.runCommand)
|
|
781
|
+
: { passed: true, log: '' };
|
|
782
|
+
const { alwaysInclude, alwaysIncludeMissing, alwaysIncludeExtra, importerTestsAdded, scenarioTests, testFiles,
|
|
783
|
+
skipTestStep, importerTestsNotRun, unrunImporterTotal, callerTestsOverflow, importerLookupFailed } = finishGateTestSelection(prepared, options, cwd, deps);
|
|
632
784
|
const lines = [
|
|
633
785
|
// ⛔⭐ 「changed=0」을 «초록»으로 읽는 사고가 났다(2026-09-02 · 🅕 보고 · 🅣 재현).
|
|
634
786
|
// 커밋 «전»에 돌리면 작업 트리 변경은 «안 세므로» changed=0 이 나오는데,
|
|
@@ -662,8 +814,13 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
662
814
|
...(options.includeImporterTests
|
|
663
815
|
? [`importer tests added: ${lookupFailed ? `lookup failed (${lookupFailed})` : `${importerTestsAdded.length} (reason=changed-source-importer${importerTestsAdded.length ? ` · ${importerTestsAdded.join(', ')}` : ''})`}`]
|
|
664
816
|
: []),
|
|
817
|
+
...(options.scenario !== undefined || options.scenarioFile !== undefined ? [`scenario tests: ${scenarioTests.length} (${scenarioTests.join(', ')})`] : []),
|
|
665
818
|
];
|
|
666
819
|
if (expose.log) lines.push(expose.log);
|
|
820
|
+
capture.baseRef = selection.baseRef;
|
|
821
|
+
capture.testFiles = skipTestStep ? [] : testFiles;
|
|
822
|
+
capture.unrunImporters = unrunImporterTotal;
|
|
823
|
+
if (lookupFailed) capture.importerLookupFailed = lookupFailed;
|
|
667
824
|
if (options.pr) {
|
|
668
825
|
const worktreeObservation = observePrWorktreeDirtiness(cwd, selection.prHeadRefName, {
|
|
669
826
|
runCommand: deps.runCommand,
|
|
@@ -687,12 +844,22 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
687
844
|
if (skipTestStep) {
|
|
688
845
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
689
846
|
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
847
|
+
Object.assign(capture, { verdict: 'skipped', artifactsUnavailable: 'no-tests' } satisfies GateArtifactCapture);
|
|
690
848
|
return { exitCode: androidPassed && iosPassed && pwaPassed && policyPassed && expose.passed ? 0 : 1, lines, changedFiles: selection.files, testFiles: [], unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, importerTestsAdded, baseline: { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 } };
|
|
691
849
|
}
|
|
692
850
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
851
|
+
// The default direct Bun path has one process and one 300s limit. Route real child/PTY tests through
|
|
852
|
+
// the separated shard runner even when the caller did not request --shards.
|
|
853
|
+
if (options.shards !== undefined || testFiles.some(isGateSpawnLaneFile)) {
|
|
854
|
+
const spawnFileCount = testFiles.filter(isGateSpawnLaneFile).length;
|
|
855
|
+
const shardCount = options.shards ?? (Math.min(3, spawnFileCount) + Number(testFiles.length > spawnFileCount));
|
|
856
|
+
const runShards = deps.runShards ?? runShardedGateTests;
|
|
857
|
+
const sharded = options.fixedShardDistribution
|
|
858
|
+
? runShards(cwd, testFiles, selection.baseRef, shardCount, undefined, undefined, undefined, { fixedDistribution: true })
|
|
859
|
+
: runShards(cwd, testFiles, selection.baseRef, shardCount);
|
|
860
|
+
capture.sharded = sharded;
|
|
861
|
+
capture.verdict = sharded.aggregate.status;
|
|
862
|
+
lines.push(`shards: ${sharded.shards.length} (${sharded.shards.map((shard) => `${shard.id}=${shard.files.join(',')}`).join('; ')})${sharded.measurementFailures ? ` · 측정 실패 ${sharded.measurementFailures}` : ''}${options.fixedShardDistribution ? ' · 고정 분배(사전 측정 없음)' : ''}`);
|
|
696
863
|
// 조각이 «못 쟀다»일 때 이유가 줄에 없으면 자리·시간 초과·죽음을 가를 수 없다(OP 10-09 light RC) — 종료 코드·신호를 같이 싣는다.
|
|
697
864
|
const side = (code: number | null, signal: string | null | undefined, junit: string | undefined) => signal ? `signal ${signal}` : code === null ? 'exit ?' : `exit ${code}${junit === undefined ? ' · junit 없음' : ''}`;
|
|
698
865
|
for (const attempt of sharded.attempts) {
|
|
@@ -705,12 +872,23 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
705
872
|
if (attempt.currentJUnit === undefined && attempt.currentDiagnostic) lines.push(`shard diagnostic: ${attempt.shardId} #${attempt.attempt} 지금 · ${renderDiagnostic(attempt.currentDiagnostic)}`);
|
|
706
873
|
if (attempt.baselineJUnit === undefined && attempt.baselineDiagnostic) lines.push(`shard diagnostic: ${attempt.shardId} #${attempt.attempt} 기준 · ${renderDiagnostic(attempt.baselineDiagnostic)}`);
|
|
707
874
|
}
|
|
875
|
+
// OP FU (MK #8178 shard-9) — 실패 조각의 자식 출력 꼬리 ⊕ exit/signal 을 파일로 남긴다(관측만 · 판정·exit 불변).
|
|
876
|
+
// --artifact-dir 이 있으면 그 아래, 없으면 임시 디렉토리(JUnit 임시 디렉토리 옆 tmpdir)에.
|
|
877
|
+
if (sharded.failureEvidence?.length) {
|
|
878
|
+
try {
|
|
879
|
+
const evidenceDir = options.artifactDir?.trim() ? resolveArtifactDir(options.artifactDir, cwd) : mkdtempSync(join(tmpdir(), 'elanous-shard-failure-'));
|
|
880
|
+
for (const path of writeShardFailureEvidence(evidenceDir, sharded.failureEvidence)) lines.push(`shard failure evidence: ${path}`);
|
|
881
|
+
} catch (error) {
|
|
882
|
+
lines.push(`⚠ shard failure evidence: 못 썼다 — ${error instanceof Error ? error.message : String(error)} (판정은 그대로다)`);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
708
885
|
const { aggregate } = sharded;
|
|
709
886
|
let shardBaseline: SelfGateCliResult['baseline'];
|
|
710
887
|
let unmeasuredReason: string | undefined;
|
|
711
888
|
if (aggregate.status === 'unmeasured') {
|
|
712
889
|
unmeasuredReason = aggregate.retryShardIds.join(', ') || sharded.reason || 'no complete JUnit';
|
|
713
890
|
lines.push(`shards: unmeasured (${unmeasuredReason})`);
|
|
891
|
+
capture.unmeasuredReason = unmeasuredReason;
|
|
714
892
|
}
|
|
715
893
|
else if (aggregate.report) {
|
|
716
894
|
const report = aggregate.report;
|
|
@@ -727,6 +905,7 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
727
905
|
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
728
906
|
shardBaseline = { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 };
|
|
729
907
|
}
|
|
908
|
+
capture.verdictLine = lines[lines.length - 1];
|
|
730
909
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
731
910
|
return {
|
|
732
911
|
exitCode: aggregate.status !== 'passed' || !policyPassed || !androidPassed || !iosPassed || !pwaPassed || !expose.passed ? 1 : 0,
|
|
@@ -739,8 +918,10 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
739
918
|
|
|
740
919
|
const test = (deps.runTests ?? ((dir, files) => (deps.runCommand ?? defaultRunCommand)('bun', ['test', ...files], dir)))(cwd, testFiles);
|
|
741
920
|
const worktreeLog = formatProcessOutput(test);
|
|
921
|
+
Object.assign(capture, { unshardedRc: test.status, artifactsUnavailable: 'unsharded' } satisfies GateArtifactCapture);
|
|
742
922
|
if (test.status === 0 && !test.error) {
|
|
743
923
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
|
|
924
|
+
Object.assign(capture, { verdict: 'passed', verdictLine: lines[lines.length - 1] } satisfies GateArtifactCapture);
|
|
744
925
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
745
926
|
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
746
927
|
return { exitCode: policyPassed && androidPassed && iosPassed && pwaPassed && expose.passed ? 0 : 1, lines, changedFiles: selection.files, testFiles, unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, importerTestsAdded, baseline: { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 } };
|
|
@@ -763,6 +944,10 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
763
944
|
lookupFailed: importerLookupFailed,
|
|
764
945
|
});
|
|
765
946
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, formatGateBaselineNote(report, unrunImporterTotal ?? 0)));
|
|
947
|
+
Object.assign(capture, {
|
|
948
|
+
verdict: report.introduced > 0 || report.unknown > 0 || report.preconditionUnmet > 0 ? 'failed' : 'passed',
|
|
949
|
+
verdictLine: lines[lines.length - 1],
|
|
950
|
+
} satisfies GateArtifactCapture);
|
|
766
951
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
767
952
|
const exitCode = !androidPassed || !iosPassed || !pwaPassed || !policyPassed || !expose.passed || report.introduced > 0 || report.unknown > 0 || report.preconditionUnmet > 0 ? 1 : 0;
|
|
768
953
|
return { exitCode, lines, changedFiles: selection.files, testFiles, unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, importerTestsAdded, baseline: { introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown, preconditionUnmet: report.preconditionUnmet } };
|
|
@@ -7,6 +7,7 @@ import { existsSync, lstatSync, realpathSync } from 'node:fs';
|
|
|
7
7
|
import { loadavg } from 'node:os';
|
|
8
8
|
import { isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
9
9
|
import { debug } from '../debug/log.js';
|
|
10
|
+
import { gateHostReservationRoot, inspectReleaseGateHost } from '../release-loop/gate-host-reservation.js';
|
|
10
11
|
import type { GateRemoteConfig } from '../user-config.js';
|
|
11
12
|
|
|
12
13
|
export type GateRemoteTool = 'self-gate' | 'ci-typecheck-changed' | 'public-export-test-run';
|
|
@@ -16,14 +17,15 @@ export interface GateRemoteSettings {
|
|
|
16
17
|
host: string;
|
|
17
18
|
loadThreshold: number;
|
|
18
19
|
hostCap: number;
|
|
20
|
+
hostCaps?: Record<string, number>;
|
|
19
21
|
mirror: string;
|
|
20
22
|
slotWaitSeconds: number;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
export const MAX_HOST_CAP =
|
|
25
|
+
export const MAX_HOST_CAP = 8;
|
|
24
26
|
|
|
25
27
|
export const GATE_REMOTE_DEFAULTS: GateRemoteSettings = {
|
|
26
|
-
enabled: true, host: 'node-b', loadThreshold: 20, hostCap: 2, mirror: '~/mirror/elanous-agent.git', slotWaitSeconds: 600,
|
|
28
|
+
enabled: true, host: 'node-b', loadThreshold: 20, hostCap: 2, hostCaps: {}, mirror: '~/mirror/elanous-agent.git', slotWaitSeconds: 600,
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
const hostPattern = /^(?:[\w.-]+@)?[\w.-]+$/;
|
|
@@ -43,13 +45,23 @@ export function resolveGateRemoteSettings(config: GateRemoteConfig | undefined,
|
|
|
43
45
|
enabled: config?.enabled ?? envEnabled ?? GATE_REMOTE_DEFAULTS.enabled,
|
|
44
46
|
host: isValidGateHost(host) ? host : GATE_REMOTE_DEFAULTS.host,
|
|
45
47
|
loadThreshold: config?.loadThreshold ?? envLoad ?? GATE_REMOTE_DEFAULTS.loadThreshold,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
hostCap: Math.min(GATE_REMOTE_DEFAULTS.hostCap, Math.max(1, Math.floor(config?.hostCap ?? GATE_REMOTE_DEFAULTS.hostCap))),
|
|
49
|
+
hostCaps: Object.fromEntries(Object.entries(config?.hostCaps ?? {}).filter(([key, value]) =>
|
|
50
|
+
isValidGateHost(key) && Number.isSafeInteger(value) && value >= 1 && value <= MAX_HOST_CAP)),
|
|
48
51
|
mirror: mirrorPattern.test(mirror) && !mirror.split('/').includes('..') ? mirror : GATE_REMOTE_DEFAULTS.mirror,
|
|
49
52
|
slotWaitSeconds: config?.slotWaitSeconds ?? GATE_REMOTE_DEFAULTS.slotWaitSeconds,
|
|
50
53
|
};
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
/** Explicit and rerouted hosts use their own slot budget; absent entries retain the default cap. */
|
|
57
|
+
export function gateRemoteHostCap(settings: GateRemoteSettings, host: string): number {
|
|
58
|
+
const caps = settings.hostCaps;
|
|
59
|
+
const bareHost = host.split('@').at(-1)!;
|
|
60
|
+
const configured = caps && Object.hasOwn(caps, host) ? caps[host]
|
|
61
|
+
: caps && Object.hasOwn(caps, bareHost) ? caps[bareHost] : undefined;
|
|
62
|
+
return Math.min(MAX_HOST_CAP, Math.max(1, Math.floor(configured ?? settings.hostCap)));
|
|
63
|
+
}
|
|
64
|
+
|
|
53
65
|
/** The token after a bare `--remote` is its host when it is a valid ssh destination that is not an existing path and does
|
|
54
66
|
* not look like a test/list file — so `--remote node-b.lan a.test.ts` takes the host and `--remote a.test.ts` keeps the file. */
|
|
55
67
|
export function looksLikeHost(token: string, exists: (path: string) => boolean = existsSync): boolean {
|
|
@@ -105,17 +117,21 @@ export type SlotLockTool = 'flock' | 'lockf';
|
|
|
105
117
|
const SLOT_LOCK = { flock: 'flock -n', lockf: 'lockf -k -s -t 0' } as const;
|
|
106
118
|
|
|
107
119
|
/** `tools` is the preference order (default: Linux flock, then BSD/macOS lockf); a test can pin one path. */
|
|
108
|
-
|
|
120
|
+
function hostSlotScriptWithSlot(cap: number, dir: string, tools: readonly SlotLockTool[], passSlot: boolean): string[] {
|
|
109
121
|
const n = Math.min(MAX_HOST_CAP, Math.max(1, Math.floor(cap)));
|
|
110
122
|
const pick = tools.map((tool, i) => `${i ? 'elif' : 'if'} command -v ${tool} >/dev/null 2>&1; then GL="${SLOT_LOCK[tool]}"; `).join('');
|
|
111
123
|
return [
|
|
112
124
|
`GS=${quote(dir)}; mkdir -p "$GS" || infra slots`,
|
|
113
125
|
`${pick}else infra lock-tool; fi`,
|
|
114
|
-
`n=1; while [ $n -le ${n} ]; do $GL "$GS/slot$n" sh "$W/run.sh"; s=$?; [ -f "$W/started" ] && exit $s; n=$((n+1)); done`,
|
|
115
|
-
`echo "${BUSY}" >&2; exit 98`,
|
|
126
|
+
`n=1; while [ $n -le ${n} ]; do $GL "$GS/slot$n" ${passSlot ? 'env GATE_REMOTE_SLOT="$n" ' : ''}sh "$W/run.sh"; s=$?; [ -f "$W/started" ] && exit $s; n=$((n+1)); done`,
|
|
127
|
+
`echo "${BUSY}=$((n-1))" >&2; exit 98`,
|
|
116
128
|
];
|
|
117
129
|
}
|
|
118
130
|
|
|
131
|
+
export function hostSlotScript(cap: number, dir = SLOT_DIR, tools: readonly SlotLockTool[] = ['flock', 'lockf']): string[] {
|
|
132
|
+
return hostSlotScriptWithSlot(cap, dir, tools, false);
|
|
133
|
+
}
|
|
134
|
+
|
|
119
135
|
// ── remote execution ───────────────────────────────────────────────
|
|
120
136
|
|
|
121
137
|
export interface ExecResult { rc: number | null; stdout: string; stderr: string; error?: string }
|
|
@@ -149,7 +165,7 @@ export const PUSH_TIMEOUT_MS = 10 * 60_000;
|
|
|
149
165
|
|
|
150
166
|
export type RemoteRunOutcome =
|
|
151
167
|
| { kind: 'ran'; rc: number; stdout: Buffer; stderr: Buffer; commit: string; host: string; ms: number }
|
|
152
|
-
| { kind: 'busy' }
|
|
168
|
+
| { kind: 'busy'; occupied?: number }
|
|
153
169
|
| { kind: 'infra'; reason: string };
|
|
154
170
|
|
|
155
171
|
export interface RemoteRunOptions {
|
|
@@ -167,6 +183,8 @@ export interface RemoteRunOptions {
|
|
|
167
183
|
/** Extra local refs whose commits must exist remotely (e.g. a --base ref). Resolved to shas. */
|
|
168
184
|
refs?: string[];
|
|
169
185
|
installPwa?: boolean;
|
|
186
|
+
/** An exclusive slot checkout path allows the opt-in TypeScript graph cache to survive scratch runs. */
|
|
187
|
+
stableCheckout?: boolean;
|
|
170
188
|
timeoutMs?: number;
|
|
171
189
|
/** Files the remote run needs from this machine (e.g. the private export redaction table): sent over ssh stdin, written
|
|
172
190
|
* mode 600 inside the scratch directory, exposed to the tool via `env`, removed with it. Never on argv. */
|
|
@@ -177,7 +195,7 @@ export interface PayloadFile { env: string; content: string }
|
|
|
177
195
|
export type RemoteArgv = string[] | ((sha: (ref: string) => string) => string[]);
|
|
178
196
|
|
|
179
197
|
/** Build the remote shell script (exported for tests). Every setup failure ends in an INFRA marker, the tool's rc in an RC marker. */
|
|
180
|
-
export function remoteScript(input: { mirror: string; commit: string; fetchShas: string[]; mainSha?: string; argv: string[]; installPwa: boolean; payloadFiles?: PayloadFile[]; hostCap?: number; slotDir?: string }): string {
|
|
198
|
+
export function remoteScript(input: { mirror: string; commit: string; fetchShas: string[]; mainSha?: string; argv: string[]; installPwa: boolean; stableCheckout?: boolean; payloadFiles?: PayloadFile[]; hostCap?: number; slotDir?: string }): string {
|
|
181
199
|
const mirror = input.mirror.startsWith('~/') ? `"$HOME"/${quote(input.mirror.slice(2))}` : quote(input.mirror);
|
|
182
200
|
const fetches = input.fetchShas.map((sha) => `refs/elanous/gate/${sha}:refs/elanous/gate/${sha}`).join(' ');
|
|
183
201
|
const payloads = (input.payloadFiles ?? []).filter((file) => /^[A-Z_][A-Z0-9_]*$/.test(file.env));
|
|
@@ -193,8 +211,25 @@ export function remoteScript(input: { mirror: string; commit: string; fetchShas:
|
|
|
193
211
|
const work = [
|
|
194
212
|
`infra() { echo "${INFRA}$1" >&2; exit 97; }`,
|
|
195
213
|
': > "$W/started"',
|
|
196
|
-
|
|
197
|
-
|
|
214
|
+
...(input.stableCheckout ? [
|
|
215
|
+
'T="$HOME/.cache/elanous/gate-remote/slot$GATE_REMOTE_SLOT/checkout"',
|
|
216
|
+
'mkdir -p "$(dirname "$T")" || infra stable-dir',
|
|
217
|
+
'if [ -d "$T/.git" ]; then',
|
|
218
|
+
' git -C "$T" reset --hard -q >>"$W/setup.log" 2>&1 || infra stable-reset',
|
|
219
|
+
' git -C "$T" clean -ffd -q >>"$W/setup.log" 2>&1 || infra stable-clean',
|
|
220
|
+
` git -C "$T" remote set-url origin ${mirror} >>"$W/setup.log" 2>&1 || infra stable-origin`,
|
|
221
|
+
'else',
|
|
222
|
+
' rm -rf "$T" || infra stable-remove',
|
|
223
|
+
` git clone -q --shared --no-checkout ${mirror} "$T" >"$W/setup.log" 2>&1 || infra clone`,
|
|
224
|
+
'fi',
|
|
225
|
+
'rm -rf "$T/apps/pwa/.next" || infra pwa-build-clean',
|
|
226
|
+
'rm -f "$T/apps/pwa/"*.tsbuildinfo || infra pwa-buildinfo-clean',
|
|
227
|
+
'ELANOUS_TSC_CACHE_DIR="$HOME/.cache/elanous/gate-remote/slot$GATE_REMOTE_SLOT/cache"; export ELANOUS_TSC_CACHE_DIR',
|
|
228
|
+
] : [
|
|
229
|
+
'T="$W/t"',
|
|
230
|
+
`git clone -q --shared --no-checkout ${mirror} "$T" >"$W/setup.log" 2>&1 || infra clone`,
|
|
231
|
+
]),
|
|
232
|
+
'cd "$T" || infra cd',
|
|
198
233
|
`git fetch -q origin ${fetches} >>"$W/setup.log" 2>&1 || infra fetch`,
|
|
199
234
|
`git checkout -q --detach ${input.commit} >>"$W/setup.log" 2>&1 || infra checkout`,
|
|
200
235
|
...(input.mainSha ? [`git update-ref refs/remotes/origin/main ${input.mainSha} || infra origin-main`] : []),
|
|
@@ -221,7 +256,7 @@ export function remoteScript(input: { mirror: string; commit: string; fetchShas:
|
|
|
221
256
|
`cat > "$W/run.sh" <<'${RUN}' || infra run-script`,
|
|
222
257
|
...work,
|
|
223
258
|
RUN,
|
|
224
|
-
...
|
|
259
|
+
...hostSlotScriptWithSlot(input.hostCap ?? GATE_REMOTE_DEFAULTS.hostCap, input.slotDir ?? SLOT_DIR, ['flock', 'lockf'], !!input.stableCheckout),
|
|
225
260
|
'}',
|
|
226
261
|
'',
|
|
227
262
|
].join('\n');
|
|
@@ -277,7 +312,7 @@ export function runOnRemote(opts: RemoteRunOptions, runner: GateRemoteRunner = r
|
|
|
277
312
|
env: { ...process.env, GIT_SSH_COMMAND: 'ssh -o BatchMode=yes -o ConnectTimeout=10', GIT_TERMINAL_PROMPT: '0' },
|
|
278
313
|
});
|
|
279
314
|
if (push.rc !== 0 || push.error) return { kind: 'infra', reason: `push-failed rc=${push.rc}: ${(push.stderr || push.error || '').trim().split('\n').slice(-2).join(' | ')}` };
|
|
280
|
-
const script = remoteScript({ mirror: opts.mirror, commit, fetchShas: shas, mainSha, argv, installPwa: opts.installPwa ?? false, payloadFiles: opts.payloadFiles, hostCap: opts.hostCap, slotDir: opts.slotDir });
|
|
315
|
+
const script = remoteScript({ mirror: opts.mirror, commit, fetchShas: shas, mainSha, argv, installPwa: opts.installPwa ?? false, stableCheckout: opts.stableCheckout, payloadFiles: opts.payloadFiles, hostCap: opts.hostCap, slotDir: opts.slotDir });
|
|
281
316
|
const run = runner.ssh(opts.host, script, opts.timeoutMs ?? 120 * 60_000);
|
|
282
317
|
// The script prints "\n<marker><rc>\n": everything before that leading newline is the tool's own stderr, byte for byte.
|
|
283
318
|
const stdoutBytes = Buffer.from(run.stdout);
|
|
@@ -288,7 +323,10 @@ export function runOnRemote(opts: RemoteRunOptions, runner: GateRemoteRunner = r
|
|
|
288
323
|
// run exits 0 after the rc marker, and its stderr belongs to the tool — never scanned for markers.
|
|
289
324
|
if (!(run.rc === 0 && marker >= 0)) {
|
|
290
325
|
const last = stderrText.trimEnd().split('\n').at(-1) ?? '';
|
|
291
|
-
if (run.rc === 98
|
|
326
|
+
if (run.rc === 98) {
|
|
327
|
+
const busy = /^__GATE_REMOTE_BUSY(?:=(\d+))?$/.exec(last);
|
|
328
|
+
if (busy) return { kind: 'busy', ...(busy[1] !== undefined ? { occupied: Number(busy[1]) } : {}) };
|
|
329
|
+
}
|
|
292
330
|
if (run.rc === 97 && last.startsWith(INFRA)) return { kind: 'infra', reason: `remote-${last.slice(INFRA.length).trim()}` };
|
|
293
331
|
}
|
|
294
332
|
// No marker, or ssh did not end cleanly after it (the script always exits 0 once the marker is written): output may be cut.
|
|
@@ -371,10 +409,20 @@ export interface DispatchOptions {
|
|
|
371
409
|
installPwa?: boolean;
|
|
372
410
|
payloadFiles?: PayloadFile[];
|
|
373
411
|
json?: boolean;
|
|
374
|
-
/** Set when this invocation cannot be reproduced remotely (e.g. self gate without --base):
|
|
375
|
-
*
|
|
412
|
+
/** Set when this invocation cannot be reproduced remotely (e.g. self gate without --base): automatic placement
|
|
413
|
+
* falls back with this reason; an explicit self gate --remote reports an unmeasured check instead. */
|
|
376
414
|
localOnlyReason?: string;
|
|
415
|
+
/** Self gate CLI only: explicit --remote must never be measured by a local fallback. */
|
|
416
|
+
explicitRemoteOnly?: boolean;
|
|
417
|
+
/** Self gate CLI only: name the host for both automatic and explicit remote execution. */
|
|
418
|
+
reportRemoteHost?: boolean;
|
|
419
|
+
/** Self gate's state universe; omitted by other callers and injected tests. */
|
|
420
|
+
reservationRoot?: string;
|
|
377
421
|
runLocal: () => number | Promise<number>;
|
|
422
|
+
/** Called once with the final remote outcome (never on a local decision), before its output passes through or the
|
|
423
|
+
* local fallback runs — e.g. `self gate --artifact-dir` fetches (ran) or removes (infra) the host-side artifact dir.
|
|
424
|
+
* A throw is logged and swallowed: the hook never changes the check's rc. */
|
|
425
|
+
onRemoteOutcome?: (outcome: RemoteRunOutcome, host: string, runner: GateRemoteRunner) => void;
|
|
378
426
|
}
|
|
379
427
|
|
|
380
428
|
export interface DispatchDeps {
|
|
@@ -394,21 +442,52 @@ async function loadSettings(): Promise<GateRemoteSettings> {
|
|
|
394
442
|
} catch { return resolveGateRemoteSettings(undefined); }
|
|
395
443
|
}
|
|
396
444
|
|
|
397
|
-
/** Decide local/remote, run, and return the tool's exit code.
|
|
445
|
+
/** Decide local/remote, run, and return the tool's exit code. Automatic infra failure ⇒ visible local fallback. */
|
|
398
446
|
export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDeps = {}): Promise<number> {
|
|
399
447
|
const settings = deps.settings ?? await loadSettings();
|
|
400
448
|
const env = deps.env ?? process.env;
|
|
401
449
|
const write = deps.write ?? { out: (d: string | Uint8Array) => process.stdout.write(d), err: (d: string | Uint8Array) => process.stderr.write(d) };
|
|
402
450
|
const decision = decideGateDispatch({ flags: opts.flags, settings, load1: deps.load1 ?? loadavg()[0]!, env });
|
|
403
451
|
debug.log('gate.remote', 'decision', { tool: opts.tool, mode: decision.mode, host: decision.host, reason: decision.reason, load1: decision.load1 });
|
|
404
|
-
if (decision.mode === 'local')
|
|
405
|
-
|
|
452
|
+
if (decision.mode === 'local') {
|
|
453
|
+
if (opts.explicitRemoteOnly && opts.flags.remote !== undefined && decision.reason !== 'flag-local') {
|
|
454
|
+
write.err(`[gate.remote] remote unmeasured — ${decision.reason}\n`);
|
|
455
|
+
return 1;
|
|
456
|
+
}
|
|
457
|
+
return opts.runLocal();
|
|
458
|
+
}
|
|
459
|
+
let host = decision.host!;
|
|
460
|
+
const reservationRoot = opts.tool === 'self-gate' ? opts.reservationRoot ?? (deps.runner ? undefined : gateHostReservationRoot()) : undefined;
|
|
461
|
+
if (reservationRoot) {
|
|
462
|
+
const reservationHost = host.split('@').at(-1)!;
|
|
463
|
+
const first = inspectReleaseGateHost(reservationRoot, reservationHost);
|
|
464
|
+
if (first.status !== 'free') {
|
|
465
|
+
const alternate = reservationHost === 'node-b' ? 'node-c' : null;
|
|
466
|
+
const other = alternate ? inspectReleaseGateHost(reservationRoot, alternate) : null;
|
|
467
|
+
if (alternate && other?.status === 'free') {
|
|
468
|
+
debug.log('gate.remote', 'host-reserved-reroute', { from: host, to: alternate, reason: first.reason, status: first.status });
|
|
469
|
+
write.err(`[gate.remote] ${host} reserved (${first.reason}) — using ${alternate}\n`);
|
|
470
|
+
host = alternate;
|
|
471
|
+
} else {
|
|
472
|
+
const reason = `host-reserved: ${host} (${first.reason}); alternate ${alternate ?? '(none)'} ${other?.status ?? 'unavailable'}`;
|
|
473
|
+
debug.log('gate.remote', 'host-reserved-unmeasured', { host, reason });
|
|
474
|
+
write.err(`[gate.remote] remote unmeasured — ${reason}\n`);
|
|
475
|
+
return 1;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
406
479
|
const fallback = (reason: string) => {
|
|
480
|
+
if (opts.explicitRemoteOnly && opts.flags.remote !== undefined) {
|
|
481
|
+
debug.log('gate.remote', 'remote-unmeasured', { tool: opts.tool, host, reason });
|
|
482
|
+
write.err(`[gate.remote] remote unmeasured on ${host} — ${reason.replace(/\s+/g, ' ').trim()}\n`);
|
|
483
|
+
return 1;
|
|
484
|
+
}
|
|
407
485
|
debug.log('gate.remote', 'fallback', { tool: opts.tool, host, reason });
|
|
408
486
|
write.err(`[gate.remote] fallback to local — ${reason}\n`);
|
|
409
487
|
return opts.runLocal();
|
|
410
488
|
};
|
|
411
489
|
if (opts.localOnlyReason) return fallback(opts.localOnlyReason);
|
|
490
|
+
const hostCap = gateRemoteHostCap(settings, host);
|
|
412
491
|
const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
|
|
413
492
|
const now = deps.now ?? Date.now;
|
|
414
493
|
const deadline = now() + settings.slotWaitSeconds * 1000;
|
|
@@ -416,26 +495,32 @@ export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDe
|
|
|
416
495
|
let outcome: RemoteRunOutcome;
|
|
417
496
|
for (;;) {
|
|
418
497
|
try {
|
|
419
|
-
outcome = runOnRemote({ repo: opts.repo, host, mirror: settings.mirror, argv: opts.remoteArgv, refs: opts.refs, ...(opts.commit !== undefined ? { commit: opts.commit } : {}), installPwa: opts.installPwa, payloadFiles: opts.payloadFiles, hostCap
|
|
498
|
+
outcome = runOnRemote({ repo: opts.repo, host, mirror: settings.mirror, argv: opts.remoteArgv, refs: opts.refs, ...(opts.commit !== undefined ? { commit: opts.commit } : {}), installPwa: opts.installPwa, payloadFiles: opts.payloadFiles, hostCap }, deps.runner);
|
|
420
499
|
} catch (error) {
|
|
421
500
|
outcome = { kind: 'infra', reason: `exception: ${error instanceof Error ? error.message : String(error)}` };
|
|
422
501
|
}
|
|
423
502
|
if (outcome.kind !== 'busy') break;
|
|
424
|
-
debug.log('gate.remote', 'host-busy', { tool: opts.tool, host, cap:
|
|
425
|
-
// Never start an attempt past the deadline: an expired wait
|
|
503
|
+
debug.log('gate.remote', 'host-busy', { tool: opts.tool, host, cap: hostCap, occupied: outcome.occupied ?? null });
|
|
504
|
+
// Never start an attempt past the deadline: an expired wait falls back only for automatic placement.
|
|
426
505
|
const left = deadline - now();
|
|
427
506
|
if (left <= 0) break;
|
|
428
507
|
await sleep(Math.min(15_000, left));
|
|
429
508
|
if (now() >= deadline) break;
|
|
430
509
|
}
|
|
431
|
-
if (
|
|
510
|
+
if (opts.onRemoteOutcome) {
|
|
511
|
+
try { opts.onRemoteOutcome(outcome, host, deps.runner ?? realGateRemoteRunner); }
|
|
512
|
+
catch (error) { debug.log('gate.remote', 'outcome-hook-failed', { tool: opts.tool, host, error: error instanceof Error ? error.message : String(error) }); }
|
|
513
|
+
}
|
|
514
|
+
if (outcome.kind === 'busy') return fallback(`host-busy (occupied ${outcome.occupied ?? 'unknown'}/${hostCap}, held for ${settings.slotWaitSeconds}s)`);
|
|
432
515
|
if (outcome.kind === 'infra') return fallback(outcome.reason);
|
|
433
|
-
// Parity: the tool's own stdout/stderr/rc pass through unchanged
|
|
516
|
+
// Parity: the tool's own stdout/stderr/rc pass through unchanged; JSON gains host · remote:true,
|
|
517
|
+
// and the self gate CLI appends a host diagnostic to human-readable stderr.
|
|
434
518
|
debug.log('gate.remote', 'result', { tool: opts.tool, host: outcome.host, commit: outcome.commit, rc: outcome.rc, ms: outcome.ms });
|
|
435
|
-
//
|
|
519
|
+
// Tool bytes pass through untouched; only a JSON object stdout is re-serialised (to add host · remote:true).
|
|
436
520
|
const text = opts.json ? outcome.stdout.toString('utf8') : undefined;
|
|
437
521
|
const annotated = text !== undefined ? annotateJsonStdout(text, outcome.host) : undefined;
|
|
438
522
|
write.out(annotated !== undefined && annotated !== text ? annotated : outcome.stdout);
|
|
439
523
|
write.err(outcome.stderr);
|
|
524
|
+
if (opts.reportRemoteHost && !opts.json) write.err(`[gate.remote] executed on ${outcome.host} (rc=${outcome.rc})\n`);
|
|
440
525
|
return outcome.rc;
|
|
441
526
|
}
|