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
|
@@ -16,7 +16,7 @@ import { collectPodArtifacts } from './pod-artifact-return.js';
|
|
|
16
16
|
import { getDefaultLogStore, type LogStore } from '../../mss/logging/log-store.js';
|
|
17
17
|
import { podBunCacheVolume } from './pod-bun-cache.js';
|
|
18
18
|
import { POD_JOB_TTL_AFTER_FINISHED_SECONDS } from './pod-lease.js';
|
|
19
|
-
import {
|
|
19
|
+
import { podHostDirsCheckScript, podInstallSlotsVolume, prepareHostDirsOnce, type HostDirsPrepResult, podHostDirsScript } from './pod-install-slots.js';
|
|
20
20
|
import { type PodPoolMember, PodPoolScheduler, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, type PoolKubectl } from './pod-pool.js';
|
|
21
21
|
import { podSkillsDigest, readSkillEnvFiles, resolvePodSkills } from './pod-skills.js';
|
|
22
22
|
import { podSourceScript, type PodSource } from './pod-source-receive.js';
|
|
@@ -40,11 +40,18 @@ export const POD_LITE_IMAGE = 'elanous-harness-lite:local';
|
|
|
40
40
|
|
|
41
41
|
export const POD_LITE_MEMORY_LIMIT = '2Gi';
|
|
42
42
|
|
|
43
|
+
/** W5 (10-15 #27801): where a memory-backed TMPDIR is mounted for release gate shards — the overlayfs `/tmp` made SQLite
|
|
44
|
+
* tests take 0.4~5s per turn (once 124s). tmpfs pages count against the container memory limit, so the caller's cap
|
|
45
|
+
* (`tmpfsSizeLimit`) stays small next to the 16Gi shard limit (request 6Gi). */
|
|
46
|
+
export const POD_TMPFS_MOUNT_PATH = '/tmp-mem';
|
|
47
|
+
|
|
43
48
|
/** 요청은 한도를 넘을 수 없다(쿠버네티스가 Job 을 거부한다) — lite 2Gi 처럼 한도가 기본 요청보다 작으면 한도로 맞춘다. */
|
|
44
49
|
/** The command Job container's CPU limit when the caller names none (GATE-SPEED A3①: unchanged default). */
|
|
45
50
|
export const POD_COMMAND_CPU_LIMIT_DEFAULT = '4';
|
|
46
51
|
/** 게이트 조각·pod-command 의 CPU 요청 기본 — 하니스 Pod(POD_CHILD_REQUESTS.cpu)와 따로 둔다(조각은 bun test 로 CPU 를 실제로 쓴다). */
|
|
47
52
|
export const POD_COMMAND_CPU_REQUEST_DEFAULT = '1';
|
|
53
|
+
/** Gate and command Pods retain their measured 6Gi scheduler request; si-task admission uses its own size. */
|
|
54
|
+
export const POD_COMMAND_MEMORY_REQUEST_DEFAULT = '6Gi';
|
|
48
55
|
|
|
49
56
|
/** Container CPU request/limit override. Omitted fields keep the defaults (request `POD_COMMAND_CPU_REQUEST_DEFAULT` · limit 4). */
|
|
50
57
|
export interface PodCpu { request?: string; limit?: string }
|
|
@@ -93,9 +100,9 @@ export function parsePodCpu(value: unknown, label = 'cpu'): PodCpu | undefined {
|
|
|
93
100
|
|
|
94
101
|
export function memoryRequestWithin(limit: string | undefined): string {
|
|
95
102
|
const gi = (value: string | undefined) => { const m = /^(\d+)Gi$/.exec(value ?? ''); return m ? Number(m[1]) : null; };
|
|
96
|
-
const request = gi(
|
|
103
|
+
const request = gi(POD_COMMAND_MEMORY_REQUEST_DEFAULT);
|
|
97
104
|
const max = gi(limit);
|
|
98
|
-
return request !== null && max !== null && request > max ? limit! :
|
|
105
|
+
return request !== null && max !== null && request > max ? limit! : POD_COMMAND_MEMORY_REQUEST_DEFAULT;
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
/** POD7 must-fix: the skill list alone can't tell a network-only job from one that needs ffmpeg/browser — so lite is
|
|
@@ -133,18 +140,24 @@ export function tailBytes(text: string, maxBytes: number): string {
|
|
|
133
140
|
return `…[앞 ${bytes.length - maxBytes}바이트 생략]\n${cut.subarray(start).toString('utf8')}`;
|
|
134
141
|
}
|
|
135
142
|
|
|
136
|
-
/**
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
/**
|
|
144
|
+
* The isolation probe: wait until the NetworkPolicy blocks the host/prod daemons, then go on with the child shell.
|
|
145
|
+
* GATE-WARM-BOOT-NO-INIT (10-15) — this used to be the `isolation-gate` init container; it is now the child shell's first
|
|
146
|
+
* lines, before any credential is read. Same probes, same log lines, same exit 1 when isolation is not enforced in 30 s.
|
|
147
|
+
* Measured on node-b k3d (#27805): init 2 → 354 s · init 1 → 41 s · none → 1 s from Pod creation to the child start.
|
|
148
|
+
*/
|
|
149
|
+
export function isolationGateLines(): string {
|
|
150
|
+
return `elanous_isolation_gate() {
|
|
151
|
+
local ok=0 i
|
|
152
|
+
for i in $(seq 1 60); do
|
|
153
|
+
if curl -s -m 1 -o /dev/null http://host.orb.internal:31415/health || curl -s -m 1 -o /dev/null http://core.elanous-prod:8080/; then ok=0; else ok=$((ok+1)); fi
|
|
154
|
+
[ "$ok" -ge 3 ] && { echo "[gate] isolation enforced after \${i} probes"; return 0; }
|
|
155
|
+
sleep 0.5
|
|
156
|
+
done
|
|
157
|
+
echo "[gate] ISOLATION NOT ENFORCED within 30s"; exit 1
|
|
158
|
+
}
|
|
159
|
+
elanous_isolation_gate || exit 1`;
|
|
145
160
|
}
|
|
146
|
-
|
|
147
|
-
const GATE = isolationGateScript();
|
|
148
161
|
|
|
149
162
|
/** Export the command's log store into the existing outbox return channel without changing the command exit status. */
|
|
150
163
|
const COMMAND_LOG_EXPORT = `if mkdir -p "$HOME/outbox/pod-logs" && elanous --test="$HOME/.elanous-test" logs --instance prod --since 12h --limit 20000 --json --json-data > "$HOME/outbox/pod-logs/logs.jsonl"; then
|
|
@@ -182,7 +195,7 @@ if [ -d "$HOME/outbox" ]; then
|
|
|
182
195
|
else
|
|
183
196
|
printf 'ELANOUS_POD_ARTIFACT_SKIPPED %s %s\\n' "$relative" "$size"
|
|
184
197
|
fi
|
|
185
|
-
done < <(find "$HOME/outbox" -type f -print0)
|
|
198
|
+
done < <(find "$HOME/outbox" -type f -print0 | while IFS= read -r -d '' f; do printf '%s\\t%s\\0' "$(( $(wc -c < "$f") ))" "$f"; done | LC_ALL=C sort -z -t $'\\t' -k1,1n -k2 | while IFS= read -r -d '' row; do printf '%s\\0' "\${row#*$'\\t'}"; done)
|
|
186
199
|
fi`;
|
|
187
200
|
|
|
188
201
|
export interface PodCommandJobInput {
|
|
@@ -208,9 +221,13 @@ export interface PodCommandJobInput {
|
|
|
208
221
|
memoryLimit?: string;
|
|
209
222
|
/** GATE-SPEED A3①: CPU request/limit override (release gate shards only). Omitted = request 1 / limit 4. */
|
|
210
223
|
cpu?: PodCpu;
|
|
224
|
+
/** W5 — emptyDir{medium: Memory} sizeLimit mounted at {@link POD_TMPFS_MOUNT_PATH} ⊕ `TMPDIR` (release gate shards only). Omitted = image `/tmp`. */
|
|
225
|
+
tmpfsSizeLimit?: string;
|
|
211
226
|
source?: PodSource;
|
|
212
227
|
deadlineSeconds: number;
|
|
213
228
|
runId?: string;
|
|
229
|
+
/** GATE-WARM-BOOT-NO-INIT fallback: the node-side hand-over did not run, so a root init container hands the hostPath dirs to uid 1000. */
|
|
230
|
+
hostDirsInit?: boolean;
|
|
214
231
|
}
|
|
215
232
|
|
|
216
233
|
function bashSingleQuote(value: string): string {
|
|
@@ -226,8 +243,11 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
|
|
|
226
243
|
const grok = o.llm === 'grok';
|
|
227
244
|
const bunCache = o.bunCache ? podBunCacheVolume(o.bunCache) : undefined;
|
|
228
245
|
const installSlots = o.installSlots ? podInstallSlotsVolume(o.installSlots) : undefined;
|
|
229
|
-
// hostPath directories the uid-1000 child writes
|
|
246
|
+
// hostPath directories the uid-1000 child writes. DirectoryOrCreate makes them root 0755, so runPodCommand hands them to
|
|
247
|
+
// uid 1000 once per node (prepareHostDirsOnce); the child only reports a directory it still cannot write.
|
|
230
248
|
const hostDirMounts = [...(bunCache ? [bunCache.volumeMount] : []), ...(installSlots ? [installSlots.volumeMount] : [])];
|
|
249
|
+
const tmpfs = o.tmpfsSizeLimit?.trim() || undefined;
|
|
250
|
+
const tmpfsMounts = tmpfs ? [{ name: 'tmp-mem', mountPath: POD_TMPFS_MOUNT_PATH }] : [];
|
|
231
251
|
const cpu = resolvePodCpu(o.cpu);
|
|
232
252
|
const quotedArgs = o.command.map(bashSingleQuote).join(' ');
|
|
233
253
|
const credLines = [
|
|
@@ -237,12 +257,14 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
|
|
|
237
257
|
: []),
|
|
238
258
|
];
|
|
239
259
|
const script = [
|
|
260
|
+
isolationGateLines(),
|
|
240
261
|
'set -u',
|
|
241
262
|
...credLines,
|
|
242
263
|
'curl -s -m 3 -o /dev/null http://host.orb.internal:31415/health && { echo "[pod] ISOLATION FAIL"; exit 3; }',
|
|
243
264
|
...(o.clone
|
|
244
265
|
? ['export GH_TOKEN="$(cat /creds/gh-token)" && gh auth setup-git', podSourceScript(o.source ?? { kind: 'default' }, o.repoUrl)]
|
|
245
266
|
: ['mkdir -p ~/work && cd ~/work']),
|
|
267
|
+
...(hostDirMounts.length ? [podHostDirsCheckScript(hostDirMounts)] : []),
|
|
246
268
|
...(bunCache ? [bunCache.shellPrefix] : []),
|
|
247
269
|
`set -- ${quotedArgs}`,
|
|
248
270
|
'"$@"',
|
|
@@ -270,14 +292,10 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
|
|
|
270
292
|
spec: {
|
|
271
293
|
restartPolicy: 'Never',
|
|
272
294
|
securityContext: { runAsUser: 1000, fsGroup: 1000 },
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
hostDirMounts.length
|
|
278
|
-
? { name: 'isolation-gate', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never', securityContext: { runAsUser: 0 }, command: ['bash', '-c'], args: [isolationGateScript(podHostDirsScript(hostDirMounts))], volumeMounts: hostDirMounts.map((mount) => ({ ...mount })) }
|
|
279
|
-
: { name: 'isolation-gate', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never', command: ['bash', '-c'], args: [GATE] },
|
|
280
|
-
],
|
|
295
|
+
// Normal path: no init container. Fallback only when the node-side hand-over did not run (no member · prep failed).
|
|
296
|
+
...(o.hostDirsInit && hostDirMounts.length ? { initContainers: [
|
|
297
|
+
{ name: 'host-dirs', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never', securityContext: { runAsUser: 0 }, command: ['bash', '-c'], args: [podHostDirsScript(hostDirMounts)], volumeMounts: hostDirMounts.map((mount) => ({ ...mount })) },
|
|
298
|
+
] } : {}),
|
|
281
299
|
containers: [{
|
|
282
300
|
name: 'child', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never',
|
|
283
301
|
resources: { requests: { ...POD_CHILD_REQUESTS, cpu: cpu.request, memory: memoryRequestWithin(o.memoryLimit) }, limits: { memory: o.memoryLimit ?? '16Gi', cpu: cpu.limit } },
|
|
@@ -286,18 +304,21 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
|
|
|
286
304
|
...(o.runId ? [{ name: 'ELANOUS_RUN_ID', value: o.runId }] : []),
|
|
287
305
|
{ name: 'ELANOUS_SUBSTRATE', value: 'pod' },
|
|
288
306
|
{ name: 'ELANOUS_POD_NAME', valueFrom: { fieldRef: { fieldPath: 'metadata.name' } } },
|
|
307
|
+
...(tmpfs ? [{ name: 'TMPDIR', value: POD_TMPFS_MOUNT_PATH }] : []),
|
|
289
308
|
],
|
|
290
|
-
...(secretKeys || o.hostMirror || hostDirMounts.length ? { volumeMounts: [
|
|
309
|
+
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumeMounts: [
|
|
291
310
|
...(secretKeys ? [{ name: 'creds', mountPath: '/creds', readOnly: true }] : []),
|
|
292
311
|
...(o.hostMirror ? [{ name: 'host-mirror', mountPath: '/host-mirror', readOnly: true }] : []),
|
|
293
312
|
...hostDirMounts,
|
|
313
|
+
...tmpfsMounts,
|
|
294
314
|
] } : {}),
|
|
295
315
|
}],
|
|
296
|
-
...(secretKeys || o.hostMirror || hostDirMounts.length ? { volumes: [
|
|
316
|
+
...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumes: [
|
|
297
317
|
...(secretKeys ? [{ name: 'creds', secret: { secretName: `${o.name}-creds`, defaultMode: 0o400 } }] : []),
|
|
298
318
|
...(o.hostMirror ? [{ name: 'host-mirror', hostPath: { path: o.hostMirror, type: 'Directory' } }] : []),
|
|
299
319
|
...(bunCache ? [bunCache.volume] : []),
|
|
300
320
|
...(installSlots ? [installSlots.volume] : []),
|
|
321
|
+
...(tmpfs ? [{ name: 'tmp-mem', emptyDir: { medium: 'Memory', sizeLimit: tmpfs } }] : []),
|
|
301
322
|
] } : {}),
|
|
302
323
|
},
|
|
303
324
|
},
|
|
@@ -374,6 +395,8 @@ export interface RunPodCommandOptions {
|
|
|
374
395
|
memoryLimit?: string;
|
|
375
396
|
/** GATE-SPEED A3①: CPU request/limit override — only the release gate passes it. Omitted = request 1 / limit 4. */
|
|
376
397
|
cpu?: PodCpu;
|
|
398
|
+
/** W5 — memory-backed TMPDIR sizeLimit mounted at {@link POD_TMPFS_MOUNT_PATH}; only the release gate passes it. Omitted = image `/tmp`. */
|
|
399
|
+
tmpfsSizeLimit?: string;
|
|
377
400
|
/** POD7: 호출부가 «네트워크 스킬만 쓰는 명령»이라고 말할 때만 lite 이미지 ⊕ 2Gi. */
|
|
378
401
|
lite?: boolean;
|
|
379
402
|
source?: PodSource;
|
|
@@ -398,6 +421,8 @@ export interface RunPodCommandOptions {
|
|
|
398
421
|
seedMirror?: (o: { host: string; commit: string; cwd: string }) => Promise<MirrorSeedResult | undefined>;
|
|
399
422
|
/** GATE-WARM-BOOT — the git tree the seed pushes from (default: the process cwd — the gate runs in the repo tree). */
|
|
400
423
|
mirrorSeedCwd?: string;
|
|
424
|
+
/** GATE-WARM-BOOT-NO-INIT — hands the hostPath dirs to uid 1000 on the member's nodes (test seam · default {@link prepareHostDirsOnce}). */
|
|
425
|
+
prepareHostDirs?: (o: { member: PodPoolMember; hostPaths: readonly string[] }) => Promise<HostDirsPrepResult | undefined>;
|
|
401
426
|
checkPool?: typeof checkPodPool;
|
|
402
427
|
syncImages?: typeof syncPoolImages;
|
|
403
428
|
imageCommit?: string | null;
|
|
@@ -417,6 +442,8 @@ export interface RunPodCommandOptions {
|
|
|
417
442
|
/** GATE-POD-RESULT-MARKER — the child script's final line (`\n<marker> <token> rc=<n>\n`), printed after the artifact emit. */
|
|
418
443
|
export const POD_RESULT_MARKER = '__ELANOUS_POD_DONE__';
|
|
419
444
|
/** The marker bound to one launch (`token` = the launch's random id · the Job name when the manifest has no launch). */
|
|
445
|
+
/** Full-log re-reads after an early marker return before the artifacts count as lost (GATE-POD-RESULT-MARKER follow-up). */
|
|
446
|
+
export const POD_MARKER_LOG_RETRIES = 2;
|
|
420
447
|
export function podResultMarker(token: string): string { return `${POD_RESULT_MARKER} ${token}`; }
|
|
421
448
|
|
|
422
449
|
/** Split the child's logs into the command output (marker tail removed, bytes otherwise unchanged) and the marker rc (null = no marker for this token). */
|
|
@@ -563,6 +590,24 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
563
590
|
.catch((error: unknown) => ({ host: member!.sshHost!, ok: false, ms: 0, detail: String(error).slice(0, 300) }));
|
|
564
591
|
log('pod.command-job', 'mirror-seed', { host: member.sshHost, commit: options.source.sha, ok: seed?.ok ?? false, ms: seed?.ms ?? 0, ...(seed?.detail ? { detail: seed.detail } : {}) });
|
|
565
592
|
}
|
|
593
|
+
// GATE-WARM-BOOT-NO-INIT (10-15): the hostPath dirs the uid-1000 child writes are handed over on the node itself, once per
|
|
594
|
+
// member·paths in this process (no init container). Best effort: a failure only logs; the child then falls back.
|
|
595
|
+
const hostDirPaths = [...(bunCache ? [bunCache] : []), ...(installSlots ? [installSlots] : [])];
|
|
596
|
+
const prepareHostDirs = options.prepareHostDirs ?? (options.kubectl ? undefined : prepareHostDirsOnce);
|
|
597
|
+
let hostDirsPrepared = false;
|
|
598
|
+
if (hostDirPaths.length) {
|
|
599
|
+
// Observed whether or not a hand-over runs: no member (nothing to reach) and an injected kubectl without a seam are skips.
|
|
600
|
+
if (!member) log('pod.command-job', 'host-dirs-prep', { ok: false, reason: 'no-pool-member', paths: hostDirPaths });
|
|
601
|
+
else if (!prepareHostDirs) log('pod.command-job', 'host-dirs-prep', { ok: false, reason: 'prep-disabled', paths: hostDirPaths });
|
|
602
|
+
else {
|
|
603
|
+
const prep = await prepareHostDirs({ member, hostPaths: hostDirPaths })
|
|
604
|
+
.catch((error: unknown) => ({ host: member!.sshHost ?? 'local', ok: false, ms: 0, detail: String(error).slice(0, 300) }));
|
|
605
|
+
hostDirsPrepared = prep?.ok === true;
|
|
606
|
+
log('pod.command-job', 'host-dirs-prep', { host: prep?.host ?? member.sshHost ?? 'local', ok: prep?.ok ?? false, ms: prep?.ms ?? 0, paths: hostDirPaths, ...(prep?.detail ? { detail: prep.detail } : {}) });
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
// Any path where the node-side hand-over did not succeed keeps the old in-Pod hand-over (review mf: uid 1000 could not write).
|
|
610
|
+
const hostDirsInit = hostDirPaths.length > 0 && !hostDirsPrepared;
|
|
566
611
|
const ghToken = options.clone ? (options.ghToken ?? defaultGhToken)() : undefined;
|
|
567
612
|
const secret = commandJobSecret({ name, namespace, launch, skills, skillEnvText, ...(grokAuth !== undefined ? { grokAuth } : {}), ...(ghToken !== undefined ? { ghToken } : {}) });
|
|
568
613
|
if (secret) {
|
|
@@ -573,8 +618,9 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
573
618
|
name, namespace, launch, image: imageRef ?? image,
|
|
574
619
|
...(imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
|
|
575
620
|
repoUrl, command, skills, ...(options.returnLogs ? { returnLogs: true } : {}), ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
|
|
576
|
-
...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), deadlineSeconds,
|
|
621
|
+
...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
|
|
577
622
|
...(options.runId ? { runId: options.runId } : {}),
|
|
623
|
+
...(hostDirsInit ? { hostDirsInit: true } : {}),
|
|
578
624
|
});
|
|
579
625
|
kubectl(['-n', namespace, 'delete', 'job', '-l', own, '--ignore-not-found']);
|
|
580
626
|
const applied = kubectl(['apply', '-f', '-'], JSON.stringify(manifest));
|
|
@@ -611,7 +657,21 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
611
657
|
} else unreadableSince = null;
|
|
612
658
|
await sleep(options.pollMs ?? 15_000);
|
|
613
659
|
}
|
|
614
|
-
|
|
660
|
+
let logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
|
|
661
|
+
// Marker path returns before the Job condition — a full-log read can hit the same transient window the tail read
|
|
662
|
+
// already survived (container log rotation · API hiccup). Retry it a little before calling the artifacts lost.
|
|
663
|
+
// A read that «succeeds» but stops before this launch's marker (empty · cut off) is incomplete too (review mf · #27842).
|
|
664
|
+
const fullLogIncomplete = (r: { status: number | null; stdout: string }) =>
|
|
665
|
+
r.status !== 0 || splitPodResultMarker(r.stdout.startsWith('\n') ? r.stdout : `\n${r.stdout}`, launch).rc === null;
|
|
666
|
+
for (let attempt = 1; markerRc !== null && fullLogIncomplete(logsResult) && attempt <= POD_MARKER_LOG_RETRIES; attempt++) {
|
|
667
|
+
log('pod.command-job', 'result-marker-log-retry', { job: name, attempt, ...(logsResult.status !== 0 ? { error: (logsResult.stderr ?? '').trim().slice(0, 200) } : { reason: 'marker-missing-in-full-log' }) });
|
|
668
|
+
await sleep(options.pollMs === undefined ? 1_000 : Math.min(options.pollMs, 1_000)); // ≤2 re-reads within ≈2s total
|
|
669
|
+
logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
|
|
670
|
+
}
|
|
671
|
+
// Still without this launch's marker after the retries: the artifacts are not trusted as complete (explicit failure).
|
|
672
|
+
if (markerRc !== null && logsResult.status === 0 && fullLogIncomplete(logsResult)) {
|
|
673
|
+
logsResult = { ...logsResult, status: 1, stderr: 'full log ended before this launch\'s result marker (incomplete after retries)' };
|
|
674
|
+
}
|
|
615
675
|
const logsFailed = logsResult.status !== 0;
|
|
616
676
|
const logs = logsFailed ? '' : splitPodResultMarker(logsResult.stdout, launch).logs;
|
|
617
677
|
const artifactDir = artifactRoot;
|
|
@@ -6,7 +6,15 @@ export const STOP_CLASS_NO_LAUNCH = 'no-launch' as const;
|
|
|
6
6
|
const CHILD_RESULT_KINDS = new Set(['self', 'external']);
|
|
7
7
|
|
|
8
8
|
/** The dev child's terminal line nests the stage: {ok, kind, result:{stage, ok, node, outcome, …}}. Other JSON rows are not results. */
|
|
9
|
-
export function nestedPodResult(row: Record<string, unknown>): {
|
|
9
|
+
export function nestedPodResult(row: Record<string, unknown>): {
|
|
10
|
+
stage: string;
|
|
11
|
+
ok: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
reasonCode?: string;
|
|
14
|
+
checkName?: string;
|
|
15
|
+
targetPath?: string;
|
|
16
|
+
preflightChecks?: PreflightCheck[];
|
|
17
|
+
} | null {
|
|
10
18
|
if (typeof row.kind !== 'string' || !CHILD_RESULT_KINDS.has(row.kind) || typeof row.ok !== 'boolean') return null;
|
|
11
19
|
if (!row.result || typeof row.result !== 'object' || Array.isArray(row.result)) return null;
|
|
12
20
|
const result = row.result as Record<string, unknown>;
|
|
@@ -18,28 +26,72 @@ export function nestedPodResult(row: Record<string, unknown>): { stage: string;
|
|
|
18
26
|
? (classification as Record<string, unknown>).classification : undefined;
|
|
19
27
|
const reason = [result.node, result.outcome].filter((part): part is string => typeof part === 'string' && part.length > 0).join(' ');
|
|
20
28
|
const error = [reason || (typeof result.error === 'string' ? result.error : ''), typeof detail === 'string' && detail ? detail : ''].filter(Boolean).join(' · ');
|
|
21
|
-
|
|
29
|
+
// PREFLIGHT-RESULT-LINE: a nested preflight rejection carries its blockers under result.blockers — the same ledger fields as the flat row.
|
|
30
|
+
const blockers = result.stage === 'preflight-blocked' ? preflightBlockerText(result.blockers)
|
|
31
|
+
: { error: '', preflightChecks: [] as PreflightCheck[] };
|
|
32
|
+
return {
|
|
33
|
+
stage: result.stage,
|
|
34
|
+
ok: false,
|
|
35
|
+
...(error || blockers.error ? { error: error || blockers.error } : {}),
|
|
36
|
+
...(blockers.preflightChecks.length === 1 ? blockers.preflightChecks[0] : {}),
|
|
37
|
+
...(blockers.preflightChecks.length > 1 ? { preflightChecks: blockers.preflightChecks } : {}),
|
|
38
|
+
};
|
|
22
39
|
}
|
|
23
40
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
function ledgerString(value: unknown): string {
|
|
42
|
+
return typeof value === 'string' && value.trim().length > 0 ? value : '';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type PreflightCheck = { reasonCode: string; checkName: string; targetPath?: string };
|
|
46
|
+
|
|
47
|
+
/** Keep each structured check paired with its own path; legacy blockers retain their name/detail diagnostic. */
|
|
48
|
+
function preflightBlockerText(blockers: unknown): { error: string; preflightChecks: PreflightCheck[] } {
|
|
49
|
+
if (!Array.isArray(blockers)) return { error: '', preflightChecks: [] };
|
|
50
|
+
const errors: string[] = [];
|
|
51
|
+
const preflightChecks: PreflightCheck[] = [];
|
|
52
|
+
for (const blocker of blockers) {
|
|
53
|
+
if (!blocker || typeof blocker !== 'object' || Array.isArray(blocker)) continue;
|
|
54
|
+
const record = blocker as Record<string, unknown>;
|
|
55
|
+
const reasonCode = ledgerString(record.reasonCode);
|
|
56
|
+
const checkName = ledgerString(record.checkName);
|
|
57
|
+
if (reasonCode && checkName) {
|
|
58
|
+
const targetPath = ledgerString(record.targetPath);
|
|
59
|
+
preflightChecks.push({ reasonCode, checkName, ...(targetPath ? { targetPath } : {}) });
|
|
60
|
+
errors.push(`${reasonCode} · ${checkName}`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const parts = [record.name, record.detail]
|
|
64
|
+
.filter((part): part is string => typeof part === 'string' && part.trim().length > 0)
|
|
65
|
+
.map((part) => part.trim().replace(/\s+/gu, ' '));
|
|
66
|
+
if (parts.length) errors.push(parts.join(' — '));
|
|
67
|
+
}
|
|
68
|
+
return { error: errors.join(' · '), preflightChecks };
|
|
33
69
|
}
|
|
34
70
|
|
|
35
71
|
/** A child terminal row: the legacy flat form {stage, ok, error?} (no kind, or a child kind) or the nested dev result. Any other kind is not a result. */
|
|
36
|
-
export function podTerminalRow(row: Record<string, unknown>): {
|
|
72
|
+
export function podTerminalRow(row: Record<string, unknown>): {
|
|
73
|
+
stage: string;
|
|
74
|
+
ok: boolean;
|
|
75
|
+
error?: string;
|
|
76
|
+
reasonCode?: string;
|
|
77
|
+
checkName?: string;
|
|
78
|
+
targetPath?: string;
|
|
79
|
+
preflightChecks?: PreflightCheck[];
|
|
80
|
+
} | null {
|
|
37
81
|
if (typeof row.kind === 'string' && !CHILD_RESULT_KINDS.has(row.kind)) return null;
|
|
38
82
|
if (typeof row.stage === 'string' && typeof row.ok === 'boolean') {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
83
|
+
// PREFLIGHT-RESULT-LINE: preserve structured blockers even when an explicit error supplies the human-readable reason.
|
|
84
|
+
if (row.ok === false && row.stage === 'preflight-blocked') {
|
|
85
|
+
const blockers = preflightBlockerText(row.blockers);
|
|
86
|
+
return {
|
|
87
|
+
stage: row.stage,
|
|
88
|
+
ok: row.ok,
|
|
89
|
+
...(typeof row.error === 'string' ? { error: row.error } : blockers.error ? { error: blockers.error } : {}),
|
|
90
|
+
...(blockers.preflightChecks.length === 1 ? blockers.preflightChecks[0] : {}),
|
|
91
|
+
...(blockers.preflightChecks.length > 1 ? { preflightChecks: blockers.preflightChecks } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return { stage: row.stage, ok: row.ok, ...(typeof row.error === 'string' ? { error: row.error } : {}) };
|
|
43
95
|
}
|
|
44
96
|
return nestedPodResult(row);
|
|
45
97
|
}
|
|
@@ -64,9 +116,21 @@ export function classifyPodExit(input: {
|
|
|
64
116
|
jobReason?: string | null;
|
|
65
117
|
logs: string;
|
|
66
118
|
result?: Record<string, unknown> | null;
|
|
67
|
-
}): {
|
|
119
|
+
}): {
|
|
120
|
+
class: PodExitClass;
|
|
121
|
+
errorCode: string | null;
|
|
122
|
+
containerReason: string | null;
|
|
123
|
+
exitCode: number | null;
|
|
124
|
+
jobReason: string | null;
|
|
125
|
+
tail: string[];
|
|
126
|
+
reasonCode?: string;
|
|
127
|
+
checkName?: string;
|
|
128
|
+
targetPath?: string;
|
|
129
|
+
preflightChecks?: PreflightCheck[];
|
|
130
|
+
noResultLine?: true;
|
|
131
|
+
} {
|
|
68
132
|
const logLines = input.logs.split(/\r\n|\n|\r/u).map((line) => line.trim()).filter(Boolean);
|
|
69
|
-
let terminalResult:
|
|
133
|
+
let terminalResult: ReturnType<typeof podTerminalRow> = null;
|
|
70
134
|
for (const line of logLines) {
|
|
71
135
|
if (!line.startsWith('{')) continue;
|
|
72
136
|
let parsed: unknown;
|
|
@@ -74,8 +138,8 @@ export function classifyPodExit(input: {
|
|
|
74
138
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;
|
|
75
139
|
terminalResult = podTerminalRow(parsed as Record<string, unknown>) ?? terminalResult;
|
|
76
140
|
}
|
|
77
|
-
if (!terminalResult && input.result) terminalResult = podTerminalRow(input.result);
|
|
78
141
|
const hasResultLine = terminalResult !== null;
|
|
142
|
+
if (!terminalResult && input.result) terminalResult = podTerminalRow(input.result);
|
|
79
143
|
const askReprompt = logLines.some((line) =>
|
|
80
144
|
/^\[ask\](?!\s+\d+\)\s).*(?:implementation[_ -]?target|reprompt|re-prompt|되묻)/iu.test(line));
|
|
81
145
|
// 파싱되는 JSON 줄(진행·결과 행)은 오류 «줄»로 세지 않는다 — tail 과 같은 기준.
|
|
@@ -116,6 +180,11 @@ export function classifyPodExit(input: {
|
|
|
116
180
|
exitCode: input.containerExitCode ?? null,
|
|
117
181
|
jobReason: input.jobReason ?? null,
|
|
118
182
|
tail,
|
|
183
|
+
...(terminalResult?.reasonCode ? { reasonCode: terminalResult.reasonCode } : {}),
|
|
184
|
+
...(terminalResult?.checkName ? { checkName: terminalResult.checkName } : {}),
|
|
185
|
+
...(terminalResult?.targetPath ? { targetPath: terminalResult.targetPath } : {}),
|
|
186
|
+
...(terminalResult?.preflightChecks ? { preflightChecks: terminalResult.preflightChecks } : {}),
|
|
187
|
+
...(!hasResultLine ? { noResultLine: true as const } : {}),
|
|
119
188
|
};
|
|
120
189
|
}
|
|
121
190
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// ⛔ 기본 꺼짐(opt-in): 옵션 → env `ELANOUS_POD_HOST_ACP_REVIEW` → config `llm.podHostAcpReview` 순.
|
|
12
12
|
// 📌 남은 조각(②-b): 이 문이 켜진 런에서 Pod 안 api 리뷰를 «끄는» 것은 Pod 이미지 쪽 변경이라 따로 간다.
|
|
13
13
|
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import { SPAWN_SYNC_MAX_BUFFER } from '../../util/spawn-sync-output.js';
|
|
14
15
|
import { debug } from '../../debug/log.js';
|
|
15
16
|
import type { ReviewResult } from '../../agent-substrate/pr-reviewer.js';
|
|
16
17
|
import type { SubscriptionReviewerSpec } from '../../user-config.js';
|
|
@@ -57,7 +58,7 @@ export interface PodHostAcpReviewDeps {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
function defaultReadPr(prNumber: number, repoRoot: string): { headRefOid: string; title: string; body: string; diff: string } | undefined {
|
|
60
|
-
const view = spawnSync('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,title,body'], { cwd: repoRoot, encoding: 'utf8', timeout: 60_000 });
|
|
61
|
+
const view = spawnSync('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,title,body'], { cwd: repoRoot, encoding: 'utf8', timeout: 60_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
|
|
61
62
|
if (view.status !== 0) return undefined;
|
|
62
63
|
const diff = spawnSync('gh', ['pr', 'diff', String(prNumber)], { cwd: repoRoot, encoding: 'utf8', timeout: 120_000, maxBuffer: 64 * 1024 * 1024 });
|
|
63
64
|
if (diff.status !== 0) return undefined;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* 이미지는 표준판(elanous-harness)만 — 이 발사 경로는 lite 를 쓰지 않는다.
|
|
15
15
|
*/
|
|
16
16
|
import { spawnSync } from 'node:child_process';
|
|
17
|
+
import { SPAWN_SYNC_MAX_BUFFER } from '../../util/spawn-sync-output.js';
|
|
17
18
|
import { debug } from '../../debug/log.js';
|
|
18
19
|
import { memberHasRegistry, registryImageRef, type RemoteRun } from './pod-pool.js';
|
|
19
20
|
|
|
@@ -71,7 +72,7 @@ export function memberPinRegistry(member: PodImageMember, source: Extract<PodIma
|
|
|
71
72
|
|
|
72
73
|
/** 실제 조회 — 원격은 pod-pool 의 SSH 판정, 로컬은 이 기계의 docker/curl 로 조회한다. */
|
|
73
74
|
export function podPoolImageLookup(run?: RemoteRun, localRun: (cmd: string, args: readonly string[]) => { status: number | null; stdout: string } = (cmd, args) => {
|
|
74
|
-
const r = spawnSync(cmd, [...args], { encoding: 'utf8', timeout: 10_000 });
|
|
75
|
+
const r = spawnSync(cmd, [...args], { encoding: 'utf8', timeout: 10_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
|
|
75
76
|
return { status: r.status, stdout: r.stdout ?? '' };
|
|
76
77
|
}): {
|
|
77
78
|
hasRegistry: (member: PodImageMember & { context: string }, registry: string) => boolean;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
|
|
1
3
|
// GATE-INSTALL-CACHE (0.2.20) — a node-wide throttle for the release-gate shards' `bun install`.
|
|
2
4
|
//
|
|
3
5
|
// Cause, measured on the 0.2.19 gate (`elanous logs --category release-loop.gate --event pod-shard --all --include-test`):
|
|
@@ -21,8 +23,8 @@ export const POD_INSTALL_SLOTS_HOST_PATH = '/var/lib/elanous/gate-install-slots'
|
|
|
21
23
|
export const POD_INSTALL_SLOTS_DEFAULT = 4;
|
|
22
24
|
export const POD_INSTALL_SLOTS_MOUNT = '/gate-install-slots';
|
|
23
25
|
|
|
24
|
-
/** hostPath volume ⊕ mount for the tokens. `DirectoryOrCreate` makes a root-owned 0755 directory, so the
|
|
25
|
-
* {@link
|
|
26
|
+
/** hostPath volume ⊕ mount for the tokens. `DirectoryOrCreate` makes a root-owned 0755 directory, so the node also needs
|
|
27
|
+
* {@link prepareHostDirsOnce} (the child runs as uid 1000). */
|
|
26
28
|
export function podInstallSlotsVolume(hostPath: string = POD_INSTALL_SLOTS_HOST_PATH) {
|
|
27
29
|
return {
|
|
28
30
|
volume: { name: 'install-slots', hostPath: { path: hostPath, type: 'DirectoryOrCreate' } },
|
|
@@ -30,17 +32,125 @@ export function podInstallSlotsVolume(hostPath: string = POD_INSTALL_SLOTS_HOST_
|
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
// GATE-WARM-BOOT-NO-INIT (10-15) — the root hand-over of the hostPath directories left the Pod. It was an init container
|
|
36
|
+
// (`host-dirs`, then folded into `isolation-gate` by GATE-WARM-BOOT), and every init container cost a container
|
|
37
|
+
// transition on a loaded k3d node (#27805 on node-b: init 2 → 354 s · init 1 → 41 s · none → 1 s to the child start).
|
|
38
|
+
// The directories live on the node and outlive every Pod, so the hand-over is a node fact: done once per node from the
|
|
39
|
+
// pool host (`docker exec` into each k3d node container · idempotent `mkdir -p`/`chown`/`chmod`), and the child shell only
|
|
40
|
+
// reports a directory it still cannot write. Never fails the Pod: an unwritable directory means the child falls back
|
|
41
|
+
// (no cache · no throttle), exactly as before when the hand-over failed.
|
|
42
|
+
|
|
43
|
+
const SAFE_HOST_PATH = /^\/[A-Za-z0-9._/-]+$/;
|
|
44
|
+
const SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
45
|
+
export const HOST_DIRS_PREP_LIMIT_MS = 30_000;
|
|
46
|
+
|
|
47
|
+
/** Child-shell line: report (never fail on) a mounted host directory the uid-1000 child cannot write. */
|
|
48
|
+
/** Root hand-over inside the Pod — only for runs whose hostPath dirs could not be prepared on the node (no pool member ·
|
|
49
|
+
* prep failed · prep disabled). Same lines the old `isolation-gate` init ran; it never fails the Pod. */
|
|
39
50
|
export function podHostDirsScript(mounts: ReadonlyArray<{ mountPath: string }>): string {
|
|
40
51
|
const paths = mounts.map((mount) => `'${mount.mountPath.replace(/'/g, `'\\''`)}'`).join(' ');
|
|
41
52
|
return `for d in ${paths}; do mkdir -p "$d" && chown 1000:1000 "$d" && chmod 0775 "$d" || echo "[host-dirs] could not prepare $d"; done; exit 0`;
|
|
42
53
|
}
|
|
43
54
|
|
|
55
|
+
export function podHostDirsCheckScript(mounts: ReadonlyArray<{ mountPath: string }>): string {
|
|
56
|
+
const paths = mounts.map((mount) => `'${mount.mountPath.replace(/'/g, `'\\''`)}'`).join(' ');
|
|
57
|
+
return `for d in ${paths}; do [ -d "$d" ] && [ -w "$d" ] || echo "[host-dirs] could not prepare $d (not writable by uid $(id -u) · node not prepared)"; done`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Host-side shell (on the pool host): hand the node directories to uid 1000 in every k3d node container of `cluster`. */
|
|
61
|
+
export function podHostDirsNodeScript(o: { cluster: string; hostPaths: readonly string[] }): string {
|
|
62
|
+
if (!SAFE_NAME.test(o.cluster)) throw new Error(`invalid k3d cluster: ${o.cluster}`);
|
|
63
|
+
for (const path of o.hostPaths) if (!SAFE_HOST_PATH.test(path) || path.split('/').includes('..')) throw new Error(`invalid host dir: ${path}`);
|
|
64
|
+
const inner = `for d in ${o.hostPaths.join(' ')}; do mkdir -p "$d" && chown 1000:1000 "$d" && chmod 0775 "$d" || { echo "[host-dirs] could not prepare $d"; exit 1; }; done`;
|
|
65
|
+
return [
|
|
66
|
+
`nodes=$(docker ps --filter label=k3d.cluster=${o.cluster} --format '{{.Names}} {{.Label "k3d.role"}}' | awk '$2=="server"||$2=="agent"{print $1}')`,
|
|
67
|
+
`[ -n "$nodes" ] || { echo "[host-dirs] no k3d node for ${o.cluster}"; exit 2; }`,
|
|
68
|
+
'rc=0',
|
|
69
|
+
`for n in $nodes; do docker exec "$n" sh -c '${inner}' || rc=1; done`,
|
|
70
|
+
'exit $rc',
|
|
71
|
+
].join('\n');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** The member's current k3d server/agent container IDs, sorted — the node «generation» the hand-over memo is keyed by. */
|
|
75
|
+
export function podHostDirsNodeIdsScript(cluster: string): string {
|
|
76
|
+
if (!SAFE_NAME.test(cluster)) throw new Error(`invalid k3d cluster: ${cluster}`);
|
|
77
|
+
return `docker ps --no-trunc --filter label=k3d.cluster=${cluster} --format '{{.ID}} {{.Label "k3d.role"}}' | awk '$2=="server"||$2=="agent"{print $1}' | sort | tr '\\n' ' '`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface HostDirsPrepResult { host: string; ok: boolean; ms: number; detail?: string }
|
|
81
|
+
|
|
82
|
+
type HostShell = (host: string | undefined, script: string, limitMs: number) => Promise<{ rc: number; output: string }>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Bounded shell on the pool host (`ssh <host>`) or this machine (no host); never throws. At `limitMs` the whole process
|
|
86
|
+
* group is killed and the call returns rc 124 at once — a stuck `docker exec` grandchild holding the pipe must not keep
|
|
87
|
+
* the caller (and the Job launch behind it) waiting for `close`.
|
|
88
|
+
*/
|
|
89
|
+
export function hostShellWithin(host: string | undefined, script: string, limitMs: number): Promise<{ rc: number; output: string }> {
|
|
90
|
+
const env = 'export PATH=/opt/homebrew/bin:/usr/local/bin:$HOME/.orbstack/bin:$PATH; ';
|
|
91
|
+
const [cmd, args] = host
|
|
92
|
+
? ['ssh', ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=10', host, env + script]] as const
|
|
93
|
+
: ['bash', ['-c', env + script]] as const;
|
|
94
|
+
return new Promise((resolve) => {
|
|
95
|
+
let output = '';
|
|
96
|
+
let settled = false;
|
|
97
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
98
|
+
const finish = (rc: number, text: string) => { if (!settled) { settled = true; clearTimeout(timer); resolve({ rc, output: text }); } };
|
|
99
|
+
let child: ReturnType<typeof spawn>;
|
|
100
|
+
try { child = spawn(cmd, [...args], { stdio: ['ignore', 'pipe', 'pipe'], detached: true }); }
|
|
101
|
+
catch (error) { resolve({ rc: 2, output: String(error) }); return; }
|
|
102
|
+
timer = setTimeout(() => {
|
|
103
|
+
try { if (child.pid) process.kill(-child.pid, 'SIGKILL'); else child.kill('SIGKILL'); } catch { child.kill('SIGKILL'); }
|
|
104
|
+
child.stdout?.destroy();
|
|
105
|
+
child.stderr?.destroy();
|
|
106
|
+
finish(124, `${output}\n[host-dirs] timed out after ${limitMs} ms`);
|
|
107
|
+
}, limitMs);
|
|
108
|
+
child.stdout?.on('data', (chunk) => { output += String(chunk); });
|
|
109
|
+
child.stderr?.on('data', (chunk) => { output += String(chunk); });
|
|
110
|
+
child.on('error', (error) => finish(2, `${output}\n${String(error)}`));
|
|
111
|
+
child.on('close', (code) => finish(code ?? 2, output));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const prepared = new Map<string, Promise<HostDirsPrepResult>>();
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Hand `hostPaths` to uid 1000 on the member's k3d nodes once per (host, cluster, node generation, path) in this process — every shard Job
|
|
119
|
+
* on the same member awaits the same run, and a path already handed over (or in flight) is not run again even when it
|
|
120
|
+
* comes with a different companion path. A failure is not memoized (the next Job tries again) and never throws.
|
|
121
|
+
*/
|
|
122
|
+
export async function prepareHostDirsOnce(o: { member: { sshHost?: string; k3dCluster: string }; hostPaths: readonly string[]; shell?: HostShell; limitMs?: number }): Promise<HostDirsPrepResult> {
|
|
123
|
+
const host = o.member.sshHost;
|
|
124
|
+
const label = host ?? 'local';
|
|
125
|
+
const start = Date.now();
|
|
126
|
+
const shell = o.shell ?? hostShellWithin;
|
|
127
|
+
// Node generation (review mf): a recreated cluster or a new agent has other container IDs, so a hand-over remembered for
|
|
128
|
+
// the old node set is not reused. Unreadable IDs → no memo at all (every path runs, success is not remembered).
|
|
129
|
+
const ids = await shell(host, podHostDirsNodeIdsScript(o.member.k3dCluster), o.limitMs ?? HOST_DIRS_PREP_LIMIT_MS)
|
|
130
|
+
.catch(() => ({ rc: 2, output: '' }));
|
|
131
|
+
const generation = ids.rc === 0 && ids.output.trim() ? ids.output.trim() : null;
|
|
132
|
+
const gen = generation ?? `unknown-${start}-${Math.random()}`;
|
|
133
|
+
const keyOf = (path: string) => `${label}\0${o.member.k3dCluster}\0${gen}\0${path}`;
|
|
134
|
+
const paths = [...new Set(o.hostPaths)].sort();
|
|
135
|
+
const fresh = paths.filter((path) => !prepared.has(keyOf(path)));
|
|
136
|
+
if (fresh.length) {
|
|
137
|
+
const run = (async (): Promise<HostDirsPrepResult> => {
|
|
138
|
+
const script = podHostDirsNodeScript({ cluster: o.member.k3dCluster, hostPaths: fresh });
|
|
139
|
+
const r = await shell(host, script, o.limitMs ?? HOST_DIRS_PREP_LIMIT_MS);
|
|
140
|
+
const ms = Date.now() - start;
|
|
141
|
+
return r.rc === 0 ? { host: label, ok: true, ms } : { host: label, ok: false, ms, detail: r.output.trim().slice(-300) || `rc=${r.rc}` };
|
|
142
|
+
})().catch((error: unknown) => ({ host: label, ok: false, ms: Date.now() - start, detail: String(error).slice(0, 300) }))
|
|
143
|
+
.then((result) => { if (!result.ok || generation === null) for (const path of fresh) prepared.delete(keyOf(path)); return result; });
|
|
144
|
+
for (const path of fresh) prepared.set(keyOf(path), run);
|
|
145
|
+
}
|
|
146
|
+
const results = await Promise.all(paths.map((path) => prepared.get(keyOf(path))!));
|
|
147
|
+
const failed = results.find((result) => !result.ok);
|
|
148
|
+
return failed ?? { host: label, ok: true, ms: Date.now() - start };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Test seam — forget the per-process hand-over memo. */
|
|
152
|
+
export function resetHostDirsPrepMemo(): void { prepared.clear(); }
|
|
153
|
+
|
|
44
154
|
const int = (value: number, label: string) => {
|
|
45
155
|
if (!Number.isSafeInteger(value) || value < 1) throw new Error(`invalid ${label}: ${value}`);
|
|
46
156
|
return value;
|
|
@@ -66,7 +176,9 @@ export function installSlotScript(o: { dir?: string; slots: number; waitSeconds?
|
|
|
66
176
|
' if [ ! -d "$d" ] || [ ! -w "$d" ]; then echo "[gate] install-slot none (directory not writable)"; return 0; fi',
|
|
67
177
|
' while :; do',
|
|
68
178
|
` for n in $(seq 0 ${slots - 1}); do`,
|
|
69
|
-
'
|
|
179
|
+
// The token is taken by bash's own noclobber create (O_EXCL), not by `mkdir`: uutils coreutils `mkdir` (0.8 · wsl gate host)
|
|
180
|
+
// let two racing callers both succeed on one path (10-16 · 3 holders on 2 slots). A directory token left by an older shell still counts as held.
|
|
181
|
+
' if (set -C; : > "$d/slot-$n") 2>/dev/null; then',
|
|
70
182
|
' install_slot="$d/slot-$n"',
|
|
71
183
|
' echo "[gate] install-slot $n waited $(( $(date +%s) - t0 ))s"; return 0',
|
|
72
184
|
' fi',
|