elanous 0.2.32 → 0.2.34
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/{IVKr3AlRUVLKsw2fh7eXF → L04y73dlwKeTW-GetaTF3}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +79 -0
- package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +94 -0
- package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 1644.35dd25240ae24e4b.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 1895-60ed0e341c658bd4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 2124.ed5bf480cea7f85b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +23 -0
- package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +115 -0
- package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +8 -0
- package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 2547.dd27303624cb4da8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 2554.3b5e200f5f5cfcd6.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 2987-30cf9c2eb7b8bdd5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3541-ce3a5424ed5ad7f1.js → 3001-5a52788c813b6113.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +34 -0
- package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 3110.0a7065f25c841818.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3121.779fafe3e44612c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 3414.172ad4ca2d9b08e8.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4745.67d6f99c245af3f7.js → 3498.cf2a15a8a9e5b926.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +32 -0
- package/apps/pwa/out/_next/static/chunks/{5543.a438b8ab5a13ea47.js → 3837.722e053fb9f321ad.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +104 -0
- package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +286 -0
- package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +149 -0
- package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +148 -0
- package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +64 -0
- package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +74 -0
- package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → 4fa33ebd.21c1bd5b294496e6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 5014f970-22bef0b5210f7d60.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2112-e4efc21a6505d5bc.js → 5028-f0722e6114c313e7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2898.fd781bc7cf01a7b7.js → 5249.96a848656b582a93.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{9407.e49124dedf0f5e72.js → 5446.edf141cff9ef647d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9002.e5658224e3dc1b6f.js → 5489.ec2dd1b5272a19dc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 5576-82d3703636d5c4b9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 6086.913a69e6fa3e4a8b.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +1 -0
- package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 6740.43de73fc427c9fe2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +90 -0
- package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7005.1623d2aea78eb85f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +287 -0
- package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 7431.3051e9b8a4372d2d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{3583.a05e88cc8d594628.js → 7448.478958ffbbba0ac0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +41 -0
- package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +27 -0
- package/apps/pwa/out/_next/static/chunks/{9989.3694300e5f000b14.js → 7952.b192c31b6a0e00cc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +36 -0
- package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +1 -0
- package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 8368.014caa8de2f5af34.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 8548.036c344973968847.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 9131-fce7256c4180c4a5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +93 -0
- package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9550.d5f76828f972058c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{2534.e85ae21ad0dac829.js → 9739.8d5f36ac67a3b236.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +1 -0
- package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → 9a8cb466.cc9fc9e6e46038aa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → 9b48c871.204d5d13e7809bd0.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → abb4b98b.163e0f56e84ae35d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-8c66a3b24a745630.js → page-398c0faa173203f7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-df3445b207ceceab.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +122 -0
- package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{ebc7d829.264a0bcb6c750b50.js → ffdc3a04.b9c23c1b28dd4a96.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +1 -0
- 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 +22 -22
- 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 +21 -21
- 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 +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- 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/bin/elanous.mjs +9 -2
- package/docs/goal-context/README.md +1 -0
- package/graphs/default-loop.yaml +20 -3
- package/graphs/document-loop.yaml +21 -2
- package/graphs/implement-loop.yaml +6 -0
- package/graphs/journey/SCENARIOS.md +33 -0
- package/graphs/journey/recipes.yaml +1 -0
- package/graphs/journey/ta-journey.yaml +84 -0
- package/graphs/journey/units/author/author.yaml +20 -0
- package/graphs/journey/units/author/recipes.yaml +2 -0
- package/graphs/journey/units/green/green.yaml +20 -0
- package/graphs/journey/units/green/recipes.yaml +2 -0
- package/graphs/journey/units/pr/pr.yaml +20 -0
- package/graphs/journey/units/pr/recipes.yaml +2 -0
- package/graphs/journey/units/remember/recipes.yaml +2 -0
- package/graphs/journey/units/remember/remember.yaml +20 -0
- package/graphs/operate-loop.yaml +21 -2
- package/graphs/overlays/stop-heal-ladder.yaml +1 -1
- package/graphs/release-rehearsal/recipes.yaml +1 -1
- package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
- package/graphs/research-loop.yaml +23 -2
- package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
- package/graphs/units/dispatch-pod/recipes.yaml +14 -0
- package/graphs/units/entry/entry.yaml +50 -0
- package/graphs/units/entry/recipes.yaml +14 -0
- package/graphs/units/harvest/harvest.yaml +25 -0
- package/graphs/units/harvest/recipes.yaml +4 -0
- package/graphs/units/land/land.yaml +45 -0
- package/graphs/units/land/recipes.yaml +3 -0
- package/graphs/units/recipes.yaml +7 -0
- package/graphs/units/recover.yaml +39 -0
- package/graphs/units/reflect/recipes.yaml +3 -0
- package/graphs/units/reflect/reflect.yaml +15 -0
- package/graphs/units/task-agent-recover-review.yaml +17 -0
- package/graphs/units/task-agent-recover-wait.yaml +17 -0
- package/graphs/units/verbs/make-doc.yaml +34 -0
- package/graphs/units/verbs/recipes.yaml +33 -0
- package/graphs/units/verbs/verify.yaml +55 -0
- package/graphs/work/recipes.yaml +2 -0
- package/graphs/work/research-report.yaml +28 -0
- package/package.json +1 -1
- package/scripts/ci-typecheck-changed.ts +69 -16
- package/scripts/docs/generate-graph-anatomy.ts +19 -2
- package/scripts/graph-harvest-unit.ts +22 -0
- package/scripts/graph-units/journey-stub.ts +6 -0
- package/scripts/graph-units/land-enqueue.ts +78 -0
- package/scripts/graph-units/recover-plan.ts +15 -0
- package/scripts/graph-units/reflect-node.ts +88 -0
- package/scripts/graph-units/ta-journey-observe.ts +109 -0
- package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
- package/scripts/graph-units/verbs/verify-stage.ts +75 -0
- package/scripts/graph-units/verbs-envelope.ts +139 -0
- package/scripts/hq/standby-snapshot.ts +25 -0
- package/scripts/public-export.ts +43 -1
- package/scripts/ratchets/train-side-invariants.sh +45 -0
- package/scripts/release-loop/auto-approve-node.ts +30 -16
- package/scripts/release-loop/gate-closure.ts +5 -1
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-node.ts +498 -31
- package/scripts/release-loop/gate-partial.ts +3 -3
- package/scripts/release-loop/gate-radius-shadow.ts +138 -0
- package/scripts/release-loop/gate-traffic-mode.ts +128 -0
- package/scripts/release-loop/gate-triage-node.ts +5 -2
- package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
- package/scripts/release-loop/known-issues-node.ts +77 -8
- package/scripts/release-loop/preflight.ts +93 -7
- package/scripts/release-loop/publish-node.ts +60 -9
- package/scripts/release-loop/resume-cap.ts +56 -0
- package/scripts/release-loop/resume-release.ts +114 -15
- package/scripts/release-loop/resume.ts +24 -1
- package/scripts/release-loop/tui-sim-node.ts +8 -2
- package/scripts/release-loop/unattended-release.ts +8 -2
- package/src/acp/core-turn-bridge.ts +20 -5
- package/src/acp/reasoning-thought-buffer.ts +45 -0
- package/src/agent-substrate/acp-reviewer.ts +52 -12
- package/src/agent-substrate/review-finding-key.ts +53 -0
- package/src/agent-substrate/self-review-cli.ts +126 -5
- package/src/ask-user-question/pending-questions.ts +1 -1
- package/src/autopilot/pr-manager.ts +192 -43
- package/src/chat/tool-render/dispatch.ts +62 -10
- package/src/cli/control-cli.ts +24 -7
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/light-entry-route.ts +35 -0
- package/src/cli/llm-detect-cli.ts +23 -1
- package/src/cli/pr-cli.ts +76 -12
- package/src/cli/pr-land-base-read.ts +2 -0
- package/src/cli/pr-land-overlap-evidence.ts +154 -16
- package/src/cli/pr-land-recovery.ts +64 -0
- package/src/cli/pty-takeover-cli.ts +6 -5
- package/src/cli/release-cli.ts +120 -33
- package/src/cli/release-run-if-ready.ts +29 -28
- package/src/cli/release-single-flight.ts +178 -0
- package/src/cli/seat-cli.ts +37 -0
- package/src/cli/setup-cli.ts +40 -1
- package/src/cli/tasks-cli.ts +149 -5
- package/src/control/control-status.ts +8 -3
- package/src/control-plane/ledger.ts +5 -3
- package/src/control-plane/server.ts +5 -3
- package/src/core-turn/short-question.ts +5 -1
- package/src/dashboard/index.ts +36 -67
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
- package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
- package/src/dashboard/input/seat-autowake.ts +56 -3
- package/src/dashboard/seat-boot-preamble.ts +1 -1
- package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
- package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
- package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
- package/src/dashboard/turn-preamble.ts +47 -1
- package/src/dashboard/turn-stream-formatter.ts +34 -1
- package/src/dashboard/turn-stream-runtime.ts +2 -0
- package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
- package/src/domains/guardian-tick.ts +54 -2
- package/src/domains/outbound-alert.ts +3 -2
- package/src/extractors.ts +3 -1
- package/src/git-fs/retry.ts +4 -0
- package/src/git-fs/runner.ts +2 -0
- package/src/graph-runner/runner.ts +114 -44
- package/src/grok/credential.ts +5 -0
- package/src/harness/harness-cli-command.ts +39 -10
- package/src/harness/harness-incidents.ts +4 -0
- package/src/harness/harness-pod-dispatch.ts +38 -1
- package/src/harness/harness-salvage-cli.ts +14 -2
- package/src/index.ts +192 -8
- package/src/intake-plane/already-built-hint.ts +89 -0
- package/src/knowhow/pack.ts +199 -0
- package/src/light-cli.ts +95 -0
- package/src/llm.ts +55 -9
- package/src/loops/budget.ts +95 -0
- package/src/loops/msg-wake.ts +8 -2
- package/src/loops/orchestrator/traffic.ts +132 -1
- package/src/mss/logging/log-store.ts +4 -5
- package/src/nexus/api/graphs-api.ts +22 -3
- package/src/nexus/api/http-server.ts +1 -1
- package/src/nexus/api/ops-api.ts +12 -0
- package/src/oauth/claude-pty-maturity.ts +66 -0
- package/src/oauth/codex-access-mirror.ts +55 -0
- package/src/oauth/fallback-chain.ts +1 -1
- package/src/onboarding/first-run.ts +5 -3
- package/src/onboarding/non-interactive.ts +64 -13
- package/src/onboarding.ts +10 -2
- package/src/ops/overview-collect.ts +36 -1
- package/src/ops/overview.ts +11 -0
- package/src/pr-tool/census.ts +23 -5
- package/src/pr-tool/inflight-registry.ts +160 -7
- package/src/prompt-library/gpt6-family-addendum.ts +14 -1
- package/src/pty-shell/herdr-agent-report.ts +442 -0
- package/src/pty-shell/pty-control-ipc.ts +5 -5
- package/src/pty-shell/pty-write-outcome.ts +24 -6
- package/src/pty-shell/tui-run-state.ts +117 -3
- package/src/release-loop/checklist.ts +79 -5
- package/src/release-loop/feature-store.ts +19 -2
- package/src/release-loop/placement.ts +10 -3
- package/src/release-loop/rehearsal.ts +205 -25
- package/src/release-loop/rubric.ts +16 -2
- package/src/self-dev/draft-sweep.ts +52 -3
- package/src/self-dev/graph-journey-nodes.ts +10 -6
- package/src/self-dev/graph-journey-route.ts +60 -6
- package/src/self-dev/orchestrate.ts +79 -3
- package/src/self-dev/run-supervisor.ts +107 -12
- package/src/self-dev/run-types.ts +5 -1
- package/src/self-implement/gate-baseline.ts +49 -5
- package/src/self-implement/gate-remote.ts +9 -5
- package/src/self-implement/goal-author-identity.ts +66 -0
- package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
- package/src/self-implement/goal-author.ts +4 -120
- package/src/self-implement/graph-overlay-yaml.ts +17 -2
- package/src/self-implement/graph-unit-flatten.ts +103 -0
- package/src/self-implement/graph-unit-resolver.ts +107 -0
- package/src/self-implement/graph-yaml.ts +151 -1
- package/src/self-implement/headless-elanous-driver.ts +1 -0
- package/src/self-implement/knowhow-pack.ts +103 -0
- package/src/self-implement/orchestrator.ts +8 -0
- package/src/self-implement/pod-warm-pool-profile.ts +45 -0
- package/src/self-implement/review-mustfix-class.ts +203 -0
- package/src/self-implement/run-stop.ts +8 -2
- package/src/self-implement/seams.ts +32 -1
- package/src/self-implement/stop-autoheal.ts +25 -1
- package/src/session/chat.ts +27 -0
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/skills/tools/schedule-wakeup.ts +66 -17
- package/src/steward/release-day.ts +7 -3
- package/src/steward/triage.ts +37 -4
- package/src/task-agent/harvest-unit.ts +141 -0
- package/src/task-agent/live-moves.ts +98 -12
- package/src/task-agent/parent-host.ts +93 -3
- package/src/task-agent/postland-card.ts +80 -1
- package/src/task-agent/rejudge-on-head.ts +112 -26
- package/src/task-agent/repair-branch-cas.ts +4 -1
- package/src/task-agent/repair-cycle.ts +16 -3
- package/src/task-agent/run-identity.ts +4 -3
- package/src/task-agent/shadow.ts +12 -2
- package/src/task-agent/task-hand.ts +54 -7
- package/src/task-agent/work-order-build.ts +22 -0
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +39 -3
- package/src/task-orchestrator/surfaces/pod-command-job.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
- package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +54 -4
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +26 -3
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +389 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +223 -38
- package/src/task-orchestrator/surfaces/self-implement.ts +83 -2
- package/src/tool-runtime/truncation-store.ts +4 -0
- package/src/tui-client/dashboard-session.ts +10 -1
- package/src/user-config/coercion.ts +36 -0
- package/src/user-config.ts +18 -41
- package/src/ux-sim/scenario.ts +72 -13
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
- package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
- package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
- package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
- package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
- package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
- package/apps/pwa/out/_next/static/chunks/3267c0e6.d34854e7b3984a6e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +0 -34
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
- package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
- package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
- package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
- package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
- package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
- package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
- package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
- package/apps/pwa/out/_next/static/chunks/69-0a2c8209c6d4a158.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
- package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
- package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-a27b1e5a0d1b308f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-32866485913d6a04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
- package/src/cli/g6a-registration-probe.ts +0 -16
- /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → L04y73dlwKeTW-GetaTF3}/_ssgManifest.js +0 -0
package/src/cli/release-cli.ts
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
// elanous release tag --version <x.y.z> --source <commit> [--yes]
|
|
6
6
|
// elanous release verify [--version <x.y.z>]
|
|
7
7
|
// elanous release notes --from <ref> [--to <ref>]
|
|
8
|
-
// elanous release run --version <x.y.z> [--prerelease rc] [--main-cut | --cut-commit <sha>] [--publish-at <iso>] [--gate-executor <pod|host> [--gate-host <ssh-host>]] [--dry-run] [--json] [--if-ready]
|
|
9
|
-
// elanous release resume --run <runId> --from <node> [--waive <node> --reason <text>] [--accepted-regressions <json>] [--gate-executor <pod|host> [--gate-host <ssh-host>]] [--json]
|
|
8
|
+
// elanous release run --version <x.y.z> [--prerelease rc] [--main-cut | --cut-commit <sha>] [--publish-at <iso>] [--gate-executor <pod|host> [--gate-host <ssh-host>]] [--dry-run] [--json] [--if-ready] [--force-new]
|
|
9
|
+
// elanous release resume --run <runId> --from <node> [--waive <node> --reason <text>] [--accepted-regressions <json>] [--gate-executor <pod|host> [--gate-host <ssh-host>]] [--gate-pod-pool <pool>] [--json]
|
|
10
10
|
// elanous release auto-start [--window-minutes <n>] [--apply] [--json]
|
|
11
11
|
// elanous release rehearsal tick [--apply] [--checkout <dir>] [--shards <n>] [--remote <host>] [--json]
|
|
12
|
-
// elanous release preflight --version <x.y.z> [--publish-at <iso>] [--json] (컷
|
|
12
|
+
// elanous release preflight --version <x.y.z> [--publish-at <iso>] [--json] (컷 − 60분 main export 포함 사전 점검 · 읽기 전용 · ⛔ 있으면 exit 1)
|
|
13
13
|
// elanous release cut-branch --version <x.y.z> --base <sha> --pick <sha>... [--dry-run]
|
|
14
14
|
//
|
|
15
15
|
// 🩸 계기(2026-09-25 v0.1.0 첫 공개): 손으로 밟은 절차에서 둘을 빠뜨릴 뻔했다 — 공개본 git 커밋(판 커밋이 공개본 커밋이 된다) ·
|
|
@@ -28,13 +28,13 @@ import { effectiveInstanceRoot, releaseLedgerRoot } from '../instance/resolve.js
|
|
|
28
28
|
import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
|
|
29
29
|
import { envLiteral } from '../platform/env-literal.js';
|
|
30
30
|
import { getUserConfig, userConfigPath } from '../user-config.js';
|
|
31
|
-
import { addItem, cellsReferencingDoc, claimItem, decodeClaimHistoryEntry, devVersion, inspectChecklistTargetPaths, lintDocRefs, listChecklist, normalizeRefs, ownerMatches, parseOwner, parityGap, refRoots, removeItem, renderRefsStatus, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind, type ChecklistDispatchKind } from '../release-loop/checklist.js';
|
|
31
|
+
import { addItem, cellsReferencingDoc, claimItem, decodeClaimHistoryEntry, devVersion, inspectChecklistTargetPaths, lintDocRefs, listChecklist, normalizeRefs, noteDispatchSkip, ownerMatches, parseOwner, parityGap, refRoots, removeItem, renderRefsStatus, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind, type ChecklistDispatchKind } from '../release-loop/checklist.js';
|
|
32
32
|
import * as features from '../release-loop/feature-store.js';
|
|
33
33
|
import { evidencePlan, landedButYellow, type MergedChecklistPr } from '../release-loop/landed-but-yellow.js';
|
|
34
34
|
import { formatSchedule, getSchedule, listSchedules, setSchedule } from '../release-loop/release-schedule.js';
|
|
35
35
|
import { mergedPrsLast24h, placeCell, planPullForward, pullForwardPlacementConfig, rebalance, seatMove, type PlacementPriority } from '../release-loop/placement.js';
|
|
36
36
|
import { readTrafficSignal } from '../seat-loop/traffic-signal.js';
|
|
37
|
-
import { parseRubric, readRubricItems, rubricGrade, rubricScore } from '../release-loop/rubric.js';
|
|
37
|
+
import { parseRubric, parseRubricS, readRubricItems, rubricGrade, rubricScore } from '../release-loop/rubric.js';
|
|
38
38
|
import { writeStdoutJson } from './stdout-json.js';
|
|
39
39
|
import { CliUserError } from './cli-user-error.js';
|
|
40
40
|
import { hqCliWriteAllowed, type HqDeps } from '../hq/hq.js';
|
|
@@ -43,11 +43,12 @@ import { isIsolatedLedgerWriteRoot } from '../hq/ledger-write-target.js';
|
|
|
43
43
|
import { runUnattendedRelease, type UnattendedReleaseDeps } from '../../scripts/release-loop/unattended-release.js';
|
|
44
44
|
import { publishAtError } from '../../scripts/release-loop/publish-at.js';
|
|
45
45
|
import { cutReleaseBranch } from '../../scripts/release-loop/cut-branch.js';
|
|
46
|
-
import { resumeReleaseRun } from '../../scripts/release-loop/resume-release.js';
|
|
46
|
+
import { planResumeReleaseRun, resumeReleaseRun } from '../../scripts/release-loop/resume-release.js';
|
|
47
47
|
import type { AcceptedRegression } from '../../scripts/release-loop/resume.js';
|
|
48
48
|
import type { PrereleaseKind } from '../../scripts/release-loop/release-version.js';
|
|
49
49
|
import { releaseReadiness } from '../../scripts/release-loop/release-readiness.js';
|
|
50
50
|
import { runReleaseIfReady } from './release-run-if-ready.js';
|
|
51
|
+
import { ReleaseRunClaimConflict, findActiveReleaseRun, readActiveForceReleaseRun, readReleaseRunLock, withDirectReleaseRunLock, withForceReleaseRunMarker } from './release-single-flight.js';
|
|
51
52
|
import { formatPreflight, releasePreflight } from '../../scripts/release-loop/preflight.js';
|
|
52
53
|
import { defaultReleaseGraphRunsRoot, formatPublishProposal, measurePublishWindow, proposePublishAt, publishWindowWarning } from '../../scripts/release-loop/publish-window.js';
|
|
53
54
|
import { autoStartScheduledRelease, type AutoStartDeferral } from '../release-loop/auto-start.js';
|
|
@@ -491,13 +492,33 @@ async function jsonAction<T>(json: boolean | undefined, body: (log: (l: string)
|
|
|
491
492
|
}
|
|
492
493
|
}
|
|
493
494
|
|
|
494
|
-
function warnChecklistTargetPaths(input: { title: string; evidence?: string; refs?: readonly string[]; dispatchKind?: ChecklistDispatchKind }): void {
|
|
495
|
+
function warnChecklistTargetPaths(input: { title: string; evidence?: string; refs?: readonly string[]; dispatchKind?: ChecklistDispatchKind }, strict = false): void {
|
|
495
496
|
const cwd = process.cwd();
|
|
496
|
-
const
|
|
497
|
-
if (path.startsWith('/') || path.split('/').includes('..')) return
|
|
498
|
-
const
|
|
499
|
-
|
|
497
|
+
const objectTypeAtMain = (path: string): 'blob' | 'tree' | 'commit' | 'blocked-blob' | 'blocked-gitlink' | 'unavailable' | null => {
|
|
498
|
+
if (path.startsWith('/') || path.split('/').includes('..')) return null;
|
|
499
|
+
const segments = path.split('/');
|
|
500
|
+
for (let length = 1; length < segments.length; length++) {
|
|
501
|
+
const ancestor = segments.slice(0, length).join('/');
|
|
502
|
+
const lookup = spawnSync('git', ['cat-file', '-t', `origin/main:${ancestor}`], { cwd, timeout: 5_000, encoding: 'utf8' });
|
|
503
|
+
if (lookup.status === 0) {
|
|
504
|
+
if (lookup.stdout.trim() === 'blob') return 'blocked-blob';
|
|
505
|
+
if (lookup.stdout.trim() === 'commit') return 'blocked-gitlink';
|
|
506
|
+
if (lookup.stdout.trim() !== 'tree') return 'unavailable';
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
const missing = spawnSync('git', ['ls-tree', 'origin/main', '--', ancestor], { cwd, timeout: 5_000, encoding: 'utf8' });
|
|
510
|
+
return missing.status === 0 && missing.stdout.trim() === '' ? null : 'unavailable';
|
|
511
|
+
}
|
|
512
|
+
const result = spawnSync('git', ['cat-file', '-t', `origin/main:${path}`], { cwd, timeout: 5_000, encoding: 'utf8' });
|
|
513
|
+
const type = result.status === 0 ? result.stdout.trim() : '';
|
|
514
|
+
if (type === 'blob' || type === 'tree' || type === 'commit') return type;
|
|
515
|
+
if (result.status === 0) return 'unavailable';
|
|
516
|
+
// cat-file also fails for a genuinely new path. ls-tree distinguishes that
|
|
517
|
+
// from a missing ref or another Git read failure before --strict accepts 신설:.
|
|
518
|
+
const probe = spawnSync('git', ['ls-tree', 'origin/main', '--', path], { cwd, timeout: 5_000, encoding: 'utf8' });
|
|
519
|
+
return probe.status === 0 && probe.stdout.trim() === '' ? null : 'unavailable';
|
|
500
520
|
};
|
|
521
|
+
const existsAtMain = (path: string): boolean => objectTypeAtMain(path) === 'blob';
|
|
501
522
|
const mergedPrFiles = (number: number): string[] => {
|
|
502
523
|
const result = spawnSync('gh', ['pr', 'view', String(number), '--json', 'state,files'], { cwd, encoding: 'utf8', timeout: 10_000 });
|
|
503
524
|
if (result.status !== 0) return [];
|
|
@@ -506,7 +527,8 @@ function warnChecklistTargetPaths(input: { title: string; evidence?: string; ref
|
|
|
506
527
|
return pr.state === 'MERGED' ? (pr.files ?? []).map((file) => file.path).filter((path): path is string => typeof path === 'string') : [];
|
|
507
528
|
} catch { return []; }
|
|
508
529
|
};
|
|
509
|
-
const report = inspectChecklistTargetPaths(input, { existsAtMain, mergedPrFiles });
|
|
530
|
+
const report = inspectChecklistTargetPaths(input, { existsAtMain, objectTypeAtMain, mergedPrFiles });
|
|
531
|
+
if (strict && report.warnings.length) throw new CliUserError(`칸 대상 경로/완료 경계 검사: ${report.warnings.join(' · ')}`, '문면을 고치거나 --strict 없이 경고로 저장한다');
|
|
510
532
|
for (const warning of report.warnings) {
|
|
511
533
|
console.error(`⚠ 대상 경로: ${warning}${report.candidates.length ? ` · 후보: ${report.candidates.join(' · ')}` : ''}`);
|
|
512
534
|
debug.log('release.checklist', 'target-path-warning', { warning, candidates: report.candidates });
|
|
@@ -713,9 +735,9 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
713
735
|
for (const item of readRubricItems(version, releaseLedgerRoot())) {
|
|
714
736
|
if (item.priority !== 'P0' && item.priority !== 'P1') continue;
|
|
715
737
|
const group = byPriority[item.priority];
|
|
716
|
-
const
|
|
717
|
-
if (
|
|
718
|
-
else { group.s[
|
|
738
|
+
const s = parseRubricS(item.evidence ?? '') ?? parseRubric(item.title)?.S ?? parseRubricS(item.title);
|
|
739
|
+
if (s === null) group.missing++;
|
|
740
|
+
else { group.s[s as 0 | 1 | 2 | 3]++; group.total += s; }
|
|
719
741
|
}
|
|
720
742
|
const result = { version, byPriority, total: byPriority.P0.total + byPriority.P1.total, missing: byPriority.P0.missing + byPriority.P1.missing };
|
|
721
743
|
if (opts.json) await writeStdoutJson(`${JSON.stringify(result)}\n`);
|
|
@@ -858,7 +880,7 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
858
880
|
if (opts.applyEvidence && !opts.dryRun && !mayWrite(cmd)) return;
|
|
859
881
|
const snapshots = opts.open ? openSnapshots : [(landedDeps.checklist ?? listChecklist)(context(cmd).version)];
|
|
860
882
|
const now = (landedDeps.now ?? (() => new Date()))();
|
|
861
|
-
// --version 도 --open 과 같은 판 전체
|
|
883
|
+
// --version 도 --open 과 같은 판 전체 최초 수정일로 병합 PR 을 찾는다 — 선택 판 칸의 updatedAt 에 묶이면 그보다 오래 전에 병합된 PR 을 놓친다(LBY-VERSION-OPEN-MISMATCH · OPT #4059).
|
|
862
884
|
const sinceSnapshots = opts.open ? snapshots : [...openSnapshots, ...snapshots];
|
|
863
885
|
const updated = sinceSnapshots.flatMap(({ items }) => items
|
|
864
886
|
.filter((item) => (item.status === 'yellow' || item.status === 'red') && (opts.owner === undefined || ownerMatches(item.owner, opts.owner)))
|
|
@@ -908,13 +930,14 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
908
930
|
.option('--ceo-minutes <minutes>', '대표 손 분량(분)').option('--ceo-date <date>', '대표 손 날짜 YYYY-MM-DD (없으면 판 착지일 KST)')
|
|
909
931
|
.option('--accelerator', '가속 등급 — 다른 칸의 처리량을 올리는 칸(자율성·효율성·동시성). 생략하면 등급 없음')
|
|
910
932
|
.option('--allow-duplicate-id', '다른 판에 같은 id 가 있어도 경고 후 추가')
|
|
933
|
+
.option('--strict', '대상 경로·완료 경계 경고가 있으면 저장 전 거부')
|
|
911
934
|
.option('--ref <path...>', '근거 문서 — 저장소 상대 경로[#절] (반복 가능)')
|
|
912
|
-
.action((id: string, title: string, opts: { ref?: string[]; owner?: string; kind?: string; priority?: string; deadlineVersion?: string; predecessor?: string[]; ceoMinutes?: string; ceoDate?: string; accelerator?: boolean; allowDuplicateId?: boolean }, cmd: Command) => {
|
|
935
|
+
.action((id: string, title: string, opts: { ref?: string[]; owner?: string; kind?: string; priority?: string; deadlineVersion?: string; predecessor?: string[]; ceoMinutes?: string; ceoDate?: string; accelerator?: boolean; allowDuplicateId?: boolean; strict?: boolean }, cmd: Command) => {
|
|
913
936
|
const { version, json } = context(cmd);
|
|
914
937
|
if (!mayWrite(cmd)) return;
|
|
915
938
|
const dispatchKind = opts.kind && !['screen', 'postpub'].includes(opts.kind) ? opts.kind as ChecklistDispatchKind : undefined;
|
|
939
|
+
warnChecklistTargetPaths({ title, refs: opts.ref, dispatchKind }, opts.strict);
|
|
916
940
|
const data = addItem(version, { id, title, ...(opts.ref !== undefined ? { refs: opts.ref } : {}), ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.kind !== undefined && !dispatchKind ? { kind: opts.kind as ChecklistKind } : {}), ...(dispatchKind ? { dispatchKind } : {}), ...(opts.priority !== undefined ? { priority: opts.priority as PlacementPriority } : {}), ...(opts.deadlineVersion !== undefined ? { deadlineVersion: opts.deadlineVersion } : {}), ...(opts.predecessor !== undefined ? { predecessors: opts.predecessor } : {}), ...(opts.ceoMinutes !== undefined ? { ceoMinutes: ceoMinutes(opts.ceoMinutes) } : {}), ...(opts.ceoDate !== undefined ? { ceoDate: opts.ceoDate } : {}), ...(opts.accelerator ? { accelerator: true } : {}) }, { allowDuplicateId: opts.allowDuplicateId });
|
|
917
|
-
warnChecklistTargetPaths({ title, refs: opts.ref, dispatchKind });
|
|
918
941
|
if (json) console.log(JSON.stringify(data)); else console.log(`✅ ${id} 추가`);
|
|
919
942
|
});
|
|
920
943
|
withContext(checklist.command('set <id>').description('칸 상태·근거·담당·처분 갱신'))
|
|
@@ -977,15 +1000,26 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
977
1000
|
else features.move(id, from, to, actor(), undefined, undefined, opts.reason);
|
|
978
1001
|
if (json) console.log(JSON.stringify(listChecklist(to))); else console.log(`✅ ${id} ${from} → ${to}`);
|
|
979
1002
|
});
|
|
980
|
-
withContext(checklist.command('retitle <id> <title>').description('칸 제목 수정')).action((id: string, title: string,
|
|
1003
|
+
withContext(checklist.command('retitle <id> <title>').description('칸 제목 수정')).option('--strict', '대상 경로·완료 경계 경고가 있으면 저장 전 거부').action((id: string, title: string, opts: { strict?: boolean }, cmd: Command) => {
|
|
981
1004
|
const { version, json } = context(cmd);
|
|
982
1005
|
if (!mayWrite(cmd)) return;
|
|
983
1006
|
const snapshot = listChecklist(version);
|
|
984
|
-
features.retitle(id, title, actor(), snapshot.released, snapshot.dev);
|
|
985
1007
|
const item = snapshot.items.find((entry) => entry.id === id);
|
|
986
|
-
warnChecklistTargetPaths({ title, evidence: item?.evidence, refs: item?.refs, dispatchKind: item?.dispatchKind });
|
|
1008
|
+
if (!opts.strict) warnChecklistTargetPaths({ title, evidence: item?.evidence, refs: item?.refs, dispatchKind: item?.dispatchKind });
|
|
1009
|
+
features.retitle(id, title, actor(), snapshot.released, snapshot.dev, opts.strict
|
|
1010
|
+
? (affected) => warnChecklistTargetPaths({ title, evidence: affected.evidence, refs: affected.refs, dispatchKind: affected.dispatchKind }, true)
|
|
1011
|
+
: undefined);
|
|
987
1012
|
if (json) console.log(JSON.stringify(listChecklist(version))); else console.log(`✅ ${id} 제목 수정`);
|
|
988
1013
|
});
|
|
1014
|
+
withContext(checklist.command('skip-note <id> <reason>').description('디스패처 건너뜀 사유를 칸 근거에 중복 없이 기록'))
|
|
1015
|
+
.requiredOption('--expected-title <title>', '검사한 칸 제목; 바뀐 제목이면 기록하지 않는다')
|
|
1016
|
+
.requiredOption('--by <actor>', '실제 기록 주체(디스패처 자리)')
|
|
1017
|
+
.action((id: string, reason: string, opts: { expectedTitle: string; by: string }, cmd: Command) => {
|
|
1018
|
+
const { version, json } = context(cmd);
|
|
1019
|
+
if (!mayWrite(cmd)) return;
|
|
1020
|
+
const data = noteDispatchSkip(version, id, reason, opts.expectedTitle, opts.by);
|
|
1021
|
+
if (json) console.log(JSON.stringify(data)); else console.log(`✅ ${id} 건너뜀 근거 확인`);
|
|
1022
|
+
});
|
|
989
1023
|
const evidence = checklist.command('evidence').description('칸의 PR·커밋 근거');
|
|
990
1024
|
withContext(evidence.command('add <id> <ref>').description('근거 참조 추가')).action((id: string, ref: string, _opts: unknown, cmd: Command) => {
|
|
991
1025
|
const { version, json } = context(cmd);
|
|
@@ -1082,7 +1116,7 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1082
1116
|
.action(async (o: { version: string; base: string; pick: string[]; append?: boolean; dryRun?: boolean; json?: boolean }) => {
|
|
1083
1117
|
await jsonAction(o.json, async (log) => cutReleaseBranch({ ...o, log }), () => true);
|
|
1084
1118
|
});
|
|
1085
|
-
const runAction = async (o: { version: string; cutCommit?: string; mainCut?: boolean; prerelease?: string; dryRun?: boolean; ifReady?: boolean; publishAt?: string; forceFreeze?: boolean; gateExecutor?: string; gateHost?: string; json?: boolean }, logRun = console.log): Promise<boolean | AutoStartDeferral | undefined> => {
|
|
1119
|
+
const runAction = async (o: { version: string; cutCommit?: string; mainCut?: boolean; prerelease?: string; dryRun?: boolean; ifReady?: boolean; publishAt?: string; forceFreeze?: boolean; forceNew?: boolean; gateExecutor?: string; gateHost?: string; json?: boolean }, logRun = console.log): Promise<boolean | AutoStartDeferral | undefined> => {
|
|
1086
1120
|
// Only the rc rehearsal channel is operated for now (alpha/beta stay valid version shapes, not run options).
|
|
1087
1121
|
if (o.prerelease !== undefined && o.prerelease !== 'rc') {
|
|
1088
1122
|
const message = `--prerelease supports rc only: ${o.prerelease}`;
|
|
@@ -1099,6 +1133,18 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1099
1133
|
process.exitCode = 1;
|
|
1100
1134
|
return false;
|
|
1101
1135
|
}
|
|
1136
|
+
const ledgerRoot = releaseRunDeps.ledgerRoot ?? releaseLedgerRoot();
|
|
1137
|
+
if (!o.dryRun && !o.forceNew) {
|
|
1138
|
+
const active = findActiveReleaseRun(o.version, ledgerRoot) ?? readActiveForceReleaseRun(o.version, ledgerRoot);
|
|
1139
|
+
if (active) {
|
|
1140
|
+
const error = `release run already running: ${o.version} runId=${active.runId} pid=${active.pid} startedAt=${active.startedAt} (--force-new to bypass)`;
|
|
1141
|
+
debug.log('release.run', 'already-running', { version: o.version, ...active });
|
|
1142
|
+
if (o.json) await writeStdoutJson(`${JSON.stringify({ ok: false, reason: 'already-running', error, ...active })}\n`);
|
|
1143
|
+
else console.error(`⛔ ${error}`);
|
|
1144
|
+
process.exitCode = 1;
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1102
1148
|
const prerelease = o.prerelease as PrereleaseKind | undefined;
|
|
1103
1149
|
if (!o.dryRun) {
|
|
1104
1150
|
try {
|
|
@@ -1130,10 +1176,20 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1130
1176
|
try {
|
|
1131
1177
|
const outcome = await runReleaseIfReady(o.version, {
|
|
1132
1178
|
ledgerRoot: releaseRunDeps.ledgerRoot,
|
|
1179
|
+
forceNew: o.forceNew,
|
|
1133
1180
|
readiness: (version, options) => releaseReadiness(version, { ledgerRoot: releaseRunDeps.ledgerRoot, checklist: releaseRunDeps.checklist, ...options }),
|
|
1134
|
-
run: () => runUnattendedRelease({ version: o.version, cutCommit: o.cutCommit, mainCut: o.mainCut, prerelease, forceFreeze: o.forceFreeze, publishAt: o.publishAt, gateExecutor: o.gateExecutor, gateHost: o.gateHost }, releaseRunDeps),
|
|
1181
|
+
run: () => runUnattendedRelease({ version: o.version, cutCommit: o.cutCommit, mainCut: o.mainCut, prerelease, forceFreeze: o.forceFreeze, forceNew: o.forceNew, publishAt: o.publishAt, gateExecutor: o.gateExecutor, gateHost: o.gateHost }, releaseRunDeps),
|
|
1135
1182
|
});
|
|
1136
1183
|
if (outcome.skipped) {
|
|
1184
|
+
if (outcome.reason === 'already-running') {
|
|
1185
|
+
const active = findActiveReleaseRun(o.version, ledgerRoot) ?? readActiveForceReleaseRun(o.version, ledgerRoot);
|
|
1186
|
+
const lock = readReleaseRunLock(o.version, ledgerRoot);
|
|
1187
|
+
const error = `release run already running: ${o.version} runId=${active?.runId ?? 'pending'} pid=${active?.pid ?? lock?.pid ?? 'unknown'} startedAt=${active?.startedAt ?? lock?.startedAt ?? 'unknown'} (--force-new to bypass)`;
|
|
1188
|
+
if (o.json) await writeStdoutJson(`${JSON.stringify({ ok: false, reason: 'already-running', error, ...(active ?? {}) })}\n`);
|
|
1189
|
+
else console.error(`⛔ ${error}`);
|
|
1190
|
+
process.exitCode = 1;
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1137
1193
|
if (o.json) await writeStdoutJson(`${JSON.stringify(outcome)}\n`);
|
|
1138
1194
|
else logRun(`· 준비 안 됨 ${o.version} · ${outcome.reason} · ${outcome.detail}`);
|
|
1139
1195
|
return { deferred: true, reason: outcome.reason };
|
|
@@ -1159,7 +1215,20 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1159
1215
|
}
|
|
1160
1216
|
}
|
|
1161
1217
|
await jsonAction(o.json, async (log) => {
|
|
1162
|
-
const
|
|
1218
|
+
const run = () => runUnattendedRelease({ version: o.version, dryRun: o.dryRun, cutCommit: o.cutCommit, mainCut: o.mainCut, prerelease, forceFreeze: o.forceFreeze, forceNew: o.forceNew, publishAt: o.publishAt, gateExecutor: o.gateExecutor, gateHost: o.gateHost }, releaseRunDeps);
|
|
1219
|
+
const forceRun = () => {
|
|
1220
|
+
const atStart = releaseReadiness(o.version, { ledgerRoot, checklist: releaseRunDeps.checklist, isPidAlive: () => false });
|
|
1221
|
+
if (!atStart.ready) throw new Error(`release run --force-new not ready after claim: ${atStart.reason}`);
|
|
1222
|
+
return run();
|
|
1223
|
+
};
|
|
1224
|
+
let result: Awaited<ReturnType<typeof runUnattendedRelease>>;
|
|
1225
|
+
try { result = o.dryRun ? await run() : o.forceNew ? await withForceReleaseRunMarker(o.version, ledgerRoot, forceRun) : await withDirectReleaseRunLock(o.version, ledgerRoot, run); }
|
|
1226
|
+
catch (error) {
|
|
1227
|
+
if (!(error instanceof ReleaseRunClaimConflict)) throw error;
|
|
1228
|
+
const active = findActiveReleaseRun(o.version, ledgerRoot) ?? readActiveForceReleaseRun(o.version, ledgerRoot);
|
|
1229
|
+
const lock = readReleaseRunLock(o.version, ledgerRoot);
|
|
1230
|
+
throw new Error(`release run already running: ${o.version} runId=${active?.runId ?? 'pending'} pid=${active?.pid ?? lock?.pid ?? 'unknown'} startedAt=${active?.startedAt ?? lock?.startedAt ?? 'unknown'} (--force-new to bypass)`);
|
|
1231
|
+
}
|
|
1163
1232
|
log(`${result.dryRun ? '· 드라이런' : '▶ 릴리스 루프'} ${result.input.version} · 입력 ${JSON.stringify(result.input)}`);
|
|
1164
1233
|
return result;
|
|
1165
1234
|
}, (r) => r.dryRun || r.state?.status === 'done' || r.state?.status === 'awaiting-approval');
|
|
@@ -1174,12 +1243,13 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1174
1243
|
.option('--if-ready', '준비되지 않았으면 사유를 출력하고 성공으로 건너뛴다')
|
|
1175
1244
|
.option('--publish-at <iso>', '승인·선행 노드 통과 뒤 지정 시각까지 발행 대기(오프셋 포함 ISO 시각)')
|
|
1176
1245
|
.option('--force-freeze', '동결 중 게이트·발행 강행(관측 기록) — 가지 컷은 동결이 필요 없다 · 동결은 비상 스위치로 남는다')
|
|
1246
|
+
.option('--force-new', '같은 판의 살아 있는 릴리스 런을 확인한 뒤에도 새 런을 명시적으로 시작')
|
|
1177
1247
|
.option('--gate-executor <pod|host>', 'gate 노드 실행기(기본 pod) — host 는 Pod 대신 SSH 호스트의 깨끗한 클론에서 같은 판정(면제 아님)')
|
|
1178
1248
|
.option('--gate-host <ssh-host>', '--gate-executor host 의 SSH 호스트(기본 release.loop.gateRemote)')
|
|
1179
1249
|
.option('--json', '결과 한 줄 JSON(stdout) · 사람 줄은 stderr')
|
|
1180
|
-
.action(async (o: { version: string; cutCommit?: string; mainCut?: boolean; prerelease?: string; dryRun?: boolean; ifReady?: boolean; publishAt?: string; forceFreeze?: boolean; gateExecutor?: string; gateHost?: string; json?: boolean }) => { await runAction(o); });
|
|
1250
|
+
.action(async (o: { version: string; cutCommit?: string; mainCut?: boolean; prerelease?: string; dryRun?: boolean; ifReady?: boolean; publishAt?: string; forceFreeze?: boolean; forceNew?: boolean; gateExecutor?: string; gateHost?: string; json?: boolean }) => { await runAction(o); });
|
|
1181
1251
|
release.command('preflight')
|
|
1182
|
-
.description('컷
|
|
1252
|
+
.description('컷 전 사전 점검(읽기 전용) — 체크리스트·런 입력·동결·일정 + 컷 − 60분 origin/main export(자동 예약 없음). ⛔ 있으면 exit 1')
|
|
1183
1253
|
.requiredOption('--version <v>', '점검할 판(x.y.z)')
|
|
1184
1254
|
.option('--publish-at <iso>', '계획 발행 시각(기본: 컷 뒤 첫 07·18시 KST)')
|
|
1185
1255
|
.option('--json', '결과 한 줄 JSON(stdout)')
|
|
@@ -1229,8 +1299,11 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1229
1299
|
.option('--accepted-regressions <json>', '알려진 문제 추가 입력 JSON 배열 [{"id":"…","note":"…"}]')
|
|
1230
1300
|
.option('--gate-executor <pod|host>', '다시 도는 gate 의 실행기 전환(--from gate 이전만) — 런 입력에 기록 · 면제 아님')
|
|
1231
1301
|
.option('--gate-host <ssh-host>', '--gate-executor host 의 SSH 호스트(기본 저장된 런 입력 gateRemote)')
|
|
1302
|
+
.option('--gate-pod-pool <pool>', '다시 도는 gate 의 Pod 풀을 전환(--from gate 이전만) — 런 입력에 기록')
|
|
1303
|
+
.option('--command-root <path>', '노드 명령을 실행할 컷 tip checkout(생략 시 현재 폴더)')
|
|
1304
|
+
.option('--dry-run', '재개 preflight만 수행하고 런·상태 원장·시도 횟수는 변경하지 않는다')
|
|
1232
1305
|
.option('--json', '결과 한 줄 JSON(stdout)')
|
|
1233
|
-
.action(async (o: { run: string; from: string; partial?: boolean; waive?: string; reason?: string; acceptedRegressions?: string; gateExecutor?: string; gateHost?: string; json?: boolean }) => {
|
|
1306
|
+
.action(async (o: { run: string; from: string; partial?: boolean; waive?: string; reason?: string; acceptedRegressions?: string; gateExecutor?: string; gateHost?: string; gatePodPool?: string; commandRoot?: string; dryRun?: boolean; json?: boolean }) => {
|
|
1234
1307
|
await jsonAction(o.json, async (log) => {
|
|
1235
1308
|
let acceptedRegressions: AcceptedRegression[] | undefined;
|
|
1236
1309
|
if (o.acceptedRegressions !== undefined) {
|
|
@@ -1241,21 +1314,34 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1241
1314
|
throw new Error('acceptedRegressions must be an array of {id, note}');
|
|
1242
1315
|
}
|
|
1243
1316
|
}
|
|
1244
|
-
const
|
|
1317
|
+
const resumeOptions = { runId: o.run, from: o.from, partial: o.partial, commandRoot: o.commandRoot,
|
|
1245
1318
|
...(o.waive === undefined ? {} : { waive: o.waive }),
|
|
1246
1319
|
...(o.reason === undefined ? {} : { reason: o.reason }),
|
|
1247
1320
|
...(o.acceptedRegressions === undefined ? {} : { acceptedRegressions }),
|
|
1248
1321
|
...(o.gateExecutor === undefined ? {} : { gateExecutor: o.gateExecutor }),
|
|
1249
|
-
...(o.gateHost === undefined ? {} : { gateHost: o.gateHost })
|
|
1250
|
-
|
|
1251
|
-
if (o.
|
|
1322
|
+
...(o.gateHost === undefined ? {} : { gateHost: o.gateHost }),
|
|
1323
|
+
...(o.gatePodPool === undefined ? {} : { gatePodPool: o.gatePodPool }) };
|
|
1324
|
+
if (o.dryRun) {
|
|
1325
|
+
const plan = await planResumeReleaseRun(resumeOptions, { onSource: log });
|
|
1326
|
+
const gate = plan.gatePlan.mode === 'not-run' ? 'gate 실행 없음'
|
|
1327
|
+
: plan.gatePlan.mode === 'partial' ? `부분 gate 계획 ${plan.partial.requested && plan.partial.applied ? `${plan.partial.files}파일` : '미상'}`
|
|
1328
|
+
: `전체 gate${plan.gatePlan.reason ? ` (${plan.gatePlan.reason})` : ''}`;
|
|
1329
|
+
log(`· 재개 preflight 통과 · ${plan.version} · ${plan.fromNode}부터 · tip ${plan.tip.to.slice(0, 12)}${plan.tip.changed ? ` (기록 tip ${plan.tip.from.slice(0, 12)}에서 이동)` : ''} · ${gate} · 시도 ${plan.nextAttempt}/${plan.attemptLimit} · 실행·원장 변경 없음`);
|
|
1330
|
+
return plan;
|
|
1331
|
+
}
|
|
1332
|
+
const result = await resumeReleaseRun(resumeOptions, { onSource: log });
|
|
1333
|
+
const executorOverride = [...(result.state.inputOverrides ?? [])].reverse().find((item) => item.kind === 'gate-executor');
|
|
1334
|
+
const poolOverride = [...(result.state.inputOverrides ?? [])].reverse().find((item) => item.kind === 'gate-pod-pool');
|
|
1335
|
+
if (o.gateExecutor !== undefined && executorOverride?.kind === 'gate-executor') log(`⇄ gate 실행기 ${executorOverride.set.gateExecutor}${executorOverride.set.gateRemote ? ` @ ${executorOverride.set.gateRemote}` : ''} (런 입력에 기록 · 면제 아님)`);
|
|
1336
|
+
if (o.gatePodPool !== undefined && poolOverride?.kind === 'gate-pod-pool') log(`⇄ gate Pod 풀 ${poolOverride.set.gatePodPool} (런 입력에 기록)`);
|
|
1252
1337
|
if (result.partial.requested) log(result.partial.applied
|
|
1253
1338
|
? `◐ 부분 재검${result.partial.auto ? '(기본)' : ''}: ${result.partial.files}파일${result.partial.closure ? ` (코드 닿음 ${result.partial.closure.reached} · 닫힘 불투명 ${result.partial.closure.opaque})` : ''} · 나머지는 앞 게이트(${result.partial.priorCommit.slice(0, 12)}) 결과를 잇는다`
|
|
1254
1339
|
: `● 전체 게이트로: ${result.partial.reason}`);
|
|
1255
1340
|
log(`${result.tip.changed ? `↻ ${result.tip.branch} ${result.tip.from.slice(0, 12)} → ${result.tip.to.slice(0, 12)} (백업 ${result.tip.backup})` : `· ${result.tip.branch} 끝 그대로 ${result.tip.to.slice(0, 12)}`} · ${o.from} 부터 → ${result.state.status}`);
|
|
1256
1341
|
return { tip: result.tip, partial: result.partial, status: result.state.status, runId: result.state.runId,
|
|
1257
|
-
...(o.gateExecutor !== undefined &&
|
|
1258
|
-
|
|
1342
|
+
...(o.gateExecutor !== undefined && executorOverride?.kind === 'gate-executor' ? { gateExecutor: executorOverride } : {}),
|
|
1343
|
+
...(o.gatePodPool !== undefined && poolOverride?.kind === 'gate-pod-pool' ? { gatePodPool: poolOverride } : {}) };
|
|
1344
|
+
}, (r) => 'preflight' in r || r.status === 'done' || r.status === 'awaiting-approval');
|
|
1259
1345
|
});
|
|
1260
1346
|
release.command('gate-history')
|
|
1261
1347
|
.description('GATE-FAIL-HISTORY (0.2.29) — 판을 넘는 게이트 실패 표 — 모든 release-loop·light-rc 런 원장 ⊕ gate-verdict 에서 시험 파일별 introduced·preexisting·env·flaky 횟수 · 마지막 실패 판 · 원인 PR(수리 PR 본문 «원인 #N»)')
|
|
@@ -1308,6 +1394,7 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
1308
1394
|
await jsonAction(o.json, async (log) => {
|
|
1309
1395
|
const ledgerRoot = scheduleLedgerRoot();
|
|
1310
1396
|
if (o.apply && !mayWriteLedger('release rehearsal tick', false, ledgerRoot)) throw new Error('release rehearsal tick: ledger write denied');
|
|
1397
|
+
// The tick reports a preflight shard shortage as an unmeasured attempt; its released stage can be claimed on the next CLI tick.
|
|
1311
1398
|
const result = await runRehearsalTick({ apply: o.apply, checkout: o.checkout, shards: o.shards === undefined ? undefined : Number(o.shards), remote: o.remote, ledgerRoot }, rehearsalDeps);
|
|
1312
1399
|
log(`· 리허설 ${result.status}${'version' in result ? ` ${result.version}` : ''}${result.status === 'due' ? ` · 실행 ${result.run ?? '-'} · 건너뜀 ${result.supersede.join(', ') || '-'}` : ''}`);
|
|
1313
1400
|
return result;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { closeSync, mkdirSync, openSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
1
|
import { debug } from '../debug/log.js';
|
|
4
2
|
import { releaseLedgerRoot } from '../instance/resolve.js';
|
|
5
3
|
import { adviseLaunch, compareLaunchAdvice } from '../harness/launch-advice.js';
|
|
6
4
|
import type { QueuePool } from '../harness/harness-queue.js';
|
|
7
5
|
import type { ReleaseReadiness } from '../../scripts/release-loop/release-readiness.js';
|
|
6
|
+
import { ReleaseRunClaimConflict, releaseRunLockOwnerAlive, withDirectReleaseRunLock, withForceReleaseRunMarker } from './release-single-flight.js';
|
|
8
7
|
|
|
9
8
|
export type ReleaseIfReadySkip = { skipped: true; reason: Exclude<ReleaseReadiness, { ready: true }>['reason']; detail: string };
|
|
10
9
|
|
|
@@ -16,6 +15,8 @@ export async function runReleaseIfReady<T>(version: string, deps: {
|
|
|
16
15
|
now?: () => Date;
|
|
17
16
|
advice?: typeof adviseLaunch;
|
|
18
17
|
pool?: () => QueuePool | undefined;
|
|
18
|
+
/** Explicit operator override: keep readiness checks, bypass only the same-version lock. */
|
|
19
|
+
forceNew?: boolean;
|
|
19
20
|
}): Promise<ReleaseIfReadySkip | { skipped: false; result: T }> {
|
|
20
21
|
const skip = (readiness: Exclude<ReleaseReadiness, { ready: true }>): ReleaseIfReadySkip => {
|
|
21
22
|
const detail = readiness.reason === 'checklist-blocked'
|
|
@@ -24,36 +25,36 @@ export async function runReleaseIfReady<T>(version: string, deps: {
|
|
|
24
25
|
debug.log('release-loop.readiness', readiness.reason, { version, detail });
|
|
25
26
|
return { skipped: true, reason: readiness.reason, detail };
|
|
26
27
|
};
|
|
27
|
-
const
|
|
28
|
+
const ledgerRoot = deps.ledgerRoot ?? releaseLedgerRoot();
|
|
29
|
+
const readiness = await deps.readiness(version, { isPidAlive: deps.forceNew ? () => false
|
|
30
|
+
: (pid) => releaseRunLockOwnerAlive(version, ledgerRoot, pid) });
|
|
28
31
|
if (!readiness.ready) return skip(readiness);
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
if (deps.forceNew) return withForceReleaseRunMarker(version, ledgerRoot, async () => {
|
|
34
|
+
const atStart = await deps.readiness(version, { isPidAlive: () => false });
|
|
35
|
+
if (!atStart.ready) return skip(atStart);
|
|
36
|
+
return { skipped: false, result: await deps.run() };
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
return await withDirectReleaseRunLock(version, ledgerRoot, async () => {
|
|
41
|
+
// This call still checks publication and checklist, but must not treat our own lock as another runner.
|
|
42
|
+
const insideLock = await deps.readiness(version, { isPidAlive: () => false });
|
|
43
|
+
if (!insideLock.ready) return skip(insideLock);
|
|
44
|
+
debug.log('release-loop.readiness', 'ready', { version });
|
|
45
|
+
try {
|
|
46
|
+
const advice = (deps.advice ?? adviseLaunch)({ pool: deps.pool?.(), caller: 'release-run' });
|
|
47
|
+
const { kind } = compareLaunchAdvice(advice, 'launched');
|
|
48
|
+
debug.log('resource.advice', 'launch-advice', { caller: 'release-run', verdict: advice.verdict, why: advice.why, actual: 'launched', kind, version });
|
|
49
|
+
} catch {
|
|
50
|
+
// Shadow only: a throwing advice seam must never affect the launch decision or result.
|
|
51
|
+
}
|
|
52
|
+
return { skipped: false, result: await deps.run() };
|
|
53
|
+
}, { pid: deps.pid, now: deps.now });
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (!(error instanceof ReleaseRunClaimConflict)) throw error;
|
|
37
56
|
const detail = 'run.lock already exists';
|
|
38
57
|
debug.log('release-loop.readiness', 'already-running', { version, detail });
|
|
39
58
|
return { skipped: true, reason: 'already-running', detail };
|
|
40
59
|
}
|
|
41
|
-
try {
|
|
42
|
-
writeFileSync(fd, `${JSON.stringify({ pid: deps.pid ?? process.pid, startedAt: (deps.now ?? (() => new Date()))().toISOString() })}\n`);
|
|
43
|
-
// This call still checks publication and checklist, but must not treat our own lock as another runner.
|
|
44
|
-
const insideLock = await deps.readiness(version, { isPidAlive: () => false });
|
|
45
|
-
if (!insideLock.ready) return skip(insideLock);
|
|
46
|
-
debug.log('release-loop.readiness', 'ready', { version });
|
|
47
|
-
try {
|
|
48
|
-
const advice = (deps.advice ?? adviseLaunch)({ pool: deps.pool?.(), caller: 'release-run' });
|
|
49
|
-
const { kind } = compareLaunchAdvice(advice, 'launched');
|
|
50
|
-
debug.log('resource.advice', 'launch-advice', { caller: 'release-run', verdict: advice.verdict, why: advice.why, actual: 'launched', kind, version });
|
|
51
|
-
} catch {
|
|
52
|
-
// Shadow only: a throwing advice seam must never affect the launch decision or result.
|
|
53
|
-
}
|
|
54
|
-
return { skipped: false, result: await deps.run() };
|
|
55
|
-
} finally {
|
|
56
|
-
closeSync(fd);
|
|
57
|
-
rmSync(lock);
|
|
58
|
-
}
|
|
59
60
|
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { closeSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { Database } from 'bun:sqlite';
|
|
5
|
+
import { graphRunAlive, type GraphRunState } from '../graph-runner/runner.js';
|
|
6
|
+
import { psProcessStartMs, START_TOLERANCE_MS } from '../harness/harness-stop.js';
|
|
7
|
+
|
|
8
|
+
export interface ActiveReleaseRun {
|
|
9
|
+
runId: string;
|
|
10
|
+
pid: number;
|
|
11
|
+
startedAt: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class ReleaseRunClaimConflict extends Error {
|
|
15
|
+
readonly code = 'EEXIST';
|
|
16
|
+
constructor() { super('release run claim already exists'); }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isPidAlive(pid: number): boolean {
|
|
20
|
+
try { process.kill(pid, 0); return true; }
|
|
21
|
+
catch (error) {
|
|
22
|
+
if ((error as NodeJS.ErrnoException).code === 'ESRCH') return false;
|
|
23
|
+
if ((error as NodeJS.ErrnoException).code === 'EPERM') return true;
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The saved graph run is the authority for an active release, not a process-name match. */
|
|
29
|
+
export function findActiveReleaseRun(version: string, ledgerRoot: string): ActiveReleaseRun | undefined {
|
|
30
|
+
const dir = join(ledgerRoot, 'graph-runs', 'release-loop');
|
|
31
|
+
let names: string[];
|
|
32
|
+
try { names = readdirSync(dir).filter((name) => name.endsWith('.json')); }
|
|
33
|
+
catch (error) {
|
|
34
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
const runs: ActiveReleaseRun[] = [];
|
|
38
|
+
for (const name of names) {
|
|
39
|
+
try {
|
|
40
|
+
const state = JSON.parse(readFileSync(join(dir, name), 'utf8')) as {
|
|
41
|
+
graphId?: unknown; runId?: unknown; status?: unknown; pid?: unknown; pidStartedAt?: unknown; startedAt?: unknown;
|
|
42
|
+
input?: { version?: unknown };
|
|
43
|
+
};
|
|
44
|
+
if (state.graphId !== 'release-loop' || state.status !== 'running' || state.input?.version !== version
|
|
45
|
+
|| typeof state.runId !== 'string' || typeof state.startedAt !== 'string'
|
|
46
|
+
|| typeof state.pid !== 'number' || !Number.isSafeInteger(state.pid) || state.pid <= 0
|
|
47
|
+
|| graphRunAlive(state as GraphRunState) !== true) continue;
|
|
48
|
+
runs.push({ runId: state.runId, pid: state.pid, startedAt: state.startedAt });
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error instanceof SyntaxError || (error as NodeJS.ErrnoException).code === 'ENOENT') continue;
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return runs.sort((a, b) => b.startedAt.localeCompare(a.startedAt))[0];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function readReleaseRunLock(version: string, ledgerRoot: string): { pid?: number; startedAt?: string; pidStartedAt?: string } | undefined {
|
|
58
|
+
try {
|
|
59
|
+
const value = JSON.parse(readFileSync(join(ledgerRoot, 'release', version, 'run.lock'), 'utf8')) as { pid?: unknown; startedAt?: unknown; pidStartedAt?: unknown };
|
|
60
|
+
return { pid: typeof value.pid === 'number' ? value.pid : undefined,
|
|
61
|
+
startedAt: typeof value.startedAt === 'string' ? value.startedAt : undefined,
|
|
62
|
+
pidStartedAt: typeof value.pidStartedAt === 'string' ? value.pidStartedAt : undefined };
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;
|
|
65
|
+
if (error instanceof SyntaxError) return {};
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** A live PID belongs to this lock only if its process birth still matches. */
|
|
71
|
+
export function releaseRunLockOwnerAlive(version: string, ledgerRoot: string, pid: number): boolean {
|
|
72
|
+
const owner = readReleaseRunLock(version, ledgerRoot);
|
|
73
|
+
if (!owner || owner.pid !== pid || !isPidAlive(pid)) return false;
|
|
74
|
+
const actual = psProcessStartMs(pid);
|
|
75
|
+
// A failed birth probe must not let a second launch reclaim a live PID's lock.
|
|
76
|
+
if (actual === null) return true;
|
|
77
|
+
const recorded = Date.parse(owner.pidStartedAt ?? '');
|
|
78
|
+
if (Number.isFinite(recorded)) return Math.abs(actual - recorded) <= START_TOLERANCE_MS;
|
|
79
|
+
// Older locks have only their claim time. A process born after that claim reused the PID.
|
|
80
|
+
const claimedAt = Date.parse(owner.startedAt ?? '');
|
|
81
|
+
return Number.isFinite(claimedAt) && actual <= claimedAt + START_TOLERANCE_MS;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function claimDb(ledgerRoot: string): Database {
|
|
85
|
+
mkdirSync(join(ledgerRoot, 'release'), { recursive: true });
|
|
86
|
+
const db = new Database(join(ledgerRoot, 'release', 'run-lock-claim.sqlite'), { create: true });
|
|
87
|
+
db.exec('PRAGMA busy_timeout = 5000');
|
|
88
|
+
db.exec('CREATE TABLE IF NOT EXISTS force_starts (token TEXT PRIMARY KEY, version TEXT NOT NULL, pid INTEGER NOT NULL, pid_started_at TEXT NOT NULL, started_at TEXT NOT NULL)');
|
|
89
|
+
return db;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
type ForceStart = { token: string; version: string; pid: number; pid_started_at: string; started_at: string };
|
|
93
|
+
function forceStartAlive(row: ForceStart): boolean {
|
|
94
|
+
if (!isPidAlive(row.pid)) return false;
|
|
95
|
+
const actual = psProcessStartMs(row.pid);
|
|
96
|
+
return actual === null || Math.abs(actual - Date.parse(row.pid_started_at)) <= START_TOLERANCE_MS;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function liveForceStart(db: Database, version: string): ForceStart | undefined {
|
|
100
|
+
const rows = db.query('SELECT token, version, pid, pid_started_at, started_at FROM force_starts WHERE version = ?').all(version) as ForceStart[];
|
|
101
|
+
for (const row of rows) {
|
|
102
|
+
if (forceStartAlive(row)) return row;
|
|
103
|
+
db.query('DELETE FROM force_starts WHERE token = ?').run(row.token);
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function readActiveForceReleaseRun(version: string, ledgerRoot: string): ActiveReleaseRun | undefined {
|
|
109
|
+
const db = claimDb(ledgerRoot);
|
|
110
|
+
try {
|
|
111
|
+
const row = liveForceStart(db, version);
|
|
112
|
+
return row && { runId: 'pending', pid: row.pid, startedAt: row.started_at };
|
|
113
|
+
} finally { db.close(); }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Force runs bypass refusal but publish a claim before launching so later normal runs refuse. */
|
|
117
|
+
export async function withForceReleaseRunMarker<T>(version: string, ledgerRoot: string, run: () => Promise<T>): Promise<T> {
|
|
118
|
+
const db = claimDb(ledgerRoot);
|
|
119
|
+
const token = randomUUID();
|
|
120
|
+
try {
|
|
121
|
+
db.exec('BEGIN IMMEDIATE');
|
|
122
|
+
try {
|
|
123
|
+
const pidStartedAt = psProcessStartMs(process.pid) ?? Date.now() - process.uptime() * 1000;
|
|
124
|
+
db.query('INSERT INTO force_starts (token, version, pid, pid_started_at, started_at) VALUES (?, ?, ?, ?, ?)')
|
|
125
|
+
.run(token, version, process.pid, new Date(pidStartedAt).toISOString(), new Date().toISOString());
|
|
126
|
+
db.exec('COMMIT');
|
|
127
|
+
} catch (error) { db.exec('ROLLBACK'); throw error; }
|
|
128
|
+
return await run();
|
|
129
|
+
} finally {
|
|
130
|
+
db.query('DELETE FROM force_starts WHERE token = ?').run(token);
|
|
131
|
+
db.close();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Atomic claim closes the gap before the graph's first saved state. SQLite serializes
|
|
137
|
+
* stale-lock reclamation among direct entrants; a scheduled entrant only uses O_EXCL,
|
|
138
|
+
* so it either wins after removal or sees the direct entrant's new file.
|
|
139
|
+
*/
|
|
140
|
+
export async function withDirectReleaseRunLock<T>(version: string, ledgerRoot: string, run: () => Promise<T>,
|
|
141
|
+
owner: { pid?: number; now?: () => Date } = {}): Promise<T> {
|
|
142
|
+
const dir = join(ledgerRoot, 'release', version);
|
|
143
|
+
mkdirSync(dir, { recursive: true });
|
|
144
|
+
const lock = join(dir, 'run.lock');
|
|
145
|
+
const db = claimDb(ledgerRoot);
|
|
146
|
+
const token = randomUUID();
|
|
147
|
+
let fd: number | undefined;
|
|
148
|
+
try {
|
|
149
|
+
db.exec('BEGIN IMMEDIATE');
|
|
150
|
+
try {
|
|
151
|
+
if (liveForceStart(db, version)) {
|
|
152
|
+
throw new ReleaseRunClaimConflict();
|
|
153
|
+
}
|
|
154
|
+
const existing = readReleaseRunLock(version, ledgerRoot);
|
|
155
|
+
if (existing?.pid && !releaseRunLockOwnerAlive(version, ledgerRoot, existing.pid)) rmSync(lock, { force: true });
|
|
156
|
+
fd = openSync(lock, 'wx', 0o600);
|
|
157
|
+
const pid = owner.pid ?? process.pid;
|
|
158
|
+
const pidStartedAt = psProcessStartMs(pid) ?? Date.now() - process.uptime() * 1000;
|
|
159
|
+
writeFileSync(fd, `${JSON.stringify({ pid, pidStartedAt: new Date(pidStartedAt).toISOString(), startedAt: (owner.now ?? (() => new Date()))().toISOString(), token })}\n`);
|
|
160
|
+
db.exec('COMMIT');
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (fd !== undefined) { closeSync(fd); rmSync(lock, { force: true }); fd = undefined; }
|
|
163
|
+
db.exec('ROLLBACK');
|
|
164
|
+
if ((error as NodeJS.ErrnoException).code === 'EEXIST') throw new ReleaseRunClaimConflict();
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
} finally { db.close(); }
|
|
168
|
+
try { return await run(); }
|
|
169
|
+
finally {
|
|
170
|
+
if (fd !== undefined) closeSync(fd);
|
|
171
|
+
try {
|
|
172
|
+
const current = JSON.parse(readFileSync(lock, 'utf8')) as { token?: unknown };
|
|
173
|
+
if (current.token === token) rmSync(lock);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|