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
|
@@ -13,7 +13,14 @@ export const ELANOUS_MARKET_URL = 'https://elanvitalai.github.io/elanous-plugins
|
|
|
13
13
|
const NAME = /^[a-z0-9][a-z0-9-]{1,39}$/;
|
|
14
14
|
const MAX_INDEX_BYTES = 8 * 1024 * 1024;
|
|
15
15
|
|
|
16
|
-
export interface MarketConfig {
|
|
16
|
+
export interface MarketConfig {
|
|
17
|
+
name: string;
|
|
18
|
+
url: string;
|
|
19
|
+
/** Explicit tenant allowlist for a private market; absent for existing plugin markets. */
|
|
20
|
+
enterpriseIds?: string[];
|
|
21
|
+
/** Keys bound to this private market, never inherited from the global plugin trust pool. */
|
|
22
|
+
trustedKeys?: Array<{ keyId: string; publicKey: string }>;
|
|
23
|
+
}
|
|
17
24
|
export interface MarketFetchOptions {
|
|
18
25
|
root?: string;
|
|
19
26
|
marketDir?: string;
|
|
@@ -75,6 +82,24 @@ function configuredMarkets(settings: Record<string, unknown>): MarketConfig[] {
|
|
|
75
82
|
return { name, url: marketUrl(url) };
|
|
76
83
|
});
|
|
77
84
|
}
|
|
85
|
+
function internalMarkets(settings: Record<string, unknown>): MarketConfig[] {
|
|
86
|
+
const entries = settings.internalMarkets;
|
|
87
|
+
if (entries === undefined) return [];
|
|
88
|
+
if (!Array.isArray(entries)) throw new MarketFetchError('io', 'invalid internal markets configuration');
|
|
89
|
+
const names = new Set<string>();
|
|
90
|
+
return entries.map((entry: unknown) => {
|
|
91
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) throw new MarketFetchError('io', 'invalid internal market configuration');
|
|
92
|
+
const { name, url, enterpriseIds, trustedKeys } = entry as Record<string, unknown>;
|
|
93
|
+
if (typeof name !== 'string' || !NAME.test(name) || names.has(name) || name === 'elanous') throw new MarketFetchError('io', `invalid or duplicate internal market name: ${String(name)}`);
|
|
94
|
+
if (!Array.isArray(enterpriseIds) || !enterpriseIds.length || !enterpriseIds.every(id => typeof id === 'string' && id.trim() && id === id.trim())
|
|
95
|
+
|| new Set(enterpriseIds).size !== enterpriseIds.length) throw new MarketFetchError('io', `invalid internal market enterprise allowlist: ${name}`);
|
|
96
|
+
if (!Array.isArray(trustedKeys) || !trustedKeys.length || !trustedKeys.every(key => key && typeof key === 'object' && typeof key.keyId === 'string' && /^[a-fA-F0-9]{8}$/.test(key.keyId) && typeof key.publicKey === 'string' && key.publicKey.length > 0)
|
|
97
|
+
|| new Set(trustedKeys.map(key => key.keyId)).size !== trustedKeys.length) throw new MarketFetchError('io', `invalid internal market trusted keys: ${name}`);
|
|
98
|
+
names.add(name);
|
|
99
|
+
return { name, url: marketUrl(url), enterpriseIds: enterpriseIds as string[], trustedKeys: trustedKeys as Array<{ keyId: string; publicKey: string }> };
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
78
103
|
function trust(settings: Record<string, unknown>, opts: MarketFetchOptions): ReadonlyArray<{ keyId: string; publicKey: string }> {
|
|
79
104
|
const additional = settings.trustedKeys;
|
|
80
105
|
if (additional !== undefined && (!Array.isArray(additional) || !additional.every(key => key && typeof key.keyId === 'string' && typeof key.publicKey === 'string'))) {
|
|
@@ -115,7 +140,7 @@ function location(name: string, opts: MarketFetchOptions): string {
|
|
|
115
140
|
return join(resolve(opts.marketDir ?? join(opts.root ?? elanousStateRoot(), 'markets')), name);
|
|
116
141
|
}
|
|
117
142
|
|
|
118
|
-
interface CacheState { url: string; lastSequence: number; indexHash: string; signatureHash: string }
|
|
143
|
+
interface CacheState { url: string; lastSequence: number; indexHash: string; signatureHash: string; trustHash?: string }
|
|
119
144
|
|
|
120
145
|
function cacheState(path: string): CacheState | undefined {
|
|
121
146
|
if (!existsSync(path)) return undefined;
|
|
@@ -123,13 +148,14 @@ function cacheState(path: string): CacheState | undefined {
|
|
|
123
148
|
try { value = JSON.parse(readFileSync(path, 'utf8')); }
|
|
124
149
|
catch { throw new MarketFetchError('io', 'invalid market cache state'); }
|
|
125
150
|
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new MarketFetchError('io', 'invalid market cache state');
|
|
126
|
-
const { url, lastSequence, indexHash, signatureHash } = value as Record<string, unknown>;
|
|
151
|
+
const { url, lastSequence, indexHash, signatureHash, trustHash } = value as Record<string, unknown>;
|
|
127
152
|
if (typeof url !== 'string' || !Number.isSafeInteger(lastSequence) || (lastSequence as number) < 0
|
|
128
153
|
|| typeof indexHash !== 'string' || !/^[a-f0-9]{64}$/.test(indexHash)
|
|
129
|
-
|| typeof signatureHash !== 'string' || !/^[a-f0-9]{64}$/.test(signatureHash)
|
|
154
|
+
|| typeof signatureHash !== 'string' || !/^[a-f0-9]{64}$/.test(signatureHash)
|
|
155
|
+
|| (trustHash !== undefined && (typeof trustHash !== 'string' || !/^[a-f0-9]{64}$/.test(trustHash)))) {
|
|
130
156
|
throw new MarketFetchError('io', 'invalid market cache state');
|
|
131
157
|
}
|
|
132
|
-
return { url, lastSequence: lastSequence as number, indexHash, signatureHash };
|
|
158
|
+
return { url, lastSequence: lastSequence as number, indexHash, signatureHash, ...(trustHash === undefined ? {} : { trustHash }) };
|
|
133
159
|
}
|
|
134
160
|
|
|
135
161
|
function digest(bytes: Uint8Array | string): string {
|
|
@@ -147,9 +173,21 @@ function checked(bytes: Uint8Array, signatureText: string, name: string, keys: R
|
|
|
147
173
|
const marketIndexQueues = new Map<string, Promise<void>>();
|
|
148
174
|
|
|
149
175
|
export function ensureMarketIndex(name: string, opts: MarketFetchOptions = {}): Promise<MarketIndex> {
|
|
150
|
-
|
|
176
|
+
return queuedMarketIndex(name, opts);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Private indices require a configured market, a bound signing key and an explicitly allowed enterprise. */
|
|
180
|
+
export function ensureInternalMarketIndex(name: string, enterpriseId: string, opts: MarketFetchOptions = {}): Promise<MarketIndex> {
|
|
181
|
+
if (typeof enterpriseId !== 'string' || !enterpriseId.trim() || enterpriseId !== enterpriseId.trim()) {
|
|
182
|
+
return Promise.reject(new MarketFetchError('io', `enterprise not allowed for internal market: ${name}`));
|
|
183
|
+
}
|
|
184
|
+
return queuedMarketIndex(name, opts, enterpriseId);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function queuedMarketIndex(name: string, opts: MarketFetchOptions, enterpriseId?: string): Promise<MarketIndex> {
|
|
188
|
+
const directory = enterpriseId === undefined ? location(name, opts) : join(resolve(opts.marketDir ?? join(opts.root ?? elanousStateRoot(), 'markets')), '.internal', name, digest(enterpriseId));
|
|
151
189
|
const previous = marketIndexQueues.get(directory) ?? Promise.resolve();
|
|
152
|
-
const result = previous.then(() => fetchMarketIndex(name, opts));
|
|
190
|
+
const result = previous.then(() => fetchMarketIndex(name, opts, enterpriseId, directory));
|
|
153
191
|
const tail = result.then(() => {}, () => {});
|
|
154
192
|
marketIndexQueues.set(directory, tail);
|
|
155
193
|
void tail.then(() => {
|
|
@@ -158,11 +196,25 @@ export function ensureMarketIndex(name: string, opts: MarketFetchOptions = {}):
|
|
|
158
196
|
return result;
|
|
159
197
|
}
|
|
160
198
|
|
|
161
|
-
async function fetchMarketIndex(name: string, opts: MarketFetchOptions): Promise<MarketIndex> {
|
|
162
|
-
const
|
|
199
|
+
async function fetchMarketIndex(name: string, opts: MarketFetchOptions, enterpriseId: string | undefined, directory: string): Promise<MarketIndex> {
|
|
200
|
+
const settings = marketSettings(config(opts));
|
|
201
|
+
const market: MarketConfig | undefined = enterpriseId === undefined
|
|
202
|
+
? [{ name: 'elanous', url: ELANOUS_MARKET_URL }, ...configuredMarkets(settings)].find(entry => entry.name === name)
|
|
203
|
+
: internalMarkets(settings).find(entry => entry.name === name);
|
|
163
204
|
if (!market) throw new MarketFetchError('io', `market not configured: ${name}`);
|
|
164
|
-
|
|
165
|
-
|
|
205
|
+
if (enterpriseId !== undefined && !market.enterpriseIds?.includes(enterpriseId)) {
|
|
206
|
+
throw new MarketFetchError('io', `enterprise not allowed for internal market: ${name}`);
|
|
207
|
+
}
|
|
208
|
+
const keys = enterpriseId === undefined ? trust(settings, opts) : market.trustedKeys!;
|
|
209
|
+
const verificationOptions = enterpriseId === undefined ? opts : { ...opts, verifySignature: verifyIndex };
|
|
210
|
+
const trustHash = enterpriseId === undefined ? undefined : digest(JSON.stringify(keys));
|
|
211
|
+
const authorized = (verified: ReturnType<typeof checked>): ReturnType<typeof checked> => {
|
|
212
|
+
if (enterpriseId !== undefined && [...(verified.index.knowledgePacks ?? []), ...(verified.index.loopBundles ?? [])]
|
|
213
|
+
.some(entry => entry.visibility !== 'internal' || entry.enterpriseId !== enterpriseId)) {
|
|
214
|
+
throw new MarketFetchError('io', `internal market contains entries outside enterprise allowlist: ${name}`);
|
|
215
|
+
}
|
|
216
|
+
return verified;
|
|
217
|
+
};
|
|
166
218
|
const indexFile = join(directory, 'marketplace.json');
|
|
167
219
|
const sigFile = join(directory, 'index.sig');
|
|
168
220
|
const stateFile = join(directory, 'cache-state.json');
|
|
@@ -170,12 +222,12 @@ async function fetchMarketIndex(name: string, opts: MarketFetchOptions): Promise
|
|
|
170
222
|
// The URL is part of the cache identity, not just the market name.
|
|
171
223
|
const lastSequence = state?.url === market.url ? state.lastSequence : undefined;
|
|
172
224
|
let cached: ReturnType<typeof checked> | undefined;
|
|
173
|
-
if (state?.url === market.url && existsSync(indexFile) && existsSync(sigFile)) {
|
|
225
|
+
if (state?.url === market.url && (trustHash === undefined || state.trustHash === trustHash) && existsSync(indexFile) && existsSync(sigFile)) {
|
|
174
226
|
const indexBytes = readFileSync(indexFile);
|
|
175
227
|
const signatureText = readFileSync(sigFile, 'utf8');
|
|
176
228
|
if (digest(indexBytes) === state.indexHash && digest(signatureText) === state.signatureHash) {
|
|
177
229
|
try {
|
|
178
|
-
cached = checked(indexBytes, signatureText, name, keys,
|
|
230
|
+
cached = authorized(checked(indexBytes, signatureText, name, keys, verificationOptions, lastSequence));
|
|
179
231
|
} catch (error) {
|
|
180
232
|
if (!(error instanceof MarketFetchError)) throw error;
|
|
181
233
|
}
|
|
@@ -216,13 +268,13 @@ async function fetchMarketIndex(name: string, opts: MarketFetchOptions): Promise
|
|
|
216
268
|
};
|
|
217
269
|
const bytes = await load('marketplace.json');
|
|
218
270
|
const signature = new TextDecoder('utf-8', { fatal: true }).decode(await load('index.sig'));
|
|
219
|
-
const verified = checked(bytes, signature, name, keys,
|
|
271
|
+
const verified = authorized(checked(bytes, signature, name, keys, verificationOptions, lastSequence));
|
|
220
272
|
mkdirSync(directory, { recursive: true });
|
|
221
273
|
// Cross-process: another CLI may have published a newer index since we read cache-state. Re-check the high-water
|
|
222
274
|
// mark under a file lock right before publishing, so a slower process cannot roll the cache back (review R3).
|
|
223
275
|
return withFileLockSync(join(directory, '.publish.lock'), () => {
|
|
224
276
|
const current = cacheState(stateFile);
|
|
225
|
-
if (current?.url === market.url && current.lastSequence
|
|
277
|
+
if (current?.url === market.url && current.lastSequence > verified.index.sequence) {
|
|
226
278
|
throw new MarketFetchError('signature', `market index rollback refused: ${name} sequence ${verified.index.sequence} < ${current.lastSequence}`);
|
|
227
279
|
}
|
|
228
280
|
const staging = mkdtempSync(join(directory, '.index-'));
|
|
@@ -232,7 +284,7 @@ async function fetchMarketIndex(name: string, opts: MarketFetchOptions): Promise
|
|
|
232
284
|
const tempState = join(staging, 'cache-state.json');
|
|
233
285
|
writeFileSync(tempIndex, bytes);
|
|
234
286
|
writeFileSync(tempSig, signature);
|
|
235
|
-
writeFileSync(tempState, JSON.stringify({ url: market.url, lastSequence: verified.index.sequence, indexHash: digest(bytes), signatureHash: digest(signature) } satisfies CacheState));
|
|
287
|
+
writeFileSync(tempState, JSON.stringify({ url: market.url, lastSequence: verified.index.sequence, indexHash: digest(bytes), signatureHash: digest(signature), ...(trustHash === undefined ? {} : { trustHash }) } satisfies CacheState));
|
|
236
288
|
// Commit the verified high-water mark before replacing either cache file.
|
|
237
289
|
// An interrupted publication then cannot roll back a previously verified index.
|
|
238
290
|
renameSync(tempState, stateFile);
|
|
@@ -2,14 +2,16 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { closeSync, cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
|
-
import { basename, dirname, isAbsolute, join, resolve, sep } from 'node:path';
|
|
5
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
6
6
|
import { dlopen, FFIType } from 'bun:ffi';
|
|
7
7
|
import { loadPluginManifestFromDir, type PluginManifest } from '../core/manifest.js';
|
|
8
|
+
import { inspectPluginSecurity } from '../core/capability-policy.js';
|
|
9
|
+
import { decidePluginInstallation } from '../core/trust-store.js';
|
|
8
10
|
import { loadPluginNodes } from '../../graph-kinds/plugin-nodes.js';
|
|
9
11
|
import { getNodeKindRegistration, listNodeKinds, unregisterPluginNodeKind } from '../../graph-kinds/registry.js';
|
|
10
12
|
import { verifyIndex, type MarketplaceIndex, type VerifyIndexResult } from '../../market/signed-index.js';
|
|
11
13
|
import { elanousStateRoot } from '../../autopilot/state-paths.js';
|
|
12
|
-
import { ensureMarketIndex, MarketFetchError, type MarketFetchOptions } from './market-fetch.js';
|
|
14
|
+
import { ensureInternalMarketIndex, ensureMarketIndex, MarketFetchError, type MarketFetchOptions } from './market-fetch.js';
|
|
13
15
|
|
|
14
16
|
const NAME = /^[a-z0-9][a-z0-9-]{1,39}$/;
|
|
15
17
|
const VERSION = /^[0-9]+\.[0-9]+\.[0-9]+(?:[-+][a-zA-Z0-9.-]+)?$/;
|
|
@@ -48,6 +50,8 @@ export interface InstallOptions {
|
|
|
48
50
|
consent?: (capabilities: string[]) => boolean | Promise<boolean>;
|
|
49
51
|
fetcher?: MarketFetchOptions['fetcher'];
|
|
50
52
|
configPath?: string;
|
|
53
|
+
/** Enterprise context for knowledge packs in a private market. */
|
|
54
|
+
enterpriseId?: string;
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
export class PluginInstallError extends Error {
|
|
@@ -83,6 +87,53 @@ function safeTree(root: string): void {
|
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
|
|
90
|
+
function packPathExists(path: string): boolean {
|
|
91
|
+
try { lstatSync(path); return true; }
|
|
92
|
+
catch (error) {
|
|
93
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Never follow a linked installation root or parent while reusing, moving or rolling back a package. */
|
|
99
|
+
function assertInstallParents(root: string, destination: string): void {
|
|
100
|
+
const parts = relative(root, dirname(destination)).split(sep).filter(Boolean);
|
|
101
|
+
if (parts.some(part => part === '..') || isAbsolute(relative(root, destination))) fail('io', `unsafe installation path: ${destination}`);
|
|
102
|
+
// macOS exposes system aliases such as /var -> /private/var; inspect the
|
|
103
|
+
// canonical path after that alias, without exempting any caller-owned parent.
|
|
104
|
+
const systemAlias = process.platform === 'darwin' && ['/var', '/tmp'].find(path => root === path || root.startsWith(`${path}${sep}`));
|
|
105
|
+
const checkedRoot = systemAlias ? resolve(realpathSync(systemAlias), relative(systemAlias, root)) : root;
|
|
106
|
+
const parents = [checkedRoot];
|
|
107
|
+
while (dirname(parents[0]!) !== parents[0]) parents.unshift(dirname(parents[0]!));
|
|
108
|
+
let parent = checkedRoot;
|
|
109
|
+
for (const part of parts) {
|
|
110
|
+
parent = join(parent, part);
|
|
111
|
+
parents.push(parent);
|
|
112
|
+
}
|
|
113
|
+
for (const path of parents) {
|
|
114
|
+
try {
|
|
115
|
+
const stat = lstatSync(path);
|
|
116
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) fail('io', `unsafe installation parent: ${path}`);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Only an unchanged, ordinary extracted tree can satisfy the verified staged artifact. */
|
|
124
|
+
function samePackTree(existing: string, verified: string): boolean {
|
|
125
|
+
if (!lstatSync(existing).isDirectory()) return false;
|
|
126
|
+
const current = readdirSync(existing, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
127
|
+
const expected = readdirSync(verified, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
128
|
+
if (current.length !== expected.length) return false;
|
|
129
|
+
return current.every((entry, i) => {
|
|
130
|
+
const other = expected[i]!;
|
|
131
|
+
if (entry.name !== other.name || entry.isSymbolicLink() || other.isSymbolicLink()) return false;
|
|
132
|
+
if (entry.isDirectory() && other.isDirectory()) return samePackTree(join(existing, entry.name), join(verified, entry.name));
|
|
133
|
+
return entry.isFile() && other.isFile() && readFileSync(join(existing, entry.name)).equals(readFileSync(join(verified, entry.name)));
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
86
137
|
function copyPlugin(source: string, destination: string): void {
|
|
87
138
|
if (!existsSync(source) || !lstatSync(source).isDirectory()) fail('io', `plugin directory not found: ${source}`);
|
|
88
139
|
safeTree(source);
|
|
@@ -189,21 +240,33 @@ async function fetchedMarketSource(spec: string, target: string, opts: InstallOp
|
|
|
189
240
|
refresh: opts.refresh, verifySignature: opts.verifySignature, trustedKeys: opts.trustedKeys,
|
|
190
241
|
});
|
|
191
242
|
} catch (error) {
|
|
192
|
-
if (error instanceof MarketFetchError && /^market not configured: /.test(error.message) &&
|
|
243
|
+
if (error instanceof MarketFetchError && /^market not configured: /.test(error.message) && opts.enterpriseId !== undefined) {
|
|
244
|
+
try {
|
|
245
|
+
marketIndex = await ensureInternalMarketIndex(marketName, opts.enterpriseId, {
|
|
246
|
+
root: opts.root, marketDir: opts.marketDir, configPath: opts.configPath, fetcher: opts.fetcher, refresh: opts.refresh,
|
|
247
|
+
});
|
|
248
|
+
} catch (internalError) {
|
|
249
|
+
if (internalError instanceof MarketFetchError) throw new PluginInstallError(internalError.reason, internalError.message);
|
|
250
|
+
throw internalError;
|
|
251
|
+
}
|
|
252
|
+
} else if (error instanceof MarketFetchError && /^market not configured: /.test(error.message) && hasLocalMarketIndex(marketName, opts)) {
|
|
193
253
|
return localMarketSource(spec, target, opts);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
throw error;
|
|
254
|
+
} else if (error instanceof MarketFetchError) throw new PluginInstallError(error.reason, error.message);
|
|
255
|
+
else throw error;
|
|
197
256
|
}
|
|
198
257
|
const matches = marketIndex.index.plugins.filter(entry => entry.name === name);
|
|
199
258
|
if (matches.length !== 1) fail('io', `plugin not found or ambiguous in ${marketName}: ${name}`);
|
|
200
259
|
const entry = matches[0]!;
|
|
201
|
-
|
|
260
|
+
await fetchVerifiedArtifact(entry.artifact, marketIndex.market.url, target, opts);
|
|
261
|
+
return { market: marketName, sha256: entry.artifact.sha256, signature: marketIndex.signature, expectedName: name, expectedVersion: entry.version };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function fetchVerifiedArtifact(artifact: MarketplaceIndex['plugins'][number]['artifact'], marketUrl: string, target: string, opts: InstallOptions): Promise<void> {
|
|
202
265
|
if (!artifact || typeof artifact.key !== 'string' || !artifact.key || !HASH.test(artifact.sha256)
|
|
203
266
|
|| !Number.isSafeInteger(artifact.bytes) || artifact.bytes < 0) fail('io', 'invalid artifact key, hash or size');
|
|
204
267
|
// Check the key as written, before URL resolution folds `..`/`.` or percent-encoded separators away.
|
|
205
268
|
if (!/^[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/.test(artifact.key) || artifact.key.split('/').some(part => part === '.' || part === '..')) fail('io', 'unsafe artifact key');
|
|
206
|
-
const base = new URL(
|
|
269
|
+
const base = new URL(marketUrl);
|
|
207
270
|
const url = new URL(artifact.key, base);
|
|
208
271
|
if (url.protocol !== 'https:' || url.origin !== base.origin || !url.pathname.startsWith(base.pathname)
|
|
209
272
|
|| url.username || url.password || url.search || url.hash || /[\\?#]/.test(artifact.key)) fail('io', 'unsafe artifact key');
|
|
@@ -235,7 +298,77 @@ async function fetchedMarketSource(spec: string, target: string, opts: InstallOp
|
|
|
235
298
|
fail('scan', 'artifact sha256 or size mismatch');
|
|
236
299
|
}
|
|
237
300
|
unpackArchive(bytes, target);
|
|
238
|
-
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async function stageRequiredKnowledgePacks(names: string[], market: string, stage: string, root: string, opts: InstallOptions): Promise<Array<{ name: string; destination: string; staged: string }>> {
|
|
304
|
+
if (!names.length) return [];
|
|
305
|
+
if (market === 'local') fail('io', 'knowledge pack requires need a signed market');
|
|
306
|
+
const unique = [...new Set(names)];
|
|
307
|
+
if (unique.some(name => !NAME.test(name))) fail('io', 'invalid required knowledge pack name');
|
|
308
|
+
let index: MarketplaceIndex;
|
|
309
|
+
let url: string | undefined;
|
|
310
|
+
let directory: string | undefined;
|
|
311
|
+
let internalVerified = false;
|
|
312
|
+
try {
|
|
313
|
+
const options = { root, marketDir: opts.marketDir, configPath: opts.configPath, fetcher: opts.fetcher,
|
|
314
|
+
refresh: opts.refresh, verifySignature: opts.verifySignature, trustedKeys: opts.trustedKeys };
|
|
315
|
+
let result: Awaited<ReturnType<typeof ensureMarketIndex>>;
|
|
316
|
+
try { result = await ensureMarketIndex(market, options); }
|
|
317
|
+
catch (error) {
|
|
318
|
+
if (!(error instanceof MarketFetchError) || !/^market not configured: /.test(error.message) || opts.enterpriseId === undefined) throw error;
|
|
319
|
+
result = await ensureInternalMarketIndex(market, opts.enterpriseId, options);
|
|
320
|
+
internalVerified = true;
|
|
321
|
+
}
|
|
322
|
+
index = result.index;
|
|
323
|
+
url = result.market.url;
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (error instanceof MarketFetchError && /^market not configured: /.test(error.message) && hasLocalMarketIndex(market, opts)) {
|
|
326
|
+
const path = indexPath(market, opts);
|
|
327
|
+
directory = dirname(path);
|
|
328
|
+
const sig = join(directory, 'index.sig');
|
|
329
|
+
if (!existsSync(sig)) fail('signature', `missing index.sig: ${market}`);
|
|
330
|
+
const result = (opts.verifySignature ?? verifyIndex)({ marketplaceBytes: readFileSync(path), signatureText: readFileSync(sig, 'utf8'), trustedKeys: opts.trustedKeys ?? [] });
|
|
331
|
+
if (!result.ok) fail('signature', `${result.reason}: ${result.detail}`);
|
|
332
|
+
if (result.index.name !== market) fail('io', `market index name mismatch: ${market}`);
|
|
333
|
+
index = result.index;
|
|
334
|
+
} else if (error instanceof MarketFetchError) throw new PluginInstallError(error.reason, error.message);
|
|
335
|
+
else throw error;
|
|
336
|
+
}
|
|
337
|
+
const packs: Array<{ name: string; destination: string; staged: string }> = [];
|
|
338
|
+
for (const name of unique) {
|
|
339
|
+
const matches = (index.knowledgePacks ?? []).filter(entry => entry.name === name);
|
|
340
|
+
if (matches.length !== 1) fail('io', `required knowledge pack not found or ambiguous: ${name}`);
|
|
341
|
+
const entry = matches[0]!;
|
|
342
|
+
if (!VERSION.test(entry.version)) fail('io', `invalid required knowledge pack version: ${name}`);
|
|
343
|
+
if (entry.visibility === 'internal') {
|
|
344
|
+
if (!opts.enterpriseId || entry.enterpriseId !== opts.enterpriseId) fail('io', `knowledge pack not authorized: ${name}`);
|
|
345
|
+
if (!internalVerified) {
|
|
346
|
+
try {
|
|
347
|
+
const authorized = await ensureInternalMarketIndex(market, opts.enterpriseId, {
|
|
348
|
+
root, marketDir: opts.marketDir, configPath: opts.configPath, fetcher: opts.fetcher, refresh: opts.refresh,
|
|
349
|
+
});
|
|
350
|
+
if (!authorized.index.knowledgePacks?.some(pack => pack.name === name && pack.version === entry.version
|
|
351
|
+
&& pack.artifact.sha256 === entry.artifact.sha256 && pack.artifact.bytes === entry.artifact.bytes
|
|
352
|
+
&& pack.artifact.key === entry.artifact.key)) fail('io', `knowledge pack not authorized: ${name}`);
|
|
353
|
+
} catch (error) {
|
|
354
|
+
if (error instanceof MarketFetchError) throw new PluginInstallError(error.reason, error.message);
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const staged = join(stage, `knowledge-${packs.length}`);
|
|
360
|
+
if (directory) {
|
|
361
|
+
const artifactPath = inside(directory, entry.artifact.key);
|
|
362
|
+
if (!existsSync(artifactPath) || !realpathSync(artifactPath).startsWith(`${realpathSync(directory)}${sep}`)) fail('scan', `unsafe knowledge pack artifact: ${name}`);
|
|
363
|
+
const bytes = readFileSync(artifactPath);
|
|
364
|
+
if (bytes.length !== entry.artifact.bytes || (opts.hashArtifact ?? (data => createHash('sha256').update(data).digest('hex')))(bytes).toLowerCase() !== entry.artifact.sha256.toLowerCase()) fail('scan', 'artifact sha256 or size mismatch');
|
|
365
|
+
unpackArchive(bytes, staged);
|
|
366
|
+
} else {
|
|
367
|
+
await fetchVerifiedArtifact(entry.artifact, url!, staged, opts);
|
|
368
|
+
}
|
|
369
|
+
packs.push({ name, staged, destination: join(root, 'knowledge-packs', market, name, entry.version) });
|
|
370
|
+
}
|
|
371
|
+
return packs;
|
|
239
372
|
}
|
|
240
373
|
|
|
241
374
|
export function resolvePluginSource(spec: string, target: string, opts: InstallOptions = {}): ResolvedPluginSource {
|
|
@@ -308,7 +441,9 @@ function declaresMain(packageRoot: string): boolean {
|
|
|
308
441
|
export async function installPlugin(spec: string, opts: InstallOptions = {}): Promise<InstalledPlugin> {
|
|
309
442
|
const root = resolve(opts.root ?? elanousStateRoot());
|
|
310
443
|
const stageRoot = join(root, 'plugins', '.staging');
|
|
444
|
+
assertInstallParents(root, join(stageRoot, 'plugin'));
|
|
311
445
|
mkdirSync(stageRoot, { recursive: true });
|
|
446
|
+
assertInstallParents(root, join(stageRoot, 'plugin'));
|
|
312
447
|
const stage = mkdtempSync(join(stageRoot, 'plugin-'));
|
|
313
448
|
try {
|
|
314
449
|
const source = marketSpec(spec, opts)
|
|
@@ -348,11 +483,20 @@ export async function installPlugin(spec: string, opts: InstallOptions = {}): Pr
|
|
|
348
483
|
const destination = join(root, 'plugins', source.market, name, version);
|
|
349
484
|
const emit = (event: InstallEvent) => opts.onEvent?.(event);
|
|
350
485
|
emit({ event: 'resolve', plugin: name, version, sha256: source.sha256 });
|
|
351
|
-
|
|
486
|
+
let security: ReturnType<typeof inspectPluginSecurity>;
|
|
487
|
+
try { security = inspectPluginSecurity(packageRoot); }
|
|
488
|
+
catch { fail('scan', 'plugin static security scan failed'); }
|
|
489
|
+
emit({ event: 'verify', signature: source.signature, scan: security.scan });
|
|
352
490
|
const capabilities = manifest.capabilities.map(capability => capability.kind);
|
|
353
491
|
const required = capabilities.length > 0;
|
|
492
|
+
const preConsent = decidePluginInstallation(security, capabilities, false);
|
|
493
|
+
if (!preConsent.ok && preConsent.reason === 'scan') fail('scan', 'plugin static security scan rejected package');
|
|
354
494
|
emit({ event: 'consent', capabilities, required });
|
|
355
|
-
|
|
495
|
+
const consented = !required || !!(opts.yes || await opts.consent?.(capabilities));
|
|
496
|
+
const decision = decidePluginInstallation(security, capabilities, consented);
|
|
497
|
+
if (!decision.ok) fail(decision.reason, decision.reason === 'scan'
|
|
498
|
+
? 'plugin static security scan rejected package' : 'plugin capabilities require consent');
|
|
499
|
+
const packs = await stageRequiredKnowledgePacks(manifest.requires?.knowledgePacks ?? [], source.market, stage, root, opts);
|
|
356
500
|
emit({ event: 'credentials', connectors: (manifest.contributes.connectors ?? []).map(connector => ({
|
|
357
501
|
id: connector.id, fields: (connector.fields ?? connector.userConfig?.map(field => ({ name: field.key, secret: field.secret })) ?? [])
|
|
358
502
|
.map(field => ({ name: field.name, secret: field.secret === true })),
|
|
@@ -370,17 +514,44 @@ export async function installPlugin(spec: string, opts: InstallOptions = {}): Pr
|
|
|
370
514
|
const { nodes, nodeErrors } = inspectPluginNodes(packageRoot, manifest);
|
|
371
515
|
emit({ event: 'registered', kinds, nodes, nodeErrors, graphs, skills });
|
|
372
516
|
const installed = withLedgerLock(root, () => {
|
|
517
|
+
assertInstallParents(root, destination);
|
|
373
518
|
if (existsSync(destination)) fail('conflict', `plugin already installed: ${name}@${version}`);
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
519
|
+
for (const pack of packs) {
|
|
520
|
+
assertInstallParents(root, pack.destination);
|
|
521
|
+
if (packPathExists(pack.destination) && !samePackTree(pack.destination, pack.staged)) {
|
|
522
|
+
fail('conflict', `installed knowledge pack differs from verified artifact: ${pack.name}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
const moved: string[] = [];
|
|
377
526
|
try {
|
|
527
|
+
for (const pack of packs) {
|
|
528
|
+
assertInstallParents(root, pack.destination);
|
|
529
|
+
if (packPathExists(pack.destination)) continue;
|
|
530
|
+
mkdirSync(dirname(pack.destination), { recursive: true });
|
|
531
|
+
assertInstallParents(root, pack.destination);
|
|
532
|
+
renameSync(pack.staged, pack.destination);
|
|
533
|
+
moved.push(pack.destination);
|
|
534
|
+
}
|
|
535
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
536
|
+
assertInstallParents(root, destination);
|
|
537
|
+
renameSync(join(stage, 'package'), destination);
|
|
538
|
+
moved.push(destination);
|
|
539
|
+
const item = { name, version, market: source.market, path: destination, sha256: source.sha256, installedAt: new Date().toISOString() };
|
|
540
|
+
let installedSecurity: ReturnType<typeof inspectPluginSecurity>;
|
|
541
|
+
try { installedSecurity = inspectPluginSecurity(destination); }
|
|
542
|
+
catch { fail('scan', 'plugin package integrity verification failed'); }
|
|
543
|
+
if (installedSecurity.integrity !== security.integrity || installedSecurity.scan === 'dangerous') {
|
|
544
|
+
fail('scan', 'plugin package integrity changed during installation');
|
|
545
|
+
}
|
|
378
546
|
writeLedger(root, [...listInstalledPlugins(root), item]);
|
|
547
|
+
return item;
|
|
379
548
|
} catch (error) {
|
|
380
|
-
|
|
549
|
+
for (const path of moved.reverse()) {
|
|
550
|
+
assertInstallParents(root, path);
|
|
551
|
+
rmSync(path, { recursive: true, force: true });
|
|
552
|
+
}
|
|
381
553
|
throw error;
|
|
382
554
|
}
|
|
383
|
-
return item;
|
|
384
555
|
});
|
|
385
556
|
// The install is committed above; a listener that throws must not turn a finished install into a failure
|
|
386
557
|
// (the ledger would say «installed» while the caller saw «io», and a retry would hit «conflict»).
|
|
@@ -10,6 +10,7 @@ import { dispatchOmniSearch } from '../../skills/tools/omni-search.js';
|
|
|
10
10
|
import { runGraph } from '../../graph-runner/runner.js';
|
|
11
11
|
import { parseGraphTemplateYaml } from '../../self-implement/graph-yaml.js';
|
|
12
12
|
import { installPlugin } from '../install/plugin-install.js';
|
|
13
|
+
import { inspectPluginSecurity } from '../core/capability-policy.js';
|
|
13
14
|
import { generateWizardFiles, type WizardResearchDraft } from './wizard-generate.js';
|
|
14
15
|
import { bundleInstalledWizardPlugin, type MarketBundleResult } from './market-bundle.js';
|
|
15
16
|
|
|
@@ -127,7 +128,7 @@ export async function validatePluginDir(dir: string): Promise<string[]> {
|
|
|
127
128
|
if (lstatSync(file).isSymbolicLink()) errors.push('안전하지 않은 plugin.json 링크');
|
|
128
129
|
else manifest = JSON.parse(readFileSync(file, 'utf8'));
|
|
129
130
|
}
|
|
130
|
-
catch
|
|
131
|
+
catch { errors.push('plugin.json 파싱 실패'); }
|
|
131
132
|
const extension = isRecord(manifest) && isRecord(manifest.extensions) ? manifest.extensions['ai.elanous'] : undefined;
|
|
132
133
|
const graphs = isRecord(extension) ? extension.graphs : undefined;
|
|
133
134
|
if (isRecord(extension) && extension.contributes !== undefined) errors.push('extension contributes 덮어쓰기 금지');
|
|
@@ -143,69 +144,73 @@ export async function validatePluginDir(dir: string): Promise<string[]> {
|
|
|
143
144
|
if (lstatSync(file).isSymbolicLink()) errors.push('안전하지 않은 recipes.yaml 링크');
|
|
144
145
|
else recipes = parseYaml(readFileSync(file, 'utf8'));
|
|
145
146
|
}
|
|
146
|
-
catch
|
|
147
|
+
catch { errors.push('recipes.yaml 파싱 실패'); }
|
|
147
148
|
if (!isRecord(recipes)) errors.push('recipes.yaml 은 맵이어야 한다');
|
|
148
149
|
else for (const [id, recipe] of Object.entries(recipes)) {
|
|
149
150
|
if (!isRecord(recipe) ||
|
|
150
151
|
(!(typeof recipe.command === 'string' && recipe.command.trim()) && !(typeof recipe.approval === 'string' && recipe.approval.trim())) ||
|
|
151
152
|
(recipe.command !== undefined && (typeof recipe.command !== 'string' || !recipe.command.trim())) ||
|
|
152
153
|
(recipe.approval !== undefined && (typeof recipe.approval !== 'string' || !recipe.approval.trim())) ||
|
|
153
|
-
(recipe.timeout_ms !== undefined && (!Number.isSafeInteger(recipe.timeout_ms) || Number(recipe.timeout_ms) <= 0))) errors.push(`잘못된 recipe: ${id}`);
|
|
154
|
+
(recipe.timeout_ms !== undefined && (!Number.isSafeInteger(recipe.timeout_ms) || Number(recipe.timeout_ms) <= 0))) errors.push(`잘못된 recipe: ${/^[a-zA-Z0-9_-]+$/.test(id) ? id : 'invalid'}`);
|
|
154
155
|
}
|
|
155
156
|
for (const graph of Array.isArray(graphs) ? graphs : []) {
|
|
156
157
|
if (typeof graph !== 'string') continue;
|
|
157
158
|
const file = inside(dir, graph);
|
|
158
|
-
if (!file || !/^\.\/graphs\/[a-zA-Z0-9_-]+\.ya?ml$/.test(graph)) { errors.push(
|
|
159
|
+
if (!file || !/^\.\/graphs\/[a-zA-Z0-9_-]+\.ya?ml$/.test(graph)) { errors.push('안전하지 않은 graph 경로'); continue; }
|
|
159
160
|
try {
|
|
160
|
-
if (lstatSync(file).isSymbolicLink()) { errors.push(
|
|
161
|
+
if (lstatSync(file).isSymbolicLink()) { errors.push('안전하지 않은 graph 링크'); continue; }
|
|
161
162
|
const parsed = parseGraphTemplateYaml(readFileSync(file, 'utf8'), file);
|
|
162
|
-
errors.push(...parsed.errors.map(
|
|
163
|
+
errors.push(...parsed.errors.map(() => 'graph 정의 오류'));
|
|
163
164
|
const template = parsed.template;
|
|
164
165
|
if (!template) continue;
|
|
165
|
-
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(template.graphId)) errors.push(
|
|
166
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(template.graphId)) errors.push('잘못된 graph_id');
|
|
166
167
|
if (template.terminalNodes.length !== 2 || !template.terminalNodes.includes('done') || !template.terminalNodes.includes('failed')) errors.push('terminal_nodes 는 done, failed 이어야 한다');
|
|
167
168
|
const executionNodes = template.nodes.filter(node => !template.terminalNodes.includes(node.nodeId));
|
|
168
169
|
if (executionNodes.length < 2) errors.push(`실행 노드는 2개 이상이어야 한다: ${executionNodes.length}개`);
|
|
169
170
|
for (const node of template.nodes) {
|
|
170
171
|
if (node.recipe.startsWith('cmd:')) {
|
|
171
172
|
const id = node.recipe.slice(4);
|
|
172
|
-
if (!isRecord(recipes) || !isRecord(recipes[id]) || recipes[id].approval !== undefined || typeof recipes[id].command !== 'string' || !recipes[id].command.trim()) errors.push(`recipe ${id} 없음`);
|
|
173
|
+
if (!isRecord(recipes) || !isRecord(recipes[id]) || recipes[id].approval !== undefined || typeof recipes[id].command !== 'string' || !recipes[id].command.trim()) errors.push(`recipe ${/^[a-zA-Z0-9_-]+$/.test(id) ? id : 'invalid'} 없음`);
|
|
173
174
|
} else if (node.recipe.startsWith('approval:')) {
|
|
174
175
|
const id = node.recipe.slice(9);
|
|
175
|
-
if (!isRecord(recipes) || !isRecord(recipes[id]) || typeof recipes[id].approval !== 'string' || !recipes[id].approval.trim()) errors.push(`approval recipe ${id} 없음`);
|
|
176
|
-
} else if (node.recipe !== 'none') errors.push(`지원하지 않는 recipe: ${node.recipe}`);
|
|
176
|
+
if (!isRecord(recipes) || !isRecord(recipes[id]) || typeof recipes[id].approval !== 'string' || !recipes[id].approval.trim()) errors.push(`approval recipe ${/^[a-zA-Z0-9_-]+$/.test(id) ? id : 'invalid'} 없음`);
|
|
177
|
+
} else if (node.recipe !== 'none') errors.push(`지원하지 않는 recipe: ${/^[a-zA-Z0-9_:-]+$/.test(node.recipe) ? node.recipe : 'invalid'}`);
|
|
177
178
|
}
|
|
178
|
-
} catch
|
|
179
|
+
} catch { errors.push('graph 파싱 실패'); }
|
|
179
180
|
}
|
|
180
181
|
const visit = (path: string): void => {
|
|
181
182
|
for (const entry of readdirSync(path, { withFileTypes: true })) {
|
|
182
183
|
const file = join(path, entry.name);
|
|
183
|
-
if (entry.isSymbolicLink() || (!entry.isDirectory() && !entry.isFile())) { errors.push(
|
|
184
|
+
if (entry.isSymbolicLink() || (!entry.isDirectory() && !entry.isFile())) { errors.push('안전하지 않은 파일'); continue; }
|
|
184
185
|
if (entry.isDirectory()) visit(file);
|
|
185
186
|
else if (/\.[cm]?[jt]sx?$/.test(entry.name)) {
|
|
186
187
|
const source = readFileSync(file, 'utf8');
|
|
187
188
|
for (const match of source.matchAll(/\b(?:import|export)\s*(?:[\s\S]*?\s+from\s*)?["']([^"']+)["']|\b(?:import|require)\s*\(\s*["']([^"']+)["']/g)) {
|
|
188
189
|
const target = match[1] ?? match[2]!;
|
|
189
|
-
if (/(?:^|\/)src\//.test(target) && (target.startsWith('/') || target.startsWith('.'))) errors.push(
|
|
190
|
+
if (/(?:^|\/)src\//.test(target) && (target.startsWith('/') || target.startsWith('.'))) errors.push('src import 금지');
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
194
|
};
|
|
194
|
-
try { visit(dir); } catch
|
|
195
|
+
try { visit(dir); } catch { errors.push('파일 검사 실패'); }
|
|
195
196
|
try {
|
|
196
197
|
const example = join(dir, 'examples', 'input.json');
|
|
197
198
|
if (lstatSync(example).isSymbolicLink()) errors.push('안전하지 않은 examples/input.json 링크');
|
|
198
199
|
else JSON.parse(readFileSync(example, 'utf8'));
|
|
199
|
-
} catch
|
|
200
|
+
} catch { errors.push('examples/input.json 파싱 실패'); }
|
|
201
|
+
let security: ReturnType<typeof inspectPluginSecurity>;
|
|
202
|
+
try { security = inspectPluginSecurity(dir); }
|
|
203
|
+
catch { errors.push('보안 검사 실패'); return errors; }
|
|
204
|
+
if (security.scan === 'dangerous') errors.push(...security.findings.filter(f => f.level === 'dangerous').map(f => `보안 검사 차단: ${f.code}`));
|
|
200
205
|
const step = join(dir, 'graphs', 'run-step.ts');
|
|
201
206
|
try {
|
|
202
207
|
if (!existsSync(step)) errors.push('run-step.ts 없음');
|
|
203
|
-
else if (errors.some(error => error.startsWith('안전하지 않은
|
|
208
|
+
else if (errors.some(error => error.startsWith('안전하지 않은 파일'))) return errors;
|
|
204
209
|
else {
|
|
205
210
|
const build = await Bun.build({ entrypoints: [step], target: 'bun' });
|
|
206
|
-
if (!build.success) errors.push(
|
|
211
|
+
if (!build.success) errors.push('run-step.ts 문법 오류');
|
|
207
212
|
}
|
|
208
|
-
} catch
|
|
213
|
+
} catch { errors.push('run-step.ts 문법 오류'); }
|
|
209
214
|
return errors;
|
|
210
215
|
}
|
|
211
216
|
|
|
@@ -359,7 +364,7 @@ export async function makePlugin({ request, draftFile, name, parentDir, run, mar
|
|
|
359
364
|
const step = async (stage: keyof MakePluginResult['timings'], action: () => void | Promise<void>): Promise<void> => {
|
|
360
365
|
const start = performance.now();
|
|
361
366
|
try { await action(); }
|
|
362
|
-
finally { const ms = Math.round(performance.now() - start); timings[stage] = ms; debug.log('plugin.maker', stage, { ms, errors: result.errors }); }
|
|
367
|
+
finally { const ms = Math.round(performance.now() - start); timings[stage] = ms; debug.log('plugin.maker', stage, { ms, errors: redactSecrets(result.errors) }); }
|
|
363
368
|
};
|
|
364
369
|
try {
|
|
365
370
|
emit('request', request);
|
|
@@ -461,7 +466,7 @@ export async function makePlugin({ request, draftFile, name, parentDir, run, mar
|
|
|
461
466
|
}
|
|
462
467
|
} catch (error) {
|
|
463
468
|
result.status = 'failed';
|
|
464
|
-
result.errors.push(error instanceof Error ? error.message : String(error));
|
|
469
|
+
result.errors.push(redactSecretText(error instanceof Error ? error.message : String(error)));
|
|
465
470
|
} finally {
|
|
466
471
|
emit('done', result.status, { errors: result.errors });
|
|
467
472
|
}
|
|
@@ -10,6 +10,7 @@ export interface WizardResearchDraft {
|
|
|
10
10
|
credentials?: Array<{ name: string }>;
|
|
11
11
|
}>;
|
|
12
12
|
skill?: { description: string; instructions: string; requires?: string[] };
|
|
13
|
+
requires?: { knowledgePacks?: string[] };
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
const SLUG = /^[a-z0-9][a-z0-9-]{1,31}$/;
|
|
@@ -46,9 +47,16 @@ export function generateWizardFiles(dir: string, slug: string, draft: WizardRese
|
|
|
46
47
|
if (!Array.isArray(requires) || requires.some(resource => typeof resource !== 'string' || !knownResources.has(resource))) {
|
|
47
48
|
throw new Error('wizard requires must reference existing resource ids');
|
|
48
49
|
}
|
|
50
|
+
if (draft.requires !== undefined && (!draft.requires || typeof draft.requires !== 'object' || Array.isArray(draft.requires) ||
|
|
51
|
+
Object.keys(draft.requires).some(key => key !== 'knowledgePacks') ||
|
|
52
|
+
(draft.requires.knowledgePacks !== undefined && (!Array.isArray(draft.requires.knowledgePacks) ||
|
|
53
|
+
draft.requires.knowledgePacks.some(pack => typeof pack !== 'string' || !pack.trim()))))) {
|
|
54
|
+
throw new Error('wizard knowledge packs must be non-empty names');
|
|
55
|
+
}
|
|
49
56
|
const manifestPath = join(dir, 'plugin.json');
|
|
50
57
|
const existing = existsSync(manifestPath) ? JSON.parse(readFileSync(manifestPath, 'utf8')) as {
|
|
51
|
-
name: string; description?: string;
|
|
58
|
+
name: string; description?: string; requires?: { knowledgePacks?: string[]; [key: string]: unknown };
|
|
59
|
+
extensions: { 'ai.elanous': { connectors?: unknown[]; graphs?: string[]; researchDraft?: boolean } };
|
|
52
60
|
} : undefined;
|
|
53
61
|
if (existing && (existing.name !== slug || !existing.extensions?.['ai.elanous'])) {
|
|
54
62
|
throw new Error('wizard scaffold name or extension mismatch');
|
|
@@ -69,9 +77,13 @@ export function generateWizardFiles(dir: string, slug: string, draft: WizardRese
|
|
|
69
77
|
throw new Error('wizard cannot replace existing scaffold connectors');
|
|
70
78
|
}
|
|
71
79
|
const manifest = existing ?? { name: slug, version: '0.1.0', description: draft.description,
|
|
80
|
+
requires: undefined as { knowledgePacks?: string[]; [key: string]: unknown } | undefined,
|
|
72
81
|
extensions: { 'ai.elanous': { graphs: [`./graphs/${slug}.yaml`],
|
|
73
82
|
capabilities: ['fs:workdir', 'proc:bun', 'proc:elanous'], connectors: [] as unknown[], researchDraft: true } } };
|
|
74
83
|
if (options.regenerate) manifest.description = draft.description;
|
|
84
|
+
if (draft.requires?.knowledgePacks !== undefined) {
|
|
85
|
+
manifest.requires = { ...manifest.requires, knowledgePacks: [...new Set(draft.requires.knowledgePacks)] };
|
|
86
|
+
}
|
|
75
87
|
manifest.extensions['ai.elanous'].connectors = connectors;
|
|
76
88
|
manifest.extensions['ai.elanous'].researchDraft = true;
|
|
77
89
|
|
|
@@ -125,7 +137,8 @@ export function listWizardDrafts(parent: string): Array<{ name: string; descript
|
|
|
125
137
|
const skillPath = join(skillDir, 'SKILL.md');
|
|
126
138
|
if (lstatSync(manifestPath).isSymbolicLink() || lstatSync(skillDir).isSymbolicLink() || lstatSync(skillPath).isSymbolicLink()) return [];
|
|
127
139
|
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as {
|
|
128
|
-
name?: string; description?: string;
|
|
140
|
+
name?: string; description?: string; requires?: { knowledgePacks?: string[] };
|
|
141
|
+
extensions?: { 'ai.elanous'?: { researchDraft?: boolean; connectors?: Array<{ id: string; fields: Array<{ name: string }> }> } } };
|
|
129
142
|
if (manifest.name !== entry.name || manifest.extensions?.['ai.elanous']?.researchDraft !== true) return [];
|
|
130
143
|
const skill = readFileSync(skillPath, 'utf8');
|
|
131
144
|
const parts = /^---\n([\s\S]*?)---\n\n([\s\S]*)$/.exec(skill);
|
|
@@ -134,6 +147,7 @@ export function listWizardDrafts(parent: string): Array<{ name: string; descript
|
|
|
134
147
|
return [{ name: entry.name, description: manifest.description, draft: {
|
|
135
148
|
description: manifest.description,
|
|
136
149
|
connectors: manifest.extensions['ai.elanous'].connectors?.map(connector => ({ id: connector.id, credentials: connector.fields.map(field => ({ name: field.name })) })) ?? [],
|
|
150
|
+
...(manifest.requires?.knowledgePacks !== undefined ? { requires: { knowledgePacks: manifest.requires.knowledgePacks } } : {}),
|
|
137
151
|
skill: { description: meta.description ?? manifest.description, instructions: parts[2]!.trimEnd(), requires: meta.requires ?? [] },
|
|
138
152
|
} }];
|
|
139
153
|
} catch { return []; }
|