elanous 0.2.22 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +7 -0
- package/README.md +32 -22
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
- package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
- package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
- package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
- package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
- package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
- package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
- package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
- package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
- package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
- package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
- package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
- package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
- package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
- package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
- package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-6168a7c43e6ef8f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +1 -0
- package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
- package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +1 -0
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
- package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +24 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +24 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
- package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
- package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
- package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
- package/catalog/models/openai/gpt-6-astra.yaml +6 -0
- package/catalog/models/openai/gpt-6-luna.yaml +6 -0
- package/catalog/models/openai/gpt-6-sol.yaml +6 -0
- package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
- package/graphs/log-horizon/recipes.yaml +3 -0
- package/graphs/release/recipes.yaml +1 -1
- package/graphs/release/release-loop.yaml +6 -2
- package/graphs/release-rehearsal/recipes.yaml +12 -0
- package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
- package/package.json +4 -1
- package/scripts/bench-report.ts +82 -3
- package/scripts/ci-typecheck-changed.ts +10 -1
- package/scripts/hq/hq-fence-wrapper.sh +148 -0
- package/scripts/lib/typecheck-ratchet.ts +51 -0
- package/scripts/openai-relay-server.ts +5 -1
- package/scripts/release-loop/docs-node.ts +258 -43
- package/scripts/release-loop/gate-method.ts +59 -0
- package/scripts/release-loop/gate-node.ts +73 -7
- package/scripts/release-loop/gate-wall.ts +208 -0
- package/scripts/release-loop/known-issues-node.ts +53 -8
- package/scripts/release-loop/publish-at.ts +14 -0
- package/scripts/release-loop/publish-node.ts +17 -2
- package/scripts/release-loop/resume-release.ts +34 -4
- package/scripts/release-loop/resume.ts +53 -0
- package/scripts/release-loop/shard-plan.ts +3 -11
- package/scripts/release-loop/tui-node-checks.ts +22 -0
- package/scripts/release-loop/unattended-release.ts +8 -1
- package/scripts/rhythm/daily.ts +51 -2
- package/scripts/rhythm/weekly.ts +3 -2
- package/scripts/tsc-main-safety-net.ts +189 -0
- package/scripts/usage-rollup.ts +8 -4
- package/src/acp/codex-plugins.ts +48 -6
- package/src/agent/monad-agent-turn.ts +67 -5
- package/src/agent/run-context.ts +10 -0
- package/src/agent/tool-profile.ts +28 -2
- package/src/agent-mission/acp-judge.ts +8 -2
- package/src/agent-mission/capabilities-cli.ts +16 -1
- package/src/agent-mission/driver.ts +1 -1
- package/src/agent-mission/pr-review-watch.ts +6 -2
- package/src/agent-mission/review-loop.ts +33 -5
- package/src/agent-substrate/acp-reviewer.ts +17 -8
- package/src/agent-substrate/pr-reviewer.ts +164 -28
- package/src/agent-substrate/review-intent.ts +6 -4
- package/src/agent-substrate/self-review-cli.ts +111 -16
- package/src/agent-substrate/shard-boundary-intent.ts +92 -26
- package/src/ask-user-question/pending-questions.ts +8 -2
- package/src/autopilot/build/llm-conflict-merge.ts +216 -12
- package/src/autopilot/codebase-grounding.ts +44 -0
- package/src/autopilot/llm-control-brain.ts +13 -1
- package/src/autopilot/mission-codebase-gate.ts +8 -77
- package/src/autopilot/pr-manager.ts +12 -3
- package/src/boot/acp-server.ts +4 -7
- package/src/boot/acp-socket-path.ts +7 -0
- package/src/briefing/brief-items.ts +21 -13
- package/src/chat/index.ts +12 -3
- package/src/cli/agent-cli.ts +20 -0
- package/src/cli/brief-cli.ts +27 -21
- package/src/cli/cli-user-error.ts +9 -2
- package/src/cli/log-event-names.ts +3 -0
- package/src/cli/logs-cli.ts +1 -0
- package/src/cli/mcp-login.ts +111 -37
- package/src/cli/plugin-cli.ts +21 -1
- package/src/cli/pod-cli.ts +26 -0
- package/src/cli/pr-cli.ts +30 -2
- package/src/cli/pr-land-overlap-evidence.ts +131 -0
- package/src/cli/release-cli.ts +53 -11
- package/src/cli/self-update.ts +173 -10
- package/src/cli/skills-cli.ts +12 -3
- package/src/cli/tasks-cli.ts +133 -27
- package/src/context-bus/context-first.ts +51 -2
- package/src/context-bus/context-now-surfaces.ts +13 -2
- package/src/context-bus/long-term-memory.ts +3 -1
- package/src/context-bus/nightly-condense.ts +3 -2
- package/src/core-turn/run-goal-loop.ts +86 -2
- package/src/dashboard/chat-fold.ts +20 -0
- package/src/dashboard/first-screen-band.ts +151 -1
- package/src/dashboard/index.ts +27 -5
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
- package/src/dashboard/stale-install-check.ts +13 -2
- package/src/dashboard/turn-stream-formatter.ts +25 -0
- package/src/debug/log-diet.ts +159 -0
- package/src/debug/log.ts +52 -17
- package/src/display/coordinator.ts +25 -2
- package/src/domains/coo-admin-tool.ts +27 -0
- package/src/domains/cron-match.ts +1 -0
- package/src/domains/outbound-alert.ts +17 -6
- package/src/domains/release-tool.ts +119 -10
- package/src/domains/schedule-registry.ts +10 -7
- package/src/domains/schedule-runner.ts +1 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/elanous-daemon.ts +3 -3
- package/src/execution-loop/launch-gate.ts +1 -1
- package/src/expression/i18n/messages.en.ts +5 -0
- package/src/expression/i18n/messages.ja.ts +5 -0
- package/src/expression/i18n/messages.ko.ts +5 -0
- package/src/expression/i18n/messages.zh.ts +5 -0
- package/src/expression/i18n/types.ts +8 -0
- package/src/github/pr-labels.ts +1 -0
- package/src/graph-runner/runner.ts +54 -5
- package/src/harness/dispatch-backpressure.ts +259 -0
- package/src/harness/harness-cli-command.ts +107 -28
- package/src/harness/harness-seams.ts +2 -20
- package/src/harness/harness-substrate-default.ts +72 -1
- package/src/harness/nested-elanous-policy.ts +4 -2
- package/src/hq/fence-wrapper.ts +7 -0
- package/src/hq/hq.ts +33 -2
- package/src/hq/lease.ts +13 -0
- package/src/hq/seats.ts +114 -18
- package/src/index.ts +163 -64
- package/src/intake-plane/collect-github.ts +19 -1
- package/src/intake-plane/digest.ts +45 -20
- package/src/intake-plane/lens.ts +36 -8
- package/src/intelligence-map/model-alias.ts +6 -0
- package/src/intelligence-map/model-catalog.ts +41 -0
- package/src/knowledge/kgs/pack.ts +5 -2
- package/src/knowledge/kgs/sqlite-store.ts +15 -0
- package/src/knowledge/tools/knowledge-query.ts +20 -2
- package/src/knowledge/write.ts +234 -2
- package/src/llm/bedrock-provider.ts +175 -0
- package/src/llm/bedrock.ts +345 -0
- package/src/llm/provider-credentials.ts +3 -1
- package/src/llm.ts +306 -35
- package/src/loops/budget.ts +150 -0
- package/src/loops/orchestrator/seat-share.ts +6 -49
- package/src/loops/orchestrator/traffic.ts +5 -81
- package/src/market/signed-index.ts +42 -0
- package/src/mcp/mcp-oauth.ts +136 -17
- package/src/model-tier/llm-tier-map.ts +48 -4
- package/src/models/prompts.ts +22 -1
- package/src/mss/logging/horizon-watch.ts +168 -0
- package/src/mss/logging/log-store.ts +204 -15
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/consult-requests.ts +7 -10
- package/src/nexus/api/discord-trigger-bot.ts +6 -3
- package/src/nexus/api/error-reports.ts +30 -8
- package/src/nexus/api/http-server.ts +8 -0
- package/src/nexus/api/loop-resources.ts +42 -0
- package/src/nexus/api/outbound-report.ts +8 -3
- package/src/nexus/api/telegram-trigger-bot.ts +6 -3
- package/src/nexus/index.ts +10 -0
- package/src/nexus/outbound/format.ts +2 -0
- package/src/nexus/outbound/router.ts +198 -13
- package/src/oauth/codex-account-rotation.ts +16 -18
- package/src/oauth/codex-account-store.ts +134 -5
- package/src/oauth/fallback-chain.ts +28 -6
- package/src/onboarding.ts +2 -1
- package/src/plugins/adapters/claude-package.ts +4 -12
- package/src/plugins/core/capability-policy.ts +141 -0
- package/src/plugins/core/host.ts +21 -8
- package/src/plugins/core/manifest.ts +19 -2
- package/src/plugins/core/trust-store.ts +15 -0
- package/src/plugins/core/types.ts +12 -0
- package/src/plugins/install/market-fetch.ts +68 -16
- package/src/plugins/install/plugin-install.ts +187 -16
- package/src/plugins/maker/plugin-maker.ts +25 -20
- package/src/plugins/maker/wizard-generate.ts +16 -2
- package/src/policy/llm-policy.ts +14 -1
- package/src/process/pid-liveness.ts +1 -1
- package/src/prompt-cache/openai.ts +10 -6
- package/src/prompt-cache/openrouter.ts +94 -0
- package/src/prompt-enhance/enhance.ts +46 -5
- package/src/prompt-library/family-prompt-coverage.ts +1 -0
- package/src/prompt-library/universal-preamble.ts +2 -2
- package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
- package/src/registry/loader.ts +6 -1
- package/src/release-loop/checklist.ts +24 -9
- package/src/release-loop/feature-store.ts +3 -0
- package/src/release-loop/gate-shards.ts +48 -4
- package/src/release-loop/landed-to-green.ts +81 -0
- package/src/release-loop/light-rc.ts +11 -1
- package/src/release-loop/merged-pr-checklist.ts +10 -0
- package/src/release-loop/placement.ts +91 -22
- package/src/release-loop/rehearsal.ts +317 -0
- package/src/release-loop/release-schedule.ts +13 -1
- package/src/release-loop/rubric-types.ts +1 -0
- package/src/release-loop/rubric.ts +2 -2
- package/src/retro/daily.ts +23 -9
- package/src/seat-loop/seat-loop.ts +34 -1
- package/src/seat-loop/traffic-signal.ts +44 -0
- package/src/self-dev/ask-launch-flow.ts +2 -2
- package/src/self-dev/dev-cli.ts +67 -3
- package/src/self-dev/dev-pipeline.ts +4 -6
- package/src/self-dev/draft-residue.ts +463 -0
- package/src/self-dev/draft-sweep.ts +151 -10
- package/src/self-dev/draft-triage-rules.ts +27 -1
- package/src/self-dev/launch-preflight-text.ts +549 -0
- package/src/self-dev/launch-preflight.ts +10 -545
- package/src/self-dev/orchestrate-cli.ts +57 -2
- package/src/self-dev/orchestrate-summary-line.ts +13 -0
- package/src/self-dev/orchestrate.ts +8 -135
- package/src/self-dev/review-provider-fallback.ts +115 -19
- package/src/self-dev/run-store.ts +1 -3
- package/src/self-dev/run-supervisor.ts +3 -22
- package/src/self-dev/run-types.ts +178 -0
- package/src/self-dev/shard-aggregate.ts +61 -13
- package/src/self-dev/shard-plan.ts +5 -1
- package/src/self-dev/shard-run.ts +23 -5
- package/src/self-dev/supervisor-verdict-edges.ts +2 -4
- package/src/self-implement/blocked-draft-policy.ts +3 -19
- package/src/self-implement/draft-on-stop-mode.ts +18 -0
- package/src/self-implement/follow-up-goals.ts +114 -38
- package/src/self-implement/gate-baseline-reap.ts +157 -0
- package/src/self-implement/gate-baseline.ts +78 -16
- package/src/self-implement/gate-cli.ts +12 -2
- package/src/self-implement/gate-remote.ts +17 -6
- package/src/self-implement/goal-author.ts +24 -4
- package/src/self-implement/goal-digest.ts +19 -0
- package/src/self-implement/graph-overlay-condition.ts +4 -0
- package/src/self-implement/headless-elanous-driver.ts +11 -9
- package/src/self-implement/host-regate.ts +120 -29
- package/src/self-implement/l8-merge-queue.ts +67 -5
- package/src/self-implement/merge-train.ts +131 -0
- package/src/self-implement/off-diff-evidence.ts +9 -0
- package/src/self-implement/orchestrator.ts +133 -16
- package/src/self-implement/review-finding-recurrence.ts +28 -0
- package/src/self-implement/rework-policy.ts +2 -1
- package/src/self-implement/round-summary-card.ts +63 -0
- package/src/self-implement/run-ledger.ts +4 -3
- package/src/self-implement/run-step-projection.ts +147 -0
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/seams.ts +36 -3
- package/src/self-implement/self-implement-cli.ts +3 -1
- package/src/self-implement/train-gate-remote.ts +158 -0
- package/src/session-runtime/index.ts +10 -1
- package/src/session-runtime/retry-api.ts +11 -1
- package/src/skills/gift-install.ts +119 -0
- package/src/skills/runner.ts +59 -2
- package/src/skills/skill-feedback.ts +31 -1
- package/src/skills/skill-tier.ts +1 -0
- package/src/smart-wizard/capability-index.ts +231 -0
- package/src/smart-wizard/rung.ts +74 -0
- package/src/steward/launch.ts +20 -9
- package/src/steward/triage.ts +4 -2
- package/src/storage/file-lock.ts +8 -1
- package/src/task-agent/actions.ts +4 -0
- package/src/task-agent/card-evidence.ts +59 -13
- package/src/task-agent/judge.ts +4 -3
- package/src/task-agent/land-worktree.ts +201 -0
- package/src/task-agent/live-move-history.ts +133 -0
- package/src/task-agent/live-moves.ts +106 -19
- package/src/task-agent/parent-host.ts +117 -8
- package/src/task-agent/rejudge-on-head.ts +297 -0
- package/src/task-agent/review-result-capture.ts +218 -0
- package/src/task-agent/shadow.ts +103 -7
- package/src/task-agent/task-hand.ts +136 -11
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
- package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +66 -14
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
- package/src/task-orchestrator/surfaces/self-implement.ts +6 -2
- package/src/telegram-service.ts +5 -1
- package/src/telegram.ts +17 -4
- package/src/time/format.ts +13 -4
- package/src/tool-runtime/goal-author-runtime.ts +1 -0
- package/src/tool-runtime/self-cognition-catalog.ts +23 -0
- package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
- package/src/user-config.ts +132 -24
- package/src/ux-sim/slash-menu-frames.ts +168 -0
- package/src/version/packed-revision.json +1 -1
- package/src/web-terminal/preview-tap-registry.ts +5 -2
- package/src/workflow-runtime/triggers/scheduler.ts +1 -0
- package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
- package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
- package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
- package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
- package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
- package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
- package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
- package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
- package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
- package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
- package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
- package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
- package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
- package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
- package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
- package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
- package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
- /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → rfkMm4movqkqMebBrCXiR}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import type { Keybinding, SlashCommand } from './types.js';
|
|
3
|
+
import type { Keybinding, PluginDependency, SlashCommand } from './types.js';
|
|
4
4
|
import type { PromptKind, PromptScope, PromptTargetSlot } from '../../prompt-bank/types.js';
|
|
5
5
|
import type {
|
|
6
6
|
MissionDefinition,
|
|
@@ -223,6 +223,8 @@ export interface PluginManifest {
|
|
|
223
223
|
activationEvents: string[];
|
|
224
224
|
contributes: PluginManifestContributes;
|
|
225
225
|
capabilities: PluginCapability[];
|
|
226
|
+
/** `plugin.json` requirement metadata; does not trigger installation. */
|
|
227
|
+
requires?: PluginDependency;
|
|
226
228
|
dependencies?: {
|
|
227
229
|
widgets?: string[];
|
|
228
230
|
plugins?: string[];
|
|
@@ -328,6 +330,7 @@ export function parsePluginManifest(
|
|
|
328
330
|
? raw.capabilities
|
|
329
331
|
: [...parseCapabilities(raw.capabilities), ...parseCapabilities(extension.capabilities)]);
|
|
330
332
|
const dependencies = parseDependencies(raw.dependencies);
|
|
333
|
+
const requires = parsePluginRequires(raw.requires === undefined ? extension.requires : raw.requires);
|
|
331
334
|
const description = typeof raw.description === 'string' ? raw.description : undefined;
|
|
332
335
|
const allowMultiActive = typeof raw.allowMultiActive === 'boolean' ? raw.allowMultiActive : undefined;
|
|
333
336
|
const activePeerCompat = parseActivePeerCompat(raw.activePeerCompat);
|
|
@@ -341,6 +344,7 @@ export function parsePluginManifest(
|
|
|
341
344
|
activationEvents,
|
|
342
345
|
contributes,
|
|
343
346
|
capabilities,
|
|
347
|
+
...(requires ? { requires } : {}),
|
|
344
348
|
...(dependencies ? { dependencies } : {}),
|
|
345
349
|
...(allowMultiActive !== undefined ? { allowMultiActive } : {}),
|
|
346
350
|
...(activePeerCompat ? { activePeerCompat } : {}),
|
|
@@ -354,7 +358,7 @@ function objectOrEmpty(value: unknown, label: string): Record<string, unknown> {
|
|
|
354
358
|
return value as Record<string, unknown>;
|
|
355
359
|
}
|
|
356
360
|
|
|
357
|
-
function parseElanousExtension(value: unknown): { contributes: Record<string, unknown>; capabilities?: unknown } {
|
|
361
|
+
function parseElanousExtension(value: unknown): { contributes: Record<string, unknown>; capabilities?: unknown; requires?: unknown } {
|
|
358
362
|
const extensions = objectOrEmpty(value, 'extensions');
|
|
359
363
|
const extension = objectOrEmpty(extensions['ai.elanous'], 'extensions["ai.elanous"]');
|
|
360
364
|
const contributes = objectOrEmpty(extension.contributes, 'extensions["ai.elanous"].contributes');
|
|
@@ -365,6 +369,7 @@ function parseElanousExtension(value: unknown): { contributes: Record<string, un
|
|
|
365
369
|
.map(key => [key, extension[key]])),
|
|
366
370
|
},
|
|
367
371
|
capabilities: extension.capabilities,
|
|
372
|
+
requires: extension.requires,
|
|
368
373
|
};
|
|
369
374
|
}
|
|
370
375
|
|
|
@@ -1117,6 +1122,18 @@ function parseCapabilities(value: unknown): PluginCapability[] {
|
|
|
1117
1122
|
});
|
|
1118
1123
|
}
|
|
1119
1124
|
|
|
1125
|
+
function parsePluginRequires(value: unknown): PluginDependency | undefined {
|
|
1126
|
+
if (value === undefined) return undefined;
|
|
1127
|
+
const raw = objectOrEmpty(value, 'requires');
|
|
1128
|
+
return {
|
|
1129
|
+
...(raw.elanous !== undefined ? { elanous: stringOr(raw.elanous) } : {}),
|
|
1130
|
+
...(raw.tools !== undefined ? { tools: stringArrayOr(raw.tools, []) } : {}),
|
|
1131
|
+
...(raw.optionalTools !== undefined ? { optionalTools: stringArrayOr(raw.optionalTools, []) } : {}),
|
|
1132
|
+
...(raw.optionalPython !== undefined ? { optionalPython: stringArrayOr(raw.optionalPython, []) } : {}),
|
|
1133
|
+
...(raw.knowledgePacks !== undefined ? { knowledgePacks: stringArrayOr(raw.knowledgePacks, []) } : {}),
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1120
1137
|
function parseDependencies(value: unknown): PluginManifest['dependencies'] | undefined {
|
|
1121
1138
|
if (value === undefined) return undefined;
|
|
1122
1139
|
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('dependencies must be an object');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { DATA_DIR } from '../../config.js';
|
|
4
|
+
import type { PluginSecurityDecision } from './capability-policy.js';
|
|
4
5
|
|
|
5
6
|
export type PluginTrustScope = 'user' | 'workspace';
|
|
6
7
|
|
|
@@ -16,6 +17,20 @@ interface PluginTrustFile {
|
|
|
16
17
|
records: PluginTrustRecord[];
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
/** Ephemeral installation decision; never persisted as a trust record or a credential. */
|
|
21
|
+
export function decidePluginInstallation(security: PluginSecurityDecision, capabilities: readonly string[], consent: boolean):
|
|
22
|
+
{ ok: true } | { ok: false; reason: 'scan' | 'consent-denied' } {
|
|
23
|
+
if (security.scan === 'dangerous') return { ok: false, reason: 'scan' };
|
|
24
|
+
if (capabilities.length > 0 && !consent) return { ok: false, reason: 'consent-denied' };
|
|
25
|
+
return { ok: true };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Hooks default off for installed (imported/generated) plugins: there is no approval path yet, so none run.
|
|
29
|
+
* Built-in and user-dir plugins keep their declared hooks unchanged. */
|
|
30
|
+
export function enabledPluginHooks<T>(hooks: readonly T[], source: string): T[] {
|
|
31
|
+
return source === 'installed' ? [] : [...hooks];
|
|
32
|
+
}
|
|
33
|
+
|
|
19
34
|
export class PluginTrustStore {
|
|
20
35
|
constructor(private readonly path = defaultPluginTrustPath()) {}
|
|
21
36
|
|
|
@@ -26,6 +26,15 @@ import type {
|
|
|
26
26
|
|
|
27
27
|
export type PaneSlot = 'skills' | 'files' | 'preview' | 'log' | 'hud';
|
|
28
28
|
|
|
29
|
+
/** Requirements declared by a plugin.json `requires` block. This is metadata, not an install request. */
|
|
30
|
+
export interface PluginDependency {
|
|
31
|
+
elanous?: string;
|
|
32
|
+
tools?: string[];
|
|
33
|
+
optionalTools?: string[];
|
|
34
|
+
optionalPython?: string[];
|
|
35
|
+
knowledgePacks?: string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
export interface DashboardPaneSummary {
|
|
30
39
|
pane: string;
|
|
31
40
|
visible: boolean;
|
|
@@ -327,6 +336,9 @@ export interface ElanousPlugin<S = unknown> {
|
|
|
327
336
|
slashCommands?: SlashCommand[];
|
|
328
337
|
keybindings?: Keybinding[];
|
|
329
338
|
llmTools?: LLMToolDef[];
|
|
339
|
+
/** Host registers only adapters also declared in contributes.connectors;
|
|
340
|
+
* registration is disposed with this plugin activation. */
|
|
341
|
+
channelAdapters?: import('../../nexus/outbound/router.js').ChannelAdapter[];
|
|
330
342
|
onActivate?(ctx: PluginContext): void | Promise<void>;
|
|
331
343
|
onDeactivate?(ctx: PluginContext): void | Promise<void>;
|
|
332
344
|
/** Plugin is executing a long-running op — host blocks input while true.
|
|
@@ -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»).
|