@decibelsystems/tools 2.2.0-beta.0 → 3.1.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/CHANGELOG.md +226 -0
- package/dist/agentCommands.d.ts +0 -1
- package/dist/agentCommands.d.ts.map +1 -1
- package/dist/agentCommands.js +19 -8
- package/dist/agentCommands.js.map +1 -1
- package/dist/agentPresence.d.ts +82 -0
- package/dist/agentPresence.d.ts.map +1 -1
- package/dist/agentPresence.js +194 -26
- package/dist/agentPresence.js.map +1 -1
- package/dist/agentic/index.d.ts +18 -8
- package/dist/agentic/index.d.ts.map +1 -1
- package/dist/agentic/index.js +18 -144
- package/dist/agentic/index.js.map +1 -1
- package/dist/agentic/types.d.ts +106 -0
- package/dist/agentic/types.d.ts.map +1 -1
- package/dist/agentic/types.js +77 -1
- package/dist/agentic/types.js.map +1 -1
- package/dist/architectAdrs.d.ts +27 -3
- package/dist/architectAdrs.d.ts.map +1 -1
- package/dist/architectAdrs.js +92 -4
- package/dist/architectAdrs.js.map +1 -1
- package/dist/artifacts.d.ts +60 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +208 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/asks.d.ts +93 -0
- package/dist/asks.d.ts.map +1 -0
- package/dist/asks.js +383 -0
- package/dist/asks.js.map +1 -0
- package/dist/chat.d.ts +47 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +288 -0
- package/dist/chat.js.map +1 -0
- package/dist/client/transports.d.ts.map +1 -1
- package/dist/client/transports.js +13 -3
- package/dist/client/transports.js.map +1 -1
- package/dist/daemon.d.ts +33 -3
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +225 -52
- package/dist/daemon.js.map +1 -1
- package/dist/daemonConfig.d.ts +46 -0
- package/dist/daemonConfig.d.ts.map +1 -1
- package/dist/daemonConfig.js +57 -12
- package/dist/daemonConfig.js.map +1 -1
- package/dist/decibelPaths.d.ts.map +1 -1
- package/dist/decibelPaths.js +39 -6
- package/dist/decibelPaths.js.map +1 -1
- package/dist/domain/issue.d.ts +81 -0
- package/dist/domain/issue.d.ts.map +1 -0
- package/dist/domain/issue.js +106 -0
- package/dist/domain/issue.js.map +1 -0
- package/dist/domain/issueCodec.d.ts +39 -0
- package/dist/domain/issueCodec.d.ts.map +1 -0
- package/dist/domain/issueCodec.js +308 -0
- package/dist/domain/issueCodec.js.map +1 -0
- package/dist/domain/issueRepository.d.ts +124 -0
- package/dist/domain/issueRepository.d.ts.map +1 -0
- package/dist/domain/issueRepository.js +296 -0
- package/dist/domain/issueRepository.js.map +1 -0
- package/dist/domain/uid.d.ts +16 -0
- package/dist/domain/uid.d.ts.map +1 -0
- package/dist/domain/uid.js +43 -0
- package/dist/domain/uid.js.map +1 -0
- package/dist/facades/definitions.d.ts +0 -1
- package/dist/facades/definitions.d.ts.map +1 -1
- package/dist/facades/definitions.js +140 -116
- package/dist/facades/definitions.js.map +1 -1
- package/dist/facades/index.d.ts +2 -1
- package/dist/facades/index.d.ts.map +1 -1
- package/dist/facades/index.js +1 -1
- package/dist/facades/index.js.map +1 -1
- package/dist/facades/types.d.ts +17 -0
- package/dist/facades/types.d.ts.map +1 -1
- package/dist/hq/defineAgent.d.ts.map +1 -1
- package/dist/hq/defineAgent.js +7 -11
- package/dist/hq/defineAgent.js.map +1 -1
- package/dist/httpArgs.d.ts +11 -0
- package/dist/httpArgs.d.ts.map +1 -0
- package/dist/httpArgs.js +39 -0
- package/dist/httpArgs.js.map +1 -0
- package/dist/httpServer.d.ts +1 -12
- package/dist/httpServer.d.ts.map +1 -1
- package/dist/httpServer.js +298 -144
- package/dist/httpServer.js.map +1 -1
- package/dist/identity.d.ts +123 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +312 -0
- package/dist/identity.js.map +1 -0
- package/dist/kernel.d.ts +46 -1
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +334 -26
- package/dist/kernel.js.map +1 -1
- package/dist/killSwitch.d.ts +117 -0
- package/dist/killSwitch.d.ts.map +1 -0
- package/dist/killSwitch.js +161 -0
- package/dist/killSwitch.js.map +1 -0
- package/dist/lib/agent-services/assumptions.d.ts.map +1 -1
- package/dist/lib/agent-services/assumptions.js +8 -2
- package/dist/lib/agent-services/assumptions.js.map +1 -1
- package/dist/lib/atomicWrite.d.ts +49 -0
- package/dist/lib/atomicWrite.d.ts.map +1 -0
- package/dist/lib/atomicWrite.js +157 -0
- package/dist/lib/atomicWrite.js.map +1 -0
- package/dist/lib/envelope.d.ts +31 -0
- package/dist/lib/envelope.d.ts.map +1 -0
- package/dist/lib/envelope.js +80 -0
- package/dist/lib/envelope.js.map +1 -0
- package/dist/lib/fileLock.d.ts +38 -0
- package/dist/lib/fileLock.d.ts.map +1 -0
- package/dist/lib/fileLock.js +124 -0
- package/dist/lib/fileLock.js.map +1 -0
- package/dist/lib/recordIdAllocator.d.ts +102 -0
- package/dist/lib/recordIdAllocator.d.ts.map +1 -0
- package/dist/lib/recordIdAllocator.js +179 -0
- package/dist/lib/recordIdAllocator.js.map +1 -0
- package/dist/orgId.d.ts +23 -0
- package/dist/orgId.d.ts.map +1 -0
- package/dist/orgId.js +73 -0
- package/dist/orgId.js.map +1 -0
- package/dist/pairCli.d.ts +2 -0
- package/dist/pairCli.d.ts.map +1 -0
- package/dist/pairCli.js +97 -0
- package/dist/pairCli.js.map +1 -0
- package/dist/peerBroker.d.ts +40 -0
- package/dist/peerBroker.d.ts.map +1 -0
- package/dist/peerBroker.js +70 -0
- package/dist/peerBroker.js.map +1 -0
- package/dist/peerBrokerSupervisor.d.ts +21 -0
- package/dist/peerBrokerSupervisor.d.ts.map +1 -0
- package/dist/peerBrokerSupervisor.js +131 -0
- package/dist/peerBrokerSupervisor.js.map +1 -0
- package/dist/projectPaths.d.ts.map +1 -1
- package/dist/projectPaths.js +1 -19
- package/dist/projectPaths.js.map +1 -1
- package/dist/projectRegistry.d.ts +22 -0
- package/dist/projectRegistry.d.ts.map +1 -1
- package/dist/projectRegistry.js +69 -2
- package/dist/projectRegistry.js.map +1 -1
- package/dist/pty/boundary.d.ts +39 -0
- package/dist/pty/boundary.d.ts.map +1 -0
- package/dist/pty/boundary.js +100 -0
- package/dist/pty/boundary.js.map +1 -0
- package/dist/pty/errors.d.ts +6 -0
- package/dist/pty/errors.d.ts.map +1 -0
- package/dist/pty/errors.js +12 -0
- package/dist/pty/errors.js.map +1 -0
- package/dist/pty/fleet.d.ts +159 -0
- package/dist/pty/fleet.d.ts.map +1 -0
- package/dist/pty/fleet.js +543 -0
- package/dist/pty/fleet.js.map +1 -0
- package/dist/pty/launchProfile.d.ts +45 -0
- package/dist/pty/launchProfile.d.ts.map +1 -0
- package/dist/pty/launchProfile.js +149 -0
- package/dist/pty/launchProfile.js.map +1 -0
- package/dist/pty/openTerminal.d.ts +48 -0
- package/dist/pty/openTerminal.d.ts.map +1 -0
- package/dist/pty/openTerminal.js +185 -0
- package/dist/pty/openTerminal.js.map +1 -0
- package/dist/pty/pairDialog.d.ts +16 -0
- package/dist/pty/pairDialog.d.ts.map +1 -0
- package/dist/pty/pairDialog.js +121 -0
- package/dist/pty/pairDialog.js.map +1 -0
- package/dist/pty/pairing.d.ts +86 -0
- package/dist/pty/pairing.d.ts.map +1 -0
- package/dist/pty/pairing.js +351 -0
- package/dist/pty/pairing.js.map +1 -0
- package/dist/pty/routes.d.ts +49 -0
- package/dist/pty/routes.d.ts.map +1 -0
- package/dist/pty/routes.js +624 -0
- package/dist/pty/routes.js.map +1 -0
- package/dist/pty/sessions.d.ts +167 -0
- package/dist/pty/sessions.d.ts.map +1 -0
- package/dist/pty/sessions.js +513 -0
- package/dist/pty/sessions.js.map +1 -0
- package/dist/pty/tmux.d.ts +109 -0
- package/dist/pty/tmux.d.ts.map +1 -0
- package/dist/pty/tmux.js +271 -0
- package/dist/pty/tmux.js.map +1 -0
- package/dist/roster.d.ts +37 -0
- package/dist/roster.d.ts.map +1 -0
- package/dist/roster.js +126 -0
- package/dist/roster.js.map +1 -0
- package/dist/runtime/circuitBreaker.d.ts +95 -0
- package/dist/runtime/circuitBreaker.d.ts.map +1 -0
- package/dist/runtime/circuitBreaker.js +178 -0
- package/dist/runtime/circuitBreaker.js.map +1 -0
- package/dist/runtime/daemonMeta.d.ts +53 -0
- package/dist/runtime/daemonMeta.d.ts.map +1 -0
- package/dist/runtime/daemonMeta.js +121 -0
- package/dist/runtime/daemonMeta.js.map +1 -0
- package/dist/runtime/ensureRuntime.d.ts +103 -0
- package/dist/runtime/ensureRuntime.d.ts.map +1 -0
- package/dist/runtime/ensureRuntime.js +276 -0
- package/dist/runtime/ensureRuntime.js.map +1 -0
- package/dist/runtime/extensions.d.ts +57 -0
- package/dist/runtime/extensions.d.ts.map +1 -0
- package/dist/runtime/extensions.js +216 -0
- package/dist/runtime/extensions.js.map +1 -0
- package/dist/runtime/localHttp.d.ts +24 -0
- package/dist/runtime/localHttp.d.ts.map +1 -0
- package/dist/runtime/localHttp.js +84 -0
- package/dist/runtime/localHttp.js.map +1 -0
- package/dist/runtime/projectResolution.d.ts +29 -0
- package/dist/runtime/projectResolution.d.ts.map +1 -0
- package/dist/runtime/projectResolution.js +67 -0
- package/dist/runtime/projectResolution.js.map +1 -0
- package/dist/runtime/protocol.d.ts +62 -0
- package/dist/runtime/protocol.d.ts.map +1 -0
- package/dist/runtime/protocol.js +74 -0
- package/dist/runtime/protocol.js.map +1 -0
- package/dist/sentinelIssues.d.ts +42 -2
- package/dist/sentinelIssues.d.ts.map +1 -1
- package/dist/sentinelIssues.js +167 -65
- package/dist/sentinelIssues.js.map +1 -1
- package/dist/server.js +123 -15
- package/dist/server.js.map +1 -1
- package/dist/toolConfig.d.ts.map +1 -1
- package/dist/toolConfig.js +12 -0
- package/dist/toolConfig.js.map +1 -1
- package/dist/tools/agentic/agentQueue.d.ts.map +1 -1
- package/dist/tools/agentic/agentQueue.js +4 -0
- package/dist/tools/agentic/agentQueue.js.map +1 -1
- package/dist/tools/agentic/index.d.ts.map +1 -1
- package/dist/tools/agentic/index.js +28 -2
- package/dist/tools/agentic/index.js.map +1 -1
- package/dist/tools/architect/index.d.ts +1 -0
- package/dist/tools/architect/index.d.ts.map +1 -1
- package/dist/tools/architect/index.js +52 -3
- package/dist/tools/architect/index.js.map +1 -1
- package/dist/tools/architect.d.ts.map +1 -1
- package/dist/tools/architect.js +59 -8
- package/dist/tools/architect.js.map +1 -1
- package/dist/tools/artifacts.d.ts +5 -0
- package/dist/tools/artifacts.d.ts.map +1 -0
- package/dist/tools/artifacts.js +89 -0
- package/dist/tools/artifacts.js.map +1 -0
- package/dist/tools/asks.d.ts +6 -0
- package/dist/tools/asks.d.ts.map +1 -0
- package/dist/tools/asks.js +104 -0
- package/dist/tools/asks.js.map +1 -0
- package/dist/tools/context.d.ts +10 -5
- package/dist/tools/context.d.ts.map +1 -1
- package/dist/tools/context.js +45 -18
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/coordinator/coordinator.d.ts.map +1 -1
- package/dist/tools/coordinator/coordinator.js +48 -19
- package/dist/tools/coordinator/coordinator.js.map +1 -1
- package/dist/tools/coordinator/index.d.ts +1 -0
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +42 -2
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/tools/crit.d.ts +2 -1
- package/dist/tools/crit.d.ts.map +1 -1
- package/dist/tools/crit.js +19 -4
- package/dist/tools/crit.js.map +1 -1
- package/dist/tools/data-inspector.d.ts +1 -1
- package/dist/tools/data-inspector.d.ts.map +1 -1
- package/dist/tools/data-inspector.js +1 -1
- package/dist/tools/data-inspector.js.map +1 -1
- package/dist/tools/designer/index.d.ts.map +1 -1
- package/dist/tools/designer/index.js +4 -3
- package/dist/tools/designer/index.js.map +1 -1
- package/dist/tools/designer/lateral-tools.d.ts.map +1 -1
- package/dist/tools/designer/lateral-tools.js +4 -2
- package/dist/tools/designer/lateral-tools.js.map +1 -1
- package/dist/tools/designer.d.ts +2 -1
- package/dist/tools/designer.d.ts.map +1 -1
- package/dist/tools/designer.js +24 -12
- package/dist/tools/designer.js.map +1 -1
- package/dist/tools/dojo/index.d.ts.map +1 -1
- package/dist/tools/dojo/index.js +52 -3
- package/dist/tools/dojo/index.js.map +1 -1
- package/dist/tools/dojo.d.ts +65 -3
- package/dist/tools/dojo.d.ts.map +1 -1
- package/dist/tools/dojo.js +148 -23
- package/dist/tools/dojo.js.map +1 -1
- package/dist/tools/friction.d.ts.map +1 -1
- package/dist/tools/friction.js +16 -6
- package/dist/tools/friction.js.map +1 -1
- package/dist/tools/guardian.d.ts +7 -0
- package/dist/tools/guardian.d.ts.map +1 -1
- package/dist/tools/guardian.js +152 -11
- package/dist/tools/guardian.js.map +1 -1
- package/dist/tools/hygiene/oracle-hygiene.d.ts.map +1 -1
- package/dist/tools/hygiene/oracle-hygiene.js +8 -2
- package/dist/tools/hygiene/oracle-hygiene.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +33 -18
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/killswitch/index.d.ts +13 -0
- package/dist/tools/killswitch/index.d.ts.map +1 -0
- package/dist/tools/killswitch/index.js +138 -0
- package/dist/tools/killswitch/index.js.map +1 -0
- package/dist/tools/learnings.d.ts +2 -1
- package/dist/tools/learnings.d.ts.map +1 -1
- package/dist/tools/learnings.js +31 -15
- package/dist/tools/learnings.js.map +1 -1
- package/dist/tools/oracle/index.d.ts.map +1 -1
- package/dist/tools/oracle/index.js +8 -0
- package/dist/tools/oracle/index.js.map +1 -1
- package/dist/tools/oracle.d.ts +7 -0
- package/dist/tools/oracle.d.ts.map +1 -1
- package/dist/tools/oracle.js +41 -12
- package/dist/tools/oracle.js.map +1 -1
- package/dist/tools/policy.d.ts +2 -1
- package/dist/tools/policy.d.ts.map +1 -1
- package/dist/tools/policy.js +28 -9
- package/dist/tools/policy.js.map +1 -1
- package/dist/tools/postoffice/index.d.ts +10 -0
- package/dist/tools/postoffice/index.d.ts.map +1 -0
- package/dist/tools/postoffice/index.js +218 -0
- package/dist/tools/postoffice/index.js.map +1 -0
- package/dist/tools/postoffice.d.ts +78 -0
- package/dist/tools/postoffice.d.ts.map +1 -0
- package/dist/tools/postoffice.js +199 -0
- package/dist/tools/postoffice.js.map +1 -0
- package/dist/tools/provenance.d.ts +18 -2
- package/dist/tools/provenance.d.ts.map +1 -1
- package/dist/tools/provenance.js +68 -40
- package/dist/tools/provenance.js.map +1 -1
- package/dist/tools/registry/index.d.ts.map +1 -1
- package/dist/tools/registry/index.js +24 -0
- package/dist/tools/registry/index.js.map +1 -1
- package/dist/tools/sentinel/index.d.ts +1 -0
- package/dist/tools/sentinel/index.d.ts.map +1 -1
- package/dist/tools/sentinel/index.js +142 -6
- package/dist/tools/sentinel/index.js.map +1 -1
- package/dist/tools/sentinel.d.ts +152 -1
- package/dist/tools/sentinel.d.ts.map +1 -1
- package/dist/tools/sentinel.js +609 -328
- package/dist/tools/sentinel.js.map +1 -1
- package/dist/tools/shared/index.d.ts +2 -1
- package/dist/tools/shared/index.d.ts.map +1 -1
- package/dist/tools/shared/index.js +2 -1
- package/dist/tools/shared/index.js.map +1 -1
- package/dist/tools/shared/response.d.ts +24 -0
- package/dist/tools/shared/response.d.ts.map +1 -1
- package/dist/tools/shared/response.js +61 -7
- package/dist/tools/shared/response.js.map +1 -1
- package/dist/tools/shared/runTracker.d.ts +2 -0
- package/dist/tools/shared/runTracker.d.ts.map +1 -1
- package/dist/tools/shared/runTracker.js +38 -0
- package/dist/tools/shared/runTracker.js.map +1 -1
- package/dist/tools/shared/storeRead.d.ts +153 -0
- package/dist/tools/shared/storeRead.d.ts.map +1 -0
- package/dist/tools/shared/storeRead.js +242 -0
- package/dist/tools/shared/storeRead.js.map +1 -0
- package/dist/tools/swarm.d.ts +3 -1
- package/dist/tools/swarm.d.ts.map +1 -1
- package/dist/tools/swarm.js +6 -12
- package/dist/tools/swarm.js.map +1 -1
- package/dist/tools/testSpec.d.ts +3 -2
- package/dist/tools/testSpec.d.ts.map +1 -1
- package/dist/tools/testSpec.js +51 -14
- package/dist/tools/testSpec.js.map +1 -1
- package/dist/tools/vector.d.ts +33 -1
- package/dist/tools/vector.d.ts.map +1 -1
- package/dist/tools/vector.js +31 -5
- package/dist/tools/vector.js.map +1 -1
- package/dist/tools/voice/index.d.ts +1 -0
- package/dist/tools/voice/index.d.ts.map +1 -1
- package/dist/tools/voice/index.js +33 -2
- package/dist/tools/voice/index.js.map +1 -1
- package/dist/tools/voice.d.ts +48 -1
- package/dist/tools/voice.d.ts.map +1 -1
- package/dist/tools/voice.js +63 -3
- package/dist/tools/voice.js.map +1 -1
- package/dist/tools/zoom/index.d.ts +15 -0
- package/dist/tools/zoom/index.d.ts.map +1 -0
- package/dist/tools/zoom/index.js +174 -0
- package/dist/tools/zoom/index.js.map +1 -0
- package/dist/tools/zoom.d.ts +234 -0
- package/dist/tools/zoom.d.ts.map +1 -0
- package/dist/tools/zoom.js +627 -0
- package/dist/tools/zoom.js.map +1 -0
- package/dist/transports/bridge.d.ts +1 -1
- package/dist/transports/bridge.d.ts.map +1 -1
- package/dist/transports/bridge.js +4 -1
- package/dist/transports/bridge.js.map +1 -1
- package/dist/transports/http.d.ts +1 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +3 -1
- package/dist/transports/http.js.map +1 -1
- package/dist/transports/index.d.ts +1 -0
- package/dist/transports/index.d.ts.map +1 -1
- package/dist/transports/index.js +1 -0
- package/dist/transports/index.js.map +1 -1
- package/dist/transports/mcp.d.ts +1 -1
- package/dist/transports/mcp.d.ts.map +1 -1
- package/dist/transports/mcp.js +9 -4
- package/dist/transports/mcp.js.map +1 -1
- package/dist/transports/stdio.d.ts +1 -1
- package/dist/transports/stdio.d.ts.map +1 -1
- package/dist/transports/stdio.js +2 -0
- package/dist/transports/stdio.js.map +1 -1
- package/dist/transports/thinStdio.d.ts +22 -0
- package/dist/transports/thinStdio.d.ts.map +1 -0
- package/dist/transports/thinStdio.js +218 -0
- package/dist/transports/thinStdio.js.map +1 -0
- package/dist/transports/types.d.ts +8 -1
- package/dist/transports/types.d.ts.map +1 -1
- package/dist/types/agent-services.d.ts +7 -0
- package/dist/types/agent-services.d.ts.map +1 -1
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +23 -0
- package/dist/version.js.map +1 -0
- package/package.json +20 -4
- package/templates/AGENT.md +3 -0
- package/templates/CLAUDE-decibel.md +11 -0
- package/templates/com.decibel.daemon.plist +6 -1
- package/dist/tools/deck.d.ts +0 -11
- package/dist/tools/deck.d.ts.map +0 -1
- package/dist/tools/deck.js +0 -1656
- package/dist/tools/deck.js.map +0 -1
- package/dist/tools/mother.d.ts +0 -11
- package/dist/tools/mother.d.ts.map +0 -1
- package/dist/tools/mother.js +0 -503
- package/dist/tools/mother.js.map +0 -1
- package/dist/tools/registry.d.ts +0 -3
- package/dist/tools/registry.d.ts.map +0 -1
- package/dist/tools/registry.js +0 -189
- package/dist/tools/registry.js.map +0 -1
- package/dist/tools/senken.d.ts +0 -11
- package/dist/tools/senken.d.ts.map +0 -1
- package/dist/tools/senken.js +0 -482
- package/dist/tools/senken.js.map +0 -1
- package/dist/tools/terminal.d.ts +0 -17
- package/dist/tools/terminal.d.ts.map +0 -1
- package/dist/tools/terminal.js +0 -968
- package/dist/tools/terminal.js.map +0 -1
- package/dist/tools/toolsIndex.d.ts +0 -5
- package/dist/tools/toolsIndex.d.ts.map +0 -1
- package/dist/tools/toolsIndex.js +0 -37
- package/dist/tools/toolsIndex.js.map +0 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-facade circuit breaker.
|
|
3
|
+
*
|
|
4
|
+
* The failure this exists for: one facade's dependency wedges — Mother's
|
|
5
|
+
* Postgres stops accepting connections, Supabase hangs, a disk mount goes
|
|
6
|
+
* away — and every call into that facade sits on a socket until it times out.
|
|
7
|
+
* With six clients sharing one runtime that is enough to make the whole
|
|
8
|
+
* runtime feel dead, even though twenty other facades are fine. The breaker
|
|
9
|
+
* turns a slow, repeated failure into a fast, local one.
|
|
10
|
+
*
|
|
11
|
+
* WHAT COUNTS AS A FAULT is the whole design, because Decibel's tools rarely
|
|
12
|
+
* throw. `senken_trade_summary` catches its own Postgres error and returns
|
|
13
|
+
* `{isError: true}` (src/tools/senken.ts:117), so a breaker that only counted
|
|
14
|
+
* exceptions would never trip on the exact case it was built for. But counting
|
|
15
|
+
* every `isError` is worse: `create_issue` missing a title is an `isError`
|
|
16
|
+
* too, and five bad calls in a row from one confused agent must not take the
|
|
17
|
+
* sentinel facade offline for everyone.
|
|
18
|
+
*
|
|
19
|
+
* So the signal is *unresponsiveness*, not *unhappiness*:
|
|
20
|
+
*
|
|
21
|
+
* - a thrown exception is always a fault (the handler didn't handle it)
|
|
22
|
+
* - an `isError` result that took longer than `slowFailureMs` is a fault
|
|
23
|
+
* (a dependency that times out is slow; a rejected argument is not)
|
|
24
|
+
* - an `isError` result that came back fast is neither fault nor proof of
|
|
25
|
+
* health — it leaves the counters exactly where they were
|
|
26
|
+
* - a success closes the circuit and clears the count
|
|
27
|
+
*
|
|
28
|
+
* State machine: closed → (threshold consecutive faults) → open → (cooldown
|
|
29
|
+
* elapses) → half-open → success closes it, fault re-opens it. Half-open
|
|
30
|
+
* admits exactly one probe; concurrent callers are rejected until it lands, so
|
|
31
|
+
* a recovering database gets one connection attempt rather than six.
|
|
32
|
+
*
|
|
33
|
+
* The breaker never converts a working call into a failure — it only refuses
|
|
34
|
+
* calls it has good reason to believe would fail slowly.
|
|
35
|
+
*/
|
|
36
|
+
const DEFAULTS = {
|
|
37
|
+
failureThreshold: 5,
|
|
38
|
+
cooldownMs: 30_000,
|
|
39
|
+
slowFailureMs: 2_000,
|
|
40
|
+
};
|
|
41
|
+
export class CircuitBreakerRegistry {
|
|
42
|
+
circuits = new Map();
|
|
43
|
+
failureThreshold;
|
|
44
|
+
cooldownMs;
|
|
45
|
+
slowFailureMs;
|
|
46
|
+
now;
|
|
47
|
+
constructor(opts = {}) {
|
|
48
|
+
this.failureThreshold = opts.failureThreshold ?? DEFAULTS.failureThreshold;
|
|
49
|
+
this.cooldownMs = opts.cooldownMs ?? DEFAULTS.cooldownMs;
|
|
50
|
+
this.slowFailureMs = opts.slowFailureMs ?? DEFAULTS.slowFailureMs;
|
|
51
|
+
this.now = opts.now ?? Date.now;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Ask whether a call to `key` may proceed. Transitions open → half_open when
|
|
55
|
+
* the cooldown has elapsed, and reserves the half-open probe for the caller
|
|
56
|
+
* it says yes to.
|
|
57
|
+
*/
|
|
58
|
+
beforeCall(key) {
|
|
59
|
+
const c = this.circuits.get(key);
|
|
60
|
+
if (!c || c.state === 'closed')
|
|
61
|
+
return { allowed: true };
|
|
62
|
+
if (c.state === 'open') {
|
|
63
|
+
const elapsed = this.now() - c.openedAt;
|
|
64
|
+
if (elapsed < this.cooldownMs) {
|
|
65
|
+
return {
|
|
66
|
+
allowed: false,
|
|
67
|
+
retryAfterMs: this.cooldownMs - elapsed,
|
|
68
|
+
lastError: c.lastError,
|
|
69
|
+
openedAt: new Date(c.openedAt).toISOString(),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// Cooldown elapsed — this caller becomes the probe.
|
|
73
|
+
c.state = 'half_open';
|
|
74
|
+
c.probeInFlight = true;
|
|
75
|
+
return { allowed: true };
|
|
76
|
+
}
|
|
77
|
+
// half_open: one probe at a time.
|
|
78
|
+
if (c.probeInFlight) {
|
|
79
|
+
return {
|
|
80
|
+
allowed: false,
|
|
81
|
+
retryAfterMs: this.cooldownMs,
|
|
82
|
+
lastError: c.lastError,
|
|
83
|
+
openedAt: new Date(c.openedAt).toISOString(),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
c.probeInFlight = true;
|
|
87
|
+
return { allowed: true };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Report what happened. `threw` and `durationMs` decide whether this was a
|
|
91
|
+
* fault; see the module comment for why `isError` alone is not enough and
|
|
92
|
+
* not too much.
|
|
93
|
+
*/
|
|
94
|
+
afterCall(key, outcome) {
|
|
95
|
+
const fault = outcome.threw || (outcome.isError && outcome.durationMs >= this.slowFailureMs);
|
|
96
|
+
if (fault) {
|
|
97
|
+
this.recordFault(key, outcome.error);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (outcome.isError) {
|
|
101
|
+
// Fast domain error: says nothing about the dependency's health. Release
|
|
102
|
+
// the probe if we were half-open, but leave the fault count alone.
|
|
103
|
+
const c = this.circuits.get(key);
|
|
104
|
+
if (c?.state === 'half_open')
|
|
105
|
+
this.close(key);
|
|
106
|
+
else if (c)
|
|
107
|
+
c.probeInFlight = false;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.recordSuccess(key);
|
|
111
|
+
}
|
|
112
|
+
recordSuccess(key) {
|
|
113
|
+
const c = this.circuits.get(key);
|
|
114
|
+
if (!c)
|
|
115
|
+
return;
|
|
116
|
+
this.close(key);
|
|
117
|
+
}
|
|
118
|
+
recordFault(key, error) {
|
|
119
|
+
const c = this.circuits.get(key) ?? {
|
|
120
|
+
state: 'closed',
|
|
121
|
+
faults: 0,
|
|
122
|
+
openedAt: 0,
|
|
123
|
+
probeInFlight: false,
|
|
124
|
+
};
|
|
125
|
+
c.lastError = error;
|
|
126
|
+
c.probeInFlight = false;
|
|
127
|
+
if (c.state === 'half_open') {
|
|
128
|
+
// The probe failed — straight back to open, full cooldown.
|
|
129
|
+
c.state = 'open';
|
|
130
|
+
c.openedAt = this.now();
|
|
131
|
+
this.circuits.set(key, c);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
c.faults += 1;
|
|
135
|
+
if (c.faults >= this.failureThreshold) {
|
|
136
|
+
c.state = 'open';
|
|
137
|
+
c.openedAt = this.now();
|
|
138
|
+
}
|
|
139
|
+
this.circuits.set(key, c);
|
|
140
|
+
}
|
|
141
|
+
state(key) {
|
|
142
|
+
return this.circuits.get(key)?.state ?? 'closed';
|
|
143
|
+
}
|
|
144
|
+
/** Open circuits only — a healthy runtime reports `{}`. */
|
|
145
|
+
snapshot() {
|
|
146
|
+
const out = {};
|
|
147
|
+
for (const [key, c] of this.circuits) {
|
|
148
|
+
if (c.state === 'closed' && c.faults === 0)
|
|
149
|
+
continue;
|
|
150
|
+
out[key] = {
|
|
151
|
+
state: c.state,
|
|
152
|
+
consecutive_faults: c.faults,
|
|
153
|
+
...(c.state === 'closed' ? {} : {
|
|
154
|
+
opened_at: new Date(c.openedAt).toISOString(),
|
|
155
|
+
retry_after_ms: Math.max(0, this.cooldownMs - (this.now() - c.openedAt)),
|
|
156
|
+
}),
|
|
157
|
+
...(c.lastError ? { last_error: c.lastError } : {}),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
reset(key) {
|
|
163
|
+
if (key === undefined)
|
|
164
|
+
this.circuits.clear();
|
|
165
|
+
else
|
|
166
|
+
this.circuits.delete(key);
|
|
167
|
+
}
|
|
168
|
+
close(key) {
|
|
169
|
+
const c = this.circuits.get(key);
|
|
170
|
+
if (!c)
|
|
171
|
+
return;
|
|
172
|
+
c.state = 'closed';
|
|
173
|
+
c.faults = 0;
|
|
174
|
+
c.probeInFlight = false;
|
|
175
|
+
c.openedAt = 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=circuitBreaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuitBreaker.js","sourceRoot":"","sources":["../../src/runtime/circuitBreaker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolved per call rather than captured at import, the way daemonConfig does:
|
|
3
|
+
* os.homedir() tracks $HOME, and a module-level constant freezes whatever it
|
|
4
|
+
* was when the file was first loaded — which makes this unverifiable in a test
|
|
5
|
+
* and wrong in any process that changes HOME.
|
|
6
|
+
*/
|
|
7
|
+
export declare function decibelHome(): string;
|
|
8
|
+
/**
|
|
9
|
+
* DECIBEL_DAEMON_SIDECAR=<dir> marks a second daemon run beside the real one
|
|
10
|
+
* (a branch build on another port, decibel-hq ADR-0018 testing). Its pid,
|
|
11
|
+
* meta and logs live in <dir>, so it never takes over the machine's
|
|
12
|
+
* advertisement, and server.ts skips the machine singletons (peer broker,
|
|
13
|
+
* presence, HQ command dispatch, chat). Config, env and projects stay shared.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sidecarDir(): string | null;
|
|
16
|
+
/** Where this daemon's pid, meta and logs live: the sidecar dir, else ~/.decibel. */
|
|
17
|
+
export declare function daemonStateDir(): string;
|
|
18
|
+
export declare function metaPath(): string;
|
|
19
|
+
/** The port the daemon binds when nothing says otherwise. */
|
|
20
|
+
export declare const DEFAULT_DAEMON_PORT = 4888;
|
|
21
|
+
export interface DaemonMeta {
|
|
22
|
+
started_at: string;
|
|
23
|
+
crash_count: number;
|
|
24
|
+
port?: number;
|
|
25
|
+
pid?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Is this pid a process that currently exists?
|
|
29
|
+
*
|
|
30
|
+
* Signal 0 performs the permission and existence checks without delivering
|
|
31
|
+
* anything. EPERM means the process is there and owned by someone else, which
|
|
32
|
+
* is still alive — only ESRCH means gone.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isPidAlive(pid: number | undefined): boolean;
|
|
35
|
+
export declare function readDaemonMeta(): DaemonMeta | null;
|
|
36
|
+
/**
|
|
37
|
+
* The advertised port, or undefined when there is no usable advertisement.
|
|
38
|
+
*
|
|
39
|
+
* An entry whose pid is dead is treated as absent rather than followed. That is
|
|
40
|
+
* the whole point: a stale port is worse than no port, because callers fall
|
|
41
|
+
* back to the default when there is nothing to read and dial a corpse when
|
|
42
|
+
* there is.
|
|
43
|
+
*/
|
|
44
|
+
export declare function advertisedPort(): number | undefined;
|
|
45
|
+
/** Discovery order shared by every client: explicit > env > meta > default. */
|
|
46
|
+
export declare function resolveDaemonPort(explicit?: number): number;
|
|
47
|
+
/**
|
|
48
|
+
* True when someone else is currently advertising — a live pid that is not us.
|
|
49
|
+
* Taking discovery from a running daemon is how a second instance silently
|
|
50
|
+
* breaks the first one's clients, so callers refuse rather than overwrite.
|
|
51
|
+
*/
|
|
52
|
+
export declare function heldByAnotherProcess(): DaemonMeta | null;
|
|
53
|
+
//# sourceMappingURL=daemonMeta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemonMeta.d.ts","sourceRoot":"","sources":["../../src/runtime/daemonMeta.ts"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAG1C;AAED,qFAAqF;AACrF,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,6DAA6D;AAC7D,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAQ3D;AAED,wBAAgB,cAAc,IAAI,UAAU,GAAG,IAAI,CAOlD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,SAAS,CAKnD;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAO3D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,GAAG,IAAI,CAIxD"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// daemon.meta — machine-global daemon discovery
|
|
3
|
+
// ============================================================================
|
|
4
|
+
//
|
|
5
|
+
// ~/.decibel/daemon.meta is how every client on the machine finds the daemon:
|
|
6
|
+
// the session-init hook, the issue-close hook, the HQ client, ensureRuntime,
|
|
7
|
+
// the CLI. One small JSON file that three modules used to parse for themselves.
|
|
8
|
+
//
|
|
9
|
+
// ISS-0179. Two defects, and the second is the worse one:
|
|
10
|
+
//
|
|
11
|
+
// 1. ANY `--http` run advertised itself here, not just `--daemon`. Starting a
|
|
12
|
+
// throwaway server on another port — a test, a second checkout, a port
|
|
13
|
+
// conflict, a demo — silently redirected every hook on the machine to it.
|
|
14
|
+
//
|
|
15
|
+
// 2. Nothing removed a stale entry and no reader checked one. When that
|
|
16
|
+
// throwaway process died, the entry stayed, and every hook kept dialling a
|
|
17
|
+
// port with nothing behind it. The failure was silent at every layer: curl
|
|
18
|
+
// got connection-refused, the hook read empty output as "nothing to do",
|
|
19
|
+
// and the user saw a successful commit.
|
|
20
|
+
//
|
|
21
|
+
// The entry records the pid that wrote it, which is enough to tell a live
|
|
22
|
+
// advertisement from a dead one. That check lives here, once, because the
|
|
23
|
+
// reason it was missing is that it would have had to be written three times.
|
|
24
|
+
// ============================================================================
|
|
25
|
+
import fs from 'fs';
|
|
26
|
+
import path from 'path';
|
|
27
|
+
import os from 'os';
|
|
28
|
+
/**
|
|
29
|
+
* Resolved per call rather than captured at import, the way daemonConfig does:
|
|
30
|
+
* os.homedir() tracks $HOME, and a module-level constant freezes whatever it
|
|
31
|
+
* was when the file was first loaded — which makes this unverifiable in a test
|
|
32
|
+
* and wrong in any process that changes HOME.
|
|
33
|
+
*/
|
|
34
|
+
export function decibelHome() {
|
|
35
|
+
return path.join(os.homedir(), '.decibel');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* DECIBEL_DAEMON_SIDECAR=<dir> marks a second daemon run beside the real one
|
|
39
|
+
* (a branch build on another port, decibel-hq ADR-0018 testing). Its pid,
|
|
40
|
+
* meta and logs live in <dir>, so it never takes over the machine's
|
|
41
|
+
* advertisement, and server.ts skips the machine singletons (peer broker,
|
|
42
|
+
* presence, HQ command dispatch, chat). Config, env and projects stay shared.
|
|
43
|
+
*/
|
|
44
|
+
export function sidecarDir() {
|
|
45
|
+
const dir = process.env.DECIBEL_DAEMON_SIDECAR;
|
|
46
|
+
return dir ? path.resolve(dir) : null;
|
|
47
|
+
}
|
|
48
|
+
/** Where this daemon's pid, meta and logs live: the sidecar dir, else ~/.decibel. */
|
|
49
|
+
export function daemonStateDir() {
|
|
50
|
+
return sidecarDir() ?? decibelHome();
|
|
51
|
+
}
|
|
52
|
+
export function metaPath() {
|
|
53
|
+
return path.join(daemonStateDir(), 'daemon.meta');
|
|
54
|
+
}
|
|
55
|
+
/** The port the daemon binds when nothing says otherwise. */
|
|
56
|
+
export const DEFAULT_DAEMON_PORT = 4888;
|
|
57
|
+
/**
|
|
58
|
+
* Is this pid a process that currently exists?
|
|
59
|
+
*
|
|
60
|
+
* Signal 0 performs the permission and existence checks without delivering
|
|
61
|
+
* anything. EPERM means the process is there and owned by someone else, which
|
|
62
|
+
* is still alive — only ESRCH means gone.
|
|
63
|
+
*/
|
|
64
|
+
export function isPidAlive(pid) {
|
|
65
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
66
|
+
return false;
|
|
67
|
+
try {
|
|
68
|
+
process.kill(pid, 0);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
return err.code === 'EPERM';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function readDaemonMeta() {
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(fs.readFileSync(metaPath(), 'utf-8'));
|
|
78
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The advertised port, or undefined when there is no usable advertisement.
|
|
86
|
+
*
|
|
87
|
+
* An entry whose pid is dead is treated as absent rather than followed. That is
|
|
88
|
+
* the whole point: a stale port is worse than no port, because callers fall
|
|
89
|
+
* back to the default when there is nothing to read and dial a corpse when
|
|
90
|
+
* there is.
|
|
91
|
+
*/
|
|
92
|
+
export function advertisedPort() {
|
|
93
|
+
const meta = readDaemonMeta();
|
|
94
|
+
if (!meta || !Number.isInteger(meta.port))
|
|
95
|
+
return undefined;
|
|
96
|
+
if (meta.pid !== undefined && !isPidAlive(meta.pid))
|
|
97
|
+
return undefined;
|
|
98
|
+
return meta.port;
|
|
99
|
+
}
|
|
100
|
+
/** Discovery order shared by every client: explicit > env > meta > default. */
|
|
101
|
+
export function resolveDaemonPort(explicit) {
|
|
102
|
+
if (Number.isInteger(explicit) && explicit > 0 && explicit < 65536) {
|
|
103
|
+
return explicit;
|
|
104
|
+
}
|
|
105
|
+
const fromEnv = Number(process.env.DECIBEL_DAEMON_PORT);
|
|
106
|
+
if (Number.isInteger(fromEnv) && fromEnv > 0 && fromEnv < 65536)
|
|
107
|
+
return fromEnv;
|
|
108
|
+
return advertisedPort() ?? DEFAULT_DAEMON_PORT;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* True when someone else is currently advertising — a live pid that is not us.
|
|
112
|
+
* Taking discovery from a running daemon is how a second instance silently
|
|
113
|
+
* breaks the first one's clients, so callers refuse rather than overwrite.
|
|
114
|
+
*/
|
|
115
|
+
export function heldByAnotherProcess() {
|
|
116
|
+
const meta = readDaemonMeta();
|
|
117
|
+
if (!meta || meta.pid === undefined || meta.pid === process.pid)
|
|
118
|
+
return null;
|
|
119
|
+
return isPidAlive(meta.pid) ? meta : null;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=daemonMeta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemonMeta.js","sourceRoot":"","sources":["../../src/runtime/daemonMeta.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ensureRuntime — the one lifecycle primitive.
|
|
3
|
+
*
|
|
4
|
+
* Every surface that needs the Decibel runtime (MCP adapters, the CLI, the
|
|
5
|
+
* VS Code extension, shell hooks) calls this. None of them should carry their
|
|
6
|
+
* own "is the daemon up? should I start it?" logic — that duplication is how
|
|
7
|
+
* five subtly different startup behaviours end up in one codebase.
|
|
8
|
+
*
|
|
9
|
+
* Two things this deliberately does NOT do:
|
|
10
|
+
*
|
|
11
|
+
* 1. It does not use the PID file as the source of truth. `~/.decibel/daemon.pid`
|
|
12
|
+
* goes stale — an unclean exit leaves a pid pointing at nothing, or worse,
|
|
13
|
+
* at a recycled pid belonging to an unrelated process. A successful
|
|
14
|
+
* `/health` response is the only proof the runtime is actually serving.
|
|
15
|
+
*
|
|
16
|
+
* 2. It does not check-then-spawn. When six clients start at once, six
|
|
17
|
+
* "is it running? no → start it" sequences race and you get six daemons
|
|
18
|
+
* fighting over one port. Startup is arbitrated by an atomic O_EXCL lock
|
|
19
|
+
* file: exactly one caller wins the right to spawn, and the losers wait
|
|
20
|
+
* for the winner's daemon rather than starting their own.
|
|
21
|
+
*/
|
|
22
|
+
/** Default port the daemon binds. Overridden by daemon.meta or DECIBEL_DAEMON_PORT. */
|
|
23
|
+
export declare const DEFAULT_RUNTIME_PORT = 4888;
|
|
24
|
+
export interface RuntimeHealth {
|
|
25
|
+
status: string;
|
|
26
|
+
version: string;
|
|
27
|
+
protocol_version?: string;
|
|
28
|
+
pid: number;
|
|
29
|
+
uptime_ms: number;
|
|
30
|
+
facade_count: number;
|
|
31
|
+
license_tier: string;
|
|
32
|
+
[key: string]: unknown;
|
|
33
|
+
}
|
|
34
|
+
export interface RuntimeHandle {
|
|
35
|
+
/** Base URL, e.g. `http://127.0.0.1:4888`. No trailing slash. */
|
|
36
|
+
url: string;
|
|
37
|
+
port: number;
|
|
38
|
+
/** PID of the serving runtime — reported by /health, not read from a pid file. */
|
|
39
|
+
pid: number;
|
|
40
|
+
/** Package version of the running runtime. */
|
|
41
|
+
version: string;
|
|
42
|
+
/** Wire protocol the running runtime speaks. */
|
|
43
|
+
protocolVersion: string;
|
|
44
|
+
licenseTier: string;
|
|
45
|
+
/** True when this call started the runtime; false when it was already up. */
|
|
46
|
+
spawned: boolean;
|
|
47
|
+
health: RuntimeHealth;
|
|
48
|
+
}
|
|
49
|
+
export interface EnsureRuntimeOptions {
|
|
50
|
+
/** Protocol version this client requires. Defaults to the compiled-in version. */
|
|
51
|
+
protocolVersion?: string;
|
|
52
|
+
/** Port override. Falls back to daemon.meta, then DECIBEL_DAEMON_PORT, then 4888. */
|
|
53
|
+
port?: number;
|
|
54
|
+
/** Total time to wait for a runtime to become healthy. */
|
|
55
|
+
timeoutMs?: number;
|
|
56
|
+
/**
|
|
57
|
+
* When false, never spawn — probe only, and throw if nothing is serving.
|
|
58
|
+
* Used by callers that must not have side effects (status commands, health
|
|
59
|
+
* checks, anything running inside a hook with a hard timeout).
|
|
60
|
+
*/
|
|
61
|
+
autoStart?: boolean;
|
|
62
|
+
/** Absolute path to the runtime entry point. Defaults to this package's dist/server.js. */
|
|
63
|
+
serverEntry?: string;
|
|
64
|
+
}
|
|
65
|
+
/** Thrown when a runtime is serving but speaks an incompatible protocol. */
|
|
66
|
+
export declare class RuntimeProtocolMismatchError extends Error {
|
|
67
|
+
readonly serverVersion: string | undefined;
|
|
68
|
+
readonly clientVersion: string;
|
|
69
|
+
constructor(serverVersion: string | undefined, clientVersion: string, reason: string);
|
|
70
|
+
}
|
|
71
|
+
/** Thrown when no runtime is serving and one could not be started. */
|
|
72
|
+
export declare class RuntimeUnavailableError extends Error {
|
|
73
|
+
constructor(port: number, detail: string);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolve the port to talk to, in precedence order:
|
|
77
|
+
* explicit option → DECIBEL_DAEMON_PORT → daemon.meta → default.
|
|
78
|
+
*
|
|
79
|
+
* daemon.meta is a *hint*, not proof of life — it records the port the daemon
|
|
80
|
+
* last bound. We still confirm with /health before trusting anything.
|
|
81
|
+
*/
|
|
82
|
+
export declare function resolveRuntimePort(explicit?: number): number;
|
|
83
|
+
/**
|
|
84
|
+
* GET /health. Returns null when nothing is listening or the response is not a
|
|
85
|
+
* usable health payload — callers treat null as "no runtime here", never as an
|
|
86
|
+
* error worth surfacing.
|
|
87
|
+
*/
|
|
88
|
+
export declare function probeRuntime(port: number): Promise<RuntimeHealth | null>;
|
|
89
|
+
/**
|
|
90
|
+
* Return a handle to a healthy, protocol-compatible runtime, starting one if
|
|
91
|
+
* needed.
|
|
92
|
+
*
|
|
93
|
+
* Throws rather than degrading:
|
|
94
|
+
* - RuntimeProtocolMismatchError when something is serving but speaks a
|
|
95
|
+
* contract this client does not understand.
|
|
96
|
+
* - RuntimeUnavailableError when nothing is serving and none could be started.
|
|
97
|
+
*
|
|
98
|
+
* Callers must not silently fall back to doing the work in-process. A client
|
|
99
|
+
* that quietly becomes a second writer is exactly the failure this runtime
|
|
100
|
+
* exists to prevent.
|
|
101
|
+
*/
|
|
102
|
+
export declare function ensureRuntime(options?: EnsureRuntimeOptions): Promise<RuntimeHandle>;
|
|
103
|
+
//# sourceMappingURL=ensureRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensureRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/ensureRuntime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAeH,uFAAuF;AACvF,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAczC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,kFAAkF;IAClF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,4EAA4E;AAC5E,qBAAa,4BAA6B,SAAQ,KAAK;IAEnD,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS;IAC1C,QAAQ,CAAC,aAAa,EAAE,MAAM;gBADrB,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,aAAa,EAAE,MAAM,EAC9B,MAAM,EAAE,MAAM;CASjB;AAED,sEAAsE;AACtE,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAQzC;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAY5D;AAMD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAW9E;AAgHD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,CAkExB"}
|