elanous 0.2.22 → 0.2.23
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/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-b23d2e92161d11fd.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-fbef064c213b2b18.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-d5341ac96203a983.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-6168a7c43e6ef8f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.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-2bd9ce9c020d02d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.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-745d9b6c015076f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.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/5619d59e87eddf66.css +1 -0
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
- package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +1 -1
- 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/graphs/log-horizon/log-horizon-watch.yaml +25 -0
- package/graphs/log-horizon/recipes.yaml +3 -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/bench-report.ts +82 -3
- package/scripts/ci-typecheck-changed.ts +10 -1
- package/scripts/hq/hq-fence-wrapper.sh +148 -0
- package/scripts/lib/typecheck-ratchet.ts +51 -0
- package/scripts/openai-relay-server.ts +5 -1
- package/scripts/release-loop/docs-node.ts +258 -43
- package/scripts/release-loop/gate-method.ts +59 -0
- package/scripts/release-loop/gate-node.ts +73 -7
- 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 +34 -4
- package/scripts/release-loop/resume.ts +53 -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 +8 -1
- package/scripts/rhythm/daily.ts +51 -2
- package/scripts/rhythm/weekly.ts +3 -2
- package/scripts/tsc-main-safety-net.ts +189 -0
- package/scripts/usage-rollup.ts +8 -4
- package/src/acp/codex-plugins.ts +48 -6
- package/src/agent/monad-agent-turn.ts +67 -5
- package/src/agent/run-context.ts +10 -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 +1 -1
- package/src/agent-mission/pr-review-watch.ts +6 -2
- package/src/agent-mission/review-loop.ts +33 -5
- package/src/agent-substrate/acp-reviewer.ts +17 -8
- package/src/agent-substrate/pr-reviewer.ts +164 -28
- package/src/agent-substrate/review-intent.ts +6 -4
- package/src/agent-substrate/self-review-cli.ts +111 -16
- 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/pr-manager.ts +12 -3
- 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/chat/index.ts +12 -3
- package/src/cli/agent-cli.ts +20 -0
- package/src/cli/brief-cli.ts +27 -21
- package/src/cli/cli-user-error.ts +9 -2
- package/src/cli/log-event-names.ts +3 -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 +30 -2
- package/src/cli/pr-land-overlap-evidence.ts +131 -0
- package/src/cli/release-cli.ts +53 -11
- package/src/cli/self-update.ts +173 -10
- package/src/cli/skills-cli.ts +12 -3
- package/src/cli/tasks-cli.ts +133 -27
- 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 +86 -2
- package/src/dashboard/chat-fold.ts +20 -0
- package/src/dashboard/first-screen-band.ts +151 -1
- package/src/dashboard/index.ts +27 -5
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
- package/src/dashboard/stale-install-check.ts +13 -2
- package/src/dashboard/turn-stream-formatter.ts +25 -0
- package/src/debug/log-diet.ts +159 -0
- package/src/debug/log.ts +52 -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 +119 -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/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 +1 -0
- package/src/graph-runner/runner.ts +54 -5
- package/src/harness/dispatch-backpressure.ts +259 -0
- package/src/harness/harness-cli-command.ts +107 -28
- package/src/harness/harness-seams.ts +2 -20
- package/src/harness/harness-substrate-default.ts +72 -1
- package/src/harness/nested-elanous-policy.ts +4 -2
- package/src/hq/fence-wrapper.ts +7 -0
- package/src/hq/hq.ts +33 -2
- package/src/hq/lease.ts +13 -0
- package/src/hq/seats.ts +114 -18
- package/src/index.ts +163 -64
- 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/intelligence-map/model-alias.ts +6 -0
- package/src/intelligence-map/model-catalog.ts +41 -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-provider.ts +175 -0
- package/src/llm/bedrock.ts +345 -0
- package/src/llm/provider-credentials.ts +3 -1
- package/src/llm.ts +306 -35
- package/src/loops/budget.ts +150 -0
- 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/mcp/mcp-oauth.ts +136 -17
- package/src/model-tier/llm-tier-map.ts +48 -4
- package/src/models/prompts.ts +22 -1
- package/src/mss/logging/horizon-watch.ts +168 -0
- package/src/mss/logging/log-store.ts +204 -15
- 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/outbound-report.ts +8 -3
- package/src/nexus/api/telegram-trigger-bot.ts +6 -3
- package/src/nexus/index.ts +10 -0
- package/src/nexus/outbound/format.ts +2 -0
- package/src/nexus/outbound/router.ts +198 -13
- package/src/oauth/codex-account-rotation.ts +16 -18
- package/src/oauth/codex-account-store.ts +134 -5
- package/src/oauth/fallback-chain.ts +28 -6
- package/src/onboarding.ts +2 -1
- 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 +10 -6
- package/src/prompt-cache/openrouter.ts +94 -0
- package/src/prompt-enhance/enhance.ts +46 -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 +91 -22
- 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/retro/daily.ts +23 -9
- package/src/seat-loop/seat-loop.ts +34 -1
- 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 +67 -3
- package/src/self-dev/dev-pipeline.ts +4 -6
- package/src/self-dev/draft-residue.ts +463 -0
- package/src/self-dev/draft-sweep.ts +151 -10
- package/src/self-dev/draft-triage-rules.ts +27 -1
- 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 +57 -2
- package/src/self-dev/orchestrate-summary-line.ts +13 -0
- package/src/self-dev/orchestrate.ts +8 -135
- 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 +3 -22
- package/src/self-dev/run-types.ts +178 -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 +2 -4
- package/src/self-implement/blocked-draft-policy.ts +3 -19
- package/src/self-implement/draft-on-stop-mode.ts +18 -0
- package/src/self-implement/follow-up-goals.ts +114 -38
- 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.ts +24 -4
- package/src/self-implement/goal-digest.ts +19 -0
- package/src/self-implement/graph-overlay-condition.ts +4 -0
- package/src/self-implement/headless-elanous-driver.ts +11 -9
- 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 +133 -16
- 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/seams.ts +36 -3
- package/src/self-implement/self-implement-cli.ts +3 -1
- 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/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 +20 -9
- package/src/steward/triage.ts +4 -2
- package/src/storage/file-lock.ts +8 -1
- package/src/task-agent/actions.ts +4 -0
- package/src/task-agent/card-evidence.ts +59 -13
- package/src/task-agent/judge.ts +4 -3
- package/src/task-agent/land-worktree.ts +201 -0
- package/src/task-agent/live-move-history.ts +133 -0
- package/src/task-agent/live-moves.ts +106 -19
- package/src/task-agent/parent-host.ts +117 -8
- package/src/task-agent/rejudge-on-head.ts +297 -0
- package/src/task-agent/review-result-capture.ts +218 -0
- package/src/task-agent/shadow.ts +103 -7
- package/src/task-agent/task-hand.ts +136 -11
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
- package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +66 -14
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
- package/src/task-orchestrator/surfaces/self-implement.ts +6 -2
- 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/user-config.ts +132 -24
- 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/scheduler.ts +1 -0
- 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 → rfkMm4movqkqMebBrCXiR}/_ssgManifest.js +0 -0
|
@@ -6,12 +6,15 @@
|
|
|
6
6
|
// ⛔ 토큰 «값»은 어디에도 출력하지 않는다 — accountId 앞 8자만(R-LLM2).
|
|
7
7
|
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
|
-
import {
|
|
9
|
+
import { mkdirSync, openSync, closeSync, unlinkSync, readFileSync, writeFileSync, statSync } from 'node:fs';
|
|
10
|
+
import { dirname, join, resolve } from 'node:path';
|
|
11
|
+
import { consumeCodexResetCredits, listCodexResetCredits } from '../budget/codex-reset-credits.js';
|
|
12
|
+
import { codexCredentialRoot, readAvailabilityState, writeAvailabilityState } from '../budget/codex-reset-credit-state.js';
|
|
10
13
|
import {
|
|
11
14
|
DEFAULT_CODEX_ACCOUNT, codexStoreKey, accountNameFromStoreKey, isValidAccountName, isCodexStoreKey,
|
|
12
15
|
resolveCodexAccount, effectiveCodexHome, type CodexHomeSource, type CodexAccountResolution,
|
|
13
16
|
} from './codex-account.js';
|
|
14
|
-
import { authStorePath, defaultCodexHome, listProviders, loadTokens, saveTokens } from './store.js';
|
|
17
|
+
import { authStorePath, defaultCodexHome, isUnderTestRunner, listProviders, loadTokens, saveTokens } from './store.js';
|
|
15
18
|
import { readFreshAvailabilityState, quotaSignalDir, readQuotaSignal, readQuotaSignalCredits, readQuotaSignalUsedPercent, readQuotaSignalObservedAt, readQuotaSignalObservedAtRaw } from '../budget/codex-reset-credit-state.js';
|
|
16
19
|
import { creditPaceStatus } from '../budget/codex-credit-pace.js';
|
|
17
20
|
import { loadLlmPolicy } from '../policy/llm-policy.js';
|
|
@@ -29,6 +32,8 @@ import {
|
|
|
29
32
|
type FallbackDecision, type FallbackInput, type RotationOutcome,
|
|
30
33
|
} from './fallback-chain.js';
|
|
31
34
|
import { resolveGrokCredential } from '../grok/credential.js';
|
|
35
|
+
import { getOpenRouterApiKey } from '../config.js';
|
|
36
|
+
import { lookupOpenRouterModelSpec } from '../model-tier/llm-tier-map.js';
|
|
32
37
|
import { sendOutbound } from '../domains/outbound-alert.js';
|
|
33
38
|
|
|
34
39
|
type CodexAccountOutboundSender = (text: string, kind?: string) => boolean;
|
|
@@ -47,7 +52,7 @@ export function _setCodexAccountOutboundSenderForTesting(sender: CodexAccountOut
|
|
|
47
52
|
/** ⛔⭐ 정적 import 로 읽는다 — 종전 `require()` 는 ESM 에서 «정의되지 않을 수 있고», 그러면
|
|
48
53
|
* fail-soft 가 삼켜 ***config false 가 영영 무시된다***(리뷰 should-fix: 노브가 no-op 이 된다).
|
|
49
54
|
* ⚠️ 순환 없음을 확인했다 — user-config 는 oauth 를 안 끌어온다. */
|
|
50
|
-
type RotationConfig = { llm?: { codexAccountRotation?: boolean; codexAccountAlerts?: boolean; codexAccountRotationThresholdPercent?: unknown; codexAccountRotationThresholdPercentByAccount?: Readonly<Record<string, unknown>>; codexCreditsAllowed?: boolean; codexQuotaPolicy?: unknown; fallbackChain?: unknown } };
|
|
55
|
+
type RotationConfig = { llm?: { codexAccountRotation?: boolean; codexAccountAlerts?: boolean; codexAccountRotationThresholdPercent?: unknown; codexAccountRotationThresholdPercentByAccount?: Readonly<Record<string, unknown>>; codexCreditsAllowed?: boolean; codexResetAutoConsumePerDay?: number; codexQuotaPolicy?: unknown; fallbackChain?: unknown; openrouter?: { fallbackModel?: unknown } } };
|
|
51
56
|
|
|
52
57
|
function readUserConfig(): RotationConfig {
|
|
53
58
|
return getUserConfig();
|
|
@@ -636,6 +641,9 @@ export function resolveCodexAccountForRun(
|
|
|
636
641
|
to: decision.reason === 'credit-pace' ? decision.to?.name ?? current.name : decision.to?.name,
|
|
637
642
|
});
|
|
638
643
|
observeRotation(decision, current.name);
|
|
644
|
+
// 순서 ② — 구독 남은 계정이 없고 리셋권이 있으면 «스스로 1개» 쓴다(일일 상한 · 비동기 · 이번 호출은 종전대로 머문다).
|
|
645
|
+
// ⛔ 판정이 `reset-credit-available` 일 때만 닿는다 — 구독 남은 계정이 있으면(rotated) 여기 안 온다.
|
|
646
|
+
if (decision.reason === 'reset-credit-available') void autoConsumeCodexResetCredit({ storePath: path });
|
|
639
647
|
const resolved = applyRotation(current, decision);
|
|
640
648
|
if (resolved.source === 'rotated') {
|
|
641
649
|
notifyCodexAccountEventWithUsage('rotation', path, now,
|
|
@@ -658,6 +666,111 @@ export function resolveCodexAccountForRun(
|
|
|
658
666
|
return resolved;
|
|
659
667
|
}
|
|
660
668
|
|
|
669
|
+
/** 리셋권 자동 소비 결과 — 소비했거나, 왜 안 했는지(관측 `reset-consume-skipped` 와 같은 이유). */
|
|
670
|
+
export type CodexResetAutoConsumeOutcome =
|
|
671
|
+
| { readonly consumed: true; readonly account: string; readonly expiresAt: string | null; readonly todayCount: number; readonly redecision?: string }
|
|
672
|
+
| { readonly consumed: false; readonly reason: 'disabled' | 'daily-cap-reached' | 'test-runtime-guard' | 'in-flight' | 'lock-held' | 'no-available-credit' | 'consume-failed' | 'error'; readonly detail?: string };
|
|
673
|
+
|
|
674
|
+
export interface CodexResetAutoConsumeDeps {
|
|
675
|
+
readonly storePath?: string;
|
|
676
|
+
readonly now?: number;
|
|
677
|
+
/** ⛔ 테스트는 «반드시» 가짜를 준다 — 안 주면 실물이고, 테스트 러너 안에서는 실물을 «부르지 않는다». */
|
|
678
|
+
readonly consume?: typeof consumeCodexResetCredits;
|
|
679
|
+
readonly list?: typeof listCodexResetCredits;
|
|
680
|
+
/** 일일 카운터 파일(테스트 격리). 기본 = 자격 뿌리 `budget/codex-reset-auto-consume.json`. */
|
|
681
|
+
readonly counterPath?: string;
|
|
682
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/** `llm.codexResetAutoConsumePerDay` — 기본 1 · 0 이면 끔 · 못 읽으면 기본. */
|
|
686
|
+
function resetAutoConsumePerDayFromConfig(): number {
|
|
687
|
+
try {
|
|
688
|
+
const v = (configReader().llm as { codexResetAutoConsumePerDay?: unknown } | undefined)?.codexResetAutoConsumePerDay;
|
|
689
|
+
return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0 ? v : 1;
|
|
690
|
+
} catch { return 1; }
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function readAutoConsumeCount(path: string, day: string): number {
|
|
694
|
+
try {
|
|
695
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8')) as { day?: unknown; count?: unknown };
|
|
696
|
+
return parsed.day === day && typeof parsed.count === 'number' && Number.isFinite(parsed.count) ? parsed.count : 0;
|
|
697
|
+
} catch { return 0; }
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
let autoConsumeInFlight = false;
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* 순서 ② «리셋권» — 만료가 가장 이른 계정의 리셋권을 «하나» 쓴다. ⛔ 되돌릴 수 없다.
|
|
704
|
+
* ⛔ 소비는 기존 `consumeCodexResetCredits` 한 연산뿐이다(새 API 경로 없음).
|
|
705
|
+
* ⛔ 하루 상한(UTC 일) — 소비 «전»에 칸을 잡는다(실패해도 그날 칸은 쓴 것으로 센다: 되돌릴 수 없는 일은 덜 하는 쪽).
|
|
706
|
+
* 성공 → `codex.rotation reset-consumed` ⊕ 소비 알림 ⊕ 판정을 한 번 다시 돈다(조회 전용).
|
|
707
|
+
* 실패·상한 → `codex.rotation reset-consume-skipped { reason }` — 호출부는 종전대로 크레딧 단계로 간다.
|
|
708
|
+
*/
|
|
709
|
+
export async function autoConsumeCodexResetCredit(deps: CodexResetAutoConsumeDeps = {}): Promise<CodexResetAutoConsumeOutcome> {
|
|
710
|
+
const skip = (reason: Extract<CodexResetAutoConsumeOutcome, { consumed: false }>['reason'], extra: Record<string, unknown> = {}): CodexResetAutoConsumeOutcome => {
|
|
711
|
+
debug.log('codex.rotation', 'reset-consume-skipped', { reason, ...extra });
|
|
712
|
+
return { consumed: false, reason, ...(typeof extra.detail === 'string' ? { detail: extra.detail } : {}) };
|
|
713
|
+
};
|
|
714
|
+
const cap = resetAutoConsumePerDayFromConfig();
|
|
715
|
+
if (cap <= 0) return skip('disabled', { cap });
|
|
716
|
+
const now = deps.now ?? Date.now();
|
|
717
|
+
const day = new Date(now).toISOString().slice(0, 10);
|
|
718
|
+
const counterPath = deps.counterPath ?? join(codexCredentialRoot(), 'budget', 'codex-reset-auto-consume.json');
|
|
719
|
+
const before = readAutoConsumeCount(counterPath, day);
|
|
720
|
+
if (before >= cap) return skip('daily-cap-reached', { cap, todayCount: before });
|
|
721
|
+
// ⛔⭐ 되돌릴 수 없는 실물 소비를 테스트가 «절대» 못 부르게 — 가짜를 안 줬고 테스트 러너면 멈춘다.
|
|
722
|
+
if ((!deps.consume || !deps.list) && isUnderTestRunner(deps.env ?? process.env)) return skip('test-runtime-guard');
|
|
723
|
+
const consume = deps.consume ?? consumeCodexResetCredits;
|
|
724
|
+
const list = deps.list ?? listCodexResetCredits;
|
|
725
|
+
if (autoConsumeInFlight) return skip('in-flight');
|
|
726
|
+
const lockPath = `${counterPath}.lock`;
|
|
727
|
+
let lockFd: number | undefined;
|
|
728
|
+
autoConsumeInFlight = true;
|
|
729
|
+
try {
|
|
730
|
+
mkdirSync(dirname(counterPath), { recursive: true });
|
|
731
|
+
try { lockFd = openSync(lockPath, 'wx'); } catch {
|
|
732
|
+
// 죽은 프로세스가 남긴 잠금(10분 넘음)은 걷고 한 번만 다시 잡는다 — 안 그러면 자동 소비가 영영 꺼진다.
|
|
733
|
+
try { if (now - statSync(lockPath).mtimeMs > 10 * 60_000) { unlinkSync(lockPath); lockFd = openSync(lockPath, 'wx'); } } catch { /* */ }
|
|
734
|
+
if (lockFd === undefined) return skip('lock-held');
|
|
735
|
+
}
|
|
736
|
+
// 다른 프로세스가 방금 썼을 수 있다 — 잠근 «뒤»에 다시 센다.
|
|
737
|
+
const locked = readAutoConsumeCount(counterPath, day);
|
|
738
|
+
if (locked >= cap) return skip('daily-cap-reached', { cap, todayCount: locked });
|
|
739
|
+
const path = deps.storePath ?? authStorePath();
|
|
740
|
+
let earliest: { name: string; home: string; expiresAt: string | null; expiresMs: number } | undefined;
|
|
741
|
+
for (const candidate of buildRotationCandidates(path, now, deps.env ?? process.env)) {
|
|
742
|
+
if (!candidate.home) continue;
|
|
743
|
+
const listed = await list({ authFilePath: join(candidate.home, 'auth.json'), env: { CODEX_HOME: candidate.home } as unknown as NodeJS.ProcessEnv });
|
|
744
|
+
if (!listed.ok) continue;
|
|
745
|
+
for (const credit of listed.value.credits) {
|
|
746
|
+
if (credit.status !== 'available' || credit.redeemed_at) continue;
|
|
747
|
+
const ms = credit.expires_at ? Date.parse(credit.expires_at) : Number.POSITIVE_INFINITY;
|
|
748
|
+
const expiresMs = Number.isFinite(ms) || ms === Number.POSITIVE_INFINITY ? ms : Number.POSITIVE_INFINITY;
|
|
749
|
+
if (!earliest || expiresMs < earliest.expiresMs) earliest = { name: candidate.name, home: candidate.home, expiresAt: credit.expires_at, expiresMs };
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
if (!earliest) return skip('no-available-credit');
|
|
753
|
+
const todayCount = locked + 1;
|
|
754
|
+
writeFileSync(counterPath, `${JSON.stringify({ day, count: todayCount, lastAccount: earliest.name, at: new Date(now).toISOString() })}\n`, 'utf8');
|
|
755
|
+
const result = await consume({ authFilePath: join(earliest.home, 'auth.json'), env: { CODEX_HOME: earliest.home } as unknown as NodeJS.ProcessEnv });
|
|
756
|
+
if (!result.ok) return skip('consume-failed', { account: earliest.name, kind: result.kind, detail: result.message.slice(0, 200), todayCount });
|
|
757
|
+
const previous = readAvailabilityState(earliest.home);
|
|
758
|
+
const remaining = typeof previous === 'number' ? Math.max(0, previous - 1) : undefined;
|
|
759
|
+
if (remaining !== undefined) { try { writeAvailabilityState(remaining, earliest.home); } catch { /* 관측 갱신 실패는 소비를 되돌리지 않는다 */ } }
|
|
760
|
+
debug.log('codex.rotation', 'reset-consumed', { account: earliest.name, expiresAt: earliest.expiresAt, todayCount });
|
|
761
|
+
notifyCodexResetCreditConsumed({ name: earliest.name }, remaining, { storePath: path, now });
|
|
762
|
+
// 판정을 한 번 다시 돈다 — 조회 전용(관측·고정 없음). 다음 런 판정이 그 계정을 구독으로 고른다.
|
|
763
|
+
let redecision: string | undefined;
|
|
764
|
+
try { redecision = inspectCodexRotation(deps.env ?? process.env, { storePath: path }).reason; } catch { /* 재판정 실패는 소비 결과를 바꾸지 않는다 */ }
|
|
765
|
+
return { consumed: true, account: earliest.name, expiresAt: earliest.expiresAt, todayCount, ...(redecision ? { redecision } : {}) };
|
|
766
|
+
} catch (error) {
|
|
767
|
+
return skip('error', { detail: error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200) });
|
|
768
|
+
} finally {
|
|
769
|
+
if (lockFd !== undefined) { try { closeSync(lockFd); } catch { /* */ } try { unlinkSync(lockPath); } catch { /* */ } }
|
|
770
|
+
autoConsumeInFlight = false;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
661
774
|
/**
|
|
662
775
|
* ⛔⭐⭐⭐⭐⭐ **회전한 계정을 «자식 env»로만 내려보낸다** (2026-08-07 · 크레딧 유출 차단).
|
|
663
776
|
*
|
|
@@ -738,6 +851,8 @@ export function resolveRunFallback(
|
|
|
738
851
|
readonly grokAvailable?: boolean;
|
|
739
852
|
/** ⛔ grok «잔량» seam — 안 주면 재지 «않고» 'unknown' 이다(이 판정은 네트워크를 안 친다). */
|
|
740
853
|
readonly grokQuota?: 'usable' | 'exhausted' | 'unknown';
|
|
854
|
+
/** OpenRouter 키 «존재» seam(테스트 격리) — 안 주면 `getOpenRouterApiKey()` 로 잰다. 키 값은 기록하지 않는다. */
|
|
855
|
+
readonly openrouterAvailable?: boolean;
|
|
741
856
|
} & Pick<FallbackInput, 'currentStep' | 'currentCredentialRateLimited'> = {},
|
|
742
857
|
): FallbackDecision {
|
|
743
858
|
try {
|
|
@@ -777,11 +892,18 @@ export function resolveRunFallback(
|
|
|
777
892
|
// ⛔ 「지금 쓸 수 있나」는 «자격과 다른 축»이다. 안 주면 'unknown' — 그리고 unknown 은 «통과»다.
|
|
778
893
|
// ⇒ 「모르고 갔다」와 「알고 갔다」가 관측에서 갈린다(아래 grokQuota).
|
|
779
894
|
const grokQuota = deps.grokQuota ?? readCachedGrokQuota();
|
|
780
|
-
const
|
|
895
|
+
const fallbackModel = configReader().llm?.openrouter?.fallbackModel;
|
|
896
|
+
const openrouterFallbackModel = typeof fallbackModel === 'string' ? fallbackModel : undefined;
|
|
897
|
+
const openrouterAvailable = chain.includes('openrouter')
|
|
898
|
+
&& (deps.openrouterAvailable ?? Boolean(getOpenRouterApiKey()?.trim()));
|
|
899
|
+
const fallbackBase = { rotation, chain, grokAvailable, grokQuota, openrouterFallbackModel, openrouterAvailable };
|
|
781
900
|
const fallbackInput: FallbackInput = deps.currentCredentialRateLimited === true && deps.currentStep
|
|
782
901
|
? { ...fallbackBase, currentStep: deps.currentStep, currentCredentialRateLimited: true }
|
|
783
902
|
: { ...fallbackBase, ...(deps.currentStep ? { currentStep: deps.currentStep } : {}) };
|
|
784
903
|
const decision = decideFallback(fallbackInput);
|
|
904
|
+
// tier-map 칸(가격·창 근거) — 유료 전환은 «무슨 값으로 가는지»를 관측에 남긴다. 미등록이면 'unregistered'.
|
|
905
|
+
const openrouterSpec = decision.action === 'switch-backend' && decision.backend === 'openrouter'
|
|
906
|
+
? lookupOpenRouterModelSpec(decision.model) : undefined;
|
|
785
907
|
|
|
786
908
|
debug.log('oauth.fallback-chain', 'decide', {
|
|
787
909
|
rotationReason: rotation.reason,
|
|
@@ -797,16 +919,23 @@ export function resolveRunFallback(
|
|
|
797
919
|
...(dropped.length > 0 ? { droppedSteps: dropped } : {}),
|
|
798
920
|
grokAvailable,
|
|
799
921
|
grokQuota,
|
|
922
|
+
...(chain.includes('openrouter') ? { openrouterAvailable, openrouterModelConfigured: Boolean(openrouterFallbackModel?.trim()) } : {}),
|
|
800
923
|
action: decision.action,
|
|
801
924
|
...(decision.action === 'switch-backend' ? { backend: decision.backend } : {}),
|
|
925
|
+
...(decision.action === 'switch-backend' && decision.backend === 'openrouter'
|
|
926
|
+
? { model: decision.model, modelSpec: openrouterSpec ? `${openrouterSpec.label} · ${openrouterSpec.rationale}` : 'unregistered' }
|
|
927
|
+
: {}),
|
|
802
928
|
...(decision.action === 'stay' ? { why: decision.why } : {}),
|
|
803
929
|
...(decision.action === 'codex-rotate' ? { to: decision.to.name } : {}),
|
|
804
930
|
});
|
|
805
931
|
if (decision.action === 'switch-backend') {
|
|
932
|
+
const openrouterNote = decision.backend === 'openrouter'
|
|
933
|
+
? ` · API 과금 ${decision.model} (${openrouterSpec ? `${openrouterSpec.label} · ${openrouterSpec.rationale}` : 'tier-map 미등록'})`
|
|
934
|
+
: '';
|
|
806
935
|
emitDecision({
|
|
807
936
|
kind: 'ROUTE',
|
|
808
937
|
what: `공급자 전환 codex → ${decision.backend}`,
|
|
809
|
-
reason: `회전 ${rotation.reason} · 정책 ${quotaPolicy}${fallbackInput.currentCredentialRateLimited ? ' · 한도 오류' : ''}`,
|
|
938
|
+
reason: `회전 ${rotation.reason} · 정책 ${quotaPolicy}${openrouterNote}${fallbackInput.currentCredentialRateLimited ? ' · 한도 오류' : ''}`,
|
|
810
939
|
purpose: '작업을 멈추지 않고 이어 간다',
|
|
811
940
|
target: decision.backend,
|
|
812
941
|
paths: chain.length,
|
|
@@ -22,7 +22,7 @@ import type { RotationCandidate } from './codex-account-rotation.js';
|
|
|
22
22
|
import type { ClaudePtyMaturity } from './claude-pty-maturity.js';
|
|
23
23
|
|
|
24
24
|
/** 체인에 놓을 수 있는 칸. ⛔ 모르는 이름은 «조용히 건너뛰지 않고» 거부한다(오타 방어). */
|
|
25
|
-
export const FALLBACK_STEPS = ['codex-rotate', 'grok', 'claude-pty'] as const;
|
|
25
|
+
export const FALLBACK_STEPS = ['codex-rotate', 'grok', 'claude-pty', 'openrouter'] as const;
|
|
26
26
|
export type FallbackStep = (typeof FALLBACK_STEPS)[number];
|
|
27
27
|
|
|
28
28
|
/** 기본 체인 — ⛔⭐ **2026-08-20 에 `grok` 이 «기본»으로 들어왔다**(대표 지시).
|
|
@@ -78,6 +78,8 @@ export type FallbackDecision =
|
|
|
78
78
|
| { readonly action: 'codex-rotate'; readonly to: RotationCandidate }
|
|
79
79
|
/** 백엔드를 통째로 바꾼다. */
|
|
80
80
|
| { readonly action: 'switch-backend'; readonly backend: 'grok' | 'claude' }
|
|
81
|
+
/** 명시한 유료 OpenRouter 모델로 전환한다. 호출부가 모델을 바꾸지 못하면 실행하지 않는다. */
|
|
82
|
+
| { readonly action: 'switch-backend'; readonly backend: 'openrouter'; readonly model: string }
|
|
81
83
|
/** 아무것도 안 한다 — 이유를 «값으로» 남긴다. */
|
|
82
84
|
| { readonly action: 'stay'; readonly why: StayReason };
|
|
83
85
|
|
|
@@ -98,6 +100,8 @@ export type StayReason =
|
|
|
98
100
|
| 'grok-unavailable'
|
|
99
101
|
/** grok 자격은 있는데 «잔량이 소진»됐다 — 자격 부재와 «다른 값»이다. */
|
|
100
102
|
| 'grok-exhausted'
|
|
103
|
+
/** 유료 OpenRouter 모델 또는 키가 없다. */
|
|
104
|
+
| 'openrouter-unavailable'
|
|
101
105
|
/** claude PTY 의 최근 표본이 성숙 관문을 통과하지 못했거나 읽히지 않는다. */
|
|
102
106
|
| 'claude-pty-immature';
|
|
103
107
|
|
|
@@ -113,6 +117,10 @@ export type FallbackInput = {
|
|
|
113
117
|
/** grok 자격이 «있나». ⛔ 「모른다」를 boolean 에 접지 마라 — 호출자가
|
|
114
118
|
* `resolveGrokCredential() !== null` 로 확정해서 준다. */
|
|
115
119
|
readonly grokAvailable: boolean;
|
|
120
|
+
/** `llm.openrouter.fallbackModel` — 기본 모델로의 유료 폴백은 허용하지 않는다. */
|
|
121
|
+
readonly openrouterFallbackModel?: string;
|
|
122
|
+
/** OpenRouter 키 존재 여부(키 값 자체는 판정·관측에 넣지 않는다). */
|
|
123
|
+
readonly openrouterAvailable?: boolean;
|
|
116
124
|
/**
|
|
117
125
|
* grok 이 «지금 쓸 수 있나» — ⛔ 자격(`grokAvailable`)과 «다른 축»이다.
|
|
118
126
|
* 'usable' 쓸 수 있다(잔량 있음 · 무제한 · 임계 미만)
|
|
@@ -154,11 +162,13 @@ export function decideFallback(input: FallbackInput): FallbackDecision {
|
|
|
154
162
|
const {
|
|
155
163
|
rotation, chain, currentStep, currentCredentialRateLimited = false,
|
|
156
164
|
grokAvailable, grokQuota = 'unknown', claudePtyMaturity, stayOnResetCreditAvailable = false,
|
|
165
|
+
openrouterFallbackModel, openrouterAvailable = false,
|
|
157
166
|
} = input;
|
|
167
|
+
const openrouter = { model: openrouterFallbackModel, available: openrouterAvailable };
|
|
158
168
|
|
|
159
169
|
if (currentCredentialRateLimited) {
|
|
160
170
|
if (currentStep === undefined) return { action: 'stay', why: 'chain-exhausted' };
|
|
161
|
-
return stepAfter(chain, currentStep, grokAvailable, grokQuota, claudePtyMaturity, 'chain-exhausted');
|
|
171
|
+
return stepAfter(chain, currentStep, grokAvailable, grokQuota, claudePtyMaturity, openrouter, 'chain-exhausted');
|
|
162
172
|
}
|
|
163
173
|
if (rotation.reason === 'explicit') return { action: 'stay', why: 'explicit' };
|
|
164
174
|
if (rotation.reason === 'not-reached' || (rotation.reason === 'credit-pace' && !('to' in rotation))) {
|
|
@@ -172,13 +182,13 @@ export function decideFallback(input: FallbackInput): FallbackDecision {
|
|
|
172
182
|
// 회전이 답을 냈는데 체인이 codex-rotate 를 «빼» 놨다면 그 뜻을 존중하고
|
|
173
183
|
// 다음 칸으로 간다(회전을 원치 않는 구성).
|
|
174
184
|
if (chain.includes('codex-rotate')) return { action: 'codex-rotate', to: rotation.to };
|
|
175
|
-
return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, 'chain-exhausted');
|
|
185
|
+
return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, openrouter, 'chain-exhausted');
|
|
176
186
|
}
|
|
177
187
|
|
|
178
188
|
// no-candidate | disabled | reset-credit-available(기본) — codex 축이 끝났다. 다음 칸을 본다.
|
|
179
189
|
// ⛔ 다음 칸이 «없을 때»의 이름만 고른다. 진행(stepAfterCodex)은 그대로다.
|
|
180
190
|
const fallbackWhy = stayReasonWhenCodexAxisEnds(rotation.reason === 'credit-pace' ? 'no-candidate' : rotation.reason);
|
|
181
|
-
return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, fallbackWhy);
|
|
191
|
+
return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, openrouter, fallbackWhy);
|
|
182
192
|
}
|
|
183
193
|
|
|
184
194
|
/** codex 축이 끝났는데 체인 다음 칸도 없을 때 머무는 이유.
|
|
@@ -197,9 +207,10 @@ function stepAfterCodex(
|
|
|
197
207
|
grokAvailable: boolean,
|
|
198
208
|
grokQuota: 'usable' | 'exhausted' | 'unknown',
|
|
199
209
|
claudePtyMaturity: ClaudePtyMaturity | undefined,
|
|
210
|
+
openrouter: { readonly model?: string; readonly available: boolean },
|
|
200
211
|
whyIfNone: StayReason,
|
|
201
212
|
): FallbackDecision {
|
|
202
|
-
return stepAfter(chain, 'codex-rotate', grokAvailable, grokQuota, claudePtyMaturity, whyIfNone);
|
|
213
|
+
return stepAfter(chain, 'codex-rotate', grokAvailable, grokQuota, claudePtyMaturity, openrouter, whyIfNone);
|
|
203
214
|
}
|
|
204
215
|
|
|
205
216
|
function stepAfter(
|
|
@@ -208,12 +219,21 @@ function stepAfter(
|
|
|
208
219
|
grokAvailable: boolean,
|
|
209
220
|
grokQuota: 'usable' | 'exhausted' | 'unknown',
|
|
210
221
|
claudePtyMaturity: ClaudePtyMaturity | undefined,
|
|
222
|
+
openrouter: { readonly model?: string; readonly available: boolean },
|
|
211
223
|
whyIfNone: StayReason,
|
|
212
224
|
): FallbackDecision {
|
|
213
225
|
const idx = currentStep === undefined ? -1 : chain.indexOf(currentStep);
|
|
214
226
|
const rest = idx === -1 ? chain : chain.slice(idx + 1);
|
|
215
227
|
let unavailableWhy: StayReason | undefined;
|
|
216
228
|
for (const step of rest) {
|
|
229
|
+
if (step === 'openrouter') {
|
|
230
|
+
const model = openrouter.model?.trim();
|
|
231
|
+
if (!openrouter.available || !model || !/^openrouter\/[^/\s]+\/[^\s]+$/.test(model)) {
|
|
232
|
+
unavailableWhy = 'openrouter-unavailable';
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
return { action: 'switch-backend', backend: 'openrouter', model };
|
|
236
|
+
}
|
|
217
237
|
if (step === 'grok') {
|
|
218
238
|
// 자격 부재와 소진은 다른 값이다. 다음 칸이 있으면 그 칸을 살핀다.
|
|
219
239
|
if (!grokAvailable) { unavailableWhy = 'grok-unavailable'; continue; }
|
|
@@ -236,7 +256,9 @@ export function describeFallback(decision: FallbackDecision): string {
|
|
|
236
256
|
case 'codex-rotate':
|
|
237
257
|
return `codex 계정 전환 → ${decision.to.name}`;
|
|
238
258
|
case 'switch-backend':
|
|
239
|
-
return
|
|
259
|
+
return decision.backend === 'openrouter'
|
|
260
|
+
? `백엔드 전환 → openrouter (${decision.model} · API 과금)`
|
|
261
|
+
: `백엔드 전환 → ${decision.backend} (구독)`;
|
|
240
262
|
case 'stay':
|
|
241
263
|
return `전환 없음 (${decision.why})`;
|
|
242
264
|
}
|
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);
|
|
@@ -72,25 +72,17 @@ export function readClaudePackageLedger(
|
|
|
72
72
|
return { status: 'installed-plugins-unreadable', packages: [] };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const marketplacesRaw = readJsonFile(marketplacesPath);
|
|
76
|
-
if (marketplacesRaw === undefined) {
|
|
77
|
-
return { status: 'known-marketplaces-unreadable', packages: [] };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
75
|
const plugins = asPluginMap(installedRaw);
|
|
81
76
|
if (plugins === undefined) {
|
|
82
77
|
return { status: 'installed-plugins-unreadable', packages: [] };
|
|
83
78
|
}
|
|
84
79
|
|
|
85
|
-
const marketplaces = asMarketplaceMap(
|
|
86
|
-
|
|
87
|
-
return { status: 'known-marketplaces-unreadable', packages: [] };
|
|
88
|
-
}
|
|
89
|
-
|
|
80
|
+
const marketplaces = asMarketplaceMap(readJsonFile(marketplacesPath));
|
|
81
|
+
const status: ClaudePackageLedgerStatus = marketplaces === undefined ? 'known-marketplaces-unreadable' : 'ok';
|
|
90
82
|
const packages: ClaudeInstalledPackage[] = [];
|
|
91
83
|
for (const [key, records] of Object.entries(plugins)) {
|
|
92
84
|
const { plugin, marketplace } = splitClaudePluginKey(key);
|
|
93
|
-
const source = formatMarketplaceSource(marketplaces[marketplace]);
|
|
85
|
+
const source = formatMarketplaceSource(marketplaces?.[marketplace]);
|
|
94
86
|
for (const record of records) {
|
|
95
87
|
packages.push({
|
|
96
88
|
name: key,
|
|
@@ -104,7 +96,7 @@ export function readClaudePackageLedger(
|
|
|
104
96
|
}
|
|
105
97
|
}
|
|
106
98
|
|
|
107
|
-
return { status
|
|
99
|
+
return { status, packages };
|
|
108
100
|
}
|
|
109
101
|
|
|
110
102
|
function readJsonFile(path: string): unknown {
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
3
|
+
import { join, relative, resolve, sep } from 'node:path';
|
|
1
4
|
import type { ExecutionSurfaceSpec } from '../../display/index.js';
|
|
2
5
|
import type { PluginCapability, PluginSource } from './manifest.js';
|
|
3
6
|
|
|
@@ -83,6 +86,144 @@ export class PluginCapabilityPolicy {
|
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
|
|
89
|
+
export type PluginScanLevel = 'safe' | 'caution' | 'dangerous';
|
|
90
|
+
export interface PluginSecurityFinding { level: Exclude<PluginScanLevel, 'safe'>; code: string }
|
|
91
|
+
export interface PluginSecurityDecision {
|
|
92
|
+
scan: PluginScanLevel;
|
|
93
|
+
findings: PluginSecurityFinding[];
|
|
94
|
+
integrity: string;
|
|
95
|
+
license: 'redistributable' | 'restricted' | 'unknown';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Scan bytes before consent or installation. Only non-identifying codes leave this boundary. */
|
|
99
|
+
export function inspectPluginSecurity(dir: string): PluginSecurityDecision {
|
|
100
|
+
const findings: PluginSecurityFinding[] = [];
|
|
101
|
+
const hash = createHash('sha256');
|
|
102
|
+
let license: PluginSecurityDecision['license'] = 'unknown';
|
|
103
|
+
// Code files are collected first; import/exec checks run after we know which files are reachable at runtime.
|
|
104
|
+
const code = new Map<string, { text: string; test: boolean }>();
|
|
105
|
+
const entrypoints: string[] = [];
|
|
106
|
+
const visit = (folder: string): void => {
|
|
107
|
+
for (const entry of readdirSync(folder, { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
108
|
+
const file = join(folder, entry.name);
|
|
109
|
+
const rel = relative(dir, file).replaceAll('\\', '/');
|
|
110
|
+
if (entry.isSymbolicLink() || (!entry.isDirectory() && !entry.isFile())) {
|
|
111
|
+
findings.push({ level: 'dangerous', code: 'unsafe-entry' });
|
|
112
|
+
hash.update(rel).update('!\0');
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (entry.isDirectory()) { hash.update(rel).update('/\0'); visit(file); continue; }
|
|
116
|
+
hash.update(rel).update('\0');
|
|
117
|
+
// Size is checked before reading so an oversized import cannot exhaust memory in the scanner.
|
|
118
|
+
const size = statSync(file).size;
|
|
119
|
+
if (size > 2_000_000) {
|
|
120
|
+
hash.update(String(size)).update('\0').update('oversize');
|
|
121
|
+
findings.push({ level: 'dangerous', code: 'unscannable-file' });
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const bytes = readFileSync(file);
|
|
125
|
+
hash.update(String(bytes.length)).update('\0').update(bytes);
|
|
126
|
+
if (/(?:^|\/)(?:\.env(?:\.|$)|id_rsa$|credentials?\.json$)/i.test(rel)) {
|
|
127
|
+
findings.push({ level: 'dangerous', code: 'credential-file' });
|
|
128
|
+
}
|
|
129
|
+
if (/(?:api[_-]?key|secret|token)\s*[:=]\s*[A-Za-z0-9_-]{16,}/i.test(rel)) {
|
|
130
|
+
findings.push({ level: 'dangerous', code: 'credential-filename' });
|
|
131
|
+
}
|
|
132
|
+
if (/^(?:LICENSE|LICENCE)(?:\.[^/]*)?$/i.test(rel)) {
|
|
133
|
+
if (/\b(?:MIT License|Apache License, Version 2\.0|BSD [23]-Clause|ISC License)\b/i.test(bytes.toString('utf8'))) license = 'redistributable';
|
|
134
|
+
else if (license !== 'redistributable') license = 'restricted';
|
|
135
|
+
}
|
|
136
|
+
if (bytes.includes(0)) {
|
|
137
|
+
findings.push({ level: 'dangerous', code: 'unscannable-file' });
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const text = bytes.toString('utf8');
|
|
141
|
+
if (/^plugin\.json$/.test(rel)) {
|
|
142
|
+
try {
|
|
143
|
+
const manifest: unknown = JSON.parse(text);
|
|
144
|
+
if (manifest && typeof manifest === 'object' && !Array.isArray(manifest)) {
|
|
145
|
+
const raw = manifest as Record<string, unknown>;
|
|
146
|
+
const ext = raw.extensions && typeof raw.extensions === 'object' ? (raw.extensions as Record<string, unknown>)['ai.elanous'] : undefined;
|
|
147
|
+
for (const main of [raw.main, ext && typeof ext === 'object' ? (ext as Record<string, unknown>).main : undefined]) {
|
|
148
|
+
if (typeof main === 'string' && main.trim()) entrypoints.push(resolve(dir, main));
|
|
149
|
+
}
|
|
150
|
+
if (typeof raw.license === 'string' && raw.license.trim()) {
|
|
151
|
+
license = /^(?:MIT|Apache-2\.0|BSD-2-Clause|BSD-3-Clause|ISC|0BSD|CC0-1\.0)$/.test(raw.license.trim())
|
|
152
|
+
? 'redistributable' : 'restricted';
|
|
153
|
+
}
|
|
154
|
+
const contributes = raw.contributes ?? (ext && typeof ext === 'object' ? (ext as Record<string, unknown>).contributes : undefined);
|
|
155
|
+
if (contributes && typeof contributes === 'object' && Array.isArray((contributes as Record<string, unknown>).hooks)
|
|
156
|
+
&& ((contributes as Record<string, unknown>).hooks as unknown[]).length) {
|
|
157
|
+
findings.push({ level: 'caution', code: 'hooks-disabled' });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} catch { findings.push({ level: 'dangerous', code: 'invalid-manifest' }); }
|
|
161
|
+
}
|
|
162
|
+
// Quotes may be JSON-escaped (a value nested inside a JSON string field), so allow a backslash before them.
|
|
163
|
+
const sensitive = /(?:-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|(?:\\?["'])?(?:api[_-]?key|secret|token)(?:\\?["'])?\s*[:=]\s*(\\?["'])?([A-Za-z0-9_\-]{16,})(\(?))/gi;
|
|
164
|
+
// Two narrow non-secrets: a documented placeholder (`tvly-YOUR_API_KEY`, `xxxxxxxx…`, `REPLACE_ME`) and an
|
|
165
|
+
// unquoted call result (`apiKey = getUpstageApiKey()`). Anything else that matches — quoted or not — still counts.
|
|
166
|
+
// Both exemptions look at the WHOLE value: a placeholder shape (optional vendor prefix), or a digit-free
|
|
167
|
+
// camelCase function name immediately called. A key with `xxxxxxxx` or `YOUR_` inside it still counts.
|
|
168
|
+
const placeholder = /^(?:[A-Za-z0-9]+[_-])*(?:YOUR[_-][A-Za-z_-]+|PLACEHOLDER[A-Za-z_-]*|REPLACE[_-]?ME[A-Za-z_-]*|x{8,})$/i;
|
|
169
|
+
const callee = /^[a-z_$][A-Za-z_$]*[a-z][A-Z][A-Za-z_$]*$/;
|
|
170
|
+
const hasSecret = [...text.matchAll(sensitive)].some(([, quote, value, call]) => value === undefined
|
|
171
|
+
|| !(placeholder.test(value) || (!quote && call === '(' && callee.test(value))));
|
|
172
|
+
if (/(?:^|\/)(?:knowledge|knowledge-packs?)(?:\/|$)/i.test(rel) && hasSecret) {
|
|
173
|
+
findings.push({ level: 'dangerous', code: 'knowledge-dlp' });
|
|
174
|
+
} else if (hasSecret && !/\.lock$/.test(rel)) {
|
|
175
|
+
findings.push({ level: 'dangerous', code: 'embedded-secret' });
|
|
176
|
+
}
|
|
177
|
+
if (/\.[cm]?[jt]sx?$/.test(rel)) code.set(resolve(file), { text, test: /(?:^|\/)[^/]+\.(?:test|spec)\.[cm]?[jt]sx?$/.test(rel) });
|
|
178
|
+
if (/(?:curl|wget)\b[^\n|]*\|\s*(?:sh|bash)\b|\b(?:rm\s+-rf|sudo)\b/i.test(text)) {
|
|
179
|
+
findings.push({ level: 'dangerous', code: 'unsafe-command' });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
visit(dir);
|
|
184
|
+
if (!entrypoints.length) entrypoints.push(resolve(dir, 'plugin.ts'));
|
|
185
|
+
// Shipped test fixtures are skipped only while nothing executable reaches them: the manifest `main`
|
|
186
|
+
// and every non-test code file are roots, and any test file they import (transitively) is scanned too.
|
|
187
|
+
const importsOf = (text: string): string[] =>
|
|
188
|
+
[...text.matchAll(/\b(?:import|export)\s*(?:[\s\S]*?\s+from\s*)?["']([^"']+)["']|\b(?:import|require)\s*\(\s*["']([^"']+)["']/g)]
|
|
189
|
+
.map(match => match[1] ?? match[2] ?? '').filter(Boolean);
|
|
190
|
+
const resolveLocal = (from: string, target: string): string | undefined => {
|
|
191
|
+
if (!target.startsWith('.')) return undefined;
|
|
192
|
+
const base = resolve(from, '..', target);
|
|
193
|
+
const swapped = base.replace(/\.([cm]?)js(x?)$/, '.$1ts$2');
|
|
194
|
+
return [base, swapped, `${base}.ts`, `${base}.tsx`, `${base}.js`, `${base}.mjs`, join(base, 'index.ts'), join(base, 'index.js')]
|
|
195
|
+
.find(candidate => code.has(candidate));
|
|
196
|
+
};
|
|
197
|
+
const reachable = new Set<string>();
|
|
198
|
+
const queue = [...entrypoints.filter(path => code.has(path)), ...[...code].filter(([, info]) => !info.test).map(([path]) => path)];
|
|
199
|
+
while (queue.length) {
|
|
200
|
+
const file = queue.pop()!;
|
|
201
|
+
if (reachable.has(file)) continue;
|
|
202
|
+
reachable.add(file);
|
|
203
|
+
for (const target of importsOf(code.get(file)!.text)) {
|
|
204
|
+
const next = resolveLocal(file, target);
|
|
205
|
+
if (next && !reachable.has(next)) queue.push(next);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
for (const file of reachable) {
|
|
209
|
+
const text = code.get(file)!.text;
|
|
210
|
+
if (/\b(?:eval\s*\(|new\s+Function\s*\(|child_process\b|Bun\.spawn\s*\()/i.test(text)) {
|
|
211
|
+
findings.push({ level: 'caution', code: 'executable-code' });
|
|
212
|
+
}
|
|
213
|
+
for (const target of importsOf(text)) {
|
|
214
|
+
// A relative or absolute import must stay inside the package; the package's own `./src/…` is fine,
|
|
215
|
+
// while `../…/src/`, `/abs/…/src/` or a `file:` URL that can leave the package root is unsafe.
|
|
216
|
+
if (/^file:/i.test(target)
|
|
217
|
+
|| ((target.startsWith('.') || target.startsWith('/')) && !resolve(file, '..', target).startsWith(`${resolve(dir)}${sep}`))) {
|
|
218
|
+
findings.push({ level: 'dangerous', code: 'unsafe-import' });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if ((license as PluginSecurityDecision['license']) !== 'redistributable') findings.push({ level: 'caution', code: 'private-only-license' });
|
|
223
|
+
return { scan: findings.some(f => f.level === 'dangerous') ? 'dangerous' : findings.length ? 'caution' : 'safe',
|
|
224
|
+
findings, integrity: hash.digest('hex'), license };
|
|
225
|
+
}
|
|
226
|
+
|
|
86
227
|
export function assertCapability(decision: CapabilityDecision): void {
|
|
87
228
|
if (!decision.ok) throw new Error(decision.reason);
|
|
88
229
|
}
|
package/src/plugins/core/host.ts
CHANGED
|
@@ -38,7 +38,7 @@ import { debug } from '../../debug/log.js';
|
|
|
38
38
|
import { getSessionCwd } from '../../session/working-dir.js';
|
|
39
39
|
import { CommandRegistry, type CommandDisposable, type RegisteredCommand } from '../../command-registry.js';
|
|
40
40
|
import { PluginCapabilityPolicy, assertCapability } from './capability-policy.js';
|
|
41
|
-
import { PluginTrustStore } from './trust-store.js';
|
|
41
|
+
import { PluginTrustStore, enabledPluginHooks } from './trust-store.js';
|
|
42
42
|
import { PluginTaskService } from './task-service.js';
|
|
43
43
|
import { readClipboardText, writeClipboard } from '../../clipboard/index.js';
|
|
44
44
|
import {
|
|
@@ -54,6 +54,7 @@ import { getGlobalElementRegistry, publishElementEvent } from '../../element-reg
|
|
|
54
54
|
import { mintPluginUri } from '../../mss/uri/builder.js';
|
|
55
55
|
import type { PluginUri } from '../../mss/uri/brand.js';
|
|
56
56
|
import { loadPluginNodes } from '../../graph-kinds/plugin-nodes.js';
|
|
57
|
+
import { registerOutboundAdapter } from '../../nexus/outbound/router.js';
|
|
57
58
|
import { getNodeKindRegistration, listNodeKinds, unregisterPluginNodeKind, type NodeKindEntry } from '../../graph-kinds/registry.js';
|
|
58
59
|
|
|
59
60
|
/** Clamp a tool handler's return value to something short enough for
|
|
@@ -113,8 +114,10 @@ export interface ActivePlugin {
|
|
|
113
114
|
ownedCommandDisposables: CommandDisposable[];
|
|
114
115
|
/** Task registrations for this activation. */
|
|
115
116
|
ownedTaskDisposables: Array<{ dispose(): void }>;
|
|
116
|
-
/**
|
|
117
|
-
|
|
117
|
+
/** Connector registrations are owner-scoped and removed on deactivate. */
|
|
118
|
+
ownedChannelDisposers: Array<() => void>;
|
|
119
|
+
/** Hook registrations from manifest.contributes.hooks[]; disposed on deactivate.
|
|
120
|
+
* PluginContext does not expose a programmatic hooks registration API. */
|
|
118
121
|
ownedHookDisposers: Array<() => void>;
|
|
119
122
|
/** PX-4: mission registrations (one per contributes.missions[] entry).
|
|
120
123
|
* Disposers tear down globalMissionRegistry entries on deactivate. */
|
|
@@ -369,13 +372,12 @@ export class PluginHost {
|
|
|
369
372
|
}
|
|
370
373
|
}
|
|
371
374
|
|
|
372
|
-
/**
|
|
373
|
-
*
|
|
374
|
-
* entry so deactivate() unregisters them. In-process hooks go
|
|
375
|
-
* through ctx.hooks.register inside onActivate (see buildContext). */
|
|
375
|
+
/** Register manifest-declared shell hooks for the plugin being activated.
|
|
376
|
+
* Installed plugins' hooks stay off (no approval path); disposers unregister them on deactivate. */
|
|
376
377
|
private registerManifestHooks(entry: PluginEntry): void {
|
|
377
378
|
if (!this.activeEntry) return;
|
|
378
|
-
const
|
|
379
|
+
const declared = entry.manifest.contributes.hooks ?? [];
|
|
380
|
+
const specs = enabledPluginHooks(declared, entry.source);
|
|
379
381
|
if (specs.length === 0) return;
|
|
380
382
|
// Lazy imports so headless tests that don't exercise hooks never
|
|
381
383
|
// pull in the dispatcher stack.
|
|
@@ -770,6 +772,7 @@ export class PluginHost {
|
|
|
770
772
|
ownedDisplayDisposables: [],
|
|
771
773
|
ownedCommandDisposables: [],
|
|
772
774
|
ownedTaskDisposables: [],
|
|
775
|
+
ownedChannelDisposers: [],
|
|
773
776
|
ownedHookDisposers: [],
|
|
774
777
|
ownedMissionDisposers: [],
|
|
775
778
|
ownedRouteDisposers: [],
|
|
@@ -822,6 +825,13 @@ export class PluginHost {
|
|
|
822
825
|
const ctx = this.buildContext();
|
|
823
826
|
try {
|
|
824
827
|
await plugin.onActivate?.(ctx);
|
|
828
|
+
for (const adapter of plugin.channelAdapters ?? []) {
|
|
829
|
+
if (!entry.manifest.contributes.connectors?.some(connector => connector.id === adapter.type)) {
|
|
830
|
+
throw new Error(`channel connector ${adapter.type} must be declared in contributes.connectors`);
|
|
831
|
+
}
|
|
832
|
+
// The manifest declaration alone is not an active channel.
|
|
833
|
+
this.activeEntry.ownedChannelDisposers.push(registerOutboundAdapter(adapter));
|
|
834
|
+
}
|
|
825
835
|
// Resolve layout after onActivate so the plugin can initialize
|
|
826
836
|
// state first (e.g. fetch remote rows). buildLayout can spawn
|
|
827
837
|
// widgets via the tracked helper — we record ids for dispose.
|
|
@@ -848,6 +858,7 @@ export class PluginHost {
|
|
|
848
858
|
for (const d of this.activeEntry.ownedDisplayDisposables) d.dispose();
|
|
849
859
|
for (const d of this.activeEntry.ownedCommandDisposables) d.dispose();
|
|
850
860
|
for (const d of this.activeEntry.ownedTaskDisposables) d.dispose();
|
|
861
|
+
for (const d of this.activeEntry.ownedChannelDisposers) d();
|
|
851
862
|
for (const d of this.activeEntry.ownedHookDisposers) d();
|
|
852
863
|
for (const d of this.activeEntry.ownedMissionDisposers) d();
|
|
853
864
|
for (const d of this.activeEntry.ownedRouteDisposers) d();
|
|
@@ -880,6 +891,7 @@ export class PluginHost {
|
|
|
880
891
|
for (const d of this.activeEntry.ownedDisplayDisposables) d.dispose();
|
|
881
892
|
for (const d of this.activeEntry.ownedCommandDisposables) d.dispose();
|
|
882
893
|
for (const d of this.activeEntry.ownedTaskDisposables) d.dispose();
|
|
894
|
+
for (const d of this.activeEntry.ownedChannelDisposers) d();
|
|
883
895
|
const promptStore = getPromptBankStore();
|
|
884
896
|
for (const id of this.activeEntry.promptFragmentIds) promptStore.delete(id);
|
|
885
897
|
// PX-3: dispose hook registrations for this plugin.
|
|
@@ -1746,6 +1758,7 @@ function normalizePluginExport(plugin: Partial<ElanousPlugin>, manifest: PluginM
|
|
|
1746
1758
|
...(plugin.slashCommands ? { slashCommands: plugin.slashCommands } : {}),
|
|
1747
1759
|
...(plugin.keybindings ? { keybindings: plugin.keybindings } : {}),
|
|
1748
1760
|
...(plugin.llmTools ? { llmTools: plugin.llmTools } : {}),
|
|
1761
|
+
...(plugin.channelAdapters ? { channelAdapters: plugin.channelAdapters } : {}),
|
|
1749
1762
|
...(plugin.onActivate ? { onActivate: plugin.onActivate } : {}),
|
|
1750
1763
|
...(plugin.onDeactivate ? { onDeactivate: plugin.onDeactivate } : {}),
|
|
1751
1764
|
...(plugin.isBusy ? { isBusy: plugin.isBusy } : {}),
|