@portel/photon 1.4.1 → 1.6.0
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/README.md +326 -1177
- package/dist/auto-ui/beam.d.ts +14 -0
- package/dist/auto-ui/beam.d.ts.map +1 -0
- package/dist/auto-ui/beam.js +3057 -0
- package/dist/auto-ui/beam.js.map +1 -0
- package/dist/auto-ui/bridge/index.d.ts +37 -0
- package/dist/auto-ui/bridge/index.d.ts.map +1 -0
- package/dist/auto-ui/bridge/index.js +555 -0
- package/dist/auto-ui/bridge/index.js.map +1 -0
- package/dist/auto-ui/bridge/openai-shim.d.ts +20 -0
- package/dist/auto-ui/bridge/openai-shim.d.ts.map +1 -0
- package/dist/auto-ui/bridge/openai-shim.js +231 -0
- package/dist/auto-ui/bridge/openai-shim.js.map +1 -0
- package/dist/auto-ui/bridge/photon-app.d.ts +162 -0
- package/dist/auto-ui/bridge/photon-app.d.ts.map +1 -0
- package/dist/auto-ui/bridge/photon-app.js +460 -0
- package/dist/auto-ui/bridge/photon-app.js.map +1 -0
- package/dist/auto-ui/bridge/types.d.ts +128 -0
- package/dist/auto-ui/bridge/types.d.ts.map +1 -0
- package/dist/auto-ui/bridge/types.js +7 -0
- package/dist/auto-ui/bridge/types.js.map +1 -0
- package/dist/auto-ui/components/card.d.ts +13 -0
- package/dist/auto-ui/components/card.d.ts.map +1 -0
- package/dist/auto-ui/components/card.js +64 -0
- package/dist/auto-ui/components/card.js.map +1 -0
- package/dist/auto-ui/components/form.d.ts +15 -0
- package/dist/auto-ui/components/form.d.ts.map +1 -0
- package/dist/auto-ui/components/form.js +72 -0
- package/dist/auto-ui/components/form.js.map +1 -0
- package/dist/auto-ui/components/list.d.ts +13 -0
- package/dist/auto-ui/components/list.d.ts.map +1 -0
- package/dist/auto-ui/components/list.js +58 -0
- package/dist/auto-ui/components/list.js.map +1 -0
- package/dist/auto-ui/components/progress.d.ts +18 -0
- package/dist/auto-ui/components/progress.d.ts.map +1 -0
- package/dist/auto-ui/components/progress.js +125 -0
- package/dist/auto-ui/components/progress.js.map +1 -0
- package/dist/auto-ui/components/table.d.ts +13 -0
- package/dist/auto-ui/components/table.d.ts.map +1 -0
- package/dist/auto-ui/components/table.js +82 -0
- package/dist/auto-ui/components/table.js.map +1 -0
- package/dist/auto-ui/components/tree.d.ts +13 -0
- package/dist/auto-ui/components/tree.d.ts.map +1 -0
- package/dist/auto-ui/components/tree.js +61 -0
- package/dist/auto-ui/components/tree.js.map +1 -0
- package/dist/auto-ui/daemon-tools.d.ts +45 -0
- package/dist/auto-ui/daemon-tools.d.ts.map +1 -0
- package/dist/auto-ui/daemon-tools.js +580 -0
- package/dist/auto-ui/daemon-tools.js.map +1 -0
- package/dist/auto-ui/design-system/index.d.ts +21 -0
- package/dist/auto-ui/design-system/index.d.ts.map +1 -0
- package/dist/auto-ui/design-system/index.js +27 -0
- package/dist/auto-ui/design-system/index.js.map +1 -0
- package/dist/auto-ui/design-system/tokens.d.ts +9 -0
- package/dist/auto-ui/design-system/tokens.d.ts.map +1 -0
- package/dist/auto-ui/design-system/tokens.js +27 -0
- package/dist/auto-ui/design-system/tokens.js.map +1 -0
- package/dist/auto-ui/design-system/transaction-ui.d.ts +70 -0
- package/dist/auto-ui/design-system/transaction-ui.d.ts.map +1 -0
- package/dist/auto-ui/design-system/transaction-ui.js +982 -0
- package/dist/auto-ui/design-system/transaction-ui.js.map +1 -0
- package/dist/auto-ui/frontend/index.html +84 -0
- package/dist/auto-ui/index.d.ts +23 -0
- package/dist/auto-ui/index.d.ts.map +1 -0
- package/dist/auto-ui/index.js +28 -0
- package/dist/auto-ui/index.js.map +1 -0
- package/dist/auto-ui/openapi-generator.d.ts +71 -0
- package/dist/auto-ui/openapi-generator.d.ts.map +1 -0
- package/dist/auto-ui/openapi-generator.js +223 -0
- package/dist/auto-ui/openapi-generator.js.map +1 -0
- package/dist/auto-ui/photon-bridge.d.ts +159 -0
- package/dist/auto-ui/photon-bridge.d.ts.map +1 -0
- package/dist/auto-ui/photon-bridge.js +262 -0
- package/dist/auto-ui/photon-bridge.js.map +1 -0
- package/dist/auto-ui/photon-host.d.ts +113 -0
- package/dist/auto-ui/photon-host.d.ts.map +1 -0
- package/dist/auto-ui/photon-host.js +284 -0
- package/dist/auto-ui/photon-host.js.map +1 -0
- package/dist/auto-ui/platform-compat.d.ts +71 -0
- package/dist/auto-ui/platform-compat.d.ts.map +1 -0
- package/dist/auto-ui/platform-compat.js +628 -0
- package/dist/auto-ui/platform-compat.js.map +1 -0
- package/dist/auto-ui/playground-html.d.ts +15 -0
- package/dist/auto-ui/playground-html.d.ts.map +1 -0
- package/dist/auto-ui/playground-html.js +1113 -0
- package/dist/auto-ui/playground-html.js.map +1 -0
- package/dist/auto-ui/playground-server.d.ts +7 -0
- package/dist/auto-ui/playground-server.d.ts.map +1 -0
- package/dist/auto-ui/playground-server.js +840 -0
- package/dist/auto-ui/playground-server.js.map +1 -0
- package/dist/auto-ui/registry.d.ts +13 -0
- package/dist/auto-ui/registry.d.ts.map +1 -0
- package/dist/auto-ui/registry.js +62 -0
- package/dist/auto-ui/registry.js.map +1 -0
- package/dist/auto-ui/renderer.d.ts +14 -0
- package/dist/auto-ui/renderer.d.ts.map +1 -0
- package/dist/auto-ui/renderer.js +88 -0
- package/dist/auto-ui/renderer.js.map +1 -0
- package/dist/auto-ui/rendering/components.d.ts +29 -0
- package/dist/auto-ui/rendering/components.d.ts.map +1 -0
- package/dist/auto-ui/rendering/components.js +773 -0
- package/dist/auto-ui/rendering/components.js.map +1 -0
- package/dist/auto-ui/rendering/field-analyzer.d.ts +48 -0
- package/dist/auto-ui/rendering/field-analyzer.d.ts.map +1 -0
- package/dist/auto-ui/rendering/field-analyzer.js +270 -0
- package/dist/auto-ui/rendering/field-analyzer.js.map +1 -0
- package/dist/auto-ui/rendering/field-renderers.d.ts +64 -0
- package/dist/auto-ui/rendering/field-renderers.d.ts.map +1 -0
- package/dist/auto-ui/rendering/field-renderers.js +317 -0
- package/dist/auto-ui/rendering/field-renderers.js.map +1 -0
- package/dist/auto-ui/rendering/index.d.ts +28 -0
- package/dist/auto-ui/rendering/index.d.ts.map +1 -0
- package/dist/auto-ui/rendering/index.js +60 -0
- package/dist/auto-ui/rendering/index.js.map +1 -0
- package/dist/auto-ui/rendering/layout-selector.d.ts +48 -0
- package/dist/auto-ui/rendering/layout-selector.d.ts.map +1 -0
- package/dist/auto-ui/rendering/layout-selector.js +352 -0
- package/dist/auto-ui/rendering/layout-selector.js.map +1 -0
- package/dist/auto-ui/rendering/template-engine.d.ts +41 -0
- package/dist/auto-ui/rendering/template-engine.d.ts.map +1 -0
- package/dist/auto-ui/rendering/template-engine.js +238 -0
- package/dist/auto-ui/rendering/template-engine.js.map +1 -0
- package/dist/auto-ui/streamable-http-transport.d.ts +103 -0
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -0
- package/dist/auto-ui/streamable-http-transport.js +1875 -0
- package/dist/auto-ui/streamable-http-transport.js.map +1 -0
- package/dist/auto-ui/types.d.ts +384 -0
- package/dist/auto-ui/types.d.ts.map +1 -0
- package/dist/auto-ui/types.js +92 -0
- package/dist/auto-ui/types.js.map +1 -0
- package/dist/beam.bundle.js +63137 -0
- package/dist/beam.bundle.js.map +7 -0
- package/dist/claude-code-plugin.d.ts.map +1 -1
- package/dist/claude-code-plugin.js +30 -30
- package/dist/claude-code-plugin.js.map +1 -1
- package/dist/cli/commands/info.d.ts +11 -0
- package/dist/cli/commands/info.d.ts.map +1 -0
- package/dist/cli/commands/info.js +313 -0
- package/dist/cli/commands/info.js.map +1 -0
- package/dist/cli/commands/marketplace.d.ts +11 -0
- package/dist/cli/commands/marketplace.d.ts.map +1 -0
- package/dist/cli/commands/marketplace.js +198 -0
- package/dist/cli/commands/marketplace.js.map +1 -0
- package/dist/cli/commands/package-app.d.ts +9 -0
- package/dist/cli/commands/package-app.d.ts.map +1 -0
- package/dist/cli/commands/package-app.js +191 -0
- package/dist/cli/commands/package-app.js.map +1 -0
- package/dist/cli/commands/package.d.ts +11 -0
- package/dist/cli/commands/package.d.ts.map +1 -0
- package/dist/cli/commands/package.js +573 -0
- package/dist/cli/commands/package.js.map +1 -0
- package/dist/cli-alias.d.ts.map +1 -1
- package/dist/cli-alias.js +30 -28
- package/dist/cli-alias.js.map +1 -1
- package/dist/cli-formatter.d.ts +8 -24
- package/dist/cli-formatter.d.ts.map +1 -1
- package/dist/cli-formatter.js +8 -325
- package/dist/cli-formatter.js.map +1 -1
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1166 -1131
- package/dist/cli.js.map +1 -1
- package/dist/daemon/client.d.ts +84 -3
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +561 -11
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.d.ts +51 -12
- package/dist/daemon/manager.d.ts.map +1 -1
- package/dist/daemon/manager.js +122 -61
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/protocol.d.ts +62 -6
- package/dist/daemon/protocol.d.ts.map +1 -1
- package/dist/daemon/protocol.js +76 -1
- package/dist/daemon/protocol.js.map +1 -1
- package/dist/daemon/server.d.ts +6 -6
- package/dist/daemon/server.js +743 -133
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/session-manager.d.ts +8 -1
- package/dist/daemon/session-manager.d.ts.map +1 -1
- package/dist/daemon/session-manager.js +32 -9
- package/dist/daemon/session-manager.js.map +1 -1
- package/dist/deploy/cloudflare.d.ts +12 -0
- package/dist/deploy/cloudflare.d.ts.map +1 -0
- package/dist/deploy/cloudflare.js +216 -0
- package/dist/deploy/cloudflare.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +191 -21
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +1186 -319
- package/dist/loader.js.map +1 -1
- package/dist/markdown-utils.d.ts +8 -0
- package/dist/markdown-utils.d.ts.map +1 -0
- package/dist/markdown-utils.js +63 -0
- package/dist/markdown-utils.js.map +1 -0
- package/dist/marketplace-manager.d.ts +10 -0
- package/dist/marketplace-manager.d.ts.map +1 -1
- package/dist/marketplace-manager.js +112 -28
- package/dist/marketplace-manager.js.map +1 -1
- package/dist/mcp-client.d.ts +9 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +11 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/mcp-elicitation.d.ts +32 -0
- package/dist/mcp-elicitation.d.ts.map +1 -0
- package/dist/mcp-elicitation.js +26 -0
- package/dist/mcp-elicitation.js.map +1 -0
- package/dist/path-resolver.d.ts +9 -12
- package/dist/path-resolver.d.ts.map +1 -1
- package/dist/path-resolver.js +13 -43
- package/dist/path-resolver.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +204 -77
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/photon-doc-extractor.d.ts +89 -0
- package/dist/photon-doc-extractor.d.ts.map +1 -1
- package/dist/photon-doc-extractor.js +560 -32
- package/dist/photon-doc-extractor.js.map +1 -1
- package/dist/photons/maker.photon.d.ts +182 -0
- package/dist/photons/maker.photon.d.ts.map +1 -0
- package/dist/photons/maker.photon.js +504 -0
- package/dist/photons/maker.photon.js.map +1 -0
- package/dist/photons/maker.photon.ts +626 -0
- package/dist/photons/marketplace.photon.d.ts +110 -0
- package/dist/photons/marketplace.photon.d.ts.map +1 -0
- package/dist/photons/marketplace.photon.js +260 -0
- package/dist/photons/marketplace.photon.js.map +1 -0
- package/dist/photons/marketplace.photon.ts +378 -0
- package/dist/photons/tunnel.photon.d.ts +80 -0
- package/dist/photons/tunnel.photon.d.ts.map +1 -0
- package/dist/photons/tunnel.photon.js +269 -0
- package/dist/photons/tunnel.photon.js.map +1 -0
- package/dist/photons/tunnel.photon.ts +345 -0
- package/dist/security-scanner.d.ts.map +1 -1
- package/dist/security-scanner.js +18 -15
- package/dist/security-scanner.js.map +1 -1
- package/dist/serv/auth/jwt.d.ts +89 -0
- package/dist/serv/auth/jwt.d.ts.map +1 -0
- package/dist/serv/auth/jwt.js +239 -0
- package/dist/serv/auth/jwt.js.map +1 -0
- package/dist/serv/auth/oauth.d.ts +117 -0
- package/dist/serv/auth/oauth.d.ts.map +1 -0
- package/dist/serv/auth/oauth.js +395 -0
- package/dist/serv/auth/oauth.js.map +1 -0
- package/dist/serv/auth/well-known.d.ts +60 -0
- package/dist/serv/auth/well-known.d.ts.map +1 -0
- package/dist/serv/auth/well-known.js +154 -0
- package/dist/serv/auth/well-known.js.map +1 -0
- package/dist/serv/db/d1-client.d.ts +65 -0
- package/dist/serv/db/d1-client.d.ts.map +1 -0
- package/dist/serv/db/d1-client.js +137 -0
- package/dist/serv/db/d1-client.js.map +1 -0
- package/dist/serv/db/d1-stores.d.ts +62 -0
- package/dist/serv/db/d1-stores.d.ts.map +1 -0
- package/dist/serv/db/d1-stores.js +307 -0
- package/dist/serv/db/d1-stores.js.map +1 -0
- package/dist/serv/index.d.ts +114 -0
- package/dist/serv/index.d.ts.map +1 -0
- package/dist/serv/index.js +172 -0
- package/dist/serv/index.js.map +1 -0
- package/dist/serv/local.d.ts +118 -0
- package/dist/serv/local.d.ts.map +1 -0
- package/dist/serv/local.js +392 -0
- package/dist/serv/local.js.map +1 -0
- package/dist/serv/middleware/auth.d.ts +66 -0
- package/dist/serv/middleware/auth.d.ts.map +1 -0
- package/dist/serv/middleware/auth.js +178 -0
- package/dist/serv/middleware/auth.js.map +1 -0
- package/dist/serv/middleware/tenant.d.ts +94 -0
- package/dist/serv/middleware/tenant.d.ts.map +1 -0
- package/dist/serv/middleware/tenant.js +152 -0
- package/dist/serv/middleware/tenant.js.map +1 -0
- package/dist/serv/runtime/executor.d.ts +76 -0
- package/dist/serv/runtime/executor.d.ts.map +1 -0
- package/dist/serv/runtime/executor.js +105 -0
- package/dist/serv/runtime/executor.js.map +1 -0
- package/dist/serv/runtime/index.d.ts +8 -0
- package/dist/serv/runtime/index.d.ts.map +1 -0
- package/dist/serv/runtime/index.js +10 -0
- package/dist/serv/runtime/index.js.map +1 -0
- package/dist/serv/runtime/oauth-context.d.ts +121 -0
- package/dist/serv/runtime/oauth-context.d.ts.map +1 -0
- package/dist/serv/runtime/oauth-context.js +153 -0
- package/dist/serv/runtime/oauth-context.js.map +1 -0
- package/dist/serv/session/kv-store.d.ts +54 -0
- package/dist/serv/session/kv-store.d.ts.map +1 -0
- package/dist/serv/session/kv-store.js +149 -0
- package/dist/serv/session/kv-store.js.map +1 -0
- package/dist/serv/session/store.d.ts +113 -0
- package/dist/serv/session/store.d.ts.map +1 -0
- package/dist/serv/session/store.js +284 -0
- package/dist/serv/session/store.js.map +1 -0
- package/dist/serv/types/index.d.ts +147 -0
- package/dist/serv/types/index.d.ts.map +1 -0
- package/dist/serv/types/index.js +8 -0
- package/dist/serv/types/index.js.map +1 -0
- package/dist/serv/vault/token-vault.d.ts +102 -0
- package/dist/serv/vault/token-vault.d.ts.map +1 -0
- package/dist/serv/vault/token-vault.js +177 -0
- package/dist/serv/vault/token-vault.js.map +1 -0
- package/dist/server.d.ts +184 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1995 -86
- package/dist/server.js.map +1 -1
- package/dist/shared/cli-sections.d.ts +6 -0
- package/dist/shared/cli-sections.d.ts.map +1 -0
- package/dist/shared/cli-sections.js +16 -0
- package/dist/shared/cli-sections.js.map +1 -0
- package/dist/shared/cli-utils.d.ts +81 -0
- package/dist/shared/cli-utils.d.ts.map +1 -0
- package/dist/shared/cli-utils.js +174 -0
- package/dist/shared/cli-utils.js.map +1 -0
- package/dist/shared/config-docs.d.ts +6 -0
- package/dist/shared/config-docs.d.ts.map +1 -0
- package/dist/shared/config-docs.js +6 -0
- package/dist/shared/config-docs.js.map +1 -0
- package/dist/shared/error-handler.d.ts +128 -0
- package/dist/shared/error-handler.d.ts.map +1 -0
- package/dist/shared/error-handler.js +342 -0
- package/dist/shared/error-handler.js.map +1 -0
- package/dist/shared/logger.d.ts +42 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/logger.js +123 -0
- package/dist/shared/logger.js.map +1 -0
- package/dist/shared/performance.d.ts +65 -0
- package/dist/shared/performance.d.ts.map +1 -0
- package/dist/shared/performance.js +136 -0
- package/dist/shared/performance.js.map +1 -0
- package/dist/shared/task-runner.d.ts +2 -0
- package/dist/shared/task-runner.d.ts.map +1 -0
- package/dist/shared/task-runner.js +16 -0
- package/dist/shared/task-runner.js.map +1 -0
- package/dist/shared/validation.d.ts +6 -0
- package/dist/shared/validation.d.ts.map +1 -0
- package/dist/shared/validation.js +6 -0
- package/dist/shared/validation.js.map +1 -0
- package/dist/shared-utils.d.ts +63 -0
- package/dist/shared-utils.d.ts.map +1 -0
- package/dist/shared-utils.js +123 -0
- package/dist/shared-utils.js.map +1 -0
- package/dist/template-manager.d.ts +23 -2
- package/dist/template-manager.d.ts.map +1 -1
- package/dist/template-manager.js +176 -87
- package/dist/template-manager.js.map +1 -1
- package/dist/test-client.d.ts.map +1 -1
- package/dist/test-client.js +10 -8
- package/dist/test-client.js.map +1 -1
- package/dist/test-runner.d.ts +52 -0
- package/dist/test-runner.d.ts.map +1 -0
- package/dist/test-runner.js +785 -0
- package/dist/test-runner.js.map +1 -0
- package/dist/testing.d.ts +103 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +163 -0
- package/dist/testing.js.map +1 -0
- package/dist/version-checker.d.ts.map +1 -1
- package/dist/version-checker.js +2 -2
- package/dist/version-checker.js.map +1 -1
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +21 -0
- package/dist/version.js.map +1 -0
- package/dist/watcher.d.ts +6 -3
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +49 -10
- package/dist/watcher.js.map +1 -1
- package/package.json +57 -7
- package/templates/cloudflare/worker.ts.template +381 -0
- package/templates/cloudflare/wrangler.toml.template +9 -0
- package/dist/base.d.ts +0 -58
- package/dist/base.d.ts.map +0 -1
- package/dist/base.js +0 -92
- package/dist/base.js.map +0 -1
- package/dist/dependency-manager.d.ts +0 -49
- package/dist/dependency-manager.d.ts.map +0 -1
- package/dist/dependency-manager.js +0 -165
- package/dist/dependency-manager.js.map +0 -1
- package/dist/registry-manager.d.ts +0 -76
- package/dist/registry-manager.d.ts.map +0 -1
- package/dist/registry-manager.js +0 -220
- package/dist/registry-manager.js.map +0 -1
- package/dist/schema-extractor.d.ts +0 -110
- package/dist/schema-extractor.d.ts.map +0 -1
- package/dist/schema-extractor.js +0 -727
- package/dist/schema-extractor.js.map +0 -1
- package/dist/test-marketplace-sources.d.ts +0 -5
- package/dist/test-marketplace-sources.d.ts.map +0 -1
- package/dist/test-marketplace-sources.js +0 -53
- package/dist/test-marketplace-sources.js.map +0 -1
- package/dist/types.d.ts +0 -109
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -12
- package/dist/types.js.map +0 -1
package/dist/daemon/server.js
CHANGED
|
@@ -1,96 +1,432 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Daemon Server
|
|
3
|
+
* Global Photon Daemon Server
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
5
|
+
* Single daemon process for all photons.
|
|
6
|
+
* - Listens on global Unix socket / named pipe (~/.photon/daemon.sock)
|
|
7
|
+
* - Handles requests for multiple photons via photonName field
|
|
8
|
+
* - Lazy-initializes SessionManagers per photon on first request
|
|
9
|
+
* - Provides pub/sub, locks, scheduled jobs, and webhooks
|
|
10
10
|
*/
|
|
11
11
|
import * as net from 'net';
|
|
12
|
+
import * as http from 'http';
|
|
12
13
|
import * as fs from 'fs';
|
|
13
14
|
import { SessionManager } from './session-manager.js';
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
import { isValidDaemonRequest, } from './protocol.js';
|
|
16
|
+
import { setPromptHandler } from '@portel/photon-core';
|
|
17
|
+
import { createLogger } from '../shared/logger.js';
|
|
18
|
+
import { getErrorMessage } from '../shared/error-handler.js';
|
|
19
|
+
// Command line args: socketPath (global daemon only needs socket path)
|
|
20
|
+
const socketPath = process.argv[2];
|
|
21
|
+
const logger = createLogger({
|
|
22
|
+
component: 'daemon-server',
|
|
23
|
+
scope: 'global',
|
|
24
|
+
minimal: true,
|
|
25
|
+
});
|
|
26
|
+
if (!socketPath) {
|
|
27
|
+
logger.error('Missing required argument: socketPath');
|
|
21
28
|
process.exit(1);
|
|
22
29
|
}
|
|
23
|
-
|
|
30
|
+
// Map of photonName -> SessionManager (lazy initialized)
|
|
31
|
+
const sessionManagers = new Map();
|
|
32
|
+
const photonPaths = new Map(); // photonName -> photonPath
|
|
24
33
|
let idleTimeout = 600000; // 10 minutes default
|
|
25
34
|
let idleTimer = null;
|
|
26
35
|
// Track pending prompts waiting for user input
|
|
27
|
-
// Map: requestId -> { resolve, reject } for resolving prompt responses
|
|
28
36
|
const pendingPrompts = new Map();
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
// Channel subscriptions for pub/sub
|
|
38
|
+
const channelSubscriptions = new Map();
|
|
39
|
+
const EVENT_BUFFER_SIZE = 30;
|
|
40
|
+
const channelEventBuffers = new Map();
|
|
41
|
+
function bufferEvent(channel, message) {
|
|
42
|
+
let buffer = channelEventBuffers.get(channel);
|
|
43
|
+
if (!buffer) {
|
|
44
|
+
buffer = { events: [], nextId: 1 };
|
|
45
|
+
channelEventBuffers.set(channel, buffer);
|
|
46
|
+
}
|
|
47
|
+
const eventId = buffer.nextId++;
|
|
48
|
+
const event = {
|
|
49
|
+
id: eventId,
|
|
50
|
+
channel,
|
|
51
|
+
message,
|
|
52
|
+
timestamp: Date.now(),
|
|
53
|
+
};
|
|
54
|
+
buffer.events.push(event);
|
|
55
|
+
// Keep only last N events (circular buffer)
|
|
56
|
+
if (buffer.events.length > EVENT_BUFFER_SIZE) {
|
|
57
|
+
buffer.events.shift();
|
|
58
|
+
}
|
|
59
|
+
return eventId;
|
|
60
|
+
}
|
|
61
|
+
function getEventsSince(channel, lastEventId) {
|
|
62
|
+
const buffer = channelEventBuffers.get(channel);
|
|
63
|
+
if (!buffer || buffer.events.length === 0) {
|
|
64
|
+
return { events: [], refreshNeeded: false };
|
|
65
|
+
}
|
|
66
|
+
const oldestEvent = buffer.events[0];
|
|
67
|
+
// If lastEventId is older than our oldest buffered event, refresh needed
|
|
68
|
+
if (lastEventId < oldestEvent.id) {
|
|
69
|
+
return { events: [], refreshNeeded: true };
|
|
70
|
+
}
|
|
71
|
+
// Find events to replay
|
|
72
|
+
const events = buffer.events.filter((e) => e.id > lastEventId);
|
|
73
|
+
return { events, refreshNeeded: false };
|
|
74
|
+
}
|
|
75
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
76
|
+
// DISTRIBUTED LOCKS
|
|
77
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
78
|
+
const activeLocks = new Map();
|
|
79
|
+
const DEFAULT_LOCK_TIMEOUT = 30000;
|
|
80
|
+
function acquireLock(lockName, holder, timeout = DEFAULT_LOCK_TIMEOUT) {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
const existing = activeLocks.get(lockName);
|
|
83
|
+
if (existing && existing.expiresAt > now) {
|
|
84
|
+
if (existing.holder !== holder) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
existing.expiresAt = now + timeout;
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
activeLocks.set(lockName, {
|
|
91
|
+
name: lockName,
|
|
92
|
+
holder,
|
|
93
|
+
acquiredAt: now,
|
|
94
|
+
expiresAt: now + timeout,
|
|
95
|
+
});
|
|
96
|
+
logger.info('Lock acquired', { lockName, holder, timeout });
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
function releaseLock(lockName, holder) {
|
|
100
|
+
const existing = activeLocks.get(lockName);
|
|
101
|
+
if (!existing)
|
|
102
|
+
return true;
|
|
103
|
+
if (existing.holder !== holder)
|
|
104
|
+
return false;
|
|
105
|
+
activeLocks.delete(lockName);
|
|
106
|
+
logger.info('Lock released', { lockName, holder });
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
function cleanupExpiredLocks() {
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
for (const [name, lock] of activeLocks.entries()) {
|
|
112
|
+
if (lock.expiresAt <= now) {
|
|
113
|
+
activeLocks.delete(name);
|
|
114
|
+
logger.info('Lock expired', { lockName: name, holder: lock.holder });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
setInterval(cleanupExpiredLocks, 10000);
|
|
119
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
120
|
+
// SCHEDULED JOBS
|
|
121
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
122
|
+
const scheduledJobs = new Map();
|
|
123
|
+
const jobTimers = new Map();
|
|
124
|
+
function parseCron(cron) {
|
|
125
|
+
const parts = cron.trim().split(/\s+/);
|
|
126
|
+
if (parts.length !== 5) {
|
|
127
|
+
return { isValid: false, nextRun: 0 };
|
|
128
|
+
}
|
|
129
|
+
const [minute, hour] = parts;
|
|
130
|
+
const now = new Date();
|
|
131
|
+
const nextDate = new Date(now);
|
|
132
|
+
nextDate.setSeconds(0);
|
|
133
|
+
nextDate.setMilliseconds(0);
|
|
134
|
+
if (minute === '*' && hour === '*') {
|
|
135
|
+
nextDate.setMinutes(nextDate.getMinutes() + 1);
|
|
136
|
+
}
|
|
137
|
+
else if (minute.startsWith('*/')) {
|
|
138
|
+
const interval = parseInt(minute.slice(2));
|
|
139
|
+
const currentMinute = nextDate.getMinutes();
|
|
140
|
+
const nextMinute = Math.ceil((currentMinute + 1) / interval) * interval;
|
|
141
|
+
nextDate.setMinutes(nextMinute);
|
|
142
|
+
}
|
|
143
|
+
else if (hour === '*') {
|
|
144
|
+
const targetMinute = parseInt(minute);
|
|
145
|
+
if (nextDate.getMinutes() >= targetMinute) {
|
|
146
|
+
nextDate.setHours(nextDate.getHours() + 1);
|
|
147
|
+
}
|
|
148
|
+
nextDate.setMinutes(targetMinute);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const targetMinute = parseInt(minute);
|
|
152
|
+
const targetHour = parseInt(hour);
|
|
153
|
+
nextDate.setMinutes(targetMinute);
|
|
154
|
+
nextDate.setHours(targetHour);
|
|
155
|
+
if (nextDate <= now) {
|
|
156
|
+
nextDate.setDate(nextDate.getDate() + 1);
|
|
44
157
|
}
|
|
45
158
|
}
|
|
159
|
+
return { isValid: true, nextRun: nextDate.getTime() };
|
|
160
|
+
}
|
|
161
|
+
function scheduleJob(job) {
|
|
162
|
+
const { isValid, nextRun } = parseCron(job.cron);
|
|
163
|
+
if (!isValid) {
|
|
164
|
+
logger.error('Invalid cron expression', { jobId: job.id, cron: job.cron });
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
job.nextRun = nextRun;
|
|
168
|
+
scheduledJobs.set(job.id, job);
|
|
169
|
+
const existingTimer = jobTimers.get(job.id);
|
|
170
|
+
if (existingTimer) {
|
|
171
|
+
clearTimeout(existingTimer);
|
|
172
|
+
}
|
|
173
|
+
const delay = nextRun - Date.now();
|
|
174
|
+
const timer = setTimeout(() => runJob(job.id), delay);
|
|
175
|
+
jobTimers.set(job.id, timer);
|
|
176
|
+
logger.info('Job scheduled', {
|
|
177
|
+
jobId: job.id,
|
|
178
|
+
method: job.method,
|
|
179
|
+
photon: job.photonName,
|
|
180
|
+
nextRun: new Date(nextRun).toISOString(),
|
|
181
|
+
});
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
async function runJob(jobId) {
|
|
185
|
+
const job = scheduledJobs.get(jobId);
|
|
186
|
+
if (!job)
|
|
187
|
+
return;
|
|
188
|
+
const sessionManager = sessionManagers.get(job.photonName);
|
|
189
|
+
if (!sessionManager) {
|
|
190
|
+
logger.warn('Cannot run job - photon not initialized', { jobId, photon: job.photonName });
|
|
191
|
+
scheduleJob(job); // Reschedule anyway
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
logger.info('Running scheduled job', { jobId, method: job.method, photon: job.photonName });
|
|
195
|
+
try {
|
|
196
|
+
const session = await sessionManager.getOrCreateSession('scheduler', 'scheduler');
|
|
197
|
+
await sessionManager.loader.executeTool(session.instance, job.method, job.args || {});
|
|
198
|
+
job.lastRun = Date.now();
|
|
199
|
+
job.runCount++;
|
|
200
|
+
publishToChannel(`jobs:${job.photonName}`, {
|
|
201
|
+
event: 'job-completed',
|
|
202
|
+
jobId,
|
|
203
|
+
method: job.method,
|
|
204
|
+
runCount: job.runCount,
|
|
205
|
+
});
|
|
206
|
+
logger.info('Job completed', { jobId, method: job.method, runCount: job.runCount });
|
|
207
|
+
}
|
|
46
208
|
catch (error) {
|
|
47
|
-
|
|
48
|
-
|
|
209
|
+
logger.error('Job failed', { jobId, method: job.method, error: getErrorMessage(error) });
|
|
210
|
+
publishToChannel(`jobs:${job.photonName}`, {
|
|
211
|
+
event: 'job-failed',
|
|
212
|
+
jobId,
|
|
213
|
+
method: job.method,
|
|
214
|
+
error: getErrorMessage(error),
|
|
215
|
+
});
|
|
49
216
|
}
|
|
217
|
+
scheduleJob(job);
|
|
50
218
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
clearTimeout(idleTimer);
|
|
219
|
+
function unscheduleJob(jobId) {
|
|
220
|
+
const timer = jobTimers.get(jobId);
|
|
221
|
+
if (timer) {
|
|
222
|
+
clearTimeout(timer);
|
|
223
|
+
jobTimers.delete(jobId);
|
|
57
224
|
}
|
|
58
|
-
|
|
59
|
-
|
|
225
|
+
const existed = scheduledJobs.delete(jobId);
|
|
226
|
+
if (existed) {
|
|
227
|
+
logger.info('Job unscheduled', { jobId });
|
|
60
228
|
}
|
|
61
|
-
|
|
62
|
-
|
|
229
|
+
return existed;
|
|
230
|
+
}
|
|
231
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
232
|
+
// WEBHOOK HTTP SERVER
|
|
233
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
234
|
+
let webhookServer = null;
|
|
235
|
+
const WEBHOOK_PORT = parseInt(process.env.PHOTON_WEBHOOK_PORT || '0');
|
|
236
|
+
function startWebhookServer(port) {
|
|
237
|
+
if (port <= 0)
|
|
238
|
+
return;
|
|
239
|
+
webhookServer = http.createServer(async (req, res) => {
|
|
240
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
241
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
242
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Webhook-Secret, X-Photon-Name');
|
|
243
|
+
if (req.method === 'OPTIONS') {
|
|
244
|
+
res.writeHead(204);
|
|
245
|
+
res.end();
|
|
63
246
|
return;
|
|
64
|
-
const lastActivity = sessionManager.getLastActivity();
|
|
65
|
-
const idleTime = Date.now() - lastActivity;
|
|
66
|
-
if (idleTime >= idleTimeout) {
|
|
67
|
-
console.error(`[daemon-server] Idle timeout reached (${idleTime}ms). Shutting down.`);
|
|
68
|
-
shutdown();
|
|
69
247
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
248
|
+
// Parse URL: /webhook/{photonName}/{method}
|
|
249
|
+
const url = new URL(req.url || '/', `http://localhost:${port}`);
|
|
250
|
+
const pathParts = url.pathname.split('/').filter(Boolean);
|
|
251
|
+
if (pathParts[0] !== 'webhook' || !pathParts[1] || !pathParts[2]) {
|
|
252
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
253
|
+
res.end(JSON.stringify({ error: 'Not found. Use /webhook/{photonName}/{method}' }));
|
|
254
|
+
return;
|
|
73
255
|
}
|
|
74
|
-
|
|
256
|
+
const photonName = pathParts[1];
|
|
257
|
+
const method = pathParts[2];
|
|
258
|
+
const expectedSecret = process.env.PHOTON_WEBHOOK_SECRET;
|
|
259
|
+
if (expectedSecret) {
|
|
260
|
+
const providedSecret = req.headers['x-webhook-secret'];
|
|
261
|
+
if (providedSecret !== expectedSecret) {
|
|
262
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
263
|
+
res.end(JSON.stringify({ error: 'Invalid webhook secret' }));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
let body = '';
|
|
268
|
+
req.on('data', (chunk) => {
|
|
269
|
+
body += chunk;
|
|
270
|
+
});
|
|
271
|
+
req.on('end', async () => {
|
|
272
|
+
let args = {};
|
|
273
|
+
try {
|
|
274
|
+
if (body) {
|
|
275
|
+
args = JSON.parse(body);
|
|
276
|
+
}
|
|
277
|
+
args._webhook = {
|
|
278
|
+
method: req.method,
|
|
279
|
+
headers: req.headers,
|
|
280
|
+
query: Object.fromEntries(url.searchParams),
|
|
281
|
+
timestamp: Date.now(),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
286
|
+
res.end(JSON.stringify({ error: 'Invalid JSON body' }));
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const sessionManager = sessionManagers.get(photonName);
|
|
290
|
+
if (!sessionManager) {
|
|
291
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
292
|
+
res.end(JSON.stringify({ error: `Photon '${photonName}' not initialized` }));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
const session = await sessionManager.getOrCreateSession('webhook', 'webhook');
|
|
297
|
+
const result = await sessionManager.loader.executeTool(session.instance, method, args);
|
|
298
|
+
logger.info('Webhook executed', { photon: photonName, method });
|
|
299
|
+
publishToChannel(`webhooks:${photonName}`, {
|
|
300
|
+
event: 'webhook-received',
|
|
301
|
+
method,
|
|
302
|
+
timestamp: Date.now(),
|
|
303
|
+
});
|
|
304
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
305
|
+
res.end(JSON.stringify({ success: true, data: result }));
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
logger.error('Webhook execution failed', {
|
|
309
|
+
photon: photonName,
|
|
310
|
+
method,
|
|
311
|
+
error: getErrorMessage(error),
|
|
312
|
+
});
|
|
313
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
314
|
+
res.end(JSON.stringify({ error: getErrorMessage(error) }));
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
webhookServer.listen(port, () => {
|
|
319
|
+
logger.info('Webhook server started', { port });
|
|
320
|
+
});
|
|
321
|
+
webhookServer.on('error', (error) => {
|
|
322
|
+
logger.error('Webhook server error', { error: getErrorMessage(error) });
|
|
323
|
+
});
|
|
75
324
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
function
|
|
80
|
-
|
|
325
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
326
|
+
// PUB/SUB
|
|
327
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
328
|
+
function cleanupSocketSubscriptions(socket) {
|
|
329
|
+
for (const [channel, subs] of channelSubscriptions.entries()) {
|
|
330
|
+
subs.delete(socket);
|
|
331
|
+
if (subs.size === 0) {
|
|
332
|
+
channelSubscriptions.delete(channel);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
81
335
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
336
|
+
function publishToChannel(channel, message, excludeSocket) {
|
|
337
|
+
// Buffer the event for replay
|
|
338
|
+
const eventId = bufferEvent(channel, message);
|
|
339
|
+
const payload = JSON.stringify({
|
|
340
|
+
type: 'channel_message',
|
|
341
|
+
id: `ch_${eventId}`,
|
|
342
|
+
eventId,
|
|
343
|
+
channel,
|
|
344
|
+
message,
|
|
345
|
+
}) + '\n';
|
|
346
|
+
const sentSockets = new Set();
|
|
347
|
+
// Send to exact channel subscribers
|
|
348
|
+
const exactSubscribers = channelSubscriptions.get(channel);
|
|
349
|
+
if (exactSubscribers) {
|
|
350
|
+
for (const socket of exactSubscribers) {
|
|
351
|
+
if (socket !== excludeSocket && !socket.destroyed && !sentSockets.has(socket)) {
|
|
352
|
+
try {
|
|
353
|
+
socket.write(payload);
|
|
354
|
+
sentSockets.add(socket);
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
// Socket write failed
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// Send to wildcard subscribers
|
|
363
|
+
const channelPrefix = channel.split(':')[0];
|
|
364
|
+
if (channelPrefix) {
|
|
365
|
+
const wildcardChannel = `${channelPrefix}:*`;
|
|
366
|
+
const wildcardSubscribers = channelSubscriptions.get(wildcardChannel);
|
|
367
|
+
if (wildcardSubscribers) {
|
|
368
|
+
for (const socket of wildcardSubscribers) {
|
|
369
|
+
if (socket !== excludeSocket && !socket.destroyed && !sentSockets.has(socket)) {
|
|
370
|
+
try {
|
|
371
|
+
socket.write(payload);
|
|
372
|
+
sentSockets.add(socket);
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
// Socket write failed
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
logger.debug('Published to channel', {
|
|
382
|
+
channel,
|
|
383
|
+
eventId,
|
|
384
|
+
exactSubs: exactSubscribers?.size || 0,
|
|
385
|
+
wildcardSubs: channelSubscriptions.get(`${channelPrefix}:*`)?.size || 0,
|
|
386
|
+
});
|
|
387
|
+
return eventId;
|
|
388
|
+
}
|
|
389
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
390
|
+
// SESSION MANAGER (Lazy Initialization)
|
|
391
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
392
|
+
async function getOrCreateSessionManager(photonName, photonPath) {
|
|
393
|
+
let manager = sessionManagers.get(photonName);
|
|
394
|
+
if (manager) {
|
|
395
|
+
return manager;
|
|
396
|
+
}
|
|
397
|
+
// Need photonPath to initialize
|
|
398
|
+
const storedPath = photonPaths.get(photonName);
|
|
399
|
+
const pathToUse = photonPath || storedPath;
|
|
400
|
+
if (!pathToUse) {
|
|
401
|
+
logger.warn('Cannot initialize photon - no path provided', { photonName });
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
try {
|
|
405
|
+
logger.info('Initializing session manager', { photonName, photonPath: pathToUse });
|
|
406
|
+
manager = new SessionManager(pathToUse, photonName, idleTimeout, logger.child({ scope: photonName }));
|
|
407
|
+
sessionManagers.set(photonName, manager);
|
|
408
|
+
photonPaths.set(photonName, pathToUse);
|
|
409
|
+
logger.info('Session manager initialized', { photonName });
|
|
410
|
+
return manager;
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
logger.error('Failed to initialize session manager', {
|
|
414
|
+
photonName,
|
|
415
|
+
error: getErrorMessage(error),
|
|
416
|
+
});
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
421
|
+
// PROMPT HANDLER
|
|
422
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
85
423
|
function createSocketPromptHandler(socket, requestId) {
|
|
86
424
|
return async (message, defaultValue) => {
|
|
87
425
|
return new Promise((resolve, reject) => {
|
|
88
|
-
// Store the resolver for when we get the response
|
|
89
426
|
pendingPrompts.set(requestId, {
|
|
90
427
|
resolve: (value) => resolve(value),
|
|
91
428
|
reject,
|
|
92
429
|
});
|
|
93
|
-
// Send prompt request to client
|
|
94
430
|
const promptResponse = {
|
|
95
431
|
type: 'prompt',
|
|
96
432
|
id: requestId,
|
|
@@ -104,163 +440,437 @@ function createSocketPromptHandler(socket, requestId) {
|
|
|
104
440
|
});
|
|
105
441
|
};
|
|
106
442
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
443
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
444
|
+
// REQUEST HANDLER
|
|
445
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
110
446
|
async function handleRequest(request, socket) {
|
|
111
447
|
resetIdleTimer();
|
|
112
448
|
if (request.type === 'ping') {
|
|
113
|
-
return {
|
|
114
|
-
type: 'pong',
|
|
115
|
-
id: request.id,
|
|
116
|
-
};
|
|
449
|
+
return { type: 'pong', id: request.id };
|
|
117
450
|
}
|
|
118
451
|
if (request.type === 'shutdown') {
|
|
119
452
|
shutdown();
|
|
453
|
+
return { type: 'result', id: request.id, success: true, data: { message: 'Shutting down' } };
|
|
454
|
+
}
|
|
455
|
+
// Handle hot-reload request
|
|
456
|
+
if (request.type === 'reload') {
|
|
457
|
+
const photonName = request.photonName;
|
|
458
|
+
const photonPath = request.photonPath;
|
|
459
|
+
if (!photonName || !photonPath) {
|
|
460
|
+
return {
|
|
461
|
+
type: 'error',
|
|
462
|
+
id: request.id,
|
|
463
|
+
error: 'photonName and photonPath required for reload',
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
const result = await reloadPhoton(photonName, photonPath);
|
|
120
467
|
return {
|
|
121
468
|
type: 'result',
|
|
122
469
|
id: request.id,
|
|
123
|
-
success:
|
|
124
|
-
data:
|
|
470
|
+
success: result.success,
|
|
471
|
+
data: result.success
|
|
472
|
+
? { message: 'Reload complete', sessionsUpdated: result.sessionsUpdated }
|
|
473
|
+
: { error: result.error },
|
|
125
474
|
};
|
|
126
475
|
}
|
|
127
|
-
// Handle prompt response
|
|
476
|
+
// Handle prompt response
|
|
128
477
|
if (request.type === 'prompt_response') {
|
|
129
478
|
const pending = pendingPrompts.get(request.id);
|
|
130
479
|
if (pending) {
|
|
131
480
|
pendingPrompts.delete(request.id);
|
|
132
481
|
pending.resolve(request.promptValue ?? null);
|
|
133
482
|
}
|
|
134
|
-
// Don't send a response back - the original command handler will respond
|
|
135
483
|
return null;
|
|
136
484
|
}
|
|
485
|
+
// Handle channel subscribe
|
|
486
|
+
if (request.type === 'subscribe') {
|
|
487
|
+
const channel = request.channel;
|
|
488
|
+
const lastEventId = request.lastEventId;
|
|
489
|
+
let subs = channelSubscriptions.get(channel);
|
|
490
|
+
if (!subs) {
|
|
491
|
+
subs = new Set();
|
|
492
|
+
channelSubscriptions.set(channel, subs);
|
|
493
|
+
}
|
|
494
|
+
subs.add(socket);
|
|
495
|
+
logger.info('Client subscribed to channel', { channel, subscribers: subs.size });
|
|
496
|
+
// Replay missed events if lastEventId provided
|
|
497
|
+
if (lastEventId !== undefined) {
|
|
498
|
+
const parsedLastEventId = parseInt(String(lastEventId), 10) || 0;
|
|
499
|
+
const { events, refreshNeeded } = getEventsSince(channel, parsedLastEventId);
|
|
500
|
+
if (refreshNeeded) {
|
|
501
|
+
// Send refresh-needed signal
|
|
502
|
+
socket.write(JSON.stringify({
|
|
503
|
+
type: 'refresh_needed',
|
|
504
|
+
id: request.id,
|
|
505
|
+
channel,
|
|
506
|
+
}) + '\n');
|
|
507
|
+
logger.info('Replay: refresh needed', { channel, lastEventId });
|
|
508
|
+
}
|
|
509
|
+
else if (events.length > 0) {
|
|
510
|
+
// Replay events
|
|
511
|
+
for (const event of events) {
|
|
512
|
+
socket.write(JSON.stringify({
|
|
513
|
+
type: 'channel_message',
|
|
514
|
+
id: `replay_${event.id}`,
|
|
515
|
+
eventId: event.id,
|
|
516
|
+
channel: event.channel,
|
|
517
|
+
message: event.message,
|
|
518
|
+
replay: true,
|
|
519
|
+
}) + '\n');
|
|
520
|
+
}
|
|
521
|
+
logger.info('Replayed events', { channel, count: events.length });
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return {
|
|
525
|
+
type: 'result',
|
|
526
|
+
id: request.id,
|
|
527
|
+
success: true,
|
|
528
|
+
data: { subscribed: true, channel },
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
// Handle channel unsubscribe
|
|
532
|
+
if (request.type === 'unsubscribe') {
|
|
533
|
+
const channel = request.channel;
|
|
534
|
+
const subs = channelSubscriptions.get(channel);
|
|
535
|
+
if (subs) {
|
|
536
|
+
subs.delete(socket);
|
|
537
|
+
if (subs.size === 0) {
|
|
538
|
+
channelSubscriptions.delete(channel);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
logger.info('Client unsubscribed from channel', { channel });
|
|
542
|
+
return { type: 'result', id: request.id, success: true, data: { unsubscribed: true, channel } };
|
|
543
|
+
}
|
|
544
|
+
// Handle channel publish
|
|
545
|
+
if (request.type === 'publish') {
|
|
546
|
+
const channel = request.channel;
|
|
547
|
+
const message = request.message;
|
|
548
|
+
const eventId = publishToChannel(channel, message, socket);
|
|
549
|
+
return {
|
|
550
|
+
type: 'result',
|
|
551
|
+
id: request.id,
|
|
552
|
+
success: true,
|
|
553
|
+
data: { published: true, channel, eventId },
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
// Handle get_events_since (for event replay)
|
|
557
|
+
if (request.type === 'get_events_since') {
|
|
558
|
+
const channel = request.channel;
|
|
559
|
+
const parsedLastEventId = parseInt(String(request.lastEventId || '0'), 10) || 0;
|
|
560
|
+
const { events, refreshNeeded } = getEventsSince(channel, parsedLastEventId);
|
|
561
|
+
return {
|
|
562
|
+
type: 'result',
|
|
563
|
+
id: request.id,
|
|
564
|
+
success: true,
|
|
565
|
+
data: { events, refreshNeeded },
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
// Handle lock acquisition
|
|
569
|
+
if (request.type === 'lock') {
|
|
570
|
+
const lockName = request.lockName;
|
|
571
|
+
const holder = request.sessionId || request.id;
|
|
572
|
+
const timeout = request.lockTimeout || DEFAULT_LOCK_TIMEOUT;
|
|
573
|
+
const acquired = acquireLock(lockName, holder, timeout);
|
|
574
|
+
return {
|
|
575
|
+
type: 'result',
|
|
576
|
+
id: request.id,
|
|
577
|
+
success: acquired,
|
|
578
|
+
data: {
|
|
579
|
+
acquired,
|
|
580
|
+
lockName,
|
|
581
|
+
holder,
|
|
582
|
+
...(acquired ? {} : { reason: 'Lock held by another client' }),
|
|
583
|
+
},
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
// Handle lock release
|
|
587
|
+
if (request.type === 'unlock') {
|
|
588
|
+
const lockName = request.lockName;
|
|
589
|
+
const holder = request.sessionId || request.id;
|
|
590
|
+
const released = releaseLock(lockName, holder);
|
|
591
|
+
return {
|
|
592
|
+
type: 'result',
|
|
593
|
+
id: request.id,
|
|
594
|
+
success: released,
|
|
595
|
+
data: {
|
|
596
|
+
released,
|
|
597
|
+
lockName,
|
|
598
|
+
...(released ? {} : { reason: 'Cannot release lock held by another client' }),
|
|
599
|
+
},
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
// Handle list locks
|
|
603
|
+
if (request.type === 'list_locks') {
|
|
604
|
+
const locks = Array.from(activeLocks.values());
|
|
605
|
+
return { type: 'result', id: request.id, success: true, data: { locks } };
|
|
606
|
+
}
|
|
607
|
+
// Handle job scheduling
|
|
608
|
+
if (request.type === 'schedule') {
|
|
609
|
+
const photonName = request.photonName;
|
|
610
|
+
if (!photonName) {
|
|
611
|
+
return { type: 'error', id: request.id, error: 'photonName required for scheduling' };
|
|
612
|
+
}
|
|
613
|
+
const job = {
|
|
614
|
+
id: request.jobId,
|
|
615
|
+
method: request.method,
|
|
616
|
+
args: request.args,
|
|
617
|
+
cron: request.cron,
|
|
618
|
+
runCount: 0,
|
|
619
|
+
createdAt: Date.now(),
|
|
620
|
+
createdBy: request.sessionId,
|
|
621
|
+
photonName,
|
|
622
|
+
};
|
|
623
|
+
const scheduled = scheduleJob(job);
|
|
624
|
+
return {
|
|
625
|
+
type: 'result',
|
|
626
|
+
id: request.id,
|
|
627
|
+
success: scheduled,
|
|
628
|
+
data: scheduled
|
|
629
|
+
? { scheduled: true, jobId: job.id, nextRun: job.nextRun }
|
|
630
|
+
: { scheduled: false, reason: 'Invalid cron expression' },
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
// Handle job unscheduling
|
|
634
|
+
if (request.type === 'unschedule') {
|
|
635
|
+
const jobId = request.jobId;
|
|
636
|
+
const unscheduled = unscheduleJob(jobId);
|
|
637
|
+
return { type: 'result', id: request.id, success: true, data: { unscheduled, jobId } };
|
|
638
|
+
}
|
|
639
|
+
// Handle list jobs
|
|
640
|
+
if (request.type === 'list_jobs') {
|
|
641
|
+
const jobs = Array.from(scheduledJobs.values());
|
|
642
|
+
return { type: 'result', id: request.id, success: true, data: { jobs } };
|
|
643
|
+
}
|
|
644
|
+
// Handle command execution
|
|
137
645
|
if (request.type === 'command') {
|
|
138
646
|
if (!request.method) {
|
|
139
|
-
return {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
};
|
|
647
|
+
return { type: 'error', id: request.id, error: 'Method name required' };
|
|
648
|
+
}
|
|
649
|
+
const photonName = request.photonName;
|
|
650
|
+
if (!photonName) {
|
|
651
|
+
return { type: 'error', id: request.id, error: 'photonName required for commands' };
|
|
144
652
|
}
|
|
653
|
+
const sessionManager = await getOrCreateSessionManager(photonName, request.photonPath);
|
|
145
654
|
if (!sessionManager) {
|
|
146
655
|
return {
|
|
147
656
|
type: 'error',
|
|
148
657
|
id: request.id,
|
|
149
|
-
error: '
|
|
658
|
+
error: `Cannot initialize photon '${photonName}'. Provide photonPath in request.`,
|
|
150
659
|
};
|
|
151
660
|
}
|
|
152
661
|
try {
|
|
153
|
-
// Get or create session for this client
|
|
154
662
|
const session = await sessionManager.getOrCreateSession(request.sessionId, request.clientType);
|
|
155
|
-
|
|
156
|
-
|
|
663
|
+
logger.info('Executing request', {
|
|
664
|
+
method: request.method,
|
|
665
|
+
photon: photonName,
|
|
666
|
+
sessionId: session.id,
|
|
667
|
+
});
|
|
157
668
|
setPromptHandler(createSocketPromptHandler(socket, request.id));
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
type: 'result',
|
|
164
|
-
id: request.id,
|
|
165
|
-
success: true,
|
|
166
|
-
data: result,
|
|
669
|
+
const outputHandler = (emit) => {
|
|
670
|
+
if (emit && typeof emit === 'object' && emit.channel) {
|
|
671
|
+
publishToChannel(emit.channel, emit, socket);
|
|
672
|
+
logger.debug('Published to channel', { channel: emit.channel });
|
|
673
|
+
}
|
|
167
674
|
};
|
|
675
|
+
const result = await sessionManager.loader.executeTool(session.instance, request.method, request.args || {}, { outputHandler });
|
|
676
|
+
setPromptHandler(null);
|
|
677
|
+
return { type: 'result', id: request.id, success: true, data: result };
|
|
168
678
|
}
|
|
169
679
|
catch (error) {
|
|
170
|
-
|
|
171
|
-
|
|
680
|
+
logger.error('Error executing request', {
|
|
681
|
+
method: request.method,
|
|
682
|
+
error: getErrorMessage(error),
|
|
683
|
+
});
|
|
172
684
|
setPromptHandler(null);
|
|
173
|
-
return {
|
|
174
|
-
type: 'error',
|
|
175
|
-
id: request.id,
|
|
176
|
-
error: error.message,
|
|
177
|
-
};
|
|
685
|
+
return { type: 'error', id: request.id, error: getErrorMessage(error) };
|
|
178
686
|
}
|
|
179
687
|
}
|
|
180
|
-
return {
|
|
181
|
-
type: 'error',
|
|
182
|
-
id: request.id,
|
|
183
|
-
error: `Unknown request type: ${request.type}`,
|
|
184
|
-
};
|
|
688
|
+
return { type: 'error', id: request.id, error: `Unknown request type: ${request.type}` };
|
|
185
689
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
690
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
691
|
+
// HOT RELOAD
|
|
692
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
693
|
+
async function reloadPhoton(photonName, newPhotonPath) {
|
|
694
|
+
try {
|
|
695
|
+
logger.info('Hot-reloading photon', { photonName, path: newPhotonPath });
|
|
696
|
+
const sessionManager = sessionManagers.get(photonName);
|
|
697
|
+
if (!sessionManager) {
|
|
698
|
+
// First time - just register the path
|
|
699
|
+
photonPaths.set(photonName, newPhotonPath);
|
|
700
|
+
return { success: true, sessionsUpdated: 0 };
|
|
701
|
+
}
|
|
702
|
+
await sessionManager.loader.reloadFile(newPhotonPath);
|
|
703
|
+
const sessions = sessionManager.getSessions();
|
|
704
|
+
let updatedCount = 0;
|
|
705
|
+
for (const session of sessions) {
|
|
706
|
+
try {
|
|
707
|
+
const newInstance = await sessionManager.loader.loadFile(newPhotonPath);
|
|
708
|
+
const oldInstance = session.instance;
|
|
709
|
+
if (oldInstance && typeof oldInstance === 'object') {
|
|
710
|
+
for (const key of Object.keys(oldInstance)) {
|
|
711
|
+
const value = oldInstance[key];
|
|
712
|
+
if (typeof value !== 'function' && key !== 'constructor') {
|
|
713
|
+
try {
|
|
714
|
+
newInstance[key] = value;
|
|
715
|
+
}
|
|
716
|
+
catch {
|
|
717
|
+
// Some properties may be read-only
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
if (sessionManager.updateSessionInstance(session.id, newInstance)) {
|
|
723
|
+
updatedCount++;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
catch (err) {
|
|
727
|
+
logger.error('Failed to update session instance', {
|
|
728
|
+
sessionId: session.id,
|
|
729
|
+
error: getErrorMessage(err),
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
publishToChannel(`system:${photonName}`, {
|
|
734
|
+
event: 'photon-reloaded',
|
|
735
|
+
timestamp: Date.now(),
|
|
736
|
+
sessionsUpdated: updatedCount,
|
|
737
|
+
});
|
|
738
|
+
logger.info('Photon reloaded successfully', { photonName, sessionsUpdated: updatedCount });
|
|
739
|
+
return { success: true, sessionsUpdated: updatedCount };
|
|
740
|
+
}
|
|
741
|
+
catch (error) {
|
|
742
|
+
const errorMessage = getErrorMessage(error);
|
|
743
|
+
logger.error('Photon reload failed', { photonName, error: errorMessage });
|
|
744
|
+
return { success: false, error: errorMessage };
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
748
|
+
// IDLE TIMER
|
|
749
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
750
|
+
function startIdleTimer() {
|
|
751
|
+
if (idleTimer) {
|
|
752
|
+
clearTimeout(idleTimer);
|
|
753
|
+
}
|
|
754
|
+
if (idleTimeout <= 0)
|
|
755
|
+
return;
|
|
756
|
+
idleTimer = setTimeout(() => {
|
|
757
|
+
let activeSubscribers = 0;
|
|
758
|
+
for (const subs of channelSubscriptions.values()) {
|
|
759
|
+
activeSubscribers += subs.size;
|
|
760
|
+
}
|
|
761
|
+
if (activeSubscribers > 0) {
|
|
762
|
+
logger.debug('Active channel subscribers, staying alive', { activeSubscribers });
|
|
763
|
+
startIdleTimer();
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
// Check if any session manager has recent activity
|
|
767
|
+
let lastActivity = 0;
|
|
768
|
+
for (const manager of sessionManagers.values()) {
|
|
769
|
+
const activity = manager.getLastActivity();
|
|
770
|
+
if (activity > lastActivity) {
|
|
771
|
+
lastActivity = activity;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
const idleTime = Date.now() - lastActivity;
|
|
775
|
+
if (idleTime >= idleTimeout && sessionManagers.size > 0) {
|
|
776
|
+
logger.warn('Idle timeout reached, shutting down', { idleTime });
|
|
777
|
+
shutdown();
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
startIdleTimer();
|
|
781
|
+
}
|
|
782
|
+
}, idleTimeout);
|
|
783
|
+
}
|
|
784
|
+
function resetIdleTimer() {
|
|
785
|
+
startIdleTimer();
|
|
786
|
+
}
|
|
787
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
788
|
+
// SERVER
|
|
789
|
+
// ════════════════════════════════════════════════════════════════════════════════
|
|
189
790
|
function startServer() {
|
|
190
791
|
const server = net.createServer((socket) => {
|
|
191
|
-
|
|
792
|
+
logger.info('Client connected');
|
|
192
793
|
let buffer = '';
|
|
193
794
|
socket.on('data', async (chunk) => {
|
|
194
795
|
buffer += chunk.toString();
|
|
195
|
-
// Process complete JSON messages (newline-delimited)
|
|
196
796
|
const lines = buffer.split('\n');
|
|
197
|
-
buffer = lines.pop() || '';
|
|
797
|
+
buffer = lines.pop() || '';
|
|
198
798
|
for (const line of lines) {
|
|
199
799
|
if (!line.trim())
|
|
200
800
|
continue;
|
|
201
801
|
try {
|
|
202
|
-
const
|
|
802
|
+
const parsed = JSON.parse(line);
|
|
803
|
+
if (!isValidDaemonRequest(parsed)) {
|
|
804
|
+
socket.write(JSON.stringify({ type: 'error', id: 'unknown', error: 'Invalid request format' }) +
|
|
805
|
+
'\n');
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
const request = parsed;
|
|
203
809
|
const response = await handleRequest(request, socket);
|
|
204
|
-
// Only send response if handler returned one (null for prompt_response)
|
|
205
810
|
if (response !== null) {
|
|
206
811
|
socket.write(JSON.stringify(response) + '\n');
|
|
207
812
|
}
|
|
208
813
|
}
|
|
209
814
|
catch (error) {
|
|
210
|
-
|
|
211
|
-
socket.write(JSON.stringify({
|
|
212
|
-
type: 'error',
|
|
213
|
-
id: 'unknown',
|
|
214
|
-
error: error.message,
|
|
215
|
-
}) + '\n');
|
|
815
|
+
logger.error('Error processing request', { error: getErrorMessage(error) });
|
|
816
|
+
socket.write(JSON.stringify({ type: 'error', id: 'unknown', error: getErrorMessage(error) }) + '\n');
|
|
216
817
|
}
|
|
217
818
|
}
|
|
218
819
|
});
|
|
219
820
|
socket.on('end', () => {
|
|
220
|
-
|
|
821
|
+
logger.info('Client disconnected');
|
|
822
|
+
cleanupSocketSubscriptions(socket);
|
|
221
823
|
});
|
|
222
824
|
socket.on('error', (error) => {
|
|
223
|
-
|
|
825
|
+
logger.warn('Socket error', { error: getErrorMessage(error) });
|
|
826
|
+
cleanupSocketSubscriptions(socket);
|
|
827
|
+
});
|
|
828
|
+
socket.on('close', () => {
|
|
829
|
+
cleanupSocketSubscriptions(socket);
|
|
224
830
|
});
|
|
225
831
|
});
|
|
226
832
|
server.listen(socketPath, () => {
|
|
227
|
-
|
|
228
|
-
console.error(`[daemon-server] PID: ${process.pid}`);
|
|
833
|
+
logger.info('Global Photon daemon listening', { socketPath, pid: process.pid });
|
|
229
834
|
});
|
|
230
835
|
server.on('error', (error) => {
|
|
231
|
-
|
|
836
|
+
logger.error('Server error', { error: getErrorMessage(error) });
|
|
232
837
|
process.exit(1);
|
|
233
838
|
});
|
|
234
|
-
// Graceful shutdown handlers
|
|
235
839
|
process.on('SIGTERM', shutdown);
|
|
236
840
|
process.on('SIGINT', shutdown);
|
|
237
841
|
}
|
|
238
|
-
/**
|
|
239
|
-
* Shutdown daemon
|
|
240
|
-
*/
|
|
241
842
|
function shutdown() {
|
|
242
|
-
|
|
843
|
+
logger.info('Shutting down global daemon');
|
|
243
844
|
if (idleTimer) {
|
|
244
845
|
clearTimeout(idleTimer);
|
|
245
846
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
847
|
+
for (const timer of jobTimers.values()) {
|
|
848
|
+
clearTimeout(timer);
|
|
849
|
+
}
|
|
850
|
+
jobTimers.clear();
|
|
851
|
+
scheduledJobs.clear();
|
|
852
|
+
activeLocks.clear();
|
|
853
|
+
for (const manager of sessionManagers.values()) {
|
|
854
|
+
manager.destroy();
|
|
855
|
+
}
|
|
856
|
+
sessionManagers.clear();
|
|
857
|
+
if (webhookServer) {
|
|
858
|
+
webhookServer.close();
|
|
249
859
|
}
|
|
250
|
-
// Clean up socket file (Unix only)
|
|
251
860
|
if (fs.existsSync(socketPath) && process.platform !== 'win32') {
|
|
252
861
|
try {
|
|
253
862
|
fs.unlinkSync(socketPath);
|
|
254
863
|
}
|
|
255
|
-
catch
|
|
864
|
+
catch {
|
|
256
865
|
// Ignore cleanup errors
|
|
257
866
|
}
|
|
258
867
|
}
|
|
259
868
|
process.exit(0);
|
|
260
869
|
}
|
|
261
870
|
// Main execution
|
|
262
|
-
(
|
|
263
|
-
await initializeSessionManager();
|
|
871
|
+
(() => {
|
|
264
872
|
startServer();
|
|
873
|
+
startWebhookServer(WEBHOOK_PORT);
|
|
874
|
+
startIdleTimer();
|
|
265
875
|
})();
|
|
266
876
|
//# sourceMappingURL=server.js.map
|