@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 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.d.ts","sourceRoot":"","sources":["../../src/pty/tmux.ts"],"names":[],"mappings":"AAmBA,qFAAqF;AACrF,eAAO,MAAM,cAAc,SAAS,CAAC;AAOrC,wBAAgB,WAAW,IAAI,MAAM,CAMpC;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,CAAC,GAAE,MAAM,GAAG,IAAW,GAAG,IAAI,CAE5D;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1C,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAcvD;AAED,6EAA6E;AAC7E;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,QAGmF,CAAC;AAE7G,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAElD;AAwBD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,EAAE,CAE/E;AAED,wBAAgB,QAAQ,CAAC,IAAI,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAetF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,EAAE,CAIlF;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAM9F;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,YAAY,CAAC;AAEnC;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,SAAM,GAAG,MAAM,GAAG,SAAS,CAI/E;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,IAAI,EAAE,OAAO,CAAC;CACf;AAgBD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAKlD;AAgBD,yGAAyG;AACzG,wBAAsB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAG7E;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CAgB3D;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAY/D;AAED,oEAAoE;AACpE,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAEhF"}
|
package/dist/pty/tmux.js
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// tmux — the substrate hosted sessions live in (ADR-0012 / decibel-hq EPIC-0015)
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Every call is execFile with an argv array, never a shell string, so a session
|
|
5
|
+
// name or label can never become a command. Session targets use tmux's `=name`
|
|
6
|
+
// exact-match form: a bare `-t name` is a PREFIX match, so `-t dcb-a` would
|
|
7
|
+
// happily hit `dcb-abc`.
|
|
8
|
+
//
|
|
9
|
+
// Session metadata (project, branch, issue label) is stored ON the tmux session
|
|
10
|
+
// as user options (@dcb_*), not in a daemon-side file. It then lives exactly as
|
|
11
|
+
// long as the session does and survives a daemon restart with nothing to
|
|
12
|
+
// reconcile.
|
|
13
|
+
// ============================================================================
|
|
14
|
+
import { execFile } from 'child_process';
|
|
15
|
+
import { existsSync } from 'fs';
|
|
16
|
+
import { log } from '../config.js';
|
|
17
|
+
import { SessionError } from './errors.js';
|
|
18
|
+
/** Prefix for sessions the daemon spawned. Anything else is adopted, never owned. */
|
|
19
|
+
export const SPAWNED_PREFIX = 'dcb-';
|
|
20
|
+
/**
|
|
21
|
+
* launchd does not give the daemon a login PATH, so `tmux` alone may not
|
|
22
|
+
* resolve. Probe the usual install locations first.
|
|
23
|
+
*/
|
|
24
|
+
let tmuxPath = null;
|
|
25
|
+
export function resolveTmux() {
|
|
26
|
+
if (tmuxPath)
|
|
27
|
+
return tmuxPath;
|
|
28
|
+
for (const p of ['/opt/homebrew/bin/tmux', '/usr/local/bin/tmux', '/usr/bin/tmux']) {
|
|
29
|
+
if (existsSync(p))
|
|
30
|
+
return (tmuxPath = p);
|
|
31
|
+
}
|
|
32
|
+
return (tmuxPath = 'tmux');
|
|
33
|
+
}
|
|
34
|
+
/** Test seam: forget the cached binary path. */
|
|
35
|
+
export function _resetTmuxPath(p = null) {
|
|
36
|
+
tmuxPath = p;
|
|
37
|
+
}
|
|
38
|
+
export const OWNED_SOCKET_DEFAULT = 'decibel';
|
|
39
|
+
export function socketArgs(server) {
|
|
40
|
+
// -f /dev/null: the owned server must not read ~/.tmux.conf. HQ's pane needs
|
|
41
|
+
// predictable behaviour — no custom prefix, and no `mouse on`, whose mouse
|
|
42
|
+
// capture breaks xterm.js selection. (-f only matters when the server starts;
|
|
43
|
+
// passing it on every call is harmless.)
|
|
44
|
+
//
|
|
45
|
+
// -u on every call: launchd gives the daemon no locale, and a tmux client
|
|
46
|
+
// without one is treated as non-UTF-8 — every non-ASCII glyph Claude draws
|
|
47
|
+
// (❯, ⏵⏵, the logo) arrived in HQ as '_'. cleanEnv also supplies a UTF-8
|
|
48
|
+
// LANG/LC_CTYPE, so a server started by the daemon is UTF-8 too. Found by
|
|
49
|
+
// decibel-hq on its first live pass.
|
|
50
|
+
if (server === 'owned')
|
|
51
|
+
return ['-u', '-L', process.env.DECIBEL_TMUX_SOCKET || OWNED_SOCKET_DEFAULT, '-f', '/dev/null'];
|
|
52
|
+
const user = process.env.DECIBEL_TMUX_USER_SOCKET;
|
|
53
|
+
return user ? ['-u', '-L', user] : ['-u'];
|
|
54
|
+
}
|
|
55
|
+
/** Which server a session key lives on: the prefix is the ownership mark. */
|
|
56
|
+
/**
|
|
57
|
+
* Terminal title for clients of the owned server (set-titles): the repo, plus
|
|
58
|
+
* the issue label, or else a branch other than main/master. Built from the
|
|
59
|
+
* @dcb_* options the daemon sets at spawn, which cleanLabel has already
|
|
60
|
+
* stripped of control characters. tmux sends it as OSC 2 to every attached
|
|
61
|
+
* client, so a Ghostty tab is titled without any title text in its command
|
|
62
|
+
* (ISS-0210).
|
|
63
|
+
*/
|
|
64
|
+
export const TITLE_FORMAT = '#{?@dcb_project,#{@dcb_project},#{session_name}}' +
|
|
65
|
+
'#{?@dcb_issue, · #{@dcb_issue},' +
|
|
66
|
+
'#{?#{&&:#{@dcb_branch},#{&&:#{!=:#{@dcb_branch},main},#{!=:#{@dcb_branch},master}}}, · #{@dcb_branch},}}';
|
|
67
|
+
export function serverFor(name) {
|
|
68
|
+
return name.startsWith(SPAWNED_PREFIX) ? 'owned' : 'user';
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The environment every tmux client and spawned claude gets. TMUX is removed so
|
|
72
|
+
* a daemon started inside tmux does not make nested-client calls. CLAUDECODE,
|
|
73
|
+
* CLAUDE_CODE_* and CLAUDE_PID are removed because claude refuses to start when
|
|
74
|
+
* it sees them (the nested-session guard): a daemon ever launched from inside a
|
|
75
|
+
* Claude Code session would otherwise start an owned server whose every session
|
|
76
|
+
* dies instantly. Found by decibel-hq against its mock of this contract.
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* The daemon's own environment, which a spawned agent must not inherit
|
|
80
|
+
* (ISS-0225). launchd starts the daemon with its env file loaded and
|
|
81
|
+
* NODE_ENV=production, and before this every hosted Claude session held them
|
|
82
|
+
* all, including SUPABASE_SERVICE_KEY, which bypasses RLS on Core. Only the
|
|
83
|
+
* daemon writes with service_role; an agent and anything it runs must not.
|
|
84
|
+
* NODE_ENV=production also makes npm/pnpm skip and prune devDependencies.
|
|
85
|
+
*
|
|
86
|
+
* Matched by name: credentials by suffix, plus the daemon-only config.
|
|
87
|
+
* ANTHROPIC_* is kept, so Claude Code's own auth is untouched.
|
|
88
|
+
*/
|
|
89
|
+
const DAEMON_ONLY = new Set(['NODE_ENV', 'SUPABASE_URL', 'SUPABASE_ANON_KEY', 'SUPABASE_SERVICE_KEY', 'SUPABASE_SERVICE_ROLE_KEY', 'DECIBEL_ORG_ID']);
|
|
90
|
+
const CREDENTIAL_RE = /(_KEY|_TOKEN|_SECRET|PASSWORD|_DATABASE_URL|_DSN)$/i;
|
|
91
|
+
export function isDaemonOnlyVar(name) {
|
|
92
|
+
if (name.startsWith('ANTHROPIC_'))
|
|
93
|
+
return false;
|
|
94
|
+
return DAEMON_ONLY.has(name) || CREDENTIAL_RE.test(name);
|
|
95
|
+
}
|
|
96
|
+
/** Names in `base` that cleanEnv drops for being the daemon's. Names only, never values. */
|
|
97
|
+
export function daemonOnlyNames(base = process.env) {
|
|
98
|
+
return Object.keys(base).filter((k) => base[k] !== undefined && isDaemonOnlyVar(k)).sort();
|
|
99
|
+
}
|
|
100
|
+
export function cleanEnv(base = process.env) {
|
|
101
|
+
const env = {};
|
|
102
|
+
for (const [k, v] of Object.entries(base)) {
|
|
103
|
+
if (v === undefined)
|
|
104
|
+
continue;
|
|
105
|
+
if (k === 'TMUX' || k === 'TMUX_PANE' || k === 'CLAUDECODE' || k === 'CLAUDE_PID' || k.startsWith('CLAUDE_CODE_'))
|
|
106
|
+
continue;
|
|
107
|
+
if (isDaemonOnlyVar(k))
|
|
108
|
+
continue;
|
|
109
|
+
env[k] = v;
|
|
110
|
+
}
|
|
111
|
+
// No locale at all (launchd) means tmux and claude both fall back to ASCII.
|
|
112
|
+
// Supply UTF-8 only when nothing is set, so a user's own choice stands.
|
|
113
|
+
if (!env.LANG && !env.LC_ALL && !env.LC_CTYPE) {
|
|
114
|
+
env.LANG = 'en_US.UTF-8';
|
|
115
|
+
env.LC_CTYPE = 'en_US.UTF-8';
|
|
116
|
+
}
|
|
117
|
+
return env;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* tmux keeps the environment its server started with as the GLOBAL
|
|
121
|
+
* environment and copies it into every new session. A server started before
|
|
122
|
+
* ISS-0225 already holds the daemon's variables, so cleaning the client env
|
|
123
|
+
* is not enough: unset them there too. Applied before every spawn and at
|
|
124
|
+
* daemon start.
|
|
125
|
+
*/
|
|
126
|
+
export function unsetDaemonEnvArgs(base = process.env) {
|
|
127
|
+
const out = [];
|
|
128
|
+
for (const name of daemonOnlyNames(base))
|
|
129
|
+
out.push(';', 'set-environment', '-g', '-u', name);
|
|
130
|
+
return out.slice(1);
|
|
131
|
+
}
|
|
132
|
+
export function tmux(server, args, timeoutMs = 5000) {
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
execFile(resolveTmux(), [...socketArgs(server), ...args], { timeout: timeoutMs, env: cleanEnv() }, (err, stdout, stderr) => {
|
|
135
|
+
resolve({ ok: !err, stdout: String(stdout), stderr: String(stderr) || (err ? err.message : '') });
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Exact-match session target, for commands that take a SESSION target:
|
|
141
|
+
* has-session, kill-session, attach-session.
|
|
142
|
+
*/
|
|
143
|
+
export function sessionTarget(name) {
|
|
144
|
+
return `=${name}`;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Exact-match target for everything that parses -t as a pane or window:
|
|
148
|
+
* set-option, show-options, send-keys, respawn-pane. tmux 3.5a rejects a bare
|
|
149
|
+
* `=name` there with "no such session"; the trailing colon is required
|
|
150
|
+
* (verified 2026-09-25, and hit independently by decibel-hq's mock).
|
|
151
|
+
*/
|
|
152
|
+
export function paneTarget(name) {
|
|
153
|
+
return `=${name}:`;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Field separator for -F output. PRINTABLE on purpose: with no LANG/LC_* in
|
|
157
|
+
* the environment — which is exactly the launchd daemon's environment — tmux
|
|
158
|
+
* rewrites a TAB in format output as '_', every field collapsed into the
|
|
159
|
+
* session name, and no spawned session ever matched its project. The tests
|
|
160
|
+
* passed because the shell running them had a locale. Pinned by a test that
|
|
161
|
+
* lists with the locale removed.
|
|
162
|
+
*/
|
|
163
|
+
export const FIELD_SEP = '|:dcb:|';
|
|
164
|
+
/**
|
|
165
|
+
* Newlines and the field separator would corrupt list output, and a label has
|
|
166
|
+
* no business being long. Applied to every value written into a tmux option.
|
|
167
|
+
*/
|
|
168
|
+
export function cleanLabel(v, max = 200) {
|
|
169
|
+
if (v === undefined || v === null)
|
|
170
|
+
return undefined;
|
|
171
|
+
const cleaned = String(v).split(FIELD_SEP).join(' ').replace(/[\t\r\n]/g, ' ').trim().slice(0, max);
|
|
172
|
+
return cleaned || undefined;
|
|
173
|
+
}
|
|
174
|
+
const LIST_FORMAT = [
|
|
175
|
+
'#{session_name}',
|
|
176
|
+
'#{@dcb_project}',
|
|
177
|
+
'#{@dcb_branch}',
|
|
178
|
+
'#{@dcb_issue}',
|
|
179
|
+
'#{@dcb_uuid}',
|
|
180
|
+
'#{session_created}',
|
|
181
|
+
'#{pane_current_path}',
|
|
182
|
+
'#{pane_dead}',
|
|
183
|
+
// #{pane_current_path} is empty once the pane is dead, so spawned sessions
|
|
184
|
+
// also record their cwd as an option (found by decibel-hq's mock).
|
|
185
|
+
'#{@dcb_cwd}',
|
|
186
|
+
].join(FIELD_SEP);
|
|
187
|
+
/**
|
|
188
|
+
* "No server" is a normal answer; "could not ask" is not. A missing socket
|
|
189
|
+
* means no server, so no sessions. Any other failure — a server that exists
|
|
190
|
+
* but did not answer — must NOT read as an empty list, because HQ would render
|
|
191
|
+
* a live session as gone. It gets one retry and then throws. (A spawned session
|
|
192
|
+
* once went unlisted for minutes while its server was plainly up; the old check
|
|
193
|
+
* swallowed every "error connecting to" as "no server". Cause unverified.)
|
|
194
|
+
*/
|
|
195
|
+
export function isNoServer(stderr) {
|
|
196
|
+
// A stale socket file (the server died without removing it) refuses the
|
|
197
|
+
// connection; that is also "no server".
|
|
198
|
+
return /no server running/.test(stderr) ||
|
|
199
|
+
/error connecting to .*\((No such file or directory|Connection refused)\)/.test(stderr);
|
|
200
|
+
}
|
|
201
|
+
async function tmuxRead(server, args) {
|
|
202
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
203
|
+
const r = await tmux(server, args);
|
|
204
|
+
if (r.ok)
|
|
205
|
+
return r;
|
|
206
|
+
if (isNoServer(r.stderr))
|
|
207
|
+
return null;
|
|
208
|
+
log(`Sessions: tmux ${args[0]} (${server}) failed${attempt ? '' : ', retrying'}: ${r.stderr.trim() || 'no stderr'}`);
|
|
209
|
+
if (!attempt)
|
|
210
|
+
await new Promise((res) => setTimeout(res, 250));
|
|
211
|
+
else {
|
|
212
|
+
throw new SessionError(503, 'TMUX_UNAVAILABLE', `The ${server} tmux server did not answer: ${r.stderr.trim() || 'no stderr'}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
/** Every session on one server. Empty when that server is not running; throws when it cannot be read. */
|
|
218
|
+
export async function listSessions(server) {
|
|
219
|
+
const r = await tmuxRead(server, ['list-sessions', '-F', LIST_FORMAT]);
|
|
220
|
+
return r ? parseSessions(r.stdout) : [];
|
|
221
|
+
}
|
|
222
|
+
export function parseSessions(stdout) {
|
|
223
|
+
const out = [];
|
|
224
|
+
for (const line of stdout.split('\n')) {
|
|
225
|
+
if (!line.trim())
|
|
226
|
+
continue;
|
|
227
|
+
const [name, project, branch, issue, uuid, created, paneCwd, dead, dcbCwd] = line.split(FIELD_SEP);
|
|
228
|
+
const cwd = dcbCwd || paneCwd;
|
|
229
|
+
const s = { name, dead: dead === '1' };
|
|
230
|
+
if (uuid)
|
|
231
|
+
s.claude_session_id = uuid;
|
|
232
|
+
if (project)
|
|
233
|
+
s.project_id = project;
|
|
234
|
+
if (branch)
|
|
235
|
+
s.branch = branch;
|
|
236
|
+
if (issue)
|
|
237
|
+
s.issue_label = issue;
|
|
238
|
+
if (created && /^\d+$/.test(created))
|
|
239
|
+
s.created = new Date(Number(created) * 1000).toISOString();
|
|
240
|
+
if (cwd)
|
|
241
|
+
s.cwd = cwd;
|
|
242
|
+
out.push(s);
|
|
243
|
+
}
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* pane tty (without /dev/) → session name, across BOTH servers, for matching
|
|
248
|
+
* claude-peers ttys. A user-server session carrying the dcb- prefix is skipped:
|
|
249
|
+
* the prefix means "owned", and honouring it on the wrong server would route
|
|
250
|
+
* attach and kill to a session the daemon does not own.
|
|
251
|
+
*/
|
|
252
|
+
export async function paneTtyMap() {
|
|
253
|
+
const m = new Map();
|
|
254
|
+
for (const server of ['owned', 'user']) {
|
|
255
|
+
const r = await tmuxRead(server, ['list-panes', '-a', '-F', `#{pane_tty}${FIELD_SEP}#{session_name}`]);
|
|
256
|
+
if (!r)
|
|
257
|
+
continue;
|
|
258
|
+
for (const line of r.stdout.split('\n')) {
|
|
259
|
+
const [tty, name] = line.split(FIELD_SEP);
|
|
260
|
+
if (!tty || !name || serverFor(name) !== server)
|
|
261
|
+
continue;
|
|
262
|
+
m.set(tty.replace(/^\/dev\//, ''), name);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return m;
|
|
266
|
+
}
|
|
267
|
+
/** Find a session by key on the server its key says it lives on. */
|
|
268
|
+
export async function findSession(name) {
|
|
269
|
+
return (await listSessions(serverFor(name))).find((s) => s.name === name);
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=tmux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../src/pty/tmux.ts"],"names":[],"mappings":"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"}
|
package/dist/roster.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface ScopeFilter {
|
|
2
|
+
assignee?: unknown;
|
|
3
|
+
team?: unknown;
|
|
4
|
+
}
|
|
5
|
+
export interface ScopeTerm {
|
|
6
|
+
requested: string;
|
|
7
|
+
/** Every id a record may carry to match this filter. */
|
|
8
|
+
match: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface ResolvedScope {
|
|
11
|
+
assignee?: ScopeTerm;
|
|
12
|
+
team?: ScopeTerm;
|
|
13
|
+
/** True when the roster answered and aliases were applied. */
|
|
14
|
+
expanded: boolean;
|
|
15
|
+
/** Present whenever the result may be short, and why. */
|
|
16
|
+
note?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface RosterRow {
|
|
19
|
+
id: string;
|
|
20
|
+
kind: string;
|
|
21
|
+
canonical_id: string | null;
|
|
22
|
+
aliases: string[] | null;
|
|
23
|
+
}
|
|
24
|
+
export type RosterResolver = (ids: string[]) => Promise<RosterRow[]>;
|
|
25
|
+
/** Test seam. */
|
|
26
|
+
export declare function _setRosterResolver(fn: RosterResolver | null): void;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a scope filter. Returns null when no filter was given, so an
|
|
29
|
+
* unscoped call keeps exactly its current behaviour.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveScope(f: ScopeFilter): Promise<ResolvedScope | null>;
|
|
32
|
+
/** Does a record fall inside the scope? Both terms must hold when both are set. */
|
|
33
|
+
export declare function inScope(record: {
|
|
34
|
+
assignee?: string;
|
|
35
|
+
team?: string;
|
|
36
|
+
}, scope: ResolvedScope): boolean;
|
|
37
|
+
//# sourceMappingURL=roster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;AAkBrE,iBAAiB;AACjB,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAGlE;AA+BD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAoChF;AAED,mFAAmF;AACnF,wBAAgB,OAAO,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAInG"}
|
package/dist/roster.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Roster resolution for scoped reads (EPIC-0040 slice 3)
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// A filter such as assignee=user:<ben> has to match every id that means Ben:
|
|
5
|
+
// the canonical user:<uuid> AND every human:<name> claimed to that account.
|
|
6
|
+
// Records are never rewritten to upgrade a human: to a user:, so without this
|
|
7
|
+
// expansion a filter by user:<uuid> misses every record written before the
|
|
8
|
+
// claim (44 human:ben records in this repo alone) and returns a confidently
|
|
9
|
+
// short list.
|
|
10
|
+
//
|
|
11
|
+
// HQ owns the mapping: hq.resolve_ids(p_org, p_ids) returns, per input id, its
|
|
12
|
+
// canonical_id and aliases. The daemon turns one filter id into an IN-list:
|
|
13
|
+
// {requested} ∪ {canonical_id} ∪ aliases.
|
|
14
|
+
//
|
|
15
|
+
// Offline degradation, agreed with decibel-hq: when the roster is unreachable,
|
|
16
|
+
// match the literal id only and SAY SO in the result ("not expanded"). Never a
|
|
17
|
+
// guess, never a quiet omission.
|
|
18
|
+
// ============================================================================
|
|
19
|
+
import { assertActor, assertTeam, IdentityError } from './identity.js';
|
|
20
|
+
import { requireOrgId } from './orgId.js';
|
|
21
|
+
import { getSupabaseServiceClient, isSupabaseConfigured } from './lib/supabase.js';
|
|
22
|
+
const CACHE_MS = 5 * 60_000;
|
|
23
|
+
const TIMEOUT_MS = 3_000;
|
|
24
|
+
const cache = new Map();
|
|
25
|
+
async function supabaseResolver(ids) {
|
|
26
|
+
if (!isSupabaseConfigured())
|
|
27
|
+
throw new Error('Supabase is not configured on this process');
|
|
28
|
+
const client = getSupabaseServiceClient();
|
|
29
|
+
const call = client.schema('hq').rpc('resolve_ids', { p_org: requireOrgId(), p_ids: ids });
|
|
30
|
+
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`no answer in ${TIMEOUT_MS}ms`)), TIMEOUT_MS));
|
|
31
|
+
const { data, error } = (await Promise.race([call, timeout]));
|
|
32
|
+
if (error)
|
|
33
|
+
throw new Error(error.message);
|
|
34
|
+
if (!Array.isArray(data))
|
|
35
|
+
throw new Error('resolve_ids returned no rows');
|
|
36
|
+
return data;
|
|
37
|
+
}
|
|
38
|
+
let resolver = supabaseResolver;
|
|
39
|
+
/** Test seam. */
|
|
40
|
+
export function _setRosterResolver(fn) {
|
|
41
|
+
resolver = fn ?? supabaseResolver;
|
|
42
|
+
cache.clear();
|
|
43
|
+
}
|
|
44
|
+
/** Validate a filter's SHAPE. Membership is HQ's business, never checked here. */
|
|
45
|
+
function parseFilter(f) {
|
|
46
|
+
const out = {};
|
|
47
|
+
try {
|
|
48
|
+
if (f.assignee !== undefined && f.assignee !== '') {
|
|
49
|
+
if (typeof f.assignee !== 'string')
|
|
50
|
+
throw new IdentityError('assignee must be a string');
|
|
51
|
+
assertActor(f.assignee);
|
|
52
|
+
out.assignee = f.assignee;
|
|
53
|
+
}
|
|
54
|
+
if (f.team !== undefined && f.team !== '') {
|
|
55
|
+
if (typeof f.team !== 'string')
|
|
56
|
+
throw new IdentityError('team must be a string');
|
|
57
|
+
assertTeam(f.team);
|
|
58
|
+
out.team = f.team;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
throw new Error(`Invalid scope filter: ${err instanceof Error ? err.message : String(err)}`);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function termFrom(requested, row) {
|
|
67
|
+
const ids = new Set([requested]);
|
|
68
|
+
if (row && row.kind !== 'unresolved') {
|
|
69
|
+
if (row.canonical_id)
|
|
70
|
+
ids.add(row.canonical_id);
|
|
71
|
+
for (const a of row.aliases ?? [])
|
|
72
|
+
ids.add(a);
|
|
73
|
+
}
|
|
74
|
+
return { requested, match: [...ids] };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Resolve a scope filter. Returns null when no filter was given, so an
|
|
78
|
+
* unscoped call keeps exactly its current behaviour.
|
|
79
|
+
*/
|
|
80
|
+
export async function resolveScope(f) {
|
|
81
|
+
const parsed = parseFilter(f);
|
|
82
|
+
const wanted = [parsed.assignee, parsed.team].filter((x) => !!x);
|
|
83
|
+
if (!wanted.length)
|
|
84
|
+
return null;
|
|
85
|
+
const now = Date.now();
|
|
86
|
+
const rows = new Map();
|
|
87
|
+
const missing = wanted.filter((id) => {
|
|
88
|
+
const hit = cache.get(id);
|
|
89
|
+
if (hit && now - hit.at < CACHE_MS) {
|
|
90
|
+
rows.set(id, hit.row);
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
let failure;
|
|
96
|
+
if (missing.length) {
|
|
97
|
+
try {
|
|
98
|
+
const answered = await resolver(missing);
|
|
99
|
+
for (const row of answered) {
|
|
100
|
+
rows.set(row.id, row);
|
|
101
|
+
cache.set(row.id, { row, at: now });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
failure = err instanceof Error ? err.message : String(err);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const scope = { expanded: !failure };
|
|
109
|
+
if (parsed.assignee)
|
|
110
|
+
scope.assignee = termFrom(parsed.assignee, rows.get(parsed.assignee));
|
|
111
|
+
if (parsed.team)
|
|
112
|
+
scope.team = termFrom(parsed.team, rows.get(parsed.team));
|
|
113
|
+
if (failure) {
|
|
114
|
+
scope.note = `Roster unreachable (${failure}): matched the literal id only; local identities were not expanded, so this list may be short.`;
|
|
115
|
+
}
|
|
116
|
+
return scope;
|
|
117
|
+
}
|
|
118
|
+
/** Does a record fall inside the scope? Both terms must hold when both are set. */
|
|
119
|
+
export function inScope(record, scope) {
|
|
120
|
+
if (scope.assignee && !(record.assignee && scope.assignee.match.includes(record.assignee)))
|
|
121
|
+
return false;
|
|
122
|
+
if (scope.team && !(record.team && scope.team.match.includes(record.team)))
|
|
123
|
+
return false;
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=roster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roster.js","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
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
|
+
export type CircuitState = 'closed' | 'open' | 'half_open';
|
|
37
|
+
export interface CircuitBreakerOptions {
|
|
38
|
+
/** Consecutive faults before the circuit opens. Default 5. */
|
|
39
|
+
failureThreshold?: number;
|
|
40
|
+
/** How long the circuit stays open before admitting a probe. Default 30s. */
|
|
41
|
+
cooldownMs?: number;
|
|
42
|
+
/** An `isError` result slower than this counts as a fault. Default 2s. */
|
|
43
|
+
slowFailureMs?: number;
|
|
44
|
+
/** Injectable clock — tests drive this instead of sleeping. */
|
|
45
|
+
now?: () => number;
|
|
46
|
+
}
|
|
47
|
+
export interface CircuitSnapshot {
|
|
48
|
+
state: CircuitState;
|
|
49
|
+
consecutive_faults: number;
|
|
50
|
+
opened_at?: string;
|
|
51
|
+
retry_after_ms?: number;
|
|
52
|
+
last_error?: string;
|
|
53
|
+
}
|
|
54
|
+
/** What the caller learns when it asks permission to run. */
|
|
55
|
+
export type CircuitDecision = {
|
|
56
|
+
allowed: true;
|
|
57
|
+
} | {
|
|
58
|
+
allowed: false;
|
|
59
|
+
retryAfterMs: number;
|
|
60
|
+
lastError?: string;
|
|
61
|
+
openedAt?: string;
|
|
62
|
+
};
|
|
63
|
+
export declare class CircuitBreakerRegistry {
|
|
64
|
+
private readonly circuits;
|
|
65
|
+
private readonly failureThreshold;
|
|
66
|
+
private readonly cooldownMs;
|
|
67
|
+
readonly slowFailureMs: number;
|
|
68
|
+
private readonly now;
|
|
69
|
+
constructor(opts?: CircuitBreakerOptions);
|
|
70
|
+
/**
|
|
71
|
+
* Ask whether a call to `key` may proceed. Transitions open → half_open when
|
|
72
|
+
* the cooldown has elapsed, and reserves the half-open probe for the caller
|
|
73
|
+
* it says yes to.
|
|
74
|
+
*/
|
|
75
|
+
beforeCall(key: string): CircuitDecision;
|
|
76
|
+
/**
|
|
77
|
+
* Report what happened. `threw` and `durationMs` decide whether this was a
|
|
78
|
+
* fault; see the module comment for why `isError` alone is not enough and
|
|
79
|
+
* not too much.
|
|
80
|
+
*/
|
|
81
|
+
afterCall(key: string, outcome: {
|
|
82
|
+
threw: boolean;
|
|
83
|
+
isError: boolean;
|
|
84
|
+
durationMs: number;
|
|
85
|
+
error?: string;
|
|
86
|
+
}): void;
|
|
87
|
+
recordSuccess(key: string): void;
|
|
88
|
+
recordFault(key: string, error?: string): void;
|
|
89
|
+
state(key: string): CircuitState;
|
|
90
|
+
/** Open circuits only — a healthy runtime reports `{}`. */
|
|
91
|
+
snapshot(): Record<string, CircuitSnapshot>;
|
|
92
|
+
reset(key?: string): void;
|
|
93
|
+
private close;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=circuitBreaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuitBreaker.d.ts","sourceRoot":"","sources":["../../src/runtime/circuitBreaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAgBpF,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,IAAI,GAAE,qBAA0B;IAO5C;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe;IAiCxC;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAiB/G,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAMhC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IA0B9C,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY;IAIhC,2DAA2D;IAC3D,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC;IAiB3C,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAKzB,OAAO,CAAC,KAAK;CAQd"}
|