superacli 1.1.22 → 1.1.26
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/.beads/.br_history/{issues.20260427_104638_898729442.jsonl → issues.20260427_114912_061702372.jsonl} +65 -65
- package/.beads/.br_history/{issues.20260427_104638_209211116.jsonl → issues.20260427_115013_063113906.jsonl} +66 -66
- package/.beads/.br_history/{issues.20260427_104637_752744777.jsonl → issues.20260427_115114_208497343.jsonl} +67 -67
- package/.beads/.br_history/{issues.20260427_104615_669652069.jsonl → issues.20260427_115215_176080241.jsonl} +68 -68
- package/.beads/.br_history/issues.20260427_115316_481573328.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_115335_866978652.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_115436_866087391.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_115538_016094860.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_115638_932947449.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_115739_982932603.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_115840_963681039.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_115941_912431509.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_120043_043356448.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_120144_955596968.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_120246_060733977.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_120307_717985017.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_120408_871846736.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_121003_963750732.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_121006_018509431.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_121019_617062931.jsonl +261 -0
- package/.beads/.br_history/issues.20260427_121021_689536311.jsonl +261 -0
- package/.beads/.br_history/issues.20260428_172005_240631447.jsonl +261 -0
- package/.beads/.br_history/issues.20260430_073641_144807989.jsonl +262 -0
- package/.beads/.br_history/issues.20260430_073642_807075699.jsonl +263 -0
- package/.beads/.br_history/issues.20260430_073645_625754223.jsonl +264 -0
- package/.beads/.br_history/issues.20260430_090639_154646058.jsonl +265 -0
- package/.beads/.br_history/issues.20260430_090640_350560318.jsonl +266 -0
- package/.beads/.br_history/issues.20260430_090641_509319001.jsonl +267 -0
- package/.beads/.br_history/issues.20260430_095140_396749398.jsonl +268 -0
- package/.beads/.br_history/issues.20260501_230041_334056077.jsonl +269 -0
- package/.beads/.br_recovery/beads.db-wal.20260427_121006_010373120.rebuild-failed +0 -0
- package/.beads/.br_recovery/beads.db.20260427_121006_010373120.rebuild-failed +0 -0
- package/.beads/beads.db.corrupted +0 -0
- package/.beads/issues.jsonl +46 -37
- package/.supercli/adapters/test-cli-adapter.js +19 -0
- package/cli/adapters/mcp.js +89 -3
- package/cli/adapters/openapi.js +71 -2
- package/cli/config.js +69 -1
- package/cli/daemon.js +349 -0
- package/cli/plugins-manager.js +41 -1
- package/cli/server-command.js +174 -4
- package/cli/supercli.js +35 -15
- package/docs/changelog-2026-04.html +6 -0
- package/docs/index.html +95 -8
- package/docs/plugins.html +30 -0
- package/docs/server.md +80 -0
- package/graphify-out/GRAPH_REPORT.md +140 -128
- package/graphify-out/cache/036077d325d5aa25fc6ad7f01ca32721b02e3f981231f67fb22f59380063572b.json +1 -0
- package/graphify-out/cache/11938479cfbdb8e52bf5f0f3c132d56204245ebb19aefe89bb0394feb36dbd5e.json +1 -0
- package/graphify-out/cache/141362b25039dee7a4959ef475befea0a25671aae66f3d14917e711e597ffbf6.json +1 -0
- package/graphify-out/cache/362adb1b6b483f56d09feaf652f4122366e568aaede752f48383b76d61f5d9d6.json +1 -0
- package/graphify-out/cache/42bc8f64d69d2cd9ecf64e92e38f89f7ea479f69c947de5984919e2fd5a716ee.json +1 -0
- package/graphify-out/cache/4b5cffce31d9193b7d0a8f15e8a41c66f6733a6490ebaeff2c8ca19701c72c0e.json +1 -0
- package/graphify-out/cache/5262fb95a8855fc90efbfff767eb3aacca82c4da5799605a969554580a255404.json +1 -0
- package/graphify-out/cache/5ef4e31750d9e7bc4ff4a7b535f247d9ab5ab9627d72e20794779ec4be424c66.json +1 -0
- package/graphify-out/cache/68e2b11c95ede4f05b88d001040008cb3ac72d7bd27f351497c87e128fb3b221.json +1 -0
- package/graphify-out/cache/6d5023ecffa52382d31152c8c06e86e286789228a3d4f7fde72087f3eafa11bc.json +1 -0
- package/graphify-out/cache/6e5776e123142a78f50fa0bfd5ae2d289282051a9b392ae507de7aa9017f95d4.json +1 -0
- package/graphify-out/cache/75982dc60fa7353600ca48a3b33f5ba497eea9d5743daac6e61e9cf4f64774be.json +1 -0
- package/graphify-out/cache/7796066b51d3a99071debdfb5f40c854400b5bf3aa7c1e83dd6ae88eddca0370.json +1 -0
- package/graphify-out/cache/8308aa47b396b929d5b896051ca91422afdde4861108d6f18f5094901093df79.json +1 -0
- package/graphify-out/cache/8ccd3b557a1ea98005fba84433f160ccd4a951fbdb6a4c9b7d7ba894f905b06b.json +1 -0
- package/graphify-out/cache/90ab53b8f1f3306e7c3a1f92ec628717ea90f4e684db764f7d7aa8e884fe2cae.json +1 -0
- package/graphify-out/cache/9832101a7622924f58b9e7d7752b41518049447171f7955e4c50dfd386574e12.json +1 -0
- package/graphify-out/cache/9fa6604cc820f3857c55c753ca0024788e4cbb61c4e12ba7ce0e4a1ce4ee0655.json +1 -0
- package/graphify-out/cache/a1e24a07beede2876e688cdb6c14e2d24abb22064862a6420cac321efabd3efd.json +1 -0
- package/graphify-out/cache/a418312f2805259c33007a18b36b6ae3b6a4da376ccae6006a3b9999262495db.json +1 -0
- package/graphify-out/cache/a6d9c029bd31a99b67357291305e27b01c5ef388925f7f2a6e985fec4efa8024.json +1 -0
- package/graphify-out/cache/a6ed52b709dd79f98adf72c483e8dfb6098203d7327470b82feb5e11390a5cf4.json +1 -0
- package/graphify-out/cache/b045ae4443d972ee8f47b91a0d61c984a190195b38ae1d331430b4c51c43acfd.json +1 -0
- package/graphify-out/cache/b849fb88344c2f88f3d22e42b67516e071c7d1e65f77f4ca23f25af6edfca3b3.json +1 -0
- package/graphify-out/cache/bc514f4074f89d2f7e7834670602e50bba0f24b8cd8c9d21ff4d361d3fd4d558.json +1 -0
- package/graphify-out/cache/be3fc87936f9f24d2d4f4b22b9d2a16f33f538cef1a181663120e23ecf16b81a.json +1 -0
- package/graphify-out/cache/c5a4822edbe3a95a56f9f943eed1567e5a5c913d59b1fa3df4ad54ffd9b02697.json +1 -0
- package/graphify-out/cache/cf411f1ddde50ee97c1c501f59ed7985bcdc022134574816bcce37ac20848e64.json +1 -0
- package/graphify-out/cache/d88625b5813742ca941ce8155cb77afb02425632002f621aca34f217440a392d.json +1 -0
- package/graphify-out/cache/da97fdc8af2a3306c292921110f84648bba2b0e85d27473b460b0e8a862ff225.json +1 -0
- package/graphify-out/cache/e88de9f1ae117f26fd217c3717eff7e525a284cc942b5f4d26ef2c4d65db59bd.json +1 -0
- package/graphify-out/cache/ebf6bd96ef2d8d396389ac7199e6ba818ee2d0c5dfc131fab7cdece9fb710f11.json +1 -0
- package/graphify-out/cache/f2a302550a6fe0649d36b8ef0b04b77673bca9f115732af8ae89751944dc9cc6.json +1 -0
- package/graphify-out/cache/f9ee11f4395cb41b6f6900079cb7e94297c89b1b0b4798398d2f7a2e244c683b.json +1 -0
- package/graphify-out/cache/fb46bd3ef530273918fc8915842453f21b418d536653d3b705b75b417255c246.json +1 -0
- package/graphify-out/cache/fcfdab94fe91af1f21fcefdba5a96674b9a16bb768288f3573fe68765163c765.json +1 -0
- package/graphify-out/graph.json +2420 -1157
- package/package.json +1 -1
- package/plugins/bluebuild/install-guidance.json +11 -0
- package/plugins/bluebuild/meta.json +5 -0
- package/plugins/bluebuild/plugin.json +99 -0
- package/plugins/bluebuild/skills/quickstart/SKILL.md +47 -0
- package/plugins/cargo-public-api/install-guidance.json +11 -0
- package/plugins/cargo-public-api/meta.json +5 -0
- package/plugins/cargo-public-api/plugin.json +88 -0
- package/plugins/cargo-public-api/skills/quickstart/SKILL.md +51 -0
- package/plugins/context-mode/plugin.json +10 -0
- package/plugins/context-mode/scripts/post-install.js +1 -1
- package/plugins/csview/install-guidance.json +11 -0
- package/plugins/csview/meta.json +5 -0
- package/plugins/csview/plugin.json +67 -0
- package/plugins/csview/skills/quickstart/SKILL.md +51 -0
- package/plugins/cymbal/install-guidance.json +11 -0
- package/plugins/cymbal/meta.json +5 -0
- package/plugins/cymbal/plugin.json +121 -0
- package/plugins/cymbal/skills/quickstart/SKILL.md +54 -0
- package/plugins/difftastic/install-guidance.json +11 -0
- package/plugins/difftastic/meta.json +5 -0
- package/plugins/difftastic/plugin.json +87 -0
- package/plugins/difftastic/skills/quickstart/SKILL.md +53 -0
- package/plugins/dlm/install-guidance.json +11 -0
- package/plugins/dlm/meta.json +5 -0
- package/plugins/dlm/plugin.json +85 -0
- package/plugins/dlm/skills/quickstart/SKILL.md +49 -0
- package/plugins/dofigen/install-guidance.json +11 -0
- package/plugins/dofigen/meta.json +5 -0
- package/plugins/dofigen/plugin.json +84 -0
- package/plugins/dofigen/skills/quickstart/SKILL.md +50 -0
- package/plugins/example-server-resources/meta.json +11 -0
- package/plugins/example-server-resources/plugin.json +46 -0
- package/plugins/http-nu/install-guidance.json +11 -0
- package/plugins/http-nu/meta.json +5 -0
- package/plugins/http-nu/plugin.json +84 -0
- package/plugins/http-nu/skills/quickstart/SKILL.md +52 -0
- package/plugins/hwatch/install-guidance.json +11 -0
- package/plugins/hwatch/meta.json +5 -0
- package/plugins/hwatch/plugin.json +100 -0
- package/plugins/hwatch/skills/quickstart/SKILL.md +54 -0
- package/plugins/hyperfine/install-guidance.json +3 -3
- package/plugins/hyperfine/meta.json +2 -2
- package/plugins/hyperfine/plugin.json +39 -16
- package/plugins/hyperfine/skills/quickstart/SKILL.md +33 -61
- package/plugins/json5/install-guidance.json +12 -0
- package/plugins/json5/meta.json +5 -0
- package/plugins/json5/plugin.json +88 -0
- package/plugins/json5/skills/quickstart/SKILL.md +55 -0
- package/plugins/mdsf/install-guidance.json +11 -0
- package/plugins/mdsf/meta.json +5 -0
- package/plugins/mdsf/plugin.json +101 -0
- package/plugins/mdsf/skills/quickstart/SKILL.md +55 -0
- package/plugins/oha/install-guidance.json +11 -0
- package/plugins/oha/meta.json +5 -0
- package/plugins/oha/plugin.json +67 -0
- package/plugins/oha/skills/quickstart/SKILL.md +44 -0
- package/plugins/pv-migrate/install-guidance.json +11 -0
- package/plugins/pv-migrate/meta.json +5 -0
- package/plugins/pv-migrate/plugin.json +102 -0
- package/plugins/pv-migrate/skills/quickstart/SKILL.md +58 -0
- package/plugins/rash/install-guidance.json +11 -0
- package/plugins/rash/meta.json +5 -0
- package/plugins/rash/plugin.json +85 -0
- package/plugins/rash/skills/quickstart/SKILL.md +46 -0
- package/plugins/rsonpath/install-guidance.json +11 -0
- package/plugins/rsonpath/meta.json +5 -0
- package/plugins/rsonpath/plugin.json +87 -0
- package/plugins/rsonpath/skills/quickstart/SKILL.md +44 -0
- package/plugins/rsql/install-guidance.json +11 -0
- package/plugins/rsql/meta.json +5 -0
- package/plugins/rsql/plugin.json +84 -0
- package/plugins/rsql/skills/quickstart/SKILL.md +52 -0
- package/plugins/temporal/install-guidance.json +11 -0
- package/plugins/temporal/meta.json +5 -0
- package/plugins/temporal/plugin.json +95 -0
- package/plugins/temporal/skills/quickstart/SKILL.md +49 -0
- package/plugins/tkn/install-guidance.json +11 -0
- package/plugins/tkn/meta.json +5 -0
- package/plugins/tkn/plugin.json +98 -0
- package/plugins/tkn/skills/quickstart/SKILL.md +50 -0
- package/plugins/toml2json/install-guidance.json +11 -0
- package/plugins/toml2json/meta.json +5 -0
- package/plugins/toml2json/plugin.json +85 -0
- package/plugins/toml2json/skills/quickstart/SKILL.md +47 -0
- package/plugins/worktrunk/install-guidance.json +11 -0
- package/plugins/worktrunk/meta.json +5 -0
- package/plugins/worktrunk/plugin.json +116 -0
- package/plugins/worktrunk/skills/quickstart/SKILL.md +62 -0
- package/server/app.js +46 -13
- package/server/middleware/auth.js +70 -0
- package/server/routes/adapters.js +3 -11
- package/server/routes/clients.js +46 -0
- package/server/routes/docs.js +10 -0
- package/server/routes/jobs.js +3 -2
- package/server/routes/mcp.js +1 -0
- package/server/routes/plugins.js +109 -26
- package/server/routes/settings.js +93 -0
- package/server/routes/specs.js +8 -3
- package/server/services/adaptersService.js +1 -0
- package/server/services/pluginResourceService.js +262 -0
- package/server/services/pluginsService.js +24 -0
- package/server/uploads/superbackend-openapi.json +47 -0
- package/server/uploads/test-auth-openapi.json +74 -0
- package/server/uploads/test-auth-spec.json +36 -0
- package/server/views/adapters.ejs +1 -0
- package/server/views/api-keys.ejs +147 -0
- package/server/views/clients.ejs +82 -0
- package/server/views/docs.ejs +7 -0
- package/server/views/jobs.ejs +26 -2
- package/server/views/layout.ejs +35 -21
- package/server/views/mcp.ejs +278 -21
- package/server/views/partials/head.ejs +4 -0
- package/server/views/plugins.ejs +33 -32
- package/server/views/settings.ejs +99 -0
- package/server/views/specs.ejs +217 -22
- package/.beads/.br_history/issues.20260427_103259_082222986.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_103400_358332602.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_103419_681839669.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_103522_226669683.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_103623_568379011.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_103724_772051154.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_103825_935228905.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_103927_159626780.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104028_436388960.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104129_670562810.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104230_885162615.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104332_071213892.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104349_051129644.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104450_358444507.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104555_654123963.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104559_805009051.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104600_255068030.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104600_717042012.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104601_215845416.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104601_899140331.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104606_172300551.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104606_658098709.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104607_085798670.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104607_627598880.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104608_071298223.jsonl +0 -261
- package/.beads/.br_history/issues.20260427_104615_198124329.jsonl +0 -261
- package/scripts/post-tweet-issues.js +0 -161
- /package/.beads/.br_history/{issues.20260427_103259_082222986.jsonl.meta.json → issues.20260427_114912_061702372.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_103400_358332602.jsonl.meta.json → issues.20260427_115013_063113906.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_103419_681839669.jsonl.meta.json → issues.20260427_115114_208497343.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_103522_226669683.jsonl.meta.json → issues.20260427_115215_176080241.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_103623_568379011.jsonl.meta.json → issues.20260427_115316_481573328.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_103724_772051154.jsonl.meta.json → issues.20260427_115335_866978652.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_103825_935228905.jsonl.meta.json → issues.20260427_115436_866087391.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_103927_159626780.jsonl.meta.json → issues.20260427_115538_016094860.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104028_436388960.jsonl.meta.json → issues.20260427_115638_932947449.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104129_670562810.jsonl.meta.json → issues.20260427_115739_982932603.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104230_885162615.jsonl.meta.json → issues.20260427_115840_963681039.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104332_071213892.jsonl.meta.json → issues.20260427_115941_912431509.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104349_051129644.jsonl.meta.json → issues.20260427_120043_043356448.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104450_358444507.jsonl.meta.json → issues.20260427_120144_955596968.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104555_654123963.jsonl.meta.json → issues.20260427_120246_060733977.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104559_805009051.jsonl.meta.json → issues.20260427_120307_717985017.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104600_255068030.jsonl.meta.json → issues.20260427_120408_871846736.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104600_717042012.jsonl.meta.json → issues.20260427_121003_963750732.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104601_215845416.jsonl.meta.json → issues.20260427_121006_018509431.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104601_899140331.jsonl.meta.json → issues.20260427_121019_617062931.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104606_172300551.jsonl.meta.json → issues.20260427_121021_689536311.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104606_658098709.jsonl.meta.json → issues.20260428_172005_240631447.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104607_085798670.jsonl.meta.json → issues.20260430_073641_144807989.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104607_627598880.jsonl.meta.json → issues.20260430_073642_807075699.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104608_071298223.jsonl.meta.json → issues.20260430_073645_625754223.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104615_198124329.jsonl.meta.json → issues.20260430_090639_154646058.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104615_669652069.jsonl.meta.json → issues.20260430_090640_350560318.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104637_752744777.jsonl.meta.json → issues.20260430_090641_509319001.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104638_209211116.jsonl.meta.json → issues.20260430_095140_396749398.jsonl.meta.json} +0 -0
- /package/.beads/.br_history/{issues.20260427_104638_898729442.jsonl.meta.json → issues.20260501_230041_334056077.jsonl.meta.json} +0 -0
package/server/views/mcp.ejs
CHANGED
|
@@ -9,30 +9,62 @@
|
|
|
9
9
|
<button @click="showForm=!showForm" class="btn btn-primary">+ Add Server</button>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
12
|
-
<!-- Add form -->
|
|
12
|
+
<!-- Add/Edit form -->
|
|
13
13
|
<div v-if="showForm" class="bento-card p-6 mb-6">
|
|
14
|
-
<form @submit.prevent="create">
|
|
14
|
+
<form @submit.prevent="editing ? update() : create()">
|
|
15
15
|
<div class="flex flex-col md:flex-row gap-4 items-end mb-4">
|
|
16
16
|
<div class="flex-1 w-full">
|
|
17
17
|
<label class="block text-xs font-semibold text-[#787774] uppercase tracking-wider mb-2">Name</label>
|
|
18
18
|
<input v-model="form.name" class="w-full px-4 py-3 bg-[#F7F6F3] border border-[#EAEAEA] rounded-md text-[#111111] focus:outline-none focus:border-[#111111] transition-colors" required placeholder="e.g. context-mode">
|
|
19
19
|
</div>
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="mb-4">
|
|
23
|
+
<label class="block text-xs font-semibold text-[#787774] uppercase tracking-wider mb-3">Transport Mode</label>
|
|
24
|
+
<div class="flex gap-6">
|
|
25
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
26
|
+
<input type="radio" v-model="form.transport" value="http" class="w-4 h-4 accent-[#111111]">
|
|
27
|
+
<span class="text-sm text-[#2F3437]">SSE/HTTP</span>
|
|
28
|
+
</label>
|
|
29
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
30
|
+
<input type="radio" v-model="form.transport" value="stdio" class="w-4 h-4 accent-[#111111]">
|
|
31
|
+
<span class="text-sm text-[#2F3437]">STDIO</span>
|
|
32
|
+
</label>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<!-- SSE/HTTP fields -->
|
|
37
|
+
<div v-if="form.transport === 'http'" class="space-y-4">
|
|
38
|
+
<div>
|
|
39
|
+
<label class="block text-xs font-semibold text-[#787774] uppercase tracking-wider mb-2">URL</label>
|
|
22
40
|
<input v-model="form.url" class="w-full px-4 py-3 bg-[#F7F6F3] border border-[#EAEAEA] rounded-md text-[#111111] focus:outline-none focus:border-[#111111] transition-colors" placeholder="https://mcp.example.com">
|
|
41
|
+
<p class="text-xs text-[#787774] mt-1">Uses SSE with HTTP fallback</p>
|
|
23
42
|
</div>
|
|
24
|
-
<div
|
|
25
|
-
<label class="block text-xs font-semibold text-[#787774] uppercase tracking-wider mb-2">
|
|
26
|
-
<input v-model="form.
|
|
43
|
+
<div>
|
|
44
|
+
<label class="block text-xs font-semibold text-[#787774] uppercase tracking-wider mb-2">Timeout (ms)</label>
|
|
45
|
+
<input v-model="form.timeout_ms" type="number" class="w-full px-4 py-3 bg-[#F7F6F3] border border-[#EAEAEA] rounded-md text-[#111111] focus:outline-none focus:border-[#111111] transition-colors" placeholder="30000">
|
|
46
|
+
<p class="text-xs text-[#787774] mt-1">Default: 30000ms (30 seconds)</p>
|
|
27
47
|
</div>
|
|
28
48
|
</div>
|
|
29
|
-
|
|
49
|
+
|
|
50
|
+
<!-- STDIO fields -->
|
|
51
|
+
<div v-if="form.transport === 'stdio'" class="space-y-4">
|
|
52
|
+
<div>
|
|
53
|
+
<label class="block text-xs font-semibold text-[#787774] uppercase tracking-wider mb-2">Command</label>
|
|
54
|
+
<input v-model="form.command" class="w-full px-4 py-3 bg-[#F7F6F3] border border-[#EAEAEA] rounded-md text-[#111111] focus:outline-none focus:border-[#111111] transition-colors" placeholder="e.g. context-mode">
|
|
55
|
+
</div>
|
|
30
56
|
<label class="flex items-center gap-2 cursor-pointer">
|
|
31
57
|
<input type="checkbox" v-model="form.stateful" class="w-4 h-4 accent-[#111111]">
|
|
32
|
-
<
|
|
58
|
+
<div class="flex flex-col">
|
|
59
|
+
<span class="text-sm text-[#2F3437]">Stateful (requires daemon)</span>
|
|
60
|
+
<span class="text-xs text-[#787774]">Daemon runs on CLI side, starts when command is executed via CLI (not server)</span>
|
|
61
|
+
</div>
|
|
33
62
|
</label>
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div class="flex gap-4 items-center mt-4">
|
|
66
|
+
<button type="submit" class="btn btn-primary">{{ editing ? 'Update' : 'Save' }}</button>
|
|
67
|
+
<button type="button" @click="cancelEdit" class="btn">Cancel</button>
|
|
36
68
|
</div>
|
|
37
69
|
</form>
|
|
38
70
|
</div>
|
|
@@ -42,21 +74,45 @@
|
|
|
42
74
|
<thead>
|
|
43
75
|
<tr class="border-b border-[#EAEAEA] bg-[#F7F6F3]">
|
|
44
76
|
<th class="px-6 py-3 text-left text-xs font-semibold text-[#787774] uppercase tracking-wider">Name</th>
|
|
77
|
+
<th class="px-6 py-3 text-left text-xs font-semibold text-[#787774] uppercase tracking-wider">Plugin</th>
|
|
45
78
|
<th class="px-6 py-3 text-left text-xs font-semibold text-[#787774] uppercase tracking-wider">Source</th>
|
|
46
79
|
<th class="px-6 py-3 text-left text-xs font-semibold text-[#787774] uppercase tracking-wider">Type</th>
|
|
47
80
|
<th class="px-6 py-3 text-left text-xs font-semibold text-[#787774] uppercase tracking-wider">Actions</th>
|
|
48
81
|
</tr>
|
|
49
82
|
</thead>
|
|
50
83
|
<tbody>
|
|
51
|
-
<tr v-if="servers.length===0"><td colspan="
|
|
84
|
+
<tr v-if="servers.length===0"><td colspan="5" class="px-6 py-12 text-center text-[#787774]">No MCP servers registered.</td></tr>
|
|
52
85
|
<tr v-for="s in servers" :key="s._id" class="border-b border-[#EAEAEA] hover:bg-[#F7F6F3] transition-colors">
|
|
53
|
-
<td class="px-6 py-4"
|
|
86
|
+
<td class="px-6 py-4">
|
|
87
|
+
<code class="mono-text text-sm text-[#1F6C9F]">{{ s.displayName || s.name }}</code>
|
|
88
|
+
<div v-if="getUsedCommands(s).length > 0" class="mt-1 text-xs text-[#787774]">
|
|
89
|
+
used by: {{ getUsedCommands(s).map(c => `${c.namespace}.${c.resource}.${c.action}`).join(', ') }}
|
|
90
|
+
</div>
|
|
91
|
+
<div v-if="s.clientId" class="mt-1 text-xs text-[#787774]">
|
|
92
|
+
synced by: {{ s.clientId.substring(0, 8) }}...
|
|
93
|
+
</div>
|
|
94
|
+
</td>
|
|
95
|
+
<td class="px-6 py-4">
|
|
96
|
+
<span v-if="s.origin" class="px-2 py-1 rounded-full text-xs font-semibold" :class="{
|
|
97
|
+
'bg-blue-100 text-blue-700': s.origin === 'cli',
|
|
98
|
+
'bg-green-100 text-green-700': s.origin === 'server',
|
|
99
|
+
'bg-gray-100 text-gray-700': s.origin === 'manual'
|
|
100
|
+
}">{{ s.origin }}</span>
|
|
101
|
+
<span v-else class="text-xs text-[#787774]">manual</span>
|
|
102
|
+
</td>
|
|
54
103
|
<td class="px-6 py-4 max-w-xs truncate text-[#2F3437]">{{ s.url || s.command || '' }}</td>
|
|
55
104
|
<td class="px-6 py-4">
|
|
56
105
|
<span v-if="s.stateful" class="badge bg-[#111111] text-white">stateful</span>
|
|
57
|
-
<span v-else class="badge">{{ s.url ? 'http' : 'stdio' }}</span>
|
|
106
|
+
<span v-else class="badge">{{ s.url ? 'sse/http' : 'stdio' }}</span>
|
|
107
|
+
<span v-if="s.url && s.status" class="ml-2 text-xs" :class="{'text-green-600': s.status === 'alive', 'text-red-600': s.status === 'error'}">
|
|
108
|
+
{{ s.status === 'alive' ? '✓' : '✗' }} {{ s.lastCheck }}
|
|
109
|
+
</span>
|
|
58
110
|
</td>
|
|
59
111
|
<td class="px-6 py-4">
|
|
112
|
+
<button v-if="s.url" @click="check(s)" :disabled="s.checking" class="btn text-xs border-green-200 text-green-600 hover:bg-green-50 hover:border-green-300 mr-2" :class="{'opacity-50': s.checking}">
|
|
113
|
+
{{ s.checking ? 'Checking...' : 'Check' }}
|
|
114
|
+
</button>
|
|
115
|
+
<button @click="edit(s)" class="btn text-xs border-blue-200 text-blue-600 hover:bg-blue-50 hover:border-blue-300 mr-2">Edit</button>
|
|
60
116
|
<button @click="remove(s._id)" class="btn text-xs border-red-200 text-red-600 hover:bg-red-50 hover:border-red-300">Delete</button>
|
|
61
117
|
</td>
|
|
62
118
|
</tr>
|
|
@@ -72,16 +128,84 @@
|
|
|
72
128
|
data() {
|
|
73
129
|
return {
|
|
74
130
|
servers: initialServers,
|
|
131
|
+
commands: [],
|
|
75
132
|
showForm: false,
|
|
76
|
-
|
|
133
|
+
editing: false,
|
|
134
|
+
editId: null,
|
|
135
|
+
form: { name: '', transport: 'http', url: '', timeout_ms: 30000, command: '', stateful: false },
|
|
136
|
+
autoCheckInterval: null
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
mounted() {
|
|
140
|
+
// Start auto-check every minute for HTTP/SSE servers
|
|
141
|
+
this.autoCheckInterval = setInterval(() => {
|
|
142
|
+
this.autoCheck()
|
|
143
|
+
}, 60000)
|
|
144
|
+
|
|
145
|
+
// Fetch commands
|
|
146
|
+
this.fetchCommands()
|
|
147
|
+
|
|
148
|
+
// Refresh commands every 30 seconds
|
|
149
|
+
setInterval(() => {
|
|
150
|
+
this.fetchCommands()
|
|
151
|
+
}, 30000)
|
|
152
|
+
},
|
|
153
|
+
beforeUnmount() {
|
|
154
|
+
if (this.autoCheckInterval) {
|
|
155
|
+
clearInterval(this.autoCheckInterval)
|
|
77
156
|
}
|
|
78
157
|
},
|
|
79
158
|
methods: {
|
|
159
|
+
async fetchCommands() {
|
|
160
|
+
try {
|
|
161
|
+
const res = await fetch('/api/commands?format=json')
|
|
162
|
+
const data = await res.json()
|
|
163
|
+
this.commands = data.commands || data || []
|
|
164
|
+
} catch (err) {
|
|
165
|
+
console.error('Failed to fetch commands:', err)
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
getUsedCommands(server) {
|
|
169
|
+
// Find commands that use this MCP server
|
|
170
|
+
return this.commands.filter(cmd => {
|
|
171
|
+
const adapterConfig = cmd.adapterConfig || {}
|
|
172
|
+
// Match by server name (for stdio) or URL (for HTTP)
|
|
173
|
+
if (server.url) {
|
|
174
|
+
return adapterConfig.url === server.url
|
|
175
|
+
} else {
|
|
176
|
+
return adapterConfig.server === server.name
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
},
|
|
180
|
+
edit(server) {
|
|
181
|
+
this.editing = true
|
|
182
|
+
this.editId = server._id
|
|
183
|
+
this.form = {
|
|
184
|
+
name: server.name,
|
|
185
|
+
transport: server.url ? 'http' : 'stdio',
|
|
186
|
+
url: server.url || '',
|
|
187
|
+
timeout_ms: server.timeout_ms || 30000,
|
|
188
|
+
command: server.command || '',
|
|
189
|
+
stateful: server.stateful || false
|
|
190
|
+
}
|
|
191
|
+
this.showForm = true
|
|
192
|
+
},
|
|
193
|
+
cancelEdit() {
|
|
194
|
+
this.editing = false
|
|
195
|
+
this.editId = null
|
|
196
|
+
this.form = { name: '', transport: 'http', url: '', timeout_ms: 30000, command: '', stateful: false }
|
|
197
|
+
this.showForm = false
|
|
198
|
+
},
|
|
80
199
|
async create() {
|
|
81
200
|
const payload = { name: this.form.name }
|
|
82
|
-
if (this.form.
|
|
83
|
-
|
|
84
|
-
|
|
201
|
+
if (this.form.transport === 'http') {
|
|
202
|
+
payload.url = this.form.url
|
|
203
|
+
if (this.form.timeout_ms) payload.timeout_ms = parseInt(this.form.timeout_ms)
|
|
204
|
+
}
|
|
205
|
+
if (this.form.transport === 'stdio') {
|
|
206
|
+
payload.command = this.form.command
|
|
207
|
+
if (this.form.stateful) payload.stateful = true
|
|
208
|
+
}
|
|
85
209
|
const r = await fetch('/api/mcp', {
|
|
86
210
|
method: 'POST',
|
|
87
211
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -89,14 +213,147 @@
|
|
|
89
213
|
})
|
|
90
214
|
const doc = await r.json()
|
|
91
215
|
this.servers.push(doc)
|
|
92
|
-
this.
|
|
93
|
-
this.
|
|
216
|
+
this.cancelEdit()
|
|
217
|
+
await this.fetchCommands()
|
|
218
|
+
},
|
|
219
|
+
async update() {
|
|
220
|
+
const payload = { name: this.form.name }
|
|
221
|
+
if (this.form.transport === 'http') {
|
|
222
|
+
payload.url = this.form.url
|
|
223
|
+
if (this.form.timeout_ms) payload.timeout_ms = parseInt(this.form.timeout_ms)
|
|
224
|
+
}
|
|
225
|
+
if (this.form.transport === 'stdio') {
|
|
226
|
+
payload.command = this.form.command
|
|
227
|
+
if (this.form.stateful) payload.stateful = true
|
|
228
|
+
}
|
|
229
|
+
const r = await fetch('/api/mcp/' + this.editId, {
|
|
230
|
+
method: 'PUT',
|
|
231
|
+
headers: { 'Content-Type': 'application/json' },
|
|
232
|
+
body: JSON.stringify(payload)
|
|
233
|
+
})
|
|
234
|
+
const doc = await r.json()
|
|
235
|
+
const idx = this.servers.findIndex(s => s._id === this.editId)
|
|
236
|
+
if (idx !== -1) this.servers[idx] = { ...this.servers[idx], ...payload, updatedAt: new Date() }
|
|
237
|
+
this.cancelEdit()
|
|
238
|
+
await this.fetchCommands()
|
|
239
|
+
},
|
|
240
|
+
async check(server) {
|
|
241
|
+
server.checking = true
|
|
242
|
+
let sessionId = null
|
|
243
|
+
try {
|
|
244
|
+
const timeout = server.timeout_ms || 10000
|
|
245
|
+
const controller = new AbortController()
|
|
246
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
|
247
|
+
|
|
248
|
+
// Try different endpoints
|
|
249
|
+
const endpoints = ['/mcp', '/tool', '/sse']
|
|
250
|
+
let response = null
|
|
251
|
+
|
|
252
|
+
// First try without session (stateless)
|
|
253
|
+
for (const endpoint of endpoints) {
|
|
254
|
+
try {
|
|
255
|
+
response = await fetch(server.url + endpoint, {
|
|
256
|
+
method: 'POST',
|
|
257
|
+
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream' },
|
|
258
|
+
body: JSON.stringify({ jsonrpc: '2.0', method: 'tools/list', id: 1 }),
|
|
259
|
+
signal: controller.signal
|
|
260
|
+
})
|
|
261
|
+
// Accept any response that returns data (SSE might not be 200)
|
|
262
|
+
if (response.status >= 200 && response.status < 500) break
|
|
263
|
+
} catch (e) {
|
|
264
|
+
// Try next endpoint
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// If stateless check failed with session error, try with session
|
|
269
|
+
if (!response || response.status >= 500) {
|
|
270
|
+
// Try to create a session
|
|
271
|
+
for (const endpoint of endpoints) {
|
|
272
|
+
try {
|
|
273
|
+
const sessionRes = await fetch(server.url + endpoint, {
|
|
274
|
+
method: 'POST',
|
|
275
|
+
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream' },
|
|
276
|
+
body: JSON.stringify({ jsonrpc: '2.0', method: 'initialize', id: 1 }),
|
|
277
|
+
signal: controller.signal
|
|
278
|
+
})
|
|
279
|
+
if (sessionRes.status >= 200 && sessionRes.status < 500) {
|
|
280
|
+
const text = await sessionRes.text()
|
|
281
|
+
// Extract session ID from response
|
|
282
|
+
const match = text.match(/id:\s*([^\s_]+)/)
|
|
283
|
+
if (match) {
|
|
284
|
+
sessionId = match[1]
|
|
285
|
+
break
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
} catch (e) {
|
|
289
|
+
// Try next endpoint
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// If we got a session, try the check with it
|
|
294
|
+
if (sessionId) {
|
|
295
|
+
for (const endpoint of endpoints) {
|
|
296
|
+
try {
|
|
297
|
+
response = await fetch(server.url + endpoint, {
|
|
298
|
+
method: 'POST',
|
|
299
|
+
headers: {
|
|
300
|
+
'Content-Type': 'application/json',
|
|
301
|
+
'Accept': 'application/json, text/event-stream',
|
|
302
|
+
'X-MCP-Session-Id': sessionId
|
|
303
|
+
},
|
|
304
|
+
body: JSON.stringify({ jsonrpc: '2.0', method: 'tools/list', id: 1 }),
|
|
305
|
+
signal: controller.signal
|
|
306
|
+
})
|
|
307
|
+
if (response.status >= 200 && response.status < 500) break
|
|
308
|
+
} catch (e) {
|
|
309
|
+
// Try next endpoint
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
clearTimeout(timeoutId)
|
|
316
|
+
|
|
317
|
+
if (response && response.status >= 200 && response.status < 500) {
|
|
318
|
+
server.status = 'alive'
|
|
319
|
+
server.lastCheck = new Date().toLocaleTimeString()
|
|
320
|
+
} else {
|
|
321
|
+
server.status = 'error'
|
|
322
|
+
server.lastCheck = new Date().toLocaleTimeString()
|
|
323
|
+
}
|
|
324
|
+
} catch (err) {
|
|
325
|
+
server.status = 'error'
|
|
326
|
+
server.lastCheck = new Date().toLocaleTimeString()
|
|
327
|
+
} finally {
|
|
328
|
+
server.checking = false
|
|
329
|
+
// Clean up session if created
|
|
330
|
+
if (sessionId) {
|
|
331
|
+
try {
|
|
332
|
+
await fetch(server.url + '/mcp', {
|
|
333
|
+
method: 'POST',
|
|
334
|
+
headers: { 'Content-Type': 'application/json' },
|
|
335
|
+
body: JSON.stringify({ jsonrpc: '2.0', method: 'shutdown', id: 1 })
|
|
336
|
+
})
|
|
337
|
+
} catch (e) {
|
|
338
|
+
// Ignore cleanup errors
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
94
342
|
},
|
|
95
343
|
async remove(id) {
|
|
96
344
|
if (!confirm('Delete this server?')) return
|
|
97
345
|
await fetch('/api/mcp/' + id, { method: 'DELETE' })
|
|
98
346
|
this.servers = this.servers.filter(s => s._id !== id)
|
|
99
|
-
|
|
347
|
+
await this.fetchCommands()
|
|
348
|
+
},
|
|
349
|
+
autoCheck() {
|
|
350
|
+
// Check all HTTP/SSE servers that aren't already being checked
|
|
351
|
+
this.servers.forEach(server => {
|
|
352
|
+
if (server.url && !server.checking) {
|
|
353
|
+
this.check(server)
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
},
|
|
100
357
|
}
|
|
101
358
|
}).mount('#mcp-app')
|
|
102
359
|
</script>
|
|
@@ -98,7 +98,11 @@
|
|
|
98
98
|
<a href="/api/specs" class="btn justify-start" id="nav-specs">OpenAPI Specs</a>
|
|
99
99
|
<a href="/api/mcp" class="btn justify-start" id="nav-mcp">MCP Servers</a>
|
|
100
100
|
<a href="/api/plugins" class="btn justify-start" id="nav-plugins">Server Plugins</a>
|
|
101
|
+
<a href="/api/settings" class="btn justify-start" id="nav-settings">Settings</a>
|
|
102
|
+
<a href="/api/api-keys" class="btn justify-start" id="nav-api-keys">API Keys</a>
|
|
103
|
+
<a href="/api/clients" class="btn justify-start" id="nav-clients">Clients</a>
|
|
101
104
|
<a href="/api/jobs" class="btn justify-start" id="nav-jobs">Jobs</a>
|
|
105
|
+
<a href="/api/docs" class="btn justify-start" id="nav-docs">Documentation</a>
|
|
102
106
|
</aside>
|
|
103
107
|
<!-- Main content -->
|
|
104
108
|
<main class="flex-1 p-8 bg-[#FBFBFA]">
|
package/server/views/plugins.ejs
CHANGED
|
@@ -15,30 +15,8 @@
|
|
|
15
15
|
<span><strong>Admin Mode Enabled:</strong> CLI clients can modify server state without authentication. Disable when not needed.</span>
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
-
<div class="grid grid-cols-1 lg:grid-cols-
|
|
18
|
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-6">
|
|
19
19
|
<div class="card bg-base-100 border border-base-300">
|
|
20
|
-
<div class="card-body p-4">
|
|
21
|
-
<h2 class="card-title text-base">Settings</h2>
|
|
22
|
-
<label class="form-control mb-2">
|
|
23
|
-
<span class="label-text text-xs">Max ZIP Size (MB)</span>
|
|
24
|
-
<input v-model.number="settings.max_zip_mb" type="number" min="1" class="input input-bordered input-sm" />
|
|
25
|
-
</label>
|
|
26
|
-
<label class="form-control mb-3">
|
|
27
|
-
<span class="label-text text-xs">Default Hooks Policy</span>
|
|
28
|
-
<select v-model="settings.default_hooks_policy" class="select select-bordered select-sm">
|
|
29
|
-
<option value="deny">deny</option>
|
|
30
|
-
<option value="allow">allow</option>
|
|
31
|
-
</select>
|
|
32
|
-
</label>
|
|
33
|
-
<label class="label cursor-pointer justify-start gap-2 mb-3">
|
|
34
|
-
<input type="checkbox" v-model="settings.admin_mode_enabled" class="checkbox checkbox-error checkbox-sm" />
|
|
35
|
-
<span class="label-text text-xs text-error font-semibold">Admin Mode (allows CLI modifications)</span>
|
|
36
|
-
</label>
|
|
37
|
-
<button class="btn btn-sm btn-primary" @click="saveSettings">Save Settings</button>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<div class="card bg-base-100 border border-base-300 lg:col-span-2">
|
|
42
20
|
<div class="card-body p-4">
|
|
43
21
|
<h2 class="card-title text-base">Create JSON Plugin</h2>
|
|
44
22
|
<div class="grid grid-cols-2 gap-2 mb-2">
|
|
@@ -180,15 +158,6 @@
|
|
|
180
158
|
this.plugins = out.plugins || []
|
|
181
159
|
if (out.settings) this.settings = out.settings
|
|
182
160
|
},
|
|
183
|
-
async saveSettings() {
|
|
184
|
-
try {
|
|
185
|
-
await this.api('/api/plugins/settings', 'PUT', this.settings)
|
|
186
|
-
this.setMessage('success', 'Settings updated')
|
|
187
|
-
await this.reloadPlugins()
|
|
188
|
-
} catch (err) {
|
|
189
|
-
this.setMessage('error', err.message)
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
161
|
async createJsonPlugin() {
|
|
193
162
|
try {
|
|
194
163
|
const manifest = JSON.parse(this.jsonForm.manifestStr)
|
|
@@ -266,6 +235,38 @@
|
|
|
266
235
|
this.setMessage('error', err.message)
|
|
267
236
|
}
|
|
268
237
|
},
|
|
238
|
+
async createApiKey() {
|
|
239
|
+
if (!this.newKeyName.trim()) {
|
|
240
|
+
this.setMessage('error', 'API key name is required')
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
const result = await this.api('/api/plugins/api-keys', 'POST', { name: this.newKeyName })
|
|
245
|
+
this.setMessage('success', `Created API key '${result.name}'`)
|
|
246
|
+
this.newKeyName = ''
|
|
247
|
+
await this.reloadPlugins()
|
|
248
|
+
} catch (err) {
|
|
249
|
+
this.setMessage('error', err.message)
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
async deleteApiKey(key) {
|
|
253
|
+
if (!confirm('Delete this API key?')) return
|
|
254
|
+
try {
|
|
255
|
+
await this.api(`/api/plugins/api-keys/${encodeURIComponent(key)}`, 'DELETE')
|
|
256
|
+
this.setMessage('success', 'API key deleted')
|
|
257
|
+
await this.reloadPlugins()
|
|
258
|
+
} catch (err) {
|
|
259
|
+
this.setMessage('error', err.message)
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
async copyApiKey(key) {
|
|
263
|
+
try {
|
|
264
|
+
await navigator.clipboard.writeText(key)
|
|
265
|
+
this.setMessage('success', 'API key copied to clipboard')
|
|
266
|
+
} catch (err) {
|
|
267
|
+
this.setMessage('error', 'Failed to copy API key')
|
|
268
|
+
}
|
|
269
|
+
},
|
|
269
270
|
},
|
|
270
271
|
}).mount('#plugins-app')
|
|
271
272
|
</script>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<%- include("partials/head", { title: "Server Settings" }) %>
|
|
2
|
+
|
|
3
|
+
<div id="settings-app" class="max-w-4xl">
|
|
4
|
+
<div class="flex justify-between items-center mb-6">
|
|
5
|
+
<h1 class="text-2xl font-bold">Server Settings</h1>
|
|
6
|
+
<div class="text-sm opacity-80">Configure server-wide behavior and security.</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div v-if="message.text" :class="['alert mb-4', message.type === 'error' ? 'alert-error' : 'alert-success']">
|
|
10
|
+
<span>{{ message.text }}</span>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div v-if="settings.admin_mode_enabled" class="alert alert-error mb-4">
|
|
14
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
|
15
|
+
<span><strong>Admin Mode Enabled:</strong> CLI clients can modify server state without authentication. Disable when not needed.</span>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="card bg-base-100 border border-base-300">
|
|
19
|
+
<div class="card-body">
|
|
20
|
+
<h2 class="card-title">General Settings</h2>
|
|
21
|
+
<label class="form-control mb-3">
|
|
22
|
+
<span class="label-text">Max ZIP Size (MB)</span>
|
|
23
|
+
<input v-model.number="settings.max_zip_mb" type="number" min="1" class="input input-bordered" />
|
|
24
|
+
</label>
|
|
25
|
+
<label class="form-control mb-3">
|
|
26
|
+
<span class="label-text">Default Hooks Policy</span>
|
|
27
|
+
<select v-model="settings.default_hooks_policy" class="select select-bordered">
|
|
28
|
+
<option value="deny">deny</option>
|
|
29
|
+
<option value="allow">allow</option>
|
|
30
|
+
</select>
|
|
31
|
+
</label>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="card bg-base-100 border border-base-300 mt-4">
|
|
36
|
+
<div class="card-body">
|
|
37
|
+
<h2 class="card-title">Security Settings</h2>
|
|
38
|
+
<label class="label cursor-pointer justify-start gap-2 mb-3">
|
|
39
|
+
<input type="checkbox" v-model="settings.admin_mode_enabled" class="checkbox checkbox-error" />
|
|
40
|
+
<span class="label-text text-error font-semibold">Admin Mode (allows CLI modifications without auth)</span>
|
|
41
|
+
</label>
|
|
42
|
+
<label class="label cursor-pointer justify-start gap-2 mb-3">
|
|
43
|
+
<input type="checkbox" v-model="settings.public_access" class="checkbox" />
|
|
44
|
+
<span class="label-text">Public Access (allow API requests without API key)</span>
|
|
45
|
+
</label>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="mt-6">
|
|
50
|
+
<button class="btn btn-primary" @click="saveSettings">Save Settings</button>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<script>
|
|
55
|
+
const { createApp } = Vue
|
|
56
|
+
|
|
57
|
+
createApp({
|
|
58
|
+
data() {
|
|
59
|
+
return {
|
|
60
|
+
settings: {},
|
|
61
|
+
message: { text: '', type: 'success' }
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
async mounted() {
|
|
65
|
+
await this.loadSettings()
|
|
66
|
+
},
|
|
67
|
+
methods: {
|
|
68
|
+
async loadSettings() {
|
|
69
|
+
try {
|
|
70
|
+
const res = await fetch('/api/settings?format=json')
|
|
71
|
+
const data = await res.json()
|
|
72
|
+
this.settings = data
|
|
73
|
+
} catch (err) {
|
|
74
|
+
this.setMessage('error', err.message)
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
async saveSettings() {
|
|
78
|
+
try {
|
|
79
|
+
const res = await fetch('/api/settings', {
|
|
80
|
+
method: 'PUT',
|
|
81
|
+
headers: { 'Content-Type': 'application/json' },
|
|
82
|
+
body: JSON.stringify(this.settings)
|
|
83
|
+
})
|
|
84
|
+
const data = await res.json()
|
|
85
|
+
this.settings = data.settings
|
|
86
|
+
this.setMessage('success', 'Settings saved')
|
|
87
|
+
} catch (err) {
|
|
88
|
+
this.setMessage('error', err.message)
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
setMessage(type, text) {
|
|
92
|
+
this.message = { type, text }
|
|
93
|
+
setTimeout(() => this.message = { text: '', type: 'success' }, 3000)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}).mount('#settings-app')
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<%- include("partials/foot") %>
|