jishushell 0.6.18 → 0.7.3
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/apps/anythingllm-container.yaml +1 -0
- package/apps/browserless-chromium-container.yaml +1 -0
- package/apps/filebrowser-container.yaml +1 -0
- package/apps/hermes-container.yaml +1 -7
- package/apps/immich-container-lite.yaml +337 -0
- package/apps/immich-container.yaml +371 -0
- package/apps/jishu-kb-container.yaml +26 -21
- package/apps/ollama-binary.yaml +1 -0
- package/apps/ollama-cpu-container.yaml +1 -0
- package/apps/ollama-with-hollama-binary.yaml +2 -0
- package/apps/openclaw-binary.yaml +4 -8
- package/apps/openclaw-container.yaml +1 -7
- package/apps/openclaw-with-ollama-container.yaml +1 -0
- package/apps/openclaw-with-searxng-container.yaml +20 -0
- package/apps/searxng-container.yaml +20 -0
- package/apps/weknora-container.yaml +5 -0
- package/dependencies/jishushell-panel-0.7.3.tgz +0 -0
- package/dist/cli/core.js +1 -1
- package/dist/cli/core.js.map +1 -1
- package/dist/cli/doctor.js +96 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/config.d.ts +9 -1
- package/dist/config.js +72 -2
- package/dist/config.js.map +1 -1
- package/dist/install.js +60 -19
- package/dist/install.js.map +1 -1
- package/dist/routes/admin.d.ts +2 -0
- package/dist/routes/admin.js +72 -0
- package/dist/routes/admin.js.map +1 -0
- package/dist/routes/docker.d.ts +2 -0
- package/dist/routes/docker.js +58 -0
- package/dist/routes/docker.js.map +1 -0
- package/dist/routes/file-mounts.js +5 -8
- package/dist/routes/file-mounts.js.map +1 -1
- package/dist/routes/instances.d.ts +0 -14
- package/dist/routes/instances.js +44 -1184
- package/dist/routes/instances.js.map +1 -1
- package/dist/server.d.ts +6 -0
- package/dist/server.js +53 -20
- package/dist/server.js.map +1 -1
- package/dist/services/app-common/catalog-service.js +15 -5
- package/dist/services/app-common/catalog-service.js.map +1 -1
- package/dist/services/app-common/delete-service.js +5 -0
- package/dist/services/app-common/delete-service.js.map +1 -1
- package/dist/services/app-common/instance-store.js +3 -0
- package/dist/services/app-common/instance-store.js.map +1 -1
- package/dist/services/app-common/lifecycle-service.js +12 -4
- package/dist/services/app-common/lifecycle-service.js.map +1 -1
- package/dist/services/app-common/ownership.d.ts +3 -0
- package/dist/services/app-common/ownership.js +11 -0
- package/dist/services/app-common/ownership.js.map +1 -0
- package/dist/services/app-common/runtime-facts.js +2 -0
- package/dist/services/app-common/runtime-facts.js.map +1 -1
- package/dist/services/app-common/spec-materializer.d.ts +0 -1
- package/dist/services/app-common/spec-materializer.js +21 -87
- package/dist/services/app-common/spec-materializer.js.map +1 -1
- package/dist/services/app-common/status-refresh.js +25 -13
- package/dist/services/app-common/status-refresh.js.map +1 -1
- package/dist/services/app-modules/browserless/routes.js +5 -3
- package/dist/services/app-modules/browserless/routes.js.map +1 -1
- package/dist/services/capabilities/contract.d.ts +1 -2
- package/dist/services/capabilities/contract.js +0 -10
- package/dist/services/capabilities/contract.js.map +1 -1
- package/dist/services/capabilities/endpoint-validator.js +0 -1
- package/dist/services/capabilities/endpoint-validator.js.map +1 -1
- package/dist/services/capabilities/health.js +1 -1
- package/dist/services/capabilities/health.js.map +1 -1
- package/dist/services/capability-proxy/http.d.ts +7 -0
- package/dist/services/capability-proxy/http.js +555 -0
- package/dist/services/capability-proxy/http.js.map +1 -0
- package/dist/services/capability-proxy/terminal.d.ts +4 -0
- package/dist/services/capability-proxy/terminal.js +179 -0
- package/dist/services/capability-proxy/terminal.js.map +1 -0
- package/dist/services/connections/admin.js +19 -9
- package/dist/services/connections/admin.js.map +1 -1
- package/dist/services/connections/apply.d.ts +3 -9
- package/dist/services/connections/apply.js +0 -29
- package/dist/services/connections/apply.js.map +1 -1
- package/dist/services/connections/transactor.js +2 -2
- package/dist/services/connections/transactor.js.map +1 -1
- package/dist/services/files/bootstrap.d.ts +7 -0
- package/dist/services/files/bootstrap.js +16 -0
- package/dist/services/files/bootstrap.js.map +1 -0
- package/dist/services/files/photos/upload-page.d.ts +2 -0
- package/dist/services/files/photos/upload-page.js +248 -0
- package/dist/services/files/photos/upload-page.js.map +1 -0
- package/dist/services/files/photos/upload-store.d.ts +74 -0
- package/dist/services/files/photos/upload-store.js +432 -0
- package/dist/services/files/photos/upload-store.js.map +1 -0
- package/dist/services/http/proxy-utils.d.ts +7 -0
- package/dist/services/http/proxy-utils.js +29 -0
- package/dist/services/http/proxy-utils.js.map +1 -0
- package/dist/services/http/request-utils.d.ts +3 -0
- package/dist/services/http/request-utils.js +23 -0
- package/dist/services/http/request-utils.js.map +1 -0
- package/dist/services/instances/manager.d.ts +6 -5
- package/dist/services/instances/manager.js +45 -51
- package/dist/services/instances/manager.js.map +1 -1
- package/dist/services/instances/pairing.d.ts +17 -0
- package/dist/services/instances/pairing.js +53 -0
- package/dist/services/instances/pairing.js.map +1 -0
- package/dist/services/instances/status.d.ts +2 -0
- package/dist/services/instances/status.js +11 -0
- package/dist/services/instances/status.js.map +1 -0
- package/dist/services/integrations/hermes/integration.d.ts +1 -1
- package/dist/services/integrations/hermes/integration.js +7 -8
- package/dist/services/integrations/hermes/integration.js.map +1 -1
- package/dist/services/integrations/immich/client.d.ts +93 -0
- package/dist/services/integrations/immich/client.js +458 -0
- package/dist/services/integrations/immich/client.js.map +1 -0
- package/dist/services/integrations/immich/config.d.ts +15 -0
- package/dist/services/integrations/immich/config.js +178 -0
- package/dist/services/integrations/immich/config.js.map +1 -0
- package/dist/services/integrations/immich/discovery.d.ts +9 -0
- package/dist/services/integrations/immich/discovery.js +101 -0
- package/dist/services/integrations/immich/discovery.js.map +1 -0
- package/dist/services/integrations/immich/gallery-renderer.d.ts +5 -0
- package/dist/services/integrations/immich/gallery-renderer.js +150 -0
- package/dist/services/integrations/immich/gallery-renderer.js.map +1 -0
- package/dist/services/integrations/immich/immich-shim.d.ts +11 -0
- package/dist/services/integrations/immich/immich-shim.js +439 -0
- package/dist/services/integrations/immich/immich-shim.js.map +1 -0
- package/dist/services/integrations/immich/integration.d.ts +18 -0
- package/dist/services/integrations/immich/integration.js +64 -0
- package/dist/services/integrations/immich/integration.js.map +1 -0
- package/dist/services/integrations/immich/photo-library.d.ts +4 -0
- package/dist/services/integrations/immich/photo-library.js +63 -0
- package/dist/services/integrations/immich/photo-library.js.map +1 -0
- package/dist/services/integrations/immich/review-executor.d.ts +3 -0
- package/dist/services/integrations/immich/review-executor.js +41 -0
- package/dist/services/integrations/immich/review-executor.js.map +1 -0
- package/dist/services/integrations/immich/review-session-service.d.ts +27 -0
- package/dist/services/integrations/immich/review-session-service.js +206 -0
- package/dist/services/integrations/immich/review-session-service.js.map +1 -0
- package/dist/services/integrations/immich/review-store.d.ts +47 -0
- package/dist/services/integrations/immich/review-store.js +347 -0
- package/dist/services/integrations/immich/review-store.js.map +1 -0
- package/dist/services/integrations/immich/routes.d.ts +7 -0
- package/dist/services/integrations/immich/routes.js +363 -0
- package/dist/services/integrations/immich/routes.js.map +1 -0
- package/dist/services/integrations/immich/types.d.ts +186 -0
- package/dist/services/integrations/immich/types.js +2 -0
- package/dist/services/integrations/immich/types.js.map +1 -0
- package/dist/services/integrations/index.d.ts +1 -0
- package/dist/services/integrations/index.js +1 -0
- package/dist/services/integrations/index.js.map +1 -1
- package/dist/services/integrations/installable/installers/integration.js +113 -7
- package/dist/services/integrations/installable/installers/integration.js.map +1 -1
- package/dist/services/integrations/jishukb/integration.d.ts +3 -1
- package/dist/services/integrations/jishukb/integration.js +121 -10
- package/dist/services/integrations/jishukb/integration.js.map +1 -1
- package/dist/services/integrations/openclaw/integration.d.ts +21 -7
- package/dist/services/integrations/openclaw/integration.js +385 -158
- package/dist/services/integrations/openclaw/integration.js.map +1 -1
- package/dist/services/integrations/openclaw/jishukb-native-mcp.d.ts +58 -0
- package/dist/services/integrations/openclaw/jishukb-native-mcp.js +373 -0
- package/dist/services/integrations/openclaw/jishukb-native-mcp.js.map +1 -0
- package/dist/services/integrations/openclaw/jishukb-shim.d.ts +8 -4
- package/dist/services/integrations/openclaw/jishukb-shim.js +624 -17
- package/dist/services/integrations/openclaw/jishukb-shim.js.map +1 -1
- package/dist/services/integrations/openclaw/mcporter.d.ts +13 -0
- package/dist/services/integrations/openclaw/mcporter.js +31 -0
- package/dist/services/integrations/openclaw/mcporter.js.map +1 -1
- package/dist/services/integrations/openclaw/native-mcp.d.ts +48 -0
- package/dist/services/integrations/openclaw/native-mcp.js +125 -0
- package/dist/services/integrations/openclaw/native-mcp.js.map +1 -0
- package/dist/services/integrations/openclaw/routes.js +4 -1
- package/dist/services/integrations/openclaw/routes.js.map +1 -1
- package/dist/services/integrations/types.d.ts +5 -17
- package/dist/services/repair/runtime-repair.js +68 -1
- package/dist/services/repair/runtime-repair.js.map +1 -1
- package/dist/services/runtime/docker-network.d.ts +8 -0
- package/dist/services/runtime/docker-network.js +123 -0
- package/dist/services/runtime/docker-network.js.map +1 -0
- package/dist/services/runtime/driver-registry.d.ts +4 -0
- package/dist/services/runtime/driver-registry.js.map +1 -1
- package/dist/services/runtime/drivers/nomad.d.ts +1 -0
- package/dist/services/runtime/drivers/nomad.js +35 -5
- package/dist/services/runtime/drivers/nomad.js.map +1 -1
- package/dist/services/runtime/service-manager.d.ts +2 -0
- package/dist/services/runtime/service-manager.js +18 -0
- package/dist/services/runtime/service-manager.js.map +1 -0
- package/dist/services/runtime/types.d.ts +1 -0
- package/dist/services/runtime/workload-compiler.js +29 -4
- package/dist/services/runtime/workload-compiler.js.map +1 -1
- package/dist/services/setup/setup-manager.js +29 -73
- package/dist/services/setup/setup-manager.js.map +1 -1
- package/dist/services/system/runtime-ownership.d.ts +36 -0
- package/dist/services/system/runtime-ownership.js +250 -0
- package/dist/services/system/runtime-ownership.js.map +1 -0
- package/dist/services/system/system-reconciler.js +53 -0
- package/dist/services/system/system-reconciler.js.map +1 -1
- package/dist/types.d.ts +19 -3
- package/dist/utils/path-safety.js +1 -1
- package/dist/utils/service-user.d.ts +13 -0
- package/dist/utils/service-user.js +129 -0
- package/dist/utils/service-user.js.map +1 -0
- package/install/jishu-install.sh +0 -1
- package/node_modules/brace-expansion/dist/commonjs/index.js +24 -14
- package/node_modules/brace-expansion/dist/commonjs/index.js.map +1 -1
- package/node_modules/brace-expansion/dist/esm/index.js +24 -14
- package/node_modules/brace-expansion/dist/esm/index.js.map +1 -1
- package/node_modules/brace-expansion/package.json +2 -2
- package/node_modules/fast-uri/index.js +1 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/security.test.js +28 -0
- package/node_modules/fastify/SECURITY.md +1 -1
- package/node_modules/fastify/SPONSORS.md +6 -4
- package/node_modules/fastify/docs/Guides/Database.md +0 -28
- package/node_modules/fastify/docs/Guides/Ecosystem.md +13 -2
- package/node_modules/fastify/docs/Guides/Serverless.md +2 -2
- package/node_modules/fastify/docs/Guides/Write-Plugin.md +1 -1
- package/node_modules/fastify/docs/Reference/Encapsulation.md +27 -26
- package/node_modules/fastify/docs/Reference/Errors.md +10 -4
- package/node_modules/fastify/docs/Reference/HTTP2.md +10 -10
- package/node_modules/fastify/docs/Reference/Hooks.md +4 -4
- package/node_modules/fastify/docs/Reference/Index.md +14 -16
- package/node_modules/fastify/docs/Reference/LTS.md +12 -13
- package/node_modules/fastify/docs/Reference/Lifecycle.md +9 -8
- package/node_modules/fastify/docs/Reference/Logging.md +44 -39
- package/node_modules/fastify/docs/Reference/Middleware.md +21 -25
- package/node_modules/fastify/docs/Reference/Principles.md +2 -2
- package/node_modules/fastify/docs/Reference/Reply.md +6 -1
- package/node_modules/fastify/docs/Reference/Request.md +27 -16
- package/node_modules/fastify/docs/Reference/Routes.md +5 -2
- package/node_modules/fastify/docs/Reference/Server.md +31 -3
- package/node_modules/fastify/docs/Reference/Type-Providers.md +29 -5
- package/node_modules/fastify/docs/Reference/Validation-and-Serialization.md +15 -2
- package/node_modules/fastify/docs/Reference/Warnings.md +7 -6
- package/node_modules/fastify/eslint.config.js +7 -2
- package/node_modules/fastify/fastify.d.ts +8 -3
- package/node_modules/fastify/fastify.js +43 -14
- package/node_modules/fastify/lib/content-type-parser.js +13 -1
- package/node_modules/fastify/lib/decorate.js +11 -3
- package/node_modules/fastify/lib/error-handler.js +4 -3
- package/node_modules/fastify/lib/error-serializer.js +59 -59
- package/node_modules/fastify/lib/errors.js +16 -1
- package/node_modules/fastify/lib/four-oh-four.js +14 -9
- package/node_modules/fastify/lib/handle-request.js +11 -5
- package/node_modules/fastify/lib/plugin-override.js +2 -1
- package/node_modules/fastify/lib/plugin-utils.js +5 -5
- package/node_modules/fastify/lib/reply.js +63 -8
- package/node_modules/fastify/lib/request.js +14 -4
- package/node_modules/fastify/lib/route.js +20 -6
- package/node_modules/fastify/lib/schema-controller.js +1 -1
- package/node_modules/fastify/lib/schemas.js +37 -30
- package/node_modules/fastify/lib/symbols.js +3 -1
- package/node_modules/fastify/lib/validation.js +1 -13
- package/node_modules/fastify/lib/warnings.js +3 -3
- package/node_modules/fastify/package.json +13 -15
- package/node_modules/fastify/scripts/validate-ecosystem-links.js +1 -0
- package/node_modules/fastify/test/bundler/esbuild/package.json +1 -1
- package/node_modules/fastify/test/close-pipelining.test.js +1 -2
- package/node_modules/fastify/test/custom-http-server.test.js +38 -0
- package/node_modules/fastify/test/decorator-instance-properties.test.js +63 -0
- package/node_modules/fastify/test/diagnostics-channel/async-error-handler.test.js +74 -0
- package/node_modules/fastify/test/hooks.test.js +23 -0
- package/node_modules/fastify/test/http-methods/get.test.js +1 -1
- package/node_modules/fastify/test/http2/plain.test.js +135 -0
- package/node_modules/fastify/test/http2/secure-with-fallback.test.js +1 -1
- package/node_modules/fastify/test/https/https.test.js +1 -2
- package/node_modules/fastify/test/internals/errors.test.js +31 -1
- package/node_modules/fastify/test/internals/plugin.test.js +3 -1
- package/node_modules/fastify/test/internals/request.test.js +27 -3
- package/node_modules/fastify/test/internals/schema-controller-perf.test.js +33 -0
- package/node_modules/fastify/test/logger/logging.test.js +18 -1
- package/node_modules/fastify/test/logger/options.test.js +38 -1
- package/node_modules/fastify/test/reply-error.test.js +1 -1
- package/node_modules/fastify/test/reply-trailers.test.js +70 -0
- package/node_modules/fastify/test/request-media-type.test.js +105 -0
- package/node_modules/fastify/test/route-prefix.test.js +34 -0
- package/node_modules/fastify/test/router-options.test.js +222 -11
- package/node_modules/fastify/test/schema-serialization.test.js +108 -0
- package/node_modules/fastify/test/schema-validation.test.js +24 -0
- package/node_modules/fastify/test/scripts/validate-ecosystem-links.test.js +40 -57
- package/node_modules/fastify/test/throw.test.js +14 -0
- package/node_modules/fastify/test/trust-proxy.test.js +21 -0
- package/node_modules/fastify/test/types/content-type-parser.tst.ts +70 -0
- package/node_modules/fastify/test/types/{decorate-request-reply.test-d.ts → decorate-request-reply.tst.ts} +4 -4
- package/node_modules/fastify/test/types/{dummy-plugin.ts → dummy-plugin.mts} +1 -1
- package/node_modules/fastify/test/types/errors.tst.ts +91 -0
- package/node_modules/fastify/test/types/fastify.tst.ts +351 -0
- package/node_modules/fastify/test/types/hooks.tst.ts +578 -0
- package/node_modules/fastify/test/types/instance.tst.ts +597 -0
- package/node_modules/fastify/test/types/{logger.test-d.ts → logger.tst.ts} +61 -62
- package/node_modules/fastify/test/types/plugin.tst.ts +96 -0
- package/node_modules/fastify/test/types/register.tst.ts +245 -0
- package/node_modules/fastify/test/types/reply.tst.ts +297 -0
- package/node_modules/fastify/test/types/request.tst.ts +199 -0
- package/node_modules/fastify/test/types/route.tst.ts +576 -0
- package/node_modules/fastify/test/types/{schema.test-d.ts → schema.tst.ts} +22 -22
- package/node_modules/fastify/test/types/{serverFactory.test-d.ts → serverFactory.tst.ts} +4 -4
- package/node_modules/fastify/test/types/tsconfig.json +9 -0
- package/node_modules/fastify/test/types/{type-provider.test-d.ts → type-provider.tst.ts} +256 -250
- package/node_modules/fastify/test/types/using.tst.ts +14 -0
- package/node_modules/fastify/types/errors.d.ts +3 -0
- package/node_modules/fastify/types/request.d.ts +23 -2
- package/node_modules/jishushell-panel/output/public/assets/{ApiKeyField-NKcbHjNz.js → ApiKeyField-Ce5d1xna.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/{Dashboard-Da1fL38t.js → Dashboard-BXame3yg.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/{HermesChatPanel-DZvmYsoh.js → HermesChatPanel-BHZtPCJd.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/{HermesConfigForm-BLUWlKwm.js → HermesConfigForm-CB3GbNX9.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/{InitPassword-BAKsshzk.js → InitPassword-Boab9F6g.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/InstanceDetail-DrIWCqo-.js +14 -0
- package/node_modules/jishushell-panel/output/public/assets/{Login-DHeOmwI8.js → Login-CzpOkNau.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/NewInstance-CANXyCcL.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/{ProviderRecommendations-H0ByEYF0.js → ProviderRecommendations-BABo9VOC.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/Settings-CKp5XxFh.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/Setup-C7xVDPow.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/{WeixinLoginPanel-D-T6BxkQ.js → WeixinLoginPanel-B765Xz4C.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/{index-ERt6_ngA.js → index-Bs6DSbiR.js} +6 -6
- package/node_modules/jishushell-panel/output/public/assets/{registry-DF93EzIb.js → registry-sWIZsIEF.js} +2 -2
- package/node_modules/jishushell-panel/output/public/assets/{usePolling-DeoThIQn.js → usePolling-D4IDOQd_.js} +1 -1
- package/node_modules/jishushell-panel/output/public/assets/vendor-i18n-Df8aUdv8.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/{vendor-react-Cc84NArf.js → vendor-react-0L0rjmYG.js} +3 -3
- package/node_modules/jishushell-panel/output/public/index.html +3 -3
- package/node_modules/jishushell-panel/package.json +1 -1
- package/node_modules/semver/classes/range.js +6 -2
- package/node_modules/semver/package.json +1 -1
- package/package.json +4 -4
- package/scripts/check-app-spec.mjs +4 -12
- package/scripts/check-architecture-boundaries.mjs +178 -0
- package/scripts/pack-gui-and-send-pi.sh +5 -3
- package/dependencies/jishushell-panel-0.6.18.tgz +0 -0
- package/dist/services/connections/suggestions.d.ts +0 -27
- package/dist/services/connections/suggestions.js +0 -124
- package/dist/services/connections/suggestions.js.map +0 -1
- package/node_modules/fastify/test/types/content-type-parser.test-d.ts +0 -72
- package/node_modules/fastify/test/types/errors.test-d.ts +0 -90
- package/node_modules/fastify/test/types/fastify.test-d.ts +0 -352
- package/node_modules/fastify/test/types/hooks.test-d.ts +0 -550
- package/node_modules/fastify/test/types/import.ts +0 -2
- package/node_modules/fastify/test/types/instance.test-d.ts +0 -588
- package/node_modules/fastify/test/types/plugin.test-d.ts +0 -97
- package/node_modules/fastify/test/types/register.test-d.ts +0 -237
- package/node_modules/fastify/test/types/reply.test-d.ts +0 -254
- package/node_modules/fastify/test/types/request.test-d.ts +0 -188
- package/node_modules/fastify/test/types/route.test-d.ts +0 -553
- package/node_modules/fastify/test/types/using.test-d.ts +0 -17
- package/node_modules/jishushell-panel/output/public/assets/InstanceDetail-Dgyc_TX5.js +0 -14
- package/node_modules/jishushell-panel/output/public/assets/NewInstance-CIy0cYtp.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/Settings-DAT-UMfP.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/Setup-g3uckFYR.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/vendor-i18n-CS8DFbkQ.js +0 -1
|
@@ -40,7 +40,7 @@ import { accessSync, chmodSync, chownSync, copyFileSync, cpSync, constants, exis
|
|
|
40
40
|
import { createHash, randomBytes } from "crypto";
|
|
41
41
|
import { homedir, userInfo } from "os";
|
|
42
42
|
import { delimiter, dirname, join, resolve as pathResolve } from "path";
|
|
43
|
-
import { getNomadDriver, getOpenclawDockerImage, JISHUSHELL_HOME, getCoreLanHost, getCorePort, } from "../../../config.js";
|
|
43
|
+
import { getNomadDriver, getOpenclawDockerImage, JISHUSHELL_HOME, getCoreLanHost, getCorePort, getInternalMcpToken, } from "../../../config.js";
|
|
44
44
|
import { ensureDirContainer, ensureDirHost, writeConfigFile } from "../../../utils/fs.js";
|
|
45
45
|
import { safeWriteJson } from "../../../utils/safe-json.js";
|
|
46
46
|
import { chownToServiceUser, getInstance, getRuntimeEnvFiles, listInstances, normalizePath, notifyConfigChange, resolveServiceUser, updateInstanceMeta, updateEnvFile, } from "../../instances/manager.js";
|
|
@@ -57,7 +57,8 @@ import { resolveNomadJobId } from "../../runtime/job-id.js";
|
|
|
57
57
|
import { DEFINITION_FILENAME, MANIFEST_FILENAME, RESOLVED_SPEC_FILENAME, } from "../../app-common/paths.js";
|
|
58
58
|
import { registerIntegration } from "../registry.js";
|
|
59
59
|
import { isOwnedByInstance, writeOwnershipMarker } from "../../runtime/ownership-marker.js";
|
|
60
|
-
import { mcporterPath,
|
|
60
|
+
import { mcporterPath, removeMcporterServers } from "./mcporter.js";
|
|
61
|
+
import { removeOpenclawMcpServers, upsertOpenclawMcpServer, } from "./native-mcp.js";
|
|
61
62
|
// ── Constants physically migrated from the Nomad driver ───────────────
|
|
62
63
|
//
|
|
63
64
|
// These used to live as module-scope constants in the Nomad driver and were
|
|
@@ -243,12 +244,6 @@ function listMountedHostPaths(runtime) {
|
|
|
243
244
|
}
|
|
244
245
|
return list;
|
|
245
246
|
}
|
|
246
|
-
function listJishukbUploadRoots(runtime, openclawHome) {
|
|
247
|
-
return Array.from(new Set([
|
|
248
|
-
...listMountedHostPaths(runtime),
|
|
249
|
-
join(openclawHome, ".openclaw", "media", "inbound"),
|
|
250
|
-
]));
|
|
251
|
-
}
|
|
252
247
|
// ── Path helpers (physically migrated from instance-manager.ts) ───────
|
|
253
248
|
const INSTANCE_OPENCLAW_HOME_DIRNAME = "openclaw-home";
|
|
254
249
|
const INSTANCE_MODEL_ENV_FILENAME = "model.env";
|
|
@@ -1259,16 +1254,22 @@ export function clearBrowserlessConnectionFromConfig(configPath) {
|
|
|
1259
1254
|
* surface.
|
|
1260
1255
|
* 2026.6.12.1 — Browserless site-side anti-bot classification rule:
|
|
1261
1256
|
* site WAF/captcha blocks are not Browser Allowlist misses.
|
|
1257
|
+
* 2026.6.24.1 — Immich MCP routing rule in TOOLS.md: photo-library
|
|
1258
|
+
* requests must use the injected immich.* tools instead of
|
|
1259
|
+
* probing docker, ports, or host directories from inside
|
|
1260
|
+
* the OpenClaw container.
|
|
1262
1261
|
*
|
|
1263
1262
|
* Format: YYYY.M.D.N (date + same-day bump counter). Compare as strings;
|
|
1264
1263
|
* any difference means rotate. Stored per-instance at
|
|
1265
1264
|
* `<instanceDir>/runtime-contract.txt`
|
|
1266
1265
|
*/
|
|
1267
|
-
const RUNTIME_CONTRACT_VERSION = "2026.6.
|
|
1266
|
+
const RUNTIME_CONTRACT_VERSION = "2026.6.24.1";
|
|
1268
1267
|
const JISHUSHELL_DRIVE_HINT_BEGIN = "<!-- jishushell-drive: BEGIN auto-generated -->";
|
|
1269
1268
|
const JISHUSHELL_DRIVE_HINT_END = "<!-- jishushell-drive: END -->";
|
|
1270
1269
|
const JISHUSHELL_KB_HINT_BEGIN = "<!-- jishushell-kb: BEGIN auto-generated -->";
|
|
1271
1270
|
const JISHUSHELL_KB_HINT_END = "<!-- jishushell-kb: END -->";
|
|
1271
|
+
const JISHUSHELL_IMMICH_HINT_BEGIN = "<!-- jishushell-immich: BEGIN auto-generated -->";
|
|
1272
|
+
const JISHUSHELL_IMMICH_HINT_END = "<!-- jishushell-immich: END -->";
|
|
1272
1273
|
const JISHUSHELL_BROWSERLESS_HINT_BEGIN = "<!-- jishushell-browserless: BEGIN auto-generated -->";
|
|
1273
1274
|
const JISHUSHELL_BROWSERLESS_HINT_END = "<!-- jishushell-browserless: END -->";
|
|
1274
1275
|
/**
|
|
@@ -1652,6 +1653,21 @@ export async function resolveJishukbDefaultKbIdForOpenClaw(baseUrl, configuredKb
|
|
|
1652
1653
|
return "";
|
|
1653
1654
|
}
|
|
1654
1655
|
}
|
|
1656
|
+
function rewriteJishukbMcpUrlForOpenClawRuntime(url, runtime) {
|
|
1657
|
+
if (!runtime?.image)
|
|
1658
|
+
return url;
|
|
1659
|
+
try {
|
|
1660
|
+
const parsed = new URL(url);
|
|
1661
|
+
if (["127.0.0.1", "localhost", "0.0.0.0", "::1", "[::1]"].includes(parsed.hostname)) {
|
|
1662
|
+
parsed.hostname = "host.docker.internal";
|
|
1663
|
+
return parsed.toString();
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
catch {
|
|
1667
|
+
return url;
|
|
1668
|
+
}
|
|
1669
|
+
return url;
|
|
1670
|
+
}
|
|
1655
1671
|
/**
|
|
1656
1672
|
* Per-provider kb-shim residue cleanup. Wipes the shim source (replacing
|
|
1657
1673
|
* the bytes with a removal marker rather than `unlink`-ing — the latter
|
|
@@ -1696,7 +1712,7 @@ export function wipeKbShimDir(integrationHome, which) {
|
|
|
1696
1712
|
catch { /* best effort */ }
|
|
1697
1713
|
}
|
|
1698
1714
|
}
|
|
1699
|
-
export function patchToolsMdKbHint(workspaceDir, mode, provider, mcporterCommand = "mcporter", instanceId, mediaInboundRoot) {
|
|
1715
|
+
export function patchToolsMdKbHint(workspaceDir, mode, provider, mcporterCommand = "mcporter", instanceId, mediaInboundRoot, unavailableReason) {
|
|
1700
1716
|
try {
|
|
1701
1717
|
const toolsPath = join(workspaceDir, "TOOLS.md");
|
|
1702
1718
|
let original = "";
|
|
@@ -1721,6 +1737,30 @@ export function patchToolsMdKbHint(workspaceDir, mode, provider, mcporterCommand
|
|
|
1721
1737
|
return;
|
|
1722
1738
|
next = stripped;
|
|
1723
1739
|
}
|
|
1740
|
+
else if (mode === "unavailable") {
|
|
1741
|
+
const reason = typeof unavailableReason === "string" && unavailableReason.trim()
|
|
1742
|
+
? unavailableReason.trim().replace(/\s+/g, " ").slice(0, 500)
|
|
1743
|
+
: "native MCP is not registered";
|
|
1744
|
+
const section = [
|
|
1745
|
+
JISHUSHELL_KB_HINT_BEGIN,
|
|
1746
|
+
"",
|
|
1747
|
+
"### 📚 知识库(JishuShell-KB)暂不可用",
|
|
1748
|
+
"",
|
|
1749
|
+
"OpenClaw 已绑定 **JishuShell-KB**,但 JishuShell 当前没有检测到可用的 **native MCP** 服务,所以本轮不能调用 `kb.*` 工具。",
|
|
1750
|
+
"",
|
|
1751
|
+
`**检测原因**:${reason}`,
|
|
1752
|
+
"",
|
|
1753
|
+
"**必须这样处理**:",
|
|
1754
|
+
"- 不要声称已经检索过知识库,也不要尝试使用旧 shim、mcporter 或自己拼 HTTP 请求。",
|
|
1755
|
+
"- 如果用户要查询、上传或管理知识库,直接提醒用户:需要升级 JishuShell-KB 到包含 remote MCP 的版本,并确认 `JISHU_KB_MCP_HTTP` / MCP auth 已配置后重启 OpenClaw。",
|
|
1756
|
+
"- 在 native MCP 恢复前,知识库能力视为不可用。",
|
|
1757
|
+
"",
|
|
1758
|
+
JISHUSHELL_KB_HINT_END,
|
|
1759
|
+
"",
|
|
1760
|
+
].join("\n");
|
|
1761
|
+
const sep = stripped && !stripped.endsWith("\n") ? "\n\n" : "\n";
|
|
1762
|
+
next = (stripped ? stripped + sep : "") + section;
|
|
1763
|
+
}
|
|
1724
1764
|
else {
|
|
1725
1765
|
if (!provider) {
|
|
1726
1766
|
throw new Error("provider is required when installing KB hint");
|
|
@@ -1730,43 +1770,62 @@ export function patchToolsMdKbHint(workspaceDir, mode, provider, mcporterCommand
|
|
|
1730
1770
|
? `agent-data/${instanceId}/outbox/report.md`
|
|
1731
1771
|
: "agent-data/<instance>/outbox/report.md";
|
|
1732
1772
|
const attachmentInboxPath = mediaInboundRoot || "<openclawHome>/.openclaw/media/inbound";
|
|
1773
|
+
const nativeKbTool = (name) => `kb__${name}`;
|
|
1733
1774
|
const section = provider === "jishukb"
|
|
1734
1775
|
? [
|
|
1735
1776
|
JISHUSHELL_KB_HINT_BEGIN,
|
|
1736
1777
|
"",
|
|
1737
1778
|
"### 📚 知识库(JishuShell-KB)",
|
|
1738
1779
|
"",
|
|
1739
|
-
"用户长期投递并已经导入到 **JishuShell-KB** 的文档(手册、PDF、内部笔记、会议纪要等)可以检索;你也可以列知识库、创建知识库、把 drive
|
|
1780
|
+
"用户长期投递并已经导入到 **JishuShell-KB** 的文档(手册、PDF、内部笔记、会议纪要等)可以检索;你也可以列知识库、创建知识库、把 drive 文件或 URL 上传入库、查看已索引文档/分块/原文/FAQ、查看 ingest job、查看 handbook、读取**脱敏后的**当前配置,以及在用户明确确认时执行删除/重索引/取消任务。",
|
|
1781
|
+
"",
|
|
1782
|
+
"这些能力由 OpenClaw native MCP 暴露;直接调用 `kb__*` 工具,不要通过 shell、mcporter 或手写 HTTP 请求访问 KB。",
|
|
1740
1783
|
"",
|
|
1741
1784
|
"**当前 provider 暴露的工具**:",
|
|
1742
1785
|
"",
|
|
1743
|
-
`- \`${
|
|
1744
|
-
`- \`${
|
|
1745
|
-
`- \`${
|
|
1746
|
-
`- \`${
|
|
1747
|
-
`- \`${
|
|
1748
|
-
`- \`${
|
|
1749
|
-
`- \`${
|
|
1750
|
-
`- \`${
|
|
1751
|
-
`- \`${
|
|
1786
|
+
`- \`${nativeKbTool("kb_list")}\` — 列出所有知识库(拿 id / name / documents 文件数 / chunks 分块数;用户问“几个文件”时看 documents,不要用 chunks)`,
|
|
1787
|
+
`- \`${nativeKbTool("kb_get_capabilities")}\` — 查看 KB 当前支持的外部控制能力、上传格式和限制(不含密钥)`,
|
|
1788
|
+
`- \`${nativeKbTool("kb_create")}\` — 新建知识库`,
|
|
1789
|
+
`- \`${nativeKbTool("kb_get")}\` — 查看某个知识库的元数据、文件数、分块数、任务数和安全配置摘要`,
|
|
1790
|
+
`- \`${nativeKbTool("kb_search")}\` — 检索指定或默认知识库`,
|
|
1791
|
+
`- \`${nativeKbTool("kb_upload")}\` — 上传并索引文件到指定知识库`,
|
|
1792
|
+
`- \`${nativeKbTool("kb_import_url")}\` — 抓取可读 URL 并入库,默认异步返回 job`,
|
|
1793
|
+
`- \`${nativeKbTool("kb_list_documents")}\` — 列出指定或默认知识库里的已索引文档`,
|
|
1794
|
+
`- \`${nativeKbTool("kb_get_document")}\` — 查看单个文档的元数据和派生计数`,
|
|
1795
|
+
`- \`${nativeKbTool("kb_list_document_chunks")}\` — 查看某个文档的索引分块(文本会截断)`,
|
|
1796
|
+
`- \`${nativeKbTool("kb_read_document_raw")}\` — 读取某个文档的原始存储文本(仅在用户要看原文时用,输出会截断)`,
|
|
1797
|
+
`- \`${nativeKbTool("kb_list_document_faq")}\` — 查看某个文档生成的 FAQ 建议`,
|
|
1798
|
+
`- \`${nativeKbTool("kb_reindex_document")}\` — 重建文档索引(写操作,必须显式确认)`,
|
|
1799
|
+
`- \`${nativeKbTool("kb_list_jobs")}\` — 查看导入/索引任务`,
|
|
1800
|
+
`- \`${nativeKbTool("kb_get_job")}\` — 查看单个任务状态`,
|
|
1801
|
+
`- \`${nativeKbTool("kb_retry_job")}\` — 重试失败/取消的任务(仅在用户要求时用)`,
|
|
1802
|
+
`- \`${nativeKbTool("kb_cancel_job")}\` — 取消任务(必须显式确认)`,
|
|
1803
|
+
`- \`${nativeKbTool("kb_read_handbook")}\` — 读取 handbook 全文或指定章节`,
|
|
1804
|
+
`- \`${nativeKbTool("kb_get_config")}\` — 读取当前**脱敏后的**知识库配置摘要`,
|
|
1805
|
+
`- \`${nativeKbTool("kb_delete_document")}\` — 删除文档(危险操作,必须显式确认)`,
|
|
1806
|
+
`- \`${nativeKbTool("kb_delete_kb")}\` — 删除知识库(危险操作,必须显式确认)`,
|
|
1752
1807
|
"",
|
|
1753
1808
|
"**推荐调用顺序**:",
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
`3.
|
|
1757
|
-
`4.
|
|
1758
|
-
|
|
1759
|
-
|
|
1809
|
+
`1. 用户问“知识库里有几个文件 / 包含哪些文件” → 先 \`${nativeKbTool("kb_list_documents")}\`;如果不知道 kbId,先 \`${nativeKbTool("kb_list")}\`,再对目标库调用 \`${nativeKbTool("kb_list_documents")}\`。文件数按 documents 或 list_documents 返回数组长度计算,不要按 chunks 计算。`,
|
|
1810
|
+
`2. 用户提到“某个指定知识库 / 某个库里”但你不知道 id → 先 \`${nativeKbTool("kb_list")}\`。`,
|
|
1811
|
+
`3. 用户要把 drive 里的文件加入知识库 → 先解析本地路径,再调用 \`${nativeKbTool("kb_upload")}\`,并显式传目标 kbId。`,
|
|
1812
|
+
`4. 用户当前消息已经附了文件,而且消息里给了宿主机绝对路径(通常在 \`${attachmentInboxPath}/...\`)→ 直接把这个绝对路径传给 \`${nativeKbTool("kb_upload")}\`;不要先把内容重写到 \`files/\` 根目录,也不要自己猜 \`agent-data/agent1/...\` 这种路径。`,
|
|
1813
|
+
`5. 用户要把网页/文章 URL 加入知识库 → 先确认目标 kbId,再调用 \`${nativeKbTool("kb_import_url")}\`;返回 job 后用 \`${nativeKbTool("kb_get_job")}\` 或 \`${nativeKbTool("kb_list_jobs")}\` 看进度。`,
|
|
1814
|
+
`6. 用户要上传你**新生成**的文件 → 先写到 \`${generatedOutboxPath}\`,再解析本地路径,最后调用 \`${nativeKbTool("kb_upload")}\`。`,
|
|
1815
|
+
`7. 用户要新建库并马上上传 → \`${nativeKbTool("kb_create")}\` → 记住返回的 id → \`${nativeKbTool("kb_upload")}\` / \`${nativeKbTool("kb_import_url")}\`。`,
|
|
1816
|
+
`8. 用户要查看某个命中文档的细节 → 先 \`${nativeKbTool("kb_list_documents")}\` 找 documentId,再 \`${nativeKbTool("kb_get_document")}\`;需要解释命中原因用 \`${nativeKbTool("kb_list_document_chunks")}\`,只有用户明确要看原文时才用 \`${nativeKbTool("kb_read_document_raw")}\`。`,
|
|
1817
|
+
`9. 用户要修复索引/重跑失败导入 → 先 \`${nativeKbTool("kb_list_jobs")}\` / \`${nativeKbTool("kb_get_job")}\` 看状态;重试用 \`${nativeKbTool("kb_retry_job")}\`,重索引用 \`${nativeKbTool("kb_reindex_document")}\`。`,
|
|
1818
|
+
`10. 用户要解释某个设置项怎么用 → 先 \`${nativeKbTool("kb_read_handbook")}\`,必要时再 \`${nativeKbTool("kb_get_config")}\` 看当前值。`,
|
|
1760
1819
|
"",
|
|
1761
|
-
|
|
1820
|
+
`**安全规则**:写操作、删除操作、重索引、取消任务都不要猜目标知识库;拿不准就先 \`${nativeKbTool("kb_list")}\`。删除/重索引/取消必须是用户明确要求,且把 confirm 字段原样填成同一个 id。 \`${nativeKbTool("kb_get_config")}\` 和 \`${nativeKbTool("kb_get_capabilities")}\` 不会给你密钥。 \`${nativeKbTool("kb_upload")}\` 只接受来自当前实例已挂载文件目录,或当前实例附件 inbox(\`${attachmentInboxPath}/...\`)的绝对路径;如果 remote MCP capabilities 显示 path upload 关闭,就只能使用内容/URL 上传。 \`${nativeKbTool("kb_read_document_raw")}\` 只在用户要看原文时使用。**`,
|
|
1762
1821
|
"",
|
|
1763
1822
|
"**与 drive 的分工**:",
|
|
1764
1823
|
"- `drive.*` = 文件系统 facade(列目录、读字节、拿绝对路径)—— 要的是**文件本体**用 drive",
|
|
1765
|
-
"- `
|
|
1824
|
+
"- `kb__*` = 知识库检索/管理/上传 —— 要的是**知识库里的内容和状态**用 kb",
|
|
1766
1825
|
"",
|
|
1767
1826
|
"两者数据不共享:drive 里有文件 ≠ 某个知识库已经索引了它。",
|
|
1768
1827
|
"",
|
|
1769
|
-
"
|
|
1828
|
+
`**搜不到时的标准回复**:如果 \`${nativeKbTool("kb_search")}\` 没结果,就直接说「我在当前知识库里没找到相关内容」。如果用户问的是 drive 里已有文件,可进一步建议「要我把它上传到某个知识库吗?」—— 但上传前先确认目标 kbId,不要自己猜默认库。`,
|
|
1770
1829
|
"",
|
|
1771
1830
|
JISHUSHELL_KB_HINT_END,
|
|
1772
1831
|
"",
|
|
@@ -1815,6 +1874,96 @@ export function patchToolsMdKbHint(workspaceDir, mode, provider, mcporterCommand
|
|
|
1815
1874
|
console.warn(`[openclaw] Failed to ${mode} TOOLS.md kb hint: ${e.message}`);
|
|
1816
1875
|
}
|
|
1817
1876
|
}
|
|
1877
|
+
export function patchToolsMdKbUnavailableHint(workspaceDir, reason) {
|
|
1878
|
+
patchToolsMdKbHint(workspaceDir, "unavailable", undefined, "mcporter", undefined, undefined, reason);
|
|
1879
|
+
}
|
|
1880
|
+
/**
|
|
1881
|
+
* Inject or remove the Immich MCP usage contract in TOOLS.md.
|
|
1882
|
+
*
|
|
1883
|
+
* Immich is registered through OpenClaw's native `mcp.servers` config, so the
|
|
1884
|
+
* model receives standard tool schemas and calls them directly. This section
|
|
1885
|
+
* only supplies product behavior and safety guidance; it must not teach the
|
|
1886
|
+
* model to shell out through mcporter.
|
|
1887
|
+
*/
|
|
1888
|
+
export function patchToolsMdImmichHint(workspaceDir, mode, serverName = "immich") {
|
|
1889
|
+
try {
|
|
1890
|
+
const toolsPath = join(workspaceDir, "TOOLS.md");
|
|
1891
|
+
let original = "";
|
|
1892
|
+
try {
|
|
1893
|
+
original = readFileSync(toolsPath, "utf-8");
|
|
1894
|
+
}
|
|
1895
|
+
catch (e) {
|
|
1896
|
+
if (e?.code !== "ENOENT")
|
|
1897
|
+
throw e;
|
|
1898
|
+
if (mode === "remove")
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
const stripRe = /\n*<!-- jishushell-immich: BEGIN[^>]*-->[\s\S]*?<!-- jishushell-immich: END[^>]*-->\n*/g;
|
|
1902
|
+
const stripped = original.replace(stripRe, "\n");
|
|
1903
|
+
let next;
|
|
1904
|
+
if (mode === "remove") {
|
|
1905
|
+
if (stripped === original)
|
|
1906
|
+
return;
|
|
1907
|
+
next = stripped;
|
|
1908
|
+
}
|
|
1909
|
+
else {
|
|
1910
|
+
const tool = (name) => `${serverName}__${name}`;
|
|
1911
|
+
const section = [
|
|
1912
|
+
JISHUSHELL_IMMICH_HINT_BEGIN,
|
|
1913
|
+
"",
|
|
1914
|
+
"### 🖼️ Immich 照片库",
|
|
1915
|
+
"",
|
|
1916
|
+
`Immich 已通过 OpenClaw 原生 MCP 接入。用户询问照片、视频、图库状态、相册、标签、人物、人脸、地图位置或重复照片时,必须调用 \`${serverName}__*\` 工具,并严格按照工具提供的参数 Schema 传参。`,
|
|
1917
|
+
"",
|
|
1918
|
+
`⚠️ **不要用 shell 探测 Immich 是否安装**:OpenClaw 运行在自己的容器里;容器内没有 \`docker\` 命令、没有宿主机监听端口或 Immich 数据目录,并不代表宿主机没有运行 Immich。禁止用 \`docker ps\`、\`ss\`、\`find /\`、\`ls /opt\` 等结果判断 Immich 状态。连接状态只以 \`${tool("get_library_summary")}\` / \`${tool("ping")}\` 的结果为准。`,
|
|
1919
|
+
"",
|
|
1920
|
+
"**主要工具**:",
|
|
1921
|
+
"",
|
|
1922
|
+
`- \`${tool("get_library_summary")}\` — 首选健康检查;返回连接、版本和图库统计`,
|
|
1923
|
+
`- \`${tool("get_photo_library_status")}\` — 查看 AI Box 默认照片目录是否已接入及已扫描数量`,
|
|
1924
|
+
`- \`${tool("scan_photo_library")}\` — 扫描 AI Box 默认照片目录;首次调用会自动创建 External Library`,
|
|
1925
|
+
`- \`${tool("create_photo_upload_session")}\` — 创建短期网页上传链接;照片和视频由浏览器直接传到 AI Box;同一页面在过期前可完成并扫描多个上传批次`,
|
|
1926
|
+
`- \`${tool("list_assets")}\` — 列出照片/视频`,
|
|
1927
|
+
`- \`${tool("search_metadata")}\` — 按结构化元数据搜索`,
|
|
1928
|
+
`- \`${tool("search_smart")}\` — 用自然语言或相似图片获取 Immich Smart Search / CLIP 相似候选排序`,
|
|
1929
|
+
`- \`${tool("get_asset_info")}\` — 查看单个资源`,
|
|
1930
|
+
`- \`${tool("list_albums")}\` / \`${tool("get_album")}\` / \`${tool("delete_album")}\` — 相册`,
|
|
1931
|
+
`- \`${tool("list_tags")}\` / \`${tool("get_tag")}\` / \`${tool("delete_tag")}\` — 标签`,
|
|
1932
|
+
`- \`${tool("list_people")}\` / \`${tool("search_people")}\` — 人物`,
|
|
1933
|
+
`- \`${tool("get_duplicates")}\` — 重复项`,
|
|
1934
|
+
`- \`${tool("generate_review_gallery")}\` — 创建用户自选照片的 review 页面;确认后 Core 直接执行`,
|
|
1935
|
+
"",
|
|
1936
|
+
"**标准工具策略**:",
|
|
1937
|
+
`1. 先按用户意图选择工具,不要用 shell、mcporter 或 memory_search 代替 Immich MCP。健康检查用 \`${tool("get_library_summary")}\` / \`${tool("ping")}\`;扫描用 \`${tool("scan_photo_library")}\`,返回 \`scan_queued\` 时只说明扫描已开始,不要声称所有照片已经导入完成;上传用 \`${tool("create_photo_upload_session")}\`,上传页面可在过期前连续完成多个批次。`,
|
|
1938
|
+
`2. 读取和搜索只负责收集候选资源:普通列表用 \`${tool("list_assets")}\`,结构化条件搜索用 \`${tool("search_metadata")}\`,自然语言视觉语义或“找相似照片”用 \`${tool("search_smart")}\`,相册内容用 \`${tool("get_album")}\`,重复项用 \`${tool("get_duplicates")}\`。工具返回短 JSON 和 asset id;不要把 thumbnail base64、文件内容或大量 asset id 展示给用户。`,
|
|
1939
|
+
` \`${tool("search_smart")}\` 的实际语义是 Immich 返回一页按语义相似度排序的候选,默认 \`size=50\`、最大 \`100\`;它不是二分类器,也不保证返回“所有符合条件”的照片。小图库里可能几乎所有照片都会出现在第一页。向用户表述时使用“相似候选 / 候选结果 / 排序结果”,不要说“已经找到了所有 X 照片”或“这些全都是 X”。`,
|
|
1940
|
+
`3. 相册和标签是目标容器。用户要求把照片加入某个新相册或新标签时,先用 \`${tool("create_album")}\` 或 \`${tool("create_tag")}\` 创建目标;如果目标是否存在或应复用不明确,先查列表或向用户确认。`,
|
|
1941
|
+
`4. 删除相册或标签前,必须先用 \`${tool("get_album")}\` / \`${tool("get_tag")}\` 或列表结果核对资源名称和 id,并在对话里明确询问用户确认。调用 \`${tool("delete_album")}\` 不会删除照片;调用 \`${tool("delete_tag")}\` 不会删除照片,但会把该标签从所有关联照片上移除。`,
|
|
1942
|
+
`5. 所有需要用户从候选照片中确认子集、确认批量修改、或决定哪些重复项应处理的操作,都必须通过 \`${tool("generate_review_gallery")}\` 创建 review interaction。适用动作包括加入/移出相册、打标签/取消标签、移入回收站、处理重复项。`,
|
|
1943
|
+
`6. 对搜索驱动的批量操作采用通用的 human-in-the-loop 候选审核流程:先用读取/搜索工具得到候选集,把需要用户可见审核的候选放入 \`asset_ids\`;只有能解释清楚依据的高置信项才放入 \`preselected_asset_ids\`,让 review UI 默认勾选。最终执行仍以用户在页面中的确认和修改为准。`,
|
|
1944
|
+
`7. 不要把所有 CLIP 命中无条件当作推荐项。Smart Search 结果只能直接作为候选,推荐项应基于多信号判断:分数 score(如果工具返回)、搜索排名、文件名、相册/标签/人物、地点、日期、资源类型等。精确结构化条件、明确 asset id、或用户给出的确定集合可以默认全选;纯视觉搜索且缺少可靠阈值或存在歧义时,只预选高置信项,不能判断的保持未选,必要时先请用户缩小条件。`,
|
|
1945
|
+
`8. 用户表达“所有/全部/帮我找并加入/自动整理”时,不要把筛选工作完全丢给用户;应创建 review 页面给出候选,并在有高置信推荐项时默认选中。若候选只来自 Smart Search 且无法可靠区分,应明确说明这是相似候选排序,需要用户在页面中最终确认,而不是假装已经自动识别全部。用户表达“我来选、从图库挑、让我自己选择、选择几张”时,省略 \`preselected_asset_ids\`,让用户手动选择。`,
|
|
1946
|
+
`9. 调用 \`${tool("generate_review_gallery")}\` 时,\`action\` 必须使用工具 schema 中的枚举原值:\`add_assets_to_album\`、\`remove_assets_from_album\`、\`tag_assets\`、\`untag_assets\`、\`delete_assets_to_trash\`、\`resolve_duplicates\`。不要自造 \`add-to-album\`、\`select-assets\`、\`manage-album\` 等动作名。`,
|
|
1947
|
+
`10. 创建 review interaction 后,只把返回的 \`urls.web\` 和简短说明发给用户。如果提供了 \`preselected_asset_ids\`,说明“已默认选中推荐项,可直接确认或取消误选”;如果没有预选项,说明“这是候选页面,需要你确认哪些要处理”。用户在页面点击确认后,Core 会直接执行;不要要求用户回到对话框继续确认,也不要自行声称已经执行,除非工具返回的执行状态明确表示完成。`,
|
|
1948
|
+
"11. 如果候选集过大或用户意图不足以确定候选范围,先请用户用时间、地点、收藏、文件名、相册、标签、人物或其他结构化条件缩小范围;不要为了避免使用 review UI 而先列编号让用户在对话里挑。",
|
|
1949
|
+
"12. 删除照片只表示移入 Immich 回收站。永久删除和清空回收站不可用,不要声称已经永久删除。",
|
|
1950
|
+
"13. MCP 调用失败时,原样说明工具错误;不要改用 shell 猜测工具参数,也不要据此断言 Immich 未安装。",
|
|
1951
|
+
"",
|
|
1952
|
+
JISHUSHELL_IMMICH_HINT_END,
|
|
1953
|
+
"",
|
|
1954
|
+
].join("\n");
|
|
1955
|
+
const sep = stripped && !stripped.endsWith("\n") ? "\n\n" : "\n";
|
|
1956
|
+
next = (stripped ? stripped + sep : "") + section;
|
|
1957
|
+
}
|
|
1958
|
+
if (next === original)
|
|
1959
|
+
return;
|
|
1960
|
+
writeConfigFile(toolsPath, next);
|
|
1961
|
+
console.log(`[openclaw] ${mode === "remove" ? "Removed" : "Patched"} immich hint in ${toolsPath}`);
|
|
1962
|
+
}
|
|
1963
|
+
catch (e) {
|
|
1964
|
+
console.warn(`[openclaw] Failed to ${mode} TOOLS.md immich hint: ${e.message}`);
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1818
1967
|
/**
|
|
1819
1968
|
* Pre-seed the per-instance npm global prefix with a symlink to the image's
|
|
1820
1969
|
* baked openclaw package so OpenClaw's in-gateway "Update now" handler can
|
|
@@ -2302,6 +2451,75 @@ function assertSafeTemplateId(id) {
|
|
|
2302
2451
|
async function lazyIm() {
|
|
2303
2452
|
return await import("../../instances/manager.js");
|
|
2304
2453
|
}
|
|
2454
|
+
async function resolveCoreConnectionForOpenclaw(instanceId) {
|
|
2455
|
+
const corePort = getCorePort();
|
|
2456
|
+
let coreHost = "host.docker.internal";
|
|
2457
|
+
try {
|
|
2458
|
+
const im = await lazyIm();
|
|
2459
|
+
const runtime = im.getInstanceRuntime(instanceId);
|
|
2460
|
+
if (!runtime?.image)
|
|
2461
|
+
coreHost = getCoreLanHost();
|
|
2462
|
+
}
|
|
2463
|
+
catch (error) {
|
|
2464
|
+
console.warn(`[openclaw] core URL runtime detection failed for ${instanceId}; using container-reachable host:`, error);
|
|
2465
|
+
}
|
|
2466
|
+
return {
|
|
2467
|
+
coreUrl: `http://${coreHost}:${corePort}`,
|
|
2468
|
+
internalToken: getInternalMcpToken(),
|
|
2469
|
+
};
|
|
2470
|
+
}
|
|
2471
|
+
async function syncImmichMcpForOpenclawInstance(instanceId) {
|
|
2472
|
+
const home = openclawIntegration.resolveAgentHome(instanceId);
|
|
2473
|
+
const configPath = openclawConfigPath(instanceId, home);
|
|
2474
|
+
const { resolveImmichConfig, } = await import("../immich/config.js");
|
|
2475
|
+
const config = await resolveImmichConfig();
|
|
2476
|
+
const source = {
|
|
2477
|
+
kind: "connection",
|
|
2478
|
+
slot: "photos",
|
|
2479
|
+
consumerInstanceId: instanceId,
|
|
2480
|
+
};
|
|
2481
|
+
const shimDir = join(home, "__mcp_shims__", "immich");
|
|
2482
|
+
const shimPath = join(shimDir, "immich-shim.js");
|
|
2483
|
+
const secretPath = join(shimDir, "secret.json");
|
|
2484
|
+
const wsDir = join(home, ".openclaw", "workspace");
|
|
2485
|
+
if (config?.baseUrl && config.apiKey) {
|
|
2486
|
+
const { IMMICH_SHIM_SECRET_FILENAME, substituteImmichShimPlaceholders, } = await import("../immich/immich-shim.js");
|
|
2487
|
+
ensureDirContainer(shimDir);
|
|
2488
|
+
const { coreUrl, internalToken, } = await resolveCoreConnectionForOpenclaw(instanceId);
|
|
2489
|
+
writeFileSync(shimPath, substituteImmichShimPlaceholders({
|
|
2490
|
+
baseUrl: config.baseUrl,
|
|
2491
|
+
photoLibraryEnabled: config.mode === "managed",
|
|
2492
|
+
coreUrl,
|
|
2493
|
+
instanceId,
|
|
2494
|
+
}), { mode: 0o644 });
|
|
2495
|
+
writeFileSync(join(shimDir, IMMICH_SHIM_SECRET_FILENAME), JSON.stringify({ apiKey: config.apiKey, internalToken }) + "\n", { mode: 0o600 });
|
|
2496
|
+
try {
|
|
2497
|
+
chmodSync(secretPath, 0o600);
|
|
2498
|
+
}
|
|
2499
|
+
catch { /* best effort */ }
|
|
2500
|
+
const nativeServerName = upsertOpenclawMcpServer(configPath, "immich", {
|
|
2501
|
+
command: "node",
|
|
2502
|
+
args: [shimPath],
|
|
2503
|
+
__source: source,
|
|
2504
|
+
});
|
|
2505
|
+
if (!nativeServerName)
|
|
2506
|
+
return "missing-config";
|
|
2507
|
+
removeMcporterServers(instanceId, { source });
|
|
2508
|
+
patchToolsMdImmichHint(wsDir, "install", nativeServerName);
|
|
2509
|
+
notifyConfigChange(instanceId);
|
|
2510
|
+
return "installed";
|
|
2511
|
+
}
|
|
2512
|
+
removeOpenclawMcpServers(configPath, { source });
|
|
2513
|
+
removeMcporterServers(instanceId, { source });
|
|
2514
|
+
rmSync(shimDir, { recursive: true, force: true });
|
|
2515
|
+
patchToolsMdImmichHint(wsDir, "remove");
|
|
2516
|
+
notifyConfigChange(instanceId);
|
|
2517
|
+
return "removed";
|
|
2518
|
+
}
|
|
2519
|
+
function isOpenclawInstanceMetadata(instance) {
|
|
2520
|
+
return Array.isArray(instance.integrations)
|
|
2521
|
+
&& instance.integrations.some((entry) => entry?.kind === "openclaw");
|
|
2522
|
+
}
|
|
2305
2523
|
// ── Docker image build helpers (physically migrated from setup-manager) ─
|
|
2306
2524
|
//
|
|
2307
2525
|
// All OpenClaw-specific docker image build knowledge lives here. setup-manager
|
|
@@ -2482,71 +2700,6 @@ async function pullOrBuildOpenclawImageWithTask(task, tag) {
|
|
|
2482
2700
|
};
|
|
2483
2701
|
}
|
|
2484
2702
|
}
|
|
2485
|
-
function sanitizeConnectionMcpName(name) {
|
|
2486
|
-
return name.replace(/[^a-zA-Z0-9_-]/g, "-").slice(0, 64);
|
|
2487
|
-
}
|
|
2488
|
-
function connectionMcpTransport(protocol) {
|
|
2489
|
-
switch ((protocol || "").toLowerCase()) {
|
|
2490
|
-
case "http":
|
|
2491
|
-
case "https":
|
|
2492
|
-
return "http";
|
|
2493
|
-
case "sse":
|
|
2494
|
-
case "ws":
|
|
2495
|
-
case "wss":
|
|
2496
|
-
return "sse";
|
|
2497
|
-
default:
|
|
2498
|
-
return undefined;
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
function isIPv6Host(host) {
|
|
2502
|
-
return /:.*:/.test(host) && !host.startsWith("[");
|
|
2503
|
-
}
|
|
2504
|
-
function bracketIPv6Host(host) {
|
|
2505
|
-
return isIPv6Host(host) ? `[${host}]` : host;
|
|
2506
|
-
}
|
|
2507
|
-
function buildConnectionHttpBaseUrl(entry) {
|
|
2508
|
-
const protocol = entry.protocol === "https" ? "https" : "http";
|
|
2509
|
-
const url = new URL(`${protocol}://${bracketIPv6Host(entry.host)}:${entry.hostPort}`);
|
|
2510
|
-
if (entry.path && entry.path !== "/")
|
|
2511
|
-
url.pathname = entry.path;
|
|
2512
|
-
return url.toString().replace(/\/$/, "");
|
|
2513
|
-
}
|
|
2514
|
-
function applyOpenClawMcpBinding(args) {
|
|
2515
|
-
const { instanceId, binding } = args;
|
|
2516
|
-
if (binding.category !== "mcp" || binding.entries.length === 0)
|
|
2517
|
-
return;
|
|
2518
|
-
const source = {
|
|
2519
|
-
kind: "connection",
|
|
2520
|
-
slot: binding.slot,
|
|
2521
|
-
consumerInstanceId: instanceId,
|
|
2522
|
-
};
|
|
2523
|
-
// Replace-style: drop prior connection-managed entries for this
|
|
2524
|
-
// (slot, consumer) pair, then merge the currently resolved providers.
|
|
2525
|
-
removeMcporterServers(instanceId, { source });
|
|
2526
|
-
const servers = {};
|
|
2527
|
-
for (const entry of binding.entries) {
|
|
2528
|
-
const name = sanitizeConnectionMcpName(`${entry.capability}-${entry.instanceId}`);
|
|
2529
|
-
const transport = connectionMcpTransport(entry.protocol);
|
|
2530
|
-
const url = transport === "stdio" ? undefined : buildConnectionHttpBaseUrl(entry);
|
|
2531
|
-
servers[name] = {
|
|
2532
|
-
...(transport ? { transport } : {}),
|
|
2533
|
-
...(url ? { url } : {}),
|
|
2534
|
-
__source: source,
|
|
2535
|
-
};
|
|
2536
|
-
}
|
|
2537
|
-
mergeMcporterServers(instanceId, servers);
|
|
2538
|
-
}
|
|
2539
|
-
function unapplyOpenClawMcpBinding(args) {
|
|
2540
|
-
if (args.category !== "mcp")
|
|
2541
|
-
return;
|
|
2542
|
-
removeMcporterServers(args.instanceId, {
|
|
2543
|
-
source: {
|
|
2544
|
-
kind: "connection",
|
|
2545
|
-
slot: args.slot,
|
|
2546
|
-
consumerInstanceId: args.instanceId,
|
|
2547
|
-
},
|
|
2548
|
-
});
|
|
2549
|
-
}
|
|
2550
2703
|
// ── OpenClawIntegration class ─────────────────────────────────────────────
|
|
2551
2704
|
class OpenClawIntegration {
|
|
2552
2705
|
kind = "openclaw";
|
|
@@ -2765,7 +2918,6 @@ class OpenClawIntegration {
|
|
|
2765
2918
|
if (home) {
|
|
2766
2919
|
const { substituteDriveShimPlaceholders } = await import("./drive-shim.js");
|
|
2767
2920
|
const { mergeMcporterServers } = await import("./mcporter.js");
|
|
2768
|
-
const { getInternalMcpToken } = await import("../../../config.js");
|
|
2769
2921
|
// Pick the core URL based on how THIS instance will actually run.
|
|
2770
2922
|
// For a containerized instance (raw_exec/docker via Nomad with a
|
|
2771
2923
|
// docker image), `host.docker.internal:<corePort>` resolves through
|
|
@@ -2776,18 +2928,7 @@ class OpenClawIntegration {
|
|
|
2776
2928
|
// Detected via the instance's resolved runtime: container tasks
|
|
2777
2929
|
// carry `runtime.image`, binary tasks carry only `runtime.command`.
|
|
2778
2930
|
const corePort = getCorePort();
|
|
2779
|
-
|
|
2780
|
-
try {
|
|
2781
|
-
const im2 = await lazyIm();
|
|
2782
|
-
const rt = im2.getInstanceRuntime(instanceId);
|
|
2783
|
-
if (!rt?.image) {
|
|
2784
|
-
driveCoreHost = getCoreLanHost();
|
|
2785
|
-
}
|
|
2786
|
-
}
|
|
2787
|
-
catch (e) {
|
|
2788
|
-
console.warn(`[openclaw] drive shim runtime detection failed for ${instanceId}; using container-reachable core host:`, e);
|
|
2789
|
-
}
|
|
2790
|
-
const driveCoreUrl = `http://${driveCoreHost}:${corePort}`;
|
|
2931
|
+
const { coreUrl: driveCoreUrl, internalToken, } = await resolveCoreConnectionForOpenclaw(instanceId);
|
|
2791
2932
|
const shimDir = join(home, "__mcp_shims__", "drive");
|
|
2792
2933
|
ensureDirContainer(shimDir);
|
|
2793
2934
|
const shimPath = join(shimDir, "drive-shim.mjs");
|
|
@@ -2795,7 +2936,6 @@ class OpenClawIntegration {
|
|
|
2795
2936
|
// even when OpenClaw scrubs env on MCP subprocess spawn (verified
|
|
2796
2937
|
// 2026-05-11 on pi2: env scrub made the shim default to the
|
|
2797
2938
|
// unreachable host.docker.internal and surface as "fetch failed").
|
|
2798
|
-
const internalToken = getInternalMcpToken();
|
|
2799
2939
|
const shimSource = substituteDriveShimPlaceholders({
|
|
2800
2940
|
coreUrl: driveCoreUrl,
|
|
2801
2941
|
token: internalToken,
|
|
@@ -2853,7 +2993,8 @@ class OpenClawIntegration {
|
|
|
2853
2993
|
// the API key lives in a sibling `secret.json` (0o600).
|
|
2854
2994
|
// - mcporter.json (0o644) env carries only non-secret hints
|
|
2855
2995
|
// for hand-running. Production shim reads the secret file.
|
|
2856
|
-
//
|
|
2996
|
+
// JishuKB remote MCP auth is stored on the managed KB runtime and
|
|
2997
|
+
// provider credentials, not in the legacy shim directory.
|
|
2857
2998
|
try {
|
|
2858
2999
|
const home = openclawIntegration.resolveAgentHome(instanceId);
|
|
2859
3000
|
if (home) {
|
|
@@ -2864,9 +3005,22 @@ class OpenClawIntegration {
|
|
|
2864
3005
|
const anyllmShimDir = join(home, "__mcp_shims__", "anythingllm");
|
|
2865
3006
|
const anyllmShimPath = join(anyllmShimDir, "anythingllm-shim.js");
|
|
2866
3007
|
const anyllmSecretPath = join(anyllmShimDir, "secret.json");
|
|
2867
|
-
const jishukbShimDir = join(home, "__mcp_shims__", "jishukb");
|
|
2868
|
-
const jishukbShimPath = join(jishukbShimDir, "jishukb-shim.js");
|
|
2869
3008
|
const { mergeMcporterServers, removeMcporterServers } = await import("./mcporter.js");
|
|
3009
|
+
const { removeOpenclawMcpServers, upsertFixedOpenclawMcpServer } = await import("./native-mcp.js");
|
|
3010
|
+
const kbSource = { kind: "connection", slot: "knowledge", consumerInstanceId: instanceId };
|
|
3011
|
+
const openclawCfgPath = openclawConfigPath(instanceId, home);
|
|
3012
|
+
const cleanupManagedKb = (unavailableReason) => {
|
|
3013
|
+
removeMcporterServers(instanceId, { source: kbSource });
|
|
3014
|
+
removeOpenclawMcpServers(openclawCfgPath, { source: kbSource });
|
|
3015
|
+
notifyConfigChange(instanceId);
|
|
3016
|
+
if (unavailableReason) {
|
|
3017
|
+
patchToolsMdKbUnavailableHint(wsDir, unavailableReason);
|
|
3018
|
+
}
|
|
3019
|
+
else {
|
|
3020
|
+
patchToolsMdKbHint(wsDir, "remove");
|
|
3021
|
+
}
|
|
3022
|
+
wipeKbShimDir(home, "jishukb");
|
|
3023
|
+
};
|
|
2870
3024
|
if (provider === "jishukb") {
|
|
2871
3025
|
// Wipe the OTHER provider's residue first (including its
|
|
2872
3026
|
// 0o600 secret.json). Security smell to leave it on disk.
|
|
@@ -2882,50 +3036,80 @@ class OpenClawIntegration {
|
|
|
2882
3036
|
}
|
|
2883
3037
|
}
|
|
2884
3038
|
if (creds?.baseUrl) {
|
|
2885
|
-
const
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
const
|
|
3039
|
+
const mediaInbound = join(home, ".openclaw", "media", "inbound");
|
|
3040
|
+
ensureDirContainer(mediaInbound);
|
|
3041
|
+
const authToken = typeof creds.mcpAuthToken === "string" ? creds.mcpAuthToken.trim() : "";
|
|
3042
|
+
const { discoverJishukbRemoteMcp, preflightJishukbRemoteMcp } = await import("./jishukb-native-mcp.js");
|
|
3043
|
+
const discovery = await discoverJishukbRemoteMcp({
|
|
2889
3044
|
baseUrl: creds.baseUrl,
|
|
2890
|
-
|
|
2891
|
-
|
|
3045
|
+
authToken,
|
|
3046
|
+
expectedProfile: "openclaw",
|
|
2892
3047
|
});
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
kb: {
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
}
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
3048
|
+
if (!discovery.ok || !discovery.url) {
|
|
3049
|
+
const reason = `remote jishu-kb MCP discovery failed: ${discovery.reason || "no endpoint"}`;
|
|
3050
|
+
console.warn(`[openclaw] kb: ${reason}`);
|
|
3051
|
+
cleanupManagedKb(reason);
|
|
3052
|
+
}
|
|
3053
|
+
else {
|
|
3054
|
+
if (discovery.authRequired && !authToken) {
|
|
3055
|
+
const reason = "remote jishu-kb MCP requires bearer auth but credentials are missing mcpAuthToken";
|
|
3056
|
+
console.warn(`[openclaw] kb: ${reason}`);
|
|
3057
|
+
cleanupManagedKb(reason);
|
|
3058
|
+
}
|
|
3059
|
+
else {
|
|
3060
|
+
const preflight = await preflightJishukbRemoteMcp({
|
|
3061
|
+
url: discovery.url,
|
|
3062
|
+
authToken,
|
|
3063
|
+
expectedProfile: "openclaw",
|
|
3064
|
+
});
|
|
3065
|
+
if (!preflight.ok) {
|
|
3066
|
+
const reason = `remote jishu-kb MCP preflight failed: ${preflight.reason}`;
|
|
3067
|
+
console.warn(`[openclaw] kb: ${reason}`);
|
|
3068
|
+
cleanupManagedKb(reason);
|
|
3069
|
+
}
|
|
3070
|
+
else {
|
|
3071
|
+
const registeredUrl = rewriteJishukbMcpUrlForOpenClawRuntime(discovery.url, instMeta?.runtime ?? {});
|
|
3072
|
+
const entry = {
|
|
3073
|
+
url: registeredUrl,
|
|
3074
|
+
transport: "streamable-http",
|
|
3075
|
+
connectionTimeoutMs: 8_000,
|
|
3076
|
+
__source: kbSource,
|
|
3077
|
+
};
|
|
3078
|
+
if (authToken) {
|
|
3079
|
+
entry.headers = { Authorization: `Bearer ${authToken}` };
|
|
3080
|
+
}
|
|
3081
|
+
wipeKbShimDir(home, "jishukb");
|
|
3082
|
+
removeMcporterServers(instanceId, { source: kbSource });
|
|
3083
|
+
const result = upsertFixedOpenclawMcpServer(openclawCfgPath, "kb", entry);
|
|
3084
|
+
if (!result.ok) {
|
|
3085
|
+
const reason = result.reason === "name-conflict"
|
|
3086
|
+
? "user-managed native MCP server 'kb' blocks managed JishuKB registration"
|
|
3087
|
+
: "OpenClaw native config is missing; managed JishuKB registration skipped";
|
|
3088
|
+
console.warn(`[openclaw] kb: ${reason}`);
|
|
3089
|
+
cleanupManagedKb(reason);
|
|
3090
|
+
}
|
|
3091
|
+
else {
|
|
3092
|
+
notifyConfigChange(instanceId);
|
|
3093
|
+
patchToolsMdKbHint(wsDir, "install", "jishukb", "native", instanceId, mediaInbound);
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
2913
3098
|
}
|
|
2914
3099
|
else {
|
|
2915
3100
|
// jishu-kb bound but baseUrl not yet ready / credentials missing.
|
|
2916
3101
|
// Remove any prior kb registration so the agent doesn't
|
|
2917
3102
|
// call a stale shim, and wipe our own shim dir for hygiene.
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
});
|
|
2922
|
-
patchToolsMdKbHint(wsDir, "remove");
|
|
2923
|
-
wipeKbShimDir(home, "jishukb");
|
|
3103
|
+
const reason = `jishu-kb bound but baseUrl missing at ${credPath}; native MCP registration skipped`;
|
|
3104
|
+
console.warn(`[openclaw] kb: ${reason}`);
|
|
3105
|
+
cleanupManagedKb(reason);
|
|
2924
3106
|
}
|
|
2925
3107
|
}
|
|
2926
3108
|
else if (provider === "anythingllm") {
|
|
2927
3109
|
// Wipe the OTHER provider's residue first.
|
|
2928
3110
|
wipeKbShimDir(home, "jishukb");
|
|
3111
|
+
removeOpenclawMcpServers(openclawCfgPath, { source: kbSource });
|
|
3112
|
+
notifyConfigChange(instanceId);
|
|
2929
3113
|
const credPath = resolveProviderCredentialsPath("anythingllm-container");
|
|
2930
3114
|
let kbCreds = null;
|
|
2931
3115
|
if (existsSync(credPath)) {
|
|
@@ -2986,18 +3170,26 @@ class OpenClawIntegration {
|
|
|
2986
3170
|
// provider === null → user explicitly unbound, or bound to
|
|
2987
3171
|
// an unknown/unsupported provider. Strip kb server and wipe
|
|
2988
3172
|
// both shim dirs.
|
|
2989
|
-
|
|
2990
|
-
source: { kind: "connection", slot: "knowledge", consumerInstanceId: instanceId },
|
|
2991
|
-
});
|
|
2992
|
-
patchToolsMdKbHint(wsDir, "remove");
|
|
3173
|
+
cleanupManagedKb();
|
|
2993
3174
|
wipeKbShimDir(home, "anythingllm");
|
|
2994
|
-
wipeKbShimDir(home, "jishukb");
|
|
2995
3175
|
}
|
|
2996
3176
|
}
|
|
2997
3177
|
}
|
|
2998
3178
|
catch (e) {
|
|
2999
3179
|
console.warn(`[openclaw] kb shim wiring skipped: ${e?.message ?? e}`);
|
|
3000
3180
|
}
|
|
3181
|
+
// 4c-quinquies. Auto-wire Immich MCP when the Immich integration has
|
|
3182
|
+
// endpoint credentials. The endpoint can be external or a managed
|
|
3183
|
+
// immich-container instance. OpenClaw receives the stdio shim through
|
|
3184
|
+
// its native `mcp.servers` config, the API key and Core internal token
|
|
3185
|
+
// stay in a 0o600 sibling secret file, and user review interactions are
|
|
3186
|
+
// created through Core-owned Immich routes.
|
|
3187
|
+
try {
|
|
3188
|
+
await syncImmichMcpForOpenclawInstance(instanceId);
|
|
3189
|
+
}
|
|
3190
|
+
catch (e) {
|
|
3191
|
+
console.warn(`[openclaw] immich shim wiring skipped: ${e?.message ?? e}`);
|
|
3192
|
+
}
|
|
3001
3193
|
// 4c-bis. Self-heal MCPORTER_CONFIG env on existing instances. Without
|
|
3002
3194
|
// this, mcporter can't find its config when invoked from the
|
|
3003
3195
|
// gateway's CWD (openclaw-home/) or from the workspace symlink
|
|
@@ -3523,9 +3715,8 @@ class OpenClawIntegration {
|
|
|
3523
3715
|
* it the `web_search` tool defaults to Brave and fails with
|
|
3524
3716
|
* `missing_brave_api_key` even when the searxng plugin is fully configured.
|
|
3525
3717
|
*
|
|
3526
|
-
* Browser / LLM
|
|
3527
|
-
*
|
|
3528
|
-
* mcp already wired via the OpenClaw mcporter helper).
|
|
3718
|
+
* Browser / LLM wiring needs its own config-shape mapping
|
|
3719
|
+
* (browser → tools.browser, llm → models.providers).
|
|
3529
3720
|
*
|
|
3530
3721
|
* The write goes through `saveNativeConfig` which preserves relevant fields
|
|
3531
3722
|
* from the existing canonical on-disk config, so user-managed plugin entries (e.g.
|
|
@@ -3604,12 +3795,6 @@ class OpenClawIntegration {
|
|
|
3604
3795
|
// write a URL OpenClaw can't dial.
|
|
3605
3796
|
}
|
|
3606
3797
|
}
|
|
3607
|
-
async applyConnectionBinding(args) {
|
|
3608
|
-
applyOpenClawMcpBinding(args);
|
|
3609
|
-
}
|
|
3610
|
-
async unapplyConnectionBinding(args) {
|
|
3611
|
-
unapplyOpenClawMcpBinding(args);
|
|
3612
|
-
}
|
|
3613
3798
|
listConnectionSideEffectFiles(args) {
|
|
3614
3799
|
const home = openclawHomeFromMetadata(getInstance(args.instanceId), args.instanceId);
|
|
3615
3800
|
const envFile = getRuntimeEnvFiles(args.instanceId)[0] ?? defaultOpenclawModelEnvFile(args.instanceId);
|
|
@@ -3638,6 +3823,25 @@ class OpenClawIntegration {
|
|
|
3638
3823
|
summarizeRecentBrowserSession(instanceId) {
|
|
3639
3824
|
return summarizeRecentOpenclawBrowserSession(instanceId);
|
|
3640
3825
|
}
|
|
3826
|
+
async syncImmichMcpForAllInstances() {
|
|
3827
|
+
const updated = [];
|
|
3828
|
+
const skipped = [];
|
|
3829
|
+
for (const instance of listInstances()) {
|
|
3830
|
+
const instanceId = typeof instance.id === "string" ? instance.id : "";
|
|
3831
|
+
if (!instanceId)
|
|
3832
|
+
continue;
|
|
3833
|
+
try {
|
|
3834
|
+
if (!isOpenclawInstanceMetadata(instance))
|
|
3835
|
+
continue;
|
|
3836
|
+
await syncImmichMcpForOpenclawInstance(instanceId);
|
|
3837
|
+
updated.push(instanceId);
|
|
3838
|
+
}
|
|
3839
|
+
catch (error) {
|
|
3840
|
+
skipped.push({ instanceId, error: error?.message ?? String(error) });
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
return { updated, skipped };
|
|
3844
|
+
}
|
|
3641
3845
|
/** Env vars OpenClaw's CLI needs when backup-manager runs it as a subprocess. */
|
|
3642
3846
|
buildCliEnv(instanceId) {
|
|
3643
3847
|
return { OPENCLAW_HOME: this.resolveAgentHome(instanceId) };
|
|
@@ -3906,7 +4110,6 @@ class OpenClawIntegration {
|
|
|
3906
4110
|
getInstallStatus() {
|
|
3907
4111
|
// OPENCLAW_MODULES may be undefined when config is partially mocked in tests.
|
|
3908
4112
|
const pkgInstalled = OPENCLAW_MODULES ? existsSync(join(OPENCLAW_MODULES, "openclaw")) : false;
|
|
3909
|
-
const version = pkgInstalled ? readInstalledOpenclawVersion() : undefined;
|
|
3910
4113
|
const imageTag = getOpenclawDockerImage?.() ?? "";
|
|
3911
4114
|
let imageReady = false;
|
|
3912
4115
|
try {
|
|
@@ -3920,6 +4123,14 @@ class OpenClawIntegration {
|
|
|
3920
4123
|
}
|
|
3921
4124
|
}
|
|
3922
4125
|
catch { /* image absent */ }
|
|
4126
|
+
// Prefer the version pinned into the docker image tag — that is what
|
|
4127
|
+
// instances actually run in the default docker deployment. The host-npm
|
|
4128
|
+
// package.json (readInstalledOpenclawVersion) is unrelated to the running
|
|
4129
|
+
// container, so reporting it made the UI show "latest" while the container
|
|
4130
|
+
// still ran the old build after an update. Fall back to host-npm only when
|
|
4131
|
+
// no image is ready (legacy npm path).
|
|
4132
|
+
const imageVersion = imageReady ? versionFromImageTag(imageTag) : "";
|
|
4133
|
+
const version = imageVersion || (pkgInstalled ? readInstalledOpenclawVersion() : "");
|
|
3923
4134
|
return {
|
|
3924
4135
|
installed: imageReady || pkgInstalled,
|
|
3925
4136
|
imageReady,
|
|
@@ -3940,6 +4151,22 @@ function readInstalledOpenclawVersion() {
|
|
|
3940
4151
|
}
|
|
3941
4152
|
return "";
|
|
3942
4153
|
}
|
|
4154
|
+
/**
|
|
4155
|
+
* Extract a semver-ish version from a pinned image tag, e.g.
|
|
4156
|
+
* `ghcr.io/x-aijishu/openclaw-runtime:2026.6.10` -> `2026.6.10`. Returns "" when
|
|
4157
|
+
* the tag carries no version (mutable `:latest`/`:slim`, or the only colon is a
|
|
4158
|
+
* registry port).
|
|
4159
|
+
*/
|
|
4160
|
+
function versionFromImageTag(imageTag) {
|
|
4161
|
+
if (!imageTag)
|
|
4162
|
+
return "";
|
|
4163
|
+
const colonIdx = imageTag.lastIndexOf(":");
|
|
4164
|
+
const slashIdx = imageTag.lastIndexOf("/");
|
|
4165
|
+
if (colonIdx <= slashIdx)
|
|
4166
|
+
return "";
|
|
4167
|
+
const tag = imageTag.slice(colonIdx + 1);
|
|
4168
|
+
return /^\d+\.\d+\.\d+/.test(tag) ? tag : "";
|
|
4169
|
+
}
|
|
3943
4170
|
// Feishu app IDs issued by the open platform follow `cli_<hex/alnum>`.
|
|
3944
4171
|
const FEISHU_APP_ID_RE = /^cli_[a-zA-Z0-9]{8,64}$/;
|
|
3945
4172
|
const SAFE_ACCOUNT_ID_RE = /^[a-zA-Z0-9@._-]{1,128}$/;
|