jishushell 0.6.5 → 0.6.18
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 +15 -170
- package/apps/browserless-chromium-container.yaml +15 -10
- package/apps/filebrowser-container.yaml +14 -9
- package/apps/hermes-container.yaml +23 -2
- package/apps/jishu-kb-container.yaml +29 -161
- package/apps/ollama-binary.yaml +32 -28
- package/apps/ollama-cpu-container.yaml +5 -0
- package/apps/ollama-with-hollama-binary.yaml +33 -28
- package/apps/openclaw-binary.yaml +34 -10
- package/apps/openclaw-container.yaml +31 -7
- package/apps/openclaw-with-ollama-container.yaml +8 -2
- package/apps/openclaw-with-searxng-container.yaml +18 -6
- package/apps/searxng-container.yaml +11 -6
- package/apps/weknora-container.yaml +21 -21
- package/dependencies/jishushell-panel-0.6.18.tgz +0 -0
- package/dist/cli/app.js +244 -213
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/backup.js +15 -12
- package/dist/cli/backup.js.map +1 -1
- package/dist/cli/core.d.ts +4 -3
- package/dist/cli/core.js +392 -227
- package/dist/cli/core.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.js +17 -10
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/job.js +62 -14
- package/dist/cli/job.js.map +1 -1
- package/dist/cli/llm.js +80 -11
- package/dist/cli/llm.js.map +1 -1
- package/dist/cli/managed-list.d.ts +1 -3
- package/dist/cli/managed-list.js +18 -16
- package/dist/cli/managed-list.js.map +1 -1
- package/dist/cli/migrate.d.ts +2 -0
- package/dist/cli/migrate.js +160 -0
- package/dist/cli/migrate.js.map +1 -0
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +23 -19
- package/dist/config.js +60 -49
- package/dist/config.js.map +1 -1
- package/dist/control.d.ts +6 -6
- package/dist/control.js +31 -23
- package/dist/control.js.map +1 -1
- package/dist/core.d.ts +5 -5
- package/dist/core.js +5 -5
- package/dist/core.js.map +1 -1
- package/dist/install.d.ts +2 -2
- package/dist/install.js +18 -18
- package/dist/install.js.map +1 -1
- package/dist/routes/apps.d.ts +1 -1
- package/dist/routes/apps.js +101 -193
- package/dist/routes/apps.js.map +1 -1
- package/dist/routes/auth.js +1 -1
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/backup.js +1 -1
- package/dist/routes/backup.js.map +1 -1
- package/dist/routes/external-mounts.d.ts +1 -1
- package/dist/routes/external-mounts.js +1 -1
- package/dist/routes/external-mounts.js.map +1 -1
- package/dist/routes/file-mounts.d.ts +4 -3
- package/dist/routes/file-mounts.js +51 -30
- package/dist/routes/file-mounts.js.map +1 -1
- package/dist/routes/files-organize.d.ts +2 -2
- package/dist/routes/files-organize.js +5 -5
- package/dist/routes/files-organize.js.map +1 -1
- package/dist/routes/files.d.ts +1 -1
- package/dist/routes/files.js +1 -1
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/instances.d.ts +10 -4
- package/dist/routes/instances.js +323 -541
- package/dist/routes/instances.js.map +1 -1
- package/dist/routes/integration-apps.d.ts +14 -0
- package/dist/routes/integration-apps.js +81 -0
- package/dist/routes/integration-apps.js.map +1 -0
- package/dist/routes/integrations.d.ts +9 -0
- package/dist/routes/integrations.js +12 -0
- package/dist/routes/integrations.js.map +1 -0
- package/dist/routes/llm-proxy.js +26 -3
- package/dist/routes/llm-proxy.js.map +1 -1
- package/dist/routes/setup.js +53 -38
- package/dist/routes/setup.js.map +1 -1
- package/dist/routes/system.js +108 -68
- package/dist/routes/system.js.map +1 -1
- package/dist/routes/webdav.d.ts +1 -1
- package/dist/routes/webdav.js +2 -2
- package/dist/routes/webdav.js.map +1 -1
- package/dist/server.js +315 -213
- package/dist/server.js.map +1 -1
- package/dist/services/app-common/app-compiler.js +186 -0
- package/dist/services/app-common/app-compiler.js.map +1 -0
- package/dist/services/app-common/app-shared.d.ts +15 -0
- package/dist/services/app-common/app-shared.js +64 -0
- package/dist/services/app-common/app-shared.js.map +1 -0
- package/dist/services/app-common/capability-service.d.ts +45 -0
- package/dist/services/app-common/capability-service.js +331 -0
- package/dist/services/app-common/capability-service.js.map +1 -0
- package/dist/services/app-common/catalog-service.d.ts +59 -0
- package/dist/services/app-common/catalog-service.js +308 -0
- package/dist/services/app-common/catalog-service.js.map +1 -0
- package/dist/services/app-common/create-pipeline.d.ts +26 -0
- package/dist/services/app-common/create-pipeline.js +298 -0
- package/dist/services/app-common/create-pipeline.js.map +1 -0
- package/dist/services/app-common/delete-service.d.ts +5 -0
- package/dist/services/app-common/delete-service.js +104 -0
- package/dist/services/app-common/delete-service.js.map +1 -0
- package/dist/services/app-common/execution-owner.d.ts +23 -0
- package/dist/services/app-common/execution-owner.js +124 -0
- package/dist/services/app-common/execution-owner.js.map +1 -0
- package/dist/services/app-common/execution-service.d.ts +23 -0
- package/dist/services/app-common/execution-service.js +105 -0
- package/dist/services/app-common/execution-service.js.map +1 -0
- package/dist/services/app-common/id-normalizer.d.ts +31 -0
- package/dist/services/app-common/id-normalizer.js +83 -0
- package/dist/services/app-common/id-normalizer.js.map +1 -0
- package/dist/services/app-common/install-store.d.ts +34 -0
- package/dist/services/app-common/install-store.js +261 -0
- package/dist/services/app-common/install-store.js.map +1 -0
- package/dist/services/app-common/instance-store.d.ts +78 -0
- package/dist/services/app-common/instance-store.js +495 -0
- package/dist/services/app-common/instance-store.js.map +1 -0
- package/dist/services/app-common/integration-refs.d.ts +17 -0
- package/dist/services/app-common/integration-refs.js +47 -0
- package/dist/services/app-common/integration-refs.js.map +1 -0
- package/dist/services/app-common/lifecycle-pipeline.d.ts +62 -0
- package/dist/services/app-common/lifecycle-pipeline.js +317 -0
- package/dist/services/app-common/lifecycle-pipeline.js.map +1 -0
- package/dist/services/app-common/lifecycle-scripts.d.ts +38 -0
- package/dist/services/app-common/lifecycle-scripts.js +935 -0
- package/dist/services/app-common/lifecycle-scripts.js.map +1 -0
- package/dist/services/app-common/lifecycle-service.d.ts +68 -0
- package/dist/services/app-common/lifecycle-service.js +467 -0
- package/dist/services/app-common/lifecycle-service.js.map +1 -0
- package/dist/services/app-common/paths.d.ts +29 -0
- package/dist/services/app-common/paths.js +34 -0
- package/dist/services/app-common/paths.js.map +1 -0
- package/dist/services/app-common/platform-transform.d.ts +32 -0
- package/dist/services/app-common/platform-transform.js +65 -0
- package/dist/services/app-common/platform-transform.js.map +1 -0
- package/dist/services/app-common/provide-resolver.d.ts +29 -0
- package/dist/services/app-common/provide-resolver.js +129 -0
- package/dist/services/app-common/provide-resolver.js.map +1 -0
- package/dist/services/app-common/remote-spec.d.ts +14 -0
- package/dist/services/app-common/remote-spec.js +58 -0
- package/dist/services/app-common/remote-spec.js.map +1 -0
- package/dist/services/app-common/runtime-builder.d.ts +1 -0
- package/dist/services/app-common/runtime-builder.js +2 -0
- package/dist/services/app-common/runtime-builder.js.map +1 -0
- package/dist/services/app-common/runtime-facts.d.ts +19 -0
- package/dist/services/app-common/runtime-facts.js +126 -0
- package/dist/services/app-common/runtime-facts.js.map +1 -0
- package/dist/services/app-common/service.d.ts +9 -0
- package/dist/services/app-common/service.js +10 -0
- package/dist/services/app-common/service.js.map +1 -0
- package/dist/services/app-common/spec-materializer.d.ts +9 -0
- package/dist/services/app-common/spec-materializer.js +361 -0
- package/dist/services/app-common/spec-materializer.js.map +1 -0
- package/dist/services/app-common/status-refresh.d.ts +33 -0
- package/dist/services/app-common/status-refresh.js +759 -0
- package/dist/services/app-common/status-refresh.js.map +1 -0
- package/dist/services/app-common/task-service.d.ts +29 -0
- package/dist/services/app-common/task-service.js +93 -0
- package/dist/services/app-common/task-service.js.map +1 -0
- package/dist/services/app-common/terminal-session-manager.js +157 -0
- package/dist/services/app-common/terminal-session-manager.js.map +1 -0
- package/dist/services/app-modules/browserless/routes.d.ts +9 -0
- package/dist/services/app-modules/browserless/routes.js +517 -0
- package/dist/services/app-modules/browserless/routes.js.map +1 -0
- package/dist/services/app-modules/routes.d.ts +2 -0
- package/dist/services/app-modules/routes.js +5 -0
- package/dist/services/app-modules/routes.js.map +1 -0
- package/dist/services/backup/backup-admin.d.ts +95 -0
- package/dist/services/backup/backup-admin.js +246 -0
- package/dist/services/backup/backup-admin.js.map +1 -0
- package/dist/services/backup/backup-manager.d.ts +264 -0
- package/dist/services/backup/backup-manager.js +2318 -0
- package/dist/services/backup/backup-manager.js.map +1 -0
- package/dist/services/backup/backup-verify.js +240 -0
- package/dist/services/backup/backup-verify.js.map +1 -0
- package/dist/services/capabilities/browser-policy.d.ts +14 -0
- package/dist/services/capabilities/browser-policy.js +141 -0
- package/dist/services/capabilities/browser-policy.js.map +1 -0
- package/dist/services/capabilities/contract.d.ts +50 -0
- package/dist/services/capabilities/contract.js +129 -0
- package/dist/services/capabilities/contract.js.map +1 -0
- package/dist/services/capabilities/endpoint-validator.d.ts +42 -0
- package/dist/services/capabilities/endpoint-validator.js +114 -0
- package/dist/services/capabilities/endpoint-validator.js.map +1 -0
- package/dist/services/capabilities/health.d.ts +16 -0
- package/dist/services/capabilities/health.js +121 -0
- package/dist/services/capabilities/health.js.map +1 -0
- package/dist/services/capabilities/registry.d.ts +56 -0
- package/dist/services/capabilities/registry.js +222 -0
- package/dist/services/capabilities/registry.js.map +1 -0
- package/dist/services/capabilities/sync.d.ts +7 -0
- package/dist/services/capabilities/sync.js +223 -0
- package/dist/services/capabilities/sync.js.map +1 -0
- package/dist/services/capability-proxy/html-rewriters/browserless.d.ts +1 -0
- package/dist/services/capability-proxy/html-rewriters/browserless.js +83 -0
- package/dist/services/capability-proxy/html-rewriters/browserless.js.map +1 -0
- package/dist/services/capability-proxy/html-rewriters/index.d.ts +12 -0
- package/dist/services/capability-proxy/html-rewriters/index.js +25 -0
- package/dist/services/capability-proxy/html-rewriters/index.js.map +1 -0
- package/dist/services/capability-proxy/html-rewriters/jishukb.d.ts +1 -0
- package/dist/services/capability-proxy/html-rewriters/jishukb.js +161 -0
- package/dist/services/capability-proxy/html-rewriters/jishukb.js.map +1 -0
- package/dist/services/connections/admin.d.ts +80 -0
- package/dist/services/connections/admin.js +327 -0
- package/dist/services/connections/admin.js.map +1 -0
- package/dist/services/connections/apply.d.ts +110 -0
- package/dist/services/connections/apply.js +444 -0
- package/dist/services/connections/apply.js.map +1 -0
- package/dist/services/connections/resolver.d.ts +82 -0
- package/dist/services/connections/resolver.js +289 -0
- package/dist/services/connections/resolver.js.map +1 -0
- package/dist/services/connections/suggestions.d.ts +27 -0
- package/dist/services/connections/suggestions.js +124 -0
- package/dist/services/connections/suggestions.js.map +1 -0
- package/dist/services/connections/transactor.d.ts +39 -0
- package/dist/services/connections/transactor.js +307 -0
- package/dist/services/connections/transactor.js.map +1 -0
- package/dist/services/files/external-mounts.js +187 -0
- package/dist/services/files/external-mounts.js.map +1 -0
- package/dist/services/files/files-manager.d.ts +265 -0
- package/dist/services/files/files-manager.js +1189 -0
- package/dist/services/files/files-manager.js.map +1 -0
- package/dist/services/files/files-mounts.d.ts +42 -0
- package/dist/services/files/files-mounts.js +207 -0
- package/dist/services/files/files-mounts.js.map +1 -0
- package/dist/services/files/organize/applier.js +218 -0
- package/dist/services/files/organize/applier.js.map +1 -0
- package/dist/services/files/organize/rules.js +286 -0
- package/dist/services/files/organize/rules.js.map +1 -0
- package/dist/services/files/organize/scanner.js +366 -0
- package/dist/services/files/organize/scanner.js.map +1 -0
- package/dist/services/files/organize/store.js +82 -0
- package/dist/services/files/organize/store.js.map +1 -0
- package/dist/services/files/webdav/server.d.ts +47 -0
- package/dist/services/files/webdav/server.js +329 -0
- package/dist/services/files/webdav/server.js.map +1 -0
- package/dist/services/files/webdav/xml-builder.js.map +1 -0
- package/dist/services/instances/admin.d.ts +23 -0
- package/dist/services/instances/admin.js +218 -0
- package/dist/services/instances/admin.js.map +1 -0
- package/dist/services/instances/clone.d.ts +26 -0
- package/dist/services/instances/clone.js +78 -0
- package/dist/services/instances/clone.js.map +1 -0
- package/dist/services/instances/config-admin.d.ts +17 -0
- package/dist/services/instances/config-admin.js +181 -0
- package/dist/services/instances/config-admin.js.map +1 -0
- package/dist/services/instances/manager.d.ts +231 -0
- package/dist/services/instances/manager.js +1348 -0
- package/dist/services/instances/manager.js.map +1 -0
- package/dist/services/instances/passwords.js +173 -0
- package/dist/services/instances/passwords.js.map +1 -0
- package/dist/services/instances/types.d.ts +21 -0
- package/dist/services/instances/types.js +2 -0
- package/dist/services/instances/types.js.map +1 -0
- package/dist/services/integrations/anythingllm/integration.d.ts +25 -0
- package/dist/services/integrations/anythingllm/integration.js +251 -0
- package/dist/services/integrations/anythingllm/integration.js.map +1 -0
- package/dist/services/integrations/catalog.d.ts +3 -0
- package/dist/services/integrations/catalog.js +73 -0
- package/dist/services/integrations/catalog.js.map +1 -0
- package/dist/services/integrations/custom/integration.d.ts +28 -0
- package/dist/services/integrations/custom/integration.js +179 -0
- package/dist/services/integrations/custom/integration.js.map +1 -0
- package/dist/services/integrations/hermes/integration.d.ts +194 -0
- package/dist/services/integrations/hermes/integration.js +1669 -0
- package/dist/services/integrations/hermes/integration.js.map +1 -0
- package/dist/services/integrations/index.d.ts +40 -0
- package/dist/services/integrations/index.js +59 -0
- package/dist/services/integrations/index.js.map +1 -0
- package/dist/services/integrations/installable/catalog.d.ts +33 -0
- package/dist/services/integrations/installable/catalog.js +88 -0
- package/dist/services/integrations/installable/catalog.js.map +1 -0
- package/dist/services/integrations/installable/index.d.ts +35 -0
- package/dist/services/integrations/installable/index.js +170 -0
- package/dist/services/integrations/installable/index.js.map +1 -0
- package/dist/services/integrations/installable/installers/integration-probes.d.ts +50 -0
- package/dist/services/integrations/installable/installers/integration-probes.js +231 -0
- package/dist/services/integrations/installable/installers/integration-probes.js.map +1 -0
- package/dist/services/integrations/installable/installers/integration.d.ts +30 -0
- package/dist/services/integrations/installable/installers/integration.js +177 -0
- package/dist/services/integrations/installable/installers/integration.js.map +1 -0
- package/dist/services/integrations/installable/installers/registry-probe.js.map +1 -0
- package/dist/services/integrations/installable/installers/shell-script.d.ts +46 -0
- package/dist/services/integrations/installable/installers/shell-script.js +487 -0
- package/dist/services/integrations/installable/installers/shell-script.js.map +1 -0
- package/dist/services/integrations/installable/types.d.ts +130 -0
- package/dist/services/integrations/installable/types.js +19 -0
- package/dist/services/integrations/installable/types.js.map +1 -0
- package/dist/services/integrations/jishukb/integration.d.ts +22 -0
- package/dist/services/integrations/jishukb/integration.js +189 -0
- package/dist/services/integrations/jishukb/integration.js.map +1 -0
- package/dist/services/integrations/openclaw/anythingllm-shim.d.ts +46 -0
- package/dist/services/integrations/openclaw/anythingllm-shim.js +281 -0
- package/dist/services/integrations/openclaw/anythingllm-shim.js.map +1 -0
- package/dist/services/integrations/openclaw/drive-shim.js +490 -0
- package/dist/services/integrations/openclaw/drive-shim.js.map +1 -0
- package/dist/services/integrations/openclaw/integration.d.ts +424 -0
- package/dist/services/integrations/openclaw/integration.js +4402 -0
- package/dist/services/integrations/openclaw/integration.js.map +1 -0
- package/dist/services/integrations/openclaw/jishukb-shim.d.ts +48 -0
- package/dist/services/integrations/openclaw/jishukb-shim.js +750 -0
- package/dist/services/integrations/openclaw/jishukb-shim.js.map +1 -0
- package/dist/services/integrations/openclaw/mcporter-lite.js +276 -0
- package/dist/services/integrations/openclaw/mcporter-lite.js.map +1 -0
- package/dist/services/integrations/openclaw/mcporter.d.ts +46 -0
- package/dist/services/integrations/openclaw/mcporter.js +112 -0
- package/dist/services/integrations/openclaw/mcporter.js.map +1 -0
- package/dist/services/integrations/openclaw/routes.d.ts +21 -0
- package/dist/services/integrations/openclaw/routes.js +1191 -0
- package/dist/services/integrations/openclaw/routes.js.map +1 -0
- package/dist/services/integrations/registry.d.ts +17 -0
- package/dist/services/integrations/registry.js +36 -0
- package/dist/services/integrations/registry.js.map +1 -0
- package/dist/services/integrations/routes.d.ts +2 -0
- package/dist/services/integrations/routes.js +9 -0
- package/dist/services/integrations/routes.js.map +1 -0
- package/dist/services/integrations/types.d.ts +469 -0
- package/dist/services/integrations/types.js +2 -0
- package/dist/services/integrations/types.js.map +1 -0
- package/dist/services/legacy-migrator/classifier.d.ts +44 -0
- package/dist/services/legacy-migrator/classifier.js +309 -0
- package/dist/services/legacy-migrator/classifier.js.map +1 -0
- package/dist/services/legacy-migrator/executor.d.ts +42 -0
- package/dist/services/legacy-migrator/executor.js +637 -0
- package/dist/services/legacy-migrator/executor.js.map +1 -0
- package/dist/services/legacy-migrator/index.d.ts +31 -0
- package/dist/services/legacy-migrator/index.js +34 -0
- package/dist/services/legacy-migrator/index.js.map +1 -0
- package/dist/services/legacy-migrator/planner.d.ts +8 -0
- package/dist/services/legacy-migrator/planner.js +154 -0
- package/dist/services/legacy-migrator/planner.js.map +1 -0
- package/dist/services/legacy-migrator/provider-settings.d.ts +6 -0
- package/dist/services/legacy-migrator/provider-settings.js +72 -0
- package/dist/services/legacy-migrator/provider-settings.js.map +1 -0
- package/dist/services/legacy-migrator/report.d.ts +9 -0
- package/dist/services/legacy-migrator/report.js +99 -0
- package/dist/services/legacy-migrator/report.js.map +1 -0
- package/dist/services/legacy-migrator/scanner.d.ts +13 -0
- package/dist/services/legacy-migrator/scanner.js +157 -0
- package/dist/services/legacy-migrator/scanner.js.map +1 -0
- package/dist/services/legacy-migrator/types.d.ts +97 -0
- package/dist/services/legacy-migrator/types.js +23 -0
- package/dist/services/legacy-migrator/types.js.map +1 -0
- package/dist/services/llm-proxy/instance-proxy.d.ts +17 -1
- package/dist/services/llm-proxy/instance-proxy.js +171 -44
- package/dist/services/llm-proxy/instance-proxy.js.map +1 -1
- package/dist/services/llm-proxy/probe.js +5 -14
- package/dist/services/llm-proxy/probe.js.map +1 -1
- package/dist/services/llm-proxy/providers.js +23 -31
- package/dist/services/llm-proxy/providers.js.map +1 -1
- package/dist/services/llm-proxy/ssrf.d.ts +11 -4
- package/dist/services/llm-proxy/ssrf.js +45 -7
- package/dist/services/llm-proxy/ssrf.js.map +1 -1
- package/dist/services/llm-proxy/validate-key.js +16 -37
- package/dist/services/llm-proxy/validate-key.js.map +1 -1
- package/dist/services/repair/runtime-repair.d.ts +22 -0
- package/dist/services/repair/runtime-repair.js +307 -0
- package/dist/services/repair/runtime-repair.js.map +1 -0
- package/dist/services/runtime/driver-registry.d.ts +21 -0
- package/dist/services/runtime/driver-registry.js +22 -0
- package/dist/services/runtime/driver-registry.js.map +1 -0
- package/dist/services/runtime/drivers/nomad.d.ts +260 -0
- package/dist/services/runtime/drivers/nomad.js +3092 -0
- package/dist/services/runtime/drivers/nomad.js.map +1 -0
- package/dist/services/runtime/errors.d.ts +3 -3
- package/dist/services/runtime/errors.js +3 -3
- package/dist/services/runtime/instance.d.ts +14 -16
- package/dist/services/runtime/instance.js +93 -123
- package/dist/services/runtime/instance.js.map +1 -1
- package/dist/services/runtime/job-id.d.ts +1 -1
- package/dist/services/runtime/job-id.js +1 -1
- package/dist/services/runtime/mcp-shims/firewall.d.ts +2 -2
- package/dist/services/runtime/mcp-shims/firewall.js +2 -2
- package/dist/services/runtime/mcp-shims/searxng-shim.d.ts +3 -5
- package/dist/services/runtime/mcp-shims/searxng-shim.js +3 -5
- package/dist/services/runtime/mcp-shims/searxng-shim.js.map +1 -1
- package/dist/services/runtime/mcp-shims/write-mcp-entry.d.ts +20 -20
- package/dist/services/runtime/mcp-shims/write-mcp-entry.js +16 -16
- package/dist/services/runtime/mcp-shims/write-mcp-entry.js.map +1 -1
- package/dist/services/runtime/ownership-marker.d.ts +83 -0
- package/dist/services/runtime/ownership-marker.js +109 -0
- package/dist/services/runtime/ownership-marker.js.map +1 -0
- package/dist/services/runtime/types.d.ts +22 -501
- package/dist/services/runtime/types.js +0 -12
- package/dist/services/runtime/types.js.map +1 -1
- package/dist/services/runtime/workload-compiler.d.ts +17 -0
- package/dist/services/runtime/workload-compiler.js +525 -0
- package/dist/services/runtime/workload-compiler.js.map +1 -0
- package/dist/services/runtime/workload-types.d.ts +11 -0
- package/dist/services/runtime/workload-types.js +2 -0
- package/dist/services/runtime/workload-types.js.map +1 -0
- package/dist/services/setup/core-manager.d.ts +50 -0
- package/dist/services/setup/core-manager.js +456 -0
- package/dist/services/setup/core-manager.js.map +1 -0
- package/dist/services/setup/plugin-installer.js +136 -0
- package/dist/services/setup/plugin-installer.js.map +1 -0
- package/dist/services/setup/setup-manager.d.ts +158 -0
- package/dist/services/setup/setup-manager.js +2768 -0
- package/dist/services/setup/setup-manager.js.map +1 -0
- package/dist/services/system/cli-command.d.ts +5 -0
- package/dist/services/system/cli-command.js +18 -0
- package/dist/services/system/cli-command.js.map +1 -0
- package/dist/services/system/macos-launchd.js +312 -0
- package/dist/services/system/macos-launchd.js.map +1 -0
- package/dist/services/system/repair-orchestrator.d.ts +71 -0
- package/dist/services/system/repair-orchestrator.js +412 -0
- package/dist/services/system/repair-orchestrator.js.map +1 -0
- package/dist/services/system/system-monitor.js +96 -0
- package/dist/services/system/system-monitor.js.map +1 -0
- package/dist/services/system/system-ollama-provider.d.ts +14 -0
- package/dist/services/system/system-ollama-provider.js +129 -0
- package/dist/services/system/system-ollama-provider.js.map +1 -0
- package/dist/services/system/system-reconciler.d.ts +59 -0
- package/dist/services/system/system-reconciler.js +710 -0
- package/dist/services/system/system-reconciler.js.map +1 -0
- package/dist/services/system/update-manager.d.ts +43 -0
- package/dist/services/system/update-manager.js +315 -0
- package/dist/services/system/update-manager.js.map +1 -0
- package/dist/services/system/upgrade-finalize.d.ts +80 -0
- package/dist/services/system/upgrade-finalize.js +507 -0
- package/dist/services/system/upgrade-finalize.js.map +1 -0
- package/dist/services/tasks/registry.d.ts +44 -0
- package/dist/services/tasks/registry.js +90 -0
- package/dist/services/tasks/registry.js.map +1 -0
- package/dist/services/telemetry/activation.d.ts +6 -2
- package/dist/services/telemetry/activation.js +6 -2
- package/dist/services/telemetry/activation.js.map +1 -1
- package/dist/services/telemetry/heartbeat.d.ts +6 -2
- package/dist/services/telemetry/heartbeat.js +6 -2
- package/dist/services/telemetry/heartbeat.js.map +1 -1
- package/dist/services/workspaces/builder.d.ts +29 -0
- package/dist/services/workspaces/builder.js +186 -0
- package/dist/services/workspaces/builder.js.map +1 -0
- package/dist/types.d.ts +331 -45
- package/dist/utils/instance-lock.d.ts +2 -2
- package/dist/utils/instance-lock.js +2 -2
- package/install/jishu-install.sh +107 -26
- package/install/jishu-uninstall.sh +8 -0
- package/install/post-install.sh +162 -185
- package/install/post-uninstall.sh +6 -0
- package/node_modules/@fastify/static/.github/workflows/ci.yml +1 -1
- package/node_modules/@fastify/static/.github/workflows/lock-threads.yml +19 -0
- package/node_modules/@fastify/static/LICENSE +1 -3
- package/node_modules/@fastify/static/example/server-benchmark.js +39 -0
- package/node_modules/@fastify/static/index.js +169 -23
- package/node_modules/@fastify/static/lib/dirList.js +20 -6
- package/node_modules/@fastify/static/package.json +10 -8
- package/node_modules/@fastify/static/test/dir-list.test.js +82 -0
- package/node_modules/@fastify/static/test/static.test.js +326 -4
- package/node_modules/@fastify/static/types/index.d.ts +0 -4
- package/node_modules/@fastify/static/types/index.test-d.ts +1 -1
- package/node_modules/content-disposition/README.md +21 -22
- package/node_modules/content-disposition/index.js +122 -44
- package/node_modules/content-disposition/package.json +16 -20
- package/node_modules/glob/README.md +39 -130
- package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
- package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
- package/node_modules/glob/dist/commonjs/glob.js +2 -1
- package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
- package/node_modules/glob/dist/commonjs/index.min.js +4 -0
- package/node_modules/glob/dist/commonjs/index.min.js.map +7 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
- package/node_modules/glob/dist/commonjs/pattern.js +4 -0
- package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
- package/node_modules/glob/dist/esm/glob.d.ts +8 -0
- package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
- package/node_modules/glob/dist/esm/glob.js +2 -1
- package/node_modules/glob/dist/esm/glob.js.map +1 -1
- package/node_modules/glob/dist/esm/index.min.js +4 -0
- package/node_modules/glob/dist/esm/index.min.js.map +7 -0
- package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
- package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
- package/node_modules/glob/dist/esm/pattern.js +4 -0
- package/node_modules/glob/dist/esm/pattern.js.map +1 -1
- package/node_modules/glob/package.json +38 -37
- package/node_modules/jishushell-panel/README.md +4 -4
- package/node_modules/jishushell-panel/output/dist/server.js +17 -6
- package/node_modules/jishushell-panel/output/dist/server.js.map +1 -1
- package/node_modules/jishushell-panel/output/public/assets/ApiKeyField-NKcbHjNz.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/Dashboard-Da1fL38t.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/HermesChatPanel-DZvmYsoh.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/HermesConfigForm-BLUWlKwm.js +4 -0
- package/node_modules/jishushell-panel/output/public/assets/InitPassword-BAKsshzk.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/InstanceDetail-Dgyc_TX5.js +14 -0
- package/node_modules/jishushell-panel/output/public/assets/Login-DHeOmwI8.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/NewInstance-CIy0cYtp.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/ProviderRecommendations-H0ByEYF0.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/Settings-DAT-UMfP.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/Setup-g3uckFYR.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/WeixinLoginPanel-D-T6BxkQ.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/api-C70Gt678.js +4 -0
- package/node_modules/jishushell-panel/output/public/assets/index-DnnqTf7s.css +1 -0
- package/node_modules/jishushell-panel/output/public/assets/index-ERt6_ngA.js +23 -0
- package/node_modules/jishushell-panel/output/public/assets/registry-DF93EzIb.js +2 -0
- package/node_modules/jishushell-panel/output/public/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/setup-task-q21GnI0E.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/usePolling-DeoThIQn.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/vendor-i18n-CS8DFbkQ.js +1 -0
- package/node_modules/jishushell-panel/output/public/assets/vendor-react-Cc84NArf.js +8 -0
- package/node_modules/jishushell-panel/output/public/index.html +6 -4
- package/node_modules/jishushell-panel/package.json +2 -2
- package/node_modules/semver/classes/range.js +11 -2
- package/node_modules/semver/package.json +2 -2
- package/package.json +12 -64
- package/scripts/check-app-path-boundaries.mjs +121 -0
- package/scripts/check-app-spec.mjs +127 -25
- package/scripts/check-colima-launchd.mjs +10 -8
- package/scripts/check-integration-isolation.ts +541 -0
- package/scripts/check-new-file-tests.mjs +11 -3
- package/scripts/check-open-core-boundaries.mjs +60 -10
- package/scripts/check-test-layering.sh +1 -1
- package/scripts/fixtures/instances/hermes-sample/instance.json +3 -2
- package/scripts/fixtures/instances/legacy-openclaw-sample/instance.json +1 -1
- package/scripts/local-web-upgrade-test.README +4 -3
- package/scripts/local-web-upgrade-test.example.env +2 -2
- package/scripts/local-web-upgrade-test.sh +14 -1
- package/scripts/pack-gui-and-send-pi.sh +41 -0
- package/scripts/perf/instances.js +1 -1
- package/scripts/prune-open-core-dist.mjs +89 -2
- package/scripts/smoke/hermes-bootstrap.sh +5 -5
- package/templates/hermes-entrypoint.sh +19 -29
- package/apps/openwebui-container.yaml +0 -97
- package/apps/playwright-container.yaml +0 -126
- package/dependencies/jishushell-panel-0.6.5.tgz +0 -0
- package/dist/crypto-shim.d.ts +0 -1
- package/dist/crypto-shim.js +0 -2
- package/dist/crypto-shim.js.map +0 -1
- package/dist/routes/agent-apps.d.ts +0 -14
- package/dist/routes/agent-apps.js +0 -77
- package/dist/routes/agent-apps.js.map +0 -1
- package/dist/routes/internal.d.ts +0 -2
- package/dist/routes/internal.js +0 -55
- package/dist/routes/internal.js.map +0 -1
- package/dist/routes/openclaw-routes.d.ts +0 -22
- package/dist/routes/openclaw-routes.js +0 -1020
- package/dist/routes/openclaw-routes.js.map +0 -1
- package/dist/routes/runtime.d.ts +0 -15
- package/dist/routes/runtime.js +0 -76
- package/dist/routes/runtime.js.map +0 -1
- package/dist/services/agent-apps/catalog.d.ts +0 -33
- package/dist/services/agent-apps/catalog.js +0 -88
- package/dist/services/agent-apps/catalog.js.map +0 -1
- package/dist/services/agent-apps/index.d.ts +0 -36
- package/dist/services/agent-apps/index.js +0 -171
- package/dist/services/agent-apps/index.js.map +0 -1
- package/dist/services/agent-apps/installers/adapter-probes.d.ts +0 -49
- package/dist/services/agent-apps/installers/adapter-probes.js +0 -230
- package/dist/services/agent-apps/installers/adapter-probes.js.map +0 -1
- package/dist/services/agent-apps/installers/adapter.d.ts +0 -30
- package/dist/services/agent-apps/installers/adapter.js +0 -171
- package/dist/services/agent-apps/installers/adapter.js.map +0 -1
- package/dist/services/agent-apps/installers/registry-probe.js.map +0 -1
- package/dist/services/agent-apps/installers/shell-script.d.ts +0 -47
- package/dist/services/agent-apps/installers/shell-script.js +0 -488
- package/dist/services/agent-apps/installers/shell-script.js.map +0 -1
- package/dist/services/agent-apps/types.d.ts +0 -128
- package/dist/services/agent-apps/types.js +0 -17
- package/dist/services/agent-apps/types.js.map +0 -1
- package/dist/services/app/app-compiler.js +0 -185
- package/dist/services/app/app-compiler.js.map +0 -1
- package/dist/services/app/app-manager.d.ts +0 -184
- package/dist/services/app/app-manager.js +0 -2933
- package/dist/services/app/app-manager.js.map +0 -1
- package/dist/services/app/custom-manager.d.ts +0 -27
- package/dist/services/app/custom-manager.js +0 -382
- package/dist/services/app/custom-manager.js.map +0 -1
- package/dist/services/app/hermes-agent-manager.d.ts +0 -20
- package/dist/services/app/hermes-agent-manager.js +0 -299
- package/dist/services/app/hermes-agent-manager.js.map +0 -1
- package/dist/services/app/id-normalizer.d.ts +0 -27
- package/dist/services/app/id-normalizer.js +0 -77
- package/dist/services/app/id-normalizer.js.map +0 -1
- package/dist/services/app/ollama-manager.d.ts +0 -18
- package/dist/services/app/ollama-manager.js +0 -224
- package/dist/services/app/ollama-manager.js.map +0 -1
- package/dist/services/app/openclaw-manager.d.ts +0 -63
- package/dist/services/app/openclaw-manager.js +0 -1215
- package/dist/services/app/openclaw-manager.js.map +0 -1
- package/dist/services/app/paths.d.ts +0 -27
- package/dist/services/app/paths.js +0 -40
- package/dist/services/app/paths.js.map +0 -1
- package/dist/services/app/platform-transform.d.ts +0 -32
- package/dist/services/app/platform-transform.js +0 -65
- package/dist/services/app/platform-transform.js.map +0 -1
- package/dist/services/app/provide-resolver.d.ts +0 -29
- package/dist/services/app/provide-resolver.js +0 -135
- package/dist/services/app/provide-resolver.js.map +0 -1
- package/dist/services/app/registry.d.ts +0 -17
- package/dist/services/app/registry.js +0 -31
- package/dist/services/app/registry.js.map +0 -1
- package/dist/services/app/remote-spec.d.ts +0 -14
- package/dist/services/app/remote-spec.js +0 -58
- package/dist/services/app/remote-spec.js.map +0 -1
- package/dist/services/app/terminal-session-manager.js +0 -157
- package/dist/services/app/terminal-session-manager.js.map +0 -1
- package/dist/services/app/types.d.ts +0 -74
- package/dist/services/app/types.js +0 -16
- package/dist/services/app/types.js.map +0 -1
- package/dist/services/app-config-admin.d.ts +0 -17
- package/dist/services/app-config-admin.js +0 -177
- package/dist/services/app-config-admin.js.map +0 -1
- package/dist/services/app-create-from-installed.d.ts +0 -23
- package/dist/services/app-create-from-installed.js +0 -75
- package/dist/services/app-create-from-installed.js.map +0 -1
- package/dist/services/app-passwords.js +0 -173
- package/dist/services/app-passwords.js.map +0 -1
- package/dist/services/backup-admin.d.ts +0 -101
- package/dist/services/backup-admin.js +0 -259
- package/dist/services/backup-admin.js.map +0 -1
- package/dist/services/backup-manager.d.ts +0 -264
- package/dist/services/backup-manager.js +0 -2263
- package/dist/services/backup-manager.js.map +0 -1
- package/dist/services/backup-verify.js +0 -240
- package/dist/services/backup-verify.js.map +0 -1
- package/dist/services/capability-endpoint-validator.d.ts +0 -41
- package/dist/services/capability-endpoint-validator.js +0 -114
- package/dist/services/capability-endpoint-validator.js.map +0 -1
- package/dist/services/capability-health.d.ts +0 -16
- package/dist/services/capability-health.js +0 -121
- package/dist/services/capability-health.js.map +0 -1
- package/dist/services/capability-registry.d.ts +0 -29
- package/dist/services/capability-registry.js +0 -176
- package/dist/services/capability-registry.js.map +0 -1
- package/dist/services/capability-sync.d.ts +0 -4
- package/dist/services/capability-sync.js +0 -220
- package/dist/services/capability-sync.js.map +0 -1
- package/dist/services/connection-admin.d.ts +0 -74
- package/dist/services/connection-admin.js +0 -287
- package/dist/services/connection-admin.js.map +0 -1
- package/dist/services/connection-apply.d.ts +0 -91
- package/dist/services/connection-apply.js +0 -471
- package/dist/services/connection-apply.js.map +0 -1
- package/dist/services/connection-resolver.d.ts +0 -65
- package/dist/services/connection-resolver.js +0 -281
- package/dist/services/connection-resolver.js.map +0 -1
- package/dist/services/connection-transactor.d.ts +0 -39
- package/dist/services/connection-transactor.js +0 -354
- package/dist/services/connection-transactor.js.map +0 -1
- package/dist/services/core-manager.d.ts +0 -50
- package/dist/services/core-manager.js +0 -411
- package/dist/services/core-manager.js.map +0 -1
- package/dist/services/external-mounts.js +0 -187
- package/dist/services/external-mounts.js.map +0 -1
- package/dist/services/files-manager.d.ts +0 -252
- package/dist/services/files-manager.js +0 -1156
- package/dist/services/files-manager.js.map +0 -1
- package/dist/services/files-mounts.d.ts +0 -42
- package/dist/services/files-mounts.js +0 -207
- package/dist/services/files-mounts.js.map +0 -1
- package/dist/services/instance-admin.d.ts +0 -26
- package/dist/services/instance-admin.js +0 -218
- package/dist/services/instance-admin.js.map +0 -1
- package/dist/services/instance-manager.d.ts +0 -192
- package/dist/services/instance-manager.js +0 -1289
- package/dist/services/instance-manager.js.map +0 -1
- package/dist/services/macos-launchd.js +0 -312
- package/dist/services/macos-launchd.js.map +0 -1
- package/dist/services/nomad-manager.d.ts +0 -307
- package/dist/services/nomad-manager.js +0 -3958
- package/dist/services/nomad-manager.js.map +0 -1
- package/dist/services/organize/applier.js +0 -218
- package/dist/services/organize/applier.js.map +0 -1
- package/dist/services/organize/rules.js +0 -286
- package/dist/services/organize/rules.js.map +0 -1
- package/dist/services/organize/scanner.js +0 -366
- package/dist/services/organize/scanner.js.map +0 -1
- package/dist/services/organize/store.js +0 -82
- package/dist/services/organize/store.js.map +0 -1
- package/dist/services/plugin-installer.js +0 -128
- package/dist/services/plugin-installer.js.map +0 -1
- package/dist/services/process-manager.d.ts +0 -25
- package/dist/services/process-manager.js +0 -568
- package/dist/services/process-manager.js.map +0 -1
- package/dist/services/runtime/adapters/custom.d.ts +0 -20
- package/dist/services/runtime/adapters/custom.js +0 -188
- package/dist/services/runtime/adapters/custom.js.map +0 -1
- package/dist/services/runtime/adapters/hermes.d.ts +0 -204
- package/dist/services/runtime/adapters/hermes.js +0 -1684
- package/dist/services/runtime/adapters/hermes.js.map +0 -1
- package/dist/services/runtime/adapters/openclaw-mcporter.d.ts +0 -45
- package/dist/services/runtime/adapters/openclaw-mcporter.js +0 -108
- package/dist/services/runtime/adapters/openclaw-mcporter.js.map +0 -1
- package/dist/services/runtime/adapters/openclaw.d.ts +0 -426
- package/dist/services/runtime/adapters/openclaw.js +0 -3975
- package/dist/services/runtime/adapters/openclaw.js.map +0 -1
- package/dist/services/runtime/index.d.ts +0 -34
- package/dist/services/runtime/index.js +0 -51
- package/dist/services/runtime/index.js.map +0 -1
- package/dist/services/runtime/mcp-shims/anythingllm-shim.d.ts +0 -46
- package/dist/services/runtime/mcp-shims/anythingllm-shim.js +0 -281
- package/dist/services/runtime/mcp-shims/anythingllm-shim.js.map +0 -1
- package/dist/services/runtime/mcp-shims/drive-shim.js +0 -490
- package/dist/services/runtime/mcp-shims/drive-shim.js.map +0 -1
- package/dist/services/runtime/mcp-shims/jishukb-shim.d.ts +0 -48
- package/dist/services/runtime/mcp-shims/jishukb-shim.js +0 -723
- package/dist/services/runtime/mcp-shims/jishukb-shim.js.map +0 -1
- package/dist/services/runtime/mcp-shims/mcporter-lite.js +0 -276
- package/dist/services/runtime/mcp-shims/mcporter-lite.js.map +0 -1
- package/dist/services/runtime/migrations.d.ts +0 -23
- package/dist/services/runtime/migrations.js +0 -125
- package/dist/services/runtime/migrations.js.map +0 -1
- package/dist/services/runtime/registry.d.ts +0 -13
- package/dist/services/runtime/registry.js +0 -32
- package/dist/services/runtime/registry.js.map +0 -1
- package/dist/services/runtime-identity.d.ts +0 -13
- package/dist/services/runtime-identity.js +0 -166
- package/dist/services/runtime-identity.js.map +0 -1
- package/dist/services/runtime-repair.d.ts +0 -52
- package/dist/services/runtime-repair.js +0 -352
- package/dist/services/runtime-repair.js.map +0 -1
- package/dist/services/setup-manager.d.ts +0 -158
- package/dist/services/setup-manager.js +0 -2740
- package/dist/services/setup-manager.js.map +0 -1
- package/dist/services/suggestions.d.ts +0 -27
- package/dist/services/suggestions.js +0 -133
- package/dist/services/suggestions.js.map +0 -1
- package/dist/services/system-monitor.js +0 -79
- package/dist/services/system-monitor.js.map +0 -1
- package/dist/services/system-ollama-provider.d.ts +0 -14
- package/dist/services/system-ollama-provider.js +0 -125
- package/dist/services/system-ollama-provider.js.map +0 -1
- package/dist/services/system-reconciler.d.ts +0 -72
- package/dist/services/system-reconciler.js +0 -600
- package/dist/services/system-reconciler.js.map +0 -1
- package/dist/services/task-registry.d.ts +0 -44
- package/dist/services/task-registry.js +0 -76
- package/dist/services/task-registry.js.map +0 -1
- package/dist/services/types-shim.d.ts +0 -16
- package/dist/services/types-shim.js +0 -2
- package/dist/services/types-shim.js.map +0 -1
- package/dist/services/update-manager.d.ts +0 -47
- package/dist/services/update-manager.js +0 -351
- package/dist/services/update-manager.js.map +0 -1
- package/dist/services/webdav/server.d.ts +0 -24
- package/dist/services/webdav/server.js +0 -420
- package/dist/services/webdav/server.js.map +0 -1
- package/dist/services/webdav/xml-builder.js.map +0 -1
- package/dist/services/workspace-builder.d.ts +0 -29
- package/dist/services/workspace-builder.js +0 -188
- package/dist/services/workspace-builder.js.map +0 -1
- package/node_modules/@fastify/static/.github/stale.yml +0 -21
- package/node_modules/@isaacs/cliui/LICENSE.md +0 -63
- package/node_modules/@isaacs/cliui/README.md +0 -151
- package/node_modules/@isaacs/cliui/dist/commonjs/ansi-regex/index.d.ts +0 -4
- package/node_modules/@isaacs/cliui/dist/commonjs/ansi-regex/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/ansi-regex/index.js +0 -16
- package/node_modules/@isaacs/cliui/dist/commonjs/ansi-regex/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/ansi-styles/index.d.ts +0 -34
- package/node_modules/@isaacs/cliui/dist/commonjs/ansi-styles/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/ansi-styles/index.js +0 -170
- package/node_modules/@isaacs/cliui/dist/commonjs/ansi-styles/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/eastasianwidth/index.d.ts +0 -6
- package/node_modules/@isaacs/cliui/dist/commonjs/eastasianwidth/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/eastasianwidth/index.js +0 -307
- package/node_modules/@isaacs/cliui/dist/commonjs/eastasianwidth/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/emoji-regex/index.d.ts +0 -2
- package/node_modules/@isaacs/cliui/dist/commonjs/emoji-regex/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/emoji-regex/index.js +0 -7
- package/node_modules/@isaacs/cliui/dist/commonjs/emoji-regex/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/index.d.ts +0 -41
- package/node_modules/@isaacs/cliui/dist/commonjs/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/index.js +0 -322
- package/node_modules/@isaacs/cliui/dist/commonjs/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/index.min.js +0 -12
- package/node_modules/@isaacs/cliui/dist/commonjs/index.min.js.map +0 -7
- package/node_modules/@isaacs/cliui/dist/commonjs/package.json +0 -3
- package/node_modules/@isaacs/cliui/dist/commonjs/string-width/index.d.ts +0 -5
- package/node_modules/@isaacs/cliui/dist/commonjs/string-width/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/string-width/index.js +0 -49
- package/node_modules/@isaacs/cliui/dist/commonjs/string-width/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/strip-ansi/index.d.ts +0 -2
- package/node_modules/@isaacs/cliui/dist/commonjs/strip-ansi/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/strip-ansi/index.js +0 -8
- package/node_modules/@isaacs/cliui/dist/commonjs/strip-ansi/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/wrap-ansi/index.d.ts +0 -7
- package/node_modules/@isaacs/cliui/dist/commonjs/wrap-ansi/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/commonjs/wrap-ansi/index.js +0 -176
- package/node_modules/@isaacs/cliui/dist/commonjs/wrap-ansi/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/ansi-regex/index.d.ts +0 -4
- package/node_modules/@isaacs/cliui/dist/esm/ansi-regex/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/ansi-regex/index.js +0 -12
- package/node_modules/@isaacs/cliui/dist/esm/ansi-regex/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/ansi-styles/index.d.ts +0 -34
- package/node_modules/@isaacs/cliui/dist/esm/ansi-styles/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/ansi-styles/index.js +0 -167
- package/node_modules/@isaacs/cliui/dist/esm/ansi-styles/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/eastasianwidth/index.d.ts +0 -6
- package/node_modules/@isaacs/cliui/dist/esm/eastasianwidth/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/eastasianwidth/index.js +0 -299
- package/node_modules/@isaacs/cliui/dist/esm/eastasianwidth/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/emoji-regex/index.d.ts +0 -2
- package/node_modules/@isaacs/cliui/dist/esm/emoji-regex/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/emoji-regex/index.js +0 -3
- package/node_modules/@isaacs/cliui/dist/esm/emoji-regex/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/index.d.ts +0 -41
- package/node_modules/@isaacs/cliui/dist/esm/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/index.js +0 -317
- package/node_modules/@isaacs/cliui/dist/esm/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/index.min.js +0 -12
- package/node_modules/@isaacs/cliui/dist/esm/index.min.js.map +0 -7
- package/node_modules/@isaacs/cliui/dist/esm/package.json +0 -3
- package/node_modules/@isaacs/cliui/dist/esm/string-width/index.d.ts +0 -5
- package/node_modules/@isaacs/cliui/dist/esm/string-width/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/string-width/index.js +0 -46
- package/node_modules/@isaacs/cliui/dist/esm/string-width/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/strip-ansi/index.d.ts +0 -2
- package/node_modules/@isaacs/cliui/dist/esm/strip-ansi/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/strip-ansi/index.js +0 -4
- package/node_modules/@isaacs/cliui/dist/esm/strip-ansi/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/wrap-ansi/index.d.ts +0 -7
- package/node_modules/@isaacs/cliui/dist/esm/wrap-ansi/index.d.ts.map +0 -1
- package/node_modules/@isaacs/cliui/dist/esm/wrap-ansi/index.js +0 -172
- package/node_modules/@isaacs/cliui/dist/esm/wrap-ansi/index.js.map +0 -1
- package/node_modules/@isaacs/cliui/package.json +0 -163
- package/node_modules/content-disposition/HISTORY.md +0 -60
- package/node_modules/cross-spawn/LICENSE +0 -21
- package/node_modules/cross-spawn/README.md +0 -89
- package/node_modules/cross-spawn/index.js +0 -39
- package/node_modules/cross-spawn/lib/enoent.js +0 -59
- package/node_modules/cross-spawn/lib/parse.js +0 -91
- package/node_modules/cross-spawn/lib/util/escape.js +0 -47
- package/node_modules/cross-spawn/lib/util/readShebang.js +0 -23
- package/node_modules/cross-spawn/lib/util/resolveCommand.js +0 -52
- package/node_modules/cross-spawn/package.json +0 -73
- package/node_modules/foreground-child/LICENSE +0 -15
- package/node_modules/foreground-child/README.md +0 -128
- package/node_modules/foreground-child/dist/commonjs/all-signals.d.ts +0 -2
- package/node_modules/foreground-child/dist/commonjs/all-signals.d.ts.map +0 -1
- package/node_modules/foreground-child/dist/commonjs/all-signals.js +0 -58
- package/node_modules/foreground-child/dist/commonjs/all-signals.js.map +0 -1
- package/node_modules/foreground-child/dist/commonjs/index.d.ts +0 -58
- package/node_modules/foreground-child/dist/commonjs/index.d.ts.map +0 -1
- package/node_modules/foreground-child/dist/commonjs/index.js +0 -123
- package/node_modules/foreground-child/dist/commonjs/index.js.map +0 -1
- package/node_modules/foreground-child/dist/commonjs/package.json +0 -3
- package/node_modules/foreground-child/dist/commonjs/proxy-signals.d.ts +0 -6
- package/node_modules/foreground-child/dist/commonjs/proxy-signals.d.ts.map +0 -1
- package/node_modules/foreground-child/dist/commonjs/proxy-signals.js +0 -38
- package/node_modules/foreground-child/dist/commonjs/proxy-signals.js.map +0 -1
- package/node_modules/foreground-child/dist/commonjs/watchdog.d.ts +0 -10
- package/node_modules/foreground-child/dist/commonjs/watchdog.d.ts.map +0 -1
- package/node_modules/foreground-child/dist/commonjs/watchdog.js +0 -50
- package/node_modules/foreground-child/dist/commonjs/watchdog.js.map +0 -1
- package/node_modules/foreground-child/dist/esm/all-signals.d.ts +0 -2
- package/node_modules/foreground-child/dist/esm/all-signals.d.ts.map +0 -1
- package/node_modules/foreground-child/dist/esm/all-signals.js +0 -52
- package/node_modules/foreground-child/dist/esm/all-signals.js.map +0 -1
- package/node_modules/foreground-child/dist/esm/index.d.ts +0 -58
- package/node_modules/foreground-child/dist/esm/index.d.ts.map +0 -1
- package/node_modules/foreground-child/dist/esm/index.js +0 -115
- package/node_modules/foreground-child/dist/esm/index.js.map +0 -1
- package/node_modules/foreground-child/dist/esm/package.json +0 -3
- package/node_modules/foreground-child/dist/esm/proxy-signals.d.ts +0 -6
- package/node_modules/foreground-child/dist/esm/proxy-signals.d.ts.map +0 -1
- package/node_modules/foreground-child/dist/esm/proxy-signals.js +0 -34
- package/node_modules/foreground-child/dist/esm/proxy-signals.js.map +0 -1
- package/node_modules/foreground-child/dist/esm/watchdog.d.ts +0 -10
- package/node_modules/foreground-child/dist/esm/watchdog.d.ts.map +0 -1
- package/node_modules/foreground-child/dist/esm/watchdog.js +0 -46
- package/node_modules/foreground-child/dist/esm/watchdog.js.map +0 -1
- package/node_modules/foreground-child/package.json +0 -106
- package/node_modules/glob/dist/esm/bin.d.mts +0 -3
- package/node_modules/glob/dist/esm/bin.d.mts.map +0 -1
- package/node_modules/glob/dist/esm/bin.mjs +0 -346
- package/node_modules/glob/dist/esm/bin.mjs.map +0 -1
- package/node_modules/isexe/.npmignore +0 -2
- package/node_modules/isexe/LICENSE +0 -15
- package/node_modules/isexe/README.md +0 -51
- package/node_modules/isexe/index.js +0 -57
- package/node_modules/isexe/mode.js +0 -41
- package/node_modules/isexe/package.json +0 -31
- package/node_modules/isexe/test/basic.js +0 -221
- package/node_modules/isexe/windows.js +0 -42
- package/node_modules/jackspeak/LICENSE.md +0 -55
- package/node_modules/jackspeak/README.md +0 -394
- package/node_modules/jackspeak/dist/commonjs/index.d.ts +0 -323
- package/node_modules/jackspeak/dist/commonjs/index.d.ts.map +0 -1
- package/node_modules/jackspeak/dist/commonjs/index.js +0 -944
- package/node_modules/jackspeak/dist/commonjs/index.js.map +0 -1
- package/node_modules/jackspeak/dist/commonjs/index.min.js +0 -33
- package/node_modules/jackspeak/dist/commonjs/index.min.js.map +0 -7
- package/node_modules/jackspeak/dist/commonjs/package.json +0 -3
- package/node_modules/jackspeak/dist/esm/index.d.ts +0 -323
- package/node_modules/jackspeak/dist/esm/index.d.ts.map +0 -1
- package/node_modules/jackspeak/dist/esm/index.js +0 -936
- package/node_modules/jackspeak/dist/esm/index.js.map +0 -1
- package/node_modules/jackspeak/dist/esm/index.min.js +0 -33
- package/node_modules/jackspeak/dist/esm/index.min.js.map +0 -7
- package/node_modules/jackspeak/dist/esm/package.json +0 -3
- package/node_modules/jackspeak/package.json +0 -115
- package/node_modules/jishushell-panel/output/public/assets/ApiKeyField-D1i7zWXR.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/Dashboard-sWIvL43F.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/HermesChatPanel-DQ8RyvQY.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/HermesConfigForm-tIbPP1sB.js +0 -4
- package/node_modules/jishushell-panel/output/public/assets/InitPassword-C3Slq3Dd.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/InstanceDetail-7JqY9tq4.js +0 -92
- package/node_modules/jishushell-panel/output/public/assets/Login-BXLDJlQN.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/NewInstance-dLc5Xrpx.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/ProviderRecommendations-DIAXxesl.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/Settings-Bd5utbBh.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/Setup-Yn9_20FL.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/WeixinLoginPanel-C21doQTJ.js +0 -9
- package/node_modules/jishushell-panel/output/public/assets/index-CCkaIEjn.js +0 -20
- package/node_modules/jishushell-panel/output/public/assets/index-D7qxy-Vh.css +0 -1
- package/node_modules/jishushell-panel/output/public/assets/registry-B2ZQZXWL.js +0 -2
- package/node_modules/jishushell-panel/output/public/assets/usePolling-BFZm4do_.js +0 -1
- package/node_modules/jishushell-panel/output/public/assets/vendor-i18n-DqPtOicc.js +0 -9
- package/node_modules/jishushell-panel/output/public/assets/vendor-react-DW5juQin.js +0 -59
- package/node_modules/package-json-from-dist/LICENSE.md +0 -63
- package/node_modules/package-json-from-dist/README.md +0 -110
- package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts +0 -89
- package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts.map +0 -1
- package/node_modules/package-json-from-dist/dist/commonjs/index.js +0 -134
- package/node_modules/package-json-from-dist/dist/commonjs/index.js.map +0 -1
- package/node_modules/package-json-from-dist/dist/commonjs/package.json +0 -3
- package/node_modules/package-json-from-dist/dist/esm/index.d.ts +0 -89
- package/node_modules/package-json-from-dist/dist/esm/index.d.ts.map +0 -1
- package/node_modules/package-json-from-dist/dist/esm/index.js +0 -129
- package/node_modules/package-json-from-dist/dist/esm/index.js.map +0 -1
- package/node_modules/package-json-from-dist/dist/esm/package.json +0 -3
- package/node_modules/package-json-from-dist/package.json +0 -68
- package/node_modules/path-key/index.d.ts +0 -40
- package/node_modules/path-key/index.js +0 -16
- package/node_modules/path-key/license +0 -9
- package/node_modules/path-key/package.json +0 -39
- package/node_modules/path-key/readme.md +0 -61
- package/node_modules/safe-buffer/LICENSE +0 -21
- package/node_modules/safe-buffer/README.md +0 -584
- package/node_modules/safe-buffer/index.d.ts +0 -187
- package/node_modules/safe-buffer/index.js +0 -65
- package/node_modules/safe-buffer/package.json +0 -51
- package/node_modules/shebang-command/index.js +0 -19
- package/node_modules/shebang-command/license +0 -9
- package/node_modules/shebang-command/package.json +0 -34
- package/node_modules/shebang-command/readme.md +0 -34
- package/node_modules/shebang-regex/index.d.ts +0 -22
- package/node_modules/shebang-regex/index.js +0 -2
- package/node_modules/shebang-regex/license +0 -9
- package/node_modules/shebang-regex/package.json +0 -35
- package/node_modules/shebang-regex/readme.md +0 -33
- package/node_modules/signal-exit/LICENSE.txt +0 -16
- package/node_modules/signal-exit/README.md +0 -74
- package/node_modules/signal-exit/dist/cjs/browser.d.ts +0 -12
- package/node_modules/signal-exit/dist/cjs/browser.d.ts.map +0 -1
- package/node_modules/signal-exit/dist/cjs/browser.js +0 -10
- package/node_modules/signal-exit/dist/cjs/browser.js.map +0 -1
- package/node_modules/signal-exit/dist/cjs/index.d.ts +0 -48
- package/node_modules/signal-exit/dist/cjs/index.d.ts.map +0 -1
- package/node_modules/signal-exit/dist/cjs/index.js +0 -279
- package/node_modules/signal-exit/dist/cjs/index.js.map +0 -1
- package/node_modules/signal-exit/dist/cjs/package.json +0 -3
- package/node_modules/signal-exit/dist/cjs/signals.d.ts +0 -29
- package/node_modules/signal-exit/dist/cjs/signals.d.ts.map +0 -1
- package/node_modules/signal-exit/dist/cjs/signals.js +0 -42
- package/node_modules/signal-exit/dist/cjs/signals.js.map +0 -1
- package/node_modules/signal-exit/dist/mjs/browser.d.ts +0 -12
- package/node_modules/signal-exit/dist/mjs/browser.d.ts.map +0 -1
- package/node_modules/signal-exit/dist/mjs/browser.js +0 -4
- package/node_modules/signal-exit/dist/mjs/browser.js.map +0 -1
- package/node_modules/signal-exit/dist/mjs/index.d.ts +0 -48
- package/node_modules/signal-exit/dist/mjs/index.d.ts.map +0 -1
- package/node_modules/signal-exit/dist/mjs/index.js +0 -275
- package/node_modules/signal-exit/dist/mjs/index.js.map +0 -1
- package/node_modules/signal-exit/dist/mjs/package.json +0 -3
- package/node_modules/signal-exit/dist/mjs/signals.d.ts +0 -29
- package/node_modules/signal-exit/dist/mjs/signals.d.ts.map +0 -1
- package/node_modules/signal-exit/dist/mjs/signals.js +0 -39
- package/node_modules/signal-exit/dist/mjs/signals.js.map +0 -1
- package/node_modules/signal-exit/package.json +0 -106
- package/node_modules/which/CHANGELOG.md +0 -166
- package/node_modules/which/LICENSE +0 -15
- package/node_modules/which/README.md +0 -54
- package/node_modules/which/bin/node-which +0 -52
- package/node_modules/which/package.json +0 -43
- package/node_modules/which/which.js +0 -125
- package/scripts/check-adapter-isolation.ts +0 -293
- /package/dist/services/{app → app-common}/app-compiler.d.ts +0 -0
- /package/dist/services/{app → app-common}/terminal-session-manager.d.ts +0 -0
- /package/dist/services/{backup-verify.d.ts → backup/backup-verify.d.ts} +0 -0
- /package/dist/services/{external-mounts.d.ts → files/external-mounts.d.ts} +0 -0
- /package/dist/services/{organize → files/organize}/applier.d.ts +0 -0
- /package/dist/services/{organize → files/organize}/rules.d.ts +0 -0
- /package/dist/services/{organize → files/organize}/scanner.d.ts +0 -0
- /package/dist/services/{organize → files/organize}/store.d.ts +0 -0
- /package/dist/services/{webdav → files/webdav}/xml-builder.d.ts +0 -0
- /package/dist/services/{webdav → files/webdav}/xml-builder.js +0 -0
- /package/dist/services/{app-passwords.d.ts → instances/passwords.d.ts} +0 -0
- /package/dist/services/{agent-apps → integrations/installable}/installers/registry-probe.d.ts +0 -0
- /package/dist/services/{agent-apps → integrations/installable}/installers/registry-probe.js +0 -0
- /package/dist/services/{runtime/mcp-shims → integrations/openclaw}/drive-shim.d.ts +0 -0
- /package/dist/services/{runtime/mcp-shims → integrations/openclaw}/mcporter-lite.d.ts +0 -0
- /package/dist/services/{plugin-installer.d.ts → setup/plugin-installer.d.ts} +0 -0
- /package/dist/services/{macos-launchd.d.ts → system/macos-launchd.d.ts} +0 -0
- /package/dist/services/{system-monitor.d.ts → system/system-monitor.d.ts} +0 -0
|
@@ -0,0 +1,1348 @@
|
|
|
1
|
+
import { execFileSync } from "child_process";
|
|
2
|
+
import { chownSync, closeSync, existsSync, openSync, readFileSync, readdirSync, renameSync, statSync, } from "fs";
|
|
3
|
+
import { rm as rmAsync } from "fs/promises";
|
|
4
|
+
import { createServer as netCreateServer } from "net";
|
|
5
|
+
import { networkInterfaces, userInfo } from "os";
|
|
6
|
+
import { dirname, join, resolve } from "path";
|
|
7
|
+
import * as config from "../../config.js";
|
|
8
|
+
import { safeReadJson, safeWriteJson } from "../../utils/safe-json.js";
|
|
9
|
+
import { ensureDirContainer, writeSecretFile } from "../../utils/fs.js";
|
|
10
|
+
// integrations/index.ts gets imported only for framework-level integration lookups
|
|
11
|
+
// (preferredHostPort allocator seed). Integrations statically import BACK into this
|
|
12
|
+
// file for primitives; that static cycle is safe because no top-level code
|
|
13
|
+
// in integrations references instance-manager exports.
|
|
14
|
+
import { getIntegration } from "../integrations/index.js";
|
|
15
|
+
import { isExecutionOwnerRequiredError, resolveExecutionOwnerFromMetadata, } from "../app-common/execution-owner.js";
|
|
16
|
+
import { buildCanonicalAppInstance, readCanonicalInstance, readSpecSnapshotFromDir, } from "../app-common/instance-store.js";
|
|
17
|
+
import { DEFINITION_FILENAME, INSTANCE_METADATA_FILENAME, MANIFEST_FILENAME, RESOLVED_SPEC_FILENAME, resolveAppDir, } from "../app-common/paths.js";
|
|
18
|
+
function getConfigValue(name) {
|
|
19
|
+
return name in config ? config[name] : undefined;
|
|
20
|
+
}
|
|
21
|
+
function resolveConfigPath(value, fallback) {
|
|
22
|
+
return typeof value === "string" && value.trim() ? value : fallback;
|
|
23
|
+
}
|
|
24
|
+
const JISHUSHELL_HOME = resolveConfigPath(getConfigValue("JISHUSHELL_HOME"), resolve(process.env.HOME ?? userInfo().homedir, ".jishushell"));
|
|
25
|
+
const APPS_DIR = resolveConfigPath(getConfigValue("APPS_DIR"), join(JISHUSHELL_HOME, "apps"));
|
|
26
|
+
const BACKUPS_DIR = resolveConfigPath(getConfigValue("BACKUPS_DIR"), join(JISHUSHELL_HOME, "backups"));
|
|
27
|
+
const getCoreConfigValue = getConfigValue("getCoreConfig");
|
|
28
|
+
const _getCoreConfig = typeof getCoreConfigValue === "function"
|
|
29
|
+
? getCoreConfigValue
|
|
30
|
+
: () => ({});
|
|
31
|
+
const _configChangeListeners = [];
|
|
32
|
+
export function onConfigChange(listener) {
|
|
33
|
+
_configChangeListeners.push(listener);
|
|
34
|
+
return () => {
|
|
35
|
+
const idx = _configChangeListeners.indexOf(listener);
|
|
36
|
+
if (idx >= 0)
|
|
37
|
+
_configChangeListeners.splice(idx, 1);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Fire the config-change listener fan-out. Integrations call this after
|
|
42
|
+
* `saveNativeConfig()` so LLM proxy / config editors pick up the change.
|
|
43
|
+
*/
|
|
44
|
+
export function notifyConfigChange(instanceId) {
|
|
45
|
+
for (const listener of _configChangeListeners) {
|
|
46
|
+
try {
|
|
47
|
+
listener(instanceId);
|
|
48
|
+
}
|
|
49
|
+
catch { /* ignore listener errors */ }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
53
|
+
// ── Path helpers (framework-level) ──
|
|
54
|
+
function hasIncompleteAppInstallShadow(dir) {
|
|
55
|
+
const markers = [
|
|
56
|
+
MANIFEST_FILENAME,
|
|
57
|
+
DEFINITION_FILENAME,
|
|
58
|
+
RESOLVED_SPEC_FILENAME,
|
|
59
|
+
INSTANCE_METADATA_FILENAME,
|
|
60
|
+
].map((fileName) => existsSync(join(dir, fileName)));
|
|
61
|
+
return markers.some(Boolean) && !markers.every(Boolean);
|
|
62
|
+
}
|
|
63
|
+
function resolveInstanceRoot(instanceId) {
|
|
64
|
+
// Step 13: canonical `apps/<id>` only on the runtime path. Un-migrated
|
|
65
|
+
// `instances/<id>` directories must be handled by `jishushell migrate legacy`.
|
|
66
|
+
return resolveAppDir(instanceId);
|
|
67
|
+
}
|
|
68
|
+
export function instanceDir(instanceId) {
|
|
69
|
+
return resolveInstanceRoot(instanceId);
|
|
70
|
+
}
|
|
71
|
+
export function instanceMetaPath(instanceId) {
|
|
72
|
+
return join(instanceDir(instanceId), INSTANCE_METADATA_FILENAME);
|
|
73
|
+
}
|
|
74
|
+
// Default model env file path. Integration-specific resolvers live on the app
|
|
75
|
+
// integration; this helper provides the framework-level fallback.
|
|
76
|
+
export function defaultModelEnvFile(instanceId) {
|
|
77
|
+
return join(instanceDir(instanceId), "model.env");
|
|
78
|
+
}
|
|
79
|
+
export function normalizePath(p) {
|
|
80
|
+
return resolve(p.replace(/^~/, userInfo().homedir));
|
|
81
|
+
}
|
|
82
|
+
// ── Host port allocator ──
|
|
83
|
+
//
|
|
84
|
+
// Domain semantics (canonical port model, per Step 2 of the App Lifecycle
|
|
85
|
+
// Runtime decision):
|
|
86
|
+
// - `hostPort` is the host-side port Core exposes for an instance. Core's
|
|
87
|
+
// allocator is the ONLY decider. Nomad/Docker may not reverse-decide it.
|
|
88
|
+
// - `containerPort` is the in-container listener owned by the workload and
|
|
89
|
+
// must remain stable across host-port reallocations.
|
|
90
|
+
// - The persisted source of truth is `runtime.ports[].hostPort` on each
|
|
91
|
+
// instance's `instance.json`.
|
|
92
|
+
//
|
|
93
|
+
// In-memory reservation table.
|
|
94
|
+
//
|
|
95
|
+
// `_pendingPorts` exists to close the race window between
|
|
96
|
+
// 1. the allocator decided a host port is free, and
|
|
97
|
+
// 2. that decision is durably persisted into `instance.json`.
|
|
98
|
+
//
|
|
99
|
+
// The canonical allocator lifecycle is:
|
|
100
|
+
// - `reserve` (internal): set by `allocateHostPort` before the async
|
|
101
|
+
// `isPortInUse` probe, so a concurrent caller cannot select the same port
|
|
102
|
+
// during the await gap.
|
|
103
|
+
// - `commit`: invoked by the caller AFTER `runtime.ports[].hostPort` is
|
|
104
|
+
// durably written. The reservation slot is freed because durable
|
|
105
|
+
// ownership has taken over.
|
|
106
|
+
// - `release`: invoked by the caller on any failure path before the
|
|
107
|
+
// durable write succeeds. The reservation slot is freed so concurrent /
|
|
108
|
+
// retried allocations can reuse the port.
|
|
109
|
+
//
|
|
110
|
+
// The shape is exposed via the `HostPortAllocation` object returned by
|
|
111
|
+
// `allocateHostPort`. Callers must use that object's `commit()` /
|
|
112
|
+
// `release()` and must NOT lean on the legacy "finally { releasePendingPort
|
|
113
|
+
// } " pattern; that pattern conflates success and failure paths and was
|
|
114
|
+
// explicitly called out as forbidden in Step 2.
|
|
115
|
+
//
|
|
116
|
+
// No cross-process reconcile is required for this table: it is a transient
|
|
117
|
+
// in-memory Map; on Core restart it starts empty. Any port whose durable
|
|
118
|
+
// `runtime.ports[].hostPort` got written before the crash is already owned
|
|
119
|
+
// by the surviving `instance.json`; any port that was only reserved (no
|
|
120
|
+
// durable write yet) is simply lost on restart, which is the correct
|
|
121
|
+
// behaviour — the instance never existed.
|
|
122
|
+
const _pendingPorts = new Map();
|
|
123
|
+
export const INSTANCE_NEEDS_MIGRATION_CODE = "INSTANCE_NEEDS_MIGRATION";
|
|
124
|
+
export class CanonicalRuntimePortRequiredError extends Error {
|
|
125
|
+
code = INSTANCE_NEEDS_MIGRATION_CODE;
|
|
126
|
+
statusCode = 409;
|
|
127
|
+
instanceId;
|
|
128
|
+
constructor(instanceId) {
|
|
129
|
+
super(`Instance '${instanceId}' has no canonical runtime.ports[] host-port allocation. ` +
|
|
130
|
+
"Legacy host-port fields are no longer read on lifecycle/status/proxy paths. " +
|
|
131
|
+
"Run `jishushell system repair-instances` or `jishushell migrate legacy --yes` before retrying.");
|
|
132
|
+
this.name = "CanonicalRuntimePortRequiredError";
|
|
133
|
+
this.instanceId = instanceId;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function isCanonicalRuntimePortRequiredError(error) {
|
|
137
|
+
return error instanceof CanonicalRuntimePortRequiredError
|
|
138
|
+
|| (!!error
|
|
139
|
+
&& typeof error === "object"
|
|
140
|
+
&& error.code === INSTANCE_NEEDS_MIGRATION_CODE);
|
|
141
|
+
}
|
|
142
|
+
function reservePendingPort(instanceId, port) {
|
|
143
|
+
_pendingPorts.set(port, instanceId);
|
|
144
|
+
}
|
|
145
|
+
function clearPendingPort(port, instanceId) {
|
|
146
|
+
const owner = _pendingPorts.get(port);
|
|
147
|
+
if (owner == null)
|
|
148
|
+
return;
|
|
149
|
+
if (instanceId && owner !== instanceId)
|
|
150
|
+
return;
|
|
151
|
+
_pendingPorts.delete(port);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Read the primary externally reachable host port out of a persisted runtime record.
|
|
155
|
+
*
|
|
156
|
+
* Runtime hot paths only trust canonical `runtime.ports[].hostPort`.
|
|
157
|
+
* Legacy env/args fallbacks are repair-only readers owned by the migrator or
|
|
158
|
+
* integration repair code and must not be consulted here.
|
|
159
|
+
*/
|
|
160
|
+
export function extractPrimaryHostPort(runtime, _integrationKind) {
|
|
161
|
+
if (!runtime)
|
|
162
|
+
return null;
|
|
163
|
+
// Primary: RuntimeSpec.ports[] declaration. Prefer the first externally
|
|
164
|
+
// visible port; fall back to any hostPort only for malformed/legacy records.
|
|
165
|
+
const ports = Array.isArray(runtime.ports) ? runtime.ports : [];
|
|
166
|
+
for (const port of ports) {
|
|
167
|
+
if ((port?.visibility ?? "external") !== "internal" && Number.isInteger(port.hostPort) && port.hostPort > 0) {
|
|
168
|
+
return port.hostPort;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
for (const port of ports) {
|
|
172
|
+
if (Number.isInteger(port?.hostPort) && port.hostPort > 0) {
|
|
173
|
+
return port.hostPort;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
function requireCanonicalPrimaryHostPort(instanceId, runtime) {
|
|
179
|
+
const port = extractPrimaryHostPort(runtime);
|
|
180
|
+
if (port)
|
|
181
|
+
return port;
|
|
182
|
+
throw new CanonicalRuntimePortRequiredError(instanceId);
|
|
183
|
+
}
|
|
184
|
+
function usedHostPorts(excludeId, excludeHostPort, options = {}) {
|
|
185
|
+
const ports = new Set();
|
|
186
|
+
for (const inst of listInstances()) {
|
|
187
|
+
const hasIntegration = Array.isArray(inst.integrations)
|
|
188
|
+
&& inst.integrations.length > 0;
|
|
189
|
+
const runtimePorts = Array.isArray(inst.runtime?.ports) ? inst.runtime.ports : [];
|
|
190
|
+
const canonicalHostPorts = runtimePorts
|
|
191
|
+
.map((port) => port?.hostPort)
|
|
192
|
+
.filter((port) => Number.isInteger(port) && Number(port) > 0);
|
|
193
|
+
if (options.ignoreIncompleteCanonicalInstanceIds?.has(inst.id)
|
|
194
|
+
&& hasIntegration
|
|
195
|
+
&& canonicalHostPorts.length === 0) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (canonicalHostPorts.length === 0 && hasIntegration) {
|
|
199
|
+
throw new CanonicalRuntimePortRequiredError(inst.id);
|
|
200
|
+
}
|
|
201
|
+
for (const port of canonicalHostPorts) {
|
|
202
|
+
if (inst.id === excludeId && (excludeHostPort == null || port === excludeHostPort))
|
|
203
|
+
continue;
|
|
204
|
+
ports.add(port);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return ports;
|
|
208
|
+
}
|
|
209
|
+
function safePort(port) {
|
|
210
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
211
|
+
throw new Error(`Invalid port: ${port}`);
|
|
212
|
+
return String(port);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Probes whether a port is currently held by any process on the host.
|
|
216
|
+
*
|
|
217
|
+
* Binds four addresses concurrently — `0.0.0.0`, `127.0.0.1`, `::` (v6-only),
|
|
218
|
+
* and `::1` — and treats the port as busy if any probe returns EADDRINUSE.
|
|
219
|
+
* The single-`0.0.0.0` probe used by the earlier revision was sufficient on
|
|
220
|
+
* Linux (where binding `0.0.0.0` conflicts with any pre-existing loopback
|
|
221
|
+
* listener on the same port) but silently passed on macOS, where BSD socket
|
|
222
|
+
* semantics let a wildcard v4 bind coexist with a `127.0.0.1` listener. A
|
|
223
|
+
* loopback-only service would then be invisible to JishuShell, so port
|
|
224
|
+
* allocation could assign the same host port to a new instance and the
|
|
225
|
+
* workload would silently fail to bind at start time. Probing the loopback
|
|
226
|
+
* addresses directly closes that gap.
|
|
227
|
+
*/
|
|
228
|
+
export function isPortInUse(port) {
|
|
229
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
230
|
+
return Promise.resolve(false);
|
|
231
|
+
const probeAt = (host, opts = {}) => new Promise((resolve) => {
|
|
232
|
+
const server = netCreateServer();
|
|
233
|
+
server.once("error", (err) => {
|
|
234
|
+
if (err?.code === "EADDRINUSE")
|
|
235
|
+
return resolve(true);
|
|
236
|
+
// EACCES / EADDRNOTAVAIL / ENOTSUP / EINVAL mean we could not even
|
|
237
|
+
// attempt the bind (restricted port, address family unsupported on
|
|
238
|
+
// this host, etc). Report "not busy" from this probe so one bad
|
|
239
|
+
// locus doesn't falsely block the whole port — the other probes
|
|
240
|
+
// still cover their respective loci.
|
|
241
|
+
if (err?.code && err.code !== "EACCES" && err.code !== "EADDRNOTAVAIL"
|
|
242
|
+
&& err.code !== "ENOTSUP" && err.code !== "EINVAL" && err.code !== "EAFNOSUPPORT") {
|
|
243
|
+
console.warn(`[port-probe] bind ${host}:${port} failed with ${err.code}: ${err.message}; treating locus as free`);
|
|
244
|
+
}
|
|
245
|
+
resolve(false);
|
|
246
|
+
});
|
|
247
|
+
server.once("listening", () => {
|
|
248
|
+
server.close(() => resolve(false));
|
|
249
|
+
});
|
|
250
|
+
server.listen({ port, host, ...opts });
|
|
251
|
+
});
|
|
252
|
+
// Run probes sequentially, not in parallel: two probes on the same port
|
|
253
|
+
// collide with each other (the first bind on 0.0.0.0 makes the second
|
|
254
|
+
// bind on 127.0.0.1 hit EADDRINUSE), which would make every port look
|
|
255
|
+
// busy. Short-circuit on the first busy locus to keep the common case
|
|
256
|
+
// (port free) close to single-probe latency.
|
|
257
|
+
return (async () => {
|
|
258
|
+
const loci = [
|
|
259
|
+
["0.0.0.0", {}],
|
|
260
|
+
["127.0.0.1", {}],
|
|
261
|
+
["::", { ipv6Only: true }],
|
|
262
|
+
["::1", {}],
|
|
263
|
+
];
|
|
264
|
+
for (const [host, opts] of loci) {
|
|
265
|
+
if (await probeAt(host, opts))
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
return false;
|
|
269
|
+
})();
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Kind-agnostic host-port allocator (canonical port model).
|
|
273
|
+
*
|
|
274
|
+
* Walks upward from `defaultPort` until a free host port is found that is
|
|
275
|
+
* neither held by any canonical runtime port on an existing instance, nor by
|
|
276
|
+
* a pending reservation, nor by any listener on the host. The historical
|
|
277
|
+
* Callers may use it for every external runtime port.
|
|
278
|
+
*
|
|
279
|
+
* Concurrent callers coordinate through `_pendingPorts`: each candidate port
|
|
280
|
+
* is reserved BEFORE the async `isPortInUse` probe so concurrent calls cannot
|
|
281
|
+
* select the same port during the await gap. The returned allocation owns
|
|
282
|
+
* the lifecycle from there: the caller
|
|
283
|
+
* MUST call `commit()` once the chosen port is durably persisted, or
|
|
284
|
+
* `release()` on any failure path. Calling neither leaks the reservation
|
|
285
|
+
* slot until process restart.
|
|
286
|
+
*/
|
|
287
|
+
export async function allocateHostPort(instanceId, defaultPort, replacingHostPort, options = {}) {
|
|
288
|
+
const used = usedHostPorts(instanceId, replacingHostPort, options);
|
|
289
|
+
const skipped = [];
|
|
290
|
+
let port = defaultPort;
|
|
291
|
+
while (true) {
|
|
292
|
+
if (port > 65535) {
|
|
293
|
+
throw new Error(`No available host port found (all ports ${defaultPort}-65535 in use)`);
|
|
294
|
+
}
|
|
295
|
+
if (used.has(port) || _pendingPorts.has(port)) {
|
|
296
|
+
skipped.push(port);
|
|
297
|
+
port++;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
// Reserve BEFORE the async isPortInUse check to prevent concurrent callers
|
|
301
|
+
// from selecting the same port during the await gap.
|
|
302
|
+
reservePendingPort(instanceId, port);
|
|
303
|
+
const reservation = {
|
|
304
|
+
instanceId,
|
|
305
|
+
port,
|
|
306
|
+
skipped,
|
|
307
|
+
commit: () => {
|
|
308
|
+
clearPendingPort(port, instanceId);
|
|
309
|
+
return port;
|
|
310
|
+
},
|
|
311
|
+
release: () => {
|
|
312
|
+
clearPendingPort(port, instanceId);
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
try {
|
|
316
|
+
if (await isPortInUse(port)) {
|
|
317
|
+
reservation.release();
|
|
318
|
+
skipped.push(port);
|
|
319
|
+
port++;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
return reservation;
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
reservation.release();
|
|
326
|
+
// Skip this port on a transient OS error rather than failing the entire
|
|
327
|
+
// allocation — a single bad port check should not prevent instance creation.
|
|
328
|
+
console.warn(`[instance] Port ${port} availability check failed, trying next port`);
|
|
329
|
+
skipped.push(port);
|
|
330
|
+
port++;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Legacy by-port release helper.
|
|
337
|
+
*
|
|
338
|
+
* Production code MUST use the `commit()` / `release()` methods on the
|
|
339
|
+
* {@link HostPortAllocation} returned from {@link allocateHostPort};
|
|
340
|
+
* those make the success-vs-failure split explicit, which is the Step 2
|
|
341
|
+
* canonical contract. This function is kept only as a test/facade compatibility
|
|
342
|
+
* export for older call sites that still talk to the allocator by port number.
|
|
343
|
+
* Normal production code should not need it.
|
|
344
|
+
*/
|
|
345
|
+
export function releasePendingPort(port) {
|
|
346
|
+
clearPendingPort(port);
|
|
347
|
+
}
|
|
348
|
+
// ── Runtime / config builders ──
|
|
349
|
+
/**
|
|
350
|
+
* When jishushell runs as root (e.g. systemd service), returns the actual
|
|
351
|
+
* non-root user that should own instance files and run workload processes.
|
|
352
|
+
* Returns null when not running as root or when no suitable non-root user is found.
|
|
353
|
+
*/
|
|
354
|
+
export function resolveServiceUser() {
|
|
355
|
+
if (typeof process.getuid !== "function" || process.getuid() !== 0)
|
|
356
|
+
return null;
|
|
357
|
+
// SUDO_USER is set when launched via `sudo`
|
|
358
|
+
const sudoUser = process.env.SUDO_USER;
|
|
359
|
+
if (sudoUser && sudoUser !== "root") {
|
|
360
|
+
try {
|
|
361
|
+
const uid = parseInt(execFileSync("id", ["-u", sudoUser], { encoding: "utf-8" }).trim(), 10);
|
|
362
|
+
const gid = parseInt(execFileSync("id", ["-g", sudoUser], { encoding: "utf-8" }).trim(), 10);
|
|
363
|
+
if (!isNaN(uid) && !isNaN(gid))
|
|
364
|
+
return { username: sudoUser, uid, gid };
|
|
365
|
+
}
|
|
366
|
+
catch { /* fall through */ }
|
|
367
|
+
}
|
|
368
|
+
// Fall back to owner of APPS_DIR or JISHUSHELL_HOME
|
|
369
|
+
try {
|
|
370
|
+
const target = existsSync(APPS_DIR) ? APPS_DIR : JISHUSHELL_HOME;
|
|
371
|
+
const uid = statSync(target).uid;
|
|
372
|
+
if (uid !== 0) {
|
|
373
|
+
const username = execFileSync("id", ["-un", String(uid)], { encoding: "utf-8" }).trim();
|
|
374
|
+
const gid = parseInt(execFileSync("id", ["-g", username], { encoding: "utf-8" }).trim(), 10);
|
|
375
|
+
if (!isNaN(gid))
|
|
376
|
+
return { username, uid, gid };
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
catch { /* fall through */ }
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* When running as root, chown a file (and its .bak) to the service user so the
|
|
384
|
+
* workload process (running as that user) can read/write its own data files.
|
|
385
|
+
* No-op when not running as root.
|
|
386
|
+
*/
|
|
387
|
+
export function chownToServiceUser(...paths) {
|
|
388
|
+
const svc = resolveServiceUser();
|
|
389
|
+
if (!svc)
|
|
390
|
+
return;
|
|
391
|
+
for (const p of paths) {
|
|
392
|
+
for (const f of [p, p + ".bak", p + ".bak.1", p + ".bak.2"]) {
|
|
393
|
+
try {
|
|
394
|
+
if (existsSync(f))
|
|
395
|
+
chownSync(f, svc.uid, svc.gid);
|
|
396
|
+
}
|
|
397
|
+
catch { /* best effort */ }
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// ── Env file helpers ──
|
|
402
|
+
export function parseEnvFile(path) {
|
|
403
|
+
const env = {};
|
|
404
|
+
if (!existsSync(path))
|
|
405
|
+
return env;
|
|
406
|
+
for (let line of readFileSync(path, "utf-8").split("\n")) {
|
|
407
|
+
line = line.trim();
|
|
408
|
+
if (!line || line.startsWith("#"))
|
|
409
|
+
continue;
|
|
410
|
+
if (line.startsWith("export "))
|
|
411
|
+
line = line.slice(7).trimStart();
|
|
412
|
+
if (!line.includes("="))
|
|
413
|
+
continue;
|
|
414
|
+
const eqIdx = line.indexOf("=");
|
|
415
|
+
const key = line.slice(0, eqIdx).trim();
|
|
416
|
+
let value = line.slice(eqIdx + 1).trim();
|
|
417
|
+
if (!ENV_KEY_RE.test(key))
|
|
418
|
+
continue;
|
|
419
|
+
if (value.length >= 2 && value[0] === value[value.length - 1] && (value[0] === "'" || value[0] === '"')) {
|
|
420
|
+
value = value.slice(1, -1);
|
|
421
|
+
}
|
|
422
|
+
env[key] = value;
|
|
423
|
+
}
|
|
424
|
+
return env;
|
|
425
|
+
}
|
|
426
|
+
function quoteEnvValue(value) {
|
|
427
|
+
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value))
|
|
428
|
+
return value;
|
|
429
|
+
return JSON.stringify(value);
|
|
430
|
+
}
|
|
431
|
+
export function updateEnvFile(path, updates) {
|
|
432
|
+
ensureDirContainer(dirname(path));
|
|
433
|
+
const existing = existsSync(path) ? readFileSync(path, "utf-8").split("\n") : [];
|
|
434
|
+
const remaining = { ...updates };
|
|
435
|
+
const newLines = [];
|
|
436
|
+
for (const rawLine of existing) {
|
|
437
|
+
const stripped = rawLine.trim();
|
|
438
|
+
const candidate = stripped.startsWith("export ") ? stripped.slice(7).trimStart() : stripped;
|
|
439
|
+
if (!candidate || candidate.startsWith("#") || !candidate.includes("=")) {
|
|
440
|
+
newLines.push(rawLine);
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
const key = candidate.slice(0, candidate.indexOf("=")).trim();
|
|
444
|
+
if (!ENV_KEY_RE.test(key) || !(key in remaining)) {
|
|
445
|
+
newLines.push(rawLine);
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
const value = remaining[key];
|
|
449
|
+
delete remaining[key];
|
|
450
|
+
if (value === "")
|
|
451
|
+
continue;
|
|
452
|
+
const prefix = stripped.startsWith("export ") ? "export " : "";
|
|
453
|
+
newLines.push(`${prefix}${key}=${quoteEnvValue(value)}`);
|
|
454
|
+
}
|
|
455
|
+
for (const [key, value] of Object.entries(remaining)) {
|
|
456
|
+
if (!ENV_KEY_RE.test(key) || value === "")
|
|
457
|
+
continue;
|
|
458
|
+
newLines.push(`${key}=${quoteEnvValue(value)}`);
|
|
459
|
+
}
|
|
460
|
+
const output = newLines.join("\n").trimEnd();
|
|
461
|
+
const content = output ? output + "\n" : "";
|
|
462
|
+
// Atomic write: tmp then rename to protect against RPi power loss
|
|
463
|
+
const tmp = path + ".tmp";
|
|
464
|
+
writeSecretFile(tmp, content);
|
|
465
|
+
renameSync(tmp, path);
|
|
466
|
+
chownToServiceUser(path);
|
|
467
|
+
}
|
|
468
|
+
// ── Provider key helpers ──
|
|
469
|
+
export function inferProviderApiKeyEnvName(providerId) {
|
|
470
|
+
let normalized = providerId.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_|_$/g, "").toUpperCase();
|
|
471
|
+
if (!normalized)
|
|
472
|
+
normalized = "JISHUSHELL_PROVIDER";
|
|
473
|
+
return `${normalized}_API_KEY`;
|
|
474
|
+
}
|
|
475
|
+
// ── Public API ──
|
|
476
|
+
/**
|
|
477
|
+
* Probe whether a file is readable by the current process. Used to
|
|
478
|
+
* distinguish "primary missing / corrupted" (recoverable via safeReadJson's
|
|
479
|
+
* .bak chain) from "primary exists but permission denied" (EACCES — the
|
|
480
|
+
* common sudo-script footgun that leaves root-owned files). safeReadJson
|
|
481
|
+
* swallows every read error internally and returns null, so without this
|
|
482
|
+
* probe an unreadable primary looks identical to a truly-gone instance.
|
|
483
|
+
*/
|
|
484
|
+
function probeReadable(path) {
|
|
485
|
+
if (!existsSync(path))
|
|
486
|
+
return null;
|
|
487
|
+
try {
|
|
488
|
+
const fd = openSync(path, "r");
|
|
489
|
+
closeSync(fd);
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
catch (e) {
|
|
493
|
+
return e;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
export function listInstances() {
|
|
497
|
+
const deduped = new Map();
|
|
498
|
+
// Step 13: canonical `apps/<id>` only. Un-migrated `instances/<id>`
|
|
499
|
+
// directories are surfaced exclusively by `jishushell migrate legacy`.
|
|
500
|
+
const rootDir = APPS_DIR;
|
|
501
|
+
if (existsSync(rootDir)) {
|
|
502
|
+
const entries = readdirSync(rootDir).sort();
|
|
503
|
+
for (const name of entries) {
|
|
504
|
+
if (deduped.has(name))
|
|
505
|
+
continue;
|
|
506
|
+
const metaPath = join(rootDir, name, "instance.json");
|
|
507
|
+
const dirPath = join(rootDir, name);
|
|
508
|
+
try {
|
|
509
|
+
if (!statSync(dirPath).isDirectory())
|
|
510
|
+
continue;
|
|
511
|
+
if (hasIncompleteAppInstallShadow(dirPath))
|
|
512
|
+
continue;
|
|
513
|
+
if (!existsSync(metaPath))
|
|
514
|
+
continue;
|
|
515
|
+
// Use safeReadJson so primary instance.json that was corrupted or
|
|
516
|
+
// deleted mid-rename falls back to the .bak chain maintained by
|
|
517
|
+
// safeWriteJson. Without this, an interrupted safeWriteJson call
|
|
518
|
+
// would silently drop the instance from every list/get hot path
|
|
519
|
+
// even though the backup chain still holds valid content on disk.
|
|
520
|
+
const meta = readCanonicalInstance(name);
|
|
521
|
+
if (meta) {
|
|
522
|
+
deduped.set(name, meta);
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
// safeReadJson → null can mean any of (a) primary missing + no
|
|
526
|
+
// backups, (b) all candidates unparseable, (c) permission denied.
|
|
527
|
+
// (a) and (b) are legitimate "drop from list" cases; (c) is the
|
|
528
|
+
// sudo-script footgun and must be logged loudly so the operator
|
|
529
|
+
// doesn't just see an empty instance list with no hint why.
|
|
530
|
+
const readErr = probeReadable(metaPath);
|
|
531
|
+
if (readErr && readErr.code === "EACCES") {
|
|
532
|
+
console.error(`[instance-manager] cannot read instance '${name}': ${readErr.message}. ` +
|
|
533
|
+
`Check file ownership with: ls -la ${metaPath}`);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
catch (e) {
|
|
537
|
+
// Fallback for failures before the safeReadJson call (e.g. statSync
|
|
538
|
+
// on a directory we can't enter). Still log instead of silently
|
|
539
|
+
// dropping the entry.
|
|
540
|
+
console.error(`[instance-manager] cannot read instance '${name}': ${e.message}`);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return [...deduped.values()];
|
|
545
|
+
}
|
|
546
|
+
export function getInstance(instanceId) {
|
|
547
|
+
const metaPath = instanceMetaPath(instanceId);
|
|
548
|
+
// Go through safeReadJson so primary missing/corrupted instance.json
|
|
549
|
+
// is still served from the .bak chain. Returning null on "truly gone"
|
|
550
|
+
// (no primary, no backups) keeps the existing 404 behavior intact.
|
|
551
|
+
const meta = readCanonicalInstance(instanceId);
|
|
552
|
+
if (meta) {
|
|
553
|
+
return meta;
|
|
554
|
+
}
|
|
555
|
+
// safeReadJson swallows every read error internally, which is exactly
|
|
556
|
+
// wrong for the EACCES case — a root-owned primary would silently
|
|
557
|
+
// return null and callers would report "Instance not found" instead
|
|
558
|
+
// of the actionable "check file ownership" message. Re-probe to
|
|
559
|
+
// distinguish and throw on permission denial. Missing/corrupted with
|
|
560
|
+
// no backup still returns null (→ 404 upstream).
|
|
561
|
+
const readErr = probeReadable(metaPath);
|
|
562
|
+
if (readErr && readErr.code === "EACCES") {
|
|
563
|
+
throw new Error(`Cannot read instance '${instanceId}' metadata: ${readErr.message}. ` +
|
|
564
|
+
`Check file ownership with: ls -la ${metaPath}`);
|
|
565
|
+
}
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
export function updateInstance(instanceId, name, description) {
|
|
569
|
+
const meta = getInstance(instanceId);
|
|
570
|
+
if (!meta)
|
|
571
|
+
return null;
|
|
572
|
+
if (name != null)
|
|
573
|
+
meta.name = name;
|
|
574
|
+
if (description != null)
|
|
575
|
+
meta.description = description;
|
|
576
|
+
const snapshot = readSpecSnapshotFromDir(instanceDir(instanceId));
|
|
577
|
+
const next = buildCanonicalAppInstance({
|
|
578
|
+
raw: meta,
|
|
579
|
+
id: instanceId,
|
|
580
|
+
name: meta.name,
|
|
581
|
+
description: meta.description,
|
|
582
|
+
spec: snapshot?.spec ?? null,
|
|
583
|
+
});
|
|
584
|
+
safeWriteJson(instanceMetaPath(instanceId), next);
|
|
585
|
+
chownToServiceUser(instanceMetaPath(instanceId));
|
|
586
|
+
return next;
|
|
587
|
+
}
|
|
588
|
+
export function updateInstanceMeta(instanceId, patch) {
|
|
589
|
+
const metaPath = instanceMetaPath(instanceId);
|
|
590
|
+
const meta = getInstance(instanceId);
|
|
591
|
+
if (!meta)
|
|
592
|
+
throw new Error(`Cannot update unknown instance '${instanceId}'`);
|
|
593
|
+
Object.assign(meta, patch);
|
|
594
|
+
const snapshot = readSpecSnapshotFromDir(instanceDir(instanceId));
|
|
595
|
+
const next = buildCanonicalAppInstance({
|
|
596
|
+
raw: meta,
|
|
597
|
+
id: instanceId,
|
|
598
|
+
name: typeof meta.name === "string" ? meta.name : undefined,
|
|
599
|
+
description: typeof meta.description === "string" ? meta.description : undefined,
|
|
600
|
+
spec: snapshot?.spec ?? null,
|
|
601
|
+
});
|
|
602
|
+
safeWriteJson(metaPath, next);
|
|
603
|
+
chownToServiceUser(metaPath);
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Toggle the opt-in "privileged" (native-install-like) profile on an
|
|
607
|
+
* OpenClaw instance's docker task. Default (false / absent) keeps the
|
|
608
|
+
* hardened container (cap_drop=ALL, no-new-privileges, read-only rootfs).
|
|
609
|
+
* When enabled, `OpenClawAdapter.buildNomadTask` relaxes those so the agent
|
|
610
|
+
* has native-install-like permissions. Persisted in `instance.json` runtime
|
|
611
|
+
* so it survives restarts and is reapplied on every Nomad job submit.
|
|
612
|
+
* Returns false when the instance does not exist. Caller must restart the
|
|
613
|
+
* instance for the change to take effect.
|
|
614
|
+
*/
|
|
615
|
+
export function setInstancePrivileged(instanceId, privileged) {
|
|
616
|
+
const metaPath = instanceMetaPath(instanceId);
|
|
617
|
+
const meta = safeReadJson(metaPath, "instance-meta");
|
|
618
|
+
if (!meta)
|
|
619
|
+
return false;
|
|
620
|
+
const runtime = (meta.runtime ?? {});
|
|
621
|
+
if (privileged)
|
|
622
|
+
runtime.privileged = true;
|
|
623
|
+
else
|
|
624
|
+
delete runtime.privileged;
|
|
625
|
+
meta.runtime = runtime;
|
|
626
|
+
safeWriteJson(metaPath, meta);
|
|
627
|
+
chownToServiceUser(metaPath);
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
export async function deleteInstance(instanceId, purgeBackups = false) {
|
|
631
|
+
const d = instanceDir(instanceId);
|
|
632
|
+
if (!existsSync(d))
|
|
633
|
+
return { ok: false, warnings: ["Instance directory not found"] };
|
|
634
|
+
const warnings = [];
|
|
635
|
+
// Cancel auto-backup timer and any queued jobs for this instance
|
|
636
|
+
import("../backup/backup-manager.js").then(({ cancelAutoBackup, getQueueStatus, cancelJob }) => {
|
|
637
|
+
cancelAutoBackup(instanceId);
|
|
638
|
+
// Cancel queued (not yet running) jobs for this instance
|
|
639
|
+
const q = getQueueStatus();
|
|
640
|
+
for (const job of q.queued) {
|
|
641
|
+
if (job.instanceId === instanceId)
|
|
642
|
+
cancelJob(job.id);
|
|
643
|
+
}
|
|
644
|
+
}).catch(() => { });
|
|
645
|
+
// Cache metadata BEFORE deletion so integrations can inspect it after rm.
|
|
646
|
+
const meta = getInstance(instanceId);
|
|
647
|
+
// Integration-owned pre-delete hook. Integrations use this to emit advisories
|
|
648
|
+
// for resources that live outside the instance dir (custom integration
|
|
649
|
+
// homes, named docker volumes, etc). Errors are collected
|
|
650
|
+
// into the response so one integration misbehaving can't block removal.
|
|
651
|
+
try {
|
|
652
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
653
|
+
if (entry && meta) {
|
|
654
|
+
const integration = entry.integration;
|
|
655
|
+
if (integration.hooks?.onDelete) {
|
|
656
|
+
const hookResult = await integration.hooks.onDelete({ instanceId, meta });
|
|
657
|
+
if (hookResult && Array.isArray(hookResult.warnings)) {
|
|
658
|
+
warnings.push(...hookResult.warnings);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
catch (e) {
|
|
664
|
+
warnings.push(`integration onDelete hook failed: ${e.message}`);
|
|
665
|
+
}
|
|
666
|
+
// Clean up Nomad Variables (async, best-effort)
|
|
667
|
+
import("../runtime/drivers/nomad.js").then((nm) => {
|
|
668
|
+
nm.purgeInstanceVariables(instanceId).catch((e) => {
|
|
669
|
+
console.warn(`[instance] Failed to purge Nomad variables for ${instanceId}:`, e.message);
|
|
670
|
+
});
|
|
671
|
+
}).catch((e) => {
|
|
672
|
+
console.warn(`[instance] Could not load Nomad driver for cleanup:`, e.message);
|
|
673
|
+
});
|
|
674
|
+
// Async rm so the Node event loop stays responsive during large deletes:
|
|
675
|
+
// a fresh instance with a just-installed runtime package can be 1+ GB
|
|
676
|
+
// with hundreds of nested dirs, which takes 30-60s to unlink on SD storage.
|
|
677
|
+
// rmSync would block every other HTTP request for that whole window.
|
|
678
|
+
let dirDeleted = false;
|
|
679
|
+
try {
|
|
680
|
+
await rmAsync(d, { recursive: true, force: true });
|
|
681
|
+
dirDeleted = true;
|
|
682
|
+
}
|
|
683
|
+
catch {
|
|
684
|
+
try {
|
|
685
|
+
execFileSync("sudo", ["rm", "-rf", d], { timeout: 300000 });
|
|
686
|
+
dirDeleted = true;
|
|
687
|
+
}
|
|
688
|
+
catch (e) {
|
|
689
|
+
warnings.push(`Failed to delete instance directory: ${e.message}`);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
// Integration-home orphan warnings are emitted by integration hooks.
|
|
693
|
+
// Handle backups (stored in separate directory, not affected by the
|
|
694
|
+
// instance rm above). Backups can be hundreds of MB each and accumulate
|
|
695
|
+
// across retention windows, so use the same async rm path to keep the
|
|
696
|
+
// event loop responsive.
|
|
697
|
+
const backupDir = join(BACKUPS_DIR, instanceId);
|
|
698
|
+
if (purgeBackups && existsSync(backupDir)) {
|
|
699
|
+
try {
|
|
700
|
+
await rmAsync(backupDir, { recursive: true, force: true });
|
|
701
|
+
}
|
|
702
|
+
catch (e) {
|
|
703
|
+
warnings.push(`Failed to delete backups: ${e.message}`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
else if (existsSync(backupDir)) {
|
|
707
|
+
warnings.push(`Backups preserved at ${backupDir}`);
|
|
708
|
+
}
|
|
709
|
+
return { ok: dirDeleted, warnings: warnings.length ? warnings : undefined };
|
|
710
|
+
}
|
|
711
|
+
// ── Native config dispatch wrappers ─────────────────────────────────
|
|
712
|
+
// Integrations own the implementation (`getNativeConfig` / `getStoredNativeConfig`
|
|
713
|
+
// / `saveNativeConfig`); these helpers preserve the synchronous public API
|
|
714
|
+
// shape for existing call sites (llm-proxy, routes, backup-manager).
|
|
715
|
+
function runtimeIntegrationKind(meta) {
|
|
716
|
+
if (!meta)
|
|
717
|
+
return null;
|
|
718
|
+
const instanceId = typeof meta.id === "string" && meta.id.trim()
|
|
719
|
+
? meta.id.trim()
|
|
720
|
+
: typeof meta.instanceId === "string" && meta.instanceId.trim()
|
|
721
|
+
? meta.instanceId.trim()
|
|
722
|
+
: "<unknown>";
|
|
723
|
+
const owner = resolveExecutionOwnerFromMetadata(instanceId, meta);
|
|
724
|
+
return owner.type === "integration" ? owner.integrationKind : null;
|
|
725
|
+
}
|
|
726
|
+
function getRuntimeIntegrationEntry(meta) {
|
|
727
|
+
const integrationKind = runtimeIntegrationKind(meta);
|
|
728
|
+
if (!integrationKind)
|
|
729
|
+
return null;
|
|
730
|
+
return { kind: integrationKind, integration: getIntegration(integrationKind) };
|
|
731
|
+
}
|
|
732
|
+
export function getConfig(instanceId) {
|
|
733
|
+
const meta = getInstance(instanceId);
|
|
734
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
735
|
+
if (!entry)
|
|
736
|
+
return null;
|
|
737
|
+
const integration = entry.integration;
|
|
738
|
+
return typeof integration.getNativeConfig === "function"
|
|
739
|
+
? integration.getNativeConfig(instanceId)
|
|
740
|
+
: null;
|
|
741
|
+
}
|
|
742
|
+
export function getStoredConfig(instanceId) {
|
|
743
|
+
const meta = getInstance(instanceId);
|
|
744
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
745
|
+
if (!entry)
|
|
746
|
+
return null;
|
|
747
|
+
const integration = entry.integration;
|
|
748
|
+
return typeof integration.getStoredNativeConfig === "function"
|
|
749
|
+
? integration.getStoredNativeConfig(instanceId)
|
|
750
|
+
: null;
|
|
751
|
+
}
|
|
752
|
+
export async function saveConfig(instanceId, config) {
|
|
753
|
+
const meta = getInstance(instanceId);
|
|
754
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
755
|
+
if (!entry)
|
|
756
|
+
return false;
|
|
757
|
+
try {
|
|
758
|
+
const integration = entry.integration;
|
|
759
|
+
if (typeof integration.saveNativeConfig !== "function")
|
|
760
|
+
return false;
|
|
761
|
+
// Integrations may return boolean or Promise<boolean>. Awaiting a plain
|
|
762
|
+
// boolean is a no-op, so this handles both. Previously we stripped the
|
|
763
|
+
// Promise and always reported success for async integrations — that masked
|
|
764
|
+
// failures and left callers unable to detect dirty state.
|
|
765
|
+
const result = await integration.saveNativeConfig(instanceId, config);
|
|
766
|
+
return typeof result === "boolean" ? result : true;
|
|
767
|
+
}
|
|
768
|
+
catch (e) {
|
|
769
|
+
console.warn(`[instance-manager] saveConfig dispatch failed for ${instanceId}: ${e.message}`);
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
// ── Integration-native helper dispatch wrappers ──────────────────────
|
|
774
|
+
// Each helper resolves the app integration for the instance and forwards
|
|
775
|
+
// to the corresponding integration method. Kept here so existing callers
|
|
776
|
+
// (routes, plugin-installer, app service re-exports, tests) stay
|
|
777
|
+
// integration-agnostic.
|
|
778
|
+
/** Dispatch wrapper for `AppIntegration.isChannelPluginInstalled`. */
|
|
779
|
+
export function isChannelPluginInstalled(instanceId, channelId) {
|
|
780
|
+
try {
|
|
781
|
+
const meta = getInstance(instanceId);
|
|
782
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
783
|
+
if (!entry)
|
|
784
|
+
return false;
|
|
785
|
+
const integration = entry.integration;
|
|
786
|
+
return typeof integration.isChannelPluginInstalled === "function"
|
|
787
|
+
? integration.isChannelPluginInstalled(instanceId, channelId)
|
|
788
|
+
: false;
|
|
789
|
+
}
|
|
790
|
+
catch (error) {
|
|
791
|
+
if (isExecutionOwnerRequiredError(error))
|
|
792
|
+
throw error;
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
export function saveFeishuCredentials(instanceId, creds) {
|
|
797
|
+
const meta = getInstance(instanceId);
|
|
798
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
799
|
+
if (!entry) {
|
|
800
|
+
throw new Error(`Instance '${instanceId}' is not backed by an app integration`);
|
|
801
|
+
}
|
|
802
|
+
const a = entry.integration;
|
|
803
|
+
if (typeof a.saveFeishuCredentials !== "function") {
|
|
804
|
+
throw new Error(`Integration "${entry.kind}" does not support Feishu credentials`);
|
|
805
|
+
}
|
|
806
|
+
a.saveFeishuCredentials(instanceId, creds);
|
|
807
|
+
}
|
|
808
|
+
export function saveWeixinCredentials(instanceId, creds) {
|
|
809
|
+
const meta = getInstance(instanceId);
|
|
810
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
811
|
+
if (!entry) {
|
|
812
|
+
throw new Error(`Instance '${instanceId}' is not backed by an app integration`);
|
|
813
|
+
}
|
|
814
|
+
const a = entry.integration;
|
|
815
|
+
if (typeof a.saveWeixinCredentials !== "function") {
|
|
816
|
+
throw new Error(`Integration "${entry.kind}" does not support WeChat credentials`);
|
|
817
|
+
}
|
|
818
|
+
a.saveWeixinCredentials(instanceId, creds);
|
|
819
|
+
}
|
|
820
|
+
export function getWeixinAccounts(instanceId) {
|
|
821
|
+
const meta = getInstance(instanceId);
|
|
822
|
+
try {
|
|
823
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
824
|
+
if (!entry)
|
|
825
|
+
return [];
|
|
826
|
+
const a = entry.integration;
|
|
827
|
+
return typeof a.getWeixinAccounts === "function"
|
|
828
|
+
? a.getWeixinAccounts(instanceId)
|
|
829
|
+
: [];
|
|
830
|
+
}
|
|
831
|
+
catch (error) {
|
|
832
|
+
if (isExecutionOwnerRequiredError(error))
|
|
833
|
+
throw error;
|
|
834
|
+
return [];
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
export function getInstanceRuntime(instanceId) {
|
|
838
|
+
const meta = getInstance(instanceId);
|
|
839
|
+
if (!meta)
|
|
840
|
+
return {};
|
|
841
|
+
return structuredClone(meta.runtime || {});
|
|
842
|
+
}
|
|
843
|
+
export function getRuntimeEnvFiles(instanceId) {
|
|
844
|
+
const runtime = getInstanceRuntime(instanceId);
|
|
845
|
+
const rawEnvFiles = Array.isArray(runtime.env_files)
|
|
846
|
+
? runtime.env_files
|
|
847
|
+
: Array.isArray(runtime.envFiles)
|
|
848
|
+
? runtime.envFiles
|
|
849
|
+
: [];
|
|
850
|
+
const envFiles = rawEnvFiles.map((p) => normalizePath(p)).filter(Boolean);
|
|
851
|
+
return envFiles.length ? envFiles : [defaultModelEnvFile(instanceId)];
|
|
852
|
+
}
|
|
853
|
+
export function getPrimaryHostPort(instanceId) {
|
|
854
|
+
return requireCanonicalPrimaryHostPort(instanceId, getInstanceRuntime(instanceId));
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Detect the host address where a published app port is actually listening.
|
|
858
|
+
*
|
|
859
|
+
* Strategy by driver:
|
|
860
|
+
* - raw_exec (Linux/Pi): use `ss` to read the listening address directly.
|
|
861
|
+
* - docker (macOS/bridge): Nomad publishes the port on the Nomad client's
|
|
862
|
+
* interface IP (e.g. 10.x.x.x), NOT 127.0.0.1. Query the Nomad allocation
|
|
863
|
+
* for `AllocatedResources.Shared.Ports[].HostIP`.
|
|
864
|
+
*
|
|
865
|
+
* Result is cached for 30 s to avoid an API call on every proxy request.
|
|
866
|
+
*/
|
|
867
|
+
const _gwHostCache = new Map();
|
|
868
|
+
const GW_HOST_CACHE_TTL = 30000;
|
|
869
|
+
export function getListeningHostForPort(port) {
|
|
870
|
+
// Linux: ss is universal and parses cleanly. macOS/BSD ships lsof but
|
|
871
|
+
// not ss, so without this fallback execFileSync throws ENOENT, the
|
|
872
|
+
// catch block silently returns 127.0.0.1, and any caller that fans
|
|
873
|
+
// out to the wrong host fails (the capability HTTP proxy in
|
|
874
|
+
// `proxyProvidedCapability`, the gateway-host fallback for raw_exec
|
|
875
|
+
// instances, etc.). On macOS docker driver mode the actual published
|
|
876
|
+
// host can be e.g. 10.188.0.21 via `host_network = "external"`, never
|
|
877
|
+
// loopback — so silently picking 127.0.0.1 leaves the panel fetching
|
|
878
|
+
// a host nothing is listening on.
|
|
879
|
+
const safe = safePort(port);
|
|
880
|
+
const fromSs = () => {
|
|
881
|
+
const hosts = [];
|
|
882
|
+
try {
|
|
883
|
+
const out = execFileSync("ss", ["-tlnH", "sport", "=", ":" + safe], {
|
|
884
|
+
encoding: "utf-8",
|
|
885
|
+
timeout: 3000,
|
|
886
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
887
|
+
});
|
|
888
|
+
for (const line of out.split("\n")) {
|
|
889
|
+
let match = line.match(/\s([\d.]+):(\d+)\s/);
|
|
890
|
+
if (!match)
|
|
891
|
+
match = line.match(/\s\[([0-9a-fA-F:]+)\]:(\d+)\s/);
|
|
892
|
+
if (match && match[2] === String(port))
|
|
893
|
+
hosts.push(match[1]);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
catch { /* ss not available or no match */ }
|
|
897
|
+
return hosts;
|
|
898
|
+
};
|
|
899
|
+
const fromLsof = () => {
|
|
900
|
+
const hosts = [];
|
|
901
|
+
try {
|
|
902
|
+
// `-FnP` keeps numeric output (no name resolution, no /etc/services).
|
|
903
|
+
// Lines beginning with `n` carry the bind address: e.g. `n10.188.0.21:8080`,
|
|
904
|
+
// `n127.0.0.1:8080`, `n[::1]:8080`, or `n*:8080` for wildcard binds.
|
|
905
|
+
const out = execFileSync("lsof", ["-nP", "-iTCP:" + safe, "-sTCP:LISTEN", "-FnP"], {
|
|
906
|
+
encoding: "utf-8",
|
|
907
|
+
timeout: 3000,
|
|
908
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
909
|
+
});
|
|
910
|
+
for (const line of out.split("\n")) {
|
|
911
|
+
if (!line.startsWith("n"))
|
|
912
|
+
continue;
|
|
913
|
+
const body = line.slice(1);
|
|
914
|
+
// IPv6 form: [::1]:8080 → strip brackets
|
|
915
|
+
const v6 = body.match(/^\[([0-9a-fA-F:]+)\]:(\d+)$/);
|
|
916
|
+
if (v6 && v6[2] === String(port)) {
|
|
917
|
+
hosts.push(v6[1]);
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
const idx = body.lastIndexOf(":");
|
|
921
|
+
if (idx <= 0)
|
|
922
|
+
continue;
|
|
923
|
+
const addr = body.slice(0, idx);
|
|
924
|
+
const portPart = body.slice(idx + 1);
|
|
925
|
+
if (portPart === String(port))
|
|
926
|
+
hosts.push(addr === "*" ? "0.0.0.0" : addr);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
catch { /* lsof unavailable or no match */ }
|
|
930
|
+
return hosts;
|
|
931
|
+
};
|
|
932
|
+
const detected = process.platform === "linux"
|
|
933
|
+
? [...fromSs(), ...fromLsof()]
|
|
934
|
+
: [...fromLsof(), ...fromSs()];
|
|
935
|
+
const unique = [...new Set(detected)];
|
|
936
|
+
if (unique.length === 0)
|
|
937
|
+
return "127.0.0.1";
|
|
938
|
+
return unique[0] === "0.0.0.0" ? "127.0.0.1" : unique[0];
|
|
939
|
+
}
|
|
940
|
+
function getExclusiveLoopbackListenerForPort(port) {
|
|
941
|
+
const safe = safePort(port);
|
|
942
|
+
const hosts = new Set();
|
|
943
|
+
try {
|
|
944
|
+
const out = execFileSync("lsof", ["-nP", "-iTCP:" + safe, "-sTCP:LISTEN", "-FnP"], {
|
|
945
|
+
encoding: "utf-8",
|
|
946
|
+
timeout: 3000,
|
|
947
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
948
|
+
});
|
|
949
|
+
for (const line of out.split("\n")) {
|
|
950
|
+
if (!line.startsWith("n"))
|
|
951
|
+
continue;
|
|
952
|
+
const body = line.slice(1);
|
|
953
|
+
if (body === `127.0.0.1:${safe}`) {
|
|
954
|
+
hosts.add("127.0.0.1");
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
if (body === `[::1]:${safe}`) {
|
|
958
|
+
hosts.add("::1");
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (!body.endsWith(`:${safe}`))
|
|
962
|
+
continue;
|
|
963
|
+
const addr = body.startsWith("[")
|
|
964
|
+
? body.slice(1, body.lastIndexOf("]"))
|
|
965
|
+
: body.slice(0, body.lastIndexOf(":"));
|
|
966
|
+
hosts.add(addr === "*" ? "0.0.0.0" : addr);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
catch { /* lsof unavailable or no match */ }
|
|
970
|
+
try {
|
|
971
|
+
const out = execFileSync("ss", ["-tlnH", "sport", "=", ":" + safe], {
|
|
972
|
+
encoding: "utf-8",
|
|
973
|
+
timeout: 3000,
|
|
974
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
975
|
+
});
|
|
976
|
+
for (const line of out.split("\n")) {
|
|
977
|
+
const ipv4 = line.match(/\s([\d.]+):(\d+)\s/);
|
|
978
|
+
if (ipv4 && ipv4[2] === String(safe))
|
|
979
|
+
hosts.add(ipv4[1]);
|
|
980
|
+
const ipv6 = line.match(/\s\[([0-9a-fA-F:]+)\]:(\d+)\s/);
|
|
981
|
+
if (ipv6 && ipv6[2] === String(safe))
|
|
982
|
+
hosts.add(ipv6[1]);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
catch { /* ss unavailable or no match */ }
|
|
986
|
+
if (hosts.size === 0)
|
|
987
|
+
return null;
|
|
988
|
+
let hasIpv4Loopback = false;
|
|
989
|
+
let hasIpv6Loopback = false;
|
|
990
|
+
for (const host of hosts) {
|
|
991
|
+
if (host === "127.0.0.1") {
|
|
992
|
+
hasIpv4Loopback = true;
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
if (host === "::1") {
|
|
996
|
+
hasIpv6Loopback = true;
|
|
997
|
+
continue;
|
|
998
|
+
}
|
|
999
|
+
if (host === "0.0.0.0" || host === "::")
|
|
1000
|
+
return null;
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
if (hasIpv4Loopback)
|
|
1004
|
+
return "127.0.0.1";
|
|
1005
|
+
if (hasIpv6Loopback)
|
|
1006
|
+
return "::1";
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
export function getPrimaryIpv4Address() {
|
|
1010
|
+
try {
|
|
1011
|
+
for (const list of Object.values(networkInterfaces())) {
|
|
1012
|
+
for (const iface of list ?? []) {
|
|
1013
|
+
if (!iface.internal && iface.family === "IPv4")
|
|
1014
|
+
return iface.address;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
catch { /* fall through */ }
|
|
1019
|
+
return "127.0.0.1";
|
|
1020
|
+
}
|
|
1021
|
+
export function getAdvertisedHostForPort(port) {
|
|
1022
|
+
const host = getListeningHostForPort(port);
|
|
1023
|
+
if (host && host !== "127.0.0.1" && host !== "0.0.0.0" && host !== "::1" && host !== "::") {
|
|
1024
|
+
return host;
|
|
1025
|
+
}
|
|
1026
|
+
return getPrimaryIpv4Address();
|
|
1027
|
+
}
|
|
1028
|
+
export function getConnectHostForPort(port) {
|
|
1029
|
+
const host = getListeningHostForPort(port);
|
|
1030
|
+
if (!host || host === "0.0.0.0" || host === "::")
|
|
1031
|
+
return "127.0.0.1";
|
|
1032
|
+
return host;
|
|
1033
|
+
}
|
|
1034
|
+
export async function getPrimaryHostForInstance(instanceId) {
|
|
1035
|
+
const cached = _gwHostCache.get(instanceId);
|
|
1036
|
+
if (cached && Date.now() - cached.ts < GW_HOST_CACHE_TTL)
|
|
1037
|
+
return cached.host;
|
|
1038
|
+
const port = getPrimaryHostPort(instanceId);
|
|
1039
|
+
let result = "127.0.0.1";
|
|
1040
|
+
try {
|
|
1041
|
+
const { getNomadDriver } = await import("../../config.js");
|
|
1042
|
+
if (getNomadDriver() === "docker") {
|
|
1043
|
+
const { getNomadAddr, getNomadToken } = await import("../../config.js");
|
|
1044
|
+
// Dispatch job-id construction through the integration so every runtime
|
|
1045
|
+
// owns its own Nomad job namespace (<kind>-<id>, bare app id, etc.).
|
|
1046
|
+
// Falls back to a generic `jishushell-` prefix only when the integration
|
|
1047
|
+
// lookup fails — that branch should never fire for a registered
|
|
1048
|
+
// agent type.
|
|
1049
|
+
const meta = getInstance(instanceId);
|
|
1050
|
+
let prefix = "jishushell-";
|
|
1051
|
+
try {
|
|
1052
|
+
const a = getRuntimeIntegrationEntry(meta)?.integration;
|
|
1053
|
+
if (a && typeof a.nomadJobPrefix === "string" && a.nomadJobPrefix.length) {
|
|
1054
|
+
prefix = a.nomadJobPrefix;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
catch (error) {
|
|
1058
|
+
if (isExecutionOwnerRequiredError(error))
|
|
1059
|
+
throw error;
|
|
1060
|
+
/* use fallback prefix for non-identity integration failures */
|
|
1061
|
+
}
|
|
1062
|
+
// Avoid double-prefix when the instance ID already carries the
|
|
1063
|
+
// integration prefix. Without this guard we'd double-prefix the id,
|
|
1064
|
+
// get 0 allocs, and fall back
|
|
1065
|
+
// to the 127.0.0.1 default — which silently breaks the gateway
|
|
1066
|
+
// proxy on docker driver where the real HostIP differs.
|
|
1067
|
+
const jid = instanceId.startsWith(prefix) ? instanceId : `${prefix}${instanceId}`;
|
|
1068
|
+
const headers = { "Content-Type": "application/json" };
|
|
1069
|
+
const token = getNomadToken();
|
|
1070
|
+
if (token)
|
|
1071
|
+
headers["X-Nomad-Token"] = token;
|
|
1072
|
+
const resp = await fetch(`${getNomadAddr()}/v1/job/${encodeURIComponent(jid)}/allocations`, {
|
|
1073
|
+
headers,
|
|
1074
|
+
signal: AbortSignal.timeout(5000),
|
|
1075
|
+
});
|
|
1076
|
+
if (resp.ok) {
|
|
1077
|
+
const allocs = await resp.json();
|
|
1078
|
+
const alloc = allocs.find((a) => a.ClientStatus === "running")
|
|
1079
|
+
?? allocs.find((a) => a.ClientStatus === "pending");
|
|
1080
|
+
if (alloc) {
|
|
1081
|
+
const detail = await fetch(`${getNomadAddr()}/v1/allocation/${encodeURIComponent(alloc.ID)}`, { headers, signal: AbortSignal.timeout(5000) });
|
|
1082
|
+
if (detail.ok) {
|
|
1083
|
+
const d = await detail.json();
|
|
1084
|
+
// Preferred source: AllocatedResources.Shared.Ports (bridge mode).
|
|
1085
|
+
const sharedPorts = d?.AllocatedResources?.Shared?.Ports ?? [];
|
|
1086
|
+
const gwPort = sharedPorts.find((p) => p.Label === "gateway");
|
|
1087
|
+
if (gwPort?.HostIP && gwPort.HostIP !== "0.0.0.0") {
|
|
1088
|
+
result = gwPort.HostIP;
|
|
1089
|
+
}
|
|
1090
|
+
else {
|
|
1091
|
+
// Host mode / task-level reservation: address lives under
|
|
1092
|
+
// AllocatedResources.Tasks.<task>.Networks[*].IP. On Nomad
|
|
1093
|
+
// 1.6.5 with `network_interface = "lo"`, the IP is whichever
|
|
1094
|
+
// address the OS enumerates first — which can be IPv6 `::1`
|
|
1095
|
+
// on systems where lo has both `127.0.0.1/8` and `::1/128`
|
|
1096
|
+
// (the default on most modern Linux distros). Reading it from
|
|
1097
|
+
// here is the authoritative source and matches what nomad
|
|
1098
|
+
// configures the docker-proxy bind to use.
|
|
1099
|
+
//
|
|
1100
|
+
// Scan every task instead of indexing a hardcoded "gateway"
|
|
1101
|
+
// task — integrations are free to name the task whatever they
|
|
1102
|
+
// like, we only require the reserved port carry the
|
|
1103
|
+
// framework-level `gateway` label.
|
|
1104
|
+
const tasksMap = d?.AllocatedResources?.Tasks ?? {};
|
|
1105
|
+
for (const taskName of Object.keys(tasksMap)) {
|
|
1106
|
+
const taskNets = tasksMap[taskName]?.Networks ?? [];
|
|
1107
|
+
const net = taskNets.find((n) => {
|
|
1108
|
+
const rps = n?.ReservedPorts ?? [];
|
|
1109
|
+
return rps.some((p) => p.Label === "gateway");
|
|
1110
|
+
});
|
|
1111
|
+
if (net?.IP && net.IP !== "0.0.0.0") {
|
|
1112
|
+
result = net.IP;
|
|
1113
|
+
break;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
// If Nomad API resolved a non-default host, cache and return it
|
|
1121
|
+
if (result !== "127.0.0.1") {
|
|
1122
|
+
const localLoopbackHost = getExclusiveLoopbackListenerForPort(port);
|
|
1123
|
+
if (localLoopbackHost) {
|
|
1124
|
+
result = localLoopbackHost;
|
|
1125
|
+
}
|
|
1126
|
+
_gwHostCache.set(instanceId, { host: result, ts: Date.now() });
|
|
1127
|
+
return result;
|
|
1128
|
+
}
|
|
1129
|
+
// Otherwise fall through to ss-based detection
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
catch { /* fall through */ }
|
|
1133
|
+
result = getListeningHostForPort(port);
|
|
1134
|
+
_gwHostCache.set(instanceId, { host: result, ts: Date.now() });
|
|
1135
|
+
return result;
|
|
1136
|
+
}
|
|
1137
|
+
const _appPortHostCache = new Map();
|
|
1138
|
+
const APP_PORT_HOST_CACHE_TTL = 30000;
|
|
1139
|
+
/**
|
|
1140
|
+
* Resolve the host IP for a specific port belonging to an app's Nomad job.
|
|
1141
|
+
*
|
|
1142
|
+
* On macOS with Colima + docker driver the container port is bound *inside*
|
|
1143
|
+
* the VM, not on the host. `ss` (or `netstat`) run on the macOS host see
|
|
1144
|
+
* nothing on that port, so `getListeningHostForPort` returns 127.0.0.1 and
|
|
1145
|
+
* the core proxy gets a 502.
|
|
1146
|
+
*
|
|
1147
|
+
* This function mirrors the logic of `getPrimaryHostForInstance` but matches by port
|
|
1148
|
+
* *value* rather than by the "gateway" label, making it suitable for
|
|
1149
|
+
* arbitrary capability ports exposed by app tasks.
|
|
1150
|
+
*/
|
|
1151
|
+
export async function getHostForAppPort(instanceId, port) {
|
|
1152
|
+
const cacheKey = `${instanceId}:${port}`;
|
|
1153
|
+
const cached = _appPortHostCache.get(cacheKey);
|
|
1154
|
+
if (cached && Date.now() - cached.ts < APP_PORT_HOST_CACHE_TTL)
|
|
1155
|
+
return cached.host;
|
|
1156
|
+
let result = "127.0.0.1";
|
|
1157
|
+
try {
|
|
1158
|
+
const { getNomadDriver, getNomadAddr, getNomadToken } = await import("../../config.js");
|
|
1159
|
+
if (getNomadDriver() === "docker") {
|
|
1160
|
+
const headers = { "Content-Type": "application/json" };
|
|
1161
|
+
const token = getNomadToken();
|
|
1162
|
+
if (token)
|
|
1163
|
+
headers["X-Nomad-Token"] = token;
|
|
1164
|
+
const resp = await fetch(`${getNomadAddr()}/v1/job/${encodeURIComponent(instanceId)}/allocations`, { headers, signal: AbortSignal.timeout(5000) });
|
|
1165
|
+
if (resp.ok) {
|
|
1166
|
+
const allocs = await resp.json();
|
|
1167
|
+
const alloc = allocs.find((a) => a.ClientStatus === "running")
|
|
1168
|
+
?? allocs.find((a) => a.ClientStatus === "pending");
|
|
1169
|
+
if (alloc) {
|
|
1170
|
+
const detail = await fetch(`${getNomadAddr()}/v1/allocation/${encodeURIComponent(alloc.ID)}`, { headers, signal: AbortSignal.timeout(5000) });
|
|
1171
|
+
if (detail.ok) {
|
|
1172
|
+
const d = await detail.json();
|
|
1173
|
+
// Bridge / host-network mode: ports listed under Shared.Ports
|
|
1174
|
+
const sharedPorts = d?.AllocatedResources?.Shared?.Ports ?? [];
|
|
1175
|
+
const matched = sharedPorts.find((p) => p.Value === port || p.To === port);
|
|
1176
|
+
if (matched?.HostIP && matched.HostIP !== "0.0.0.0") {
|
|
1177
|
+
result = matched.HostIP;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
catch { /* fall through to ss-based detection */ }
|
|
1185
|
+
if (result === "127.0.0.1") {
|
|
1186
|
+
result = getListeningHostForPort(port);
|
|
1187
|
+
}
|
|
1188
|
+
_appPortHostCache.set(cacheKey, { host: result, ts: Date.now() });
|
|
1189
|
+
return result;
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Wrap an IPv6 literal in brackets for safe URL host-component / Host-header
|
|
1193
|
+
* use. Bare names ("gateway.local") and IPv4 ("127.0.0.1") contain no colon
|
|
1194
|
+
* and pass through unchanged; anything with a colon is an IPv6 literal and
|
|
1195
|
+
* MUST be bracketed before being concatenated with a port, otherwise
|
|
1196
|
+
* `http://::1:18095/` is unparseable.
|
|
1197
|
+
*/
|
|
1198
|
+
export function urlHost(host) {
|
|
1199
|
+
return host.includes(":") ? `[${host}]` : host;
|
|
1200
|
+
}
|
|
1201
|
+
export function findInstancesSharingIntegrationHome(instanceId) {
|
|
1202
|
+
const meta = getInstance(instanceId);
|
|
1203
|
+
try {
|
|
1204
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
1205
|
+
if (!entry)
|
|
1206
|
+
return [];
|
|
1207
|
+
const a = entry.integration;
|
|
1208
|
+
return typeof a.findInstancesSharingHome === "function"
|
|
1209
|
+
? a.findInstancesSharingHome(instanceId)
|
|
1210
|
+
: [];
|
|
1211
|
+
}
|
|
1212
|
+
catch (error) {
|
|
1213
|
+
if (isExecutionOwnerRequiredError(error))
|
|
1214
|
+
throw error;
|
|
1215
|
+
return [];
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Re-pick the primary host port for an existing instance and rewrite only the
|
|
1220
|
+
* persisted host-side mapping in `runtime.ports[].hostPort`.
|
|
1221
|
+
*
|
|
1222
|
+
* Used when {@link isPortInUse} reports that the previously-assigned
|
|
1223
|
+
* `hostPort` has been taken by something else between create-time and
|
|
1224
|
+
* start-time (e.g. an unrelated service that grabbed the port at boot, or a
|
|
1225
|
+
* Docker race on the next allocation). The Nomad job spec is rebuilt from
|
|
1226
|
+
* instance metadata on every submit, so updating `instance.json` here is
|
|
1227
|
+
* sufficient — no other files need patching, and the in-container process
|
|
1228
|
+
* listener keeps the same `containerPort`.
|
|
1229
|
+
*
|
|
1230
|
+
* Lifecycle: this is the canonical Step 2 reserve / commit / release flow:
|
|
1231
|
+
* - `allocateHostPort(...)` reserves a candidate hostPort.
|
|
1232
|
+
* - On successful durable persist (`safeWriteJson` of `instance.json`),
|
|
1233
|
+
* `alloc.commit()` retires the reservation; durable ownership has taken
|
|
1234
|
+
* over via `runtime.ports[].hostPort`.
|
|
1235
|
+
* - On any thrown failure, `alloc.release()` frees the slot so concurrent
|
|
1236
|
+
* / retried reallocations can reuse the port.
|
|
1237
|
+
*
|
|
1238
|
+
* Domain note: this function intentionally only rewrites `hostPort`.
|
|
1239
|
+
* Integration-specific `reallocateRuntimePort` implementations and the
|
|
1240
|
+
* generic AppSpec fallback must both preserve the workload's
|
|
1241
|
+
* `containerPort`.
|
|
1242
|
+
*
|
|
1243
|
+
* Scope note: this is a primary-port helper for single-gateway integration
|
|
1244
|
+
* runtimes and legacy compatibility paths. Generic multi-port AppSpec
|
|
1245
|
+
* preflight must not use it as a full conflict check; it should iterate every
|
|
1246
|
+
* external `runtime.ports[]` entry and call `reallocateRuntimeHostPort(...)`
|
|
1247
|
+
* for the specific conflicting task/port.
|
|
1248
|
+
*/
|
|
1249
|
+
export async function reallocatePrimaryHostPort(instanceId) {
|
|
1250
|
+
const meta = getInstance(instanceId);
|
|
1251
|
+
if (!meta)
|
|
1252
|
+
throw new Error(`Cannot reallocate port for unknown instance '${instanceId}'`);
|
|
1253
|
+
const entry = getRuntimeIntegrationEntry(meta);
|
|
1254
|
+
const fromPort = requireCanonicalPrimaryHostPort(instanceId, meta.runtime);
|
|
1255
|
+
const alloc = await allocateHostPort(instanceId, entry?.integration.preferredHostPort ?? fromPort, fromPort);
|
|
1256
|
+
let committed = false;
|
|
1257
|
+
try {
|
|
1258
|
+
const runtime = (meta.runtime ?? {});
|
|
1259
|
+
// Delegate kind-specific rewrites to integrations when present. Generic
|
|
1260
|
+
// AppSpec instances rewrite only the first externally visible
|
|
1261
|
+
// `runtime.ports[].hostPort`; never rewrite containerPort.
|
|
1262
|
+
if (typeof entry?.integration.reallocateRuntimePort === "function") {
|
|
1263
|
+
entry.integration.reallocateRuntimePort(runtime, alloc.port);
|
|
1264
|
+
}
|
|
1265
|
+
else if (Array.isArray(runtime.ports) && runtime.ports.length > 0) {
|
|
1266
|
+
let rewritten = false;
|
|
1267
|
+
runtime.ports = runtime.ports.map((port, index) => {
|
|
1268
|
+
if (!rewritten && ((port?.visibility ?? "external") !== "internal" || index === 0)) {
|
|
1269
|
+
rewritten = true;
|
|
1270
|
+
return { ...port, hostPort: alloc.port };
|
|
1271
|
+
}
|
|
1272
|
+
return port;
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
else {
|
|
1276
|
+
throw new CanonicalRuntimePortRequiredError(instanceId);
|
|
1277
|
+
}
|
|
1278
|
+
updateInstanceMeta(instanceId, { runtime });
|
|
1279
|
+
// `instance.json` now durably owns the new hostPort; flip the
|
|
1280
|
+
// reservation from `reserve` to `commit` BEFORE follow-up I/O so any
|
|
1281
|
+
// later failure does not leak the reservation slot.
|
|
1282
|
+
alloc.commit();
|
|
1283
|
+
committed = true;
|
|
1284
|
+
console.log(`[instance] ${instanceId}: primary port reallocated ${fromPort} -> ${alloc.port}`);
|
|
1285
|
+
return { from: fromPort, to: alloc.port, skipped: alloc.skipped };
|
|
1286
|
+
}
|
|
1287
|
+
catch (error) {
|
|
1288
|
+
if (!committed)
|
|
1289
|
+
alloc.release();
|
|
1290
|
+
throw error;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
export async function reallocateRuntimeHostPort(instanceId, portRef) {
|
|
1294
|
+
const meta = getInstance(instanceId);
|
|
1295
|
+
if (!meta)
|
|
1296
|
+
throw new Error(`Cannot reallocate port for unknown instance '${instanceId}'`);
|
|
1297
|
+
const runtime = structuredClone((meta.runtime ?? {}));
|
|
1298
|
+
const ports = Array.isArray(runtime.ports) ? runtime.ports : [];
|
|
1299
|
+
const index = ports.findIndex((port) => port?.name === portRef.name
|
|
1300
|
+
&& (portRef.taskName == null
|
|
1301
|
+
|| port?.taskName === portRef.taskName));
|
|
1302
|
+
if (index < 0) {
|
|
1303
|
+
throw new CanonicalRuntimePortRequiredError(instanceId);
|
|
1304
|
+
}
|
|
1305
|
+
const fromPort = ports[index]?.hostPort;
|
|
1306
|
+
if (!Number.isInteger(fromPort) || fromPort <= 0) {
|
|
1307
|
+
throw new CanonicalRuntimePortRequiredError(instanceId);
|
|
1308
|
+
}
|
|
1309
|
+
const alloc = await allocateHostPort(instanceId, fromPort + 1, fromPort);
|
|
1310
|
+
let committed = false;
|
|
1311
|
+
try {
|
|
1312
|
+
runtime.ports = ports.map((port, portIndex) => portIndex === index ? { ...port, hostPort: alloc.port } : port);
|
|
1313
|
+
updateInstanceMeta(instanceId, { runtime });
|
|
1314
|
+
alloc.commit();
|
|
1315
|
+
committed = true;
|
|
1316
|
+
console.log(`[instance] ${instanceId}: runtime port ${portRef.taskName ? `${portRef.taskName}/` : ""}${portRef.name} ` +
|
|
1317
|
+
`reallocated ${fromPort} -> ${alloc.port}`);
|
|
1318
|
+
return { from: fromPort, to: alloc.port, skipped: alloc.skipped };
|
|
1319
|
+
}
|
|
1320
|
+
catch (error) {
|
|
1321
|
+
if (!committed)
|
|
1322
|
+
alloc.release();
|
|
1323
|
+
throw error;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
export function findInstancesSharingPrimaryHostPort(instanceId) {
|
|
1327
|
+
const targetPort = getPrimaryHostPort(instanceId);
|
|
1328
|
+
return listInstances()
|
|
1329
|
+
.filter((inst) => inst.id !== instanceId)
|
|
1330
|
+
.filter((inst) => extractPrimaryHostPort(inst.runtime) === targetPort)
|
|
1331
|
+
.map((inst) => inst.id);
|
|
1332
|
+
}
|
|
1333
|
+
export function getRuntimeEnv(instanceId) {
|
|
1334
|
+
const runtime = getInstanceRuntime(instanceId);
|
|
1335
|
+
const env = {};
|
|
1336
|
+
for (const envFile of getRuntimeEnvFiles(instanceId)) {
|
|
1337
|
+
Object.assign(env, parseEnvFile(envFile));
|
|
1338
|
+
}
|
|
1339
|
+
for (const [key, value] of Object.entries(runtime.env || {})) {
|
|
1340
|
+
if (value != null)
|
|
1341
|
+
env[key] = String(value);
|
|
1342
|
+
}
|
|
1343
|
+
return env;
|
|
1344
|
+
}
|
|
1345
|
+
// Re-export instanceDir for the Nomad driver under its getInstanceDir alias.
|
|
1346
|
+
export { instanceDir as getInstanceDir };
|
|
1347
|
+
// Integration config-path resolvers are owned by their integration modules.
|
|
1348
|
+
//# sourceMappingURL=manager.js.map
|