elanous 0.2.28 → 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/{y1ltt7oCZxVpC6zVPhZ2O → LSXfY0u9QtfDbejY0Ukf_}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{ab4d57c2.e90bc2cb31949045.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/{5492-e05e26a033ba80d2.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/1654.32de4b324981a188.js +23 -0
- 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/1913.7cc6fb6055b1ed3f.js +41 -0
- package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +1 -0
- 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/{8578.dff22d988cc2b106.js → 2213.2ccbada92c33ea0f.js} +3 -3
- 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/{5081.a240b63fad28663a.js → 2871.0bca6137343b3f76.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2898.fd781bc7cf01a7b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2940-619bfd8ef337c611.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2846.d6a433b8663819a5.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/{f4dfbfc0.a69fb12f854882aa.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/3541-ce3a5424ed5ad7f1.js +1 -0
- 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/{3143.257997a5f1ed79df.js → 3902.e1e71aaac850a045.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{16e57f67.3ea19e893461e611.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1146.80d15ea7c6e6ee95.js → 4111.2bfedbb233ad206b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1516.83dd2c1b86b4e507.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/{9938.b23e4d4dfa0114cd.js → 4999.c064a4000c2a9e94.js} +2 -2
- 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/{1157.f08bf2b70915e176.js → 5304.04d24756f242a094.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{7752.5cbdd0b433c54af9.js → 5307.60f2209e809bd627.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9917-9e26abc5f7772735.js → 5458-16cd7a2b51b74c8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6196.34d6b229079e9e28.js → 5525.86debf231e181813.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4593.10f5b9bd702d4a6c.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/{7483.ba01c6c209b81bba.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/{9974.e77b4ff4884557b3.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/{3309.364573ceedbdfd5f.js → 6323.8672b4817a306928.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{94.4cfed21c0b781a06.js → 6433.fc573af22bbc9ab7.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{949.1e7d45ccb71580aa.js → 6517.4147878ac06d584d.js} +2 -2
- 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/{2528.3868070ef1be69f9.js → 6767.ea607cf0c20a25af.js} +2 -2
- 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/{1743.563d3168e95825ef.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/{5408.377c8c543635b81f.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/{65ebff95.081daeff622d238e.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2697.76ca2ac3efef6f3b.js → 8018.a32663f04a6fc5f9.js} +1 -1
- 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/9138.b6e80031afb1d973.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4204.a409ab6250c0f6a8.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/{5785-ea8d2c633b6688e3.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/9398-6aed28f0a96d0d6f.js +1 -0
- 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/997ce8a5-2ad501927003b41b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9311.24c8f5ea793253dd.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-fa46d4588e8442c2.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-ced0bcfc6542b3fc.js → page-349f2752d8cd37ad.js} +1 -1
- 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-cb249e81ed339318.js → page-0a07363b130182a1.js} +1 -1
- 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-521ee23ac8c0abfa.js +1 -0
- 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-149dc1caba411bb9.js +1 -0
- 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/{6def8a8e.c81f9ca41028eccf.js → b313b242.cb1265eea908db61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{e87d89b9.2e71c0ae475d28a1.js → e5012ffe.f727e23c231f4342.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{e117f801.e92bf10242653497.js → ebc7d829.264a0bcb6c750b50.js} +1 -1
- 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 +15 -7
- package/graphs/units/recipes.yaml +3 -0
- package/graphs/units/release-gate-recheck.yaml +15 -0
- package/package.json +2 -1
- package/plugins/agent-team/agents/research.md +1 -0
- package/scripts/check-native-tool-wiring.ts +3 -2
- package/scripts/ci-android-unit-tests.ts +16 -0
- package/scripts/ci-typecheck-changed.ts +40 -11
- package/scripts/coord-channel-watch.sh +45 -19
- package/scripts/coord-role-pack.ts +222 -0
- 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/lib/morning-report-options.ts +41 -0
- package/scripts/measure-goal-grounding-corpus.ts +2 -1
- package/scripts/pr-land-extra-remote-gates.ts +49 -0
- 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-batch-safe.ts +23 -0
- package/scripts/release-loop/gate-closure.ts +12 -8
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-history.ts +422 -0
- package/scripts/release-loop/gate-host-mirror.ts +66 -0
- package/scripts/release-loop/gate-node.ts +806 -94
- 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-triage-node.ts +190 -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 +51 -0
- package/scripts/release-loop/tui-node-checks.ts +23 -0
- package/scripts/release-loop/tui-sim-node.ts +3 -2
- package/scripts/release-loop/unattended-release.ts +16 -0
- package/scripts/release-loop/version-node.ts +62 -4
- package/scripts/test-deterministic.ts +46 -73
- 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/scripts/usage-rollup.ts +11 -3
- package/src/acp/client.ts +4 -1
- package/src/acp/core-turn-bridge.ts +145 -24
- package/src/acp/elanous-extensions.ts +2 -0
- package/src/acp/server.ts +2 -0
- package/src/ad-pipeline/run.ts +4 -2
- package/src/agent/ref-grounding.ts +18 -0
- 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 +41 -21
- 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/budget/pty-usage-reemit.ts +7 -0
- package/src/budget/run-usage-rollup.ts +9 -0
- package/src/budget/usage-daily-store.ts +98 -0
- package/src/capture/tui-self-report.ts +37 -4
- package/src/chat/chat-cli.ts +10 -2
- package/src/chat/index.ts +107 -20
- package/src/chat/input-control-key.ts +5 -3
- package/src/chat/pickers/modal-runtime.ts +1 -0
- package/src/chat/pickers/modals.ts +3 -1
- package/src/chat/tool-interrupt-behavior.ts +38 -0
- package/src/chat/tool-render/dispatch.ts +5 -1
- package/src/chat/turn-typeahead.ts +191 -29
- 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/dashboard-name-flag.ts +48 -0
- package/src/cli/decisions-cli.ts +80 -6
- package/src/cli/doctor-cli.ts +80 -0
- package/src/cli/log-event-names.ts +19 -0
- package/src/cli/mcp-login.ts +21 -5
- package/src/cli/msg-cli.ts +133 -2
- package/src/cli/pr-cli.ts +546 -112
- package/src/cli/pr-land-heavy-remote.ts +233 -0
- package/src/cli/pr-land-overlap-evidence.ts +167 -14
- 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/pty-takeover-cli.ts +125 -16
- package/src/cli/release-cli.ts +122 -14
- package/src/cli/remote-resolve.ts +2 -1
- package/src/cli/seat-cli.ts +164 -19
- package/src/cli/self-update.ts +5 -2
- package/src/cli/tasks-cli.ts +105 -21
- package/src/cli/usage-cli.ts +146 -12
- package/src/cli/usage-daily-cli.ts +84 -0
- package/src/context-bus/context-first.ts +13 -0
- package/src/context-bus/context-now.ts +95 -7
- 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/auth-rejected-notice.ts +41 -0
- package/src/core-turn/run-core-turn.ts +14 -2
- package/src/core-turn/run-goal-loop.ts +239 -4
- package/src/core-turn/seat-turn-cap.ts +79 -0
- package/src/core-turn/short-question.ts +78 -13
- package/src/core-turn/types.ts +10 -0
- package/src/dashboard/acp-active-model.ts +40 -0
- package/src/dashboard/acp-boot.ts +3 -0
- package/src/dashboard/auto-compact-runtime.ts +2 -0
- package/src/dashboard/boot-banner.ts +80 -0
- package/src/dashboard/dashboard-status-lines.ts +11 -0
- package/src/dashboard/detail-viewer-runtime.ts +15 -2
- package/src/dashboard/event-loop-stall-monitor.ts +4 -0
- package/src/dashboard/goal-loop-thinking.ts +16 -0
- package/src/dashboard/hitl-boot.ts +9 -4
- package/src/dashboard/index.ts +448 -998
- package/src/dashboard/input/chat-main-entry-runtime.ts +2 -0
- package/src/dashboard/input/chat-main-log-actions.ts +4 -0
- package/src/dashboard/input/chat-main-log-command.ts +12 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +176 -4
- package/src/dashboard/input/chat-main-session.ts +14 -3
- package/src/dashboard/input/chat-main-slash-command.ts +7 -0
- package/src/dashboard/input/chat-main-turn.ts +14 -4
- package/src/dashboard/input/compact-prepass-recovery.ts +130 -0
- package/src/dashboard/input/dashboard-chord-actions.ts +10 -1
- package/src/dashboard/input/dashboard-chord-runtime.ts +2 -0
- package/src/dashboard/input/external-input-host.ts +71 -0
- package/src/dashboard/input/internal-turn.ts +261 -0
- package/src/dashboard/input/log-fold-binding.ts +18 -0
- package/src/dashboard/input/mouse-wiring.ts +17 -4
- package/src/dashboard/input/seat-autowake.ts +318 -0
- package/src/dashboard/input/turn-steer-bridge.ts +164 -0
- package/src/dashboard/log-click-runtime.ts +5 -3
- package/src/dashboard/loop-scheduler.ts +72 -0
- package/src/dashboard/running-build-status.ts +74 -0
- package/src/dashboard/seat-boot-preamble.ts +131 -0
- package/src/dashboard/seat-local-instructions.ts +305 -0
- package/src/dashboard/skill-runtime.ts +2 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +220 -1203
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
- package/src/dashboard/slash-runtime/index.ts +13 -0
- package/src/dashboard/slash-runtime/model-choices.ts +35 -0
- package/src/dashboard/term-slash-runtime.ts +15 -0
- package/src/dashboard/turn-busy-teardown.ts +50 -0
- package/src/dashboard/turn-preamble.ts +30 -2
- package/src/dashboard/turn-session-layers.ts +176 -0
- package/src/dashboard/turn-stream-formatter.ts +14 -6
- package/src/dashboard/turn-stream-presentation-applier.ts +8 -0
- package/src/decisions/decision-ledger.ts +45 -4
- package/src/discord-self-message.ts +4 -4
- package/src/domains/release-tool.ts +26 -10
- package/src/domains/surface-events.ts +4 -1
- package/src/domains/watch-default-scheduler.ts +8 -9
- package/src/field-note/transcribe.ts +17 -0
- package/src/fold-stack.ts +24 -1
- package/src/git-fs/dirty.ts +32 -4
- package/src/git-fs/index.ts +43 -1
- package/src/github/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 +2 -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 +34 -6
- 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 +166 -26
- package/src/input/external-input-queue.ts +251 -0
- package/src/intake-plane/slash.ts +14 -3
- package/src/interactive-terminal-modal.ts +13 -0
- package/src/keybindings.ts +4 -1
- package/src/llm/route-decision.ts +25 -0
- package/src/llm/tool-loop-steered-rejection.ts +33 -0
- package/src/llm-stream-retry-display.ts +59 -0
- package/src/llm.ts +391 -74
- package/src/log-entry.ts +3 -3
- package/src/log-pane/search.ts +29 -4
- package/src/loops/agent-reply.ts +256 -0
- package/src/loops/budget.ts +37 -7
- package/src/loops/consensus.ts +348 -0
- package/src/loops/loop-cli.ts +3 -2
- package/src/loops/msg-address.ts +57 -0
- package/src/loops/msg-wake.ts +484 -0
- package/src/loops/observe.ts +19 -3
- package/src/loops/orchestrator/inbox.ts +60 -3
- package/src/loops/orchestrator/tick.ts +80 -6
- package/src/loops/orchestrator/traffic.ts +64 -1
- package/src/loops/registry.ts +72 -4
- package/src/market/signed-index.ts +14 -0
- package/src/mcp/mcp-oauth.ts +54 -5
- package/src/memory.ts +20 -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/native-tool-catalog.ts +125 -0
- package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
- package/src/nexus/api/http-server.ts +59 -15
- package/src/nexus/api/loop-resources.ts +19 -3
- package/src/nexus/api/ops-api.ts +13 -0
- package/src/nexus/api/project-autopsy.ts +127 -0
- package/src/nexus/api/terminals.ts +3 -0
- package/src/nexus/api/workflow-approvals.ts +2 -0
- package/src/nexus/daemon-thin-inventory.md +37 -0
- package/src/nexus/index.ts +70 -0
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -2
- package/src/nexus/state/state.ts +1 -0
- package/src/oauth/codex-account-store.ts +15 -3
- package/src/oauth/codex-billing-route.ts +31 -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/overview-collect.ts +19 -2
- package/src/ops/resources.ts +82 -0
- package/src/panes/log-pane.ts +67 -8
- package/src/persona/presets.ts +44 -0
- package/src/plugins/maker/connector-maker.ts +41 -0
- package/src/plugins/maker/skill-maker.ts +42 -0
- package/src/plugins/maker/wizard-generate.ts +6 -4
- package/src/pr-tool/census.ts +288 -0
- package/src/preview/terminal.ts +14 -1
- package/src/prompt-cache/types.ts +2 -0
- package/src/prompt-enhance/enhance.ts +24 -8
- package/src/prompt-library/chat-conciseness.ts +13 -0
- package/src/prompt-library/universal-preamble.ts +283 -61
- package/src/pty-shell/pty-control-ipc.ts +4 -1
- package/src/pty-shell/pty-manifest.ts +77 -5
- package/src/pty-shell/registry.ts +19 -2
- package/src/pty-shell/tui-run-state.ts +253 -0
- package/src/release-loop/gate-host-reservation.ts +97 -0
- package/src/release-loop/landing-freeze.ts +5 -0
- package/src/release-loop/light-rc.ts +32 -4
- 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/render.ts +5 -1
- 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/seat-report.ts +42 -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 +300 -24
- package/src/self-dev/run-types.ts +20 -0
- package/src/self-dev/shard-aggregate.ts +15 -2
- package/src/self-dev/shard-plan.ts +47 -0
- package/src/self-dev/shard-run.ts +135 -12
- package/src/self-dev/spawn-lane-files.ts +19 -0
- package/src/self-health/signatures.ts +132 -0
- package/src/self-implement/app-api-budget.ts +51 -11
- package/src/self-implement/config-gate.ts +2 -1
- package/src/self-implement/doctor-visit.ts +118 -0
- 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 +212 -18
- package/src/self-implement/gate-remote.ts +110 -25
- package/src/self-implement/gate-scenario.ts +85 -0
- package/src/self-implement/goal-author-decompose.ts +80 -16
- package/src/self-implement/goal-author.ts +270 -76
- package/src/self-implement/goal-authoring-grounding.ts +1 -1
- package/src/self-implement/goal-file-name.ts +65 -0
- package/src/self-implement/graph-authority.ts +38 -6
- package/src/self-implement/graph-overlay-condition.ts +92 -1
- package/src/self-implement/ground-goal.ts +2 -1
- package/src/self-implement/heal-triage.ts +79 -0
- package/src/self-implement/host-regate.ts +74 -2
- package/src/self-implement/orchestrator.ts +14 -123
- package/src/self-implement/pr-title.ts +123 -0
- package/src/self-implement/review-mustfix-class.ts +115 -0
- package/src/self-implement/run-checkpoint.ts +235 -0
- package/src/self-implement/run-ledger.ts +266 -17
- package/src/self-implement/run-stop.ts +4 -3
- package/src/self-implement/run-ttl.ts +28 -4
- package/src/self-implement/running-runs.ts +10 -6
- package/src/self-implement/seams.ts +2 -0
- package/src/self-implement/self-implement-runtime.ts +32 -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 +81 -11
- package/src/session/session-start.ts +224 -0
- package/src/session-runtime/index.ts +7 -1
- package/src/session-runtime/parallel-dispatch.ts +22 -5
- package/src/skills/tools/dev-harness.ts +6 -4
- package/src/skills/tools/ops-ledger.ts +707 -0
- package/src/skills/tools/persistent-grounding.ts +47 -7
- package/src/skills/tools/shell.ts +117 -1
- package/src/status/bar.ts +32 -2
- package/src/status/status-provider-info.ts +58 -0
- 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 +93 -13
- package/src/task-agent/remote-rejudge-bind.ts +62 -13
- package/src/task-agent/repair-cycle.ts +58 -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/kubectl-transient-retry.ts +51 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +138 -22
- 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 +122 -15
- 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 +103 -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 +237 -46
- package/src/telegram.ts +2 -4
- package/src/terminal/session-registry.ts +6 -0
- package/src/thinking-line.ts +12 -3
- package/src/tool-runtime/index.ts +4 -0
- package/src/tool-runtime/ops-ledger-runtimes.ts +84 -0
- package/src/tool-runtime/ref-consult-runtime.ts +17 -2
- package/src/tool-runtime/run-shell-runtime.ts +4 -1
- package/src/tool-runtime/self-cognition-runtimes.ts +5 -1
- package/src/tui/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 +53 -0
- package/src/user-config/gemini-server-tools.ts +9 -0
- package/src/user-config.ts +106 -21
- 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/fake-llm.ts +29 -0
- package/src/ux-sim/headless-tui.ts +72 -0
- package/src/ux-sim/in-process-cli.ts +176 -0
- 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/1027.a0f04663d24c2779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +0 -36
- package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1454-29d1d773d5996a49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +0 -32
- package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3259-86f3be56e43eaf6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +0 -287
- package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4084.15ecaf4240bd9e77.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +0 -8
- package/apps/pwa/out/_next/static/chunks/4565-67e4c620597965c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +0 -149
- package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +0 -1
- package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/599-56f2c0a5cc4a7295.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +0 -23
- package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +0 -77
- package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +0 -62
- package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-1e5fce59500a2cc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +0 -226
- package/apps/pwa/out/_next/static/chunks/83a80514-b897b64df43ce108.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +0 -93
- package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +0 -115
- package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +0 -41
- package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +0 -74
- package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/973cbf1b.3bbcf2b41548eca7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-66ad46ed0279feb9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-256ffd365d32e100.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e0de78ae7b99f01c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4c741eb760f2f77c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-e9ba98f5f1440a21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2f6f303fa114ec24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-bb1f05cd51c38944.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-646b50f63b6fe732.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-f736324afa2117c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6f131b51193a36f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-435f5e2faf02bc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-497e0eedf20e7890.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a8d28fdf995e16ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-66a67eb19ebd976b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c71267e7681da982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-781cfc5114e097da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-478157214db6a023.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-86141f12cf090b7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-7256c73bb1c36751.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-979d318a534e92da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-601fb77340e63c9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-11bf9e5725a72c22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +0 -1
- package/src/dashboard/bench-slash-runtime.ts +0 -40
- package/src/dashboard/input/search-modal-router.ts +0 -9
- package/src/dashboard/modals/pane-key-router.ts +0 -27
- package/src/dashboard/view-slash-runtime.ts +0 -48
- /package/apps/pwa/out/_next/static/{y1ltt7oCZxVpC6zVPhZ2O → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// GATE-WARM-BOOT (10-15) — put the cut commit into each pool host's git mirror before the shard Pods start.
|
|
2
|
+
//
|
|
3
|
+
// S: 0.2.29 gate Pods spent 750–840 s before the shard shell; the tests took 0–69 s. Every Pod clones from the host
|
|
4
|
+
// mirror (`pod.hostMirror` → `/host-mirror`, podSourceScript), but the cut commit e1783835 was not in the node-b mirror
|
|
5
|
+
// (the mirror's own fetch loop follows `main`; only the `--remote` host executor pushed `refs/elanous/gate/<sha>`).
|
|
6
|
+
// So all 68 Pods fell to `git fetch --depth 1 origin <sha>` from GitHub, under load, one by one.
|
|
7
|
+
// A: push `<sha>:refs/elanous/gate/<sha>` to the placed pool member's mirror once per (host, commit) per process — podSourceScript's commit branch
|
|
8
|
+
// then passes `git cat-file -e` and skips the GitHub fetch. Best effort: a failed push is recorded and the Pod keeps
|
|
9
|
+
// its old path (fetch from GitHub) — never a silent use of another tree.
|
|
10
|
+
import { spawn } from 'node:child_process';
|
|
11
|
+
import { debug } from '../../debug/log.js';
|
|
12
|
+
|
|
13
|
+
/** Host-side mirror path (relative to the ssh user's home) — the k3d node binds `~/mirror` at `/mirror-host`. */
|
|
14
|
+
export const GATE_POOL_MIRROR_PATH = 'mirror/elanous-agent.git';
|
|
15
|
+
export const GATE_MIRROR_SEED_LIMIT_MS = 120_000;
|
|
16
|
+
|
|
17
|
+
export interface MirrorSeedResult { host: string; ok: boolean; ms: number; detail?: string }
|
|
18
|
+
|
|
19
|
+
type Push = (args: string[], cwd: string, limitMs: number) => Promise<{ rc: number; output: string }>;
|
|
20
|
+
|
|
21
|
+
export async function seedPoolMirrors(o: { hosts: readonly (string | undefined)[]; commit: string; tree: string; push: Push; mirrorPath?: string; limitMs?: number }): Promise<MirrorSeedResult[]> {
|
|
22
|
+
if (!/^[0-9a-f]{40}$/.test(o.commit)) throw new Error('invalid gate commit');
|
|
23
|
+
const mirror = o.mirrorPath ?? GATE_POOL_MIRROR_PATH;
|
|
24
|
+
const hosts = [...new Set(o.hosts.filter((host): host is string => !!host && /^[\w.@-]+$/.test(host) && !host.startsWith('-')))];
|
|
25
|
+
const results = await Promise.all(hosts.map(async (host): Promise<MirrorSeedResult> => {
|
|
26
|
+
const start = Date.now();
|
|
27
|
+
try {
|
|
28
|
+
const run = await o.push(['push', '--quiet', '--no-verify', `${host}:${mirror}`, `${o.commit}:refs/elanous/gate/${o.commit}`], o.tree, o.limitMs ?? GATE_MIRROR_SEED_LIMIT_MS);
|
|
29
|
+
const ms = Date.now() - start;
|
|
30
|
+
return run.rc === 0 ? { host, ok: true, ms } : { host, ok: false, ms, detail: run.output.trim().slice(-300) };
|
|
31
|
+
} catch (error) {
|
|
32
|
+
return { host, ok: false, ms: Date.now() - start, detail: String(error).slice(0, 300) };
|
|
33
|
+
}
|
|
34
|
+
}));
|
|
35
|
+
for (const result of results) {
|
|
36
|
+
debug.log('release-loop.gate', result.ok ? 'pod-mirror-seeded' : 'pod-mirror-seed-failed', { ...result, commit: o.commit }, result.ok ? undefined : { level: 'warn' });
|
|
37
|
+
}
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const seeded = new Map<string, Promise<MirrorSeedResult | undefined>>();
|
|
42
|
+
|
|
43
|
+
/** Bounded `git <args>` in `cwd` — killed after `limitMs`; never throws. */
|
|
44
|
+
export function gitWithin(args: string[], cwd: string, limitMs: number): Promise<{ rc: number; output: string }> {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
let output = '';
|
|
47
|
+
let child;
|
|
48
|
+
try { child = spawn('git', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] }); }
|
|
49
|
+
catch (error) { resolve({ rc: 2, output: String(error) }); return; }
|
|
50
|
+
const timer = setTimeout(() => { output += `\n[mirror-seed] timed out after ${limitMs} ms`; child.kill('SIGKILL'); }, limitMs);
|
|
51
|
+
child.stdout?.on('data', (chunk) => { output += String(chunk); });
|
|
52
|
+
child.stderr?.on('data', (chunk) => { output += String(chunk); });
|
|
53
|
+
child.on('error', (error) => { clearTimeout(timer); resolve({ rc: 2, output: `${output}\n${String(error)}` }); });
|
|
54
|
+
child.on('close', (code) => { clearTimeout(timer); resolve({ rc: code ?? 2, output }); });
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Seed once per (host, commit) in this process: every shard Job placed on the same member awaits the same push, so a
|
|
60
|
+
* 28-shard gate pushes once per host. `cwd` must be a git tree that has the commit (the gate runs in the repo tree).
|
|
61
|
+
*/
|
|
62
|
+
export function seedMirrorOnce(o: { host: string; commit: string; cwd: string; push?: Push }): Promise<MirrorSeedResult | undefined> {
|
|
63
|
+
const key = `${o.host}\0${o.commit}`;
|
|
64
|
+
let pending = seeded.get(key);
|
|
65
|
+
if (!pending) {
|
|
66
|
+
// A failed seed is not memoized — the next Job on that host tries again (a transient ssh drop must not send the whole gate to GitHub).
|
|
67
|
+
pending = seedPoolMirrors({ hosts: [o.host], commit: o.commit, tree: o.cwd, push: o.push ?? gitWithin })
|
|
68
|
+
.then((results) => { if (!results[0]?.ok) seeded.delete(key); return results[0]; },
|
|
69
|
+
(error: unknown) => { seeded.delete(key); return { host: o.host, ok: false, ms: 0, detail: String(error).slice(0, 300) }; });
|
|
70
|
+
seeded.set(key, pending);
|
|
71
|
+
}
|
|
72
|
+
return pending;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* SI-SEED-DEFAULT — a default-source si-task Job (main HEAD, or `--base <branch>`) has no pinned sha, so the host resolves
|
|
77
|
+
* the branch tip once (`git ls-remote`, bounded) and makes sure the seeding tree has that commit (a bounded fetch of that
|
|
78
|
+
* one sha when it does not — objects only, no ref is moved). Never throws: a miss returns `reason` and the caller skips
|
|
79
|
+
* the seed (best effort — the Job keeps its GitHub path).
|
|
80
|
+
*/
|
|
81
|
+
export async function resolveDefaultSourceHead(o: { repoUrl: string; base?: string; cwd: string; git?: Push; limitMs?: number }): Promise<{ sha?: string; reason?: string }> {
|
|
82
|
+
const git = o.git ?? gitWithin;
|
|
83
|
+
const limitMs = o.limitMs ?? 30_000;
|
|
84
|
+
const base = o.base || 'main';
|
|
85
|
+
if (base.startsWith('-') || !/^[\w./-]+$/.test(base) || o.repoUrl.startsWith('-')) return { reason: 'invalid-ref' };
|
|
86
|
+
try {
|
|
87
|
+
const listed = await git(['ls-remote', '--', o.repoUrl, `refs/heads/${base}`], o.cwd, limitMs);
|
|
88
|
+
if (listed.rc !== 0) return { reason: 'ls-remote-failed' };
|
|
89
|
+
// Only the exact ref asked for — never the first `refs/heads/*` line (a branch named `a/refs/heads/main` must not pass).
|
|
90
|
+
const want = `refs/heads/${base}`;
|
|
91
|
+
const sha = listed.output.split(/\r?\n/).map((line) => line.split('\t')).find(([hash, ref]) => ref === want && /^[0-9a-f]{40}$/.test(hash ?? ''))?.[0];
|
|
92
|
+
if (!sha) return { reason: 'ls-remote-no-sha' };
|
|
93
|
+
if ((await git(['cat-file', '-e', `${sha}^{commit}`], o.cwd, limitMs)).rc === 0) return { sha };
|
|
94
|
+
const fetched = await git(['fetch', '--quiet', '--no-write-fetch-head', '--', o.repoUrl, sha], o.cwd, GATE_MIRROR_SEED_LIMIT_MS);
|
|
95
|
+
if (fetched.rc !== 0) return { reason: 'commit-fetch-failed' };
|
|
96
|
+
return (await git(['cat-file', '-e', `${sha}^{commit}`], o.cwd, limitMs)).rc === 0 ? { sha } : { reason: 'commit-not-local' };
|
|
97
|
+
} catch {
|
|
98
|
+
return { reason: 'resolve-threw' };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Test seam — forget the per-process seed memo. */
|
|
103
|
+
export function resetMirrorSeedMemo(): void { seeded.clear(); }
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// TA-POD-WARMBOOT-PARITY (10-15) — the Pod result marker (GATE-POD-RESULT-MARKER · #27815) for Jobs that do not go
|
|
2
|
+
// through runPodCommand (the si-task Job in self-implement-pod.ts).
|
|
3
|
+
//
|
|
4
|
+
// S: runPodCommand prints `\n<marker> <launch> rc=<n>\n` as the child's last line and ends its wait on it when the Job
|
|
5
|
+
// condition lags (k3d). The si-task Job builds its own manifest and waits only on the condition.
|
|
6
|
+
// A: reuse the marker format and split from pod-command-job.ts (no second format), and keep the one-poll judgement
|
|
7
|
+
// («no condition yet → read the tail → this launch's marker? → rc») as a pure function here.
|
|
8
|
+
// ⚠️ pod-command-job.ts imports self-implement-pod.ts statically, so self-implement-pod.ts loads this module with a
|
|
9
|
+
// dynamic import only (a static import back would hit the TDZ of the cycle).
|
|
10
|
+
// Later (after T1): runPodCommand's own loop can call podResultMarkerRc too.
|
|
11
|
+
import { podResultMarker, splitPodResultMarker } from './pod-command-job.js';
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/** The child's final shell line: prints this launch's marker with the child rc (same bytes runPodCommand's child prints).
|
|
15
|
+
* null when the token is not a plain id (`[A-Za-z0-9_.:-]+`) — the Job then runs without a marker (condition path only). */
|
|
16
|
+
export function podResultMarkerShellLine(token: string): string | null {
|
|
17
|
+
if (!/^[\w.:-]+$/.test(token)) return null;
|
|
18
|
+
return `printf '\\n%s rc=%s\\n' '${podResultMarker(token)}' "$rc"`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* One poll, condition not there yet: the `kubectl logs … --tail=2` result → this launch's rc, or null.
|
|
23
|
+
* A failed read (Pod pending · init container), another launch's marker, or a bare marker word is null (keep waiting).
|
|
24
|
+
*/
|
|
25
|
+
export function podResultMarkerRc(tail: { status: number | null; stdout: string }, token: string): number | null {
|
|
26
|
+
if (tail.status !== 0) return null;
|
|
27
|
+
return splitPodResultMarker(tail.stdout.startsWith('\n') ? tail.stdout : `\n${tail.stdout}`, token).rc;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Remove this launch's marker tail from the child logs before they are parsed (other bytes unchanged). */
|
|
31
|
+
export function stripPodResultMarker(logs: string, token: string): string {
|
|
32
|
+
return splitPodResultMarker(logs, token).logs;
|
|
33
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Files and caches that survive between requests on a reusable Pod worker. */
|
|
2
|
+
export const POD_REUSE_CLEAN_EXCLUSIONS = [
|
|
3
|
+
{ name: 'node_modules', pattern: 'node_modules' },
|
|
4
|
+
{ name: 'apps/pwa/node_modules', pattern: 'apps/pwa/node_modules' },
|
|
5
|
+
// Bun's install cache and remote gate cache live outside the worker checkout.
|
|
6
|
+
{ name: 'bun install cache', pattern: null },
|
|
7
|
+
{ name: 'TypeScript build info', pattern: '*.tsbuildinfo' },
|
|
8
|
+
{ name: 'remote gate TypeScript cache', pattern: null },
|
|
9
|
+
] as const;
|
|
10
|
+
|
|
11
|
+
export type PodReuseCleanupOutcome = 'reuse' | 'discard';
|
|
12
|
+
|
|
13
|
+
export interface PodReuseCleanupDecisionInput {
|
|
14
|
+
base: string;
|
|
15
|
+
resetExitCode: number | null;
|
|
16
|
+
cleanExitCode: number | null;
|
|
17
|
+
statusExitCode: number | null;
|
|
18
|
+
statusPorcelain: string;
|
|
19
|
+
remainingPaths?: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface PodReuseCleanupDecision {
|
|
23
|
+
resetArgs: readonly string[];
|
|
24
|
+
cleanArgs: readonly string[];
|
|
25
|
+
statusArgs: readonly string[];
|
|
26
|
+
preserved: readonly string[];
|
|
27
|
+
outcome: PodReuseCleanupOutcome;
|
|
28
|
+
reason?: 'invalid-base' | 'reset-failed' | 'clean-failed' | 'status-failed' | 'worktree-not-clean';
|
|
29
|
+
remainingPaths: readonly string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Pure request-boundary decision: return argv for the caller to execute and
|
|
34
|
+
* decide whether the worker can be reused from the command results.
|
|
35
|
+
* Execution/wiring and lifecycle event emission intentionally live in a later slice.
|
|
36
|
+
*/
|
|
37
|
+
export function decidePodReuseCleanup(input: PodReuseCleanupDecisionInput): PodReuseCleanupDecision {
|
|
38
|
+
const remainingPaths = (input.remainingPaths ?? []).slice(0, 5);
|
|
39
|
+
const resetArgs = ['reset', '--hard', input.base] as const;
|
|
40
|
+
const cleanArgs = [
|
|
41
|
+
'clean', '-ffdx',
|
|
42
|
+
...POD_REUSE_CLEAN_EXCLUSIONS.flatMap(({ pattern }) => pattern ? ['-e', pattern] : []),
|
|
43
|
+
] as const;
|
|
44
|
+
const statusArgs = ['status', '--porcelain'] as const;
|
|
45
|
+
const preserved = POD_REUSE_CLEAN_EXCLUSIONS.map(({ name }) => name);
|
|
46
|
+
|
|
47
|
+
let reason: PodReuseCleanupDecision['reason'];
|
|
48
|
+
if (!/^[0-9a-f]{40}$/i.test(input.base)) reason = 'invalid-base';
|
|
49
|
+
else if (input.resetExitCode !== 0) reason = 'reset-failed';
|
|
50
|
+
else if (input.cleanExitCode !== 0) reason = 'clean-failed';
|
|
51
|
+
else if (input.statusExitCode !== 0) reason = 'status-failed';
|
|
52
|
+
else if (input.statusPorcelain.trim() !== '') reason = 'worktree-not-clean';
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
resetArgs,
|
|
56
|
+
cleanArgs,
|
|
57
|
+
statusArgs,
|
|
58
|
+
preserved,
|
|
59
|
+
outcome: reason ? 'discard' : 'reuse',
|
|
60
|
+
...(reason ? { reason } : {}),
|
|
61
|
+
remainingPaths,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* sha·PR·커밋은 형식 검사 전에 스크립트에 넣지 않는다(셸 주입 차단). */
|
|
3
3
|
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { siTaskPodStageShell } from './pod-lifecycle-stages.js';
|
|
5
6
|
|
|
6
7
|
export type PodSource =
|
|
7
8
|
| { kind: 'default'; base?: string }
|
|
@@ -52,17 +53,30 @@ function assertRemoteBase(repoUrl: string, base: string): void {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
/** Job 스크립트의 원천 단계. 성공 갈래는 `ELANOUS_POD_SOURCE <kind> <HEAD>` 로 끝난다.
|
|
56
|
-
|
|
56
|
+
/** Job 스크립트의 원천 단계. 성공 갈래는 `ELANOUS_POD_SOURCE <kind> <HEAD>` 로 끝난다.
|
|
57
|
+
* `stageMarkers` — si-task Job 만: 호스트 미러 `clone --shared` 시도의 시작·성공을 `ELANOUS_POD_STAGE mirror start|end` 로 찍는다
|
|
58
|
+
* (건너뛰거나 실패하면 끝 표지가 없다 → 호스트가 missing 으로 읽는다). 기본은 꺼짐 — gate·pod-command Job 의 바이트는 그대로다. */
|
|
59
|
+
export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath = '/host-mirror', options: { stageMarkers?: boolean } = {}): string {
|
|
60
|
+
const mark = (edge: 'start' | 'end'): string[] => options.stageMarkers ? [siTaskPodStageShell('mirror', edge)] : [];
|
|
57
61
|
const quotedUrl = `'${repoUrl.replace(/'/g, `'\\''`)}'`;
|
|
58
62
|
const quotedMirror = `'${mirrorPath.replace(/'/g, `'\\''`)}'`;
|
|
59
63
|
const clone = `git clone -q --depth 50 ${quotedUrl} repo`;
|
|
60
64
|
const start = [
|
|
61
65
|
'if [ -e repo ]; then exit 5; fi',
|
|
62
|
-
|
|
66
|
+
// TA-POD-WARMBOOT-PARITY (10-16): the mirror fallback used to be silent — 157 HARD gate Pods all said
|
|
67
|
+
// `VIA github` and nothing said why (the Job had no /host-mirror mount). Each failed step now names itself.
|
|
68
|
+
'mirror_skip=',
|
|
69
|
+
...mark('start'),
|
|
70
|
+
`if ! [ -d ${quotedMirror} ]; then mirror_skip=no-mount`,
|
|
71
|
+
`elif ! git -C ${quotedMirror} rev-parse --verify HEAD >/dev/null 2>&1; then mirror_skip=rev-parse-failed`,
|
|
72
|
+
`elif ! git clone -q --shared -- ${quotedMirror} repo || ! git -C repo rev-parse --verify HEAD >/dev/null 2>&1; then mirror_skip=clone-failed`,
|
|
73
|
+
'fi',
|
|
74
|
+
'if [ -z "$mirror_skip" ]; then',
|
|
75
|
+
...mark('end').map((line) => ` ${line}`),
|
|
63
76
|
` git -C repo remote set-url origin ${quotedUrl} || exit 5`,
|
|
64
77
|
' source_via=mirror',
|
|
65
78
|
'else',
|
|
79
|
+
" printf 'ELANOUS_POD_SOURCE_MIRROR_SKIP %s\\n' \"$mirror_skip\"",
|
|
66
80
|
' if [ -e repo ]; then rm -r -- repo || exit 5; fi',
|
|
67
81
|
` ${clone} || exit 5`,
|
|
68
82
|
' source_via=github',
|
|
@@ -143,7 +157,9 @@ export function podSourceScript(source: PodSource, repoUrl: string, mirrorPath =
|
|
|
143
157
|
' exit 3',
|
|
144
158
|
'fi',
|
|
145
159
|
'if [ -e repo ]; then exit 5; fi',
|
|
160
|
+
...mark('start'),
|
|
146
161
|
`if [ -d ${quotedMirror} ] && git -C ${quotedMirror} rev-parse --verify HEAD >/dev/null 2>&1 && git clone -q --shared -- ${quotedMirror} repo && git -C repo rev-parse --verify HEAD >/dev/null 2>&1; then`,
|
|
162
|
+
...mark('end').map((line) => ` ${line}`),
|
|
147
163
|
` git -C repo remote set-url origin ${quotedUrl} || exit 5`,
|
|
148
164
|
' if git -C repo bundle verify /tmp/source.bundle >/dev/null 2>&1; then',
|
|
149
165
|
' git -C repo fetch /tmp/source.bundle "refs/elanous/pod-source/*:refs/remotes/bundle/*" || exit 5',
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* warm Pod 재사용 ⑤ — 소비자별 «실전 사용 가능?» 손잡이 (PLAN-warm-reuse-tonight-2026-10-15 §5).
|
|
3
|
+
*
|
|
4
|
+
* 관측: 판정마다 `debug.log('pod.warm', 'switch-decision', …)` 한 줄(소비자·live·reason·표본 수).
|
|
5
|
+
* 판단: config flag(`pod.warmReuse.{gateRecheck,land,ta}` · 기본 false) ⊕ 증거
|
|
6
|
+
* (lease 유효 · 카나리아 통과 · 같은 head/main/lock · 최근 mismatch 0 · 연속 일치 표본 ≥ minMatchSamples).
|
|
7
|
+
* 수복: live=false 면 소비자는 기존 fresh Job 경로를 그대로 탄다 — reason 이 «무엇이 모자랐나»를 넘긴다.
|
|
8
|
+
*
|
|
9
|
+
* ⛔ 이 모듈은 판정만 한다. 소비자 결선(pod-command-job · gate-node · self-implement-pod)은 각 소비자 PR 몫이다.
|
|
10
|
+
* ⛔ 못 잰 증거(undefined)는 «통과»가 아니라 «off» 다 — 모르면 켜지 않는다.
|
|
11
|
+
* 순서: gate-recheck → land → ta. 앞 소비자가 «자기 증거로» live 가 아니면 뒤 소비자도 live 가 아니다
|
|
12
|
+
* (증거는 소비자별 — 뒤 소비자의 증거로 앞 소비자를 대신 판정하지 않는다 · 앞 증거가 없으면 off).
|
|
13
|
+
*/
|
|
14
|
+
import { debug } from '../../debug/log.js';
|
|
15
|
+
|
|
16
|
+
export type WarmReuseConsumer = 'gate-recheck' | 'land' | 'ta';
|
|
17
|
+
|
|
18
|
+
/** 켜는 순서 — 뒤 소비자는 바로 앞 소비자가 live 일 때만 live 가 될 수 있다. */
|
|
19
|
+
export const WARM_REUSE_CONSUMER_ORDER: readonly WarmReuseConsumer[] = ['gate-recheck', 'land', 'ta'];
|
|
20
|
+
|
|
21
|
+
/** 연속 일치 표본 기본 하한(보수적). */
|
|
22
|
+
export const DEFAULT_WARM_MIN_MATCH_SAMPLES = 3;
|
|
23
|
+
|
|
24
|
+
/** `pod.warmReuse` config 절 — 타입이 어긋난 값은 off/기본값으로 읽는다. */
|
|
25
|
+
export interface WarmReuseSwitchConfig {
|
|
26
|
+
gateRecheck?: boolean;
|
|
27
|
+
land?: boolean;
|
|
28
|
+
ta?: boolean;
|
|
29
|
+
minMatchSamples?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** warm 워커 신원 — 기대값(fresh Job 쪽)과 워커 쪽을 같은 칸끼리 대조한다. */
|
|
33
|
+
export interface WarmReuseIdentity {
|
|
34
|
+
head?: string;
|
|
35
|
+
main?: string;
|
|
36
|
+
lock?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** 판정 증거. 칸이 비면(undefined) «못 쟀다» = off. */
|
|
40
|
+
export interface WarmReuseEvidence {
|
|
41
|
+
/** 같은 파일 fresh Job 대비 연속 일치(rc ⊕ JUnit 실패 ID) 표본 수. */
|
|
42
|
+
consecutiveMatchSamples?: number;
|
|
43
|
+
/** 최근 창의 warm↔fresh mismatch 수 — 0 이어야 live. */
|
|
44
|
+
recentMismatchCount?: number;
|
|
45
|
+
/** Nexus `pod-worker-lease` 가 현재 generation 으로 유효한가. */
|
|
46
|
+
leaseValid?: boolean;
|
|
47
|
+
/** 정비 뒤 카나리아 통과. */
|
|
48
|
+
canaryPassed?: boolean;
|
|
49
|
+
expected?: WarmReuseIdentity;
|
|
50
|
+
worker?: WarmReuseIdentity;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** 소비자별 증거 — 판정 대상 ⊕ 그 앞 소비자들의 증거가 모두 있어야 live 가 될 수 있다. */
|
|
54
|
+
export type WarmReuseEvidenceByConsumer = Partial<Record<WarmReuseConsumer, WarmReuseEvidence>>;
|
|
55
|
+
|
|
56
|
+
export interface WarmReuseDecision {
|
|
57
|
+
consumer: WarmReuseConsumer;
|
|
58
|
+
live: boolean;
|
|
59
|
+
/** `live` 이거나 첫 번째로 걸린 이유(예 `flag-off` · `predecessor-off:land` · `samples-short`). */
|
|
60
|
+
reason: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const FLAG_KEY: Record<WarmReuseConsumer, keyof Pick<WarmReuseSwitchConfig, 'gateRecheck' | 'land' | 'ta'>> = {
|
|
64
|
+
'gate-recheck': 'gateRecheck',
|
|
65
|
+
land: 'land',
|
|
66
|
+
ta: 'ta',
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const IDENTITY_FIELDS = ['head', 'main', 'lock'] as const;
|
|
70
|
+
|
|
71
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
72
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** minMatchSamples — 양의 안전 정수만, 아니면 기본값. */
|
|
76
|
+
export function resolveWarmMinMatchSamples(config: unknown): number {
|
|
77
|
+
const raw = isRecord(config) ? config.minMatchSamples : undefined;
|
|
78
|
+
return typeof raw === 'number' && Number.isSafeInteger(raw) && raw > 0 ? raw : DEFAULT_WARM_MIN_MATCH_SAMPLES;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** flag — 문자 그대로 `true` 만 켠다. */
|
|
82
|
+
export function warmReuseFlagOn(config: unknown, consumer: WarmReuseConsumer): boolean {
|
|
83
|
+
return isRecord(config) && config[FLAG_KEY[consumer]] === true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function evidenceReason(evidence: WarmReuseEvidence | undefined, minSamples: number): string | null {
|
|
87
|
+
if (!evidence) return 'evidence-unmeasured';
|
|
88
|
+
if (evidence.leaseValid !== true) return evidence.leaseValid === false ? 'lease-invalid' : 'lease-unmeasured';
|
|
89
|
+
if (evidence.canaryPassed !== true) return evidence.canaryPassed === false ? 'canary-failed' : 'canary-unmeasured';
|
|
90
|
+
for (const field of IDENTITY_FIELDS) {
|
|
91
|
+
const want = evidence.expected?.[field];
|
|
92
|
+
const got = evidence.worker?.[field];
|
|
93
|
+
if (typeof want !== 'string' || !want || typeof got !== 'string' || !got) return `identity-unmeasured:${field}`;
|
|
94
|
+
// 원값 그대로 정확히 비교한다 — 앞뒤 공백 등 형식이 어긋난 값은 고쳐 읽지 않고 off.
|
|
95
|
+
if (want !== want.trim() || got !== got.trim()) return `identity-malformed:${field}`;
|
|
96
|
+
if (want !== got) return `identity-mismatch:${field}`;
|
|
97
|
+
}
|
|
98
|
+
const mismatches = evidence.recentMismatchCount;
|
|
99
|
+
if (typeof mismatches !== 'number' || !Number.isSafeInteger(mismatches) || mismatches < 0) return 'mismatch-unmeasured';
|
|
100
|
+
if (mismatches > 0) return 'recent-mismatch';
|
|
101
|
+
const samples = evidence.consecutiveMatchSamples;
|
|
102
|
+
if (typeof samples !== 'number' || !Number.isSafeInteger(samples) || samples < 0) return 'samples-unmeasured';
|
|
103
|
+
if (samples < minSamples) return 'samples-short';
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function decide(consumer: WarmReuseConsumer, config: unknown, evidence: WarmReuseEvidenceByConsumer | undefined): string {
|
|
108
|
+
if (!warmReuseFlagOn(config, consumer)) return 'flag-off';
|
|
109
|
+
const index = WARM_REUSE_CONSUMER_ORDER.indexOf(consumer);
|
|
110
|
+
if (index > 0) {
|
|
111
|
+
const predecessor = WARM_REUSE_CONSUMER_ORDER[index - 1]!;
|
|
112
|
+
if (decide(predecessor, config, evidence) !== 'live') return `predecessor-off:${predecessor}`;
|
|
113
|
+
}
|
|
114
|
+
const own = isRecord(evidence) ? evidence[consumer] : undefined;
|
|
115
|
+
return evidenceReason(isRecord(own) ? own : undefined, resolveWarmMinMatchSamples(config)) ?? 'live';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 소비자 하나가 지금 warm 워커를 «실전»으로 써도 되나.
|
|
120
|
+
* `config` 는 `getUserConfig().pod?.warmReuse` 를 그대로 넘긴다(없으면 전부 off).
|
|
121
|
+
* `evidence` 는 소비자별 — 대상 소비자 ⊕ 그 앞 소비자들의 칸이 모두 있어야 한다(앞 칸이 비면 `predecessor-off:<앞>`).
|
|
122
|
+
*/
|
|
123
|
+
export function decideWarmReuse(
|
|
124
|
+
consumer: WarmReuseConsumer,
|
|
125
|
+
config: WarmReuseSwitchConfig | undefined,
|
|
126
|
+
evidence: WarmReuseEvidenceByConsumer | undefined,
|
|
127
|
+
): WarmReuseDecision {
|
|
128
|
+
const reason = decide(consumer, config, evidence);
|
|
129
|
+
const live = reason === 'live';
|
|
130
|
+
const own = isRecord(evidence) && isRecord(evidence[consumer]) ? evidence[consumer] : undefined;
|
|
131
|
+
debug.log('pod.warm', 'switch-decision', {
|
|
132
|
+
consumer,
|
|
133
|
+
live,
|
|
134
|
+
reason,
|
|
135
|
+
flag: warmReuseFlagOn(config, consumer),
|
|
136
|
+
minMatchSamples: resolveWarmMinMatchSamples(config),
|
|
137
|
+
samples: own?.consecutiveMatchSamples ?? null,
|
|
138
|
+
recentMismatchCount: own?.recentMismatchCount ?? null,
|
|
139
|
+
});
|
|
140
|
+
return { consumer, live, reason };
|
|
141
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* warm Pod 재사용 — 'ta' 소비자의 «그림자 비교» 순수 모듈 (PLAN-warm-reuse-tonight-2026-10-15 §5 · pod-warm-switch.ts 의 'ta' 몫).
|
|
3
|
+
*
|
|
4
|
+
* 관측: 이 모듈은 아무것도 관측하지 않는다 — 완료된 si-task Job outcome 과 lease-fenced warm candidate 를
|
|
5
|
+
* «받은 값만으로» 비교한다(자체 I/O · 부수효과 없음).
|
|
6
|
+
* 판단: 후보 키는 원문이 준 두 성분 — same source SHA / child model. lease 펜스(pod-lease.ts 세대 펜스,
|
|
7
|
+
* WarmReuseEvidence.leaseValid 와 같은 칸)가 유효하지 않으면 키가 같아도 기각한다(fail-closed).
|
|
8
|
+
* 수복: match=false 면 호출자는 기존 fresh Job 경로를 그대로 탄다 — reason 이 «무엇이 모자랐나»를 넘긴다.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ 이 모듈은 비교만 한다. 소비자 결선(self-implement-pod 연결)은 형제 샤드 몫이다(정의-결선 분리 경계).
|
|
11
|
+
* ⛔ 못 잰 값(undefined · 빈 값)은 «일치»가 아니라 «기각» 이다 — pod-warm-switch.ts 의
|
|
12
|
+
* 'unmeasured = off' 규율과 원값 그대로의 정확 비교(앞뒤 공백 등 형식 어긋남은 고쳐 읽지 않는다)를 그대로 잇는다.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* UNRESOLVED — 원문 요청 문면이 `(keyed by same source SHA / child model /` 에서 끊겼다.
|
|
17
|
+
* child model 뒤에 추가 키 성분이 더 있는지, 그리고 그 뒤에 이어지던 비교 요구가 무엇이었는지 이 문서에서 확정할 수 없다.
|
|
18
|
+
* 이 모듈은 확정된 두 키(same source SHA / child model)만 비교한다 — 나머지는 의도적으로 미정(unspecified)이며 지어내지 않는다.
|
|
19
|
+
* 추가 성분은 원문 회수 시 그 표현 그대로만 붙인다.
|
|
20
|
+
*/
|
|
21
|
+
export const TA_SHADOW_UNRESOLVED_NOTE: string =
|
|
22
|
+
"UNRESOLVED: original ask truncated after '(keyed by same source SHA / child model /' — " +
|
|
23
|
+
'confirmed keys are source SHA and child model; any further key components or comparison ' +
|
|
24
|
+
'requirements are intentionally unspecified, not invented.';
|
|
25
|
+
|
|
26
|
+
/** 완료된 si-task Job outcome — 비교에 쓰는 키 성분만 담는다(원문 확정: same source SHA / child model). */
|
|
27
|
+
export interface SiTaskJobOutcome {
|
|
28
|
+
/** 이 outcome 을 낸 원본 소스의 SHA — 후보 키 성분 ①. */
|
|
29
|
+
sourceSha: string;
|
|
30
|
+
/** 이 outcome 을 낸 자식 모델(self-implement-pod.ts `childModel` 과 같은 문자열 칸) — 후보 키 성분 ②. */
|
|
31
|
+
childModel: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* lease-fenced warm candidate — pod-lease.ts 세대 펜스가 붙은 warm 재사용 후보.
|
|
36
|
+
* `leaseValid` 는 pod-warm-switch.ts `WarmReuseEvidence.leaseValid` 와 같은 칸:
|
|
37
|
+
* `true` = 현재 generation 유효 · `false` = 펜스 기각 · `undefined` = 못 잰(off).
|
|
38
|
+
*/
|
|
39
|
+
export interface LeaseFencedWarmCandidate {
|
|
40
|
+
sourceSha: string;
|
|
41
|
+
childModel: string;
|
|
42
|
+
leaseValid?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** 비교 결과 — 첫 번째로 걸린 이유를 그대로 넘긴다(«lease-fence rejection passthrough» 포함). */
|
|
46
|
+
export interface TaShadowComparison {
|
|
47
|
+
match: boolean;
|
|
48
|
+
reason:
|
|
49
|
+
| 'match'
|
|
50
|
+
| 'lease-unmeasured'
|
|
51
|
+
| 'lease-invalid'
|
|
52
|
+
| 'source-sha-unmeasured'
|
|
53
|
+
| 'source-sha-malformed'
|
|
54
|
+
| 'source-sha-mismatch'
|
|
55
|
+
| 'child-model-unmeasured'
|
|
56
|
+
| 'child-model-malformed'
|
|
57
|
+
| 'child-model-mismatch';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 원값 그대로의 정확 비교 — 못 잼(unmeasured) · 형식 어긋남(malformed) · 불일치(mismatch) 를 갈라 뱉는다. */
|
|
61
|
+
function exactString(
|
|
62
|
+
field: 'source-sha' | 'child-model',
|
|
63
|
+
outcome: string,
|
|
64
|
+
candidate: string,
|
|
65
|
+
): TaShadowComparison['reason'] | null {
|
|
66
|
+
if (typeof outcome !== 'string' || !outcome || typeof candidate !== 'string' || !candidate) return `${field}-unmeasured`;
|
|
67
|
+
if (outcome !== outcome.trim() || candidate !== candidate.trim()) return `${field}-malformed`;
|
|
68
|
+
if (outcome !== candidate) return `${field}-mismatch`;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 완료된 si-task Job outcome 과 lease-fenced warm candidate 가 «같은 키» 인지 — 순수 비교.
|
|
74
|
+
* 순서: lease 펜스 먼저(펜스가 기각이면 키가 같아도 기각이 우선한다) → source SHA → child model.
|
|
75
|
+
*/
|
|
76
|
+
export function compareWarmTaShadow(outcome: SiTaskJobOutcome, candidate: LeaseFencedWarmCandidate): TaShadowComparison {
|
|
77
|
+
if (candidate.leaseValid !== true) {
|
|
78
|
+
return { match: false, reason: candidate.leaseValid === false ? 'lease-invalid' : 'lease-unmeasured' };
|
|
79
|
+
}
|
|
80
|
+
const sha = exactString('source-sha', outcome.sourceSha, candidate.sourceSha);
|
|
81
|
+
if (sha !== null) return { match: false, reason: sha };
|
|
82
|
+
const model = exactString('child-model', outcome.childModel, candidate.childModel);
|
|
83
|
+
if (model !== null) return { match: false, reason: model };
|
|
84
|
+
return { match: true, reason: 'match' };
|
|
85
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warm Pod wire contract. A reply is only a shadow observation until its lease,
|
|
3
|
+
* attempt, artifacts, and result agree with the existing one-shot Job.
|
|
4
|
+
* No command or result in this module launches a Pod or changes the gate verdict.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface WarmWorkerKey {
|
|
8
|
+
context: string;
|
|
9
|
+
imageDigest: string;
|
|
10
|
+
lockHash: string;
|
|
11
|
+
architecture: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WarmWorkerCommand {
|
|
15
|
+
protocol: 1;
|
|
16
|
+
runId: string;
|
|
17
|
+
attemptId: string;
|
|
18
|
+
cutSha: string;
|
|
19
|
+
baselineSha?: string;
|
|
20
|
+
leaseId: string;
|
|
21
|
+
generation: number;
|
|
22
|
+
workerId: string;
|
|
23
|
+
key: WarmWorkerKey;
|
|
24
|
+
deadlineAt: number;
|
|
25
|
+
files: readonly string[];
|
|
26
|
+
/** Named, versioned environment profile; credentials travel through the existing Secret path. */
|
|
27
|
+
envProfile: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface WarmWorkerFileResult {
|
|
31
|
+
file: string;
|
|
32
|
+
rc: number;
|
|
33
|
+
/** Canonical `file > case` IDs parsed from a complete JUnit artifact. */
|
|
34
|
+
failureIds: readonly string[];
|
|
35
|
+
/** Named unhandled errors, including those emitted outside JUnit. */
|
|
36
|
+
errorIds: readonly string[];
|
|
37
|
+
junitComplete: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface WarmWorkerReply {
|
|
41
|
+
protocol: 1;
|
|
42
|
+
runId: string;
|
|
43
|
+
attemptId: string;
|
|
44
|
+
cutSha: string;
|
|
45
|
+
baselineSha?: string;
|
|
46
|
+
leaseId: string;
|
|
47
|
+
generation: number;
|
|
48
|
+
workerId: string;
|
|
49
|
+
key: WarmWorkerKey;
|
|
50
|
+
envProfile: string;
|
|
51
|
+
startedAt: number;
|
|
52
|
+
finishedAt: number;
|
|
53
|
+
files: readonly WarmWorkerFileResult[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type WarmShadowReason = 'match' | 'no-sample' | 'reply-unmeasured' | 'reference-unmeasured' | 'invalid-reply' | 'identity' | 'missing-artifact' | 'file-set' | 'result';
|
|
57
|
+
export interface WarmShadowDecision {
|
|
58
|
+
reason: WarmShadowReason;
|
|
59
|
+
/** The existing Job remains authoritative throughout shadow mode. */
|
|
60
|
+
adopt: 'job';
|
|
61
|
+
quarantineWorker: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const decision = (reason: WarmShadowReason): WarmShadowDecision =>
|
|
65
|
+
({ reason, adopt: 'job', quarantineWorker: !['match', 'no-sample', 'reply-unmeasured', 'reference-unmeasured'].includes(reason) });
|
|
66
|
+
|
|
67
|
+
const record = (value: unknown): Record<string, unknown> | null =>
|
|
68
|
+
value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : null;
|
|
69
|
+
const named = (value: unknown): value is string => typeof value === 'string' && value.length > 0;
|
|
70
|
+
const finite = (value: unknown): value is number => typeof value === 'number' && Number.isFinite(value);
|
|
71
|
+
const nonnegativeInt = (value: unknown): value is number => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
|
|
72
|
+
|
|
73
|
+
/** Validate untrusted JSON before it can enter the shadow comparator. */
|
|
74
|
+
export function parseWarmWorkerReply(raw: unknown): WarmWorkerReply | null {
|
|
75
|
+
const reply = record(raw);
|
|
76
|
+
const key = record(reply?.key);
|
|
77
|
+
if (!reply || reply.protocol !== 1 || !named(reply.runId) || !named(reply.attemptId) || !named(reply.cutSha)
|
|
78
|
+
|| !named(reply.leaseId) || !named(reply.workerId) || !named(reply.envProfile)
|
|
79
|
+
|| !nonnegativeInt(reply.generation) || reply.generation < 1
|
|
80
|
+
|| !finite(reply.startedAt) || !finite(reply.finishedAt)
|
|
81
|
+
|| !key || !named(key.context) || !named(key.imageDigest) || !named(key.lockHash) || !named(key.architecture)
|
|
82
|
+
|| !Array.isArray(reply.files) || reply.files.some((part: unknown) => {
|
|
83
|
+
const item = record(part);
|
|
84
|
+
return !item || !named(item.file) || !nonnegativeInt(item.rc)
|
|
85
|
+
|| typeof item.junitComplete !== 'boolean'
|
|
86
|
+
|| !Array.isArray(item.failureIds) || !item.failureIds.every(named)
|
|
87
|
+
|| !Array.isArray(item.errorIds) || !item.errorIds.every(named);
|
|
88
|
+
}) || (reply.baselineSha !== undefined && !named(reply.baselineSha))) return null;
|
|
89
|
+
return raw as WarmWorkerReply;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function fileMap(files: readonly WarmWorkerFileResult[], expected: readonly string[]): Map<string, WarmWorkerFileResult> | null {
|
|
93
|
+
if (!Array.isArray(files) || !Array.isArray(expected) || files.length !== expected.length
|
|
94
|
+
|| expected.some((file) => !named(file)) || new Set(expected).size !== expected.length) return null;
|
|
95
|
+
const wanted = new Set(expected);
|
|
96
|
+
const map = new Map<string, WarmWorkerFileResult>();
|
|
97
|
+
for (const part of files) {
|
|
98
|
+
if (!part || !named(part.file) || !wanted.has(part.file) || map.has(part.file)) return null;
|
|
99
|
+
map.set(part.file, part);
|
|
100
|
+
}
|
|
101
|
+
return map;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function validPart(part: WarmWorkerFileResult): boolean {
|
|
105
|
+
const prefix = `${part.file} > `;
|
|
106
|
+
const namedId = (id: unknown) => typeof id === 'string' && id.startsWith(prefix) && id.slice(prefix.length).trim().length > 0;
|
|
107
|
+
const namedErrorId = (id: unknown) => typeof id === 'string' && id.startsWith(`${prefix}[error] `)
|
|
108
|
+
&& id.slice(`${prefix}[error] `.length).trim().length > 0;
|
|
109
|
+
return Number.isSafeInteger(part.rc) && part.rc >= 0 && part.junitComplete === true
|
|
110
|
+
&& Array.isArray(part.failureIds) && part.failureIds.every(namedId)
|
|
111
|
+
&& new Set(part.failureIds).size === part.failureIds.length
|
|
112
|
+
&& Array.isArray(part.errorIds) && part.errorIds.every(namedErrorId)
|
|
113
|
+
&& new Set(part.errorIds).size === part.errorIds.length
|
|
114
|
+
&& new Set([...part.failureIds, ...part.errorIds]).size === part.failureIds.length + part.errorIds.length
|
|
115
|
+
&& (part.rc === 0 ? part.failureIds.length + part.errorIds.length === 0 : part.failureIds.length + part.errorIds.length > 0);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function sameIds(left: readonly string[], right: readonly string[]): boolean {
|
|
119
|
+
if (new Set(left).size !== left.length || new Set(right).size !== right.length || left.length !== right.length) return false;
|
|
120
|
+
const orderedRight = [...right].sort();
|
|
121
|
+
return [...left].sort().every((id, index) => id === orderedRight[index]);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Fail closed on a stale generation, missing artifact, changed file set, or changed `rc + failure IDs`. */
|
|
125
|
+
export function assessWarmWorkerShadow(command: WarmWorkerCommand, job: readonly WarmWorkerFileResult[], rawReply: unknown): WarmShadowDecision {
|
|
126
|
+
if (!Array.isArray(command.files) || !command.files.length) return decision('no-sample');
|
|
127
|
+
const reference = fileMap(job, command.files);
|
|
128
|
+
if (!reference) return decision('reference-unmeasured');
|
|
129
|
+
// Validate the whole authoritative sample before attributing anything to the worker.
|
|
130
|
+
for (const file of command.files) if (!validPart(reference.get(file)!)) return decision('reference-unmeasured');
|
|
131
|
+
if (rawReply === null || rawReply === undefined) return decision('reply-unmeasured');
|
|
132
|
+
const reply = parseWarmWorkerReply(rawReply);
|
|
133
|
+
if (!reply) return decision('invalid-reply');
|
|
134
|
+
if (command.protocol !== 1 || reply.protocol !== 1 || !command.runId || !command.attemptId || !command.cutSha || !command.leaseId || !command.workerId
|
|
135
|
+
|| !Number.isSafeInteger(command.generation) || command.generation < 1
|
|
136
|
+
|| !Number.isFinite(command.deadlineAt)
|
|
137
|
+
|| command.runId !== reply.runId || command.attemptId !== reply.attemptId || command.cutSha !== reply.cutSha
|
|
138
|
+
|| command.baselineSha !== reply.baselineSha || command.envProfile !== reply.envProfile
|
|
139
|
+
|| command.leaseId !== reply.leaseId || command.generation !== reply.generation || command.workerId !== reply.workerId
|
|
140
|
+
|| !command.key || command.key.context !== reply.key?.context || command.key.imageDigest !== reply.key?.imageDigest
|
|
141
|
+
|| command.key.lockHash !== reply.key?.lockHash || command.key.architecture !== reply.key?.architecture
|
|
142
|
+
|| !Number.isFinite(reply.startedAt) || !Number.isFinite(reply.finishedAt) || reply.finishedAt < reply.startedAt
|
|
143
|
+
|| reply.finishedAt > command.deadlineAt) return decision('identity');
|
|
144
|
+
const candidate = fileMap(reply.files, command.files);
|
|
145
|
+
if (!candidate) return decision('file-set');
|
|
146
|
+
for (const file of command.files) if (!validPart(candidate.get(file)!)) return decision('missing-artifact');
|
|
147
|
+
for (const file of command.files) {
|
|
148
|
+
const before = reference.get(file)!;
|
|
149
|
+
const after = candidate.get(file)!;
|
|
150
|
+
if (before.rc !== after.rc || !sameIds(before.failureIds, after.failureIds) || !sameIds(before.errorIds, after.errorIds)) return decision('result');
|
|
151
|
+
}
|
|
152
|
+
return decision('match');
|
|
153
|
+
}
|