elanous 0.2.22 → 0.2.24
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/NOTICE +7 -0
- package/README.md +32 -22
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
- package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
- package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
- package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/272-0eed0fb0aab716b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
- package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3961-aaae04ed1d32622f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
- package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
- package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
- package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
- package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
- package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
- package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
- package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
- package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
- package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
- package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
- package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3b9fc39362473ae7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-24282bf9f90031a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-c0ab229673a8b0eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-22725e2570f1126b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1d809a87139dd024.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b92caddb5c715f30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
- package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.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 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +24 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
- package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
- package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
- package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
- package/catalog/models/openai/gpt-6-astra.yaml +6 -0
- package/catalog/models/openai/gpt-6-luna.yaml +6 -0
- package/catalog/models/openai/gpt-6-sol.yaml +6 -0
- package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
- package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
- package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
- package/catalog/providers/openrouter.yaml +2 -0
- package/graphs/implement-loop.yaml +31 -0
- package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
- package/graphs/log-horizon/recipes.yaml +3 -0
- package/graphs/ops/harness-gc.yaml +17 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/overlays/README.md +1 -1
- package/graphs/overlays/stop-heal-ladder.yaml +105 -0
- package/graphs/release/recipes.yaml +1 -1
- package/graphs/release/release-loop.yaml +6 -2
- package/graphs/release-rehearsal/recipes.yaml +12 -0
- package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
- package/package.json +4 -1
- package/scripts/add-api-key.sh +1 -1
- package/scripts/bench-report.ts +82 -3
- package/scripts/ci-typecheck-changed.ts +80 -14
- package/scripts/fleet/bedrock-pod-secret.ts +122 -0
- package/scripts/fleet/node-setup-linux.sh +97 -0
- package/scripts/fleet/node-setup.sh +11 -0
- package/scripts/fleet/zai-pod-secret.ts +86 -0
- package/scripts/hq/hq-fence-wrapper.sh +148 -0
- package/scripts/land-global-checks.ts +3 -0
- package/scripts/lib/typecheck-ratchet.ts +51 -0
- package/scripts/measure-log-diet-2.ts +213 -0
- package/scripts/measure-tsc-affected-roots.ts +289 -0
- package/scripts/openai-relay-server.ts +5 -1
- package/scripts/release-loop/docs-node.ts +258 -43
- package/scripts/release-loop/gate-executor.ts +28 -0
- package/scripts/release-loop/gate-method.ts +59 -0
- package/scripts/release-loop/gate-node.ts +335 -33
- package/scripts/release-loop/gate-wall.ts +208 -0
- package/scripts/release-loop/known-issues-node.ts +53 -8
- package/scripts/release-loop/publish-at.ts +14 -0
- package/scripts/release-loop/publish-node.ts +17 -2
- package/scripts/release-loop/resume-release.ts +40 -4
- package/scripts/release-loop/resume.ts +94 -0
- package/scripts/release-loop/shard-plan.ts +3 -11
- package/scripts/release-loop/tui-node-checks.ts +22 -0
- package/scripts/release-loop/unattended-release.ts +29 -7
- package/scripts/rhythm/daily.ts +51 -2
- package/scripts/rhythm/weekly.ts +3 -2
- package/scripts/tsc-baseline-cache.ts +147 -0
- package/scripts/tsc-main-safety-net.ts +189 -0
- package/scripts/usage-rollup.ts +64 -8
- package/src/acp/codex-plugins.ts +48 -6
- package/src/agent/monad-agent-turn.ts +67 -5
- package/src/agent/run-context.ts +20 -0
- package/src/agent/tool-profile.ts +28 -2
- package/src/agent-mission/acp-judge.ts +8 -2
- package/src/agent-mission/capabilities-cli.ts +16 -1
- package/src/agent-mission/driver.ts +19 -4
- package/src/agent-mission/pr-review-watch.ts +6 -2
- package/src/agent-mission/resource-ladder.ts +8 -3
- package/src/agent-mission/review-loop.ts +41 -7
- package/src/agent-substrate/acp-implementer.ts +139 -0
- package/src/agent-substrate/acp-reviewer.ts +17 -8
- package/src/agent-substrate/pr-reviewer.ts +191 -28
- package/src/agent-substrate/review-intent.ts +6 -4
- package/src/agent-substrate/self-review-cli.ts +155 -21
- package/src/agent-substrate/shard-boundary-intent.ts +92 -26
- package/src/ask-user-question/pending-questions.ts +8 -2
- package/src/autopilot/build/llm-conflict-merge.ts +216 -12
- package/src/autopilot/codebase-grounding.ts +44 -0
- package/src/autopilot/llm-control-brain.ts +13 -1
- package/src/autopilot/mission-codebase-gate.ts +8 -77
- package/src/autopilot/mission-critique.ts +18 -5
- package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
- package/src/autopilot/mission-trace.ts +12 -1
- package/src/autopilot/pr-manager.ts +12 -3
- package/src/autopilot/system-lookback-run.ts +16 -10
- package/src/bench/bench.ts +183 -0
- package/src/boot/acp-server.ts +4 -7
- package/src/boot/acp-socket-path.ts +7 -0
- package/src/briefing/brief-items.ts +21 -13
- package/src/budget/fetchers/grok.ts +15 -5
- package/src/budget/llm-cost.ts +37 -5
- package/src/budget/types.ts +8 -2
- package/src/budget/unified-usage.ts +88 -6
- package/src/chat/index.ts +12 -3
- package/src/cli/agent-cli.ts +20 -0
- package/src/cli/bench-cli.ts +34 -0
- package/src/cli/brief-cli.ts +27 -21
- package/src/cli/cli-user-error.ts +9 -2
- package/src/cli/guardian-cli.ts +26 -1
- package/src/cli/image-cli.ts +101 -0
- package/src/cli/log-event-names.ts +7 -0
- package/src/cli/logs-cli.ts +1 -0
- package/src/cli/mcp-login.ts +111 -37
- package/src/cli/plugin-cli.ts +21 -1
- package/src/cli/pod-cli.ts +26 -0
- package/src/cli/pr-cli.ts +90 -5
- package/src/cli/pr-land-overlap-evidence.ts +279 -0
- package/src/cli/release-cli.ts +63 -12
- package/src/cli/rfc-status.ts +52 -2
- package/src/cli/self-update.ts +277 -10
- package/src/cli/skills-cli.ts +12 -3
- package/src/cli/tasks-cli.ts +241 -30
- package/src/cli/usage-cli.ts +91 -8
- package/src/context-bus/context-first.ts +51 -2
- package/src/context-bus/context-now-surfaces.ts +13 -2
- package/src/context-bus/long-term-memory.ts +3 -1
- package/src/context-bus/nightly-condense.ts +3 -2
- package/src/core-turn/run-goal-loop.ts +87 -2
- package/src/dashboard/ad-run-setup-bindings.ts +279 -0
- package/src/dashboard/chat-fold.ts +20 -0
- package/src/dashboard/first-screen-band.ts +151 -1
- package/src/dashboard/index.ts +45 -281
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
- package/src/dashboard/stale-install-check.ts +24 -2
- package/src/dashboard/turn-stream-formatter.ts +25 -0
- package/src/debug/log-diet.ts +190 -0
- package/src/debug/log.ts +70 -17
- package/src/display/coordinator.ts +25 -2
- package/src/domains/coo-admin-tool.ts +27 -0
- package/src/domains/cron-match.ts +1 -0
- package/src/domains/outbound-alert.ts +17 -6
- package/src/domains/release-tool.ts +158 -10
- package/src/domains/schedule-registry.ts +10 -7
- package/src/domains/schedule-runner.ts +1 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/elanous-daemon.ts +3 -3
- package/src/error-report/report.ts +21 -4
- package/src/execution-loop/launch-gate.ts +1 -1
- package/src/expression/i18n/messages.en.ts +5 -0
- package/src/expression/i18n/messages.ja.ts +5 -0
- package/src/expression/i18n/messages.ko.ts +5 -0
- package/src/expression/i18n/messages.zh.ts +5 -0
- package/src/expression/i18n/types.ts +8 -0
- package/src/github/pr-labels.ts +2 -0
- package/src/graph-runner/graph-cli.ts +42 -1
- package/src/graph-runner/runner.ts +218 -8
- package/src/grok/usage.ts +23 -2
- package/src/grounding/ref-index.ts +253 -0
- package/src/harness/dispatch-backpressure.ts +267 -0
- package/src/harness/harness-clean.ts +199 -78
- package/src/harness/harness-cli-command.ts +229 -35
- package/src/harness/harness-gc.ts +331 -0
- package/src/harness/harness-seams.ts +2 -20
- package/src/harness/harness-stop.ts +4 -2
- package/src/harness/harness-substrate-default.ts +214 -8
- package/src/harness/launch-registry.ts +6 -0
- package/src/harness/nested-elanous-policy.ts +4 -2
- package/src/harness/worktree-branch-prefix.ts +9 -0
- package/src/hq/fence-wrapper.ts +7 -0
- package/src/hq/fence.ts +187 -0
- package/src/hq/hq.ts +33 -2
- package/src/hq/lease.ts +13 -0
- package/src/hq/seats.ts +133 -21
- package/src/images/image-ledger.ts +179 -0
- package/src/index.ts +250 -69
- package/src/instance/child-scope.ts +32 -1
- package/src/instance/dev-project.ts +133 -0
- package/src/instance/resolve.ts +24 -0
- package/src/instance/spawn-elanous.ts +45 -0
- package/src/intake-plane/collect-github.ts +19 -1
- package/src/intake-plane/digest.ts +45 -20
- package/src/intake-plane/lens.ts +36 -8
- package/src/intake-plane/ref-prefetch.ts +110 -0
- package/src/intelligence-map/model-alias.ts +6 -0
- package/src/intelligence-map/model-catalog.ts +113 -0
- package/src/knowledge/kgs/pack.ts +5 -2
- package/src/knowledge/kgs/sqlite-store.ts +15 -0
- package/src/knowledge/tools/knowledge-query.ts +20 -2
- package/src/knowledge/write.ts +234 -2
- package/src/llm/bedrock-eventstream.ts +215 -0
- package/src/llm/bedrock-provider.ts +248 -0
- package/src/llm/bedrock.ts +491 -0
- package/src/llm/openrouter-byok-cost.ts +96 -0
- package/src/llm/openrouter-deepseek.ts +151 -0
- package/src/llm/openrouter-upstream-pins.config.ts +25 -0
- package/src/llm/provider-credentials.ts +3 -1
- package/src/llm/zai-coding-plan.ts +700 -0
- package/src/llm.ts +383 -41
- package/src/loops/budget.ts +150 -0
- package/src/loops/checker.ts +148 -9
- package/src/loops/orchestrator/resync-shadow.ts +34 -7
- package/src/loops/orchestrator/seat-share.ts +6 -49
- package/src/loops/orchestrator/traffic.ts +5 -81
- package/src/market/signed-index.ts +42 -0
- package/src/maturity/feature-maturity.ts +2 -2
- package/src/mcp/mcp-oauth.ts +136 -17
- package/src/model-tier/llm-tier-map.ts +52 -4
- package/src/models/prompts.ts +23 -1
- package/src/mss/logging/horizon-watch.ts +168 -0
- package/src/mss/logging/log-store.ts +262 -26
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/consult-requests.ts +7 -10
- package/src/nexus/api/discord-trigger-bot.ts +6 -3
- package/src/nexus/api/error-reports.ts +30 -8
- package/src/nexus/api/http-server.ts +8 -0
- package/src/nexus/api/loop-resources.ts +42 -0
- package/src/nexus/api/missions.ts +73 -2
- package/src/nexus/api/ops-api.ts +18 -0
- package/src/nexus/api/outbound-report.ts +8 -3
- package/src/nexus/api/telegram-trigger-bot.ts +6 -3
- package/src/nexus/index.ts +17 -75
- package/src/nexus/outbound/format.ts +2 -0
- package/src/nexus/outbound/router.ts +198 -13
- package/src/nexus/tools-kind.ts +78 -0
- package/src/oauth/codex-account-rotation.ts +55 -20
- package/src/oauth/codex-account-store.ts +451 -23
- package/src/oauth/fallback-chain.ts +75 -15
- package/src/onboarding/first-run.ts +37 -18
- package/src/onboarding/web-first.ts +20 -2
- package/src/onboarding.ts +2 -1
- package/src/ops/machine-heartbeat.ts +185 -0
- package/src/ops/overview-cache.ts +175 -0
- package/src/ops/overview.ts +8 -0
- package/src/plugins/adapters/claude-package.ts +4 -12
- package/src/plugins/core/capability-policy.ts +141 -0
- package/src/plugins/core/host.ts +21 -8
- package/src/plugins/core/manifest.ts +19 -2
- package/src/plugins/core/trust-store.ts +15 -0
- package/src/plugins/core/types.ts +12 -0
- package/src/plugins/install/market-fetch.ts +68 -16
- package/src/plugins/install/plugin-install.ts +187 -16
- package/src/plugins/maker/plugin-maker.ts +25 -20
- package/src/plugins/maker/wizard-generate.ts +16 -2
- package/src/policy/llm-policy.ts +14 -1
- package/src/process/pid-liveness.ts +1 -1
- package/src/prompt-cache/openai.ts +13 -6
- package/src/prompt-cache/openrouter.ts +94 -0
- package/src/prompt-cache/types.ts +5 -0
- package/src/prompt-enhance/enhance.ts +69 -5
- package/src/prompt-library/family-prompt-coverage.ts +1 -0
- package/src/prompt-library/universal-preamble.ts +2 -2
- package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
- package/src/registry/loader.ts +6 -1
- package/src/release-loop/checklist.ts +24 -9
- package/src/release-loop/feature-store.ts +3 -0
- package/src/release-loop/gate-shards.ts +48 -4
- package/src/release-loop/landed-to-green.ts +81 -0
- package/src/release-loop/light-rc.ts +11 -1
- package/src/release-loop/merged-pr-checklist.ts +10 -0
- package/src/release-loop/placement.ts +107 -23
- package/src/release-loop/rehearsal.ts +317 -0
- package/src/release-loop/release-schedule.ts +13 -1
- package/src/release-loop/rubric-types.ts +1 -0
- package/src/release-loop/rubric.ts +2 -2
- package/src/requirements/requirement-ledger.ts +536 -0
- package/src/retro/daily.ts +26 -12
- package/src/seat-loop/seat-loop.ts +66 -11
- package/src/seat-loop/traffic-signal.ts +44 -0
- package/src/self-dev/ask-launch-flow.ts +2 -2
- package/src/self-dev/dev-cli.ts +109 -11
- package/src/self-dev/dev-pipeline.ts +11 -8
- package/src/self-dev/draft-residue.ts +475 -0
- package/src/self-dev/draft-sweep.ts +254 -10
- package/src/self-dev/draft-triage-rules.ts +27 -1
- package/src/self-dev/graph-journey-route.ts +6 -0
- package/src/self-dev/launch-preflight-text.ts +549 -0
- package/src/self-dev/launch-preflight.ts +10 -545
- package/src/self-dev/orchestrate-cli.ts +82 -5
- package/src/self-dev/orchestrate-summary-line.ts +13 -0
- package/src/self-dev/orchestrate.ts +49 -141
- package/src/self-dev/review-provider-fallback.ts +115 -19
- package/src/self-dev/run-store.ts +1 -3
- package/src/self-dev/run-supervisor.ts +190 -36
- package/src/self-dev/run-types.ts +191 -0
- package/src/self-dev/shard-aggregate.ts +61 -13
- package/src/self-dev/shard-plan.ts +5 -1
- package/src/self-dev/shard-run.ts +23 -5
- package/src/self-dev/supervisor-verdict-edges.ts +3 -4
- package/src/self-implement/blocked-draft-policy.ts +3 -19
- package/src/self-implement/budget-gate.ts +53 -13
- package/src/self-implement/child-context-composition.ts +139 -0
- package/src/self-implement/child-llm-preference.ts +13 -5
- package/src/self-implement/claude-acp-implement.ts +67 -0
- package/src/self-implement/draft-on-stop-mode.ts +18 -0
- package/src/self-implement/flex-signals.ts +59 -0
- package/src/self-implement/follow-up-goals.ts +114 -38
- package/src/self-implement/frozen-merges.ts +8 -3
- package/src/self-implement/gate-baseline-reap.ts +157 -0
- package/src/self-implement/gate-baseline.ts +78 -16
- package/src/self-implement/gate-cli.ts +12 -2
- package/src/self-implement/gate-remote.ts +17 -6
- package/src/self-implement/goal-author-decompose.ts +10 -2
- package/src/self-implement/goal-author.ts +48 -13
- package/src/self-implement/goal-digest.ts +19 -0
- package/src/self-implement/graph-overlay-condition.ts +32 -0
- package/src/self-implement/graph-overlay-yaml.ts +41 -7
- package/src/self-implement/graph-templates.ts +33 -1
- package/src/self-implement/graph-yaml.ts +56 -0
- package/src/self-implement/headless-elanous-driver.ts +11 -9
- package/src/self-implement/heal-intake.ts +5 -1
- package/src/self-implement/host-regate.ts +120 -29
- package/src/self-implement/l8-merge-queue.ts +67 -5
- package/src/self-implement/merge-train.ts +131 -0
- package/src/self-implement/off-diff-evidence.ts +9 -0
- package/src/self-implement/orchestrator.ts +271 -25
- package/src/self-implement/review-finding-recurrence.ts +28 -0
- package/src/self-implement/rework-policy.ts +2 -1
- package/src/self-implement/round-summary-card.ts +63 -0
- package/src/self-implement/run-ledger.ts +4 -3
- package/src/self-implement/run-step-projection.ts +147 -0
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/running-runs.ts +75 -5
- package/src/self-implement/seams.ts +83 -4
- package/src/self-implement/self-implement-cli.ts +12 -5
- package/src/self-implement/stop-autoheal.ts +69 -2
- package/src/self-implement/train-gate-remote.ts +158 -0
- package/src/session-runtime/index.ts +10 -1
- package/src/session-runtime/retry-api.ts +11 -1
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/skills/gift-install.ts +119 -0
- package/src/skills/runner.ts +59 -2
- package/src/skills/skill-feedback.ts +31 -1
- package/src/skills/skill-tier.ts +1 -0
- package/src/smart-wizard/capability-index.ts +231 -0
- package/src/smart-wizard/rung.ts +74 -0
- package/src/steward/launch.ts +22 -10
- package/src/steward/triage-budget.ts +62 -0
- package/src/steward/triage.ts +87 -24
- package/src/storage/file-lock.ts +8 -1
- package/src/task-agent/actions.ts +66 -5
- package/src/task-agent/card-evidence.ts +59 -13
- package/src/task-agent/completion-evidence.ts +5 -0
- package/src/task-agent/cover.ts +101 -3
- package/src/task-agent/judge.ts +20 -3
- package/src/task-agent/land-order-ledger.ts +95 -0
- package/src/task-agent/land-worktree.ts +201 -0
- package/src/task-agent/live-move-history.ts +219 -0
- package/src/task-agent/live-moves.ts +451 -34
- package/src/task-agent/parent-host.ts +117 -8
- package/src/task-agent/rejudge-on-head.ts +352 -0
- package/src/task-agent/review-prior-fix.ts +146 -0
- package/src/task-agent/review-result-capture.ts +218 -0
- package/src/task-agent/run-adopt.ts +136 -0
- package/src/task-agent/shadow.ts +154 -14
- package/src/task-agent/task-hand.ts +186 -14
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
- package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
- package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +42 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +94 -7
- package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +110 -17
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +32 -3
- package/src/task-orchestrator/surfaces/pod-pool.ts +86 -18
- package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +463 -50
- package/src/task-orchestrator/surfaces/self-implement.ts +25 -3
- package/src/telegram-service.ts +5 -1
- package/src/telegram.ts +17 -4
- package/src/time/format.ts +13 -4
- package/src/tool-runtime/goal-author-runtime.ts +1 -0
- package/src/tool-runtime/self-cognition-catalog.ts +23 -0
- package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
- package/src/typecheck-ratchet.ts +1 -0
- package/src/user-config.ts +180 -32
- package/src/ux-sim/slash-menu-frames.ts +168 -0
- package/src/version/packed-revision.json +1 -1
- package/src/web-terminal/preview-tap-registry.ts +5 -2
- package/src/workflow-runtime/triggers/registry.ts +59 -0
- package/src/workflow-runtime/triggers/scheduler.ts +1 -0
- package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
- package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
- package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
- package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
- package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
- package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
- package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
- package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
- package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
- package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
- package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
- package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
- package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
- package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
- package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
- package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
- package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
- package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
- /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_ssgManifest.js +0 -0
|
@@ -21,8 +21,14 @@
|
|
|
21
21
|
import type { RotationCandidate } from './codex-account-rotation.js';
|
|
22
22
|
import type { ClaudePtyMaturity } from './claude-pty-maturity.js';
|
|
23
23
|
|
|
24
|
-
/** 체인에 놓을 수 있는 칸. ⛔ 모르는 이름은 «조용히 건너뛰지 않고» 거부한다(오타 방어).
|
|
25
|
-
|
|
24
|
+
/** 체인에 놓을 수 있는 칸. ⛔ 모르는 이름은 «조용히 건너뛰지 않고» 거부한다(오타 방어).
|
|
25
|
+
*
|
|
26
|
+
* ⭐ `codex-credits`(CODEX-CREDITS-STEP · 2026-10-10) — «마지막 수단»으로 codex 를 «선불 크레딧»으로 쓴다.
|
|
27
|
+
* 한도 정책이 `fallback`(크레딧 ✗)이면 회전은 찬 계정에 «머물지» 않고(`no-candidate`) 체인의 다음 칸(grok)으로 간다.
|
|
28
|
+
* 그 grok 마저 못 쓰면 갈 곳이 없었다 — 이 칸을 grok «뒤»에 두면 그때만 크레딧으로 돌아온다.
|
|
29
|
+
* ⛔ 첫 칸의 크레딧 금지(`codexQuotaPolicy`)는 그대로다 — 이 칸은 «체인이 여기까지 왔을 때»만 돈을 쓴다.
|
|
30
|
+
* ⛔ 기본 체인에는 «없다» — 돈이라 사람이 config 에 «명시»할 때만 켜진다. */
|
|
31
|
+
export const FALLBACK_STEPS = ['codex-rotate', 'grok', 'claude-pty', 'openrouter', 'codex-credits'] as const;
|
|
26
32
|
export type FallbackStep = (typeof FALLBACK_STEPS)[number];
|
|
27
33
|
|
|
28
34
|
/** 기본 체인 — ⛔⭐ **2026-08-20 에 `grok` 이 «기본»으로 들어왔다**(대표 지시).
|
|
@@ -78,6 +84,16 @@ export type FallbackDecision =
|
|
|
78
84
|
| { readonly action: 'codex-rotate'; readonly to: RotationCandidate }
|
|
79
85
|
/** 백엔드를 통째로 바꾼다. */
|
|
80
86
|
| { readonly action: 'switch-backend'; readonly backend: 'grok' | 'claude' }
|
|
87
|
+
/** 명시한 유료 OpenRouter 모델로 전환한다. 호출부가 모델을 바꾸지 못하면 실행하지 않는다. */
|
|
88
|
+
| { readonly action: 'switch-backend'; readonly backend: 'openrouter'; readonly model: string }
|
|
89
|
+
/** codex 로 «돌아와» 선불 크레딧으로 계속한다 — 체인의 `codex-credits` 칸(마지막 수단 · 유료).
|
|
90
|
+
* `skipped` 는 «왜 앞 칸들을 못 썼나»(관측용 · 비밀 없음). */
|
|
91
|
+
| {
|
|
92
|
+
readonly action: 'codex-credits';
|
|
93
|
+
readonly skipped: readonly { readonly step: FallbackStep; readonly why: StayReason }[];
|
|
94
|
+
/** 크레딧으로 쓸 계정(잔액 많은 순 첫 계정) — 순수 판정은 비우고, 수집기(`resolveRunFallback`)가 채운다. */
|
|
95
|
+
readonly to?: RotationCandidate;
|
|
96
|
+
}
|
|
81
97
|
/** 아무것도 안 한다 — 이유를 «값으로» 남긴다. */
|
|
82
98
|
| { readonly action: 'stay'; readonly why: StayReason };
|
|
83
99
|
|
|
@@ -98,8 +114,12 @@ export type StayReason =
|
|
|
98
114
|
| 'grok-unavailable'
|
|
99
115
|
/** grok 자격은 있는데 «잔량이 소진»됐다 — 자격 부재와 «다른 값»이다. */
|
|
100
116
|
| 'grok-exhausted'
|
|
117
|
+
/** 유료 OpenRouter 모델 또는 키가 없다. */
|
|
118
|
+
| 'openrouter-unavailable'
|
|
101
119
|
/** claude PTY 의 최근 표본이 성숙 관문을 통과하지 못했거나 읽히지 않는다. */
|
|
102
|
-
| 'claude-pty-immature'
|
|
120
|
+
| 'claude-pty-immature'
|
|
121
|
+
/** 체인에 `codex-credits` 가 있는데 크레딧 잔액이 «확인된» codex 계정이 없다(모름 포함 — 돈이라 fail-closed). */
|
|
122
|
+
| 'codex-credits-unavailable';
|
|
103
123
|
|
|
104
124
|
type FallbackRunPosition =
|
|
105
125
|
| { readonly currentCredentialRateLimited?: false; readonly currentStep?: FallbackStep }
|
|
@@ -113,6 +133,10 @@ export type FallbackInput = {
|
|
|
113
133
|
/** grok 자격이 «있나». ⛔ 「모른다」를 boolean 에 접지 마라 — 호출자가
|
|
114
134
|
* `resolveGrokCredential() !== null` 로 확정해서 준다. */
|
|
115
135
|
readonly grokAvailable: boolean;
|
|
136
|
+
/** `llm.openrouter.fallbackModel` — 기본 모델로의 유료 폴백은 허용하지 않는다. */
|
|
137
|
+
readonly openrouterFallbackModel?: string;
|
|
138
|
+
/** OpenRouter 키 존재 여부(키 값 자체는 판정·관측에 넣지 않는다). */
|
|
139
|
+
readonly openrouterAvailable?: boolean;
|
|
116
140
|
/**
|
|
117
141
|
* grok 이 «지금 쓸 수 있나» — ⛔ 자격(`grokAvailable`)과 «다른 축»이다.
|
|
118
142
|
* 'usable' 쓸 수 있다(잔량 있음 · 무제한 · 임계 미만)
|
|
@@ -132,6 +156,11 @@ export type FallbackInput = {
|
|
|
132
156
|
* ⛔ 이 함수는 config 를 읽지 않는다 — 호출자가 이 칸을 준다.
|
|
133
157
|
*/
|
|
134
158
|
readonly stayOnResetCreditAvailable?: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* 크레딧 잔액이 «확인된»(잔액 > 0 · 보유 ≠ false) codex 계정이 하나라도 있나 — `codex-credits` 칸만 읽는다.
|
|
161
|
+
* ⛔ 생략·false 는 그 칸을 «건너뛴다»(돈이라 「모른다」를 통과로 접지 않는다 — grok 의 unknown 통과와 «반대»).
|
|
162
|
+
*/
|
|
163
|
+
readonly codexCreditsAvailable?: boolean;
|
|
135
164
|
} & FallbackRunPosition;
|
|
136
165
|
|
|
137
166
|
/**
|
|
@@ -154,11 +183,13 @@ export function decideFallback(input: FallbackInput): FallbackDecision {
|
|
|
154
183
|
const {
|
|
155
184
|
rotation, chain, currentStep, currentCredentialRateLimited = false,
|
|
156
185
|
grokAvailable, grokQuota = 'unknown', claudePtyMaturity, stayOnResetCreditAvailable = false,
|
|
186
|
+
openrouterFallbackModel, openrouterAvailable = false, codexCreditsAvailable = false,
|
|
157
187
|
} = input;
|
|
188
|
+
const openrouter = { model: openrouterFallbackModel, available: openrouterAvailable, codexCreditsAvailable };
|
|
158
189
|
|
|
159
190
|
if (currentCredentialRateLimited) {
|
|
160
191
|
if (currentStep === undefined) return { action: 'stay', why: 'chain-exhausted' };
|
|
161
|
-
return stepAfter(chain, currentStep, grokAvailable, grokQuota, claudePtyMaturity, 'chain-exhausted');
|
|
192
|
+
return stepAfter(chain, currentStep, grokAvailable, grokQuota, claudePtyMaturity, openrouter, 'chain-exhausted');
|
|
162
193
|
}
|
|
163
194
|
if (rotation.reason === 'explicit') return { action: 'stay', why: 'explicit' };
|
|
164
195
|
if (rotation.reason === 'not-reached' || (rotation.reason === 'credit-pace' && !('to' in rotation))) {
|
|
@@ -172,13 +203,13 @@ export function decideFallback(input: FallbackInput): FallbackDecision {
|
|
|
172
203
|
// 회전이 답을 냈는데 체인이 codex-rotate 를 «빼» 놨다면 그 뜻을 존중하고
|
|
173
204
|
// 다음 칸으로 간다(회전을 원치 않는 구성).
|
|
174
205
|
if (chain.includes('codex-rotate')) return { action: 'codex-rotate', to: rotation.to };
|
|
175
|
-
return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, 'chain-exhausted');
|
|
206
|
+
return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, openrouter, 'chain-exhausted');
|
|
176
207
|
}
|
|
177
208
|
|
|
178
209
|
// no-candidate | disabled | reset-credit-available(기본) — codex 축이 끝났다. 다음 칸을 본다.
|
|
179
210
|
// ⛔ 다음 칸이 «없을 때»의 이름만 고른다. 진행(stepAfterCodex)은 그대로다.
|
|
180
211
|
const fallbackWhy = stayReasonWhenCodexAxisEnds(rotation.reason === 'credit-pace' ? 'no-candidate' : rotation.reason);
|
|
181
|
-
return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, fallbackWhy);
|
|
212
|
+
return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, openrouter, fallbackWhy);
|
|
182
213
|
}
|
|
183
214
|
|
|
184
215
|
/** codex 축이 끝났는데 체인 다음 칸도 없을 때 머무는 이유.
|
|
@@ -192,14 +223,18 @@ export function stayReasonWhenCodexAxisEnds(
|
|
|
192
223
|
return 'chain-exhausted';
|
|
193
224
|
}
|
|
194
225
|
|
|
226
|
+
/** 칸 판정에 필요한 «나머지» 재료 — OpenRouter 모델·키, codex 크레딧 잔액 확인. */
|
|
227
|
+
type StepExtras = { readonly model?: string; readonly available: boolean; readonly codexCreditsAvailable?: boolean };
|
|
228
|
+
|
|
195
229
|
function stepAfterCodex(
|
|
196
230
|
chain: readonly FallbackStep[],
|
|
197
231
|
grokAvailable: boolean,
|
|
198
232
|
grokQuota: 'usable' | 'exhausted' | 'unknown',
|
|
199
233
|
claudePtyMaturity: ClaudePtyMaturity | undefined,
|
|
234
|
+
openrouter: StepExtras,
|
|
200
235
|
whyIfNone: StayReason,
|
|
201
236
|
): FallbackDecision {
|
|
202
|
-
return stepAfter(chain, 'codex-rotate', grokAvailable, grokQuota, claudePtyMaturity, whyIfNone);
|
|
237
|
+
return stepAfter(chain, 'codex-rotate', grokAvailable, grokQuota, claudePtyMaturity, openrouter, whyIfNone);
|
|
203
238
|
}
|
|
204
239
|
|
|
205
240
|
function stepAfter(
|
|
@@ -208,22 +243,39 @@ function stepAfter(
|
|
|
208
243
|
grokAvailable: boolean,
|
|
209
244
|
grokQuota: 'usable' | 'exhausted' | 'unknown',
|
|
210
245
|
claudePtyMaturity: ClaudePtyMaturity | undefined,
|
|
246
|
+
openrouter: StepExtras,
|
|
211
247
|
whyIfNone: StayReason,
|
|
212
248
|
): FallbackDecision {
|
|
213
249
|
const idx = currentStep === undefined ? -1 : chain.indexOf(currentStep);
|
|
214
250
|
const rest = idx === -1 ? chain : chain.slice(idx + 1);
|
|
215
251
|
let unavailableWhy: StayReason | undefined;
|
|
252
|
+
// `codex-credits` 칸이 «왜 앞 칸을 못 썼나»를 값으로 남긴다(관측 — 비밀 없음).
|
|
253
|
+
const skipped: { step: FallbackStep; why: StayReason }[] = [];
|
|
254
|
+
const skip = (step: FallbackStep, why: StayReason): void => { unavailableWhy = why; skipped.push({ step, why }); };
|
|
216
255
|
for (const step of rest) {
|
|
256
|
+
if (step === 'codex-credits') {
|
|
257
|
+
// ⛔ 크레딧은 돈이다 — 잔액이 «확인된» 계정이 없으면 건너뛴다(「모른다」는 통과가 «아니다»).
|
|
258
|
+
if (openrouter.codexCreditsAvailable !== true) { skip(step, 'codex-credits-unavailable'); continue; }
|
|
259
|
+
return { action: 'codex-credits', skipped };
|
|
260
|
+
}
|
|
261
|
+
if (step === 'openrouter') {
|
|
262
|
+
const model = openrouter.model?.trim();
|
|
263
|
+
if (!openrouter.available || !model || !/^openrouter\/[^/\s]+\/[^\s]+$/.test(model)) {
|
|
264
|
+
skip(step, 'openrouter-unavailable');
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
return { action: 'switch-backend', backend: 'openrouter', model };
|
|
268
|
+
}
|
|
217
269
|
if (step === 'grok') {
|
|
218
270
|
// 자격 부재와 소진은 다른 값이다. 다음 칸이 있으면 그 칸을 살핀다.
|
|
219
|
-
if (!grokAvailable) {
|
|
271
|
+
if (!grokAvailable) { skip(step, 'grok-unavailable'); continue; }
|
|
220
272
|
// 「모른다」는 통과시킨다 — 못 읽었다고 갈 곳을 없애지 않는다.
|
|
221
|
-
if (grokQuota === 'exhausted') {
|
|
273
|
+
if (grokQuota === 'exhausted') { skip(step, 'grok-exhausted'); continue; }
|
|
222
274
|
return { action: 'switch-backend', backend: 'grok' };
|
|
223
275
|
}
|
|
224
276
|
if (step === 'claude-pty') {
|
|
225
277
|
// 미성숙·못 읽음은 «건너뛴다» — 뒤에 다른 칸이 있으면 그 칸을 본다(없으면 이 사유로 머문다).
|
|
226
|
-
if (claudePtyMaturity?.mature !== true) {
|
|
278
|
+
if (claudePtyMaturity?.mature !== true) { skip(step, 'claude-pty-immature'); continue; }
|
|
227
279
|
return { action: 'switch-backend', backend: 'claude' };
|
|
228
280
|
}
|
|
229
281
|
}
|
|
@@ -236,7 +288,11 @@ export function describeFallback(decision: FallbackDecision): string {
|
|
|
236
288
|
case 'codex-rotate':
|
|
237
289
|
return `codex 계정 전환 → ${decision.to.name}`;
|
|
238
290
|
case 'switch-backend':
|
|
239
|
-
return
|
|
291
|
+
return decision.backend === 'openrouter'
|
|
292
|
+
? `백엔드 전환 → openrouter (${decision.model} · API 과금)`
|
|
293
|
+
: `백엔드 전환 → ${decision.backend} (구독)`;
|
|
294
|
+
case 'codex-credits':
|
|
295
|
+
return `codex 크레딧으로 계속 (마지막 칸 · 선불 크레딧 과금${decision.skipped.length ? ` · 건너뜀 ${decision.skipped.map((s) => `${s.step}:${s.why}`).join(', ')}` : ''})`;
|
|
240
296
|
case 'stay':
|
|
241
297
|
return `전환 없음 (${decision.why})`;
|
|
242
298
|
}
|
|
@@ -273,24 +329,28 @@ export function grokQuotaFromCreditAxis(axis: {
|
|
|
273
329
|
/**
|
|
274
330
|
* budget 스냅샷 → 폴백 판정이 쓰는 세 값.
|
|
275
331
|
*
|
|
276
|
-
* ⭐ 공급자가 「리밋이 찼다」고 «말한» 것을
|
|
332
|
+
* ⭐ 공급자가 「리밋이 찼다」고 «말한» 것을 weekly window 산술보다 «먼저» 본다
|
|
277
333
|
* (`UsageSnapshot.rateLimitReached` 주석의 그 권위를 그대로 따른다).
|
|
278
334
|
* ⛔ 스냅샷이 없거나 판단할 재료가 없으면 `'unknown'` 이다 — 「소진」으로 접지 «않는다».
|
|
279
335
|
* ⛔ 이 함수는 «네트워크를 안 친다» — 이미 채워진 캐시를 받는다.
|
|
280
336
|
*/
|
|
281
337
|
export function grokQuotaFromUsageSnapshot(snapshot: {
|
|
282
338
|
readonly rateLimitReached?: string;
|
|
339
|
+
readonly windows?: readonly { readonly kind: string; readonly remainingPercent: number }[];
|
|
283
340
|
readonly credits?: { readonly hasCredits?: boolean; readonly unlimited?: boolean };
|
|
284
341
|
} | null | undefined): 'usable' | 'exhausted' | 'unknown' {
|
|
285
342
|
if (!snapshot) return 'unknown';
|
|
286
|
-
// ⛔ 공급자 판정이 이긴다 —
|
|
343
|
+
// ⛔ 공급자 판정이 이긴다 — 주간 창 판정보다 앞선다.
|
|
287
344
|
if (typeof snapshot.rateLimitReached === 'string' && snapshot.rateLimitReached.length > 0) return 'exhausted';
|
|
345
|
+
const weekly = snapshot.windows?.find((window) => window.kind === 'weekly');
|
|
346
|
+
if (weekly && Number.isFinite(weekly.remainingPercent) && weekly.remainingPercent >= 0 && weekly.remainingPercent <= 100) {
|
|
347
|
+
return weekly.remainingPercent === 0 ? 'exhausted' : 'usable';
|
|
348
|
+
}
|
|
288
349
|
const credits = snapshot.credits;
|
|
289
350
|
if (!credits) return 'unknown';
|
|
290
351
|
if (credits.unlimited === true) return 'usable';
|
|
291
352
|
// ⛔⭐ `hasCredits` 는 브랜드마다 «다른 것»을 뜻할 수 있다 — grok 은 「선불 잔액이 있나」다.
|
|
292
|
-
// ⇒
|
|
293
|
-
// 그러면 hasCredits=false 하나로 「소진」을 단정하지 «않는다» — 「모른다」가 정직하다.
|
|
353
|
+
// ⇒ 주간 quota 창이 없으면 hasCredits=false 하나로 「소진」을 단정하지 «않는다» — 「모른다」가 정직하다.
|
|
294
354
|
if (credits.hasCredits === true) return 'usable';
|
|
295
355
|
return 'unknown';
|
|
296
356
|
}
|
|
@@ -13,21 +13,34 @@ export interface FirstRunDeps {
|
|
|
13
13
|
path?: string;
|
|
14
14
|
detectProviders?: () => Promise<DetectedProvider[]>;
|
|
15
15
|
isTTY?: boolean;
|
|
16
|
-
chooseProvider?: () => Promise<LLMProviderName | null>;
|
|
16
|
+
chooseProvider?: (detected: readonly LLMProviderName[]) => Promise<LLMProviderName | null>;
|
|
17
17
|
print?: (message: string) => void;
|
|
18
18
|
saveConfig?: (config: UserConfig, path: string) => void;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const CHOICE_BASE: readonly LLMProviderName[] = ['openai-codex', 'grok', 'anthropic'];
|
|
22
|
+
const CHOICE_LABEL: Partial<Record<LLMProviderName, string>> = { 'openai-codex': 'Codex', grok: 'Grok', anthropic: 'Claude' };
|
|
23
|
+
const SUBSCRIPTION_PRIORITY = ['openai-codex', 'grok', 'anthropic', 'gemini', 'openai', 'openrouter'] as const;
|
|
24
|
+
|
|
25
|
+
/** Menu order: detected subscriptions first (in priority order), then the remaining base choices. */
|
|
26
|
+
export function orderProviderChoices(detected: readonly LLMProviderName[] = []): LLMProviderName[] {
|
|
27
|
+
return [...detected, ...CHOICE_BASE.filter((name) => !detected.includes(name))];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function chooseProvider(detected: readonly LLMProviderName[] = []): Promise<LLMProviderName | null> {
|
|
31
|
+
const choices = orderProviderChoices(detected);
|
|
32
|
+
const menu = choices.map((name, i) => `${i + 1} ${CHOICE_LABEL[name] ?? name}`).join(', ');
|
|
22
33
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
23
34
|
try {
|
|
24
|
-
const answer = (await rl.question(
|
|
25
|
-
return (
|
|
35
|
+
const answer = (await rl.question(`Choose LLM (${menu}; Enter to cancel): `)).trim();
|
|
36
|
+
return choices[Number(answer) - 1] ?? null;
|
|
26
37
|
} finally {
|
|
27
38
|
rl.close();
|
|
28
39
|
}
|
|
29
40
|
}
|
|
30
41
|
|
|
42
|
+
const detectionLabel = (provider: string) => `${provider === 'openai-codex' ? 'codex' : provider} 구독`;
|
|
43
|
+
|
|
31
44
|
export async function runFirstRun(deps: FirstRunDeps = {}): Promise<{
|
|
32
45
|
outcome: 'ready' | 'needs-llm' | 'cancelled'; provider?: string; inputs: number;
|
|
33
46
|
}> {
|
|
@@ -50,21 +63,31 @@ export async function runFirstRun(deps: FirstRunDeps = {}): Promise<{
|
|
|
50
63
|
: undefined;
|
|
51
64
|
const configured = existing && existing.source !== 'none'
|
|
52
65
|
? cfg.llm.provider : undefined;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
// claude-code is detected but has no subscription path in elanous: mapping it to the 'anthropic'
|
|
67
|
+
// API-key provider would save a provider whose first call fails for a subscription-only user.
|
|
68
|
+
const usable = SUBSCRIPTION_PRIORITY.filter((name) => providers.includes(name));
|
|
69
|
+
const detectionLine = (outcome: string) => `감지: ${providers.map(detectionLabel).join(' · ')} → ${outcome}`;
|
|
70
|
+
const needsLlm = (inputs: number, extra: string[] = []) => {
|
|
71
|
+
print('eln setup llm 으로 고르세요');
|
|
72
|
+
for (const line of extra) print(line);
|
|
73
|
+
observe('needs-llm', inputs);
|
|
74
|
+
return { outcome: 'needs-llm' as const, inputs };
|
|
75
|
+
};
|
|
76
|
+
let provider: LLMProviderName | null | undefined = configured ?? (usable.length === 1 ? usable[0] : undefined);
|
|
77
|
+
if (!configured && provider) print(detectionLine(provider));
|
|
57
78
|
let inputs = 0;
|
|
58
79
|
if (!provider) {
|
|
80
|
+
if (providers.length > 0) {
|
|
81
|
+
print(detectionLine(usable.length === 0
|
|
82
|
+
? 'claude-code 구독은 구독으로 쓸 수 있는 경로가 없어 자동 선택하지 않음'
|
|
83
|
+
: '둘 이상 감지되어 고르세요'));
|
|
84
|
+
}
|
|
59
85
|
if ((deps.isTTY ?? process.stdin.isTTY) !== true) {
|
|
60
|
-
print('eln setup llm 으로 고르세요');
|
|
61
86
|
// FIRST-CHAT-NONTTY — bare `elanous` with no TTY gets the same one-line next step as the other entrances.
|
|
62
|
-
|
|
63
|
-
observe('needs-llm', 0);
|
|
64
|
-
return { outcome: 'needs-llm', inputs: 0 };
|
|
87
|
+
return needsLlm(0, [unattendedNextStepLine()]);
|
|
65
88
|
}
|
|
66
89
|
inputs = 1;
|
|
67
|
-
provider = await (deps.chooseProvider ?? chooseProvider)();
|
|
90
|
+
provider = await (deps.chooseProvider ?? chooseProvider)(usable);
|
|
68
91
|
if (!provider) return { outcome: 'cancelled', inputs };
|
|
69
92
|
observe('chosen', inputs);
|
|
70
93
|
}
|
|
@@ -74,11 +97,7 @@ export async function runFirstRun(deps: FirstRunDeps = {}): Promise<{
|
|
|
74
97
|
baseProvider: cfg.llm.provider, baseApiKey: cfg.llm.apiKey,
|
|
75
98
|
})
|
|
76
99
|
: undefined;
|
|
77
|
-
if (inputs === 1 && credential?.source === 'none')
|
|
78
|
-
print('eln setup llm 으로 고르세요');
|
|
79
|
-
observe('needs-llm', inputs);
|
|
80
|
-
return { outcome: 'needs-llm', inputs };
|
|
81
|
-
}
|
|
100
|
+
if (inputs === 1 && credential?.source === 'none') return needsLlm(inputs);
|
|
82
101
|
(deps.saveConfig ?? saveUserConfig)({
|
|
83
102
|
...cfg,
|
|
84
103
|
llm: { ...cfg.llm, provider,
|
|
@@ -15,6 +15,8 @@ export interface WebFirstSetupDeps {
|
|
|
15
15
|
/** Whether a person is at a terminal (stdin TTY). Without one the web path only uses a daemon that is already up. */
|
|
16
16
|
isTty?: boolean;
|
|
17
17
|
terminal?: boolean;
|
|
18
|
+
/** Bare first run never starts or waits for a missing daemon; explicit setup retains web launch. */
|
|
19
|
+
startIfMissing?: boolean;
|
|
18
20
|
startedAt?: number;
|
|
19
21
|
showNexus?: () => Promise<NexusShowResult>;
|
|
20
22
|
startDaemon?: () => Promise<BgLaunchResult>;
|
|
@@ -67,9 +69,13 @@ export async function runWebFirstSetup(deps: WebFirstSetupDeps): Promise<'link-s
|
|
|
67
69
|
let shown: NexusShowResult | undefined;
|
|
68
70
|
try { shown = await show(); } catch { /* A missing daemon may make inspection fail. */ }
|
|
69
71
|
const running = shown?.status === 'unregistered' || (shown?.status === 'registered' && shown.instance?.alive === true);
|
|
72
|
+
if (deps.startIfMissing === false && !running) {
|
|
73
|
+
print('오프라인 모드');
|
|
74
|
+
observe('fallback', 'offline');
|
|
75
|
+
return 'fallback';
|
|
76
|
+
}
|
|
70
77
|
// A script, pipe or CI run never starts a daemon on its own: without a terminal the web path
|
|
71
|
-
// only uses a daemon that already answers health once.
|
|
72
|
-
// stdin on /dev/tty, so the install → web path still starts one.)
|
|
78
|
+
// only uses a daemon that already answers health once.
|
|
73
79
|
if ((deps.isTty ?? (process.stdin.isTTY === true)) !== true) {
|
|
74
80
|
const rest = running ? shown?.urls?.rest.loopback : undefined;
|
|
75
81
|
const up = rest && shown?.urls?.pwa.loopback
|
|
@@ -78,6 +84,12 @@ export async function runWebFirstSetup(deps: WebFirstSetupDeps): Promise<'link-s
|
|
|
78
84
|
}
|
|
79
85
|
const deadline = Date.now() + STARTUP_TIMEOUT_MS;
|
|
80
86
|
if (!running || !shown?.urls?.pwa.loopback) {
|
|
87
|
+
if (deps.startIfMissing === false) {
|
|
88
|
+
print('오프라인 모드');
|
|
89
|
+
observe('fallback', 'offline');
|
|
90
|
+
return 'fallback';
|
|
91
|
+
}
|
|
92
|
+
print('웹 셋업을 위해 데몬을 시작합니다.');
|
|
81
93
|
let launch: BgLaunchResult;
|
|
82
94
|
try {
|
|
83
95
|
launch = await (deps.startDaemon ?? (() => runBgLaunch({ out: { log: () => {}, error: () => {} } })))();
|
|
@@ -98,9 +110,15 @@ export async function runWebFirstSetup(deps: WebFirstSetupDeps): Promise<'link-s
|
|
|
98
110
|
}
|
|
99
111
|
}
|
|
100
112
|
} catch { /* A daemon may not have published its URLs yet. */ }
|
|
113
|
+
if (deps.startIfMissing === false) break;
|
|
101
114
|
const remaining = deadline - Date.now();
|
|
102
115
|
if (remaining > 0) await Bun.sleep(Math.min(200, remaining));
|
|
103
116
|
}
|
|
117
|
+
if (!healthy && deps.startIfMissing === false) {
|
|
118
|
+
print('오프라인 모드');
|
|
119
|
+
observe('fallback', 'offline');
|
|
120
|
+
return 'fallback';
|
|
121
|
+
}
|
|
104
122
|
if (!healthy) return fallback(running ? 'daemon-health-unavailable' : 'daemon-health-timeout');
|
|
105
123
|
|
|
106
124
|
if (!shown?.urls?.pwa.loopback) return fallback('daemon-unavailable');
|
package/src/onboarding.ts
CHANGED
|
@@ -51,6 +51,7 @@ import { DiscordBot } from './discord.js';
|
|
|
51
51
|
import { pickCodexAuthMode, pickCodexModel } from './codex/setup.js';
|
|
52
52
|
import { getInventory, resolveBaseUrl } from './llm/local-manager/manager.js';
|
|
53
53
|
import { getMessages, format as i18nFormat } from './expression/i18n/index.js';
|
|
54
|
+
import { messagesEn } from './expression/i18n/messages.en.js';
|
|
54
55
|
import type {
|
|
55
56
|
ChoiceOption,
|
|
56
57
|
ChooseOpts,
|
|
@@ -1562,7 +1563,7 @@ export async function runOnboarding(opts: RunWizardOpts = {}): Promise<UserConfi
|
|
|
1562
1563
|
io.print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
1563
1564
|
io.print(` ${m.setupComplete}`);
|
|
1564
1565
|
// ER1 — first-run consent notice (default on · 대표 10-01): what is sent and how to turn it off.
|
|
1565
|
-
io.print(
|
|
1566
|
+
io.print(` ${m.setupErrorReportNotice ?? messagesEn.setupErrorReportNotice}`);
|
|
1566
1567
|
io.print(` Provider : ${marked.llm.provider}${marked.llm.model ? ` (${marked.llm.model})` : ''}`);
|
|
1567
1568
|
// EN5 — show what the loader will actually read (resolveSkillSources), not the raw preset fields.
|
|
1568
1569
|
const skillSources = resolveSkillSources(marked).filter((source) => source.enabled);
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync, renameSync } from 'node:fs';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
4
|
+
import { CardStore } from '../task-cards/card-store.js';
|
|
5
|
+
import { debug, redactSecretText } from '../debug/log.js';
|
|
6
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
7
|
+
import { recordRunExit, readRunExits } from '../harness/harness-incidents.js';
|
|
8
|
+
import { notifyOwners } from '../loops/checker.js';
|
|
9
|
+
import { bunVersion, cliFingerprint, gcTools, orphanCandidates, type FenceGcDeps } from '../hq/fence.js';
|
|
10
|
+
|
|
11
|
+
export interface MachineHeartbeatDeps extends FenceGcDeps {
|
|
12
|
+
root?: string;
|
|
13
|
+
now?: Date;
|
|
14
|
+
record?: typeof recordRunExit;
|
|
15
|
+
log?: typeof debug.log;
|
|
16
|
+
publish?: typeof notifyOwners;
|
|
17
|
+
card?: (command: string, day: string, evidencePaths: string[], root: string) => void;
|
|
18
|
+
version?: (pid: number, run: (binary: string, args: string[]) => string) => string;
|
|
19
|
+
/** How long the same tree must stay at the same CPU across guardian ticks before it is called stalled. */
|
|
20
|
+
stallMs?: number;
|
|
21
|
+
/** off = collect nothing · shadow (default) = candidates, evidence file and observation only · on = evidence, then SIGTERM. */
|
|
22
|
+
mode?: OrphanGcMode;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type OrphanGcMode = 'off' | 'shadow' | 'on';
|
|
26
|
+
|
|
27
|
+
/** A tree is «stalled» only when an earlier tick saw the very same tree at the very same CPU this long ago.
|
|
28
|
+
* One in-tick second is not enough: Linux `ps time` has whole-second resolution and I/O waits burn no CPU. */
|
|
29
|
+
export const ORPHAN_STALL_MS = 10 * 60_000;
|
|
30
|
+
/** `shadowEvidenced`: shadow already wrote this tree's evidence once — later shadow ticks skip it (no lsof/sample, no new file). */
|
|
31
|
+
type StallWatch = Record<string, { since: string; cpu: number; tree: string; shadowEvidenced?: true }>;
|
|
32
|
+
|
|
33
|
+
function readStallWatch(path: string): StallWatch {
|
|
34
|
+
if (!existsSync(path)) return {};
|
|
35
|
+
const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'));
|
|
36
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as StallWatch : {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** One cause card per command/day, with incident files as attachments in the incidents section. */
|
|
40
|
+
export function publishOrphanCauseCard(command: string, day: string, paths: string[], root: string): void {
|
|
41
|
+
const store = new CardStore(root);
|
|
42
|
+
try {
|
|
43
|
+
const hash = createHash('sha256').update(command).digest('hex').slice(0, 24);
|
|
44
|
+
const card = store.createCard({ goalId: `orphan-cli-${day}-${hash}`, title: `TC 원인 조사: ${redactSecretText(command)}` });
|
|
45
|
+
for (const path of paths) store.appendSection(card.id, { key: `incidents:${basename(path).replaceAll('.', '-')}`, owner: 'TC',
|
|
46
|
+
content: `증거: incidents/${basename(path)}\n가설(미확정): bun fs.watch 등 상주 핸들이 CLI 종료를 막음` });
|
|
47
|
+
} finally { store.close(); }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Run on the local guardian tick; an observation failure never authorizes termination. */
|
|
51
|
+
export async function runMachineHeartbeat(schedules: readonly { command: string; cron: string }[], deps: MachineHeartbeatDeps = {}): Promise<{ collected: number; terminated: number; cards: number }> {
|
|
52
|
+
const mode = deps.mode ?? 'shadow';
|
|
53
|
+
if (mode === 'off') return { collected: 0, terminated: 0, cards: 0 };
|
|
54
|
+
const tools = gcTools(deps);
|
|
55
|
+
const now = deps.now ?? new Date();
|
|
56
|
+
const root = deps.root ?? effectiveInstanceRoot();
|
|
57
|
+
const timeZone = deps.timeZone;
|
|
58
|
+
const stallMs = deps.stallMs ?? ORPHAN_STALL_MS;
|
|
59
|
+
const watchPath = join(root, 'ops', 'orphan-cli-watch.json');
|
|
60
|
+
// An unreadable watch never authorizes termination: start over and only observe this tick.
|
|
61
|
+
let watch: StallWatch;
|
|
62
|
+
try { watch = readStallWatch(watchPath); } catch { watch = {}; }
|
|
63
|
+
const nextWatch: StallWatch = {};
|
|
64
|
+
const stalled: ReturnType<typeof orphanCandidates> = [];
|
|
65
|
+
const first = tools.snapshot();
|
|
66
|
+
await tools.sleep(1_000);
|
|
67
|
+
const second = tools.snapshot();
|
|
68
|
+
let collected = 0;
|
|
69
|
+
let terminated = 0;
|
|
70
|
+
let cards = 0;
|
|
71
|
+
let alreadyEvidenced = 0;
|
|
72
|
+
const logDecision = (): void => {
|
|
73
|
+
try { (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'decision', { mode, candidates: stalled.length, collected, alreadyEvidenced, killed: terminated }); } catch { /* observe only */ }
|
|
74
|
+
};
|
|
75
|
+
for (const candidate of orphanCandidates(first, second, schedules, now, timeZone)) {
|
|
76
|
+
const key = `${candidate.process.pid}:${candidate.process.ppid}:${candidate.process.command}`;
|
|
77
|
+
const cpu = Math.round(candidate.tree.reduce((total, row) => total + row.cpuSeconds, 0) * 100) / 100;
|
|
78
|
+
const tree = candidate.tree.map(row => `${row.pid}:${row.cpuSeconds}`).join(',');
|
|
79
|
+
const seen = watch[key];
|
|
80
|
+
const elapsed = seen ? now.getTime() - Date.parse(seen.since) : NaN;
|
|
81
|
+
// Same tree, same CPU, and the process is at least as old as the watch (not a reused PID).
|
|
82
|
+
if (!seen || seen.cpu !== cpu || seen.tree !== tree || !(elapsed >= 0) || candidate.process.ageSeconds * 1000 + 2_000 < elapsed) {
|
|
83
|
+
nextWatch[key] = { since: now.toISOString(), cpu, tree };
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
nextWatch[key] = seen;
|
|
87
|
+
if (elapsed < stallMs) continue;
|
|
88
|
+
// Shadow never ends the tree, so the same hang stays stalled: evidence it once, not on every tick.
|
|
89
|
+
if (mode !== 'on' && seen.shadowEvidenced) { alreadyEvidenced++; continue; }
|
|
90
|
+
stalled.push(candidate);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
mkdirSync(join(root, 'ops'), { recursive: true });
|
|
94
|
+
const tmp = `${watchPath}.${process.pid}.tmp`;
|
|
95
|
+
writeFileSync(tmp, JSON.stringify(nextWatch), { mode: 0o600 });
|
|
96
|
+
renameSync(tmp, watchPath);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
// Without a durable watch the next tick cannot prove a stall either — observe only.
|
|
99
|
+
try { (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'observation-failed', { stage: 'stall-watch', error: redactSecretText(String(error)) }); } catch { /* observe only */ }
|
|
100
|
+
logDecision();
|
|
101
|
+
return { collected, terminated, cards };
|
|
102
|
+
}
|
|
103
|
+
const writeWatch = (): void => {
|
|
104
|
+
mkdirSync(join(root, 'ops'), { recursive: true });
|
|
105
|
+
const tmp = `${watchPath}.${process.pid}.tmp`;
|
|
106
|
+
writeFileSync(tmp, JSON.stringify(nextWatch), { mode: 0o600 });
|
|
107
|
+
renameSync(tmp, watchPath);
|
|
108
|
+
};
|
|
109
|
+
let shadowMarked = false;
|
|
110
|
+
for (const candidate of stalled) {
|
|
111
|
+
// Recheck the whole tree after slow diagnostics. A new child or CPU progress invalidates the decision.
|
|
112
|
+
let evidence: { command: string; ageSeconds: number; periodMinutes: number; pid: number; tree: number[]; lsof: string; sample: string; bunVersion: string; at: string };
|
|
113
|
+
try {
|
|
114
|
+
evidence = {
|
|
115
|
+
command: candidate.process.command, ageSeconds: candidate.process.ageSeconds, periodMinutes: candidate.periodMinutes, pid: candidate.process.pid,
|
|
116
|
+
tree: candidate.tree.map(row => row.pid),
|
|
117
|
+
lsof: tools.run('lsof', ['-p', candidate.tree.map(row => row.pid).join(',')]),
|
|
118
|
+
sample: tools.run('sample', [String(candidate.process.pid), '1']),
|
|
119
|
+
bunVersion: (deps.version ?? bunVersion)(candidate.process.pid, tools.run), at: now.toISOString(),
|
|
120
|
+
};
|
|
121
|
+
const latest = tools.snapshot();
|
|
122
|
+
const found = orphanCandidates(second, latest, schedules, now, timeZone).find(row => row.process.pid === candidate.process.pid);
|
|
123
|
+
if (!found || found.tree.length !== candidate.tree.length || found.tree.some(row => !candidate.tree.some(old => old.pid === row.pid))) continue;
|
|
124
|
+
// File + existing incident ledger + logs are committed before any signal is delivered.
|
|
125
|
+
const path = join(root, 'incidents', `orphan-cli-${now.getTime()}-${candidate.process.pid}-${randomUUID().slice(0, 8)}.json`);
|
|
126
|
+
mkdirSync(join(root, 'incidents'), { recursive: true });
|
|
127
|
+
const safe = JSON.stringify(evidence, (_key, value) => typeof value === 'string' ? redactSecretText(value) : value);
|
|
128
|
+
writeFileSync(path, safe, { flag: 'wx', mode: 0o600 });
|
|
129
|
+
const fingerprint = redactSecretText(cliFingerprint(candidate.process.command));
|
|
130
|
+
(deps.log ?? debug.log.bind(debug))('ops.orphan-cli', mode === 'on' ? 'evidence-before-termination' : 'shadow-evidence', {
|
|
131
|
+
path, command: redactSecretText(evidence.command), ageSeconds: evidence.ageSeconds, periodMinutes: evidence.periodMinutes, pid: evidence.pid,
|
|
132
|
+
tree: evidence.tree, lsof: redactSecretText(evidence.lsof), sample: redactSecretText(evidence.sample), bunVersion: evidence.bunVersion,
|
|
133
|
+
});
|
|
134
|
+
collected++;
|
|
135
|
+
if (mode !== 'on') {
|
|
136
|
+
const key = `${candidate.process.pid}:${candidate.process.ppid}:${candidate.process.command}`;
|
|
137
|
+
if (nextWatch[key]) { nextWatch[key] = { ...nextWatch[key]!, shadowEvidenced: true }; shadowMarked = true; }
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
// Children first: do not leave the stuck parent holding resources while descendants outlive it.
|
|
141
|
+
const signalFailures: Array<{ pid: number; error: string }> = [];
|
|
142
|
+
for (const row of [...found.tree].reverse()) {
|
|
143
|
+
try { tools.kill(row.pid); } catch (error) { signalFailures.push({ pid: row.pid, error: redactSecretText(String(error)) }); }
|
|
144
|
+
}
|
|
145
|
+
// The run-exit row records what the signals actually did, written after they were sent: SIGTERM only when every
|
|
146
|
+
// signal landed, otherwise no signal and the failures beside the evidence path. The evidence file and log above
|
|
147
|
+
// were committed before any signal. Either way the hang counts toward the cause card below.
|
|
148
|
+
(deps.record ?? recordRunExit)({ runId: `orphan-cli-${candidate.process.pid}-${randomUUID()}`, reason: `orphan-cli:${fingerprint}`, status: null,
|
|
149
|
+
signal: signalFailures.length === 0 ? 'SIGTERM' : null, at: now.toISOString(), pid: candidate.process.pid, entrance: 'guardian-tick',
|
|
150
|
+
lastLines: [path, ...signalFailures.map((failure) => `termination-failed pid=${failure.pid}: ${failure.error}`)] }, root);
|
|
151
|
+
if (signalFailures.length > 0) {
|
|
152
|
+
(deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'termination-failed', { path, pid: candidate.process.pid, failures: signalFailures });
|
|
153
|
+
} else terminated++;
|
|
154
|
+
const day = new Date(now.getTime() + 9 * 3_600_000).toISOString().slice(0, 10);
|
|
155
|
+
// One hang is one process: the same PID recorded on several ticks (its SIGTERM did not take) counts once.
|
|
156
|
+
const byPid = new Map<number, ReturnType<typeof readRunExits>[number]>();
|
|
157
|
+
for (const row of readRunExits(root)) {
|
|
158
|
+
if (row.reason !== `orphan-cli:${fingerprint}` || typeof row.pid !== 'number') continue;
|
|
159
|
+
if (new Date(Date.parse(row.at) + 9 * 3_600_000).toISOString().slice(0, 10) !== day) continue;
|
|
160
|
+
if (!byPid.has(row.pid)) byPid.set(row.pid, row);
|
|
161
|
+
}
|
|
162
|
+
const same = [...byPid.values()];
|
|
163
|
+
if (same.length >= 3) {
|
|
164
|
+
const paths = same.flatMap(row => row.lastLines ?? []).filter(file => existsSync(file));
|
|
165
|
+
if (paths.length < 3) {
|
|
166
|
+
(deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'cause-card-evidence-missing', { command: redactSecretText(candidate.process.command), count: same.length, evidence: paths.length });
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const reason = `원인 카드: ${fingerprint} · 하루 ${same.length}회 매달림 · 증거 ${paths.join(' , ')} · 가설(미확정): bun fs.watch 등 상주 핸들이 CLI 종료를 막음`;
|
|
170
|
+
(deps.card ?? publishOrphanCauseCard)(fingerprint, day, paths, root);
|
|
171
|
+
cards += (deps.publish ?? notifyOwners)([{ id: `orphan-cli:${fingerprint}`, owner: 'TC', enabled: true, registered: true, state: 'failing', reason }], { root, now });
|
|
172
|
+
}
|
|
173
|
+
} catch (error) {
|
|
174
|
+
try { (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'observation-failed', { pid: candidate.process.pid, error: redactSecretText(String(error)) }); } catch { /* log failure must not kill a process */ }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (shadowMarked) {
|
|
178
|
+
// A lost mark only means one more evidence file next tick — never a signal.
|
|
179
|
+
try { writeWatch(); } catch (error) {
|
|
180
|
+
try { (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'observation-failed', { stage: 'shadow-mark', error: redactSecretText(String(error)) }); } catch { /* observe only */ }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
logDecision();
|
|
184
|
+
return { collected, terminated, cards };
|
|
185
|
+
}
|