elanous 0.2.41 → 0.2.42
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 → X1ucLw10Cds_h614NoEnh}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5159.115f1c2ca471386c.js → 1063.2fb8a9dc55c731f2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +36 -0
- package/apps/pwa/out/_next/static/chunks/1147-5196d19c222051b3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9048.212083de42d25be3.js → 1262.e804feb8fd1acb8c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1319.b9b815ae0f181e06.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4527.a69f2894d1bc9f4a.js → 1487.2f67b79444062da6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1574.878c18ecc97b1bd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +32 -0
- package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1945.7b54990d578c119b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +286 -0
- package/apps/pwa/out/_next/static/chunks/2160.a097e7b138ae1c55.js +23 -0
- package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +34 -0
- package/apps/pwa/out/_next/static/chunks/2456.b6de0e1c05f28843.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +1 -0
- package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{530.d26346e18089640a.js → 2690.0521c738b7749931.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4702.4a4adc1f16d7c93b.js → 2974.595d1e29d040cb6a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2263.e09b6edea33bad2d.js → 3207.a756c95e9ec8c3c8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9541.eb8e2f8480c7feca.js → 3285.89ee2f298682f5e5.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{9507.7026657a2f47eb64.js → 3347.f846266b5e5f3ede.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +41 -0
- package/apps/pwa/out/_next/static/chunks/{1178.1aa9cad0e7695427.js → 3482.a9ae9d2ad6a5bd97.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3507.97e1977bc4d5fb0a.js +2 -0
- package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +24 -0
- package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1661.0dd330f3d89f73f3.js → 3837.a210d7d0db8d8abd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2fdf2931.b431eee4fb468bc3.js → 3d0154af.5331fec737ffe8c3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4043.6b91203436c9c86b.js +309 -0
- package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +77 -0
- package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4320.583cbab64db6be02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4770.769c9cd9c7034eba.js +148 -0
- package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +74 -0
- package/apps/pwa/out/_next/static/chunks/50061469.0326382241ef3b2d.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{1115.434ae2ecb0ad986d.js → 5112.4b9f300124fab7b3.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +27 -0
- package/apps/pwa/out/_next/static/chunks/53c73f84.373b6160adfa89a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5440-4236de26c5ea5856.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5885.0a3e52c8faccec98.js +287 -0
- package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +226 -0
- package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +90 -0
- package/apps/pwa/out/_next/static/chunks/{2073.689dcb2680113d76.js → 6377.bc7df239edbff244.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1800.f7ff51dc4978a958.js → 6632.0eac1c554f8f2ef3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +104 -0
- package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +94 -0
- package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2527-5c636a43c7cc5dde.js → 7279-c199ea83f34338fa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{385e4574.e9886ab32759eda3.js → 73d2eb0e.4966ad55293c801a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5471.1e611302ed3a7c53.js → 7411.9b4b8b747dc7b802.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +1 -0
- package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2fe2c302.41b517f88d6fe502.js → 7a98bc80.fa935989e829f9c2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8138.6c10b2a356d52fca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5574.f35accf4f132b29d.js → 8262.ddc03e06b733f184.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +8 -0
- package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8505.fd803c6c33b54cc3.js +79 -0
- package/apps/pwa/out/_next/static/chunks/{8050-9b364bdef8f71927.js → 8546-6f03f8ea34dd61d9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5947-135e26537d80a6b9.js → 8673-bab689a55f7e13b9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9211-330b6736a63d4cb3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5937.c2df9e3447e1f667.js → 9249.976f1e69a9d80754.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1971-7efb628c471dc5a0.js → 9353-12bfff0c130104cf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7191.fdc955f7d96064a4.js → 9415.69e4a21c60c7d2db.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1219.7e17964e0e7cd8e5.js → 9427.96aa912ddb5801e0.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5964-7e21164a8f2cf0ce.js → 9656-374232558fd528d0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6552.a3840aa7da35ad68.js → 9832.f4a98c878ecf2c0a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9a852a62-6192a6ea9346ced3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-0f291d3c8fd55a3a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{a0a01613.6d1cca322238d7fe.js → b450776b.3db34d8d965f82d3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{c0c1a699.0ba79f97005965d4.js → e8543907.5b040a5f22a0b0e5.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +1 -0
- package/apps/pwa/out/_next/static/css/{b9d8151e48998417.css → 62c858ad53854f47.css} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -24
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -24
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -24
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/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/overlays/stop-heal-ladder.yaml +113 -0
- package/graphs/units/verbs/recipes.yaml +11 -11
- package/graphs/work/research-report.yaml +10 -2
- package/package.json +1 -1
- package/scripts/heal/run-role.ts +99 -5
- package/scripts/land-global-checks.ts +6 -1
- 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/gate-baseline-receipt.ts +47 -9
- package/scripts/release-loop/gate-image-pin.ts +81 -0
- package/scripts/release-loop/gate-node-sim.ts +207 -0
- package/scripts/release-loop/gate-node.ts +285 -46
- 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-train-receipts.ts +122 -0
- package/scripts/release-loop/resume-release.ts +83 -8
- package/scripts/ux-sim.ts +18 -1
- package/scripts/warm-pool-provider-config.ts +263 -0
- package/skills/omni-crawl/SKILL.md +5 -2
- package/skills/omni-crawl/scripts/main.ts +84 -23
- package/src/acp/core-turn-bridge.ts +13 -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/mission-cli.ts +24 -0
- package/src/agent-mission/mission-out.ts +595 -0
- package/src/agent-mission/tool-install.ts +88 -2
- package/src/agent-substrate/context-strategy.ts +4 -4
- package/src/agent-substrate/self-review-cli.ts +178 -13
- package/src/auto-research/research-turn.ts +123 -50
- package/src/autopilot/pr-manager.ts +38 -7
- package/src/autopilot/pty-control-loop.ts +2 -0
- package/src/capture/tui-self-report.ts +22 -6
- package/src/chat/index.ts +1 -1
- 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/pr-land-heavy-remote.ts +32 -0
- package/src/cli/pr-land-overlap-evidence.ts +100 -1
- package/src/cli/pr-land-pod-shadow-job.ts +60 -0
- package/src/cli/release-checklist-read-cli.ts +20 -10
- package/src/cli/research-cli.ts +4 -5
- package/src/cli/tasks-cli.ts +7 -0
- package/src/compact/auto.ts +8 -1
- package/src/control-plane/ledger.ts +52 -2
- package/src/control-plane/server.ts +16 -2
- package/src/core-turn/run-core-turn.ts +311 -90
- package/src/core-turn/run-goal-loop.ts +18 -0
- package/src/core-turn/types.ts +2 -0
- package/src/dashboard/classic-sidetab-mission-job.ts +58 -0
- package/src/dashboard/classic-sidetab-mission.ts +185 -0
- package/src/dashboard/index.ts +149 -15
- package/src/dashboard/input/agent-wake.ts +23 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +9 -0
- package/src/dashboard/mission-cli-consumer.ts +153 -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/turn-preamble.ts +53 -15
- package/src/dashboard/turn-prompt-runtime.ts +4 -2
- package/src/graph-runner/graph-cli.ts +23 -7
- package/src/graph-runner/graph-tick.ts +10 -2
- package/src/graph-runner/runner.ts +1 -1
- package/src/grok/agent-search.ts +14 -4
- package/src/grok/credential.ts +28 -11
- package/src/harness/harness-pod-dispatch.ts +81 -15
- package/src/harness/harness-stop.ts +155 -11
- package/src/index.ts +34 -5
- package/src/instance/spawn-elanous.ts +6 -4
- package/src/llm.ts +166 -8
- package/src/loops/orchestrator/coordinator-shadow.ts +226 -0
- package/src/loops/orchestrator/tick.ts +13 -0
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/native-tool-catalog.ts +2 -2
- package/src/nexus/api/harness-traversal.ts +11 -0
- package/src/pr-tool/census.ts +3 -2
- package/src/pty-shell/tui-run-state.ts +188 -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 +121 -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/decompose.ts +119 -5
- package/src/self-dev/launch-preflight-text.ts +5 -6
- package/src/self-dev/orchestrate.ts +12 -2
- 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-implement/doctor-visit.ts +88 -0
- package/src/self-implement/goal-author.ts +326 -3
- package/src/self-implement/graph-overlay-yaml.ts +7 -0
- 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/orchestrator.ts +126 -11
- 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 +119 -0
- package/src/self-implement/run-ledger.ts +112 -11
- package/src/self-implement/run-stop.ts +188 -4
- package/src/self-implement/stop-autoheal.ts +13 -0
- package/src/session/chat.ts +38 -4
- package/src/session-runtime/index.ts +98 -4
- package/src/session-runtime/tier-flip.ts +3 -3
- package/src/sidetab-core/model.ts +19 -5
- package/src/sidetab-core/visible-agent-mission.ts +186 -0
- package/src/skills/name-match.ts +20 -0
- package/src/skills/tools/agent.ts +30 -2
- package/src/skills/tools/omni-search.ts +67 -5
- package/src/task-agent/pod-distributor-entry.ts +3 -0
- package/src/task-agent/task-hand.ts +27 -0
- package/src/task-orchestrator/surfaces/pod-distributor.ts +48 -0
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +38 -1
- 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 +163 -13
- package/src/task-orchestrator/surfaces/pod-source-spec.ts +3 -3
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +209 -39
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +80 -3
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +165 -45
- package/src/tokens.ts +35 -2
- package/src/tool-runtime/agent-runtime.ts +1 -0
- package/src/tool-runtime/elanous-skills-list-runtime.ts +5 -1
- package/src/tool-runtime/skill-exec-runtime.ts +33 -13
- package/src/tool-runtime/types.ts +1 -0
- package/src/tui/entry.ts +14 -4
- package/src/tui/sidetab/attach.ts +47 -0
- package/src/tui-client/local-chat-turn.ts +26 -13
- package/src/tui.ts +22 -0
- package/src/ux-sim/fake-kubectl.ts +37 -3
- package/src/ux-sim/fault-pool-cap.ts +11 -6
- package/src/ux-sim/mock-scenario-catalog.json +41 -0
- package/src/ux-sim/mock-scenario-catalog.ts +156 -0
- package/src/ux-sim/scenario.ts +116 -23
- package/src/version/packed-revision.json +1 -1
- package/src/voice/voice-tts-singleton.ts +18 -3
- package/src/web-search/grok.ts +5 -9
- 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/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/1999-8de7b7bb36801913.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/2692-1027cb16fe4ccf49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2743.5d3f76948be32b34.js +0 -41
- 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/3230-49298c3b73ef2268.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/4133.2056bb4d78f621af.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/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/53aeb4ee-51c92f8d683f5220.js +0 -1
- 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/5744.b9415e18ad623100.js +0 -23
- package/apps/pwa/out/_next/static/chunks/5892.2526d962339662d8.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/6736.1e36d3ac5fa5e41d.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6874.d5cf7eb8edb2cabe.js +0 -2
- 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/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/8152.64e253c35cccfaae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/83184dcd-0ee6247ff41eb3f2.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/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/9834.63ab2bbc3153172e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9869.81a1e24ca682d5a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/addc2b32.8c4ff8f0aefe987d.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/release/page-40f9e19149024298.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/devices/page-a142dfb0331a05f5.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/b2271e54.c1de3347976e90b0.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/d0a48dc099ed86cf.css +0 -1
- /package/apps/pwa/out/_next/static/{GiOLWmt4MqDZePubBjA4Q → X1ucLw10Cds_h614NoEnh}/_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;
|
|
@@ -71,6 +72,11 @@ export interface WarmPodProviderOptions {
|
|
|
71
72
|
/** Gate file this pool serves, used to bind cold prepare legs to their 1-file gate measurement key. */
|
|
72
73
|
pairingGateFile?: string;
|
|
73
74
|
}
|
|
75
|
+
type WarmPodProviderRuntimeOverrides = Pick<WarmPodProviderOptions, 'fetch' | 'kubectl' | 'prepareLockDirectory'>;
|
|
76
|
+
export interface WarmPodProviderLoadOptions {
|
|
77
|
+
pairingGateFile?: string;
|
|
78
|
+
runtimeOverrides?: Partial<WarmPodProviderRuntimeOverrides>;
|
|
79
|
+
}
|
|
74
80
|
|
|
75
81
|
export interface WarmPoolReconcileResult {
|
|
76
82
|
profile: string;
|
|
@@ -293,6 +299,15 @@ export class WarmPodProvider {
|
|
|
293
299
|
return { status: response.status, value };
|
|
294
300
|
}
|
|
295
301
|
|
|
302
|
+
private async controlBounded(path: string, credential: string, body: Record<string, unknown>, timeoutMs: number): Promise<{ status: number; value: any }> {
|
|
303
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
304
|
+
try {
|
|
305
|
+
return await Promise.race([this.control(path, credential, body), new Promise<never>((_, reject) => {
|
|
306
|
+
timer = setTimeout(() => reject(new Error('warm control request timed out')), timeoutMs);
|
|
307
|
+
})]);
|
|
308
|
+
} finally { if (timer) clearTimeout(timer); }
|
|
309
|
+
}
|
|
310
|
+
|
|
296
311
|
/** The child owns kubectl. Timeout terminates only this child process group and fences its lease. */
|
|
297
312
|
private async runTransport(spec: WarmPodSpec, command: WarmWorkerCommand): Promise<WarmPodTransportResult> {
|
|
298
313
|
if (this.options.transport) return this.options.transport(spec).request(command);
|
|
@@ -468,12 +483,37 @@ export class WarmPodProvider {
|
|
|
468
483
|
&& Object.entries(metadata.annotations).every(([key, value]) => pod.metadata.annotations?.[key] === value)
|
|
469
484
|
&& pod.spec?.nodeName === nodeName
|
|
470
485
|
&& sameSpec(normalizedSpec(pod.spec), template);
|
|
471
|
-
//
|
|
472
|
-
|
|
473
|
-
const
|
|
474
|
-
if (!Array.isArray(
|
|
475
|
-
|
|
486
|
+
// Resolve the pinned Pod independently; namespace size must not affect this read.
|
|
487
|
+
const namedResult = kubectl(['get', 'pods', `--field-selector=metadata.name=${spec.name}`, '-o', 'json']);
|
|
488
|
+
const namedList = parse(namedResult);
|
|
489
|
+
if (!Array.isArray(namedList?.items) || !namedList.metadata || typeof namedList.metadata !== 'object'
|
|
490
|
+
|| Array.isArray(namedList.metadata)) return false;
|
|
491
|
+
const namedMatches = namedList.items.filter((row: any) => row?.metadata?.name === spec.name);
|
|
492
|
+
if (namedMatches.length > 1) return false;
|
|
493
|
+
const namedPod = namedMatches[0] ?? null;
|
|
494
|
+
|
|
495
|
+
// Kubectl's continuation token is consumed explicitly so no partial page can
|
|
496
|
+
// authorize a create. A hard page cap turns a non-terminating listing into failure.
|
|
497
|
+
const warmPods: any[] = [];
|
|
498
|
+
let continuation = '';
|
|
499
|
+
const seenContinuations = new Set<string>();
|
|
500
|
+
for (let page = 0; page < 100; page++) {
|
|
501
|
+
const args = ['get', 'pods', '-l', 'elanous.kind=warm-worker', '--limit=10', '-o', 'json'];
|
|
502
|
+
if (continuation) args.splice(5, 0, '--continue', continuation);
|
|
503
|
+
const result = kubectl(args);
|
|
504
|
+
const listed = parse(result);
|
|
505
|
+
if (!listed || !Array.isArray(listed.items) || !listed.metadata || typeof listed.metadata !== 'object'
|
|
506
|
+
|| Array.isArray(listed.metadata)
|
|
507
|
+
|| (listed.metadata.continue !== undefined && typeof listed.metadata.continue !== 'string')) return false;
|
|
508
|
+
warmPods.push(...listed.items);
|
|
509
|
+
continuation = listed.metadata?.continue ?? '';
|
|
510
|
+
if (!continuation) break;
|
|
511
|
+
if (seenContinuations.has(continuation) || page === 99) return false;
|
|
512
|
+
seenContinuations.add(continuation);
|
|
513
|
+
}
|
|
514
|
+
const hostPods = warmPods.filter((row: any) => row?.metadata?.name === spec.name
|
|
476
515
|
|| row?.metadata?.annotations?.['elanous.dev/warm-worker-id'] === spec.workerId);
|
|
516
|
+
if (namedPod && !hostPods.some((row: any) => row?.metadata?.name === spec.name)) hostPods.push(namedPod);
|
|
477
517
|
if (hostPods.length > 1) return false;
|
|
478
518
|
let pod = hostPods[0];
|
|
479
519
|
const preexisting = !!pod;
|
|
@@ -481,7 +521,7 @@ export class WarmPodProvider {
|
|
|
481
521
|
if (pod && !matches(pod)) return false;
|
|
482
522
|
// Old generations still occupy memory even when their ledger rows are quarantined.
|
|
483
523
|
// Count physical warm Pods on the pinned node before admitting a new one.
|
|
484
|
-
const physical =
|
|
524
|
+
const physical = warmPods.filter((row: any) => row?.metadata?.labels?.['elanous.kind'] === 'warm-worker'
|
|
485
525
|
&& row?.spec?.nodeName === nodeName && !row?.metadata?.deletionTimestamp
|
|
486
526
|
&& row?.status?.phase !== 'Succeeded' && row?.status?.phase !== 'Failed'
|
|
487
527
|
&& row?.spec?.containers?.[0]?.resources?.limits?.memory === spec.memoryLimit).length;
|
|
@@ -602,13 +642,77 @@ export class WarmPodProvider {
|
|
|
602
642
|
const contextFailure = probeWarmPodContext(spec.kubectlContext, this.options.kubectl);
|
|
603
643
|
if (contextFailure) { lastFallback = { command: null, transport: contextFailure }; continue; }
|
|
604
644
|
let acquired: { status: number; value: any };
|
|
645
|
+
const acquisition = this.control('/v1/leases/pod-worker', this.options.memberToken, {
|
|
646
|
+
machine: host, key: spec.key, runId: input.runId, attemptId: input.attemptId,
|
|
647
|
+
ttlMs: this.options.leaseTtlMs ?? 30 * 60_000,
|
|
648
|
+
});
|
|
649
|
+
const timedOut = Symbol('warm-acquisition-timeout');
|
|
650
|
+
let deadlineTimer: ReturnType<typeof setTimeout> | undefined;
|
|
651
|
+
let acquisitionFailed = false;
|
|
652
|
+
let acquisitionResult: typeof timedOut | { status: number; value: any };
|
|
605
653
|
try {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
654
|
+
const remainingMs = input.deadlineAt - this.now();
|
|
655
|
+
if (remainingMs <= 0) acquisitionResult = timedOut;
|
|
656
|
+
else acquisitionResult = await Promise.race([acquisition, new Promise<typeof timedOut>(resolve => {
|
|
657
|
+
deadlineTimer = setTimeout(() => resolve(timedOut), remainingMs);
|
|
658
|
+
})]);
|
|
659
|
+
} catch { acquisitionFailed = true; acquisitionResult = timedOut; }
|
|
660
|
+
finally { if (deadlineTimer) clearTimeout(deadlineTimer); }
|
|
661
|
+
if (acquisitionResult === timedOut) {
|
|
662
|
+
void acquisition.then(async late => {
|
|
663
|
+
const row = late.value;
|
|
664
|
+
const lateWorkerId = row?.name;
|
|
665
|
+
const leaseId = row?.attrs?.leaseId;
|
|
666
|
+
const generation = row?.attrs?.generation;
|
|
667
|
+
const podUid = row?.attrs?.podUid;
|
|
668
|
+
const lateCandidate = this.candidates.find(candidate => candidate.spec.workerId === lateWorkerId
|
|
669
|
+
&& candidate.host === host && keyEquals(candidate.spec.key, spec.key));
|
|
670
|
+
if (late.status !== 200 || !lateCandidate || !row?.attrs?.key || !keyEquals(row.attrs.key, lateCandidate.spec.key)
|
|
671
|
+
|| typeof leaseId !== 'string' || !leaseId
|
|
672
|
+
|| !Number.isSafeInteger(generation) || typeof podUid !== 'string' || !podUid) return;
|
|
673
|
+
const lateSpec = lateCandidate.spec;
|
|
674
|
+
const command: WarmWorkerCommand = { ...input, leaseId, generation, podUid,
|
|
675
|
+
podName: lateSpec.name, podContext: lateSpec.kubectlContext, image: lateSpec.image,
|
|
676
|
+
requestedAt: new Date(this.now()).toISOString(), workerId: lateSpec.workerId, key: lateSpec.key };
|
|
677
|
+
debug.log('pod.warm', 'lease-response-after-deadline', { workerId: command.workerId,
|
|
678
|
+
leaseId, generation, podUid, runId: command.runId, attemptId: command.attemptId }, { level: 'warn' });
|
|
679
|
+
debug.log('pod.provenance', 'lease-start', { pod: lateSpec.name, podUid, leaseId,
|
|
680
|
+
runId: command.runId, attemptId: command.attemptId, requestedAt: command.requestedAt,
|
|
681
|
+
metadata: warmLeaseMetadata(command).annotations });
|
|
682
|
+
try {
|
|
683
|
+
const fenced = await this.controlBounded(`/v1/leases/pod-worker/${encodeURIComponent(lateWorkerId)}/timeout`,
|
|
684
|
+
this.options.memberToken, { runId: input.runId, attemptId: input.attemptId }, WARM_CONTROL_REQUEST_TIMEOUT_MS);
|
|
685
|
+
if (fenced.status !== 200) throw new Error(`warm timeout fence returned ${fenced.status}`);
|
|
686
|
+
} catch (error) { debug.log('pod.warm', 'late-lease-timeout-fence-failed', { workerId: lateWorkerId,
|
|
687
|
+
leaseId, generation, error: String(error) }, { level: 'warn' }); }
|
|
688
|
+
let quarantineTimer: ReturnType<typeof setTimeout> | undefined;
|
|
689
|
+
try {
|
|
690
|
+
await Promise.race([this.quarantine(command, 'lease-response-after-deadline'), new Promise<never>((_, reject) => {
|
|
691
|
+
quarantineTimer = setTimeout(() => reject(new Error('warm late-lease quarantine timed out')), WARM_CONTROL_REQUEST_TIMEOUT_MS);
|
|
692
|
+
})]);
|
|
693
|
+
}
|
|
694
|
+
catch (error) { debug.log('pod.warm', 'late-lease-quarantine-failed', { workerId: command.workerId,
|
|
695
|
+
leaseId, generation, error: String(error) }, { level: 'warn' }); }
|
|
696
|
+
finally { if (quarantineTimer) clearTimeout(quarantineTimer); }
|
|
697
|
+
}, error => debug.log('pod.warm', 'late-lease-response-failed', { workerId: spec.workerId,
|
|
698
|
+
runId: input.runId, attemptId: input.attemptId, error: String(error) }, { level: 'warn' }));
|
|
699
|
+
if (acquisitionFailed) continue;
|
|
700
|
+
return fallback('lease-unavailable');
|
|
701
|
+
}
|
|
702
|
+
acquired = acquisitionResult;
|
|
611
703
|
if (acquired.status === 409 || acquired.status === 503) {
|
|
704
|
+
if (acquired.status === 409) {
|
|
705
|
+
try {
|
|
706
|
+
const query = new URLSearchParams({ kind: 'pod-worker-lease', machine: host, name: spec.workerId });
|
|
707
|
+
const observed = await this.control(`/v1/resources?${query}`, this.options.memberToken);
|
|
708
|
+
const row = observed.status === 200 && Array.isArray(observed.value?.resources)
|
|
709
|
+
? observed.value.resources.find((entry: any) => entry?.name === spec.workerId) : undefined;
|
|
710
|
+
if (row?.attrs?.state === 'quarantined' || row?.attrs?.state === 'timeout-fenced') {
|
|
711
|
+
debug.log('pod.warm', 'quarantine-holds-slot', { workerId: spec.workerId,
|
|
712
|
+
state: row.attrs.state, at: new Date(this.now()).toISOString() }, { level: 'warn' });
|
|
713
|
+
}
|
|
714
|
+
} catch { /* Slot observation never changes the Job's cold fallback. */ }
|
|
715
|
+
}
|
|
612
716
|
lastFallback = fallback('lease-unavailable');
|
|
613
717
|
continue;
|
|
614
718
|
}
|
|
@@ -620,6 +724,16 @@ export class WarmPodProvider {
|
|
|
620
724
|
if (!workerId(row?.name) || typeof leasedId !== 'string' || !leasedId
|
|
621
725
|
|| typeof podUid !== 'string' || !podUid
|
|
622
726
|
|| !Number.isSafeInteger(generation) || generation < 1) return fallback('lease-unavailable');
|
|
727
|
+
// One terminal transition per workerId·leaseId·generation·Pod UID. A lease the
|
|
728
|
+
// control plane already settled (finalize/quarantine raced this acquisition)
|
|
729
|
+
// must never be re-adopted — not by this late reply, not by the next warm request.
|
|
730
|
+
// An uncertain ending keeps its quarantined / cold-Job verdict.
|
|
731
|
+
const terminalKey = JSON.stringify([row.name, leasedId, generation, podUid]);
|
|
732
|
+
if (this.terminalLeases.has(terminalKey) || this.quarantineRequested.has(terminalKey)) {
|
|
733
|
+
debug.log('pod.warm', 'lease-terminal-refused', { workerId: row.name, leaseId: leasedId,
|
|
734
|
+
generation, podUid, runId: input.runId, attemptId: input.attemptId }, { level: 'warn' });
|
|
735
|
+
return fallback('lease-unavailable');
|
|
736
|
+
}
|
|
623
737
|
// Acquisition selects by host/key, not by worker ID. Resolve the returned worker
|
|
624
738
|
// before choosing its transport; an unknown worker must not be executed or fenced.
|
|
625
739
|
const leasedCandidate = this.candidates.find(entry => entry.host === host
|
|
@@ -641,6 +755,20 @@ export class WarmPodProvider {
|
|
|
641
755
|
podName: leasedCandidate.spec.name, podContext: leasedCandidate.spec.kubectlContext, image: leasedCandidate.spec.image,
|
|
642
756
|
requestedAt: new Date(this.now()).toISOString(),
|
|
643
757
|
workerId: row.name, key: leasedCandidate.spec.key };
|
|
758
|
+
if (command.deadlineAt <= this.now()) {
|
|
759
|
+
debug.log('pod.warm', 'lease-response-after-deadline', { workerId: command.workerId,
|
|
760
|
+
leaseId: command.leaseId, generation: command.generation, podUid: command.podUid,
|
|
761
|
+
runId: command.runId, attemptId: command.attemptId }, { level: 'warn' });
|
|
762
|
+
// The control plane granted a lease, even though the caller's budget expired before Pod adoption.
|
|
763
|
+
// Record its short lifetime as a paired start/end and quarantine it without running transport.
|
|
764
|
+
debug.log('pod.provenance', 'lease-start', { pod: leasedCandidate.spec.name, podUid: command.podUid,
|
|
765
|
+
leaseId: command.leaseId, runId: command.runId, attemptId: command.attemptId,
|
|
766
|
+
requestedAt: command.requestedAt, metadata: warmLeaseMetadata(command).annotations });
|
|
767
|
+
try { await this.quarantine(command, 'lease-response-after-deadline'); }
|
|
768
|
+
catch (error) { debug.log('pod.warm', 'late-lease-quarantine-failed', { workerId: command.workerId,
|
|
769
|
+
leaseId: command.leaseId, generation: command.generation, error: String(error) }, { level: 'warn' }); }
|
|
770
|
+
return fallback('lease-unavailable');
|
|
771
|
+
}
|
|
644
772
|
// Acquisition is by pool key. A healthy sibling or replacement Pod must remain eligible.
|
|
645
773
|
// Never run transport on the old Pod while its previous lease is being quarantined.
|
|
646
774
|
if (this.quarantiningPods.has(JSON.stringify([command.workerId, command.podUid]))) {
|
|
@@ -710,20 +838,26 @@ export class WarmPodProvider {
|
|
|
710
838
|
}
|
|
711
839
|
|
|
712
840
|
private async finalizeOnce(command: WarmWorkerCommand): Promise<'sanitized' | 'quarantined'> {
|
|
841
|
+
const key = JSON.stringify([command.workerId, command.leaseId, command.generation, command.podUid]);
|
|
713
842
|
const candidate = this.candidates.find(row => row.spec.workerId === command.workerId);
|
|
714
843
|
if (!candidate) throw new Error('warm finalize candidate missing');
|
|
715
844
|
const released = await this.transition(command, 'release');
|
|
716
845
|
const machineToken = this.options.machineTokens?.[candidate.host];
|
|
717
846
|
// Sanitizing is the producer's machine-scoped acknowledgement, after transport's cleanup and ACK.
|
|
718
|
-
|
|
847
|
+
// Always verify and clear this exact Pod UID/lease metadata before telling the control plane it is reusable.
|
|
848
|
+
// A missing local adoption record is not evidence that no pod-side leased state exists.
|
|
849
|
+
const cleared = released
|
|
850
|
+
? patchWarmLeaseMetadata(candidate.spec, command, 'idle', this.options.kubectl)
|
|
719
851
|
: { ok: false, reason: 'release-failed' };
|
|
720
852
|
if (!cleared.ok) debug.log('pod.provenance', 'lease-patch-refused', { pod: candidate.spec.name,
|
|
721
853
|
podUid: command.podUid, leaseId: command.leaseId, reason: cleared.reason }, { level: 'warn' });
|
|
722
854
|
if (!cleared.ok || !token(machineToken) || !await this.transition(command, 'sanitize', machineToken)) {
|
|
723
|
-
|
|
855
|
+
if (!this.quarantineRequested.has(key)) {
|
|
856
|
+
this.quarantineRequested.add(key);
|
|
857
|
+
await this.quarantineOnce(command, 'sanitize-unavailable', true);
|
|
858
|
+
}
|
|
724
859
|
return 'quarantined';
|
|
725
860
|
}
|
|
726
|
-
const key = JSON.stringify([command.workerId, command.leaseId, command.generation, command.podUid]);
|
|
727
861
|
if (!this.quarantineRequested.has(key)) {
|
|
728
862
|
debug.log('pod.provenance', 'lease-end', { pod: candidate.spec.name, podUid: command.podUid,
|
|
729
863
|
leaseId: command.leaseId, runId: command.runId, attemptId: command.attemptId,
|
|
@@ -740,19 +874,21 @@ export class WarmPodProvider {
|
|
|
740
874
|
this.quarantiningPods.add(podKey);
|
|
741
875
|
const prior = this.terminalLeases.get(key);
|
|
742
876
|
if (prior) {
|
|
877
|
+
if (this.quarantineRequested.has(key)) {
|
|
878
|
+
try { await prior; this.quarantiningPods.delete(podKey); }
|
|
879
|
+
catch (error) { if (this.terminalLeases.get(key) === prior) this.terminalLeases.delete(key); throw error; }
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
743
882
|
this.quarantineRequested.add(key);
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
return 'quarantined' as const;
|
|
748
|
-
}
|
|
749
|
-
return outcome;
|
|
750
|
-
});
|
|
883
|
+
// Fence the control-plane lease immediately. Waiting for sanitize to settle leaves a window
|
|
884
|
+
// where another request could acquire the just-idled worker before this quarantine lands.
|
|
885
|
+
const terminal = this.quarantineOnce(command, reason, leaseStarted).then(() => 'quarantined' as const);
|
|
751
886
|
this.terminalLeases.set(key, terminal);
|
|
752
887
|
try { await terminal; this.quarantiningPods.delete(podKey); }
|
|
753
888
|
catch (error) { if (this.terminalLeases.get(key) === terminal) this.terminalLeases.delete(key); throw error; }
|
|
754
889
|
return;
|
|
755
890
|
}
|
|
891
|
+
this.quarantineRequested.add(key);
|
|
756
892
|
const terminal = this.quarantineOnce(command, reason, leaseStarted).then(() => 'quarantined' as const);
|
|
757
893
|
this.terminalLeases.set(key, terminal);
|
|
758
894
|
try { await terminal; this.quarantiningPods.delete(podKey); }
|
|
@@ -783,7 +919,11 @@ let configuredProvider: WarmPodProvider | null = null;
|
|
|
783
919
|
/** The trusted producer configures this once; an absent provider fails closed without creating a Pod. */
|
|
784
920
|
export function configureWarmPodProvider(provider: WarmPodProvider | null): void { configuredProvider = provider; }
|
|
785
921
|
/** Optional private producer config; a missing/unsafe file leaves the Job path untouched. */
|
|
786
|
-
export function loadWarmPodProvider(path: string,
|
|
922
|
+
export function loadWarmPodProvider(path: string, pairingGateFileOrOptions?: string | WarmPodProviderLoadOptions): WarmPodProvider {
|
|
923
|
+
const pairingGateFile = typeof pairingGateFileOrOptions === 'string'
|
|
924
|
+
? pairingGateFileOrOptions : pairingGateFileOrOptions?.pairingGateFile;
|
|
925
|
+
const runtimeOverrides = typeof pairingGateFileOrOptions === 'object'
|
|
926
|
+
? pairingGateFileOrOptions?.runtimeOverrides ?? {} : {};
|
|
787
927
|
if (!isAbsolute(path) || (statSync(path).mode & 0o077) !== 0) throw new Error('warm provider config must be private');
|
|
788
928
|
const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'));
|
|
789
929
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid warm provider config');
|
|
@@ -797,7 +937,7 @@ export function loadWarmPodProvider(path: string, pairingGateFile?: string): War
|
|
|
797
937
|
if (!pairingGateFile.trim()) throw new Error('warm provider pairing gate file must not be empty');
|
|
798
938
|
options.pairingGateFile = pairingGateFile;
|
|
799
939
|
}
|
|
800
|
-
return new WarmPodProvider(options);
|
|
940
|
+
return new WarmPodProvider({ ...options, ...runtimeOverrides });
|
|
801
941
|
}
|
|
802
942
|
function currentProvider(): WarmPodProvider | null {
|
|
803
943
|
if (configuredProvider) return configuredProvider;
|
|
@@ -851,35 +991,55 @@ export function parseWarmPodProviderArgs(argv: readonly string[]): { action: '--
|
|
|
851
991
|
throw usage();
|
|
852
992
|
}
|
|
853
993
|
|
|
854
|
-
|
|
855
|
-
|
|
994
|
+
export interface WarmPodProviderCliDependencies {
|
|
995
|
+
providerRuntime?: Partial<WarmPodProviderRuntimeOverrides>;
|
|
996
|
+
write?: (line: string) => void;
|
|
997
|
+
registerLogSink?: (name: string) => Promise<void>;
|
|
998
|
+
sleep?: (milliseconds: number) => Promise<void>;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
export async function runWarmPodProviderCli(argv: readonly string[] = process.argv.slice(2),
|
|
1002
|
+
dependencies: WarmPodProviderCliDependencies = {}): Promise<{
|
|
1003
|
+
exitCode: number;
|
|
1004
|
+
result?: WarmPoolReconcileResult | null;
|
|
1005
|
+
prepared?: boolean;
|
|
1006
|
+
}> {
|
|
1007
|
+
const { action, workerId, gateFile } = parseWarmPodProviderArgs(argv);
|
|
1008
|
+
const write = dependencies.write ?? ((line: string) => { process.stdout.write(line); });
|
|
856
1009
|
const file = process.env.ELANOUS_WARM_POD_PROVIDER_CONFIG;
|
|
857
1010
|
// The 1-file gate key this pool serves, bound into every cold prepare leg of this process.
|
|
858
|
-
const load = () =>
|
|
1011
|
+
const load = () => {
|
|
1012
|
+
if (!file) return null;
|
|
1013
|
+
return loadWarmPodProvider(file, { pairingGateFile: gateFile, runtimeOverrides: dependencies.providerRuntime });
|
|
1014
|
+
};
|
|
859
1015
|
if (action === '--pairs') {
|
|
860
1016
|
// Read-only: join the cold CLI legs and the warm gate legs both processes wrote to logs.db.
|
|
861
1017
|
try {
|
|
862
1018
|
const storeMod = await import('../../mss/logging/log-store.js');
|
|
863
1019
|
const dbPath = storeMod.logsDbPath();
|
|
864
1020
|
// No logs.db yet means no leg was ever measured: an empty pair list, not a failed query.
|
|
865
|
-
if (!existsSync(dbPath))
|
|
1021
|
+
if (!existsSync(dbPath)) write(JSON.stringify({ warmReuseTimePairs: [] }) + '\n');
|
|
866
1022
|
else {
|
|
867
1023
|
const store = storeMod.LogStore.openReadOnly(dbPath);
|
|
868
|
-
try {
|
|
1024
|
+
try { write(JSON.stringify({ warmReuseTimePairs: readWarmReuseTimePairs(store) }) + '\n'); }
|
|
869
1025
|
finally { store.close(); }
|
|
870
1026
|
}
|
|
871
1027
|
} catch (error) {
|
|
872
|
-
|
|
873
|
-
|
|
1028
|
+
write(JSON.stringify({ warmReuseTimePairs: null, reason: 'logs-unavailable', detail: String(error) }) + '\n');
|
|
1029
|
+
return { exitCode: 2 };
|
|
874
1030
|
}
|
|
1031
|
+
return { exitCode: 0 };
|
|
875
1032
|
}
|
|
876
1033
|
// The cold legs must reach the same logs.db the warm gate process (gate-node) writes; fail-open.
|
|
877
|
-
|
|
1034
|
+
try {
|
|
1035
|
+
if (dependencies.registerLogSink) await dependencies.registerLogSink('pod-warm');
|
|
1036
|
+
else await (await import('../../domains/standalone-log-sink.js')).registerStandaloneLogSink('pod-warm');
|
|
1037
|
+
}
|
|
878
1038
|
catch { /* the file trail stays the source of truth */ }
|
|
879
1039
|
// This process's own legs, echoed for the caller; the pair itself is read with --pairs.
|
|
880
1040
|
const emitPairs = (provider: WarmPodProvider) => {
|
|
881
1041
|
const legs = provider.warmReuseTimeLegs();
|
|
882
|
-
if (legs.length)
|
|
1042
|
+
if (legs.length) write(JSON.stringify({ warmReuseTimeLegs: legs }) + '\n');
|
|
883
1043
|
};
|
|
884
1044
|
if (action === '--serve') {
|
|
885
1045
|
// Reloading the private config lets the owner rotate a quarantined slot to a new worker ID.
|
|
@@ -888,30 +1048,40 @@ if (import.meta.main) {
|
|
|
888
1048
|
try {
|
|
889
1049
|
const provider = load();
|
|
890
1050
|
const result = provider ? await provider.reconcilePool() : null;
|
|
891
|
-
|
|
1051
|
+
write(JSON.stringify(result ?? { target: 0, ready: 0, failed: ['config-unavailable'] }) + '\n');
|
|
892
1052
|
if (provider) emitPairs(provider);
|
|
893
1053
|
} catch {
|
|
894
1054
|
debug.log('pod.warm', 'pool-reconcile-unavailable', { reason: 'config-unavailable' }, { level: 'warn' });
|
|
895
|
-
|
|
1055
|
+
write(JSON.stringify({ target: 0, ready: 0, failed: ['config-unavailable'] }) + '\n');
|
|
896
1056
|
}
|
|
897
|
-
await Bun.sleep(60_000);
|
|
1057
|
+
await (dependencies.sleep ?? Bun.sleep)(60_000);
|
|
898
1058
|
}
|
|
1059
|
+
return { exitCode: 0 };
|
|
899
1060
|
}
|
|
900
1061
|
if (action === '--reconcile') {
|
|
901
1062
|
let result: WarmPoolReconcileResult | null = null;
|
|
902
1063
|
let provider: WarmPodProvider | null = null;
|
|
903
1064
|
try { provider = load(); result = provider ? await provider.reconcilePool() : null; }
|
|
904
1065
|
catch { /* An invalid private config is a failed pass, never a Pod mutation. */ }
|
|
905
|
-
|
|
1066
|
+
write(JSON.stringify(result ?? { target: 0, ready: 0, failed: ['config-unavailable'] }) + '\n');
|
|
906
1067
|
if (provider) emitPairs(provider);
|
|
907
|
-
|
|
1068
|
+
return { exitCode: !result || result.ready !== result.target ? 2 : 0, result };
|
|
908
1069
|
} else if (action === '--prepare') {
|
|
909
1070
|
let prepared = false;
|
|
910
1071
|
let provider: WarmPodProvider | null = null;
|
|
911
1072
|
try { provider = load(); prepared = provider ? await provider.prepareWorker(workerId!) : false; }
|
|
912
1073
|
catch { /* An invalid private config is a failed preparation, never a Pod mutation. */ }
|
|
913
|
-
|
|
1074
|
+
write(JSON.stringify({ workerId, prepared }) + '\n');
|
|
914
1075
|
if (provider) emitPairs(provider);
|
|
915
|
-
|
|
1076
|
+
return { exitCode: prepared ? 0 : 2, prepared };
|
|
1077
|
+
}
|
|
1078
|
+
return { exitCode: 2 };
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
if (import.meta.main) {
|
|
1082
|
+
try { process.exitCode = (await runWarmPodProviderCli()).exitCode; }
|
|
1083
|
+
catch (error) {
|
|
1084
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1085
|
+
process.exitCode = 2;
|
|
916
1086
|
}
|
|
917
1087
|
}
|
|
@@ -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
|
}
|