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
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
elanous 0.2.41 · owner · daemon: online
|
|
2
|
+
┌─ Dashboard help ─────────────────────────────────────────────┐
|
|
3
|
+
│ Commands │
|
|
4
|
+
│ ▸ 대화 │
|
|
5
|
+
│ /help 이 명령들 목록 │
|
|
6
|
+
│ /new 새 대화 시작 │
|
|
7
|
+
│ /quit 종료 │
|
|
8
|
+
│ ▸ 지시 │
|
|
9
|
+
│ /directive 대표 지시 │
|
|
10
|
+
│ /decide 결정 요청 │
|
|
11
|
+
│ ▸ 작업 │
|
|
12
|
+
│ /missions 미션 목록 │
|
|
13
|
+
│ /tasks 작업 목록 │
|
|
14
|
+
│ /review 리뷰 열기 │
|
|
15
|
+
│ /publish 발행 │
|
|
16
|
+
│ ▸ 시스템 │
|
|
17
|
+
│ /provider LLM 공급자 │
|
|
18
|
+
│ /model 모델 │
|
|
19
|
+
│ /settings 설정 │
|
|
20
|
+
│ │
|
|
21
|
+
│ Keys │
|
|
22
|
+
│ Enter 메시지 보내기 │
|
|
23
|
+
│ Ctrl+C 입력 지움 · 두 번 누르면 나갑니다 │
|
|
24
|
+
│ Esc 도움말 닫기 │
|
|
25
|
+
│ PgUp/PgDn 스크롤 │
|
|
26
|
+
└──────────────────────────────────────────────────────────────┘
|
|
@@ -27,33 +27,46 @@ const HINT = /한 번 더 누르면 나갑니다/;
|
|
|
27
27
|
const ok = (reason: string): Verdict => ({ ok: true, reason });
|
|
28
28
|
const no = (reason: string): Verdict => ({ ok: false, reason });
|
|
29
29
|
|
|
30
|
-
/** The
|
|
30
|
+
/** The TUI draws panels with box/block borders (box drawing and block elements, U+2500–U+259F) — a judge must read
|
|
31
|
+
* the same «content lines» whether a screen renders a plain list or a bordered panel (0.2.41 incident:
|
|
32
|
+
* R6 warned on the healthy «│Keys …│» screen). Border characters become spaces, so a line keeps its
|
|
33
|
+
* own indentation, and a line left with nothing but whitespace was the frame itself and is dropped. */
|
|
34
|
+
export function contentLines(screen: string): string[] {
|
|
35
|
+
return screen
|
|
36
|
+
.split('\n')
|
|
37
|
+
.map((line) => line.replace(/[\u2500-\u259F]/g, ' '))
|
|
38
|
+
.filter((line) => line.trim().length > 0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The input row: the last content line that starts with the prompt marker. */
|
|
31
42
|
export function inputRow(screen: string): string | undefined {
|
|
32
|
-
return screen
|
|
43
|
+
return contentLines(screen).filter((line) => line.trimStart().startsWith('❯')).at(-1);
|
|
33
44
|
}
|
|
34
45
|
|
|
35
|
-
/** Palette entries visible after typing a slash prefix (lines other than the input row that show `/name`). */
|
|
46
|
+
/** Palette entries visible after typing a slash prefix (content lines other than the input row that show `/name`). */
|
|
36
47
|
export function paletteHas(screen: string, name: string): boolean {
|
|
48
|
+
const lines = contentLines(screen);
|
|
37
49
|
const row = inputRow(screen);
|
|
38
|
-
return
|
|
50
|
+
return lines.some((line) => line !== row && line.includes(`/${name}`));
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
export function judgeFirstScreen(screen: string): Verdict {
|
|
42
|
-
|
|
54
|
+
const lines = contentLines(screen);
|
|
55
|
+
if (lines.some((line) => /Step 1/.test(line))) return no('«Step 1» 마법사가 떴다');
|
|
43
56
|
if (!inputRow(screen)) return no('입력칸 «❯» 가 없다');
|
|
44
57
|
return ok('입력칸이 보이고 «Step 1» 이 없다');
|
|
45
58
|
}
|
|
46
59
|
|
|
47
60
|
export function judgeHintAppearsThenClears(armed: string, later: string): Verdict {
|
|
48
|
-
if (!HINT.test(
|
|
49
|
-
if (HINT.test(
|
|
61
|
+
if (!contentLines(armed).some((line) => HINT.test(line))) return no('빈 입력 Ctrl+C 뒤 안내가 안 보인다');
|
|
62
|
+
if (contentLines(later).some((line) => HINT.test(line))) return no('2.6초 뒤에도 안내가 남아 있다');
|
|
50
63
|
return ok('안내가 떴다가 2초 뒤 사라졌다');
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
export function judgeCtrlCClearsText(typed: string, after: string, text: string): Verdict {
|
|
54
67
|
if (!(inputRow(typed) ?? '').includes(text)) return no('친 글이 입력칸에 안 보인다(준비 실패)');
|
|
55
68
|
if ((inputRow(after) ?? '').includes(text)) return no('Ctrl+C 뒤에도 글이 남아 있다');
|
|
56
|
-
if (HINT.test(
|
|
69
|
+
if (contentLines(after).some((line) => HINT.test(line))) return no('글을 지우는 Ctrl+C 에 나가기 안내가 떴다');
|
|
57
70
|
return ok('글이 지워지고 안내는 없다');
|
|
58
71
|
}
|
|
59
72
|
|
|
@@ -67,11 +80,18 @@ export function judgePalette(screens: Record<string, string>, expectations: Reco
|
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
/** U1b — the help is drawn (key section ⊕ a run of command rows) and the prompt survives below it.
|
|
70
|
-
* Not «the whole grid fits»: an owner sees 60+ commands, which exceed a 50-row screen and scroll (PgUp).
|
|
83
|
+
* Not «the whole grid fits»: an owner sees 60+ commands, which exceed a 50-row screen and scroll (PgUp).
|
|
84
|
+
* Border-agnostic (0.2.41 R6 오탐): judged on content lines, so the bordered «│Keys …│» panel reads
|
|
85
|
+
* like the plain list. */
|
|
71
86
|
export function judgeHelpShown(screen: string): Verdict {
|
|
72
|
-
const lines = screen
|
|
73
|
-
const
|
|
74
|
-
|
|
87
|
+
const lines = contentLines(screen);
|
|
88
|
+
const commandsAt = lines.findIndex((line) => /^\s*Commands\s*$/.test(line));
|
|
89
|
+
const keysAt = lines.findIndex((line) => /^\s*Keys\s*$/.test(line));
|
|
90
|
+
if (commandsAt < 0) return no('/help 의 Commands 절이 안 보인다');
|
|
91
|
+
if (keysAt <= commandsAt) return no('/help 의 Keys 절이 안 보인다');
|
|
92
|
+
// Count command-bearing rows only within the panel section; commands may be in either column.
|
|
93
|
+
const commandRows = lines.slice(commandsAt + 1, keysAt)
|
|
94
|
+
.filter((line) => /(?:^|\s)\/[a-z][a-z-]*(?=\s|$)/.test(line)).length;
|
|
75
95
|
if (commandRows < 10) return no(`명령 줄이 ${commandRows}개뿐이다`);
|
|
76
96
|
if (!inputRow(screen)) return no('도움말을 연 뒤 입력칸이 화면 밖으로 밀렸다');
|
|
77
97
|
return ok(`도움말이 그려졌다(명령 줄 ${commandRows} · Keys 절 · 입력칸 유지)`);
|
|
@@ -79,7 +99,7 @@ export function judgeHelpShown(screen: string): Verdict {
|
|
|
79
99
|
|
|
80
100
|
/** U1c2 — lines typed while a reply streams show up as «my» lines, in order, each above its own answer. */
|
|
81
101
|
export function judgeQueuedEcho(screen: string): Verdict {
|
|
82
|
-
const lines = screen
|
|
102
|
+
const lines = contentLines(screen);
|
|
83
103
|
const at = (re: RegExp, after = -1) => lines.findIndex((line, i) => i > after && re.test(line));
|
|
84
104
|
const u2 = at(/Q2MARK 라고만/);
|
|
85
105
|
if (u2 < 0) return no('줄 서 있던 «Q2MARK 라고만» 이 내 말로 안 보인다');
|
|
@@ -86,7 +86,7 @@ export function runAutoApprove(context: GraphContext = readGraphContext(), deps:
|
|
|
86
86
|
writeFileSync(report, lines.join('\n'));
|
|
87
87
|
const tuiSubcheck = { runId: context.runId ?? null, level: regressStatus.level,
|
|
88
88
|
fail: failedCheckIds?.length ?? null, failedCheckIds, approvalRequired: regressNeedsApproval };
|
|
89
|
-
debug.log('release-loop.approve', 'auto-decision', { version, outcome, metrics, tuiSubcheck });
|
|
89
|
+
debug.log('release-loop.approve', 'auto-decision', { version, outcome, metrics, runId: context.runId ?? null, tuiSubcheck });
|
|
90
90
|
return { outcome, verdict: outcome === 'ok' ? 'pass' as const : 'fail' as const,
|
|
91
91
|
summary: `auto approval ${outcome}: ${metrics.filter((metric) => !WARNING_ONLY.has(metric.name) && metric.verdict === 'pass').length}/8${regressNeedsApproval ? ` · tui-regress ${regressStatus.level} failed ${failedLabel} → HITL` : ''}`,
|
|
92
92
|
runId: context.runId ?? null, tuiSubcheck, ...(outcome === 'ok' ? { decidedBy: 'release-loop metrics' as const } : {}), metrics, report };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Isolated E4 evidence bridge: GATE-MOCK-EVENT-SCENARIOS fake devices plus the production
|
|
4
|
+
* runGateNode autoheal decision/log path. It never starts a release run or a real Pod.
|
|
5
|
+
*/
|
|
6
|
+
import { mkdirSync, realpathSync } from 'node:fs';
|
|
7
|
+
import { dirname, join, resolve } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { debug } from '../../src/debug/log.js';
|
|
10
|
+
import { setElanousConfigDir } from '../../src/elanous-config-dir.js';
|
|
11
|
+
import { registerStandaloneLogSink } from '../../src/domains/standalone-log-sink.js';
|
|
12
|
+
import { prodInstanceRoot } from '../../src/instance/resolve.js';
|
|
13
|
+
import { runGateNode, type GateResult } from './gate-node.js';
|
|
14
|
+
import { GATE_NODE_SIM_SCENARIOS, judgeInjectedGateEvent } from './gate-node-sim.js';
|
|
15
|
+
|
|
16
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
17
|
+
const testRoot = join(repoRoot, '.elanous-test');
|
|
18
|
+
const runId = `gate-autoheal-sim-${new Date().toISOString().replace(/[-:.TZ]/g, '')}`;
|
|
19
|
+
|
|
20
|
+
if (realpathSync(repoRoot) === realpathSync(prodInstanceRoot())) {
|
|
21
|
+
throw new Error('refusing to run evidence simulation from the production state root');
|
|
22
|
+
}
|
|
23
|
+
if (process.env.ELANOUS_STATE_DIR && resolve(process.env.ELANOUS_STATE_DIR) !== resolve(testRoot)) {
|
|
24
|
+
throw new Error(`ELANOUS_STATE_DIR must be this worktree test root: ${testRoot}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const scenario = GATE_NODE_SIM_SCENARIOS.find((item) => item.id === 'host-down-reroute');
|
|
28
|
+
if (!scenario) throw new Error('GATE-MOCK-EVENT-SCENARIOS is missing host-down-reroute');
|
|
29
|
+
const simulated = await judgeInjectedGateEvent(scenario);
|
|
30
|
+
if (simulated.outcome !== scenario.expectedOutcome || simulated.action !== scenario.action || simulated.podCommandCalls !== 0) {
|
|
31
|
+
throw new Error(`fake-device scenario did not match: ${JSON.stringify(simulated)}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
mkdirSync(testRoot, { recursive: true });
|
|
35
|
+
process.env.ELANOUS_STATE_DIR = testRoot;
|
|
36
|
+
process.env.ELANOUS_RUN_ID = runId;
|
|
37
|
+
process.env.ELANOUS_GRAPH_CONTEXT = JSON.stringify({
|
|
38
|
+
runId,
|
|
39
|
+
input: { version: '0.2.43', previousVersion: '0.2.42', commit: 'a'.repeat(40) },
|
|
40
|
+
outputs: {},
|
|
41
|
+
});
|
|
42
|
+
setElanousConfigDir(testRoot);
|
|
43
|
+
|
|
44
|
+
if (!await registerStandaloneLogSink('release-loop')) throw new Error('could not register isolated release-loop logs.db sink');
|
|
45
|
+
|
|
46
|
+
// Inject the same host-unreachable failure class through the production node's judge seam. runGateNode
|
|
47
|
+
// performs the real cause classification, budgeted decision, ledger write, and debug.log emission.
|
|
48
|
+
const injectedFailure: GateResult = {
|
|
49
|
+
outcome: 'error', commit: 'a'.repeat(40), introduced: [], preexisting: 0, fixed: 0,
|
|
50
|
+
knownEnv: 0, knownEnvCleared: [], stalledEnv: [], rcNonzeroNoFailures: [], durationMs: 1_000,
|
|
51
|
+
error: 'gate host unreachable (simulation injection)',
|
|
52
|
+
};
|
|
53
|
+
const exitCode = await runGateNode(['--json'], process.env, undefined, async () => injectedFailure);
|
|
54
|
+
if (exitCode !== 2) throw new Error(`expected injected gate error exit=2, got ${exitCode}`);
|
|
55
|
+
debug.flush();
|
|
56
|
+
|
|
57
|
+
console.log(JSON.stringify({ label: 'simulation E4', runId, scenario: scenario.id,
|
|
58
|
+
scenarioOutcome: simulated.outcome, plannerAction: simulated.action, podCommandCalls: simulated.podCommandCalls,
|
|
59
|
+
injectedCause: 'host-down', expectedAutohealAction: 'host-switch', exitCode,
|
|
60
|
+
store: join(testRoot, 'logs/logs.db') }));
|
|
@@ -24,7 +24,7 @@ export function gateAssignableTestsAtCommit(repo: string, commit: string): strin
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export interface GateBaselineReceipt {
|
|
27
|
-
schema:
|
|
27
|
+
schema: 2;
|
|
28
28
|
valid: boolean;
|
|
29
29
|
reason: string;
|
|
30
30
|
version: string;
|
|
@@ -33,11 +33,37 @@ export interface GateBaselineReceipt {
|
|
|
33
33
|
recipeSha: string | null;
|
|
34
34
|
envFingerprint: string;
|
|
35
35
|
imageDigest: string | null;
|
|
36
|
+
executionIdentity: GatePodRuntimeIdentity | null;
|
|
36
37
|
files: number;
|
|
37
38
|
shards: number;
|
|
38
39
|
attributionRecheck?: { summary: number; observed: number; identified: number; baselineResult: string; targetFiles: string[] };
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
export interface GatePodRuntimeIdentity {
|
|
43
|
+
bunVersion: string;
|
|
44
|
+
platform: string;
|
|
45
|
+
architecture: string;
|
|
46
|
+
envFingerprint: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const validRuntimeIdentity = (value: unknown): value is GatePodRuntimeIdentity => {
|
|
50
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
51
|
+
const row = value as Partial<GatePodRuntimeIdentity>;
|
|
52
|
+
return Object.keys(value).sort().join(',') === 'architecture,bunVersion,envFingerprint,platform'
|
|
53
|
+
&& typeof row.bunVersion === 'string' && /^\d+\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(row.bunVersion)
|
|
54
|
+
&& typeof row.platform === 'string' && /^[a-z0-9_-]{1,32}$/.test(row.platform)
|
|
55
|
+
&& typeof row.architecture === 'string' && /^[a-z0-9_-]{1,32}$/.test(row.architecture)
|
|
56
|
+
&& typeof row.envFingerprint === 'string' && SHA256.test(row.envFingerprint);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** Parse runtime facts written by the gate Pod before its tests start. */
|
|
60
|
+
export function parseGatePodRuntimeIdentity(text: string): GatePodRuntimeIdentity | null {
|
|
61
|
+
try {
|
|
62
|
+
const value: unknown = JSON.parse(text);
|
|
63
|
+
return validRuntimeIdentity(value) ? value : null;
|
|
64
|
+
} catch { return null; }
|
|
65
|
+
}
|
|
66
|
+
|
|
41
67
|
/** A direct hard rehearsal has no graph run state. Pin the graph and recipe bytes at its Git SHA. */
|
|
42
68
|
export function gateSourcePins(repo: string, commit: string): { graphSha: string; recipeSha: string } | null {
|
|
43
69
|
if (!/^[0-9a-f]{40}$/i.test(commit)) return null;
|
|
@@ -87,8 +113,9 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
|
|
|
87
113
|
graphPins: { graphSha: string; recipeSha: string } | null; envFingerprint: string;
|
|
88
114
|
attributionRecheck?: { summary: number; observed: number; identified: number; baselineResult: string; targetFiles: string[] } }): GateBaselineReceipt {
|
|
89
115
|
const { root, version, commit, graphPins, envFingerprint } = input;
|
|
90
|
-
const base = { schema:
|
|
91
|
-
recipeSha: graphPins?.recipeSha ?? null, envFingerprint, imageDigest: null as string | null,
|
|
116
|
+
const base = { schema: 2 as const, version, commit, graphSha: graphPins?.graphSha ?? null,
|
|
117
|
+
recipeSha: graphPins?.recipeSha ?? null, envFingerprint, imageDigest: null as string | null,
|
|
118
|
+
executionIdentity: null as GatePodRuntimeIdentity | null, files: 0, shards: 0 };
|
|
92
119
|
const invalid = (reason: string): GateBaselineReceipt => ({ ...base, valid: false, reason });
|
|
93
120
|
if (input.attributionRecheck) {
|
|
94
121
|
const evidence = input.attributionRecheck;
|
|
@@ -102,12 +129,14 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
|
|
|
102
129
|
const dir = join(root, 'release', version, 'gate-logs', 'cut');
|
|
103
130
|
if (!existsSync(dir)) return invalid('cut Pod logs absent');
|
|
104
131
|
const names = readdirSync(dir).filter((name) => /^pod-\d+(?:-[\w-]+)?\.json$/.test(name));
|
|
105
|
-
const roots = new Map<number, { files: string[]; shardCount: number; sweepId: string; attemptId: string }>();
|
|
106
|
-
const descendants: Array<{ name: string; commit?: string; imageDigest?: string; sweepId?: string; parentAttempt?: string; attemptId?: string }> = [];
|
|
132
|
+
const roots = new Map<number, { files: string[]; shardCount: number; sweepId: string; attemptId: string; runtimeIdentity?: GatePodRuntimeIdentity }>();
|
|
133
|
+
const descendants: Array<{ name: string; commit?: string; imageDigest?: string; sweepId?: string; parentAttempt?: string; attemptId?: string; runtimeIdentity?: GatePodRuntimeIdentity }> = [];
|
|
107
134
|
const images = new Set<string>();
|
|
135
|
+
const identities = new Map<string, GatePodRuntimeIdentity>();
|
|
108
136
|
for (const name of names) {
|
|
109
137
|
const row = JSON.parse(readFileSync(join(dir, name), 'utf8')) as
|
|
110
|
-
{ commit?: string; files?: unknown; shardCount?: number; sweepId?: string; imageDigest?: string; parentAttempt?: string; attemptId?: string };
|
|
138
|
+
{ commit?: string; files?: unknown; shardCount?: number; sweepId?: string; imageDigest?: string; parentAttempt?: string; attemptId?: string; runtimeIdentity?: unknown };
|
|
139
|
+
const runtimeIdentity = validRuntimeIdentity(row.runtimeIdentity) ? row.runtimeIdentity : undefined;
|
|
111
140
|
const match = /^pod-(\d+)\.json$/.exec(name);
|
|
112
141
|
if (match) {
|
|
113
142
|
if (row.commit !== commit) return invalid(`root cut Pod ${name} belongs to another commit`);
|
|
@@ -115,12 +144,16 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
|
|
|
115
144
|
return invalid(`root cut Pod ${name} has no file list`);
|
|
116
145
|
if (!row.attemptId) return invalid(`root cut Pod ${name} has no attempt`);
|
|
117
146
|
if (!row.sweepId) return invalid(`root cut Pod ${name} has no sweep identity`);
|
|
118
|
-
roots.set(Number(match[1]), { files: row.files as string[], shardCount: row.shardCount ?? 0,
|
|
147
|
+
roots.set(Number(match[1]), { files: row.files as string[], shardCount: row.shardCount ?? 0,
|
|
148
|
+
sweepId: row.sweepId, attemptId: row.attemptId, runtimeIdentity });
|
|
119
149
|
} else descendants.push({ name, commit: row.commit, imageDigest: row.imageDigest, sweepId: row.sweepId,
|
|
120
|
-
parentAttempt: row.parentAttempt, attemptId: row.attemptId });
|
|
150
|
+
parentAttempt: row.parentAttempt, attemptId: row.attemptId, runtimeIdentity });
|
|
121
151
|
if (match) {
|
|
122
152
|
if (!row.imageDigest || !IMAGE_DIGEST.test(row.imageDigest)) return invalid(`actual Pod image digest absent: ${name}`);
|
|
153
|
+
if (!runtimeIdentity) return invalid(`actual Pod runtime identity absent: ${name}`);
|
|
154
|
+
if (runtimeIdentity.envFingerprint !== envFingerprint) return invalid(`actual Pod environment differs: ${name}`);
|
|
123
155
|
images.add(row.imageDigest.toLowerCase());
|
|
156
|
+
identities.set(JSON.stringify(runtimeIdentity), runtimeIdentity);
|
|
124
157
|
}
|
|
125
158
|
}
|
|
126
159
|
if (!roots.size) return invalid('root cut shards absent');
|
|
@@ -144,7 +177,10 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
|
|
|
144
177
|
if (row.sweepId !== sweepId) return invalid(`cut Pod ${row.name} belongs to another sweep`);
|
|
145
178
|
if (!row.imageDigest || !IMAGE_DIGEST.test(row.imageDigest)) return invalid(`actual Pod image digest absent: ${row.name}`);
|
|
146
179
|
if (!row.attemptId) return invalid(`cut Pod ${row.name} has no attempt`);
|
|
180
|
+
if (!row.runtimeIdentity) return invalid(`actual Pod runtime identity absent: ${row.name}`);
|
|
181
|
+
if (row.runtimeIdentity.envFingerprint !== envFingerprint) return invalid(`actual Pod environment differs: ${row.name}`);
|
|
147
182
|
images.add(row.imageDigest.toLowerCase());
|
|
183
|
+
identities.set(JSON.stringify(row.runtimeIdentity), row.runtimeIdentity);
|
|
148
184
|
attempts.add(row.attemptId);
|
|
149
185
|
}
|
|
150
186
|
pending = next;
|
|
@@ -157,6 +193,8 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
|
|
|
157
193
|
if (row.commit === commit && !row.sweepId) return invalid(`cut Pod ${row.name} has no sweep identity`);
|
|
158
194
|
}
|
|
159
195
|
if (images.size !== 1) return invalid('cut Pods used different image digests');
|
|
160
|
-
|
|
196
|
+
if (identities.size !== 1) return invalid('cut Pods used different runtime identities');
|
|
197
|
+
return { ...base, valid: true, reason: 'complete clean full sweep', imageDigest: [...images][0]!,
|
|
198
|
+
executionIdentity: identities.values().next().value!, files: files.length, shards: count };
|
|
161
199
|
} catch (error) { return invalid(`cut Pod evidence unreadable: ${String(error)}`); }
|
|
162
200
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/** A gate run may execute only against one immutable image identity and its exact source tag. */
|
|
5
|
+
export interface GateImagePin { runId: string; digest: string; image: string; commit: string }
|
|
6
|
+
|
|
7
|
+
export type GateImagePinResolution =
|
|
8
|
+
| { ok: true; digest: string; eligiblePools: string[] }
|
|
9
|
+
| { ok: false; reason: 'saved-image-digest-invalid' | 'initial-image-digest-invalid' | 'initial-image-digest-missing' | 'pinned-image-unavailable' };
|
|
10
|
+
|
|
11
|
+
export interface ResolveGateImagePinOptions {
|
|
12
|
+
/** Persisted at the run boundary; takes precedence over any newly probed default. */
|
|
13
|
+
savedDigest?: string | null;
|
|
14
|
+
/** Used only to create the pin for a new run. */
|
|
15
|
+
initialDigest?: string | null;
|
|
16
|
+
/** Exact immutable digest selected by the gate image probe in each pool. */
|
|
17
|
+
poolImages: ReadonlyMap<string, readonly string[]>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeGateImageDigest(value: unknown): string | null {
|
|
21
|
+
if (typeof value !== 'string' || !/^sha256:[a-f0-9]{64}$/i.test(value.trim())) return null;
|
|
22
|
+
return value.trim().toLowerCase();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the durable run pin and fail closed unless at least one pool can prove it has that exact image.
|
|
27
|
+
* Callers must filter placement to `eligiblePools`; a mutable tag is never a substitute.
|
|
28
|
+
*/
|
|
29
|
+
export function resolveGateImagePin(options: ResolveGateImagePinOptions): GateImagePinResolution {
|
|
30
|
+
const hasSaved = options.savedDigest !== undefined && options.savedDigest !== null;
|
|
31
|
+
const rawDigest = hasSaved ? options.savedDigest : options.initialDigest;
|
|
32
|
+
if (!hasSaved && (rawDigest === undefined || rawDigest === null || rawDigest.trim() === '')) {
|
|
33
|
+
return { ok: false, reason: 'initial-image-digest-missing' };
|
|
34
|
+
}
|
|
35
|
+
const digest = normalizeGateImageDigest(rawDigest);
|
|
36
|
+
if (!digest) return { ok: false, reason: hasSaved ? 'saved-image-digest-invalid' : 'initial-image-digest-invalid' };
|
|
37
|
+
const eligiblePools = [...options.poolImages]
|
|
38
|
+
.filter(([, images]) => images.some((image) => normalizeGateImageDigest(image) === digest))
|
|
39
|
+
.map(([pool]) => pool);
|
|
40
|
+
if (!eligiblePools.length) return { ok: false, reason: 'pinned-image-unavailable' };
|
|
41
|
+
return { ok: true, digest, eligiblePools };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The pin is immutable for one graph gate run; absence on resume is a hard refusal. */
|
|
45
|
+
export function readGateImagePin(path: string, expectedRunId: string, expectedImage: string, expectedCommit: string): GateImagePin | null {
|
|
46
|
+
if (!existsSync(path)) return null;
|
|
47
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8')) as { version?: unknown; runId?: unknown; digest?: unknown; image?: unknown; commit?: unknown };
|
|
48
|
+
const normalizedCommit = expectedCommit.toLowerCase();
|
|
49
|
+
if (parsed.version !== 2 || parsed.runId !== expectedRunId || parsed.image !== expectedImage || parsed.commit !== normalizedCommit
|
|
50
|
+
|| !normalizeGateImageDigest(parsed.digest))
|
|
51
|
+
throw new Error(`invalid gate image pin: ${path}`);
|
|
52
|
+
return { runId: expectedRunId, digest: normalizeGateImageDigest(parsed.digest)!, image: expectedImage, commit: normalizedCommit };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function writeGateImagePin(path: string, runId: string, digest: string, image: string, commit: string): void {
|
|
56
|
+
const normalized = normalizeGateImageDigest(digest);
|
|
57
|
+
if (!runId || !normalized || !image.trim() || !/^[0-9a-f]{40}$/i.test(commit)) throw new Error('invalid gate image pin identity');
|
|
58
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
59
|
+
const value = JSON.stringify({ version: 2, runId, digest: normalized, image, commit: commit.toLowerCase() });
|
|
60
|
+
if (existsSync(path)) {
|
|
61
|
+
const prior = JSON.parse(readFileSync(path, 'utf8')) as { runId?: unknown; digest?: unknown; image?: unknown; commit?: unknown };
|
|
62
|
+
if (prior.runId !== runId || normalizeGateImageDigest(prior.digest) !== normalized || prior.image !== image
|
|
63
|
+
|| prior.commit !== commit.toLowerCase())
|
|
64
|
+
throw new Error(`gate image pin is immutable: ${path}`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
try { writeFileSync(path, `${value}\n`, { mode: 0o600, flag: 'wx' }); }
|
|
68
|
+
catch (error) {
|
|
69
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
|
|
70
|
+
const prior = JSON.parse(readFileSync(path, 'utf8')) as { runId?: unknown; digest?: unknown; image?: unknown; commit?: unknown };
|
|
71
|
+
if (prior.runId === runId && normalizeGateImageDigest(prior.digest) === normalized && prior.image === image
|
|
72
|
+
&& prior.commit === commit.toLowerCase()) return;
|
|
73
|
+
throw new Error(`gate image pin is immutable: ${path}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function gateImagePinPath(root: string, version: string, runId: string): string {
|
|
78
|
+
if (!/^\d+\.\d+\.\d+(?:-rc\.\d+)?$/.test(version) || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(runId))
|
|
79
|
+
throw new Error('invalid gate image pin path identity');
|
|
80
|
+
return `${root.replace(/\/$/, '')}/release/${version}/gate-image-pin-${runId}.json`;
|
|
81
|
+
}
|
|
@@ -1,3 +1,142 @@
|
|
|
1
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { parse as parseYaml } from 'yaml';
|
|
4
|
+
|
|
5
|
+
export type ReleaseGateExecutor = 'pod' | 'host';
|
|
6
|
+
export interface ReleaseGateRehearsal {
|
|
7
|
+
version: string;
|
|
8
|
+
outcome: string;
|
|
9
|
+
executor?: string | null;
|
|
10
|
+
commit?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ReleaseOpsPolicy {
|
|
14
|
+
schemaVersion: 1;
|
|
15
|
+
gate: {
|
|
16
|
+
default: { executor: ReleaseGateExecutor; poolSource: 'config.release.loop.gatePodPool'; imagePin: 'cut-commit' };
|
|
17
|
+
rehearsalDecisions: Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
when: { outcome: string; executor?: string };
|
|
20
|
+
executor: ReleaseGateExecutor;
|
|
21
|
+
poolSource: 'config.release.loop.gatePodPool';
|
|
22
|
+
imagePin: 'cut-commit';
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
knownInterferences: Array<{
|
|
26
|
+
id: string;
|
|
27
|
+
observedVersion: string;
|
|
28
|
+
issue: string;
|
|
29
|
+
workaround: { executor: ReleaseGateExecutor; expiresAfterVersion: string; clearCondition: string };
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ReleaseGateMethodDecision {
|
|
34
|
+
executor: ReleaseGateExecutor;
|
|
35
|
+
pool: string;
|
|
36
|
+
imagePin: 'cut-commit';
|
|
37
|
+
decision: string;
|
|
38
|
+
rehearsalVersion: string | null;
|
|
39
|
+
expiredWorkarounds: string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const DEFAULT_RELEASE_OPS_POLICY = join(import.meta.dir, '../../packs/release-ops/policy.yaml');
|
|
43
|
+
const RELEASE_VERSION = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
|
|
44
|
+
|
|
45
|
+
function compareReleaseVersions(a: string, b: string): number {
|
|
46
|
+
if (!RELEASE_VERSION.test(a) || !RELEASE_VERSION.test(b)) throw new Error(`release policy version must be x.y.z: ${a} / ${b}`);
|
|
47
|
+
const aa = a.split('.').map(BigInt), bb = b.split('.').map(BigInt);
|
|
48
|
+
for (let i = 0; i < 3; i++) {
|
|
49
|
+
if (aa[i]! < bb[i]!) return -1;
|
|
50
|
+
if (aa[i]! > bb[i]!) return 1;
|
|
51
|
+
}
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function object(value: unknown): value is Record<string, unknown> {
|
|
56
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Read and validate the checked-in release policy. A workaround without both a clear condition and expiry is invalid. */
|
|
60
|
+
export function readReleaseOpsPolicy(path = DEFAULT_RELEASE_OPS_POLICY): ReleaseOpsPolicy {
|
|
61
|
+
const raw: unknown = parseYaml(readFileSync(path, 'utf8'));
|
|
62
|
+
if (!object(raw) || raw.schemaVersion !== 1 || !object(raw.gate) || !object(raw.gate.default)
|
|
63
|
+
|| !Array.isArray(raw.gate.rehearsalDecisions) || !Array.isArray(raw.knownInterferences)) {
|
|
64
|
+
throw new Error('release ops policy has an unsupported or incomplete schema');
|
|
65
|
+
}
|
|
66
|
+
const validExecutor = (value: unknown): value is ReleaseGateExecutor => value === 'pod' || value === 'host';
|
|
67
|
+
const checkMethod = (method: unknown): boolean =>
|
|
68
|
+
object(method) && validExecutor(method.executor) && method.poolSource === 'config.release.loop.gatePodPool' && method.imagePin === 'cut-commit';
|
|
69
|
+
if (!checkMethod(raw.gate.default)) throw new Error('release ops policy default must pin executor, config pool, and cut commit image');
|
|
70
|
+
const defaultMethod = raw.gate.default as ReleaseOpsPolicy['gate']['default'];
|
|
71
|
+
const rehearsalDecisions: ReleaseOpsPolicy['gate']['rehearsalDecisions'] = [];
|
|
72
|
+
for (const decision of raw.gate.rehearsalDecisions) {
|
|
73
|
+
if (!object(decision) || typeof decision.id !== 'string' || !decision.id.trim() || !object(decision.when)
|
|
74
|
+
|| typeof decision.when.outcome !== 'string' || (decision.when.executor !== undefined && !validExecutor(decision.when.executor))
|
|
75
|
+
|| !checkMethod(decision)) throw new Error('release ops policy has an invalid rehearsal decision');
|
|
76
|
+
const valid = decision as ReleaseOpsPolicy['gate']['rehearsalDecisions'][number];
|
|
77
|
+
rehearsalDecisions.push({ id: valid.id, when: { outcome: valid.when.outcome,
|
|
78
|
+
...(valid.when.executor !== undefined ? { executor: valid.when.executor } : {}) },
|
|
79
|
+
executor: valid.executor, poolSource: valid.poolSource, imagePin: valid.imagePin });
|
|
80
|
+
}
|
|
81
|
+
const knownInterferences: ReleaseOpsPolicy['knownInterferences'] = [];
|
|
82
|
+
for (const item of raw.knownInterferences) {
|
|
83
|
+
if (!object(item) || typeof item.id !== 'string' || !item.id.trim() || typeof item.observedVersion !== 'string'
|
|
84
|
+
|| !RELEASE_VERSION.test(item.observedVersion) || typeof item.issue !== 'string' || !item.issue.trim() || !object(item.workaround)) {
|
|
85
|
+
throw new Error('release ops policy has an invalid known interference');
|
|
86
|
+
}
|
|
87
|
+
const workaround = item.workaround;
|
|
88
|
+
if (!validExecutor(workaround.executor) || typeof workaround.expiresAfterVersion !== 'string'
|
|
89
|
+
|| !RELEASE_VERSION.test(workaround.expiresAfterVersion) || typeof workaround.clearCondition !== 'string' || !workaround.clearCondition.trim()) {
|
|
90
|
+
throw new Error('workaround must declare expiresAfterVersion and clearCondition');
|
|
91
|
+
}
|
|
92
|
+
knownInterferences.push({ id: item.id, observedVersion: item.observedVersion, issue: item.issue,
|
|
93
|
+
workaround: { executor: workaround.executor, expiresAfterVersion: workaround.expiresAfterVersion, clearCondition: workaround.clearCondition } });
|
|
94
|
+
}
|
|
95
|
+
return { schemaVersion: 1, gate: { default: defaultMethod, rehearsalDecisions }, knownInterferences };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Pick the executor from the release policy; the rehearsal can select a declared row but never create a new override. */
|
|
99
|
+
export function selectReleaseGateMethod(input: { policy: ReleaseOpsPolicy; targetVersion: string; configuredPool?: string; rehearsal?: ReleaseGateRehearsal }): ReleaseGateMethodDecision {
|
|
100
|
+
const { policy, targetVersion, configuredPool, rehearsal } = input;
|
|
101
|
+
compareReleaseVersions(targetVersion, targetVersion);
|
|
102
|
+
const method = rehearsal
|
|
103
|
+
? policy.gate.rehearsalDecisions.find((row) => row.when.outcome === rehearsal.outcome
|
|
104
|
+
&& (row.when.executor === undefined || row.when.executor === rehearsal.executor))
|
|
105
|
+
: undefined;
|
|
106
|
+
const selected = method ?? policy.gate.default;
|
|
107
|
+
const expiredWorkarounds = policy.knownInterferences.filter((item) =>
|
|
108
|
+
compareReleaseVersions(targetVersion, item.workaround.expiresAfterVersion) > 0).map((item) => item.id);
|
|
109
|
+
return { executor: selected.executor, pool: selected.executor === 'pod' && typeof configuredPool === 'string' ? configuredPool.trim() : '',
|
|
110
|
+
imagePin: selected.imagePin, decision: method?.id ?? 'policy-default', rehearsalVersion: rehearsal?.version ?? null, expiredWorkarounds };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Read the latest hard rehearsal for a published version; malformed or mismatched stamps are not evidence. */
|
|
114
|
+
export function readReleaseGateRehearsal(ledgerRoot: string, version: string): ReleaseGateRehearsal | undefined {
|
|
115
|
+
const dir = join(ledgerRoot, 'release', version, 'rehearsal');
|
|
116
|
+
let files: string[];
|
|
117
|
+
try { files = readdirSync(dir).filter((file) => /^hard-[a-z0-9-]+\.json$/.test(file)); }
|
|
118
|
+
catch { return undefined; }
|
|
119
|
+
const stamps: Array<{ endedAt: number; rehearsal?: ReleaseGateRehearsal }> = [];
|
|
120
|
+
for (const file of files) {
|
|
121
|
+
const path = join(dir, file);
|
|
122
|
+
const step = file.slice(0, -'.json'.length);
|
|
123
|
+
try {
|
|
124
|
+
const stamp = JSON.parse(readFileSync(path, 'utf8')) as Record<string, unknown>;
|
|
125
|
+
const gate = stamp.hardGate as Record<string, unknown> | undefined;
|
|
126
|
+
const endedAt = typeof stamp.endedAt === 'string' ? Date.parse(stamp.endedAt) : NaN;
|
|
127
|
+
if (stamp.version !== version || stamp.step !== step || !Number.isFinite(endedAt)) return undefined;
|
|
128
|
+
const usable = ['ok', 'regression', 'error'].includes(String(gate?.outcome))
|
|
129
|
+
&& typeof gate?.commit === 'string' && /^[a-f0-9]{40}$/i.test(gate.commit)
|
|
130
|
+
&& (gate.executor === 'pod' || gate.executor === 'host');
|
|
131
|
+
stamps.push({ endedAt, ...(usable ? { rehearsal: { version, outcome: String(gate!.outcome), executor: gate!.executor as string, commit: gate!.commit as string } } : {}) });
|
|
132
|
+
} catch { return undefined; }
|
|
133
|
+
}
|
|
134
|
+
if (!stamps.length) return undefined;
|
|
135
|
+
stamps.sort((a, b) => b.endedAt - a.endedAt);
|
|
136
|
+
if (stamps.length > 1 && stamps[0]!.endedAt === stamps[1]!.endedAt) return undefined;
|
|
137
|
+
return stamps[0]!.rehearsal;
|
|
138
|
+
}
|
|
139
|
+
|
|
1
140
|
/** File seconds are recorded on the outer testsuite of each JUnit file, not its nested describe suites. */
|
|
2
141
|
export function readJunitFileSeconds(xml: string): Map<string, number> {
|
|
3
142
|
const secondsByFile = new Map<string, number>();
|