elanous 0.2.41 → 0.2.43
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/{GiOLWmt4MqDZePubBjA4Q → Om5xS9jpjSXJCeTNGYEi4}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{2fe2c302.41b517f88d6fe502.js → 0966f8a1.745fcd44f64a87ea.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{385e4574.e9886ab32759eda3.js → 0ad6802e.ae7afb63fdcb4491.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/114.2b90424d1a3ce84c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1151-5c2bb8f002ca2dd6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1200.6a37c202f9f17e9a.js +226 -0
- package/apps/pwa/out/_next/static/chunks/1261-a616d5728e02e624.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1313-19f737e0222c4444.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1357.3bbef3976c37f94a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1362-20adddfaf662b0fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6874.d5cf7eb8edb2cabe.js → 1406.a1dc2ab6f8449374.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1737-9491fc6ab29b9ec6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1803-4f91a8e7dcaf042c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5744.b9415e18ad623100.js → 1961.a81b12872c3e93a9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1970cf59.2d4d8ce5d6c81853.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1971-8890f3962ba7ee0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2073-ba274e00e4f9efb4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5471.1e611302ed3a7c53.js → 2144.25b292396712196d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{3230-49298c3b73ef2268.js → 2268-53861f339e0b65a2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9834.63ab2bbc3153172e.js → 2312.0c8b61e22d3136d7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1800.f7ff51dc4978a958.js → 2573.387a707f6f9d720c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/273.f156eee28f11af77.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2873.d2140e5a82546401.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9048.212083de42d25be3.js → 3072.01338851ca21a6f7.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3091.a5a4143dea33d197.js +90 -0
- package/apps/pwa/out/_next/static/chunks/3095.dc44586a5f83b86d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2263.e09b6edea33bad2d.js → 3113.d7472bbc27d580c7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3228-9650b6447b6fa288.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3402.44b565b314f2263c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{addc2b32.8c4ff8f0aefe987d.js → 3557ac4a.c8931684475018ad.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/360.ae9f9f4c33c395e8.js +79 -0
- package/apps/pwa/out/_next/static/chunks/3638.80412ea63aae8f3f.js +286 -0
- package/apps/pwa/out/_next/static/chunks/{a0a01613.6d1cca322238d7fe.js → 363bfab3.9623b9f89363541f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3694.e0099884345f0198.js +64 -0
- package/apps/pwa/out/_next/static/chunks/3744.54f87db52acfd1ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3903.3ef4656c67572764.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3935.16701e33f8982dc9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3955.6922286237f2ac2b.js +24 -0
- package/apps/pwa/out/_next/static/chunks/3969.272ee7f9fd6c62e5.js +34 -0
- package/apps/pwa/out/_next/static/chunks/4199.ce86b281fd0a60b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4311-6dd3144002cc0c2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4426-2b230fad00c88930.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{530.d26346e18089640a.js → 4445.7990c76b3751a918.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4447-14c5161fa59166c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4856-b0b8075bba8c53f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4870-de370d65e73c0bb5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4885-2c989165c4b29fad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4894.fec2ca9e99caefa2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5093.8f04b7f8cb899a95.js +94 -0
- package/apps/pwa/out/_next/static/chunks/5122-2bb177cebf89e19a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5154.5f56dc3902e3d275.js +36 -0
- package/apps/pwa/out/_next/static/chunks/529.64ff7257180b2ac9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5394.5dabeb0c62293a28.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5461.08bf2404ff38ec85.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5474-22e08a85583209b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1219.7e17964e0e7cd8e5.js → 5564.9e72532188f57586.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/5567-265df39ed8fe9dcb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5570-a94ae19811cb2046.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5574-b47c9ef2dceff1fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5628.6ddb2d5ffba4ff4c.js +309 -0
- package/apps/pwa/out/_next/static/chunks/5730.43d7ccc09988e646.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1178.1aa9cad0e7695427.js → 5789.2da35c258292e1e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4133.2056bb4d78f621af.js → 5824.da9527b15a3221e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5866.366966af47fdde5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4527.a69f2894d1bc9f4a.js → 5930.8b4df3b46c32b05a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5963-c4d8469c52a0828b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6001.ec4049ceb3c43418.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6120-471f03db1e299c0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6175-41479e643aca1878.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6291.a2de4f9787637075.js +104 -0
- package/apps/pwa/out/_next/static/chunks/6400-6699907c3537436a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6428.1f4327d6ae5fdf9a.js +287 -0
- package/apps/pwa/out/_next/static/chunks/644.02cb026fa44bcd0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6466-6c87d60d3dd174fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9507.7026657a2f47eb64.js → 6540.c7bef57ad8f90a87.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/6773.d4264665ab31bec0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6822.3c789f1a8443e774.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5574.f35accf4f132b29d.js → 6944.309f4e3ea54d1537.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7261-8ff69d3b2ee671fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7266.084c6bbc70035140.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7271.5c0100e7320aa856.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7429-bf5731358c8f2f68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7464.01f7a0ae1215fbe7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7479.0fcad5f37eb64f0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7483.427a2fe2049e388d.js +148 -0
- package/apps/pwa/out/_next/static/chunks/7502-be74718178e13e56.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7530.0889722b19572065.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7645.5b2ee3ad45c55ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7788.7d1c79f1a8e18946.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7900.096f455c7c1efc53.js +77 -0
- package/apps/pwa/out/_next/static/chunks/7910-6f139bcafd238b9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7966.f71c8958d1637548.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5947-135e26537d80a6b9.js → 8062-7cd0bcc7f01455ba.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/8073.f6cf2f2c71aafbd0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8201.190b94088980f430.js +74 -0
- package/apps/pwa/out/_next/static/chunks/8205.282ca4bb62d54a0a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/8313-dfa1021bb58a46d6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/837-81336ebaca8198a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8447.7963352ef5f71b76.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8574-868e8129525ef6d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8588.d1c6a2903727ce87.js +149 -0
- package/apps/pwa/out/_next/static/chunks/8637.90f92d5c8db4732c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2743.5d3f76948be32b34.js → 868.6e953be05bcf6dca.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/8706-e1fe0309343a2273.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8749-06384cdfc4520add.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5964-7e21164a8f2cf0ce.js → 8861-cc1fa1c7b920fa8e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8967-7dfebf710c9dec9d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5159.115f1c2ca471386c.js → 8986.8e2e4efbfa655c59.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8997-3c564dbb3b58b055.js +1 -0
- package/apps/pwa/out/_next/static/chunks/923.2034d10ae91e9c20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9312.bc1b89c5d4368033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/943.39ae5e82f4f1893f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9469.0500480de55fb205.js +32 -0
- package/apps/pwa/out/_next/static/chunks/9770.5f75bc6088b16109.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9810-2543267050e58b82.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9870.8419702475254745.js +8 -0
- package/apps/pwa/out/_next/static/chunks/9941-376d1b74d51b01a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9958.385434ab04241758.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b2271e54.c1de3347976e90b0.js → aa57532f.510551854ff239b1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-deea1450b17cb8dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-70985b904f8650ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a2e15e33e56a4353.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-fc72ce2db12d6ca9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-be03e41f9436ebd9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-35a35999382da3f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-3ff5b1e6ca88b848.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-a65101300a0ee5c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-3aca5b6d67dba511.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-45b8ab0a71e61314.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-53046e282d4cda8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-17809e60e8354c17.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-fd2442d347bf5898.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-e9d720d6fc082e21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-6b8b4267bab0a677.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-deea1450b17cb8dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-8bcf6233ac7c17af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-7cc25591cfc2126f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-053e871f35c9beba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-eff819f0c2d5e084.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-4d7e9d8db5274a87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-2b2d8f5aa5f69ad4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-0b8f92c5062e68b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1bd9d0fdac2ced3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-9ee28f7df07428ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-44b7a1ff468c6648.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-cbc6523711dc1b65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-fdad47899c2695be.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-40f9e19149024298.js → page-79a8b5fee4c20871.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-03e8ac9606aeaffb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-4cd55c55ec287e2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-db17b4305404161e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-30041d848350fd02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c540da022dbf86b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9399efc538da057f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-a142dfb0331a05f5.js → page-ca2d09128c585ca4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0e2635aecd343038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ef7f4399b6b7726e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-deea1450b17cb8dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-caf530535b875468.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-eaa20c1543a5fd8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c541eb1b75120f61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-ab5e213eda9479f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-0a815f34367b6db6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-e858ba0ed9393b68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-1638ee9dd6e0582f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4cf5a399109391f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b4396321238798ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-cb72bfd21006781a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6135d0242afbc434.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a1dccf907eddb856.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{53aeb4ee-51c92f8d683f5220.js → c7945435-b44d4dbe90ba0dcb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2fdf2931.b431eee4fb468bc3.js → cb0f8df8.09a4a6be97e3fc5f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{c0c1a699.0ba79f97005965d4.js → d96660fb.cbc21a2a88539dbb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/ea514caa.05a24f78d9dffe5f.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{83184dcd-0ee6247ff41eb3f2.js → fb7d20d5-6892502b6ee39ca6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-e8a911e19b1be41f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-7022f418fabba021.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-e5f15df755756a1e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-4525f91e36940c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-140f0e519c085b0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-8f22ef63dcb865b1.js +1 -0
- package/apps/pwa/out/_next/static/css/{b9d8151e48998417.css → 62c858ad53854f47.css} +1 -1
- package/apps/pwa/out/_next/static/css/d1f8bb401740a549.css +1 -0
- 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 +24 -25
- 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 +23 -23
- 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 +24 -25
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +24 -25
- 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/catalog/external-commands.yaml +5 -3
- package/catalog/meta/catalogVersion.yaml +2 -1
- package/catalog/signing/catalog-signing-public.pem +3 -0
- package/docs/goal-context/04-mock-scenarios.md +13 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/heal/heal-loop.yaml +1 -0
- package/graphs/intake/intake-daily.yaml +16 -0
- package/graphs/intake/news-sources.yaml +1 -0
- package/graphs/intake/recipes.yaml +7 -0
- package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
- package/graphs/overlays/stop-heal-ladder.yaml +113 -0
- package/graphs/profiles/local.yaml +5 -0
- package/graphs/profiles/pod.yaml +4 -0
- package/graphs/units/verbs/recipes.yaml +11 -11
- package/graphs/work/research-report.yaml +10 -2
- package/package.json +6 -2
- package/plugins/demo-absorption-briefing/plugin.json +18 -0
- package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
- package/plugins/demo-browser-hand/plugin.json +13 -0
- package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
- package/plugins/demo-linear-secretary/plugin.json +15 -0
- package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
- package/plugins/demo-plugin-wizard/plugin.json +11 -0
- package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
- package/plugins/demo-research/plugin.json +16 -0
- package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
- package/plugins/demo-video-briefing/plugin.json +15 -0
- package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
- package/scripts/build-signed-catalog.ts +48 -0
- package/scripts/ci-typecheck-main-delta.sh +88 -0
- package/scripts/codex-fallback-live-probe.ts +1 -1
- package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
- package/scripts/demo/demo1104-stage.config.ts +21 -0
- package/scripts/demo/demo1104-stage.ts +316 -0
- package/scripts/goal-method-audit.ts +17 -1
- package/scripts/graph-units/land-enqueue.ts +90 -0
- package/scripts/heal/run-role.ts +99 -5
- package/scripts/hooks/codex-notify.sh +32 -0
- package/scripts/install.sh +10 -38
- package/scripts/land-global-checks.ts +6 -1
- package/scripts/landing-heal/land-plan.ts +57 -0
- package/scripts/lib/decompose-ab.ts +1 -0
- package/scripts/lib/fixtures/tui-regress/help-insufficient-commands.txt +15 -0
- package/scripts/lib/fixtures/tui-regress/help-live.txt +42 -0
- package/scripts/lib/fixtures/tui-regress/help-missing-keys.txt +21 -0
- package/scripts/lib/fixtures/tui-regress/help-original.txt +51 -0
- package/scripts/lib/fixtures/tui-regress/help-shifted-input.txt +26 -0
- package/scripts/lib/tui-regress-checks.ts +33 -13
- package/scripts/release-loop/auto-approve-node.ts +1 -1
- package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
- package/scripts/release-loop/gate-baseline-receipt.ts +47 -9
- package/scripts/release-loop/gate-image-pin.ts +81 -0
- package/scripts/release-loop/gate-method.ts +139 -0
- package/scripts/release-loop/gate-node-sim.ts +207 -0
- package/scripts/release-loop/gate-node.ts +463 -64
- package/scripts/release-loop/gate-pod-image-sticky-plan.ts +99 -0
- package/scripts/release-loop/gate-radius-live.ts +97 -13
- package/scripts/release-loop/gate-shard-dispatch.ts +43 -0
- package/scripts/release-loop/gate-traffic-mode.ts +151 -3
- package/scripts/release-loop/gate-train-receipts.ts +122 -0
- package/scripts/release-loop/node-verdict.ts +38 -25
- package/scripts/release-loop/preflight.ts +362 -8
- package/scripts/release-loop/resume-release.ts +83 -8
- package/scripts/release-loop/unattended-release.ts +20 -9
- package/scripts/rhythm/daily.ts +36 -4
- package/scripts/rhythm/linear-progress-sync.ts +298 -0
- package/scripts/ux-sim.ts +18 -1
- package/scripts/video-pipeline.ts +9 -1
- package/scripts/warm-pool-provider-config.ts +286 -0
- package/skills/omni-crawl/SKILL.md +5 -2
- package/skills/omni-crawl/scripts/main.ts +84 -23
- package/src/acp/agent-manager.ts +1 -0
- package/src/acp/codex-app-server-agent.ts +33 -0
- package/src/acp/codex-app-server-client.ts +153 -16
- package/src/acp/core-turn-bridge.ts +27 -9
- package/src/acp/event-router.ts +20 -1
- package/src/acp/server.ts +6 -0
- package/src/agent/registry.ts +2 -0
- package/src/agent/task-notification.ts +25 -5
- package/src/agent/types.ts +6 -0
- package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
- package/src/agent-mission/claude-headless.ts +4 -1
- package/src/agent-mission/codex-exec.ts +105 -0
- package/src/agent-mission/driver.ts +192 -11
- package/src/agent-mission/grok-auth-status.ts +47 -0
- package/src/agent-mission/hand-hooks.ts +101 -0
- package/src/agent-mission/mission-cli.ts +63 -4
- package/src/agent-mission/mission-hand-reply.ts +118 -0
- package/src/agent-mission/mission-line.ts +180 -0
- package/src/agent-mission/mission-out.ts +833 -0
- package/src/agent-mission/tool-install.ts +200 -3
- package/src/agent-substrate/context-strategy.ts +4 -4
- package/src/agent-substrate/self-review-cli.ts +178 -13
- package/src/agents/general-purpose.md +1 -1
- package/src/auto-research/research-turn.ts +211 -53
- package/src/autopilot/pr-manager.ts +69 -10
- package/src/autopilot/pty-control-loop.ts +2 -0
- package/src/boot/daemon-tools/self-implement.ts +3 -1
- package/src/boot/daemon-tools/web-search.ts +1 -2
- package/src/briefing/brief-items.ts +55 -11
- package/src/capture/tui-self-report.ts +22 -6
- package/src/chat/index.ts +1 -1
- package/src/cli/agent-cli.ts +2 -1
- package/src/cli/catalog-cli.ts +31 -0
- package/src/cli/connector-cli.ts +16 -0
- package/src/cli/doctor-fix.ts +2 -2
- package/src/cli/fixtures/review-loop-breaker/opwaiver-32646-1694ccc7a170.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/opwaiver-32853-bd8f73595c83.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/opwaiver-33097-1cc85900413c.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/opwaiver-33106-972f31e4a3ca.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/opwaiver-33113-3ab51f05968f.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/pr-33097-1cc85900413c.json +1 -0
- package/src/cli/intake-source-cli.ts +44 -8
- package/src/cli/msg-cli.ts +32 -3
- package/src/cli/pr-cli.ts +21 -1
- package/src/cli/pr-land-heavy-remote.ts +75 -5
- package/src/cli/pr-land-overlap-evidence.ts +113 -2
- package/src/cli/pr-land-pod-shadow-job.ts +202 -4
- package/src/cli/pr-land-pod-shadow.ts +9 -2
- package/src/cli/release-checklist-read-cli.ts +57 -19
- package/src/cli/release-cli.ts +23 -3
- package/src/cli/research-cli.ts +13 -5
- package/src/cli/setup-cli.ts +166 -6
- package/src/cli/setup-keys.ts +187 -0
- package/src/cli/task-plugin-wizard-host.ts +114 -0
- package/src/cli/tasks-cli.ts +61 -9
- package/src/cli/tui-test-cli.ts +186 -0
- package/src/compact/auto.ts +8 -1
- package/src/config.ts +4 -2
- package/src/connectors/linear-daily-progress.ts +228 -0
- package/src/connectors/linear-projector.ts +34 -12
- package/src/connectors/linear.ts +151 -7
- package/src/control-plane/ledger.ts +52 -2
- package/src/control-plane/server.ts +16 -2
- package/src/core-turn/deep-turn-bloom.ts +67 -0
- package/src/core-turn/research-policy.ts +37 -0
- package/src/core-turn/run-core-turn.ts +606 -95
- package/src/core-turn/run-goal-loop.ts +18 -0
- package/src/core-turn/types.ts +4 -0
- package/src/dashboard/chat/acp-chat.ts +10 -0
- package/src/dashboard/classic-sidetab-mission-job.ts +161 -0
- package/src/dashboard/classic-sidetab-mission-pair.ts +81 -0
- package/src/dashboard/classic-sidetab-mission-trio.ts +219 -0
- package/src/dashboard/classic-sidetab-mission.ts +347 -0
- package/src/dashboard/index.ts +517 -18
- package/src/dashboard/input/agent-wake.ts +23 -1
- package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +17 -0
- package/src/dashboard/mission-cli-consumer.ts +165 -0
- package/src/dashboard/plugin-wizard-runtime.ts +50 -0
- package/src/dashboard/plugin-wizard-tool.ts +55 -0
- package/src/dashboard/seat-boot-preamble.ts +171 -1
- package/src/dashboard/side-basic-runtime.ts +54 -1
- package/src/dashboard/sidetab-runtime.ts +90 -1
- package/src/dashboard/skill-catalog-preamble.ts +101 -0
- package/src/dashboard/skill-detection-runtime.ts +55 -15
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +15 -0
- package/src/dashboard/terminal-popup-runtime.ts +6 -3
- package/src/dashboard/turn-preamble.ts +53 -15
- package/src/dashboard/turn-prompt-runtime.ts +4 -2
- package/src/decisions/linear-progress-summary.ts +78 -0
- package/src/decisions/linear-progress-sync.ts +152 -0
- package/src/domains/outbound-alert.ts +49 -11
- package/src/domains/telegram-kind-route.ts +16 -9
- package/src/graph-runner/arg-allowance.ts +13 -0
- package/src/graph-runner/graph-cli.ts +23 -7
- package/src/graph-runner/graph-run-api.ts +3 -1
- package/src/graph-runner/graph-tick.ts +10 -2
- package/src/graph-runner/runner.ts +86 -18
- package/src/graph-wizard/mission-compose.ts +407 -12
- package/src/grok/agent-search.ts +14 -4
- package/src/grok/credential.ts +28 -11
- package/src/harness/dispatch-backpressure.ts +54 -1
- package/src/harness/dispatch-shadow-compare.ts +74 -0
- package/src/harness/harness-cli-command.ts +11 -1
- package/src/harness/harness-pod-dispatch.ts +81 -15
- package/src/harness/harness-stop.ts +155 -11
- package/src/harness/skill-exec.ts +21 -9
- package/src/harness/skill-select.ts +1 -1
- package/src/hooks/error-report-cloud.ts +101 -0
- package/src/hooks/receiver.ts +29 -2
- package/src/index.ts +159 -13
- package/src/instance/spawn-elanous.ts +6 -4
- package/src/intake-plane/actions.ts +354 -0
- package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
- package/src/intake-plane/intake-sources.ts +78 -8
- package/src/intake-plane/items.ts +14 -4
- package/src/intake-plane/linear-mission-sync.ts +80 -0
- package/src/intake-plane/linear-secretary-runtime.ts +178 -0
- package/src/intake-plane/linear-wish.ts +227 -1
- package/src/life/life-cli.ts +168 -0
- package/src/life/life-kinds.ts +160 -0
- package/src/live-supply/budget-consumer.ts +78 -0
- package/src/live-supply/read.ts +3 -0
- package/src/live-supply/snapshot.ts +45 -0
- package/src/llm/provider-credentials.ts +8 -2
- package/src/llm.ts +168 -9
- package/src/loops/orchestrator/coordinator-shadow.ts +226 -0
- package/src/loops/orchestrator/tick.ts +13 -0
- package/src/maturity/feature-maturity.ts +4 -4
- package/src/msg/msg-sse-server.ts +3 -3
- package/src/msg/msg-store.ts +177 -19
- package/src/native-tool-catalog.ts +38 -4
- package/src/nexus/api/harness-traversal.ts +11 -0
- package/src/nexus/api/http-server.ts +37 -1
- package/src/nexus/api/mcp-public-allowlist.ts +2 -0
- package/src/nexus/index.ts +7 -2
- package/src/nexus/outbound/format.ts +9 -0
- package/src/nexus/outbound/router.ts +98 -13
- package/src/nexus/setup-status.ts +9 -0
- package/src/nexus/state/state.ts +3 -0
- package/src/oauth/codex-account-store.ts +20 -7
- package/src/oauth/codex-owner-mirror.ts +44 -0
- package/src/oauth/codex.ts +17 -2
- package/src/oauth/fallback-chain.ts +47 -17
- package/src/onboarding/first-run-doctor.ts +8 -1
- package/src/onboarding/first-run.ts +85 -26
- package/src/onboarding/key-setup.ts +103 -0
- package/src/onboarding/menu-answer.ts +13 -0
- package/src/onboarding/secret-prompt.ts +37 -0
- package/src/plugins/install/plugin-install.ts +59 -0
- package/src/pr-tool/census.ts +133 -2
- package/src/pty-shell/pty-control-ipc.ts +4 -1
- package/src/pty-shell/tui-run-state.ts +188 -2
- package/src/registry/catalog-server.ts +232 -0
- package/src/registry/loader.ts +45 -1
- package/src/registry/types.ts +1 -2
- package/src/release-loop/checklist-target-path-hint.ts +13 -0
- package/src/release-loop/checklist.ts +9 -1
- package/src/repl/index.ts +43 -2
- package/src/research/axis-fanout.ts +136 -16
- package/src/research/bloom-exemplars.ts +3 -1
- package/src/research/gap-followup.ts +13 -1
- package/src/research/plugin-discovery.ts +36 -14
- package/src/research-bridge/invoke.ts +22 -5
- package/src/research-bridge/types.ts +2 -0
- package/src/self-dev/ask-launch-flow.ts +72 -1
- package/src/self-dev/decompose.ts +119 -5
- package/src/self-dev/dev-cli.ts +4 -1
- package/src/self-dev/dev-pipeline.ts +5 -0
- package/src/self-dev/draft-residue.ts +64 -5
- package/src/self-dev/graph-front-nodes.ts +2 -1
- package/src/self-dev/graph-journey-route.ts +76 -21
- package/src/self-dev/launch-preflight-text.ts +5 -6
- package/src/self-dev/launch-preflight.ts +58 -0
- package/src/self-dev/orchestrate.ts +13 -3
- package/src/self-dev/review-provider-fallback.ts +9 -2
- package/src/self-dev/run-supervisor.ts +42 -4
- package/src/self-dev/run-types.ts +4 -0
- package/src/self-dev/shard-aggregate.ts +4 -0
- package/src/self-dev/shard-run.ts +36 -15
- package/src/self-implement/abandoned-classification.ts +12 -3
- package/src/self-implement/budget-gate.ts +7 -0
- package/src/self-implement/child-llm-preference.ts +10 -1
- package/src/self-implement/doctor-visit.ts +118 -8
- package/src/self-implement/elanous-tui-spawn.ts +3 -0
- package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
- package/src/self-implement/gate-artifacts.ts +2 -1
- package/src/self-implement/goal-author-cli.ts +4 -2
- package/src/self-implement/goal-author.ts +684 -7
- package/src/self-implement/graph-overlay-yaml.ts +37 -4
- package/src/self-implement/graph-overlay.ts +3 -1
- package/src/self-implement/graph-profile-yaml.ts +107 -0
- package/src/self-implement/graph-yaml.ts +26 -3
- package/src/self-implement/headless-elanous-driver.ts +31 -2
- package/src/self-implement/heal-intake.ts +112 -4
- package/src/self-implement/heal-triage.ts +20 -0
- package/src/self-implement/host-regate.ts +27 -4
- package/src/self-implement/merge-train.ts +5 -0
- package/src/self-implement/off-diff-evidence.ts +249 -5
- package/src/self-implement/orchestrator.ts +365 -25
- package/src/self-implement/regate-detail.ts +38 -1
- package/src/self-implement/rework-child-provider.ts +25 -0
- package/src/self-implement/run-chart.ts +122 -0
- package/src/self-implement/run-ledger.ts +162 -11
- package/src/self-implement/run-stop.ts +188 -4
- package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
- package/src/self-implement/stop-autoheal.ts +13 -0
- package/src/self-implement/tdd-evidence-tags.ts +9 -0
- package/src/self-implement/train-gate-receipt.ts +166 -0
- package/src/self-implement/train-gate-remote.ts +62 -18
- package/src/session/chat.ts +40 -4
- package/src/session/session-fanout.ts +2 -0
- package/src/session/streaming/acp-stream-sink.ts +2 -1
- package/src/session/streaming/chunk-producer.ts +6 -0
- package/src/session/streaming/stream-compositor.ts +3 -2
- package/src/session-runtime/index.ts +135 -5
- package/src/session-runtime/retry-policy.ts +1 -1
- package/src/session-runtime/tier-flip.ts +3 -3
- package/src/setup/llm-env-detect.ts +3 -0
- package/src/setup/service-key-catalog.ts +46 -0
- package/src/setup/service-keys.ts +241 -0
- package/src/sidetab-core/model.ts +19 -5
- package/src/sidetab-core/visible-agent-mission.ts +262 -0
- package/src/skills/name-match.ts +20 -0
- package/src/skills/tools/agent.ts +53 -6
- package/src/skills/tools/omni-search.ts +173 -13
- package/src/task-agent/parent-host.ts +10 -0
- package/src/task-agent/pod-distributor-entry.ts +3 -0
- package/src/task-agent/repair-outcomes.ts +65 -0
- package/src/task-agent/task-hand.ts +47 -7
- package/src/task-orchestrator/dispatcher.ts +14 -1
- package/src/task-orchestrator/linear-capture-events.ts +55 -0
- package/src/task-orchestrator/store.ts +16 -5
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-distributor.ts +48 -0
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +92 -1
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +38 -1
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
- package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +33 -6
- package/src/task-orchestrator/surfaces/pod-source-bundle.ts +45 -9
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +178 -16
- package/src/task-orchestrator/surfaces/pod-source-spec.ts +3 -3
- package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +237 -41
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +80 -3
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +337 -51
- package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
- package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
- package/src/task-orchestrator/types.ts +14 -0
- package/src/telegram.ts +14 -16
- package/src/terminal/coding-agent.ts +14 -5
- package/src/terminal/session-registry.ts +1 -1
- package/src/tokens.ts +35 -2
- package/src/tool-hints/gate.ts +1 -0
- package/src/tool-runtime/agent-runtime.ts +2 -0
- package/src/tool-runtime/browser-hand-runtime.ts +381 -0
- package/src/tool-runtime/browser-runtime.ts +2 -1
- package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
- package/src/tool-runtime/elanous-linear-secretary-runtime.ts +57 -0
- package/src/tool-runtime/elanous-skills-list-runtime.ts +5 -1
- package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
- package/src/tool-runtime/index.ts +6 -0
- package/src/tool-runtime/skill-exec-runtime.ts +33 -13
- package/src/tool-runtime/types.ts +4 -0
- package/src/tui/entry.ts +38 -5
- package/src/tui/sidetab/attach.ts +177 -1
- package/src/tui/sidetab/herdr-portal.ts +225 -0
- package/src/tui-client/local-chat-turn.ts +26 -13
- package/src/tui.ts +22 -0
- package/src/user-config.ts +34 -9
- package/src/user-intent/types.ts +4 -3
- package/src/ux-sim/browser-hand.ts +165 -0
- package/src/ux-sim/draft-inventory-builder.ts +198 -0
- package/src/ux-sim/fake-browser-page.ts +81 -0
- package/src/ux-sim/fake-kubectl.ts +37 -3
- package/src/ux-sim/fake-linear-device.ts +31 -0
- package/src/ux-sim/fault-pool-cap.ts +11 -6
- package/src/ux-sim/graph-engine-sim.ts +47 -0
- package/src/ux-sim/linear-secretary.ts +216 -0
- package/src/ux-sim/mock-scenario-catalog.json +93 -0
- package/src/ux-sim/mock-scenario-catalog.ts +274 -0
- package/src/ux-sim/onboarding-first-run-device.ts +31 -21
- package/src/ux-sim/scenario.ts +185 -48
- package/src/ux-sim/service-key-setup.ts +50 -0
- package/src/ux-sim/term-slash-device.ts +74 -0
- package/src/ux-sim/turn-throw-sim.ts +31 -0
- package/src/version/packed-revision.json +1 -1
- package/src/voice/voice-tts-singleton.ts +18 -3
- package/src/web-search/exa.ts +77 -0
- package/src/web-search/grok.ts +5 -9
- package/src/web-search/index.ts +30 -9
- package/src/web-search/provider.ts +4 -1
- package/src/web-search/x-intent.ts +5 -0
- package/apps/pwa/out/_next/static/chunks/1115.434ae2ecb0ad986d.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +0 -36
- package/apps/pwa/out/_next/static/chunks/1197-54da59d250a6e476.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +0 -287
- package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1661.0dd330f3d89f73f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +0 -90
- package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1765.679b29625c8e88d4.js +0 -77
- package/apps/pwa/out/_next/static/chunks/1971-7efb628c471dc5a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2073.689dcb2680113d76.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +0 -1
- package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2527-5c636a43c7cc5dde.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2773.0e80b9d325fb5635.js +0 -32
- package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3097.864e92bdaa2f4d15.js +0 -79
- package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4156.ba4de4a3664f04b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +0 -148
- package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +0 -226
- package/apps/pwa/out/_next/static/chunks/4667.97e31aa38c95c475.js +0 -309
- package/apps/pwa/out/_next/static/chunks/4702.4a4adc1f16d7c93b.js +0 -64
- package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +0 -94
- package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +0 -8
- package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +0 -24
- package/apps/pwa/out/_next/static/chunks/5892.2526d962339662d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5937.c2df9e3447e1f667.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +0 -286
- package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +0 -27
- package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6552.a3840aa7da35ad68.js +0 -62
- package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +0 -122
- package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7191.fdc955f7d96064a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8050-9b364bdef8f71927.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +0 -104
- package/apps/pwa/out/_next/static/chunks/8464-e24f10451b658aac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8880.64c445592f04acaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8981.c706964c8ba27aff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9541.eb8e2f8480c7feca.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9579.4a8169600fff2058.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +0 -34
- package/apps/pwa/out/_next/static/chunks/9869.81a1e24ca682d5a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-14949db884bfa672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +0 -1
- package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +0 -1
- /package/apps/pwa/out/_next/static/{GiOLWmt4MqDZePubBjA4Q → Om5xS9jpjSXJCeTNGYEi4}/_ssgManifest.js +0 -0
|
@@ -18,6 +18,7 @@ import type { LogStore } from '../../mss/logging/log-store.js';
|
|
|
18
18
|
const POD_READY_WAIT_SECONDS = 900;
|
|
19
19
|
const POD_READY_RECHECK_SECONDS = 300;
|
|
20
20
|
const POD_READY_RETRY_DELAY_MS = 1_000;
|
|
21
|
+
const WARM_CONTROL_REQUEST_TIMEOUT_MS = 2_000;
|
|
21
22
|
|
|
22
23
|
function throwIfPrepareAborted(signal?: AbortSignal): void {
|
|
23
24
|
if (!signal?.aborted) return;
|
|
@@ -61,7 +62,9 @@ export interface WarmPodProviderOptions {
|
|
|
61
62
|
transport?: (spec: WarmPodSpec) => Pick<WarmPodTransport, 'request'>;
|
|
62
63
|
maxShadowMs?: number;
|
|
63
64
|
now?: () => number;
|
|
64
|
-
kubectl?: (args: readonly string[], input?: string) => {
|
|
65
|
+
kubectl?: (args: readonly string[], input?: string) => {
|
|
66
|
+
status: number | null; stdout: string; stderr: string; error?: NodeJS.ErrnoException;
|
|
67
|
+
};
|
|
65
68
|
/** Private directory for cross-process prepare leases; defaults to a per-user directory under tmpdir(). */
|
|
66
69
|
prepareLockDirectory?: string;
|
|
67
70
|
/** Cancels a prepare waiting for another process to finish the same host/worker slot. */
|
|
@@ -71,6 +74,11 @@ export interface WarmPodProviderOptions {
|
|
|
71
74
|
/** Gate file this pool serves, used to bind cold prepare legs to their 1-file gate measurement key. */
|
|
72
75
|
pairingGateFile?: string;
|
|
73
76
|
}
|
|
77
|
+
type WarmPodProviderRuntimeOverrides = Pick<WarmPodProviderOptions, 'fetch' | 'kubectl' | 'prepareLockDirectory'>;
|
|
78
|
+
export interface WarmPodProviderLoadOptions {
|
|
79
|
+
pairingGateFile?: string;
|
|
80
|
+
runtimeOverrides?: Partial<WarmPodProviderRuntimeOverrides>;
|
|
81
|
+
}
|
|
74
82
|
|
|
75
83
|
export interface WarmPoolReconcileResult {
|
|
76
84
|
profile: string;
|
|
@@ -293,6 +301,15 @@ export class WarmPodProvider {
|
|
|
293
301
|
return { status: response.status, value };
|
|
294
302
|
}
|
|
295
303
|
|
|
304
|
+
private async controlBounded(path: string, credential: string, body: Record<string, unknown>, timeoutMs: number): Promise<{ status: number; value: any }> {
|
|
305
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
306
|
+
try {
|
|
307
|
+
return await Promise.race([this.control(path, credential, body), new Promise<never>((_, reject) => {
|
|
308
|
+
timer = setTimeout(() => reject(new Error('warm control request timed out')), timeoutMs);
|
|
309
|
+
})]);
|
|
310
|
+
} finally { if (timer) clearTimeout(timer); }
|
|
311
|
+
}
|
|
312
|
+
|
|
296
313
|
/** The child owns kubectl. Timeout terminates only this child process group and fences its lease. */
|
|
297
314
|
private async runTransport(spec: WarmPodSpec, command: WarmWorkerCommand): Promise<WarmPodTransportResult> {
|
|
298
315
|
if (this.options.transport) return this.options.transport(spec).request(command);
|
|
@@ -416,7 +433,8 @@ export class WarmPodProvider {
|
|
|
416
433
|
const result = spawnSync('kubectl', argv, { encoding: 'utf8', input, env,
|
|
417
434
|
timeout: argv[4] === 'wait' ? (POD_READY_WAIT_SECONDS + 30) * 1000 : 360_000,
|
|
418
435
|
maxBuffer: 2 * 1024 * 1024 });
|
|
419
|
-
return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? ''
|
|
436
|
+
return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '',
|
|
437
|
+
error: result.error };
|
|
420
438
|
};
|
|
421
439
|
const parse = (result: { status: number | null; stdout: string }) => {
|
|
422
440
|
if (result.status !== 0) return null;
|
|
@@ -468,12 +486,60 @@ export class WarmPodProvider {
|
|
|
468
486
|
&& Object.entries(metadata.annotations).every(([key, value]) => pod.metadata.annotations?.[key] === value)
|
|
469
487
|
&& pod.spec?.nodeName === nodeName
|
|
470
488
|
&& sameSpec(normalizedSpec(pod.spec), template);
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
const
|
|
489
|
+
const skipDiscovery = (reason: string): false => {
|
|
490
|
+
debug.log('pod.warm', 'warm-pod-list-skipped', { reason }, { level: 'warn' });
|
|
491
|
+
return false;
|
|
492
|
+
};
|
|
493
|
+
const kubectlErrorCode = (error: unknown): string | undefined => {
|
|
494
|
+
if (!error || typeof error !== 'object' || !('code' in error)) return undefined;
|
|
495
|
+
return typeof error.code === 'string' ? error.code : undefined;
|
|
496
|
+
};
|
|
497
|
+
// Resolve the pinned Pod independently; namespace size must not affect this read.
|
|
498
|
+
let namedResult: ReturnType<typeof kubectl>;
|
|
499
|
+
try { namedResult = kubectl(['get', 'pods', `--field-selector=metadata.name=${spec.name}`, '-o', 'json']); }
|
|
500
|
+
catch (error) {
|
|
501
|
+
return skipDiscovery(kubectlErrorCode(error) === 'ENOBUFS' ? 'output-too-large' : 'kubectl-failed');
|
|
502
|
+
}
|
|
503
|
+
if (kubectlErrorCode(namedResult.error) === 'ENOBUFS') return skipDiscovery('output-too-large');
|
|
504
|
+
if (namedResult.status !== 0) return skipDiscovery('kubectl-failed');
|
|
505
|
+
const namedList = parse(namedResult);
|
|
506
|
+
if (!Array.isArray(namedList?.items) || !namedList.metadata || typeof namedList.metadata !== 'object'
|
|
507
|
+
|| Array.isArray(namedList.metadata)) return skipDiscovery('malformed-output');
|
|
508
|
+
const namedMatches = namedList.items.filter((row: any) => row?.metadata?.name === spec.name);
|
|
509
|
+
if (namedMatches.length > 1) return false;
|
|
510
|
+
const namedPod = namedMatches[0] ?? null;
|
|
511
|
+
|
|
512
|
+
// Kubectl's continuation token is consumed explicitly so no partial page can
|
|
513
|
+
// authorize a create. A hard page cap turns a non-terminating listing into failure.
|
|
514
|
+
const warmPods: any[] = [];
|
|
515
|
+
let continuation = '';
|
|
516
|
+
const seenContinuations = new Set<string>();
|
|
517
|
+
let completedPages = false;
|
|
518
|
+
for (let page = 0; page < 100; page++) {
|
|
519
|
+
const args = ['get', 'pods', '-l', 'elanous.kind=warm-worker', '--chunk-size=50', '-o', 'json'];
|
|
520
|
+
if (continuation) args.splice(5, 0, '--continue', continuation);
|
|
521
|
+
let result: ReturnType<typeof kubectl>;
|
|
522
|
+
try { result = kubectl(args); }
|
|
523
|
+
catch (error) {
|
|
524
|
+
return skipDiscovery(kubectlErrorCode(error) === 'ENOBUFS' ? 'output-too-large' : 'kubectl-failed');
|
|
525
|
+
}
|
|
526
|
+
if (kubectlErrorCode(result.error) === 'ENOBUFS') return skipDiscovery('output-too-large');
|
|
527
|
+
if (result.status !== 0) return skipDiscovery('kubectl-failed');
|
|
528
|
+
const listed = parse(result);
|
|
529
|
+
if (!listed || !Array.isArray(listed.items) || !listed.metadata || typeof listed.metadata !== 'object'
|
|
530
|
+
|| Array.isArray(listed.metadata)
|
|
531
|
+
|| (listed.metadata.continue !== undefined && typeof listed.metadata.continue !== 'string'))
|
|
532
|
+
return skipDiscovery('malformed-output');
|
|
533
|
+
warmPods.push(...listed.items);
|
|
534
|
+
continuation = listed.metadata?.continue ?? '';
|
|
535
|
+
if (!continuation) { completedPages = true; break; }
|
|
536
|
+
if (seenContinuations.has(continuation) || page === 99) return skipDiscovery('malformed-output');
|
|
537
|
+
seenContinuations.add(continuation);
|
|
538
|
+
}
|
|
539
|
+
if (!completedPages) return skipDiscovery('malformed-output');
|
|
540
|
+
const hostPods = warmPods.filter((row: any) => row?.metadata?.name === spec.name
|
|
476
541
|
|| row?.metadata?.annotations?.['elanous.dev/warm-worker-id'] === spec.workerId);
|
|
542
|
+
if (namedPod && !hostPods.some((row: any) => row?.metadata?.name === spec.name)) hostPods.push(namedPod);
|
|
477
543
|
if (hostPods.length > 1) return false;
|
|
478
544
|
let pod = hostPods[0];
|
|
479
545
|
const preexisting = !!pod;
|
|
@@ -481,7 +547,7 @@ export class WarmPodProvider {
|
|
|
481
547
|
if (pod && !matches(pod)) return false;
|
|
482
548
|
// Old generations still occupy memory even when their ledger rows are quarantined.
|
|
483
549
|
// Count physical warm Pods on the pinned node before admitting a new one.
|
|
484
|
-
const physical =
|
|
550
|
+
const physical = warmPods.filter((row: any) => row?.metadata?.labels?.['elanous.kind'] === 'warm-worker'
|
|
485
551
|
&& row?.spec?.nodeName === nodeName && !row?.metadata?.deletionTimestamp
|
|
486
552
|
&& row?.status?.phase !== 'Succeeded' && row?.status?.phase !== 'Failed'
|
|
487
553
|
&& row?.spec?.containers?.[0]?.resources?.limits?.memory === spec.memoryLimit).length;
|
|
@@ -602,13 +668,77 @@ export class WarmPodProvider {
|
|
|
602
668
|
const contextFailure = probeWarmPodContext(spec.kubectlContext, this.options.kubectl);
|
|
603
669
|
if (contextFailure) { lastFallback = { command: null, transport: contextFailure }; continue; }
|
|
604
670
|
let acquired: { status: number; value: any };
|
|
671
|
+
const acquisition = this.control('/v1/leases/pod-worker', this.options.memberToken, {
|
|
672
|
+
machine: host, key: spec.key, runId: input.runId, attemptId: input.attemptId,
|
|
673
|
+
ttlMs: this.options.leaseTtlMs ?? 30 * 60_000,
|
|
674
|
+
});
|
|
675
|
+
const timedOut = Symbol('warm-acquisition-timeout');
|
|
676
|
+
let deadlineTimer: ReturnType<typeof setTimeout> | undefined;
|
|
677
|
+
let acquisitionFailed = false;
|
|
678
|
+
let acquisitionResult: typeof timedOut | { status: number; value: any };
|
|
605
679
|
try {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
680
|
+
const remainingMs = input.deadlineAt - this.now();
|
|
681
|
+
if (remainingMs <= 0) acquisitionResult = timedOut;
|
|
682
|
+
else acquisitionResult = await Promise.race([acquisition, new Promise<typeof timedOut>(resolve => {
|
|
683
|
+
deadlineTimer = setTimeout(() => resolve(timedOut), remainingMs);
|
|
684
|
+
})]);
|
|
685
|
+
} catch { acquisitionFailed = true; acquisitionResult = timedOut; }
|
|
686
|
+
finally { if (deadlineTimer) clearTimeout(deadlineTimer); }
|
|
687
|
+
if (acquisitionResult === timedOut) {
|
|
688
|
+
void acquisition.then(async late => {
|
|
689
|
+
const row = late.value;
|
|
690
|
+
const lateWorkerId = row?.name;
|
|
691
|
+
const leaseId = row?.attrs?.leaseId;
|
|
692
|
+
const generation = row?.attrs?.generation;
|
|
693
|
+
const podUid = row?.attrs?.podUid;
|
|
694
|
+
const lateCandidate = this.candidates.find(candidate => candidate.spec.workerId === lateWorkerId
|
|
695
|
+
&& candidate.host === host && keyEquals(candidate.spec.key, spec.key));
|
|
696
|
+
if (late.status !== 200 || !lateCandidate || !row?.attrs?.key || !keyEquals(row.attrs.key, lateCandidate.spec.key)
|
|
697
|
+
|| typeof leaseId !== 'string' || !leaseId
|
|
698
|
+
|| !Number.isSafeInteger(generation) || typeof podUid !== 'string' || !podUid) return;
|
|
699
|
+
const lateSpec = lateCandidate.spec;
|
|
700
|
+
const command: WarmWorkerCommand = { ...input, leaseId, generation, podUid,
|
|
701
|
+
podName: lateSpec.name, podContext: lateSpec.kubectlContext, image: lateSpec.image,
|
|
702
|
+
requestedAt: new Date(this.now()).toISOString(), workerId: lateSpec.workerId, key: lateSpec.key };
|
|
703
|
+
debug.log('pod.warm', 'lease-response-after-deadline', { workerId: command.workerId,
|
|
704
|
+
leaseId, generation, podUid, runId: command.runId, attemptId: command.attemptId }, { level: 'warn' });
|
|
705
|
+
debug.log('pod.provenance', 'lease-start', { pod: lateSpec.name, podUid, leaseId,
|
|
706
|
+
runId: command.runId, attemptId: command.attemptId, requestedAt: command.requestedAt,
|
|
707
|
+
metadata: warmLeaseMetadata(command).annotations });
|
|
708
|
+
try {
|
|
709
|
+
const fenced = await this.controlBounded(`/v1/leases/pod-worker/${encodeURIComponent(lateWorkerId)}/timeout`,
|
|
710
|
+
this.options.memberToken, { runId: input.runId, attemptId: input.attemptId }, WARM_CONTROL_REQUEST_TIMEOUT_MS);
|
|
711
|
+
if (fenced.status !== 200) throw new Error(`warm timeout fence returned ${fenced.status}`);
|
|
712
|
+
} catch (error) { debug.log('pod.warm', 'late-lease-timeout-fence-failed', { workerId: lateWorkerId,
|
|
713
|
+
leaseId, generation, error: String(error) }, { level: 'warn' }); }
|
|
714
|
+
let quarantineTimer: ReturnType<typeof setTimeout> | undefined;
|
|
715
|
+
try {
|
|
716
|
+
await Promise.race([this.quarantine(command, 'lease-response-after-deadline'), new Promise<never>((_, reject) => {
|
|
717
|
+
quarantineTimer = setTimeout(() => reject(new Error('warm late-lease quarantine timed out')), WARM_CONTROL_REQUEST_TIMEOUT_MS);
|
|
718
|
+
})]);
|
|
719
|
+
}
|
|
720
|
+
catch (error) { debug.log('pod.warm', 'late-lease-quarantine-failed', { workerId: command.workerId,
|
|
721
|
+
leaseId, generation, error: String(error) }, { level: 'warn' }); }
|
|
722
|
+
finally { if (quarantineTimer) clearTimeout(quarantineTimer); }
|
|
723
|
+
}, error => debug.log('pod.warm', 'late-lease-response-failed', { workerId: spec.workerId,
|
|
724
|
+
runId: input.runId, attemptId: input.attemptId, error: String(error) }, { level: 'warn' }));
|
|
725
|
+
if (acquisitionFailed) continue;
|
|
726
|
+
return fallback('lease-unavailable');
|
|
727
|
+
}
|
|
728
|
+
acquired = acquisitionResult;
|
|
611
729
|
if (acquired.status === 409 || acquired.status === 503) {
|
|
730
|
+
if (acquired.status === 409) {
|
|
731
|
+
try {
|
|
732
|
+
const query = new URLSearchParams({ kind: 'pod-worker-lease', machine: host, name: spec.workerId });
|
|
733
|
+
const observed = await this.control(`/v1/resources?${query}`, this.options.memberToken);
|
|
734
|
+
const row = observed.status === 200 && Array.isArray(observed.value?.resources)
|
|
735
|
+
? observed.value.resources.find((entry: any) => entry?.name === spec.workerId) : undefined;
|
|
736
|
+
if (row?.attrs?.state === 'quarantined' || row?.attrs?.state === 'timeout-fenced') {
|
|
737
|
+
debug.log('pod.warm', 'quarantine-holds-slot', { workerId: spec.workerId,
|
|
738
|
+
state: row.attrs.state, at: new Date(this.now()).toISOString() }, { level: 'warn' });
|
|
739
|
+
}
|
|
740
|
+
} catch { /* Slot observation never changes the Job's cold fallback. */ }
|
|
741
|
+
}
|
|
612
742
|
lastFallback = fallback('lease-unavailable');
|
|
613
743
|
continue;
|
|
614
744
|
}
|
|
@@ -620,6 +750,16 @@ export class WarmPodProvider {
|
|
|
620
750
|
if (!workerId(row?.name) || typeof leasedId !== 'string' || !leasedId
|
|
621
751
|
|| typeof podUid !== 'string' || !podUid
|
|
622
752
|
|| !Number.isSafeInteger(generation) || generation < 1) return fallback('lease-unavailable');
|
|
753
|
+
// One terminal transition per workerId·leaseId·generation·Pod UID. A lease the
|
|
754
|
+
// control plane already settled (finalize/quarantine raced this acquisition)
|
|
755
|
+
// must never be re-adopted — not by this late reply, not by the next warm request.
|
|
756
|
+
// An uncertain ending keeps its quarantined / cold-Job verdict.
|
|
757
|
+
const terminalKey = JSON.stringify([row.name, leasedId, generation, podUid]);
|
|
758
|
+
if (this.terminalLeases.has(terminalKey) || this.quarantineRequested.has(terminalKey)) {
|
|
759
|
+
debug.log('pod.warm', 'lease-terminal-refused', { workerId: row.name, leaseId: leasedId,
|
|
760
|
+
generation, podUid, runId: input.runId, attemptId: input.attemptId }, { level: 'warn' });
|
|
761
|
+
return fallback('lease-unavailable');
|
|
762
|
+
}
|
|
623
763
|
// Acquisition selects by host/key, not by worker ID. Resolve the returned worker
|
|
624
764
|
// before choosing its transport; an unknown worker must not be executed or fenced.
|
|
625
765
|
const leasedCandidate = this.candidates.find(entry => entry.host === host
|
|
@@ -641,6 +781,20 @@ export class WarmPodProvider {
|
|
|
641
781
|
podName: leasedCandidate.spec.name, podContext: leasedCandidate.spec.kubectlContext, image: leasedCandidate.spec.image,
|
|
642
782
|
requestedAt: new Date(this.now()).toISOString(),
|
|
643
783
|
workerId: row.name, key: leasedCandidate.spec.key };
|
|
784
|
+
if (command.deadlineAt <= this.now()) {
|
|
785
|
+
debug.log('pod.warm', 'lease-response-after-deadline', { workerId: command.workerId,
|
|
786
|
+
leaseId: command.leaseId, generation: command.generation, podUid: command.podUid,
|
|
787
|
+
runId: command.runId, attemptId: command.attemptId }, { level: 'warn' });
|
|
788
|
+
// The control plane granted a lease, even though the caller's budget expired before Pod adoption.
|
|
789
|
+
// Record its short lifetime as a paired start/end and quarantine it without running transport.
|
|
790
|
+
debug.log('pod.provenance', 'lease-start', { pod: leasedCandidate.spec.name, podUid: command.podUid,
|
|
791
|
+
leaseId: command.leaseId, runId: command.runId, attemptId: command.attemptId,
|
|
792
|
+
requestedAt: command.requestedAt, metadata: warmLeaseMetadata(command).annotations });
|
|
793
|
+
try { await this.quarantine(command, 'lease-response-after-deadline'); }
|
|
794
|
+
catch (error) { debug.log('pod.warm', 'late-lease-quarantine-failed', { workerId: command.workerId,
|
|
795
|
+
leaseId: command.leaseId, generation: command.generation, error: String(error) }, { level: 'warn' }); }
|
|
796
|
+
return fallback('lease-unavailable');
|
|
797
|
+
}
|
|
644
798
|
// Acquisition is by pool key. A healthy sibling or replacement Pod must remain eligible.
|
|
645
799
|
// Never run transport on the old Pod while its previous lease is being quarantined.
|
|
646
800
|
if (this.quarantiningPods.has(JSON.stringify([command.workerId, command.podUid]))) {
|
|
@@ -710,20 +864,26 @@ export class WarmPodProvider {
|
|
|
710
864
|
}
|
|
711
865
|
|
|
712
866
|
private async finalizeOnce(command: WarmWorkerCommand): Promise<'sanitized' | 'quarantined'> {
|
|
867
|
+
const key = JSON.stringify([command.workerId, command.leaseId, command.generation, command.podUid]);
|
|
713
868
|
const candidate = this.candidates.find(row => row.spec.workerId === command.workerId);
|
|
714
869
|
if (!candidate) throw new Error('warm finalize candidate missing');
|
|
715
870
|
const released = await this.transition(command, 'release');
|
|
716
871
|
const machineToken = this.options.machineTokens?.[candidate.host];
|
|
717
872
|
// Sanitizing is the producer's machine-scoped acknowledgement, after transport's cleanup and ACK.
|
|
718
|
-
|
|
873
|
+
// Always verify and clear this exact Pod UID/lease metadata before telling the control plane it is reusable.
|
|
874
|
+
// A missing local adoption record is not evidence that no pod-side leased state exists.
|
|
875
|
+
const cleared = released
|
|
876
|
+
? patchWarmLeaseMetadata(candidate.spec, command, 'idle', this.options.kubectl)
|
|
719
877
|
: { ok: false, reason: 'release-failed' };
|
|
720
878
|
if (!cleared.ok) debug.log('pod.provenance', 'lease-patch-refused', { pod: candidate.spec.name,
|
|
721
879
|
podUid: command.podUid, leaseId: command.leaseId, reason: cleared.reason }, { level: 'warn' });
|
|
722
880
|
if (!cleared.ok || !token(machineToken) || !await this.transition(command, 'sanitize', machineToken)) {
|
|
723
|
-
|
|
881
|
+
if (!this.quarantineRequested.has(key)) {
|
|
882
|
+
this.quarantineRequested.add(key);
|
|
883
|
+
await this.quarantineOnce(command, 'sanitize-unavailable', true);
|
|
884
|
+
}
|
|
724
885
|
return 'quarantined';
|
|
725
886
|
}
|
|
726
|
-
const key = JSON.stringify([command.workerId, command.leaseId, command.generation, command.podUid]);
|
|
727
887
|
if (!this.quarantineRequested.has(key)) {
|
|
728
888
|
debug.log('pod.provenance', 'lease-end', { pod: candidate.spec.name, podUid: command.podUid,
|
|
729
889
|
leaseId: command.leaseId, runId: command.runId, attemptId: command.attemptId,
|
|
@@ -740,19 +900,21 @@ export class WarmPodProvider {
|
|
|
740
900
|
this.quarantiningPods.add(podKey);
|
|
741
901
|
const prior = this.terminalLeases.get(key);
|
|
742
902
|
if (prior) {
|
|
903
|
+
if (this.quarantineRequested.has(key)) {
|
|
904
|
+
try { await prior; this.quarantiningPods.delete(podKey); }
|
|
905
|
+
catch (error) { if (this.terminalLeases.get(key) === prior) this.terminalLeases.delete(key); throw error; }
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
743
908
|
this.quarantineRequested.add(key);
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
return 'quarantined' as const;
|
|
748
|
-
}
|
|
749
|
-
return outcome;
|
|
750
|
-
});
|
|
909
|
+
// Fence the control-plane lease immediately. Waiting for sanitize to settle leaves a window
|
|
910
|
+
// where another request could acquire the just-idled worker before this quarantine lands.
|
|
911
|
+
const terminal = this.quarantineOnce(command, reason, leaseStarted).then(() => 'quarantined' as const);
|
|
751
912
|
this.terminalLeases.set(key, terminal);
|
|
752
913
|
try { await terminal; this.quarantiningPods.delete(podKey); }
|
|
753
914
|
catch (error) { if (this.terminalLeases.get(key) === terminal) this.terminalLeases.delete(key); throw error; }
|
|
754
915
|
return;
|
|
755
916
|
}
|
|
917
|
+
this.quarantineRequested.add(key);
|
|
756
918
|
const terminal = this.quarantineOnce(command, reason, leaseStarted).then(() => 'quarantined' as const);
|
|
757
919
|
this.terminalLeases.set(key, terminal);
|
|
758
920
|
try { await terminal; this.quarantiningPods.delete(podKey); }
|
|
@@ -783,7 +945,11 @@ let configuredProvider: WarmPodProvider | null = null;
|
|
|
783
945
|
/** The trusted producer configures this once; an absent provider fails closed without creating a Pod. */
|
|
784
946
|
export function configureWarmPodProvider(provider: WarmPodProvider | null): void { configuredProvider = provider; }
|
|
785
947
|
/** Optional private producer config; a missing/unsafe file leaves the Job path untouched. */
|
|
786
|
-
export function loadWarmPodProvider(path: string,
|
|
948
|
+
export function loadWarmPodProvider(path: string, pairingGateFileOrOptions?: string | WarmPodProviderLoadOptions): WarmPodProvider {
|
|
949
|
+
const pairingGateFile = typeof pairingGateFileOrOptions === 'string'
|
|
950
|
+
? pairingGateFileOrOptions : pairingGateFileOrOptions?.pairingGateFile;
|
|
951
|
+
const runtimeOverrides = typeof pairingGateFileOrOptions === 'object'
|
|
952
|
+
? pairingGateFileOrOptions?.runtimeOverrides ?? {} : {};
|
|
787
953
|
if (!isAbsolute(path) || (statSync(path).mode & 0o077) !== 0) throw new Error('warm provider config must be private');
|
|
788
954
|
const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'));
|
|
789
955
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid warm provider config');
|
|
@@ -797,7 +963,7 @@ export function loadWarmPodProvider(path: string, pairingGateFile?: string): War
|
|
|
797
963
|
if (!pairingGateFile.trim()) throw new Error('warm provider pairing gate file must not be empty');
|
|
798
964
|
options.pairingGateFile = pairingGateFile;
|
|
799
965
|
}
|
|
800
|
-
return new WarmPodProvider(options);
|
|
966
|
+
return new WarmPodProvider({ ...options, ...runtimeOverrides });
|
|
801
967
|
}
|
|
802
968
|
function currentProvider(): WarmPodProvider | null {
|
|
803
969
|
if (configuredProvider) return configuredProvider;
|
|
@@ -851,35 +1017,55 @@ export function parseWarmPodProviderArgs(argv: readonly string[]): { action: '--
|
|
|
851
1017
|
throw usage();
|
|
852
1018
|
}
|
|
853
1019
|
|
|
854
|
-
|
|
855
|
-
|
|
1020
|
+
export interface WarmPodProviderCliDependencies {
|
|
1021
|
+
providerRuntime?: Partial<WarmPodProviderRuntimeOverrides>;
|
|
1022
|
+
write?: (line: string) => void;
|
|
1023
|
+
registerLogSink?: (name: string) => Promise<void>;
|
|
1024
|
+
sleep?: (milliseconds: number) => Promise<void>;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
export async function runWarmPodProviderCli(argv: readonly string[] = process.argv.slice(2),
|
|
1028
|
+
dependencies: WarmPodProviderCliDependencies = {}): Promise<{
|
|
1029
|
+
exitCode: number;
|
|
1030
|
+
result?: WarmPoolReconcileResult | null;
|
|
1031
|
+
prepared?: boolean;
|
|
1032
|
+
}> {
|
|
1033
|
+
const { action, workerId, gateFile } = parseWarmPodProviderArgs(argv);
|
|
1034
|
+
const write = dependencies.write ?? ((line: string) => { process.stdout.write(line); });
|
|
856
1035
|
const file = process.env.ELANOUS_WARM_POD_PROVIDER_CONFIG;
|
|
857
1036
|
// The 1-file gate key this pool serves, bound into every cold prepare leg of this process.
|
|
858
|
-
const load = () =>
|
|
1037
|
+
const load = () => {
|
|
1038
|
+
if (!file) return null;
|
|
1039
|
+
return loadWarmPodProvider(file, { pairingGateFile: gateFile, runtimeOverrides: dependencies.providerRuntime });
|
|
1040
|
+
};
|
|
859
1041
|
if (action === '--pairs') {
|
|
860
1042
|
// Read-only: join the cold CLI legs and the warm gate legs both processes wrote to logs.db.
|
|
861
1043
|
try {
|
|
862
1044
|
const storeMod = await import('../../mss/logging/log-store.js');
|
|
863
1045
|
const dbPath = storeMod.logsDbPath();
|
|
864
1046
|
// No logs.db yet means no leg was ever measured: an empty pair list, not a failed query.
|
|
865
|
-
if (!existsSync(dbPath))
|
|
1047
|
+
if (!existsSync(dbPath)) write(JSON.stringify({ warmReuseTimePairs: [] }) + '\n');
|
|
866
1048
|
else {
|
|
867
1049
|
const store = storeMod.LogStore.openReadOnly(dbPath);
|
|
868
|
-
try {
|
|
1050
|
+
try { write(JSON.stringify({ warmReuseTimePairs: readWarmReuseTimePairs(store) }) + '\n'); }
|
|
869
1051
|
finally { store.close(); }
|
|
870
1052
|
}
|
|
871
1053
|
} catch (error) {
|
|
872
|
-
|
|
873
|
-
|
|
1054
|
+
write(JSON.stringify({ warmReuseTimePairs: null, reason: 'logs-unavailable', detail: String(error) }) + '\n');
|
|
1055
|
+
return { exitCode: 2 };
|
|
874
1056
|
}
|
|
1057
|
+
return { exitCode: 0 };
|
|
875
1058
|
}
|
|
876
1059
|
// The cold legs must reach the same logs.db the warm gate process (gate-node) writes; fail-open.
|
|
877
|
-
|
|
1060
|
+
try {
|
|
1061
|
+
if (dependencies.registerLogSink) await dependencies.registerLogSink('pod-warm');
|
|
1062
|
+
else await (await import('../../domains/standalone-log-sink.js')).registerStandaloneLogSink('pod-warm');
|
|
1063
|
+
}
|
|
878
1064
|
catch { /* the file trail stays the source of truth */ }
|
|
879
1065
|
// This process's own legs, echoed for the caller; the pair itself is read with --pairs.
|
|
880
1066
|
const emitPairs = (provider: WarmPodProvider) => {
|
|
881
1067
|
const legs = provider.warmReuseTimeLegs();
|
|
882
|
-
if (legs.length)
|
|
1068
|
+
if (legs.length) write(JSON.stringify({ warmReuseTimeLegs: legs }) + '\n');
|
|
883
1069
|
};
|
|
884
1070
|
if (action === '--serve') {
|
|
885
1071
|
// Reloading the private config lets the owner rotate a quarantined slot to a new worker ID.
|
|
@@ -888,30 +1074,40 @@ if (import.meta.main) {
|
|
|
888
1074
|
try {
|
|
889
1075
|
const provider = load();
|
|
890
1076
|
const result = provider ? await provider.reconcilePool() : null;
|
|
891
|
-
|
|
1077
|
+
write(JSON.stringify(result ?? { target: 0, ready: 0, failed: ['config-unavailable'] }) + '\n');
|
|
892
1078
|
if (provider) emitPairs(provider);
|
|
893
1079
|
} catch {
|
|
894
1080
|
debug.log('pod.warm', 'pool-reconcile-unavailable', { reason: 'config-unavailable' }, { level: 'warn' });
|
|
895
|
-
|
|
1081
|
+
write(JSON.stringify({ target: 0, ready: 0, failed: ['config-unavailable'] }) + '\n');
|
|
896
1082
|
}
|
|
897
|
-
await Bun.sleep(60_000);
|
|
1083
|
+
await (dependencies.sleep ?? Bun.sleep)(60_000);
|
|
898
1084
|
}
|
|
1085
|
+
return { exitCode: 0 };
|
|
899
1086
|
}
|
|
900
1087
|
if (action === '--reconcile') {
|
|
901
1088
|
let result: WarmPoolReconcileResult | null = null;
|
|
902
1089
|
let provider: WarmPodProvider | null = null;
|
|
903
1090
|
try { provider = load(); result = provider ? await provider.reconcilePool() : null; }
|
|
904
1091
|
catch { /* An invalid private config is a failed pass, never a Pod mutation. */ }
|
|
905
|
-
|
|
1092
|
+
write(JSON.stringify(result ?? { target: 0, ready: 0, failed: ['config-unavailable'] }) + '\n');
|
|
906
1093
|
if (provider) emitPairs(provider);
|
|
907
|
-
|
|
1094
|
+
return { exitCode: !result || result.ready !== result.target ? 2 : 0, result };
|
|
908
1095
|
} else if (action === '--prepare') {
|
|
909
1096
|
let prepared = false;
|
|
910
1097
|
let provider: WarmPodProvider | null = null;
|
|
911
1098
|
try { provider = load(); prepared = provider ? await provider.prepareWorker(workerId!) : false; }
|
|
912
1099
|
catch { /* An invalid private config is a failed preparation, never a Pod mutation. */ }
|
|
913
|
-
|
|
1100
|
+
write(JSON.stringify({ workerId, prepared }) + '\n');
|
|
914
1101
|
if (provider) emitPairs(provider);
|
|
915
|
-
|
|
1102
|
+
return { exitCode: prepared ? 0 : 2, prepared };
|
|
1103
|
+
}
|
|
1104
|
+
return { exitCode: 2 };
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
if (import.meta.main) {
|
|
1108
|
+
try { process.exitCode = (await runWarmPodProviderCli()).exitCode; }
|
|
1109
|
+
catch (error) {
|
|
1110
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1111
|
+
process.exitCode = 2;
|
|
916
1112
|
}
|
|
917
1113
|
}
|
|
@@ -7,6 +7,7 @@ import { warmReferenceFromJobArtifacts } from '../../../scripts/release-loop/gat
|
|
|
7
7
|
import { stateDirSourceForChild } from '../../agent/identity-env.js';
|
|
8
8
|
import { debug } from '../../debug/log.js';
|
|
9
9
|
import { decidePodReuseCleanup } from './pod-reuse-cleanup.js';
|
|
10
|
+
import { podSourceScript, type PodSource } from './pod-source-receive.js';
|
|
10
11
|
import type { WarmWorkerCommand, WarmWorkerFileResult, WarmWorkerReply } from './pod-warm-worker-protocol.js';
|
|
11
12
|
|
|
12
13
|
const token = (s: unknown): s is string => typeof s === 'string' && /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(s);
|
|
@@ -24,6 +25,31 @@ const withoutGitEnvironment = (): NodeJS.ProcessEnv => {
|
|
|
24
25
|
return env;
|
|
25
26
|
};
|
|
26
27
|
|
|
28
|
+
const installedLockHashPath = (repoDir: string): string => join(repoDir, 'node_modules', '.elanous-installed-lock-hash');
|
|
29
|
+
|
|
30
|
+
function readInstalledLockHash(repoDir: string): string | null {
|
|
31
|
+
try {
|
|
32
|
+
const modules = lstatSync(join(repoDir, 'node_modules'));
|
|
33
|
+
if (!modules.isDirectory() || modules.isSymbolicLink()) return null;
|
|
34
|
+
const marker = installedLockHashPath(repoDir);
|
|
35
|
+
const stat = lstatSync(marker);
|
|
36
|
+
if (!stat.isFile() || stat.isSymbolicLink()) return null;
|
|
37
|
+
const value = readFileSync(marker, 'utf8').trim();
|
|
38
|
+
return /^[a-f0-9]{64}$/.test(value) ? value : null;
|
|
39
|
+
} catch { return null; }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Record the image's installed dependency lock once source verification ties it to the worker key. */
|
|
43
|
+
function rememberInstalledLockHash(repoDir: string, lockHash: string): void {
|
|
44
|
+
try {
|
|
45
|
+
const modules = lstatSync(join(repoDir, 'node_modules'));
|
|
46
|
+
if (!modules.isDirectory() || modules.isSymbolicLink()) return;
|
|
47
|
+
const marker = installedLockHashPath(repoDir);
|
|
48
|
+
if (existsSync(marker)) return;
|
|
49
|
+
writeFileSync(marker, `${lockHash}\n`, { mode: 0o600, flag: 'wx' });
|
|
50
|
+
} catch { /* an unknown installation stays unknown and min-sync will install before reuse */ }
|
|
51
|
+
}
|
|
52
|
+
|
|
27
53
|
function resolveThroughExistingAncestor(path: string): string | null {
|
|
28
54
|
let ancestor = resolve(path);
|
|
29
55
|
const suffix: string[] = [];
|
|
@@ -147,6 +173,12 @@ export class WarmWorkerRuntime {
|
|
|
147
173
|
runGit?: (args: readonly string[]) => WarmWorkerGitResult;
|
|
148
174
|
removeScratch?: (path: string) => void;
|
|
149
175
|
now?: () => number;
|
|
176
|
+
/** POD-REUSE-MIN-SYNC — 새 base 요청의 최소 동기화 원천: 호스트 미러 마운트(기본 /host-mirror). */
|
|
177
|
+
mirrorPath?: string;
|
|
178
|
+
/** POD-REUSE-MIN-SYNC — 부모가 넘긴 git bundle(있으면 호스트 미러보다 먼저). */
|
|
179
|
+
minSyncBundle?: { bundlePath: string; sha256: string; sizeBytes: number };
|
|
180
|
+
/** 시험 심 — min-sync 수신 스크립트 실행(기본: 체크아웃 안에서 bash -c). */
|
|
181
|
+
runMinSync?: (script: string) => { status: number | null; stdout: string; stderr: string };
|
|
150
182
|
}) {}
|
|
151
183
|
|
|
152
184
|
handle(command: WarmWorkerCommand): Promise<WarmWorkerOutcome> {
|
|
@@ -177,9 +209,18 @@ export class WarmWorkerRuntime {
|
|
|
177
209
|
return { reply: null, quarantineWorker: true, reason: 'execution-error' };
|
|
178
210
|
}
|
|
179
211
|
const repo = realpathSync(this.options.repoDir);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
212
|
+
const sourceMatches = warmWorkerSourceMatches(repo, command.cutSha, command.key.lockHash);
|
|
213
|
+
if (sourceMatches && readInstalledLockHash(repo) === null) rememberInstalledLockHash(repo, command.key.lockHash);
|
|
214
|
+
if (!sourceMatches || readInstalledLockHash(repo) !== command.key.lockHash) {
|
|
215
|
+
// POD-REUSE-MIN-SYNC — 같은 웜 Pod 로 들어온 새 base 요청: 상주 체크아웃을 호스트 미러(또는 부모가
|
|
216
|
+
// 넘긴 bundle)에서만 최소 동기화한 뒤 같은 검증으로 다시 본다. min-sync 가 아니거나 실패면
|
|
217
|
+
// 기존 폐기(quarantine) 판정이 그대로 선다.
|
|
218
|
+
if (!this.minSyncReceive(repo, command)
|
|
219
|
+
|| !warmWorkerSourceMatches(repo, command.cutSha, command.key.lockHash)
|
|
220
|
+
|| readInstalledLockHash(repo) !== command.key.lockHash) {
|
|
221
|
+
this.quarantined = true;
|
|
222
|
+
return { reply: null, quarantineWorker: true, reason: 'quarantined' };
|
|
223
|
+
}
|
|
183
224
|
}
|
|
184
225
|
debug.log('pod.warm', 'resident-checkout-verified', { runId: command.runId,
|
|
185
226
|
attemptId: command.attemptId, workerId: command.workerId,
|
|
@@ -363,4 +404,40 @@ export class WarmWorkerRuntime {
|
|
|
363
404
|
}
|
|
364
405
|
return { reply, quarantineWorker: false, reason: 'complete', artifactsDir };
|
|
365
406
|
}
|
|
407
|
+
|
|
408
|
+
/** POD-REUSE-MIN-SYNC — 체크아웃 head 또는 실제 설치 lock hash 가 요청과 다를 때만 시도한다.
|
|
409
|
+
* dirty source bytes 는 min-sync 대상으로 삼지 않는다. base 는 호스트 미러/부모 bundle 에서만 받는다(GitHub 호출 0) ·
|
|
410
|
+
* 차이 파일만 checkout/reset 하고 남은 untracked·빌드 산출만 clean 한다. 성공 표지
|
|
411
|
+
* `ELANOUS_POD_STAGE min-sync <호출 수> <바뀐 파일 수> <소요 초>` 를 관측(pod.warm/min-sync)으로 남긴다. */
|
|
412
|
+
private minSyncReceive(repo: string, command: WarmWorkerCommand): boolean {
|
|
413
|
+
const git = (args: readonly string[]): WarmWorkerGitResult => {
|
|
414
|
+
try {
|
|
415
|
+
return this.options.runGit?.(args) ?? spawnSync('git', ['-C', repo, ...args], {
|
|
416
|
+
encoding: 'utf8', env: withoutGitEnvironment(), maxBuffer: 16 * 1024 * 1024,
|
|
417
|
+
});
|
|
418
|
+
} catch { return { status: null, stdout: null }; }
|
|
419
|
+
};
|
|
420
|
+
const resident = git(['rev-parse', 'HEAD']);
|
|
421
|
+
const previousHead = resident.status === 0 ? (resident.stdout ?? '').trim() : '';
|
|
422
|
+
if (!sha(previousHead)) return false;
|
|
423
|
+
const source: PodSource = {
|
|
424
|
+
kind: 'min-sync', baseSha: command.cutSha, previousHead, lockHash: command.key.lockHash,
|
|
425
|
+
...(this.options.minSyncBundle ? { bundle: this.options.minSyncBundle } : {}),
|
|
426
|
+
};
|
|
427
|
+
const script = podSourceScript(source, 'https://github.com/unused/repo', this.options.mirrorPath ?? '/host-mirror', { checkoutDir: repo });
|
|
428
|
+
let run: { status: number | null; stdout?: string | null };
|
|
429
|
+
try {
|
|
430
|
+
run = this.options.runMinSync?.(script) ?? spawnSync('bash', ['-c', script], {
|
|
431
|
+
encoding: 'utf8', cwd: repo, env: withoutGitEnvironment(), maxBuffer: 16 * 1024 * 1024,
|
|
432
|
+
});
|
|
433
|
+
} catch { return false; }
|
|
434
|
+
const out = run.stdout ?? '';
|
|
435
|
+
const stage = /^ELANOUS_POD_STAGE min-sync (\d+) (\d+) (\d+)\r?$/m.exec(out);
|
|
436
|
+
try {
|
|
437
|
+
debug.log('pod.warm', 'min-sync', { runId: command.runId, attemptId: command.attemptId, workerId: command.workerId,
|
|
438
|
+
baseSha: command.cutSha, previousHead, ok: run.status === 0,
|
|
439
|
+
githubCalls: stage ? Number(stage[1]) : null, changedFiles: stage ? Number(stage[2]) : null, seconds: stage ? Number(stage[3]) : null });
|
|
440
|
+
} catch { /* observation is fail-soft */ }
|
|
441
|
+
return run.status === 0 && !!stage;
|
|
442
|
+
}
|
|
366
443
|
}
|