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
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { debug } from '../debug/log.js';
|
|
2
|
+
import { parentPort, Worker } from 'node:worker_threads';
|
|
3
|
+
import { collectOverview, type CollectOptions } from './overview-collect.js';
|
|
4
|
+
import { computeVerdict, unmeasured, okCell, type OverviewSnapshot, type PodMemberRow } from './overview.js';
|
|
5
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
6
|
+
import { getElanousConfigDirOverride, setElanousConfigDir } from '../elanous-config-dir.js';
|
|
7
|
+
|
|
8
|
+
const SNAPSHOT_MS = 10_000;
|
|
9
|
+
const POD_MS = 60_000;
|
|
10
|
+
const POD_STALE_MS = 2 * POD_MS;
|
|
11
|
+
/** Bounds for distinct (version, owner, since) keys: memo entries kept and collections in flight. */
|
|
12
|
+
const MAX_MEMO = 32;
|
|
13
|
+
const MAX_PENDING = 2;
|
|
14
|
+
|
|
15
|
+
type PodReading = { context: string; occupied: number | null; reason: string | null; observedAt: number };
|
|
16
|
+
type OverviewData = OverviewSnapshot & ReturnType<typeof computeVerdict> & { cacheAgeMs: number; durationMs: number; sources: string[]; refreshFailed: string | null };
|
|
17
|
+
type WorkerMessage = ({ kind: 'pods' } | { kind: 'snapshot'; options: CollectOptions }) & { configDir?: string };
|
|
18
|
+
|
|
19
|
+
/** The kubectl-capable grid reader lives in a worker, never on the HTTP event loop. */
|
|
20
|
+
const port = parentPort;
|
|
21
|
+
if (port) {
|
|
22
|
+
port.on('message', async (message: WorkerMessage) => {
|
|
23
|
+
try {
|
|
24
|
+
// A worker does not share the main thread's module state: carry the daemon's universe in.
|
|
25
|
+
if (message.configDir) setElanousConfigDir(message.configDir);
|
|
26
|
+
if (message.kind === 'pods') {
|
|
27
|
+
const { buildGridData } = await import('../nexus/api/grid.js');
|
|
28
|
+
const rows = buildGridData().members.map((m) => ({ context: m.context, occupied: m.occupied, reason: m.reason, observedAt: Date.now() }));
|
|
29
|
+
port.postMessage({ rows });
|
|
30
|
+
} else port.postMessage({ snapshot: await collectOverview(message.options) });
|
|
31
|
+
} catch (error) {
|
|
32
|
+
port.postMessage({ error: error instanceof Error ? error.message : String(error) });
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function workerRead<T>(message: WorkerMessage, timeoutMs: number, field: 'rows' | 'snapshot'): Promise<T> {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const worker = new Worker(new URL('./overview-cache.ts', import.meta.url));
|
|
40
|
+
let settled = false;
|
|
41
|
+
const finish = (error?: Error, result?: T) => {
|
|
42
|
+
if (settled) return;
|
|
43
|
+
settled = true;
|
|
44
|
+
clearTimeout(timeout);
|
|
45
|
+
void worker.terminate();
|
|
46
|
+
if (error) reject(error);
|
|
47
|
+
else resolve(result!);
|
|
48
|
+
};
|
|
49
|
+
const timeout = setTimeout(() => finish(new Error(`${field} 측정 시간 초과`)), timeoutMs);
|
|
50
|
+
worker.on('message', (result: { rows?: PodReading[]; snapshot?: OverviewSnapshot; error?: string }) => {
|
|
51
|
+
if (result.error) finish(new Error(result.error));
|
|
52
|
+
else finish(undefined, result[field] as T);
|
|
53
|
+
});
|
|
54
|
+
worker.on('error', (error) => finish(error instanceof Error ? error : new Error(String(error))));
|
|
55
|
+
const configDir = getElanousConfigDirOverride();
|
|
56
|
+
worker.postMessage({ ...message, ...(configDir ? { configDir } : {}) });
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const measurePodsInWorker = () => workerRead<PodReading[]>({ kind: 'pods' }, 55_000, 'rows');
|
|
61
|
+
const collectInWorker = (options: CollectOptions) => workerRead<OverviewSnapshot>({ kind: 'snapshot', options: { ...options, root: options.root ?? effectiveInstanceRoot() } }, 30_000, 'snapshot');
|
|
62
|
+
|
|
63
|
+
function pendingSnapshot(at: number, since: string, reason: string): OverviewSnapshot {
|
|
64
|
+
const missing = <T>(name: string) => unmeasured<T>(name, reason);
|
|
65
|
+
return {
|
|
66
|
+
// Same resolution the collector uses; never the daemon's cwd.
|
|
67
|
+
generatedAt: new Date(at).toISOString(), instanceRoot: effectiveInstanceRoot(), since,
|
|
68
|
+
release: { version: missing('release.version'), run: missing('release.run'), schedule: missing('release.schedule'), checklist: missing('release.checklist') },
|
|
69
|
+
tasks: { byOwner: missing('tasks.byOwner'), done: missing('tasks.done'), launchable: missing('tasks.launchable'), capacity: missing('tasks.capacity') },
|
|
70
|
+
machines: { hosts: [], pods: [], parents: missing('machines.parents') },
|
|
71
|
+
landings: missing('landings'), loops: [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function createOverviewCache(deps: {
|
|
76
|
+
collect?: (opts: CollectOptions) => Promise<OverviewSnapshot>;
|
|
77
|
+
measurePods?: () => Promise<PodReading[]>;
|
|
78
|
+
now?: () => number;
|
|
79
|
+
schedule?: (tick: () => void, ms: number) => NodeJS.Timeout;
|
|
80
|
+
} = {}) {
|
|
81
|
+
const now = deps.now ?? Date.now;
|
|
82
|
+
const collect = deps.collect ?? collectInWorker;
|
|
83
|
+
const backgroundSnapshot = !deps.collect;
|
|
84
|
+
const measurePods = deps.measurePods ?? measurePodsInWorker;
|
|
85
|
+
const schedule = deps.schedule ?? ((tick: () => void, ms: number): NodeJS.Timeout => setInterval(tick, ms));
|
|
86
|
+
// The memo holds the collected snapshot only; Pod occupancy and the verdict are
|
|
87
|
+
// overlaid at response time so a failed or stale (120 s) measurement shows at once.
|
|
88
|
+
type Entry = { at: number; snapshot: OverviewSnapshot; durationMs: number; failure?: string; retryAt?: number };
|
|
89
|
+
const memo = new Map<string, Entry>();
|
|
90
|
+
const pending = new Map<string, Promise<void>>();
|
|
91
|
+
let podRows: PodReading[] = [];
|
|
92
|
+
let podFailure: string | null = null;
|
|
93
|
+
let podTimer: ReturnType<typeof setInterval> | null = null;
|
|
94
|
+
let podPending = false;
|
|
95
|
+
|
|
96
|
+
const refreshPods = async () => {
|
|
97
|
+
if (podPending) return;
|
|
98
|
+
podPending = true;
|
|
99
|
+
try { podRows = await measurePods(); podFailure = null; }
|
|
100
|
+
catch (error) { podRows = []; podFailure = error instanceof Error ? error.message : String(error); }
|
|
101
|
+
finally { podPending = false; }
|
|
102
|
+
};
|
|
103
|
+
const start = () => {
|
|
104
|
+
if (podTimer) return;
|
|
105
|
+
// The timer starts on the first authorized read; measurement never runs on the request stack.
|
|
106
|
+
podTimer = schedule(() => { void refreshPods(); }, POD_MS);
|
|
107
|
+
podTimer.unref();
|
|
108
|
+
};
|
|
109
|
+
const present = (entry: Entry): OverviewData => {
|
|
110
|
+
const at = now();
|
|
111
|
+
const byContext = new Map(podRows.map((row) => [row.context, row]));
|
|
112
|
+
const pods: PodMemberRow[] = entry.snapshot.machines.pods.map((pod) => {
|
|
113
|
+
const row = byContext.get(pod.context);
|
|
114
|
+
const stale = row && at - row.observedAt >= POD_STALE_MS;
|
|
115
|
+
const occupied = !podFailure && row && !stale && row.occupied !== null
|
|
116
|
+
? okCell(row.occupied, 'pod pool background measure', new Date(row.observedAt).toISOString())
|
|
117
|
+
: unmeasured<number>('pod pool background measure', podFailure ?? (stale ? '낡음(120초)' : row?.reason ?? '측정 대기'), row ? new Date(row.observedAt).toISOString() : null);
|
|
118
|
+
return { ...pod, occupied };
|
|
119
|
+
});
|
|
120
|
+
const full = { ...entry.snapshot, machines: { ...entry.snapshot.machines, pods } };
|
|
121
|
+
return { ...full, ...computeVerdict(full), durationMs: entry.durationMs,
|
|
122
|
+
sources: [full.release.run.source, full.tasks.launchable.source, full.tasks.capacity.source],
|
|
123
|
+
cacheAgeMs: Math.max(0, at - entry.at), refreshFailed: entry.failure ?? null };
|
|
124
|
+
};
|
|
125
|
+
const get = async (options: Pick<CollectOptions, 'version' | 'owner'> & { sinceMs?: number; sinceLabel?: string } = {}): Promise<OverviewData> => {
|
|
126
|
+
start();
|
|
127
|
+
const key = JSON.stringify([options.version ?? null, options.owner ?? null, options.sinceMs ?? 3_600_000]);
|
|
128
|
+
const at = now();
|
|
129
|
+
// Drop expired entries of other keys, then cap the memo (oldest first).
|
|
130
|
+
for (const [other, entry] of memo) if (other !== key && !pending.has(other) && at - entry.at >= SNAPSHOT_MS && (entry.retryAt ?? 0) <= at) memo.delete(other);
|
|
131
|
+
const cached = memo.get(key);
|
|
132
|
+
// A failed refresh keeps the original collection time (true age) and only delays the retry.
|
|
133
|
+
if (cached && (at - cached.at < SNAPSHOT_MS || backgroundSnapshot && pending.has(key) || (cached.retryAt ?? 0) > at)) return present(cached);
|
|
134
|
+
let current = pending.get(key);
|
|
135
|
+
if (!current && pending.size >= MAX_PENDING) {
|
|
136
|
+
// Collections in flight are capped; answer from what we have instead of starting another worker.
|
|
137
|
+
const entry = cached ?? { at, snapshot: pendingSnapshot(at, options.sinceLabel ?? '최근 1h', '동시 수집 상한'), durationMs: 0 };
|
|
138
|
+
return present({ ...entry, failure: entry.failure ?? `동시 수집 상한(${MAX_PENDING})` });
|
|
139
|
+
}
|
|
140
|
+
if (!current) {
|
|
141
|
+
// Evict only when a new key is about to be stored, never on a hit for an existing key.
|
|
142
|
+
if (!memo.has(key)) while (memo.size >= MAX_MEMO) { const oldest = [...memo.keys()].find((other) => !pending.has(other)); if (!oldest) break; memo.delete(oldest); }
|
|
143
|
+
if (backgroundSnapshot && !cached) {
|
|
144
|
+
// Placeholder until the worker answers; it is not a collection.
|
|
145
|
+
memo.set(key, { at, snapshot: pendingSnapshot(at, options.sinceLabel ?? '최근 1h', '백그라운드 스냅숏 수집 대기'), durationMs: 0 });
|
|
146
|
+
}
|
|
147
|
+
current = (async () => {
|
|
148
|
+
const startAt = now();
|
|
149
|
+
const snapshot = await collect({ sinceMs: options.sinceMs ?? 3_600_000, sinceLabel: options.sinceLabel ?? '최근 1h',
|
|
150
|
+
...(options.version ? { version: options.version } : {}), ...(options.owner ? { owner: options.owner } : {}), now: startAt });
|
|
151
|
+
// Age counts from when collection started (= snapshot.generatedAt), not when it finished.
|
|
152
|
+
const entry = { at: startAt, snapshot, durationMs: now() - startAt };
|
|
153
|
+
memo.set(key, entry);
|
|
154
|
+
const verdict = present(entry);
|
|
155
|
+
debug.log('ops.overview', 'verdict', { verdict: verdict.verdict, reasons: verdict.reasons, cacheAgeMs: verdict.cacheAgeMs, durationMs: entry.durationMs });
|
|
156
|
+
})();
|
|
157
|
+
pending.set(key, current);
|
|
158
|
+
void current.then(
|
|
159
|
+
() => { pending.delete(key); },
|
|
160
|
+
(error) => {
|
|
161
|
+
pending.delete(key);
|
|
162
|
+
debug.log('ops.overview', 'refresh-failed', { reason: error instanceof Error ? error.message : String(error) });
|
|
163
|
+
const prior = memo.get(key);
|
|
164
|
+
if (prior) memo.set(key, { ...prior, failure: error instanceof Error ? error.message : String(error), retryAt: now() + SNAPSHOT_MS });
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
if (!backgroundSnapshot) {
|
|
169
|
+
try { await current; }
|
|
170
|
+
catch (error) { if (!memo.has(key)) throw error; }
|
|
171
|
+
}
|
|
172
|
+
return present(memo.get(key)!);
|
|
173
|
+
};
|
|
174
|
+
return { get, memoSize: () => memo.size, stop: () => { if (podTimer) clearInterval(podTimer); podTimer = null; memo.clear(); } };
|
|
175
|
+
}
|
package/src/ops/overview.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* ⛔ «못 잼»은 `value:null` ⊕ `reason` 이다 — 절대 0 으로 읽지 않는다(판정도 그렇다).
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { formatLandingThroughput, type LandingThroughput } from '../task-agent/cover.js';
|
|
10
|
+
|
|
9
11
|
export type CellStatus = 'ok' | 'unmeasured' | 'partial';
|
|
10
12
|
export interface Cell<T> {
|
|
11
13
|
value: T | null;
|
|
@@ -84,6 +86,8 @@ export interface OverviewSnapshot {
|
|
|
84
86
|
parents: Cell<ParentsInfo>;
|
|
85
87
|
};
|
|
86
88
|
landings: Cell<{ count: number; recent: string[] }>;
|
|
89
|
+
/** Optional until launch/PR/age sources are wired; existing snapshots keep their exact output. */
|
|
90
|
+
throughput?: Cell<LandingThroughput>;
|
|
87
91
|
loops: LoopRow[];
|
|
88
92
|
}
|
|
89
93
|
|
|
@@ -176,6 +180,7 @@ export function unmeasuredCells(s: OverviewSnapshot): string[] {
|
|
|
176
180
|
for (const h of s.machines.hosts) visit(`machines.${h.name}`, h.load);
|
|
177
181
|
for (const p of s.machines.pods) visit(`pods.${p.context}`, p.occupied);
|
|
178
182
|
visit('machines.parents', s.machines.parents); visit('landings', s.landings);
|
|
183
|
+
if (s.throughput) visit('throughput', s.throughput);
|
|
179
184
|
for (const l of s.loops) visit(`loops.${l.name}`, l.beat);
|
|
180
185
|
return out;
|
|
181
186
|
}
|
|
@@ -215,6 +220,9 @@ export function renderOverview(s: OverviewSnapshot, v: VerdictResult, meta: { el
|
|
|
215
220
|
lines.push(` Pod ${s.machines.pods.map((p) => `${p.context} ${show(p.occupied, String)}/${p.capacity}`).join(' · ') || '못 잼(풀 설정 없음)'}`);
|
|
216
221
|
lines.push(` 하니스 부모(이 기계) ${show(s.machines.parents, (p) => `${p.count} · 6h 넘음 ${p.staleOver6h}${p.oldestHours !== null ? ` · 최고 ${p.oldestHours}h` : ''}`)}`);
|
|
217
222
|
lines.push(`착지 ${s.since} ${show(s.landings, (l) => `${l.count}`)} [${s.landings.source}]`);
|
|
223
|
+
if (s.throughput) {
|
|
224
|
+
lines.push(`${show(s.throughput, formatLandingThroughput)} [${s.throughput.source}]`);
|
|
225
|
+
}
|
|
218
226
|
for (const l of s.loops) {
|
|
219
227
|
lines.push(`루프 ${l.name}${l.era === 'seat-era' ? ' [자리 시대 원천]' : ''} ${show(l.beat, (b) => `${kst(b.lastAt)} (${Math.round(b.ageSeconds / 60)}분 전)${b.alive === null ? '' : b.alive ? ' 살아 있음' : ' 프로세스 없음'}${l.staleAfterSeconds === null ? ' · 주기 미상(판정 제외)' : ''}`)}`);
|
|
220
228
|
}
|
|
@@ -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 } : {}),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import type { Keybinding, SlashCommand } from './types.js';
|
|
3
|
+
import type { Keybinding, PluginDependency, SlashCommand } from './types.js';
|
|
4
4
|
import type { PromptKind, PromptScope, PromptTargetSlot } from '../../prompt-bank/types.js';
|
|
5
5
|
import type {
|
|
6
6
|
MissionDefinition,
|
|
@@ -223,6 +223,8 @@ export interface PluginManifest {
|
|
|
223
223
|
activationEvents: string[];
|
|
224
224
|
contributes: PluginManifestContributes;
|
|
225
225
|
capabilities: PluginCapability[];
|
|
226
|
+
/** `plugin.json` requirement metadata; does not trigger installation. */
|
|
227
|
+
requires?: PluginDependency;
|
|
226
228
|
dependencies?: {
|
|
227
229
|
widgets?: string[];
|
|
228
230
|
plugins?: string[];
|
|
@@ -328,6 +330,7 @@ export function parsePluginManifest(
|
|
|
328
330
|
? raw.capabilities
|
|
329
331
|
: [...parseCapabilities(raw.capabilities), ...parseCapabilities(extension.capabilities)]);
|
|
330
332
|
const dependencies = parseDependencies(raw.dependencies);
|
|
333
|
+
const requires = parsePluginRequires(raw.requires === undefined ? extension.requires : raw.requires);
|
|
331
334
|
const description = typeof raw.description === 'string' ? raw.description : undefined;
|
|
332
335
|
const allowMultiActive = typeof raw.allowMultiActive === 'boolean' ? raw.allowMultiActive : undefined;
|
|
333
336
|
const activePeerCompat = parseActivePeerCompat(raw.activePeerCompat);
|
|
@@ -341,6 +344,7 @@ export function parsePluginManifest(
|
|
|
341
344
|
activationEvents,
|
|
342
345
|
contributes,
|
|
343
346
|
capabilities,
|
|
347
|
+
...(requires ? { requires } : {}),
|
|
344
348
|
...(dependencies ? { dependencies } : {}),
|
|
345
349
|
...(allowMultiActive !== undefined ? { allowMultiActive } : {}),
|
|
346
350
|
...(activePeerCompat ? { activePeerCompat } : {}),
|
|
@@ -354,7 +358,7 @@ function objectOrEmpty(value: unknown, label: string): Record<string, unknown> {
|
|
|
354
358
|
return value as Record<string, unknown>;
|
|
355
359
|
}
|
|
356
360
|
|
|
357
|
-
function parseElanousExtension(value: unknown): { contributes: Record<string, unknown>; capabilities?: unknown } {
|
|
361
|
+
function parseElanousExtension(value: unknown): { contributes: Record<string, unknown>; capabilities?: unknown; requires?: unknown } {
|
|
358
362
|
const extensions = objectOrEmpty(value, 'extensions');
|
|
359
363
|
const extension = objectOrEmpty(extensions['ai.elanous'], 'extensions["ai.elanous"]');
|
|
360
364
|
const contributes = objectOrEmpty(extension.contributes, 'extensions["ai.elanous"].contributes');
|
|
@@ -365,6 +369,7 @@ function parseElanousExtension(value: unknown): { contributes: Record<string, un
|
|
|
365
369
|
.map(key => [key, extension[key]])),
|
|
366
370
|
},
|
|
367
371
|
capabilities: extension.capabilities,
|
|
372
|
+
requires: extension.requires,
|
|
368
373
|
};
|
|
369
374
|
}
|
|
370
375
|
|
|
@@ -1117,6 +1122,18 @@ function parseCapabilities(value: unknown): PluginCapability[] {
|
|
|
1117
1122
|
});
|
|
1118
1123
|
}
|
|
1119
1124
|
|
|
1125
|
+
function parsePluginRequires(value: unknown): PluginDependency | undefined {
|
|
1126
|
+
if (value === undefined) return undefined;
|
|
1127
|
+
const raw = objectOrEmpty(value, 'requires');
|
|
1128
|
+
return {
|
|
1129
|
+
...(raw.elanous !== undefined ? { elanous: stringOr(raw.elanous) } : {}),
|
|
1130
|
+
...(raw.tools !== undefined ? { tools: stringArrayOr(raw.tools, []) } : {}),
|
|
1131
|
+
...(raw.optionalTools !== undefined ? { optionalTools: stringArrayOr(raw.optionalTools, []) } : {}),
|
|
1132
|
+
...(raw.optionalPython !== undefined ? { optionalPython: stringArrayOr(raw.optionalPython, []) } : {}),
|
|
1133
|
+
...(raw.knowledgePacks !== undefined ? { knowledgePacks: stringArrayOr(raw.knowledgePacks, []) } : {}),
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1120
1137
|
function parseDependencies(value: unknown): PluginManifest['dependencies'] | undefined {
|
|
1121
1138
|
if (value === undefined) return undefined;
|
|
1122
1139
|
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('dependencies must be an object');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { DATA_DIR } from '../../config.js';
|
|
4
|
+
import type { PluginSecurityDecision } from './capability-policy.js';
|
|
4
5
|
|
|
5
6
|
export type PluginTrustScope = 'user' | 'workspace';
|
|
6
7
|
|
|
@@ -16,6 +17,20 @@ interface PluginTrustFile {
|
|
|
16
17
|
records: PluginTrustRecord[];
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
/** Ephemeral installation decision; never persisted as a trust record or a credential. */
|
|
21
|
+
export function decidePluginInstallation(security: PluginSecurityDecision, capabilities: readonly string[], consent: boolean):
|
|
22
|
+
{ ok: true } | { ok: false; reason: 'scan' | 'consent-denied' } {
|
|
23
|
+
if (security.scan === 'dangerous') return { ok: false, reason: 'scan' };
|
|
24
|
+
if (capabilities.length > 0 && !consent) return { ok: false, reason: 'consent-denied' };
|
|
25
|
+
return { ok: true };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Hooks default off for installed (imported/generated) plugins: there is no approval path yet, so none run.
|
|
29
|
+
* Built-in and user-dir plugins keep their declared hooks unchanged. */
|
|
30
|
+
export function enabledPluginHooks<T>(hooks: readonly T[], source: string): T[] {
|
|
31
|
+
return source === 'installed' ? [] : [...hooks];
|
|
32
|
+
}
|
|
33
|
+
|
|
19
34
|
export class PluginTrustStore {
|
|
20
35
|
constructor(private readonly path = defaultPluginTrustPath()) {}
|
|
21
36
|
|
|
@@ -26,6 +26,15 @@ import type {
|
|
|
26
26
|
|
|
27
27
|
export type PaneSlot = 'skills' | 'files' | 'preview' | 'log' | 'hud';
|
|
28
28
|
|
|
29
|
+
/** Requirements declared by a plugin.json `requires` block. This is metadata, not an install request. */
|
|
30
|
+
export interface PluginDependency {
|
|
31
|
+
elanous?: string;
|
|
32
|
+
tools?: string[];
|
|
33
|
+
optionalTools?: string[];
|
|
34
|
+
optionalPython?: string[];
|
|
35
|
+
knowledgePacks?: string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
export interface DashboardPaneSummary {
|
|
30
39
|
pane: string;
|
|
31
40
|
visible: boolean;
|
|
@@ -327,6 +336,9 @@ export interface ElanousPlugin<S = unknown> {
|
|
|
327
336
|
slashCommands?: SlashCommand[];
|
|
328
337
|
keybindings?: Keybinding[];
|
|
329
338
|
llmTools?: LLMToolDef[];
|
|
339
|
+
/** Host registers only adapters also declared in contributes.connectors;
|
|
340
|
+
* registration is disposed with this plugin activation. */
|
|
341
|
+
channelAdapters?: import('../../nexus/outbound/router.js').ChannelAdapter[];
|
|
330
342
|
onActivate?(ctx: PluginContext): void | Promise<void>;
|
|
331
343
|
onDeactivate?(ctx: PluginContext): void | Promise<void>;
|
|
332
344
|
/** Plugin is executing a long-running op — host blocks input while true.
|