@noopolis/daimon 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +307 -45
- package/dist/contracts/attentionContract.d.ts +117 -0
- package/dist/contracts/attentionContract.d.ts.map +1 -0
- package/dist/contracts/attentionContract.js +14 -0
- package/dist/contracts/canonicalJson.d.ts +3 -0
- package/dist/contracts/canonicalJson.d.ts.map +1 -0
- package/dist/contracts/canonicalJson.js +54 -0
- package/dist/contracts/grokWorkerContract.d.ts +74 -0
- package/dist/contracts/grokWorkerContract.d.ts.map +1 -0
- package/dist/contracts/grokWorkerContract.js +88 -0
- package/dist/contracts/organizationRuntimeContract.d.ts +765 -0
- package/dist/contracts/organizationRuntimeContract.d.ts.map +1 -0
- package/dist/contracts/organizationRuntimeContract.js +121 -0
- package/dist/contracts/runtimeContractManifest.d.ts +1615 -0
- package/dist/contracts/runtimeContractManifest.d.ts.map +1 -0
- package/dist/contracts/runtimeContractManifest.js +181 -0
- package/dist/core/credentialRedaction.d.ts +4 -0
- package/dist/core/credentialRedaction.d.ts.map +1 -0
- package/dist/core/credentialRedaction.js +28 -0
- package/dist/core/siblingBuildFreshness.d.ts +21 -0
- package/dist/core/siblingBuildFreshness.d.ts.map +1 -0
- package/dist/core/siblingBuildFreshness.js +25 -0
- package/dist/core/types.d.ts +10 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/examples/exampleCausalId.d.ts +3 -0
- package/dist/examples/exampleCausalId.d.ts.map +1 -0
- package/dist/examples/exampleCausalId.js +8 -0
- package/dist/examples/jungian-play-org.js +3 -2
- package/dist/examples/jungian-triad-org.js +3 -2
- package/dist/examples/jungianPlayAgent.d.ts +1 -1
- package/dist/examples/jungianPlayAgent.d.ts.map +1 -1
- package/dist/examples/jungianPlayAgent.js +1 -1
- package/dist/examples/jungianProfiles.d.ts +1 -1
- package/dist/examples/jungianProfiles.d.ts.map +1 -1
- package/dist/examples/jungianTriadProfiles.d.ts +1 -1
- package/dist/examples/jungianTriadProfiles.d.ts.map +1 -1
- package/dist/examples/pi-agent.js +3 -2
- package/dist/examples/pi-memory-org.js +6 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/mcp/toolServer.d.ts +31 -0
- package/dist/mcp/toolServer.d.ts.map +1 -0
- package/dist/mcp/toolServer.js +145 -0
- package/dist/observability/causalEvents.d.ts +118 -0
- package/dist/observability/causalEvents.d.ts.map +1 -0
- package/dist/observability/causalEvents.js +223 -0
- package/dist/observability/controlCausal.d.ts +117 -0
- package/dist/observability/controlCausal.d.ts.map +1 -0
- package/dist/observability/controlCausal.js +107 -0
- package/dist/observability/emitCausalFixture.d.ts +25 -0
- package/dist/observability/emitCausalFixture.d.ts.map +1 -0
- package/dist/observability/emitCausalFixture.js +98 -0
- package/dist/observability/index.d.ts +2 -0
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +2 -0
- package/dist/observability/orgObserver.d.ts.map +1 -1
- package/dist/observability/orgObserver.js +3 -3
- package/dist/pi/agyHeadlessResult.d.ts +60 -0
- package/dist/pi/agyHeadlessResult.d.ts.map +1 -0
- package/dist/pi/agyHeadlessResult.js +95 -0
- package/dist/pi/cliChildOutput.d.ts +67 -0
- package/dist/pi/cliChildOutput.d.ts.map +1 -0
- package/dist/pi/cliChildOutput.js +269 -0
- package/dist/pi/cliEngineRun.d.ts +16 -0
- package/dist/pi/cliEngineRun.d.ts.map +1 -0
- package/dist/pi/cliEngineRun.js +27 -0
- package/dist/pi/cliEngineSpawn.d.ts +55 -0
- package/dist/pi/cliEngineSpawn.d.ts.map +1 -0
- package/dist/pi/cliEngineSpawn.js +164 -0
- package/dist/pi/cliEnvironment.d.ts +12 -0
- package/dist/pi/cliEnvironment.d.ts.map +1 -0
- package/dist/pi/cliEnvironment.js +32 -0
- package/dist/pi/cliMcpRegistration.d.ts +61 -0
- package/dist/pi/cliMcpRegistration.d.ts.map +1 -0
- package/dist/pi/cliMcpRegistration.js +75 -0
- package/dist/pi/cliProcess.d.ts +7 -0
- package/dist/pi/cliProcess.d.ts.map +1 -0
- package/dist/pi/cliProcess.js +132 -0
- package/dist/pi/cliSession.d.ts +106 -0
- package/dist/pi/cliSession.d.ts.map +1 -0
- package/dist/pi/cliSession.js +379 -0
- package/dist/pi/cliTurnMetering.d.ts +60 -0
- package/dist/pi/cliTurnMetering.d.ts.map +1 -0
- package/dist/pi/cliTurnMetering.js +60 -0
- package/dist/pi/codexFilesystemRules.d.ts +3 -0
- package/dist/pi/codexFilesystemRules.d.ts.map +1 -0
- package/dist/pi/codexFilesystemRules.js +28 -0
- package/dist/pi/codexHeadlessResult.d.ts +68 -0
- package/dist/pi/codexHeadlessResult.d.ts.map +1 -0
- package/dist/pi/codexHeadlessResult.js +122 -0
- package/dist/pi/codexRolloutUsage.d.ts +95 -0
- package/dist/pi/codexRolloutUsage.d.ts.map +1 -0
- package/dist/pi/codexRolloutUsage.js +221 -0
- package/dist/pi/engineWakeLimits.d.ts +39 -0
- package/dist/pi/engineWakeLimits.d.ts.map +1 -0
- package/dist/pi/engineWakeLimits.js +55 -0
- package/dist/pi/grokHeadlessResult.d.ts +36 -0
- package/dist/pi/grokHeadlessResult.d.ts.map +1 -0
- package/dist/pi/grokHeadlessResult.js +118 -0
- package/dist/pi/grokHomeMcpRegistration.d.ts +21 -0
- package/dist/pi/grokHomeMcpRegistration.d.ts.map +1 -0
- package/dist/pi/grokHomeMcpRegistration.js +57 -0
- package/dist/pi/grokSandbox.d.ts +11 -0
- package/dist/pi/grokSandbox.d.ts.map +1 -0
- package/dist/pi/grokSandbox.js +216 -0
- package/dist/pi/grokStreamUsage.d.ts +31 -0
- package/dist/pi/grokStreamUsage.d.ts.map +1 -0
- package/dist/pi/grokStreamUsage.js +51 -0
- package/dist/pi/index.d.ts +5 -0
- package/dist/pi/index.d.ts.map +1 -1
- package/dist/pi/index.js +5 -0
- package/dist/pi/memoryTools.d.ts +55 -1
- package/dist/pi/memoryTools.d.ts.map +1 -1
- package/dist/pi/memoryTools.js +144 -24
- package/dist/pi/modelRegistry.d.ts +13 -0
- package/dist/pi/modelRegistry.d.ts.map +1 -0
- package/dist/pi/modelRegistry.js +19 -0
- package/dist/pi/piAgentHandle.d.ts +46 -0
- package/dist/pi/piAgentHandle.d.ts.map +1 -0
- package/dist/pi/piAgentHandle.js +351 -0
- package/dist/pi/piAgentWakeSupport.d.ts +103 -0
- package/dist/pi/piAgentWakeSupport.d.ts.map +1 -0
- package/dist/pi/piAgentWakeSupport.js +151 -0
- package/dist/pi/piHarness.d.ts +40 -5
- package/dist/pi/piHarness.d.ts.map +1 -1
- package/dist/pi/piHarness.js +151 -256
- package/dist/pi/prompts.d.ts +10 -0
- package/dist/pi/prompts.d.ts.map +1 -0
- package/dist/pi/prompts.js +63 -0
- package/dist/pi/rawTrainingCapture.d.ts +59 -0
- package/dist/pi/rawTrainingCapture.d.ts.map +1 -0
- package/dist/pi/rawTrainingCapture.js +175 -0
- package/dist/pi/turnCausal.d.ts +73 -0
- package/dist/pi/turnCausal.d.ts.map +1 -0
- package/dist/pi/turnCausal.js +75 -0
- package/dist/pi/turnTrace.d.ts +128 -0
- package/dist/pi/turnTrace.d.ts.map +1 -0
- package/dist/pi/turnTrace.js +138 -0
- package/dist/pi/wakeAcceptance.d.ts +49 -0
- package/dist/pi/wakeAcceptance.d.ts.map +1 -0
- package/dist/pi/wakeAcceptance.js +281 -0
- package/dist/pi/wakeAcceptanceFs.d.ts +44 -0
- package/dist/pi/wakeAcceptanceFs.d.ts.map +1 -0
- package/dist/pi/wakeAcceptanceFs.js +318 -0
- package/dist/pi/wakeAcceptanceSchema.d.ts +75 -0
- package/dist/pi/wakeAcceptanceSchema.d.ts.map +1 -0
- package/dist/pi/wakeAcceptanceSchema.js +265 -0
- package/dist/pi/wakeModes.d.ts +9 -0
- package/dist/pi/wakeModes.d.ts.map +1 -0
- package/dist/pi/wakeModes.js +19 -0
- package/dist/pi/worldNudge.d.ts +22 -0
- package/dist/pi/worldNudge.d.ts.map +1 -0
- package/dist/pi/worldNudge.js +62 -0
- package/dist/pi/worldToolProtocol.d.ts +13 -0
- package/dist/pi/worldToolProtocol.d.ts.map +1 -0
- package/dist/pi/worldToolProtocol.js +49 -0
- package/dist/pi/worldTools.d.ts +32 -0
- package/dist/pi/worldTools.d.ts.map +1 -0
- package/dist/pi/worldTools.js +373 -0
- package/dist/pi/worldTrajectory.d.ts +52 -0
- package/dist/pi/worldTrajectory.d.ts.map +1 -0
- package/dist/pi/worldTrajectory.js +131 -0
- package/dist/runtime/agySubscriptionBootstrap.d.ts +16 -0
- package/dist/runtime/agySubscriptionBootstrap.d.ts.map +1 -0
- package/dist/runtime/agySubscriptionBootstrap.js +80 -0
- package/dist/runtime/agySubscriptionRealm.d.ts +38 -0
- package/dist/runtime/agySubscriptionRealm.d.ts.map +1 -0
- package/dist/runtime/agySubscriptionRealm.js +242 -0
- package/dist/runtime/attention.d.ts +21 -0
- package/dist/runtime/attention.d.ts.map +1 -0
- package/dist/runtime/attention.js +36 -0
- package/dist/runtime/attentionDispatcher.d.ts +66 -0
- package/dist/runtime/attentionDispatcher.d.ts.map +1 -0
- package/dist/runtime/attentionDispatcher.js +271 -0
- package/dist/runtime/cli.d.ts +7 -0
- package/dist/runtime/cli.d.ts.map +1 -0
- package/dist/runtime/cli.js +251 -0
- package/dist/runtime/codexSandboxProjection.d.ts +17 -0
- package/dist/runtime/codexSandboxProjection.d.ts.map +1 -0
- package/dist/runtime/codexSandboxProjection.js +40 -0
- package/dist/runtime/contract-manifest.json +1 -0
- package/dist/runtime/contract-manifest.sha256 +1 -0
- package/dist/runtime/contractManifest.d.ts +8 -0
- package/dist/runtime/contractManifest.d.ts.map +1 -0
- package/dist/runtime/contractManifest.js +4 -0
- package/dist/runtime/engineBrokerCapabilities.d.ts +30 -0
- package/dist/runtime/engineBrokerCapabilities.d.ts.map +1 -0
- package/dist/runtime/engineBrokerCapabilities.js +59 -0
- package/dist/runtime/engineBrokerControlClient.d.ts +44 -0
- package/dist/runtime/engineBrokerControlClient.d.ts.map +1 -0
- package/dist/runtime/engineBrokerControlClient.js +132 -0
- package/dist/runtime/engineBrokerCredentialJournal.d.ts +10 -0
- package/dist/runtime/engineBrokerCredentialJournal.d.ts.map +1 -0
- package/dist/runtime/engineBrokerCredentialJournal.js +17 -0
- package/dist/runtime/engineBrokerInferenceProtocol.d.ts +52 -0
- package/dist/runtime/engineBrokerInferenceProtocol.d.ts.map +1 -0
- package/dist/runtime/engineBrokerInferenceProtocol.js +65 -0
- package/dist/runtime/engineBrokerMcpCallLog.d.ts +160 -0
- package/dist/runtime/engineBrokerMcpCallLog.d.ts.map +1 -0
- package/dist/runtime/engineBrokerMcpCallLog.js +219 -0
- package/dist/runtime/engineBrokerMcpFacade.d.ts +56 -0
- package/dist/runtime/engineBrokerMcpFacade.d.ts.map +1 -0
- package/dist/runtime/engineBrokerMcpFacade.js +343 -0
- package/dist/runtime/engineBrokerNativeClient.d.ts +52 -0
- package/dist/runtime/engineBrokerNativeClient.d.ts.map +1 -0
- package/dist/runtime/engineBrokerNativeClient.js +151 -0
- package/dist/runtime/engineBrokerProtocol.d.ts +135 -0
- package/dist/runtime/engineBrokerProtocol.d.ts.map +1 -0
- package/dist/runtime/engineBrokerProtocol.js +274 -0
- package/dist/runtime/engineBrokerSealLedger.d.ts +70 -0
- package/dist/runtime/engineBrokerSealLedger.d.ts.map +1 -0
- package/dist/runtime/engineBrokerSealLedger.js +123 -0
- package/dist/runtime/engineBrokerService.d.ts +37 -0
- package/dist/runtime/engineBrokerService.d.ts.map +1 -0
- package/dist/runtime/engineBrokerService.js +138 -0
- package/dist/runtime/engineBrokerServiceCli.d.ts +5 -0
- package/dist/runtime/engineBrokerServiceCli.d.ts.map +1 -0
- package/dist/runtime/engineBrokerServiceCli.js +32 -0
- package/dist/runtime/engineBrokerServiceConfig.d.ts +50 -0
- package/dist/runtime/engineBrokerServiceConfig.d.ts.map +1 -0
- package/dist/runtime/engineBrokerServiceConfig.js +92 -0
- package/dist/runtime/engineBrokerSingleflight.d.ts +13 -0
- package/dist/runtime/engineBrokerSingleflight.d.ts.map +1 -0
- package/dist/runtime/engineBrokerSingleflight.js +24 -0
- package/dist/runtime/engineBrokerTurnAccounting.d.ts +76 -0
- package/dist/runtime/engineBrokerTurnAccounting.d.ts.map +1 -0
- package/dist/runtime/engineBrokerTurnAccounting.js +108 -0
- package/dist/runtime/engineBrokerTurnRegistry.d.ts +57 -0
- package/dist/runtime/engineBrokerTurnRegistry.d.ts.map +1 -0
- package/dist/runtime/engineBrokerTurnRegistry.js +158 -0
- package/dist/runtime/engineDispatcher.d.ts +36 -0
- package/dist/runtime/engineDispatcher.d.ts.map +1 -0
- package/dist/runtime/engineDispatcher.js +216 -0
- package/dist/runtime/engineReadiness.d.ts +23 -0
- package/dist/runtime/engineReadiness.d.ts.map +1 -0
- package/dist/runtime/engineReadiness.js +222 -0
- package/dist/runtime/grokAuthenticationError.d.ts +8 -0
- package/dist/runtime/grokAuthenticationError.d.ts.map +1 -0
- package/dist/runtime/grokAuthenticationError.js +20 -0
- package/dist/runtime/grokBrokerCredentialAuthority.d.ts +22 -0
- package/dist/runtime/grokBrokerCredentialAuthority.d.ts.map +1 -0
- package/dist/runtime/grokBrokerCredentialAuthority.js +124 -0
- package/dist/runtime/grokBrokerCredentialReader.d.ts +5 -0
- package/dist/runtime/grokBrokerCredentialReader.d.ts.map +1 -0
- package/dist/runtime/grokBrokerCredentialReader.js +37 -0
- package/dist/runtime/grokBrokerModelPolicy.d.ts +23 -0
- package/dist/runtime/grokBrokerModelPolicy.d.ts.map +1 -0
- package/dist/runtime/grokBrokerModelPolicy.js +28 -0
- package/dist/runtime/grokBrokerProjection.d.ts +106 -0
- package/dist/runtime/grokBrokerProjection.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProjection.js +94 -0
- package/dist/runtime/grokBrokerProxy.d.ts +55 -0
- package/dist/runtime/grokBrokerProxy.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProxy.js +262 -0
- package/dist/runtime/grokBrokerProxyRequest.d.ts +30 -0
- package/dist/runtime/grokBrokerProxyRequest.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProxyRequest.js +74 -0
- package/dist/runtime/grokBrokerRealmLease.d.ts +4 -0
- package/dist/runtime/grokBrokerRealmLease.d.ts.map +1 -0
- package/dist/runtime/grokBrokerRealmLease.js +33 -0
- package/dist/runtime/grokBrokerRefresh.d.ts +2 -0
- package/dist/runtime/grokBrokerRefresh.d.ts.map +1 -0
- package/dist/runtime/grokBrokerRefresh.js +15 -0
- package/dist/runtime/grokBrokerTurnMeter.d.ts +128 -0
- package/dist/runtime/grokBrokerTurnMeter.d.ts.map +1 -0
- package/dist/runtime/grokBrokerTurnMeter.js +251 -0
- package/dist/runtime/grokBrokerWorkerConfig.d.ts +86 -0
- package/dist/runtime/grokBrokerWorkerConfig.d.ts.map +1 -0
- package/dist/runtime/grokBrokerWorkerConfig.js +135 -0
- package/dist/runtime/grokEngineBroker.d.ts +48 -0
- package/dist/runtime/grokEngineBroker.d.ts.map +1 -0
- package/dist/runtime/grokEngineBroker.js +114 -0
- package/dist/runtime/grokEngineBrokerLedger.d.ts +52 -0
- package/dist/runtime/grokEngineBrokerLedger.d.ts.map +1 -0
- package/dist/runtime/grokEngineBrokerLedger.js +114 -0
- package/dist/runtime/grokEngineBrokerMetering.d.ts +51 -0
- package/dist/runtime/grokEngineBrokerMetering.d.ts.map +1 -0
- package/dist/runtime/grokEngineBrokerMetering.js +34 -0
- package/dist/runtime/grokEngineBrokerTurn.d.ts +58 -0
- package/dist/runtime/grokEngineBrokerTurn.d.ts.map +1 -0
- package/dist/runtime/grokEngineBrokerTurn.js +165 -0
- package/dist/runtime/grokInferenceClientConfig.d.ts +41 -0
- package/dist/runtime/grokInferenceClientConfig.d.ts.map +1 -0
- package/dist/runtime/grokInferenceClientConfig.js +62 -0
- package/dist/runtime/grokInferenceGrants.d.ts +77 -0
- package/dist/runtime/grokInferenceGrants.d.ts.map +1 -0
- package/dist/runtime/grokInferenceGrants.js +116 -0
- package/dist/runtime/grokInferenceProxy.d.ts +29 -0
- package/dist/runtime/grokInferenceProxy.d.ts.map +1 -0
- package/dist/runtime/grokInferenceProxy.js +82 -0
- package/dist/runtime/grokInferenceProxyRequest.d.ts +23 -0
- package/dist/runtime/grokInferenceProxyRequest.d.ts.map +1 -0
- package/dist/runtime/grokInferenceProxyRequest.js +63 -0
- package/dist/runtime/grokSlotPreflightReceipt.d.ts +70 -0
- package/dist/runtime/grokSlotPreflightReceipt.d.ts.map +1 -0
- package/dist/runtime/grokSlotPreflightReceipt.js +101 -0
- package/dist/runtime/grokSubscriptionRealm.d.ts +4 -0
- package/dist/runtime/grokSubscriptionRealm.d.ts.map +1 -0
- package/dist/runtime/grokSubscriptionRealm.js +435 -0
- package/dist/runtime/grokSubscriptionRealmTypes.d.ts +26 -0
- package/dist/runtime/grokSubscriptionRealmTypes.d.ts.map +1 -0
- package/dist/runtime/grokSubscriptionRealmTypes.js +1 -0
- package/dist/runtime/grokWorkerAttestation.d.ts +170 -0
- package/dist/runtime/grokWorkerAttestation.d.ts.map +1 -0
- package/dist/runtime/grokWorkerAttestation.js +266 -0
- package/dist/runtime/grokWorkerDenyPlacement.d.ts +80 -0
- package/dist/runtime/grokWorkerDenyPlacement.d.ts.map +1 -0
- package/dist/runtime/grokWorkerDenyPlacement.js +128 -0
- package/dist/runtime/grokWorkerHomeAttestation.d.ts +30 -0
- package/dist/runtime/grokWorkerHomeAttestation.d.ts.map +1 -0
- package/dist/runtime/grokWorkerHomeAttestation.js +69 -0
- package/dist/runtime/grokWorkerSandboxProfile.d.ts +27 -0
- package/dist/runtime/grokWorkerSandboxProfile.d.ts.map +1 -0
- package/dist/runtime/grokWorkerSandboxProfile.js +44 -0
- package/dist/runtime/grokWorkerTmpAttestation.d.ts +55 -0
- package/dist/runtime/grokWorkerTmpAttestation.d.ts.map +1 -0
- package/dist/runtime/grokWorkerTmpAttestation.js +63 -0
- package/dist/runtime/index.d.ts +26 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +23 -0
- package/dist/runtime/inferenceUsageLedger.d.ts +38 -0
- package/dist/runtime/inferenceUsageLedger.d.ts.map +1 -0
- package/dist/runtime/inferenceUsageLedger.js +53 -0
- package/dist/runtime/mcpToolResult.d.ts +127 -0
- package/dist/runtime/mcpToolResult.d.ts.map +1 -0
- package/dist/runtime/mcpToolResult.js +214 -0
- package/dist/runtime/moltnetMachineRead.d.ts +97 -0
- package/dist/runtime/moltnetMachineRead.d.ts.map +1 -0
- package/dist/runtime/moltnetMachineRead.js +183 -0
- package/dist/runtime/native/daimon-engine-broker +0 -0
- package/dist/runtime/organizationRuntime.d.ts +165 -0
- package/dist/runtime/organizationRuntime.d.ts.map +1 -0
- package/dist/runtime/organizationRuntime.js +3 -0
- package/dist/runtime/organizationRuntimeControl.d.ts +42 -0
- package/dist/runtime/organizationRuntimeControl.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeControl.js +235 -0
- package/dist/runtime/organizationRuntimeHost.d.ts +19 -0
- package/dist/runtime/organizationRuntimeHost.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeHost.js +359 -0
- package/dist/runtime/organizationRuntimeParsing.d.ts +6 -0
- package/dist/runtime/organizationRuntimeParsing.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeParsing.js +370 -0
- package/dist/runtime/organizationRuntimeReadiness.d.ts +12 -0
- package/dist/runtime/organizationRuntimeReadiness.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeReadiness.js +59 -0
- package/dist/runtime/physicalReadiness.d.ts +47 -0
- package/dist/runtime/physicalReadiness.d.ts.map +1 -0
- package/dist/runtime/physicalReadiness.js +142 -0
- package/dist/runtime/portableCredentialAuth.d.ts +6 -0
- package/dist/runtime/portableCredentialAuth.d.ts.map +1 -0
- package/dist/runtime/portableCredentialAuth.js +70 -0
- package/dist/runtime/portableCredentialMaterial.d.ts +8 -0
- package/dist/runtime/portableCredentialMaterial.d.ts.map +1 -0
- package/dist/runtime/portableCredentialMaterial.js +169 -0
- package/dist/runtime/productionAgentTools.d.ts +5 -0
- package/dist/runtime/productionAgentTools.d.ts.map +1 -0
- package/dist/runtime/productionAgentTools.js +328 -0
- package/dist/runtime/runtimeHomeLayout.d.ts +48 -0
- package/dist/runtime/runtimeHomeLayout.d.ts.map +1 -0
- package/dist/runtime/runtimeHomeLayout.js +84 -0
- package/dist/runtime/schedule.d.ts +40 -0
- package/dist/runtime/schedule.d.ts.map +1 -0
- package/dist/runtime/schedule.js +371 -0
- package/dist/runtime/storeCoordination.d.ts +23 -0
- package/dist/runtime/storeCoordination.d.ts.map +1 -0
- package/dist/runtime/storeCoordination.js +94 -0
- package/dist/runtime/toolResultSpill.d.ts +152 -0
- package/dist/runtime/toolResultSpill.d.ts.map +1 -0
- package/dist/runtime/toolResultSpill.js +351 -0
- package/dist/runtime/turnRequestLedger.d.ts +160 -0
- package/dist/runtime/turnRequestLedger.d.ts.map +1 -0
- package/dist/runtime/turnRequestLedger.js +249 -0
- package/dist/runtime/turnUsageLedger.d.ts +143 -0
- package/dist/runtime/turnUsageLedger.d.ts.map +1 -0
- package/dist/runtime/turnUsageLedger.js +203 -0
- package/dist/runtime/wakeAcceptanceProcessIdentity.d.ts +17 -0
- package/dist/runtime/wakeAcceptanceProcessIdentity.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceProcessIdentity.js +50 -0
- package/dist/runtime/wakeAcceptanceReconciliation.d.ts +211 -0
- package/dist/runtime/wakeAcceptanceReconciliation.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceReconciliation.js +289 -0
- package/dist/runtime/wakeAcceptanceRecord.d.ts +23 -0
- package/dist/runtime/wakeAcceptanceRecord.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceRecord.js +56 -0
- package/dist/runtime/wakeAcceptanceRetention.d.ts +12 -0
- package/dist/runtime/wakeAcceptanceRetention.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceRetention.js +12 -0
- package/dist/runtime/wakeAcceptanceStore.d.ts +113 -0
- package/dist/runtime/wakeAcceptanceStore.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceStore.js +558 -0
- package/dist/runtime/wakeAcceptanceTypes.d.ts +179 -0
- package/dist/runtime/wakeAcceptanceTypes.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceTypes.js +95 -0
- package/dist/runtime/wakeFuse.d.ts +69 -0
- package/dist/runtime/wakeFuse.d.ts.map +1 -0
- package/dist/runtime/wakeFuse.js +367 -0
- package/package.json +25 -17
- package/dist/examples/mixed-engine-org.d.ts +0 -2
- package/dist/examples/mixed-engine-org.d.ts.map +0 -1
- package/dist/examples/mixed-engine-org.js +0 -351
- package/dist/examples/mixedEngineCli.d.ts +0 -15
- package/dist/examples/mixedEngineCli.d.ts.map +0 -1
- package/dist/examples/mixedEngineCli.js +0 -174
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
import { sameNamespace, currentProcessIdentity, processIsAlive, WakeTransitionLockBlockedError } from "./wakeAcceptanceProcessIdentity.js";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { link, lstat, open, readFile, readdir, realpath, rename, unlink } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
6
|
+
import { MAX_WAKE_ACCEPTANCE_RECORD_BYTES, sanitizeWakeCompletionText, wakeAcceptanceDigest } from "./wakeAcceptanceTypes.js";
|
|
7
|
+
import { sanitizeExecutionError, parseStoredWakeAcceptance, publicStatus } from "./wakeAcceptanceRecord.js";
|
|
8
|
+
import { assertOfflineReconciliationLeaseAvailable } from "./wakeAcceptanceReconciliation.js";
|
|
9
|
+
import { acquireHostRegistration, releaseHostRegistration } from "./storeCoordination.js";
|
|
10
|
+
import { MAX_WAKE_ACCEPTANCE_RECORDS, terminalFilesToCompact } from "./wakeAcceptanceRetention.js";
|
|
11
|
+
const DEFAULT_CLAIM_TTL_MS = 240_000;
|
|
12
|
+
/** Durable, private idempotency authority; callers must pre-create its 0700 root. */
|
|
13
|
+
export class WakeAcceptanceStore {
|
|
14
|
+
root;
|
|
15
|
+
directory;
|
|
16
|
+
identity;
|
|
17
|
+
registration;
|
|
18
|
+
claimTtlMs;
|
|
19
|
+
now;
|
|
20
|
+
owner;
|
|
21
|
+
ownerLiveness;
|
|
22
|
+
afterFinalLockAssertion;
|
|
23
|
+
mutations = Promise.resolve();
|
|
24
|
+
acceptanceFiles = new Map();
|
|
25
|
+
constructor(root, directory, identity, registration, claimTtlMs, now, owner, ownerLiveness, afterFinalLockAssertion) {
|
|
26
|
+
this.root = root;
|
|
27
|
+
this.directory = directory;
|
|
28
|
+
this.identity = identity;
|
|
29
|
+
this.registration = registration;
|
|
30
|
+
this.claimTtlMs = claimTtlMs;
|
|
31
|
+
this.now = now;
|
|
32
|
+
this.owner = owner;
|
|
33
|
+
this.ownerLiveness = ownerLiveness;
|
|
34
|
+
this.afterFinalLockAssertion = afterFinalLockAssertion;
|
|
35
|
+
}
|
|
36
|
+
static async open(root, options = {}) {
|
|
37
|
+
const claimTtlMs = options.claimTtlMs ?? DEFAULT_CLAIM_TTL_MS;
|
|
38
|
+
if (!Number.isInteger(claimTtlMs) || claimTtlMs < 1 || claimTtlMs > 600_000)
|
|
39
|
+
throw new Error("wake acceptance claim lease is outside its bound");
|
|
40
|
+
if (!path.isAbsolute(root))
|
|
41
|
+
throw new Error("wake acceptance store path must be absolute");
|
|
42
|
+
const owner = await (options.processIdentity ?? currentProcessIdentity)();
|
|
43
|
+
await assertNoLinks(root);
|
|
44
|
+
await assertOfflineReconciliationLeaseAvailable(root).catch(() => { throw new Error("wake acceptance store is reserved for offline reconciliation"); });
|
|
45
|
+
await options.afterInitialLeaseCheckForTest?.();
|
|
46
|
+
const before = await lstat(root);
|
|
47
|
+
if (!before.isDirectory() || before.isSymbolicLink() || before.uid !== process.getuid?.() || (before.mode & 0o777) !== 0o700)
|
|
48
|
+
throw new Error("wake acceptance store must be a caller-prepared private directory");
|
|
49
|
+
const directory = await open(root, constants.O_RDONLY | directoryFlag() | noFollow());
|
|
50
|
+
try {
|
|
51
|
+
const after = await directory.stat();
|
|
52
|
+
const real = await realpath(root);
|
|
53
|
+
if (!same(identity(before), identity(after)))
|
|
54
|
+
throw new Error("wake acceptance store changed during validation");
|
|
55
|
+
const registration = await acquireHostRegistration(real, directory, owner);
|
|
56
|
+
return new WakeAcceptanceStore(real, directory, identity(before), registration, claimTtlMs, options.nowForTest ?? Date.now, owner, options.ownerLiveness ?? processIsAlive, options.afterFinalLockAssertion);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
await directory.close().catch(() => undefined);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
accept(request) {
|
|
64
|
+
return this.serialize(async () => await this.acceptNow(request));
|
|
65
|
+
}
|
|
66
|
+
async acceptNow(request) {
|
|
67
|
+
await this.verify();
|
|
68
|
+
const request_digest = wakeAcceptanceDigest(request);
|
|
69
|
+
const target = this.fileFor(request.agent_id, request.delivery_id);
|
|
70
|
+
const existing = await this.readOptional(target);
|
|
71
|
+
if (existing !== undefined) {
|
|
72
|
+
if (existing.request_digest !== request_digest)
|
|
73
|
+
throw new WakeAcceptanceConflictError();
|
|
74
|
+
return { record: existing, created: false };
|
|
75
|
+
}
|
|
76
|
+
await this.compactTerminalRecords();
|
|
77
|
+
if ((await this.files()).length >= MAX_WAKE_ACCEPTANCE_RECORDS)
|
|
78
|
+
throw new WakeInboxFullError();
|
|
79
|
+
const now = new Date().toISOString();
|
|
80
|
+
const record = { acceptance_id: randomUUID(), agent_id: request.agent_id, delivery_id: request.delivery_id, request_digest, event: request.event, state: "accepted", accepted_at: now, updated_at: now };
|
|
81
|
+
const temporary = path.join(this.root, `.pending-${randomUUID()}`);
|
|
82
|
+
try {
|
|
83
|
+
await this.writeNew(temporary, record);
|
|
84
|
+
try {
|
|
85
|
+
await link(temporary, target);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code !== "EEXIST")
|
|
89
|
+
throw error;
|
|
90
|
+
const winner = await this.read(target);
|
|
91
|
+
if (winner.request_digest !== request_digest)
|
|
92
|
+
throw new WakeAcceptanceConflictError();
|
|
93
|
+
return { record: winner, created: false };
|
|
94
|
+
}
|
|
95
|
+
await this.directory.sync();
|
|
96
|
+
this.acceptanceFiles.set(record.acceptance_id, target);
|
|
97
|
+
return { record, created: true };
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
await unlink(temporary).catch(() => undefined);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async status(acceptanceId) {
|
|
104
|
+
const record = await this.findByAcceptanceId(acceptanceId);
|
|
105
|
+
return record === undefined ? undefined : publicStatus(record);
|
|
106
|
+
}
|
|
107
|
+
async activity() { return await this.activityRows(false); }
|
|
108
|
+
/** Internal availability view; diagnostics never enter the public receipt wire. */
|
|
109
|
+
async activityWithExecutionErrors() { return await this.activityRows(true); }
|
|
110
|
+
async activityRows(includeExecutionErrors) {
|
|
111
|
+
const records = await Promise.all((await this.files()).map(async (file) => await this.read(path.join(this.root, file))));
|
|
112
|
+
records.sort((left, right) => left.accepted_at.localeCompare(right.accepted_at) || left.acceptance_id.localeCompare(right.acceptance_id));
|
|
113
|
+
const queued = new Map();
|
|
114
|
+
const activeExecutions = new Set();
|
|
115
|
+
return records.map((record) => {
|
|
116
|
+
const position = record.state === "accepted" ? (queued.get(record.agent_id) ?? 0) + 1 : undefined;
|
|
117
|
+
if (position !== undefined)
|
|
118
|
+
queued.set(record.agent_id, position);
|
|
119
|
+
const active = record.state === "running" && !activeExecutions.has(record.agent_id);
|
|
120
|
+
if (active)
|
|
121
|
+
activeExecutions.add(record.agent_id);
|
|
122
|
+
return { ...publicStatus(record), active, ...(position === undefined ? {} : { queue_position: position }),
|
|
123
|
+
...(includeExecutionErrors && record.execution_error !== undefined ? { execution_error: record.execution_error } : {}) };
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async recoverable(agentIds) {
|
|
127
|
+
const result = [];
|
|
128
|
+
for (const file of await this.files()) {
|
|
129
|
+
const record = await this.read(path.join(this.root, file));
|
|
130
|
+
if (!agentIds.has(record.agent_id))
|
|
131
|
+
throw new Error("wake acceptance store contains an unknown agent authority");
|
|
132
|
+
if (record.state === "accepted" || record.state === "running") {
|
|
133
|
+
const claim = await this.readClaimOptional(this.claimFor(record));
|
|
134
|
+
result.push(!record.deferred && record.execution_id === undefined && claim?.acceptance_ids?.includes(record.acceptance_id) && claim.execution_id !== undefined ? { ...record, execution_id: claim.execution_id } : record);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return result.sort((left, right) => left.accepted_at.localeCompare(right.accepted_at) || left.acceptance_id.localeCompare(right.acceptance_id));
|
|
138
|
+
}
|
|
139
|
+
transition(acceptanceId, state, code) {
|
|
140
|
+
return this.serialize(async () => await this.transitionNow(acceptanceId, state, code));
|
|
141
|
+
}
|
|
142
|
+
/** Fuse race seam: never stops a record that was claimed after enumeration. */
|
|
143
|
+
transitionAcceptedToStopped(acceptanceId) {
|
|
144
|
+
return this.serialize(async () => {
|
|
145
|
+
const target = await this.pathForAcceptanceId(acceptanceId);
|
|
146
|
+
const prior = await this.read(target);
|
|
147
|
+
if (prior.state !== "accepted")
|
|
148
|
+
return prior;
|
|
149
|
+
const record = { ...prior, state: "stopped", code: "host_stopping", updated_at: new Date().toISOString() };
|
|
150
|
+
await this.replace(target, record);
|
|
151
|
+
return record;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
acquireClaim(acceptanceId, ownerId, acceptanceIds, executionId) {
|
|
155
|
+
return this.serialize(async () => {
|
|
156
|
+
if (!uuid(ownerId))
|
|
157
|
+
throw new Error("wake execution owner is invalid");
|
|
158
|
+
const record = await this.findByAcceptanceId(acceptanceId);
|
|
159
|
+
if (record === undefined)
|
|
160
|
+
throw new Error("wake acceptance receipt is unavailable");
|
|
161
|
+
if (isTerminal(record.state))
|
|
162
|
+
return { state: "terminal" };
|
|
163
|
+
if (acceptanceIds !== undefined) {
|
|
164
|
+
if (!acceptanceIds.includes(acceptanceId) || acceptanceIds.length > 32 || new Set(acceptanceIds).size !== acceptanceIds.length || !executionId || !uuid(executionId))
|
|
165
|
+
throw new Error("invalid execution membership");
|
|
166
|
+
for (const member of acceptanceIds) {
|
|
167
|
+
const candidate = await this.findByAcceptanceId(member);
|
|
168
|
+
if (!candidate || candidate.agent_id !== record.agent_id || isTerminal(candidate.state))
|
|
169
|
+
throw new Error("invalid execution member");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const target = this.claimFor(record);
|
|
173
|
+
const current = await this.readClaimOptional(target);
|
|
174
|
+
if (current !== undefined && !expired(current, this.now()))
|
|
175
|
+
return { state: "held", retry_at: current.expires_at };
|
|
176
|
+
const lock = await this.acquireTransitionLock(record, ownerId);
|
|
177
|
+
if (lock === undefined)
|
|
178
|
+
return { state: "held", retry_at: new Date(this.now() + 50).toISOString() };
|
|
179
|
+
try {
|
|
180
|
+
const checked = await this.readClaimOptional(target);
|
|
181
|
+
if (checked !== undefined && !expired(checked, this.now()))
|
|
182
|
+
return { state: "held", retry_at: checked.expires_at };
|
|
183
|
+
if (checked !== undefined) {
|
|
184
|
+
await unlink(target);
|
|
185
|
+
await this.directory.sync();
|
|
186
|
+
}
|
|
187
|
+
const claim = { acceptance_id: record.acceptance_id, owner_id: ownerId, generation: randomUUID(), expires_at: new Date(this.now() + this.claimTtlMs).toISOString(), ...(acceptanceIds === undefined ? {} : { acceptance_ids: acceptanceIds, execution_id: executionId }) };
|
|
188
|
+
const temporary = path.join(this.root, `.claim-${randomUUID()}`);
|
|
189
|
+
try {
|
|
190
|
+
await this.writeNew(temporary, claim);
|
|
191
|
+
try {
|
|
192
|
+
await link(temporary, target);
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
if (error.code === "EEXIST") {
|
|
196
|
+
const winner = await this.readClaim(target);
|
|
197
|
+
return { state: "held", retry_at: winner.expires_at };
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
await this.directory.sync();
|
|
202
|
+
return { state: "acquired", claim };
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
await unlink(temporary).catch(() => undefined);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
await this.releaseTransitionLock(record, lock);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
claimHeartbeatIntervalMs() { return Math.max(1, Math.floor(this.claimTtlMs / 3)); }
|
|
214
|
+
renewClaim(acceptanceId, claim) {
|
|
215
|
+
return this.serialize(async () => {
|
|
216
|
+
const record = await this.findByAcceptanceId(acceptanceId);
|
|
217
|
+
if (record === undefined)
|
|
218
|
+
throw new Error("wake acceptance receipt is unavailable");
|
|
219
|
+
const lock = await this.acquireTransitionLock(record, claim.owner_id);
|
|
220
|
+
if (lock === undefined)
|
|
221
|
+
throw new WakeExecutionClaimLostError();
|
|
222
|
+
try {
|
|
223
|
+
const current = await this.readClaim(this.claimFor(record));
|
|
224
|
+
if (!(current.acceptance_id === acceptanceId || current.acceptance_ids?.includes(acceptanceId)) || current.acceptance_id !== claim.acceptance_id || current.owner_id !== claim.owner_id || current.generation !== claim.generation || current.expires_at !== claim.expires_at || expired(current, this.now()))
|
|
225
|
+
throw new WakeExecutionClaimLostError();
|
|
226
|
+
const renewed = { ...current, expires_at: new Date(this.now() + this.claimTtlMs).toISOString() };
|
|
227
|
+
await this.replaceValue(this.claimFor(record), renewed);
|
|
228
|
+
return renewed;
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
await this.releaseTransitionLock(record, lock);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/** `text` carries the completion output on success and the engine failure cause on failure. */
|
|
236
|
+
transitionClaimed(acceptanceId, claim, state, code, completedText, attention) {
|
|
237
|
+
return this.serialize(async () => {
|
|
238
|
+
if (completedText !== undefined && state !== "completed" && state !== "failed")
|
|
239
|
+
throw new Error("wake text requires completed or failed state");
|
|
240
|
+
const initial = await this.findByAcceptanceId(acceptanceId);
|
|
241
|
+
if (initial === undefined)
|
|
242
|
+
throw new Error("wake acceptance receipt is unavailable");
|
|
243
|
+
const lock = await this.acquireTransitionLock(initial, claim.owner_id);
|
|
244
|
+
if (lock === undefined)
|
|
245
|
+
throw new WakeExecutionClaimLostError();
|
|
246
|
+
try {
|
|
247
|
+
let record = await this.transitionNowClaimed(acceptanceId, claim);
|
|
248
|
+
if (isTerminal(record.state))
|
|
249
|
+
return record;
|
|
250
|
+
if (state !== "running" && record.claim_generation !== claim.generation)
|
|
251
|
+
throw new WakeExecutionClaimLostError();
|
|
252
|
+
await this.assertTransitionLock(record, lock);
|
|
253
|
+
record = await this.transitionNowClaimed(acceptanceId, claim);
|
|
254
|
+
if (isTerminal(record.state))
|
|
255
|
+
return record;
|
|
256
|
+
if (state !== "running" && record.claim_generation !== claim.generation)
|
|
257
|
+
throw new WakeExecutionClaimLostError();
|
|
258
|
+
await this.assertTransitionLock(record, lock);
|
|
259
|
+
await this.afterFinalLockAssertion?.();
|
|
260
|
+
await this.assertTransitionLock(record, lock);
|
|
261
|
+
const target = this.fileFor(record.agent_id, record.delivery_id);
|
|
262
|
+
// The code explains the transition that produced the CURRENT state, so a
|
|
263
|
+
// transition that names none clears it. While codes existed only on terminal
|
|
264
|
+
// records this could not matter — a terminal record returns above and is never
|
|
265
|
+
// rewritten — but a delivery reclaimed to `accepted` with its wake's outcome is
|
|
266
|
+
// claimed again later, and a carried-over code would describe the wrong state.
|
|
267
|
+
const { code: _replaced, ...carried } = record;
|
|
268
|
+
const next = { ...carried, state, updated_at: new Date().toISOString(), claim_generation: claim.generation, ...(code === undefined ? {} : { code }), ...(completedText === undefined ? {} : { text: sanitizeWakeCompletionText(completedText) }), ...(attention === undefined ? {} : { execution_id: attention.clear_execution ? undefined : attention.execution_id ?? record.execution_id, deferred: attention.deferred ?? record.deferred, execution_error: attention.execution_error === null ? undefined : attention.execution_error === undefined ? record.execution_error : sanitizeExecutionError(attention.execution_error) || undefined }) };
|
|
269
|
+
await this.replace(target, next);
|
|
270
|
+
if (claim.acceptance_ids === undefined && (isTerminal(state) || state === "accepted")) {
|
|
271
|
+
const currentClaim = await this.readClaimOptional(this.claimFor(record));
|
|
272
|
+
if (currentClaim?.owner_id === claim.owner_id && currentClaim.generation === claim.generation) {
|
|
273
|
+
await unlink(this.claimFor(record));
|
|
274
|
+
await this.directory.sync();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return next;
|
|
278
|
+
}
|
|
279
|
+
finally {
|
|
280
|
+
await this.releaseTransitionLock(initial, lock);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
releaseClaim(claim) {
|
|
285
|
+
return this.serialize(async () => {
|
|
286
|
+
const record = await this.findByAcceptanceId(claim.acceptance_id);
|
|
287
|
+
if (!record)
|
|
288
|
+
throw new WakeExecutionClaimLostError();
|
|
289
|
+
const lock = await this.acquireTransitionLock(record, claim.owner_id);
|
|
290
|
+
if (!lock)
|
|
291
|
+
throw new WakeExecutionClaimLostError();
|
|
292
|
+
try {
|
|
293
|
+
const current = await this.readClaimOptional(this.claimFor(record));
|
|
294
|
+
if (current?.generation !== claim.generation || current.owner_id !== claim.owner_id)
|
|
295
|
+
throw new WakeExecutionClaimLostError();
|
|
296
|
+
await unlink(this.claimFor(record));
|
|
297
|
+
await this.directory.sync();
|
|
298
|
+
}
|
|
299
|
+
finally {
|
|
300
|
+
await this.releaseTransitionLock(record, lock);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
releaseClaims(ownerId) {
|
|
305
|
+
return this.serialize(async () => {
|
|
306
|
+
for (const file of await this.claimFiles()) {
|
|
307
|
+
const claim = await this.readClaim(path.join(this.root, file));
|
|
308
|
+
if (claim.owner_id === ownerId)
|
|
309
|
+
await unlink(path.join(this.root, file));
|
|
310
|
+
}
|
|
311
|
+
await this.directory.sync();
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
async transitionNow(acceptanceId, state, code) {
|
|
315
|
+
const target = await this.pathForAcceptanceId(acceptanceId);
|
|
316
|
+
const prior = await this.read(target);
|
|
317
|
+
if (isTerminal(prior.state))
|
|
318
|
+
return prior;
|
|
319
|
+
const record = { ...prior, state, updated_at: new Date().toISOString(), ...(code === undefined ? {} : { code }) };
|
|
320
|
+
await this.replace(target, record);
|
|
321
|
+
return record;
|
|
322
|
+
}
|
|
323
|
+
async close() { await this.mutations; await releaseHostRegistration(this.root, this.directory, this.registration); await this.directory.close(); }
|
|
324
|
+
serialize(operation) {
|
|
325
|
+
const result = this.mutations.catch(() => undefined).then(operation);
|
|
326
|
+
this.mutations = result.then(() => undefined, () => undefined);
|
|
327
|
+
return result;
|
|
328
|
+
}
|
|
329
|
+
async findByAcceptanceId(acceptanceId) {
|
|
330
|
+
if (!uuid(acceptanceId))
|
|
331
|
+
return undefined;
|
|
332
|
+
const known = this.acceptanceFiles.get(acceptanceId);
|
|
333
|
+
if (known !== undefined)
|
|
334
|
+
return await this.readOptional(known);
|
|
335
|
+
for (const file of await this.files()) {
|
|
336
|
+
const record = await this.read(path.join(this.root, file));
|
|
337
|
+
this.acceptanceFiles.set(record.acceptance_id, path.join(this.root, file));
|
|
338
|
+
if (record.acceptance_id === acceptanceId)
|
|
339
|
+
return record;
|
|
340
|
+
}
|
|
341
|
+
return undefined;
|
|
342
|
+
}
|
|
343
|
+
async pathForAcceptanceId(acceptanceId) {
|
|
344
|
+
const record = await this.findByAcceptanceId(acceptanceId);
|
|
345
|
+
if (record === undefined)
|
|
346
|
+
throw new Error("wake acceptance receipt is unavailable");
|
|
347
|
+
return this.fileFor(record.agent_id, record.delivery_id);
|
|
348
|
+
}
|
|
349
|
+
claimFor(record) { return path.join(this.root, `${createHash("sha256").update(record.agent_id).digest("hex")}.agent-claim`); }
|
|
350
|
+
lockFor(record) { return this.fileFor(record.agent_id, record.delivery_id).replace(/\.json$/u, ".transition-lock"); }
|
|
351
|
+
async acquireTransitionLock(record, ownerId) {
|
|
352
|
+
const target = this.lockFor(record);
|
|
353
|
+
const current = await this.readLockOptional(target);
|
|
354
|
+
if (current !== undefined && !sameNamespace(current, this.owner))
|
|
355
|
+
throw new WakeTransitionLockBlockedError();
|
|
356
|
+
if (current !== undefined && await this.ownerLiveness(current))
|
|
357
|
+
return undefined;
|
|
358
|
+
if (current !== undefined) {
|
|
359
|
+
await unlink(target);
|
|
360
|
+
await this.directory.sync();
|
|
361
|
+
}
|
|
362
|
+
const lock = { owner_id: ownerId, generation: randomUUID(), ...this.owner };
|
|
363
|
+
const temporary = path.join(this.root, `.lock-${randomUUID()}`);
|
|
364
|
+
try {
|
|
365
|
+
await this.writeNew(temporary, lock);
|
|
366
|
+
try {
|
|
367
|
+
await link(temporary, target);
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (error.code === "EEXIST")
|
|
371
|
+
return undefined;
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
await this.directory.sync();
|
|
375
|
+
return lock;
|
|
376
|
+
}
|
|
377
|
+
finally {
|
|
378
|
+
await unlink(temporary).catch(() => undefined);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
async assertTransitionLock(record, lock) {
|
|
382
|
+
const current = await this.readLock(this.lockFor(record)).catch(() => { throw new WakeExecutionClaimLostError(); });
|
|
383
|
+
if (current.owner_id !== lock.owner_id || current.generation !== lock.generation || current.pid !== lock.pid || current.process_start !== lock.process_start || current.boot_id !== lock.boot_id || !sameNamespace(current, lock))
|
|
384
|
+
throw new WakeExecutionClaimLostError();
|
|
385
|
+
}
|
|
386
|
+
async releaseTransitionLock(record, lock) {
|
|
387
|
+
const target = this.lockFor(record);
|
|
388
|
+
const current = await this.readLockOptional(target);
|
|
389
|
+
if (current !== undefined && current.owner_id === lock.owner_id && current.generation === lock.generation && current.pid === lock.pid && current.process_start === lock.process_start && current.boot_id === lock.boot_id && sameNamespace(current, lock)) {
|
|
390
|
+
await unlink(target);
|
|
391
|
+
await this.directory.sync();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
fileFor(agentId, deliveryId) {
|
|
395
|
+
return path.join(this.root, `${createHash("sha256").update(`${agentId}\u0000${deliveryId}`).digest("hex")}.json`);
|
|
396
|
+
}
|
|
397
|
+
async files() {
|
|
398
|
+
await this.verify();
|
|
399
|
+
const entries = await readdir(this.root);
|
|
400
|
+
const files = entries.filter((entry) => /^[a-f0-9]{64}\.json$/.test(entry));
|
|
401
|
+
if (files.length > MAX_WAKE_ACCEPTANCE_RECORDS || entries.length > MAX_WAKE_ACCEPTANCE_RECORDS + 128)
|
|
402
|
+
throw new Error("wake acceptance store exceeds its bounded record limit");
|
|
403
|
+
return files;
|
|
404
|
+
}
|
|
405
|
+
async claimFiles() { return (await readdir(this.root)).filter((entry) => /^[a-f0-9]{64}\.agent-claim$/.test(entry)); }
|
|
406
|
+
async readOptional(file) { try {
|
|
407
|
+
return await this.read(file);
|
|
408
|
+
}
|
|
409
|
+
catch (error) {
|
|
410
|
+
if (error.code === "ENOENT")
|
|
411
|
+
return undefined;
|
|
412
|
+
throw error;
|
|
413
|
+
} }
|
|
414
|
+
async read(file) {
|
|
415
|
+
const entry = await lstat(file);
|
|
416
|
+
if (!entry.isFile() || entry.isSymbolicLink() || entry.uid !== process.getuid?.() || (entry.mode & 0o777) !== 0o600 || entry.size > MAX_WAKE_ACCEPTANCE_RECORD_BYTES)
|
|
417
|
+
throw new Error("wake acceptance record is unsafe");
|
|
418
|
+
const bytes = await readFile(file);
|
|
419
|
+
if (bytes.length > MAX_WAKE_ACCEPTANCE_RECORD_BYTES)
|
|
420
|
+
throw new Error("wake acceptance record exceeds its bound");
|
|
421
|
+
return parseStoredWakeAcceptance(JSON.parse(bytes.toString("utf8")));
|
|
422
|
+
}
|
|
423
|
+
async readClaimOptional(file) { try {
|
|
424
|
+
return await this.readClaim(file);
|
|
425
|
+
}
|
|
426
|
+
catch (error) {
|
|
427
|
+
if (error.code === "ENOENT")
|
|
428
|
+
return undefined;
|
|
429
|
+
throw error;
|
|
430
|
+
} }
|
|
431
|
+
async readClaim(file) {
|
|
432
|
+
const entry = await lstat(file);
|
|
433
|
+
if (!entry.isFile() || entry.isSymbolicLink() || entry.uid !== process.getuid?.() || (entry.mode & 0o777) !== 0o600 || entry.size > 4096)
|
|
434
|
+
throw new Error("wake execution claim is unsafe");
|
|
435
|
+
const value = JSON.parse((await readFile(file)).toString("utf8"));
|
|
436
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
437
|
+
throw new Error("wake execution claim is invalid");
|
|
438
|
+
const record = value;
|
|
439
|
+
if (Object.keys(record).some((key) => !["acceptance_id", "owner_id", "generation", "expires_at", "acceptance_ids", "execution_id"].includes(key)) || !Object.hasOwn(record, "acceptance_id") || !Object.hasOwn(record, "owner_id") || !Object.hasOwn(record, "generation") || !Object.hasOwn(record, "expires_at"))
|
|
440
|
+
throw new Error("wake execution claim is invalid");
|
|
441
|
+
const members = record.acceptance_ids;
|
|
442
|
+
if ((members === undefined) !== (record.execution_id === undefined))
|
|
443
|
+
throw new Error("wake execution membership is invalid");
|
|
444
|
+
if (members !== undefined && (!Array.isArray(members) || members.length < 1 || members.length > 32 || members.some((member) => typeof member !== "string" || !uuid(member)) || !members.includes(record.acceptance_id) || new Set(members).size !== members.length || typeof record.execution_id !== "string" || !uuid(record.execution_id)))
|
|
445
|
+
throw new Error("wake execution membership is invalid");
|
|
446
|
+
const claim = { ...(members === undefined ? {} : { acceptance_ids: members, execution_id: string(record.execution_id) }), acceptance_id: string(record.acceptance_id), owner_id: string(record.owner_id), generation: string(record.generation), expires_at: timestamp(record.expires_at) };
|
|
447
|
+
if (!uuid(claim.acceptance_id) || !uuid(claim.owner_id) || !uuid(claim.generation))
|
|
448
|
+
throw new Error("wake execution claim is invalid");
|
|
449
|
+
return claim;
|
|
450
|
+
}
|
|
451
|
+
async readLockOptional(file) { try {
|
|
452
|
+
return await this.readLock(file);
|
|
453
|
+
}
|
|
454
|
+
catch (error) {
|
|
455
|
+
if (error.code === "ENOENT")
|
|
456
|
+
return undefined;
|
|
457
|
+
throw error;
|
|
458
|
+
} }
|
|
459
|
+
async readLock(file) {
|
|
460
|
+
const entry = await lstat(file);
|
|
461
|
+
if (!entry.isFile() || entry.isSymbolicLink() || entry.uid !== process.getuid?.() || (entry.mode & 0o777) !== 0o600 || entry.size > 1_024)
|
|
462
|
+
throw new Error("wake transition lock is unsafe");
|
|
463
|
+
const value = JSON.parse((await readFile(file)).toString("utf8"));
|
|
464
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
465
|
+
throw new Error("wake transition lock is invalid");
|
|
466
|
+
const lock = value;
|
|
467
|
+
if (Object.keys(lock).length !== 7 || !Object.hasOwn(lock, "owner_id") || !Object.hasOwn(lock, "generation") || !Object.hasOwn(lock, "pid") || !Object.hasOwn(lock, "process_start") || !Object.hasOwn(lock, "boot_id") || !Object.hasOwn(lock, "pid_namespace_dev") || !Object.hasOwn(lock, "pid_namespace_ino"))
|
|
468
|
+
throw new Error("wake transition lock is invalid");
|
|
469
|
+
const result = { owner_id: string(lock.owner_id), generation: string(lock.generation), pid: integer(lock.pid), process_start: string(lock.process_start), boot_id: string(lock.boot_id), pid_namespace_dev: integer(lock.pid_namespace_dev), pid_namespace_ino: integer(lock.pid_namespace_ino) };
|
|
470
|
+
if (!uuid(result.owner_id) || !uuid(result.generation) || result.pid < 1 || !result.process_start || !result.boot_id || result.pid_namespace_dev < 1 || result.pid_namespace_ino < 1)
|
|
471
|
+
throw new Error("wake transition lock is invalid");
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
async transitionNowClaimed(acceptanceId, claim) {
|
|
475
|
+
const record = await this.findByAcceptanceId(acceptanceId);
|
|
476
|
+
if (record === undefined)
|
|
477
|
+
throw new Error("wake acceptance receipt is unavailable");
|
|
478
|
+
const current = await this.readClaim(this.claimFor(record));
|
|
479
|
+
if (!(current.acceptance_id === acceptanceId || current.acceptance_ids?.includes(acceptanceId)) || current.acceptance_id !== claim.acceptance_id || current.owner_id !== claim.owner_id || current.generation !== claim.generation || current.expires_at !== claim.expires_at || expired(current, this.now()))
|
|
480
|
+
throw new WakeExecutionClaimLostError();
|
|
481
|
+
return record;
|
|
482
|
+
}
|
|
483
|
+
async compactTerminalRecords() {
|
|
484
|
+
const files = await this.files();
|
|
485
|
+
if (files.length < 2_112)
|
|
486
|
+
return;
|
|
487
|
+
const records = await Promise.all(files.map(async (file) => ({ file, record: await this.read(path.join(this.root, file)) })));
|
|
488
|
+
for (const file of terminalFilesToCompact(records.map(({ file, record }) => ({ file, state: record.state, updatedAt: record.updated_at, acceptanceId: record.acceptance_id })))) {
|
|
489
|
+
const record = records.find((candidate) => candidate.file === file)?.record;
|
|
490
|
+
if (record !== undefined)
|
|
491
|
+
this.acceptanceFiles.delete(record.acceptance_id);
|
|
492
|
+
await unlink(path.join(this.root, file));
|
|
493
|
+
}
|
|
494
|
+
await this.directory.sync();
|
|
495
|
+
}
|
|
496
|
+
async writeNew(file, record) {
|
|
497
|
+
const handle = await open(file, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | noFollow(), 0o600);
|
|
498
|
+
try {
|
|
499
|
+
await handle.writeFile(JSON.stringify(record));
|
|
500
|
+
await handle.sync();
|
|
501
|
+
}
|
|
502
|
+
finally {
|
|
503
|
+
await handle.close();
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
async replace(target, record) { await this.replaceValue(target, record); }
|
|
507
|
+
async replaceValue(target, record) {
|
|
508
|
+
const temporary = path.join(this.root, `.replace-${randomUUID()}`);
|
|
509
|
+
try {
|
|
510
|
+
await this.writeNew(temporary, record);
|
|
511
|
+
await rename(temporary, target);
|
|
512
|
+
await this.directory.sync();
|
|
513
|
+
}
|
|
514
|
+
finally {
|
|
515
|
+
await unlink(temporary).catch(() => undefined);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
async verify() {
|
|
519
|
+
await assertNoLinks(this.root);
|
|
520
|
+
const entry = await lstat(this.root);
|
|
521
|
+
const opened = await this.directory.stat();
|
|
522
|
+
if (!same(identity(entry), this.identity) || !same(identity(opened), this.identity) || (await realpath(this.root)) !== this.root)
|
|
523
|
+
throw new Error("wake acceptance store changed after validation");
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
export class WakeInboxFullError extends Error {
|
|
527
|
+
constructor() { super("wake acceptance store has no capacity without deleting active work"); }
|
|
528
|
+
}
|
|
529
|
+
export class WakeAcceptanceConflictError extends Error {
|
|
530
|
+
constructor() { super("delivery id is already bound to a different request"); }
|
|
531
|
+
}
|
|
532
|
+
export class WakeExecutionClaimLostError extends Error {
|
|
533
|
+
constructor() { super("wake execution claim was lost"); }
|
|
534
|
+
}
|
|
535
|
+
/** A container boundary requires deployment-authorized offline reconciliation. */
|
|
536
|
+
export { WakeTransitionLockBlockedError } from "./wakeAcceptanceProcessIdentity.js";
|
|
537
|
+
export { publicAcceptance } from "./wakeAcceptanceRecord.js";
|
|
538
|
+
function string(value) { if (typeof value !== "string")
|
|
539
|
+
throw new Error("wake acceptance record is invalid"); return value; }
|
|
540
|
+
function integer(value) { if (typeof value !== "number" || !Number.isSafeInteger(value))
|
|
541
|
+
throw new Error("wake transition lock is invalid"); return value; }
|
|
542
|
+
function timestamp(value) { const result = string(value); if (Number.isNaN(Date.parse(result)) || new Date(result).toISOString() !== result)
|
|
543
|
+
throw new Error("wake acceptance record is invalid"); return result; }
|
|
544
|
+
function uuid(value) { return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(value); }
|
|
545
|
+
function isTerminal(state) { return state === "completed" || state === "failed" || state === "stopped"; }
|
|
546
|
+
function expired(claim, now) { return Date.parse(claim.expires_at) <= now; }
|
|
547
|
+
function identity(value) {
|
|
548
|
+
const numeric = value;
|
|
549
|
+
return { dev: numeric.dev, ino: numeric.ino, uid: numeric.uid, mode: numeric.mode & 0o7777 };
|
|
550
|
+
}
|
|
551
|
+
function same(left, right) { return left.dev === right.dev && left.ino === right.ino && left.uid === right.uid && left.mode === right.mode; }
|
|
552
|
+
function noFollow() { return constants.O_NOFOLLOW ?? 0; }
|
|
553
|
+
function directoryFlag() { return constants.O_DIRECTORY ?? 0; }
|
|
554
|
+
async function assertNoLinks(target) { let current = path.parse(target).root; for (const part of path.relative(current, target).split(path.sep).filter(Boolean)) {
|
|
555
|
+
current = path.join(current, part);
|
|
556
|
+
if ((await lstat(current)).isSymbolicLink() && current !== "/var")
|
|
557
|
+
throw new Error("wake acceptance store path contains a symlink");
|
|
558
|
+
} }
|