@tangle-network/agent-runtime 0.240.0 → 0.247.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/dist/{activation-q224yRQK.js → activation-DYqnl8zq.js} +3 -3
- package/dist/{activation-q224yRQK.js.map → activation-DYqnl8zq.js.map} +1 -1
- package/dist/{activation-CtkpoWet.d.ts → activation-DizpINK3.d.ts} +115 -5
- package/dist/agent.d.ts +2 -2
- package/dist/agent.js +2 -2
- package/dist/candidate-execution/index.js +7 -7
- package/dist/candidate-execution/index.js.map +1 -1
- package/dist/{coordination-driver-CMprWr0k.js → coordination-driver-BV4AAUns.js} +35 -14
- package/dist/coordination-driver-BV4AAUns.js.map +1 -0
- package/dist/{delegate-kwBecu_w.js → delegate-DQAzB5Xv.js} +2 -2
- package/dist/{delegate-kwBecu_w.js.map → delegate-DQAzB5Xv.js.map} +1 -1
- package/dist/{durable-file-D24y9zg7.js → durable-file-DWQA4ooo.js} +2 -2
- package/dist/{durable-file-D24y9zg7.js.map → durable-file-DWQA4ooo.js.map} +1 -1
- package/dist/durable.d.ts +2 -2
- package/dist/durable.js +3 -3
- package/dist/{graph-Bke7I2gs.js → graph-DcBmMLIp.js} +3 -3
- package/dist/{graph-Bke7I2gs.js.map → graph-DcBmMLIp.js.map} +1 -1
- package/dist/{improvement-cycle-BpSVwIJw.js → improvement-cycle-B049YmQ8.js} +458 -60
- package/dist/improvement-cycle-B049YmQ8.js.map +1 -0
- package/dist/{index-CbZaoYbD.d.ts → index-DLzlXwr6.d.ts} +14 -9
- package/dist/index.d.ts +11 -8
- package/dist/index.js +27 -17
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +7 -5
- package/dist/intelligence.js +15 -11
- package/dist/intelligence.js.map +1 -1
- package/dist/kernel.d.ts +3 -3
- package/dist/kernel.js +9 -9
- package/dist/{loop-runner-bin-BUkkPt10.d.ts → loop-runner-bin-HbMECmxT.d.ts} +3 -3
- package/dist/{loop-runner-bin-DU8XqsGN.js → loop-runner-bin-iqq1azfy.js} +3 -3
- package/dist/{loop-runner-bin-DU8XqsGN.js.map → loop-runner-bin-iqq1azfy.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +5 -5
- package/dist/mcp/index.js +4 -4
- package/dist/{openai-tools-BI1ofIfL.d.ts → openai-tools-DvLk_Ddg.d.ts} +2 -2
- package/dist/{prepare-Dc30WRB0.js → prepare-CibQrhfi.js} +28 -28
- package/dist/prepare-CibQrhfi.js.map +1 -0
- package/dist/profiles.d.ts +2 -2
- package/dist/{protected-model-port-D5gDcnrH.js → protected-model-port-Dhdi5mDl.js} +3 -3
- package/dist/{protected-model-port-D5gDcnrH.js.map → protected-model-port-Dhdi5mDl.js.map} +1 -1
- package/dist/{protected-redaction-wGo44k2K.js → protected-redaction-Fn1ETfJ-.js} +6 -6
- package/dist/protected-redaction-Fn1ETfJ-.js.map +1 -0
- package/dist/{provision-supervisor-DoSrqsM7.js → provision-supervisor-BgQx2Avp.js} +5 -5
- package/dist/{provision-supervisor-DoSrqsM7.js.map → provision-supervisor-BgQx2Avp.js.map} +1 -1
- package/dist/{run-layout-hZREkcfu.js → run-layout-hKAJGF4g.js} +7 -2
- package/dist/run-layout-hKAJGF4g.js.map +1 -0
- package/dist/{runtime-CmuAQsWI.js → runtime-HpTXhB3g.js} +16 -13
- package/dist/{runtime-CmuAQsWI.js.map → runtime-HpTXhB3g.js.map} +1 -1
- package/dist/{server-shkdLqls.js → server-OOE7mXrN.js} +3 -3
- package/dist/{server-shkdLqls.js.map → server-OOE7mXrN.js.map} +1 -1
- package/dist/{stream-agent-turn-DayHmtvw.d.ts → stream-agent-turn-CcumM0Bu.d.ts} +2 -2
- package/dist/{structural-rollout-CW67upUV.js → structural-rollout-z1A0okaB.js} +2 -2
- package/dist/{structural-rollout-CW67upUV.js.map → structural-rollout-z1A0okaB.js.map} +1 -1
- package/dist/{substrate-iQOskmQ_.d.ts → substrate-CQ0hfewn.d.ts} +2 -2
- package/dist/{supervise-DzoCYAe-.js → supervise-DZEOpzRw.js} +148 -35
- package/dist/supervise-DZEOpzRw.js.map +1 -0
- package/dist/{supervisor-CFSPj8rx.js → supervisor-BIBWUFUr.js} +325 -150
- package/dist/supervisor-BIBWUFUr.js.map +1 -0
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +398 -398
- package/dist/{top-app-CMMd8DgR.js → top-app-d-bmwO7O.js} +2 -2
- package/dist/{top-app-CMMd8DgR.js.map → top-app-d-bmwO7O.js.map} +1 -1
- package/dist/tui/bin.js +1 -1
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +2 -2
- package/dist/{types-CEma9LKR.d.ts → types-BUhz284C.d.ts} +25 -11
- package/dist/{workspace-archive-CBX0hwL_.js → workspace-archive-DSRT4Tro.js} +8 -8
- package/dist/workspace-archive-DSRT4Tro.js.map +1 -0
- package/package.json +6 -6
- package/dist/coordination-driver-CMprWr0k.js.map +0 -1
- package/dist/improvement-cycle-BpSVwIJw.js.map +0 -1
- package/dist/prepare-Dc30WRB0.js.map +0 -1
- package/dist/protected-redaction-wGo44k2K.js.map +0 -1
- package/dist/run-layout-hZREkcfu.js.map +0 -1
- package/dist/supervise-DzoCYAe-.js.map +0 -1
- package/dist/supervisor-CFSPj8rx.js.map +0 -1
- package/dist/workspace-archive-CBX0hwL_.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["fsConstants"],"sources":["../../src/candidate-execution/builder.ts","../../src/candidate-execution/claim-file-store.ts","../../src/candidate-execution/dispose.ts","../../src/candidate-execution/protected-model-grant.ts","../../src/candidate-execution/recover.ts","../../src/candidate-execution/workspace-tree.ts"],"sourcesContent":["import type { CodeSurface } from '@tangle-network/agent-eval/campaign'\nimport { verifyCodeSurface } from '@tangle-network/agent-eval/campaign'\nimport type {\n AgentCandidateCodeDisabled,\n AgentCandidateCodeNoOp,\n AgentCandidateExecution,\n AgentCandidateGitHubRepository,\n AgentCandidateKnowledge,\n AgentCandidateMemoryPolicy,\n AgentCandidateProfile,\n AgentProfile,\n AgentProfileDiff,\n} from '@tangle-network/agent-interface'\nimport { type AgentCandidateBundleInput, sealAgentCandidateBundle } from './bundle'\nimport { embeddedCandidateArtifact } from './digest'\nimport {\n applyExactAgentProfileDiff,\n freezeGenericAgentCandidateProfile,\n parseExactAgentProfile,\n parseExactAgentProfileDiff,\n parseExactCandidateProfile,\n} from './profile'\n\n/** A complete profile that can be frozen without losing behavior. */\nexport type AgentCandidateProfileSource =\n | {\n kind: 'profile'\n profile: AgentProfile\n }\n | {\n kind: 'profile-diffs'\n base: AgentProfile\n /** Applied in order before the resulting profile is frozen into the bundle. */\n diffs: readonly AgentProfileDiff[]\n }\n | {\n kind: 'candidate-profile'\n /** Already converted to the closed, secret-free candidate profile contract. */\n profile: AgentCandidateProfile\n }\n\n/** The only accepted path from an agent-eval code candidate to executable bytes. */\nexport interface AgentCandidateCodeSurfaceSource {\n kind: 'code-surface'\n surface: CodeSurface\n repository: AgentCandidateGitHubRepository\n /** Optional parent directory used to resolve a relative `surface.worktreeRef`. */\n worktreeDir?: string\n}\n\n/** Explicit control/no-op code or one finalized CodeSurface whose bytes must still verify. */\nexport type AgentCandidateCodeSource =\n | AgentCandidateCodeDisabled\n | AgentCandidateCodeNoOp\n | AgentCandidateCodeSurfaceSource\n\n/** Complete measured surfaces and execution policy compiled into one candidate bundle. */\nexport interface BuildAgentCandidateBundleInput {\n profile: AgentCandidateProfileSource\n code: AgentCandidateCodeSource\n execution: AgentCandidateExecution\n knowledge?: AgentCandidateKnowledge\n memory: AgentCandidateMemoryPolicy\n}\n\n/**\n * Compile one measured profile/code candidate into the immutable execution\n * contract. Code bytes are re-read and verified by agent-eval before they are\n * embedded. The returned bundle is schema-validated, canonically digested, and\n * deeply immutable; call `verifyAgentCandidateBundle` at the execution boundary\n * to re-read external memory, repository, and workspace artifacts.\n */\nexport function buildAgentCandidateBundle(\n input: BuildAgentCandidateBundleInput,\n): ReturnType<typeof sealAgentCandidateBundle> {\n const bundle: AgentCandidateBundleInput = {\n kind: 'agent-candidate-bundle',\n digestAlgorithm: 'rfc8785-sha256',\n profile: compileCandidateProfile(input.profile),\n code: compileCandidateCode(input.code),\n execution: input.execution,\n ...(input.knowledge !== undefined ? { knowledge: input.knowledge } : {}),\n memory: input.memory,\n }\n return sealAgentCandidateBundle(bundle)\n}\n\nfunction compileCandidateProfile(source: AgentCandidateProfileSource): AgentCandidateProfile {\n if (source.kind === 'candidate-profile') {\n return parseExactCandidateProfile(source.profile)\n }\n\n if (source.kind === 'profile') {\n return freezeGenericAgentCandidateProfile(source.profile)\n }\n\n if (source.kind !== 'profile-diffs') {\n throw new Error(\n `unsupported candidate profile source: ${String((source as { kind?: unknown }).kind)}`,\n )\n }\n if (source.diffs.length === 0) {\n throw new Error('profile-diffs source requires at least one AgentProfileDiff')\n }\n let profile = parseExactAgentProfile(source.base, 'base profile')\n for (const [index, inputDiff] of source.diffs.entries()) {\n const diff = parseExactAgentProfileDiff(inputDiff, `profile diff ${index}`)\n profile = applyExactAgentProfileDiff(profile, diff, `profile diff ${index}`)\n }\n return freezeGenericAgentCandidateProfile(profile)\n}\n\nfunction compileCandidateCode(source: AgentCandidateCodeSource): AgentCandidateBundleInput['code'] {\n if (source.kind === 'disabled' || source.kind === 'no-op') return source\n if (source.kind !== 'code-surface') {\n throw new Error(\n `unsupported candidate code source: ${String((source as { kind?: unknown }).kind)}`,\n )\n }\n\n const verified = verifyCodeSurface(source.surface, source.worktreeDir)\n const patch = embeddedCandidateArtifact(verified.patchBytes)\n if (\n patch.sha256 !== source.surface.patch.sha256 ||\n patch.byteLength !== source.surface.patch.byteLength\n ) {\n throw new Error('verified CodeSurface patch bytes do not match its content identity')\n }\n return {\n kind: 'git-patch',\n repository: source.repository,\n baseCommit: source.surface.baseCommit,\n baseTree: source.surface.baseTree,\n candidateTree: source.surface.candidateTree,\n patch: { format: 'git-diff-binary', artifact: patch },\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { linkSync } from 'node:fs'\nimport { mkdir, open, unlink } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { Sha256Digest } from '@tangle-network/agent-interface'\n\nimport {\n type AgentCandidateExecutionAttemptRecord,\n type AgentCandidateExecutionAttemptRef,\n type AgentCandidateExecutionClaim,\n type AgentCandidateExecutionClaimResult,\n type AgentCandidateExecutionClaimStore,\n type AgentCandidateExecutionFinishResult,\n type AgentCandidateExecutionLease,\n type AgentCandidateExecutionPhase,\n type AgentCandidateExecutionPhaseResult,\n type AgentCandidateExecutionRecoveryEvidence,\n type AgentCandidateExecutionStageResult,\n type AgentCandidateExecutionTerminalRecord,\n type AgentCandidateExecutionTerminalResult,\n type AgentCandidateRetryRejection,\n candidateClaimFileInternals,\n} from './claim'\nimport {\n assertRecoveryMatchesStaged,\n assertTerminalAllowedInPhase,\n assertTerminalMatchesClaim,\n assertTerminalMatchesStaged,\n recoveredTerminalRecord,\n rejectedFinish,\n rejectedStage,\n requireStagedTerminal,\n sealTerminalDigest,\n terminalRecord,\n} from './claim-terminal'\nimport { canonicalCandidateBytes } from './digest'\n\nconst {\n assertExpiredLease,\n assertLease,\n assertSameSlot,\n assertUnexpiredLease,\n attemptRecord,\n claimSlot,\n leaseDigest,\n newLease,\n readClaim,\n readClaimIfPresent,\n readTerminal,\n readTerminalIfPresent,\n readTransitionIfPresent,\n rejectedExistingClaim,\n rejectedRetry,\n retryRejection,\n sealAttemptRef,\n sealClaim,\n sealLease,\n} = candidateClaimFileInternals\n\nexport interface FileAgentCandidateExecutionClaimStoreOptions {\n /** Evaluator-owned directory shared by every process allowed to execute candidates. */\n directory: string\n /** Testable evaluator clock; defaults to `Date.now`. */\n now?: () => number\n}\n\n/** Cross-process lifecycle implemented as fsynced, create-if-absent records. */\nexport class FileAgentCandidateExecutionClaimStore implements AgentCandidateExecutionClaimStore {\n private readonly directory: string\n private readonly now: () => number\n\n constructor(options: FileAgentCandidateExecutionClaimStoreOptions) {\n if (options.directory.length === 0) {\n throw new Error('candidate execution claim directory must not be empty')\n }\n this.directory = options.directory\n this.now = options.now ?? Date.now\n }\n\n async tryClaim(\n requested: AgentCandidateExecutionClaim,\n ): Promise<AgentCandidateExecutionClaimResult> {\n const claim = sealClaim(requested)\n await mkdir(this.directory, { recursive: true })\n const claimPath = this.claimPath(claim)\n const existing = await readClaimIfPresent(claimPath)\n if (existing) {\n assertSameSlot(existing.claim, claim, claimPath)\n return rejectedExistingClaim(existing.claim, claim)\n }\n assertUnexpiredLease(claim.leaseExpiresAtMs, this.now())\n const retryFailure = await this.retryFailure(claim)\n if (retryFailure) return rejectedRetry(claim, retryFailure)\n\n const lease = newLease(claim)\n const acquired = await writeRecordIfAbsent(this.directory, claimPath, {\n ...claim,\n phase: 'claimed',\n leaseDigest: leaseDigest(lease),\n })\n if (acquired) return Object.freeze({ acquired: true, claim, lease })\n\n const winner = await readClaim(claimPath)\n assertSameSlot(winner.claim, claim, claimPath)\n return rejectedExistingClaim(winner.claim, claim)\n }\n\n async getAttempt(\n requestedAttempt: AgentCandidateExecutionAttemptRef,\n ): Promise<AgentCandidateExecutionAttemptRecord | undefined> {\n return await this.storedAttempt(sealAttemptRef(requestedAttempt))\n }\n\n async markCandidateMayRun(\n requestedLease: AgentCandidateExecutionLease,\n ): Promise<AgentCandidateExecutionPhaseResult> {\n const lease = sealLease(requestedLease)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const state = await this.transitionState(stored.claim)\n if (state.phase === 'candidate-may-run') {\n return Object.freeze({ marked: false, phase: 'candidate-may-run' })\n }\n if (state.staged) {\n throw new Error('candidate execution terminal was staged before candidate-may-run phase')\n }\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const marked = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(stored.claim, 1),\n {\n kind: 'candidate-execution-phase',\n executionId: stored.claim.executionId,\n attempt: stored.claim.attempt,\n executionPlanDigest: stored.claim.executionPlanDigest,\n phase: 'candidate-may-run',\n },\n this.ownerPublication(stored.claim),\n )\n if (marked) return Object.freeze({ marked: true, phase: 'candidate-may-run' })\n const winner = await this.transitionState(stored.claim)\n if (winner.phase === 'candidate-may-run') {\n return Object.freeze({ marked: false, phase: 'candidate-may-run' })\n }\n throw new Error('candidate execution terminal was staged before candidate-may-run phase')\n }\n\n async stageTerminal(\n requestedLease: AgentCandidateExecutionLease,\n result: AgentCandidateExecutionTerminalResult,\n ): Promise<AgentCandidateExecutionStageResult> {\n const lease = sealLease(requestedLease)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const terminal = terminalRecord(stored.claim, result)\n const state = await this.transitionState(stored.claim)\n if (state.staged) return rejectedStage(state.staged, terminal)\n assertTerminalAllowedInPhase(state.phase, terminal)\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const transition = state.phase === 'claimed' ? 1 : 2\n const staged = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(stored.claim, transition),\n {\n kind: 'candidate-execution-pending-terminal',\n terminal,\n },\n this.ownerPublication(stored.claim),\n )\n if (staged) return Object.freeze({ staged: true, terminal })\n const winner = await this.transitionState(stored.claim)\n if (!winner.staged) {\n throw new Error('candidate execution phase transition won while staging terminal')\n }\n return rejectedStage(winner.staged, terminal)\n }\n\n async finish(\n requestedLease: AgentCandidateExecutionLease,\n requestedTerminalDigest: Sha256Digest,\n ): Promise<AgentCandidateExecutionFinishResult> {\n const lease = sealLease(requestedLease)\n const terminalDigest = sealTerminalDigest(requestedTerminalDigest)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const state = await this.transitionState(stored.claim)\n const staged = requireStagedTerminal(state.staged, terminalDigest)\n const terminalPath = this.terminalPath(lease)\n const existing = await readTerminalIfPresent(terminalPath)\n if (existing) {\n assertTerminalMatchesClaim(existing, stored.claim, terminalPath)\n assertTerminalMatchesStaged(existing, staged, terminalPath)\n return rejectedFinish(existing, terminalDigest)\n }\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const finished = await writeRecordIfAbsent(\n this.directory,\n terminalPath,\n {\n terminal: staged,\n },\n this.ownerPublication(stored.claim),\n )\n if (finished) return Object.freeze({ finished: true, terminal: staged })\n const winner = await readTerminal(terminalPath)\n assertSameSlot(winner, lease, terminalPath)\n assertTerminalMatchesClaim(winner, stored.claim, terminalPath)\n assertTerminalMatchesStaged(winner, staged, terminalPath)\n return rejectedFinish(winner, terminalDigest)\n }\n\n async recoverExpired(\n requestedAttempt: AgentCandidateExecutionAttemptRef,\n evidence: AgentCandidateExecutionRecoveryEvidence,\n ): Promise<AgentCandidateExecutionFinishResult> {\n const attempt = sealAttemptRef(requestedAttempt)\n const record = await this.storedAttempt(attempt)\n if (!record) throw new Error('candidate execution recovery does not name an acquired attempt')\n const recovered = recoveredTerminalRecord(record.claim, record.phase, evidence)\n if (record.staged) assertRecoveryMatchesStaged(record.staged, recovered)\n const requestedDigest = record.staged?.terminalDigest ?? recovered.terminalDigest\n if (record.terminal) return rejectedFinish(record.terminal, requestedDigest)\n assertExpiredLease(record.claim.leaseExpiresAtMs, this.now())\n\n let staged = record.staged\n if (!staged) {\n const transition = record.phase === 'claimed' ? 1 : 2\n const didStage = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(record.claim, transition),\n {\n kind: 'candidate-execution-pending-terminal',\n terminal: recovered,\n },\n )\n if (didStage) {\n staged = recovered\n } else {\n const winner = await this.transitionState(record.claim)\n if (!winner.staged) {\n throw new Error(\n 'candidate execution recovery lost terminal staging to a phase transition',\n )\n }\n assertRecoveryMatchesStaged(winner.staged, recovered)\n staged = winner.staged\n }\n }\n\n const terminalPath = this.terminalPath(attempt)\n const didFinish = await writeRecordIfAbsent(this.directory, terminalPath, {\n terminal: staged,\n })\n if (didFinish) return Object.freeze({ finished: true, terminal: staged })\n const winner = await readTerminal(terminalPath)\n assertSameSlot(winner, attempt, terminalPath)\n assertTerminalMatchesClaim(winner, record.claim, terminalPath)\n assertTerminalMatchesStaged(winner, staged, terminalPath)\n return rejectedFinish(winner, staged.terminalDigest)\n }\n\n private async storedAttempt(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ): Promise<AgentCandidateExecutionAttemptRecord | undefined> {\n const claimPath = this.claimPath(claim)\n const stored = await readClaimIfPresent(claimPath)\n if (!stored) return undefined\n assertSameSlot(stored.claim, claim, claimPath)\n const terminalPath = this.terminalPath(claim)\n const terminal = await readTerminalIfPresent(terminalPath)\n // Terminal publication follows its immutable staged outbox, so read that prerequisite later.\n const state = await this.transitionState(stored.claim)\n if (terminal) {\n assertTerminalMatchesClaim(terminal, stored.claim, terminalPath)\n if (!state.staged) {\n throw new Error(\n `candidate execution terminal record at ${terminalPath} has no staged outbox`,\n )\n }\n assertTerminalMatchesStaged(terminal, state.staged, terminalPath)\n }\n return attemptRecord(stored.claim, state.phase, state.staged, terminal)\n }\n\n private async transitionState(claim: AgentCandidateExecutionClaim): Promise<{\n phase: AgentCandidateExecutionPhase\n staged?: AgentCandidateExecutionTerminalRecord\n }> {\n const firstPath = this.transitionPath(claim, 1)\n const first = await readTransitionIfPresent(firstPath, claim)\n if (!first) return { phase: 'claimed' }\n if (first.kind === 'pending') return { phase: 'claimed', staged: first.terminal }\n const secondPath = this.transitionPath(claim, 2)\n const second = await readTransitionIfPresent(secondPath, claim)\n if (!second) return { phase: 'candidate-may-run' }\n if (second.kind !== 'pending') {\n throw new Error(`candidate execution transition at ${secondPath} repeats the phase marker`)\n }\n return { phase: 'candidate-may-run', staged: second.terminal }\n }\n\n private async retryFailure(\n claim: AgentCandidateExecutionClaim,\n ): Promise<AgentCandidateRetryRejection | undefined> {\n if (claim.attempt === 1) return undefined\n return retryRejection(\n claim,\n await this.storedAttempt({\n executionId: claim.executionId,\n attempt: claim.attempt - 1,\n }),\n )\n }\n\n private ownerPublication(claim: AgentCandidateExecutionClaim): {\n authorizePublish: () => true\n } {\n return {\n authorizePublish: () => {\n assertUnexpiredLease(claim.leaseExpiresAtMs, this.now())\n return true\n },\n }\n }\n\n private claimPath(claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>): string {\n return join(this.directory, `${claimSlot(claim)}.claim.json`)\n }\n\n private terminalPath(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ): string {\n return join(this.directory, `${claimSlot(claim)}.terminal.json`)\n }\n\n private transitionPath(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ordinal: 1 | 2,\n ): string {\n return join(this.directory, `${claimSlot(claim)}.transition-${ordinal}.json`)\n }\n}\n\n/**\n * Candidate records keep this async writer because lease authorization must run after the\n * asynchronous temp-file fsync and immediately before synchronous link publication. The\n * supervisor durability helper is synchronous and has no lease hook, so combining them would\n * either move authorization earlier or add an async race to the claim boundary.\n */\nasync function writeRecordIfAbsent(\n directory: string,\n destination: string,\n record: object,\n options: {\n /** Synchronous authorization checked after temp fsync, immediately before atomic publication. */\n authorizePublish?: () => true\n } = {},\n): Promise<boolean> {\n const temporaryPath = join(directory, `.candidate-execution-${process.pid}-${randomUUID()}.tmp`)\n const handle = await open(temporaryPath, 'wx', 0o600)\n try {\n await handle.writeFile(\n Buffer.concat([Buffer.from(canonicalCandidateBytes(record)), Buffer.from('\\n')]),\n )\n await handle.sync()\n } finally {\n await handle.close()\n }\n\n let written = false\n try {\n if (options.authorizePublish && options.authorizePublish() !== true) {\n throw new Error('candidate execution record publication was not authorized')\n }\n // Authorization and the atomic filesystem call are one synchronous critical\n // section so the event loop cannot advance an injected lease clock between them.\n linkSync(temporaryPath, destination)\n written = true\n await syncDirectory(directory)\n } catch (error) {\n if (!isNodeError(error, 'EEXIST')) throw error\n } finally {\n await unlink(temporaryPath).catch((error: unknown) => {\n if (!isNodeError(error, 'ENOENT')) throw error\n })\n }\n return written\n}\n\nasync function syncDirectory(directory: string): Promise<void> {\n const handle = await open(directory, 'r')\n try {\n await handle.sync()\n } finally {\n await handle.close()\n }\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return (\n error !== null &&\n typeof error === 'object' &&\n 'code' in error &&\n (error as { code?: unknown }).code === code\n )\n}\n","import { candidateCleanupDeadline, withinCandidateCleanupDeadline } from './cleanup'\nimport { sealAgentCandidateModelSettlement } from './model-settlement'\nimport {\n assertPreparedCandidateIntegrity,\n beginPreparedCandidateDisposal,\n consumePreparedCandidateExecution,\n} from './prepared-state'\nimport type { PreparedAgentCandidateExecution } from './types'\n\nexport interface DisposePreparedAgentCandidateOptions {\n cleanupTimeoutMs?: number\n}\n\n/** Revoke reservations held by a prepared candidate that will not be executed. */\nexport async function disposePreparedAgentCandidateExecution(\n prepared: PreparedAgentCandidateExecution,\n options: DisposePreparedAgentCandidateOptions = {},\n): Promise<{ disposed: true }> {\n const initialState = assertPreparedCandidateIntegrity(prepared)\n const cleanupTimeoutMs = options.cleanupTimeoutMs ?? initialState.cleanupTimeoutMs\n if (cleanupTimeoutMs > initialState.cleanupTimeoutMs) {\n throw new Error('disposal cleanup timeout exceeds the frozen preparation bound')\n }\n const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs)\n const state = beginPreparedCandidateDisposal(prepared)\n const cleanup: Array<Promise<unknown>> = []\n\n if (state.memory.mode === 'isolated') {\n const reservation = state.memoryReservation\n if (!reservation) throw new Error('isolated memory reservation is missing')\n cleanup.push(\n withinCandidateCleanupDeadline(\n async () => {\n const closed = await state.ports.memory.close({\n executionId: state.executionId,\n preparationId: reservation.preparationId,\n accessDigest: reservation.accessDigest,\n effectiveNamespace: reservation.effectiveNamespace,\n reason: 'abandoned',\n })\n if (closed.closed !== true || Object.keys(closed).some((key) => key !== 'closed')) {\n throw new Error('abandoned isolated memory access did not acknowledge closure')\n }\n },\n cleanupDeadlineAtMs,\n 'isolated memory disposal',\n ),\n )\n }\n\n cleanup.push(\n withinCandidateCleanupDeadline(\n async () => {\n const settlement = sealAgentCandidateModelSettlement(\n await state.ports.models.settleGrant({\n executionId: state.executionId,\n preparationId: state.preparationId,\n grantDigest: state.modelReservation.digest,\n resolved: state.resolvedModel,\n reason: 'abandoned',\n }),\n {\n preparationId: state.preparationId,\n grantDigest: state.modelReservation.digest,\n model: state.resolvedModel.model,\n },\n )\n if (settlement.usage.modelCalls !== 0) {\n throw new Error('unexecuted model reservation unexpectedly contains calls')\n }\n },\n cleanupDeadlineAtMs,\n 'model reservation disposal',\n ),\n )\n\n const results = await Promise.allSettled(cleanup)\n const failures = results\n .filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n .map((result) => result.reason)\n if (failures.length > 0) {\n consumePreparedCandidateExecution(prepared, 'disposal-failed')\n throw new AggregateError(failures, 'candidate preparation disposal failed')\n }\n\n consumePreparedCandidateExecution(prepared, 'disposed')\n return Object.freeze({ disposed: true as const })\n}\n","import type { AgentCandidateResolvedModel } from '@tangle-network/agent-interface'\n\nimport type {\n AgentCandidateModelGrantActivateInput,\n AgentCandidateModelGrantReserveInput,\n AgentCandidateModelGrantSettleInput,\n} from './protected-model-port'\nimport type {\n AgentCandidateModelPort,\n AgentCandidateProtectedModelActivation,\n AgentCandidateProtectedModelReservation,\n AgentCandidateProtectedModelSettlement,\n} from './types'\n\n/** Reservation fields supplied by a caller before Runtime resolves the model. */\nexport type AgentCandidateModelGrantRunReservationInput = Omit<\n AgentCandidateModelGrantReserveInput,\n 'resolved'\n>\n\n/** Values available only while one protected model grant is active. */\nexport interface ProtectedAgentCandidateModelGrantContext {\n readonly activation: AgentCandidateProtectedModelActivation\n readonly reservation: AgentCandidateProtectedModelReservation\n readonly resolved: AgentCandidateResolvedModel\n}\n\n/** Inputs for one protected grant scoped to one bounded caller unit. */\nexport interface RunProtectedAgentCandidateModelGrantOptions<TResult> {\n /** Runtime port that validates and settles the evaluator-owned grant. */\n readonly port: AgentCandidateModelPort\n /** Provider-neutral model request resolved before any grant is reserved. */\n readonly resolve: Parameters<AgentCandidateModelPort['resolve']>[0]\n /** One bounded unit's immutable identity, attempt, expiry, and limits. */\n readonly reserve: AgentCandidateModelGrantRunReservationInput\n /** Must be no later than the reservation expiry. */\n readonly deadlineAtMs: AgentCandidateModelGrantActivateInput['deadlineAtMs']\n /** Execute exactly one bounded unit while the activated environment is valid. */\n readonly execute: (context: ProtectedAgentCandidateModelGrantContext) => Promise<TResult>\n}\n\n/** Result and sealed settlement returned after one protected grant closes. */\nexport interface RunProtectedAgentCandidateModelGrantResult<TResult> {\n readonly value: TResult\n readonly resolved: AgentCandidateResolvedModel\n readonly reservation: AgentCandidateProtectedModelReservation\n readonly settlement: AgentCandidateProtectedModelSettlement\n}\n\nconst SETTLEMENT_RETRY_INITIAL_DELAY_MS = 25\nconst SETTLEMENT_RETRY_MAX_DELAY_MS = 1_000\n\n/**\n * Run one bounded unit under a protected model grant.\n *\n * Runtime owns the grant lifecycle; callers own the unit boundary and any\n * durable scheduling or accounting around it. A reserved grant is settled\n * after activation failure or callback failure, and the callback error is\n * preserved when settlement also fails.\n */\nexport async function runProtectedAgentCandidateModelGrant<TResult>(\n options: RunProtectedAgentCandidateModelGrantOptions<TResult>,\n): Promise<RunProtectedAgentCandidateModelGrantResult<TResult>> {\n if (typeof options.execute !== 'function') {\n throw new TypeError('protected model grant execute callback is required')\n }\n\n const resolved = await options.port.resolve(options.resolve)\n const reservation = await options.port.reserveGrant({\n ...options.reserve,\n resolved,\n })\n\n let value!: TResult\n let executionError: unknown\n let executionFailed = false\n let activated = false\n let reason: AgentCandidateModelGrantSettleInput['reason'] = 'preparation-failed'\n\n try {\n const activation = await options.port.activateGrant({\n executionId: options.reserve.executionId,\n preparationId: options.reserve.preparationId,\n grantDigest: reservation.digest,\n resolved,\n deadlineAtMs: options.deadlineAtMs,\n })\n activated = true\n value = await options.execute({ activation, reservation, resolved })\n reason = 'completed'\n } catch (error) {\n executionError = error\n executionFailed = true\n if (activated) reason = 'failed'\n }\n\n let settlement: AgentCandidateProtectedModelSettlement\n try {\n settlement = await settleProtectedModelGrant(options, {\n executionId: options.reserve.executionId,\n preparationId: options.reserve.preparationId,\n grantDigest: reservation.digest,\n resolved,\n reason,\n })\n } catch (settlementError) {\n if (executionFailed) {\n throw new AggregateError(\n [executionError, settlementError],\n 'protected model execution failed and its grant did not settle',\n )\n }\n throw settlementError\n }\n\n if (executionFailed) throw executionError\n return { value, resolved, reservation, settlement }\n}\n\nasync function settleProtectedModelGrant<TResult>(\n options: RunProtectedAgentCandidateModelGrantOptions<TResult>,\n input: AgentCandidateModelGrantSettleInput,\n): Promise<AgentCandidateProtectedModelSettlement> {\n let delayMs = SETTLEMENT_RETRY_INITIAL_DELAY_MS\n for (;;) {\n try {\n return await options.port.settleGrant(input)\n } catch (error) {\n if (!isCandidateGrantDrainingError(error)) throw error\n const remainingMs = options.deadlineAtMs - Date.now()\n if (remainingMs <= 0) throw error\n await waitForSettlementRetry(Math.min(delayMs, remainingMs))\n if (Date.now() >= options.deadlineAtMs) throw error\n delayMs = Math.min(delayMs * 2, SETTLEMENT_RETRY_MAX_DELAY_MS)\n }\n }\n}\n\nfunction waitForSettlementRetry(delayMs: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, delayMs))\n}\n\n/** Only the gateway's explicit draining state is retryable; auth and ledger errors fail closed. */\nfunction isCandidateGrantDrainingError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false\n const candidate = error as { code?: unknown; message?: unknown }\n if (candidate.code === 'candidate_grant_draining') return true\n return (\n typeof candidate.message === 'string' && /\\bcandidate_grant_draining\\b/u.test(candidate.message)\n )\n}\n","import type { TraceStore } from '@tangle-network/agent-eval'\nimport type {\n AgentCandidateExecutionPlanMaterial,\n AgentCandidateMaterializationReceipt,\n} from '@tangle-network/agent-interface'\nimport {\n agentCandidateExecutionPlanMaterialSchema,\n agentCandidateMaterializationReceiptSchema,\n} from '@tangle-network/agent-interface'\n\nimport { readVerifiedArtifact } from './artifacts'\nimport type {\n AgentCandidateExecutionAttemptRef,\n AgentCandidateExecutionClaim,\n AgentCandidateExecutionClaimStore,\n AgentCandidateExecutionFinishResult,\n} from './claim'\nimport {\n candidateCleanupDeadline,\n candidateCleanupTimeout,\n withinCandidateCleanupDeadline,\n} from './cleanup'\nimport { canonicalCandidateBytes } from './digest'\nimport { sealAgentCandidateExecutorStopAcknowledgement } from './executor-capture'\nimport { sealAgentCandidateModelSettlement } from './model-settlement'\nimport { persistCandidateModelSettlementEvidence } from './outcome-evidence'\nimport { persistCandidateOutputArtifact } from './output-artifacts'\nimport { RecoveryAgentCandidateTraceStore } from './protected-trace-store'\nimport type {\n AgentCandidateExecutionPorts,\n AgentCandidateExecutorPort,\n AgentCandidateOutputArtifactPort,\n} from './types'\n\nexport interface RecoverExpiredAgentCandidateOptions {\n attempt: AgentCandidateExecutionAttemptRef\n claimStore: AgentCandidateExecutionClaimStore\n executor: AgentCandidateExecutorPort\n traceStore: TraceStore\n ports: Pick<AgentCandidateExecutionPorts, 'models' | 'memory'>\n outputArtifacts: AgentCandidateOutputArtifactPort\n cleanupTimeoutMs?: number\n /** Evaluator clock; must be the same clock used by the claim store. */\n now?: () => number\n}\n\n/** Close an expired crashed attempt from persisted non-secret handles, then record failure. */\nexport async function recoverExpiredAgentCandidateExecution(\n options: RecoverExpiredAgentCandidateOptions,\n): Promise<AgentCandidateExecutionFinishResult> {\n const record = await options.claimStore.getAttempt(options.attempt)\n if (!record) throw new Error('candidate execution recovery attempt is missing')\n if (record.terminal) {\n return Object.freeze({ finished: false, terminal: record.terminal, exactReplay: true })\n }\n const cleanupTimeoutMs = candidateCleanupTimeout(\n options.cleanupTimeoutMs ?? record.claim.cleanup.cleanupTimeoutMs,\n )\n if (cleanupTimeoutMs > record.claim.cleanup.cleanupTimeoutMs) {\n throw new Error('recovery cleanup timeout exceeds the frozen preparation bound')\n }\n\n const now = options.now ?? Date.now\n if (now() < record.claim.leaseExpiresAtMs) {\n throw new Error('candidate execution lease has not expired')\n }\n\n const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs)\n const recoveryTraceStore = new RecoveryAgentCandidateTraceStore(options.traceStore)\n const preparation = withinCandidateCleanupDeadline(\n () => readRecoveryPreparation(record.claim, options.outputArtifacts),\n cleanupDeadlineAtMs,\n 'expired candidate preparation evidence read',\n )\n const processClosure = withinCandidateCleanupDeadline(\n async (cleanupSignal) => {\n const stopped = await options.executor.stop(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n {\n traceStore: recoveryTraceStore,\n reason: 'failed',\n signal: cleanupSignal,\n deadlineAtMs: cleanupDeadlineAtMs,\n },\n )\n sealAgentCandidateExecutorStopAcknowledgement(stopped)\n if (options.executor.dispose) {\n const disposed = await options.executor.dispose(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n { signal: cleanupSignal },\n )\n if (disposed.disposed !== true || Object.keys(disposed).some((key) => key !== 'disposed')) {\n throw new Error('expired candidate executor did not acknowledge resource disposal')\n }\n }\n return { stopped: true as const }\n },\n cleanupDeadlineAtMs,\n 'expired candidate process termination',\n )\n\n const modelClosure = withinCandidateCleanupDeadline(\n async () =>\n sealAgentCandidateModelSettlement(\n await options.ports.models.settleGrant({\n executionId: record.claim.executionId,\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n resolved: record.claim.cleanup.resolvedModel,\n reason: 'failed',\n }),\n {\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n model: record.claim.cleanup.resolvedModel.model,\n },\n ),\n cleanupDeadlineAtMs,\n 'expired candidate model settlement',\n )\n\n const memoryClosure = record.claim.cleanup.memory\n ? withinCandidateCleanupDeadline(\n async () => {\n const memory = record.claim.cleanup.memory\n if (!memory) throw new Error('expired candidate memory handle is missing')\n const closed = await options.ports.memory.close({\n executionId: record.claim.executionId,\n preparationId: record.claim.cleanup.preparationId,\n accessDigest: memory.accessDigest,\n effectiveNamespace: memory.effectiveNamespace,\n reason: 'failed',\n })\n if (closed.closed !== true || Object.keys(closed).some((key) => key !== 'closed')) {\n throw new Error('expired candidate memory did not acknowledge closure')\n }\n return { closed: true as const }\n },\n cleanupDeadlineAtMs,\n 'expired candidate memory closure',\n )\n : undefined\n\n const closureOutcomes = Promise.allSettled([\n modelClosure,\n memoryClosure ?? Promise.resolve(undefined),\n ] as const)\n const [preparationOutcome, processOutcome] = await Promise.allSettled([\n preparation,\n processClosure,\n ] as const)\n const failures: unknown[] = [preparationOutcome, processOutcome]\n .filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected')\n .map((outcome) => outcome.reason)\n const [modelOutcome, memoryOutcome] = await closureOutcomes\n for (const outcome of [modelOutcome, memoryOutcome]) {\n if (outcome.status === 'rejected') failures.push(outcome.reason)\n }\n if (failures.length > 0) {\n throw new AggregateError(failures, 'expired candidate cleanup could not be proven')\n }\n\n if (modelOutcome.status !== 'fulfilled') {\n throw new Error('expired candidate model settlement was not recovered')\n }\n const model = modelOutcome.value\n const modelSettlement = await withinCandidateCleanupDeadline(\n () =>\n persistCandidateModelSettlementEvidence(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n resolvedModel: record.claim.cleanup.resolvedModel,\n },\n model,\n options.outputArtifacts,\n ),\n cleanupDeadlineAtMs,\n 'expired candidate model-settlement persistence',\n )\n const failureClass =\n record.phase === 'claimed' && model.usage.modelCalls === 0\n ? 'pre-model-infrastructure'\n : 'unknown'\n const failureEvidence = await withinCandidateCleanupDeadline(\n () =>\n persistCandidateOutputArtifact(options.outputArtifacts, {\n executionId: record.claim.executionId,\n purpose: 'failure-evidence',\n bytes: canonicalCandidateBytes({\n kind: 'agent-candidate-recovery-failure',\n executionId: record.claim.executionId,\n attempt: record.claim.attempt,\n bundleDigest: record.claim.bundleDigest,\n executionPlanDigest: record.claim.executionPlanDigest,\n materializationReceiptDigest:\n record.claim.preparationEvidence.materializationReceipt.sha256,\n failureClass,\n processStopped: true,\n modelSettlementDigest: modelSettlement.digest,\n memoryClosed: record.claim.cleanup.memory !== undefined,\n }),\n }),\n cleanupDeadlineAtMs,\n 'expired candidate failure-evidence persistence',\n )\n const memory = record.claim.cleanup.memory\n return await options.claimStore.recoverExpired(options.attempt, {\n failureClass,\n usage: model.usage,\n modelSettlement: modelSettlement.artifact,\n failureEvidence,\n process: {\n stopped: true,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n model: {\n closed: true,\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n },\n ...(memory\n ? {\n memory: {\n closed: true,\n preparationId: record.claim.cleanup.preparationId,\n accessDigest: memory.accessDigest,\n effectiveNamespace: memory.effectiveNamespace,\n },\n }\n : {}),\n })\n}\n\nasync function readRecoveryPreparation(\n claim: AgentCandidateExecutionClaim,\n artifacts: AgentCandidateOutputArtifactPort,\n): Promise<{\n plan: AgentCandidateExecutionPlanMaterial\n receipt: AgentCandidateMaterializationReceipt\n}> {\n const [planBytes, receiptBytes] = await Promise.all([\n readVerifiedArtifact(claim.preparationEvidence.executionPlan, artifacts),\n readVerifiedArtifact(claim.preparationEvidence.materializationReceipt, artifacts),\n ])\n const plan = agentCandidateExecutionPlanMaterialSchema.parse(\n parseCanonicalBytes(planBytes, 'plan'),\n )\n if (claim.preparationEvidence.executionPlan.sha256 !== claim.executionPlanDigest) {\n throw new Error('recovery execution plan artifact does not match the claimed digest')\n }\n const receiptMaterial = parseCanonicalBytes(receiptBytes, 'materialization receipt')\n const receipt = agentCandidateMaterializationReceiptSchema.parse({\n ...receiptMaterial,\n digest: claim.preparationEvidence.materializationReceipt.sha256,\n })\n if (\n receipt.bundleDigest !== claim.bundleDigest ||\n receipt.executionPlan.digest !== claim.executionPlanDigest ||\n plan.runCell.bundleDigest !== claim.bundleDigest ||\n plan.executionId !== claim.executionId\n ) {\n throw new Error('recovery preparation evidence does not match the durable claim')\n }\n return { plan, receipt }\n}\n\nfunction parseCanonicalBytes(bytes: Uint8Array, label: string): Record<string, unknown> {\n let parsed: unknown\n try {\n parsed = JSON.parse(Buffer.from(bytes).toString('utf8'))\n } catch (error) {\n throw new Error(`candidate recovery ${label} is not JSON`, { cause: error })\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`candidate recovery ${label} must be an object`)\n }\n if (!Buffer.from(canonicalCandidateBytes(parsed)).equals(Buffer.from(bytes))) {\n throw new Error(`candidate recovery ${label} bytes are not canonical`)\n }\n return parsed as Record<string, unknown>\n}\n","/**\n * A content digest over a DIRECTORY TREE, and the per-file seed that fills one.\n *\n * The question this answers is \"is this workspace the same workspace\" — the question every launch\n * and every close of a branchable run has to answer, about a tree that a live process is still\n * writing to. That is a different question from the one\n * {@link scanMaterializedWorkspaceManifest} answers, and the difference decides the policies here:\n *\n * - A candidate manifest describes ONE EXACT regular-file workspace. It refuses a symbolic link\n * outright, because `AgentCandidateWorkspaceManifestMaterial` has no representation for one, and\n * it refuses an entry that disappears, because a signed manifest describes a settled tree.\n * - A tree descriptor describes what a RUN PRODUCED. A python venv writes\n * `bin/python -> /usr/bin/python3` as a matter of course, and a work directory can lose an entry\n * between two directory reads. Refusing on either aborts the close, and a run that never wrote\n * its digest can never be branched from.\n *\n * So the two policies are the caller's, one for links and one for vanishing entries, and both\n * default to `'refuse'` — the strict reading, correct for an INPUT seed, where a link that leaves\n * the tree means the seed describes bytes it does not contain. `'exclude'` is the reading a close\n * needs: the entry is never followed, it is recorded, and the exclusion itself is hashed, so two\n * trees that differ only in an excluded entry cannot share a digest.\n *\n * NOTHING is held in memory. A file reaches the tree digest as its own streamed sha-256 plus its\n * length, so the largest file in the tree does not decide whether the tree can be described:\n * `readFile` refuses anything above 2 GiB with `ERR_FS_FILE_TOO_LARGE`, and a single multi-gigabyte\n * artifact is exactly what a run leaves behind.\n *\n * @module\n * @experimental\n */\n\nimport { createHash } from 'node:crypto'\nimport { constants as fsConstants } from 'node:fs'\nimport { cp, lstat, open, readdir, readlink, realpath } from 'node:fs/promises'\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'\nimport type { Sha256Digest } from '@tangle-network/agent-interface'\n\n/**\n * `'tree-v1'` records a file's exact permission bits. `'portable-tree-v1'` records the two modes\n * Git stores — `755` when any execute bit is set, `644` otherwise, and `755` for a directory — so a\n * digest survives a checkout whose umask differs. Both stamp the algorithm into the digest, so one\n * tree cannot produce the same digest under both.\n */\nexport type WorkspaceTreeAlgorithm = 'tree-v1' | 'portable-tree-v1'\n\n/** What a walk does with an entry it refuses to describe: fail, or record and continue. */\nexport type WorkspaceTreeEntryPolicy = 'refuse' | 'exclude'\n\n/** Why one entry contributed its name instead of its content. */\nexport type WorkspaceTreeExclusionReason =\n | 'absolute-symlink'\n | 'symlink-escapes-tree'\n | 'symlink-resolves-outside-tree'\n | 'unresolved-symlink'\n | 'entry-disappeared'\n\n/** One entry the walk recorded but did not describe. Reported rather than dropped: a digest that\n * silently omitted an entry would be a different digest with no way to tell why. */\nexport interface WorkspaceTreeExclusion {\n /** Tree-relative path, `/`-separated. */\n readonly path: string\n readonly reason: WorkspaceTreeExclusionReason\n /** The link target exactly as it was written, for a symbolic-link exclusion. */\n readonly target?: string\n}\n\nexport interface WorkspaceTreeDescriptor {\n readonly algorithm: WorkspaceTreeAlgorithm\n readonly digest: Sha256Digest\n readonly files: number\n readonly directories: number\n /** Links kept INSIDE the tree. An excluded link is counted in `excluded`, never here. */\n readonly symlinks: number\n /** Total described regular-file bytes. */\n readonly bytes: number\n readonly excluded: ReadonlyArray<WorkspaceTreeExclusion>\n}\n\nexport interface DescribeWorkspaceTreeOptions {\n /** Default `'tree-v1'`. */\n readonly algorithm?: WorkspaceTreeAlgorithm\n /**\n * A symbolic link that is absolute, leaves the tree lexically, resolves outside it, or does not\n * resolve at all. `'refuse'` (default) is correct for an input seed. `'exclude'` is correct for a\n * close-time walk over a tree a run wrote. The link is NEVER followed in either policy: an\n * escaping link must not contribute bytes from outside the tree to a content address.\n */\n readonly onEscapingLink?: WorkspaceTreeEntryPolicy\n /**\n * An entry that vanished between the directory read that named it and the walk that reached it.\n * `'refuse'` (default) is correct for a settled tree; `'exclude'` is correct for a workspace a\n * live process still writes to.\n */\n readonly onMissingEntry?: WorkspaceTreeEntryPolicy\n}\n\nexport interface SeedWorkspaceTreeInput {\n /** The tree to copy FROM. Described, then copied entry by entry. */\n readonly source: string\n /** The tree to copy INTO. Must exist, and must not lie inside `source`. */\n readonly destination: string\n /** Default `'tree-v1'`; decides only the digest this returns, never the bytes it writes. */\n readonly algorithm?: WorkspaceTreeAlgorithm\n}\n\nconst TREE_ALGORITHMS: ReadonlySet<string> = new Set<WorkspaceTreeAlgorithm>([\n 'tree-v1',\n 'portable-tree-v1',\n])\n\nconst ENTRY_POLICIES: ReadonlySet<string> = new Set<WorkspaceTreeEntryPolicy>(['refuse', 'exclude'])\n\n/**\n * Describe one directory tree by content, streaming every file.\n *\n * The digest covers, for every entry in sorted order: its kind, its tree-relative path, its mode\n * under the selected algorithm, and then — for a file, its length and its own sha-256; for a kept\n * link, its target; for an excluded entry, the reason and the target. A file's content therefore\n * never enters the tree hash directly, which is what removes any in-memory size ceiling: the tree\n * hash consumes 32 bytes per file however large the file is.\n *\n * A hard-linked regular file is described like any other regular file. Its content is what the\n * digest is about, and a package manager that links a store into `node_modules` is ordinary\n * content, not a reason to refuse a workspace.\n */\nexport async function describeWorkspaceTree(\n directory: string,\n options: DescribeWorkspaceTreeOptions = {},\n): Promise<WorkspaceTreeDescriptor> {\n const algorithm = options.algorithm ?? 'tree-v1'\n const onEscapingLink = options.onEscapingLink ?? 'refuse'\n const onMissingEntry = options.onMissingEntry ?? 'refuse'\n if (!TREE_ALGORITHMS.has(algorithm)) {\n throw new Error(`unsupported workspace tree algorithm: ${algorithm}`)\n }\n for (const [name, policy] of [\n ['onEscapingLink', onEscapingLink],\n ['onMissingEntry', onMissingEntry],\n ] as const) {\n if (!ENTRY_POLICIES.has(policy)) {\n throw new Error(`unsupported workspace tree ${name} policy: ${policy}`)\n }\n }\n\n const root = resolve(directory)\n const rootStats = await lstatIfPresent(root)\n if (rootStats === null || !rootStats.isDirectory() || rootStats.isSymbolicLink()) {\n throw new Error(`workspace tree root must be a real directory: ${directory}`)\n }\n // Resolve the root once. Every physical containment test below compares against the RESOLVED\n // root, so a symlinked prefix — which is what macOS hands out for a temp directory — does not\n // make every entry look like it escapes.\n const physicalRoot = await realpath(root)\n\n const hash = createHash('sha256')\n // The algorithm is part of the digest. Without this, a tree whose modes already are 755/644\n // produces one digest under both algorithms, and two different questions share one answer.\n hash.update(`workspace-tree\\0${algorithm}\\0`)\n const counts = { files: 0, directories: 0, symlinks: 0, bytes: 0 }\n const excluded: WorkspaceTreeExclusion[] = []\n\n const exclude = (path: string, reason: WorkspaceTreeExclusionReason, target?: string): void => {\n const name = treePath(root, path)\n excluded.push(\n Object.freeze(target === undefined ? { path: name, reason } : { path: name, reason, target }),\n )\n // The reason is hashed with the entry. Two trees that differ only in WHY an entry was excluded\n // are different trees, and a refusal must not become a way to hide a difference.\n hash.update(`excluded\\0${name}\\0${reason}\\0${target ?? ''}\\0`)\n }\n\n /** True when the caller asked to continue past a vanished entry, and it was not the root. */\n const recordMissing = (path: string): boolean => {\n if (onMissingEntry === 'refuse' || path === root) return false\n exclude(path, 'entry-disappeared')\n return true\n }\n\n const visit = async (path: string): Promise<void> => {\n const info = await lstatIfPresent(path)\n if (info === null) {\n if (recordMissing(path)) return\n throw new Error(`workspace tree entry disappeared during the walk: ${treePath(root, path)}`)\n }\n const name = treePath(root, path)\n const mode = entryMode(info.mode, algorithm, info.isDirectory(), info.isSymbolicLink())\n\n if (info.isDirectory()) {\n let entries: string[]\n try {\n entries = await readdir(path)\n } catch (error) {\n if (isMissing(error) && recordMissing(path)) return\n throw error\n }\n counts.directories += 1\n hash.update(`directory\\0${name}\\0${mode}\\0`)\n for (const entry of entries.sort()) await visit(join(path, entry))\n return\n }\n\n if (info.isSymbolicLink()) {\n await visitSymbolicLink(path, name, mode)\n return\n }\n\n if (!info.isFile()) {\n throw new Error(`workspace tree contains an unsupported entry: ${name}`)\n }\n const read = await digestFile(path)\n if (read === null) {\n if (recordMissing(path)) return\n throw new Error(`workspace tree entry disappeared during the walk: ${name}`)\n }\n counts.files += 1\n counts.bytes += read.byteLength\n hash.update(`file\\0${name}\\0${mode}\\0${read.byteLength}\\0${read.sha256}\\0`)\n }\n\n const visitSymbolicLink = async (path: string, name: string, mode: string): Promise<void> => {\n let target: string\n try {\n target = await readlink(path)\n } catch (error) {\n if (isMissing(error) && recordMissing(path)) return\n throw error\n }\n const refuse = (reason: WorkspaceTreeExclusionReason): void => {\n if (onEscapingLink === 'refuse') {\n throw new Error(\n `workspace tree contains a link that ${reasonText(reason)}: ${name} -> ${target}`,\n )\n }\n exclude(path, reason, target)\n }\n if (isAbsolute(target)) return refuse('absolute-symlink')\n if (!isWithin(root, resolve(dirname(path), target))) return refuse('symlink-escapes-tree')\n let physicalTarget: string\n try {\n physicalTarget = await realpath(path)\n } catch {\n // A dangling link is a fact about the tree, not a reason to make the run unrecoverable.\n return refuse('unresolved-symlink')\n }\n if (!isWithin(physicalRoot, physicalTarget)) return refuse('symlink-resolves-outside-tree')\n counts.symlinks += 1\n hash.update(`symlink\\0${name}\\0${mode}\\0${target}\\0`)\n }\n\n await visit(root)\n return Object.freeze({\n algorithm,\n digest: `sha256:${hash.digest('hex')}` as Sha256Digest,\n files: counts.files,\n directories: counts.directories,\n symlinks: counts.symlinks,\n bytes: counts.bytes,\n excluded: Object.freeze(excluded),\n })\n}\n\n/**\n * Seed a workspace from a directory, one entry at a time, and return the digest of what was\n * seeded.\n *\n * Nothing is packed: `cp` walks and copies file by file, so a multi-gigabyte seed costs one file\n * handle rather than one archive in memory. Existing destination entries are never overwritten —\n * a seed that could replace a file the workspace already holds would make the resulting tree\n * depend on the order two seeds ran in.\n *\n * Links are copied verbatim, exactly as they were written. Following them would copy bytes from\n * outside the seed into the workspace, which is the same rule {@link describeWorkspaceTree}\n * applies to the digest.\n */\nexport async function seedWorkspaceTree(\n input: SeedWorkspaceTreeInput,\n): Promise<WorkspaceTreeDescriptor> {\n const source = resolve(input.source)\n const destination = resolve(input.destination)\n if (source === destination || isWithin(source, destination)) {\n throw new Error('workspace seed must not contain its destination')\n }\n const destinationStats = await lstatIfPresent(destination)\n if (destinationStats === null || !destinationStats.isDirectory()) {\n throw new Error(\n `workspace seed destination must be an existing directory: ${input.destination}`,\n )\n }\n // Described BEFORE anything is copied, so a seed this refuses leaves the destination untouched.\n const descriptor = await describeWorkspaceTree(source, {\n ...(input.algorithm === undefined ? {} : { algorithm: input.algorithm }),\n })\n for (const name of (await readdir(source)).sort()) {\n if ((await lstatIfPresent(join(destination, name))) !== null) {\n throw new Error(`workspace seed would overwrite an existing entry: ${name}`)\n }\n await cp(join(source, name), join(destination, name), {\n recursive: true,\n force: false,\n errorOnExist: true,\n verbatimSymlinks: true,\n })\n }\n return descriptor\n}\n\n/** Stream one regular file into its own digest, or `null` when it vanished mid-read. */\nasync function digestFile(\n path: string,\n): Promise<{ sha256: Sha256Digest; byteLength: number } | null> {\n let descriptor: Awaited<ReturnType<typeof open>>\n try {\n descriptor = await open(\n path,\n fsConstants.O_RDONLY |\n (typeof fsConstants.O_NOFOLLOW === 'number' ? fsConstants.O_NOFOLLOW : 0),\n )\n } catch (error) {\n if (isMissing(error)) return null\n throw error\n }\n try {\n const hash = createHash('sha256')\n const buffer = Buffer.allocUnsafe(1024 * 1024)\n let total = 0\n while (true) {\n const { bytesRead } = await descriptor.read(buffer, 0, buffer.byteLength, null)\n if (bytesRead === 0) break\n total += bytesRead\n hash.update(buffer.subarray(0, bytesRead))\n }\n // The length comes from the READ, never from `lstat`, so a file that grew between the two is\n // described by the bytes that reached the digest rather than refused for ordinary churn.\n return { sha256: `sha256:${hash.digest('hex')}` as Sha256Digest, byteLength: total }\n } finally {\n await descriptor.close()\n }\n}\n\n/** Git records exactly two file modes; a portable tree records the same two, plus 755 for a\n * directory and 777 for a link, which is what every filesystem reports for one. */\nfunction entryMode(\n mode: number | bigint,\n algorithm: WorkspaceTreeAlgorithm,\n isDirectory: boolean,\n isSymbolicLink: boolean,\n): string {\n const bits = Number(mode)\n if (algorithm !== 'portable-tree-v1') return String(bits & 0o777)\n if (isDirectory) return '755'\n if (isSymbolicLink) return '777'\n return (bits & 0o111) !== 0 ? '755' : '644'\n}\n\nfunction reasonText(reason: WorkspaceTreeExclusionReason): string {\n switch (reason) {\n case 'absolute-symlink':\n return 'is absolute'\n case 'symlink-escapes-tree':\n return 'escapes its tree'\n case 'symlink-resolves-outside-tree':\n return 'resolves outside its tree'\n default:\n return 'does not resolve'\n }\n}\n\nfunction treePath(root: string, path: string): string {\n return relative(root, path).split(sep).join('/') || '.'\n}\n\nfunction isWithin(root: string, path: string): boolean {\n return path === root || path.startsWith(`${root}${sep}`)\n}\n\nfunction isMissing(error: unknown): boolean {\n return (error as { code?: unknown } | null)?.code === 'ENOENT'\n}\n\nasync function lstatIfPresent(path: string): Promise<Awaited<ReturnType<typeof lstat>> | null> {\n try {\n return await lstat(path)\n } catch (error) {\n if (isMissing(error)) return null\n throw error\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAwEA,SAAgB,0BACd,OAC6C;CAU7C,OAAO,yBAAyB;EAR9B,MAAM;EACN,iBAAiB;EACjB,SAAS,wBAAwB,MAAM,OAAO;EAC9C,MAAM,qBAAqB,MAAM,IAAI;EACrC,WAAW,MAAM;EACjB,GAAI,MAAM,cAAc,KAAA,IAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;EACtE,QAAQ,MAAM;CAEqB,CAAC;AACxC;AAEA,SAAS,wBAAwB,QAA4D;CAC3F,IAAI,OAAO,SAAS,qBAClB,OAAO,2BAA2B,OAAO,OAAO;CAGlD,IAAI,OAAO,SAAS,WAClB,OAAO,mCAAmC,OAAO,OAAO;CAG1D,IAAI,OAAO,SAAS,iBAClB,MAAM,IAAI,MACR,yCAAyC,OAAQ,OAA8B,IAAI,GACrF;CAEF,IAAI,OAAO,MAAM,WAAW,GAC1B,MAAM,IAAI,MAAM,6DAA6D;CAE/E,IAAI,UAAU,uBAAuB,OAAO,MAAM,cAAc;CAChE,KAAK,MAAM,CAAC,OAAO,cAAc,OAAO,MAAM,QAAQ,GAAG;EACvD,MAAM,OAAO,2BAA2B,WAAW,gBAAgB,OAAO;EAC1E,UAAU,2BAA2B,SAAS,MAAM,gBAAgB,OAAO;CAC7E;CACA,OAAO,mCAAmC,OAAO;AACnD;AAEA,SAAS,qBAAqB,QAAqE;CACjG,IAAI,OAAO,SAAS,cAAc,OAAO,SAAS,SAAS,OAAO;CAClE,IAAI,OAAO,SAAS,gBAClB,MAAM,IAAI,MACR,sCAAsC,OAAQ,OAA8B,IAAI,GAClF;CAIF,MAAM,QAAQ,0BADG,kBAAkB,OAAO,SAAS,OAAO,WACX,CAAC,CAAC,UAAU;CAC3D,IACE,MAAM,WAAW,OAAO,QAAQ,MAAM,UACtC,MAAM,eAAe,OAAO,QAAQ,MAAM,YAE1C,MAAM,IAAI,MAAM,oEAAoE;CAEtF,OAAO;EACL,MAAM;EACN,YAAY,OAAO;EACnB,YAAY,OAAO,QAAQ;EAC3B,UAAU,OAAO,QAAQ;EACzB,eAAe,OAAO,QAAQ;EAC9B,OAAO;GAAE,QAAQ;GAAmB,UAAU;EAAM;CACtD;AACF;;;ACnGA,MAAM,EACJ,oBACA,aACA,gBACA,sBACA,eACA,WACA,aACA,UACA,WACA,oBACA,cACA,uBACA,yBACA,uBACA,eACA,gBACA,gBACA,WACA,cACE;;AAUJ,IAAa,wCAAb,MAAgG;CAC9F;CACA;CAEA,YAAY,SAAuD;EACjE,IAAI,QAAQ,UAAU,WAAW,GAC/B,MAAM,IAAI,MAAM,uDAAuD;EAEzE,KAAK,YAAY,QAAQ;EACzB,KAAK,MAAM,QAAQ,OAAO,KAAK;CACjC;CAEA,MAAM,SACJ,WAC6C;EAC7C,MAAM,QAAQ,UAAU,SAAS;EACjC,MAAM,MAAM,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;EAC/C,MAAM,YAAY,KAAK,UAAU,KAAK;EACtC,MAAM,WAAW,MAAM,mBAAmB,SAAS;EACnD,IAAI,UAAU;GACZ,eAAe,SAAS,OAAO,OAAO,SAAS;GAC/C,OAAO,sBAAsB,SAAS,OAAO,KAAK;EACpD;EACA,qBAAqB,MAAM,kBAAkB,KAAK,IAAI,CAAC;EACvD,MAAM,eAAe,MAAM,KAAK,aAAa,KAAK;EAClD,IAAI,cAAc,OAAO,cAAc,OAAO,YAAY;EAE1D,MAAM,QAAQ,SAAS,KAAK;EAM5B,IAAI,MALmB,oBAAoB,KAAK,WAAW,WAAW;GACpE,GAAG;GACH,OAAO;GACP,aAAa,YAAY,KAAK;EAChC,CAAC,GACa,OAAO,OAAO,OAAO;GAAE,UAAU;GAAM;GAAO;EAAM,CAAC;EAEnE,MAAM,SAAS,MAAM,UAAU,SAAS;EACxC,eAAe,OAAO,OAAO,OAAO,SAAS;EAC7C,OAAO,sBAAsB,OAAO,OAAO,KAAK;CAClD;CAEA,MAAM,WACJ,kBAC2D;EAC3D,OAAO,MAAM,KAAK,cAAc,eAAe,gBAAgB,CAAC;CAClE;CAEA,MAAM,oBACJ,gBAC6C;EAC7C,MAAM,QAAQ,UAAU,cAAc;EACtC,MAAM,YAAY,KAAK,UAAU,KAAK;EACtC,MAAM,SAAS,MAAM,UAAU,SAAS;EACxC,eAAe,OAAO,OAAO,OAAO,SAAS;EAC7C,YAAY,OAAO,aAAa,OAAO,MAAM,kBAAkB,KAAK;EACpE,MAAM,QAAQ,MAAM,KAAK,gBAAgB,OAAO,KAAK;EACrD,IAAI,MAAM,UAAU,qBAClB,OAAO,OAAO,OAAO;GAAE,QAAQ;GAAO,OAAO;EAAoB,CAAC;EAEpE,IAAI,MAAM,QACR,MAAM,IAAI,MAAM,wEAAwE;EAE1F,qBAAqB,OAAO,MAAM,kBAAkB,KAAK,IAAI,CAAC;EAa9D,IAAI,MAZiB,oBACnB,KAAK,WACL,KAAK,eAAe,OAAO,OAAO,CAAC,GACnC;GACE,MAAM;GACN,aAAa,OAAO,MAAM;GAC1B,SAAS,OAAO,MAAM;GACtB,qBAAqB,OAAO,MAAM;GAClC,OAAO;EACT,GACA,KAAK,iBAAiB,OAAO,KAAK,CACpC,GACY,OAAO,OAAO,OAAO;GAAE,QAAQ;GAAM,OAAO;EAAoB,CAAC;EAE7E,KAAI,MADiB,KAAK,gBAAgB,OAAO,KAAK,EAAA,CAC3C,UAAU,qBACnB,OAAO,OAAO,OAAO;GAAE,QAAQ;GAAO,OAAO;EAAoB,CAAC;EAEpE,MAAM,IAAI,MAAM,wEAAwE;CAC1F;CAEA,MAAM,cACJ,gBACA,QAC6C;EAC7C,MAAM,QAAQ,UAAU,cAAc;EACtC,MAAM,YAAY,KAAK,UAAU,KAAK;EACtC,MAAM,SAAS,MAAM,UAAU,SAAS;EACxC,eAAe,OAAO,OAAO,OAAO,SAAS;EAC7C,YAAY,OAAO,aAAa,OAAO,MAAM,kBAAkB,KAAK;EACpE,MAAM,WAAW,eAAe,OAAO,OAAO,MAAM;EACpD,MAAM,QAAQ,MAAM,KAAK,gBAAgB,OAAO,KAAK;EACrD,IAAI,MAAM,QAAQ,OAAO,cAAc,MAAM,QAAQ,QAAQ;EAC7D,6BAA6B,MAAM,OAAO,QAAQ;EAClD,qBAAqB,OAAO,MAAM,kBAAkB,KAAK,IAAI,CAAC;EAC9D,MAAM,aAAa,MAAM,UAAU,YAAY,IAAI;EAUnD,IAAI,MATiB,oBACnB,KAAK,WACL,KAAK,eAAe,OAAO,OAAO,UAAU,GAC5C;GACE,MAAM;GACN;EACF,GACA,KAAK,iBAAiB,OAAO,KAAK,CACpC,GACY,OAAO,OAAO,OAAO;GAAE,QAAQ;GAAM;EAAS,CAAC;EAC3D,MAAM,SAAS,MAAM,KAAK,gBAAgB,OAAO,KAAK;EACtD,IAAI,CAAC,OAAO,QACV,MAAM,IAAI,MAAM,iEAAiE;EAEnF,OAAO,cAAc,OAAO,QAAQ,QAAQ;CAC9C;CAEA,MAAM,OACJ,gBACA,yBAC8C;EAC9C,MAAM,QAAQ,UAAU,cAAc;EACtC,MAAM,iBAAiB,mBAAmB,uBAAuB;EACjE,MAAM,YAAY,KAAK,UAAU,KAAK;EACtC,MAAM,SAAS,MAAM,UAAU,SAAS;EACxC,eAAe,OAAO,OAAO,OAAO,SAAS;EAC7C,YAAY,OAAO,aAAa,OAAO,MAAM,kBAAkB,KAAK;EAEpE,MAAM,SAAS,uBAAsB,MADjB,KAAK,gBAAgB,OAAO,KAAK,EAAA,CACV,QAAQ,cAAc;EACjE,MAAM,eAAe,KAAK,aAAa,KAAK;EAC5C,MAAM,WAAW,MAAM,sBAAsB,YAAY;EACzD,IAAI,UAAU;GACZ,2BAA2B,UAAU,OAAO,OAAO,YAAY;GAC/D,4BAA4B,UAAU,QAAQ,YAAY;GAC1D,OAAO,eAAe,UAAU,cAAc;EAChD;EACA,qBAAqB,OAAO,MAAM,kBAAkB,KAAK,IAAI,CAAC;EAS9D,IAAI,MARmB,oBACrB,KAAK,WACL,cACA,EACE,UAAU,OACZ,GACA,KAAK,iBAAiB,OAAO,KAAK,CACpC,GACc,OAAO,OAAO,OAAO;GAAE,UAAU;GAAM,UAAU;EAAO,CAAC;EACvE,MAAM,SAAS,MAAM,aAAa,YAAY;EAC9C,eAAe,QAAQ,OAAO,YAAY;EAC1C,2BAA2B,QAAQ,OAAO,OAAO,YAAY;EAC7D,4BAA4B,QAAQ,QAAQ,YAAY;EACxD,OAAO,eAAe,QAAQ,cAAc;CAC9C;CAEA,MAAM,eACJ,kBACA,UAC8C;EAC9C,MAAM,UAAU,eAAe,gBAAgB;EAC/C,MAAM,SAAS,MAAM,KAAK,cAAc,OAAO;EAC/C,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,gEAAgE;EAC7F,MAAM,YAAY,wBAAwB,OAAO,OAAO,OAAO,OAAO,QAAQ;EAC9E,IAAI,OAAO,QAAQ,4BAA4B,OAAO,QAAQ,SAAS;EACvE,MAAM,kBAAkB,OAAO,QAAQ,kBAAkB,UAAU;EACnE,IAAI,OAAO,UAAU,OAAO,eAAe,OAAO,UAAU,eAAe;EAC3E,mBAAmB,OAAO,MAAM,kBAAkB,KAAK,IAAI,CAAC;EAE5D,IAAI,SAAS,OAAO;EACpB,IAAI,CAAC,QAAQ;GACX,MAAM,aAAa,OAAO,UAAU,YAAY,IAAI;GASpD,IAAI,MARmB,oBACrB,KAAK,WACL,KAAK,eAAe,OAAO,OAAO,UAAU,GAC5C;IACE,MAAM;IACN,UAAU;GACZ,CACF,GAEE,SAAS;QACJ;IACL,MAAM,SAAS,MAAM,KAAK,gBAAgB,OAAO,KAAK;IACtD,IAAI,CAAC,OAAO,QACV,MAAM,IAAI,MACR,0EACF;IAEF,4BAA4B,OAAO,QAAQ,SAAS;IACpD,SAAS,OAAO;GAClB;EACF;EAEA,MAAM,eAAe,KAAK,aAAa,OAAO;EAI9C,IAAI,MAHoB,oBAAoB,KAAK,WAAW,cAAc,EACxE,UAAU,OACZ,CAAC,GACc,OAAO,OAAO,OAAO;GAAE,UAAU;GAAM,UAAU;EAAO,CAAC;EACxE,MAAM,SAAS,MAAM,aAAa,YAAY;EAC9C,eAAe,QAAQ,SAAS,YAAY;EAC5C,2BAA2B,QAAQ,OAAO,OAAO,YAAY;EAC7D,4BAA4B,QAAQ,QAAQ,YAAY;EACxD,OAAO,eAAe,QAAQ,OAAO,cAAc;CACrD;CAEA,MAAc,cACZ,OAC2D;EAC3D,MAAM,YAAY,KAAK,UAAU,KAAK;EACtC,MAAM,SAAS,MAAM,mBAAmB,SAAS;EACjD,IAAI,CAAC,QAAQ,OAAO,KAAA;EACpB,eAAe,OAAO,OAAO,OAAO,SAAS;EAC7C,MAAM,eAAe,KAAK,aAAa,KAAK;EAC5C,MAAM,WAAW,MAAM,sBAAsB,YAAY;EAEzD,MAAM,QAAQ,MAAM,KAAK,gBAAgB,OAAO,KAAK;EACrD,IAAI,UAAU;GACZ,2BAA2B,UAAU,OAAO,OAAO,YAAY;GAC/D,IAAI,CAAC,MAAM,QACT,MAAM,IAAI,MACR,0CAA0C,aAAa,sBACzD;GAEF,4BAA4B,UAAU,MAAM,QAAQ,YAAY;EAClE;EACA,OAAO,cAAc,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ,QAAQ;CACxE;CAEA,MAAc,gBAAgB,OAG3B;EACD,MAAM,YAAY,KAAK,eAAe,OAAO,CAAC;EAC9C,MAAM,QAAQ,MAAM,wBAAwB,WAAW,KAAK;EAC5D,IAAI,CAAC,OAAO,OAAO,EAAE,OAAO,UAAU;EACtC,IAAI,MAAM,SAAS,WAAW,OAAO;GAAE,OAAO;GAAW,QAAQ,MAAM;EAAS;EAChF,MAAM,aAAa,KAAK,eAAe,OAAO,CAAC;EAC/C,MAAM,SAAS,MAAM,wBAAwB,YAAY,KAAK;EAC9D,IAAI,CAAC,QAAQ,OAAO,EAAE,OAAO,oBAAoB;EACjD,IAAI,OAAO,SAAS,WAClB,MAAM,IAAI,MAAM,qCAAqC,WAAW,0BAA0B;EAE5F,OAAO;GAAE,OAAO;GAAqB,QAAQ,OAAO;EAAS;CAC/D;CAEA,MAAc,aACZ,OACmD;EACnD,IAAI,MAAM,YAAY,GAAG,OAAO,KAAA;EAChC,OAAO,eACL,OACA,MAAM,KAAK,cAAc;GACvB,aAAa,MAAM;GACnB,SAAS,MAAM,UAAU;EAC3B,CAAC,CACH;CACF;CAEA,iBAAyB,OAEvB;EACA,OAAO,EACL,wBAAwB;GACtB,qBAAqB,MAAM,kBAAkB,KAAK,IAAI,CAAC;GACvD,OAAO;EACT,EACF;CACF;CAEA,UAAkB,OAA8E;EAC9F,OAAO,KAAK,KAAK,WAAW,GAAG,UAAU,KAAK,EAAE,YAAY;CAC9D;CAEA,aACE,OACQ;EACR,OAAO,KAAK,KAAK,WAAW,GAAG,UAAU,KAAK,EAAE,eAAe;CACjE;CAEA,eACE,OACA,SACQ;EACR,OAAO,KAAK,KAAK,WAAW,GAAG,UAAU,KAAK,EAAE,cAAc,QAAQ,MAAM;CAC9E;AACF;;;;;;;AAQA,eAAe,oBACb,WACA,aACA,QACA,UAGI,CAAC,GACa;CAClB,MAAM,gBAAgB,KAAK,WAAW,wBAAwB,QAAQ,IAAI,GAAG,WAAW,EAAE,KAAK;CAC/F,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,GAAK;CACpD,IAAI;EACF,MAAM,OAAO,UACX,OAAO,OAAO,CAAC,OAAO,KAAK,wBAAwB,MAAM,CAAC,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CACjF;EACA,MAAM,OAAO,KAAK;CACpB,UAAU;EACR,MAAM,OAAO,MAAM;CACrB;CAEA,IAAI,UAAU;CACd,IAAI;EACF,IAAI,QAAQ,oBAAoB,QAAQ,iBAAiB,MAAM,MAC7D,MAAM,IAAI,MAAM,2DAA2D;EAI7E,SAAS,eAAe,WAAW;EACnC,UAAU;EACV,MAAM,cAAc,SAAS;CAC/B,SAAS,OAAO;EACd,IAAI,CAAC,YAAY,OAAO,QAAQ,GAAG,MAAM;CAC3C,UAAU;EACR,MAAM,OAAO,aAAa,CAAC,CAAC,OAAO,UAAmB;GACpD,IAAI,CAAC,YAAY,OAAO,QAAQ,GAAG,MAAM;EAC3C,CAAC;CACH;CACA,OAAO;AACT;AAEA,eAAe,cAAc,WAAkC;CAC7D,MAAM,SAAS,MAAM,KAAK,WAAW,GAAG;CACxC,IAAI;EACF,MAAM,OAAO,KAAK;CACpB,UAAU;EACR,MAAM,OAAO,MAAM;CACrB;AACF;AAEA,SAAS,YAAY,OAAgB,MAAuB;CAC1D,OACE,UAAU,QACV,OAAO,UAAU,YACjB,UAAU,SACT,MAA6B,SAAS;AAE3C;;;;AC7YA,eAAsB,uCACpB,UACA,UAAgD,CAAC,GACpB;CAC7B,MAAM,eAAe,iCAAiC,QAAQ;CAC9D,MAAM,mBAAmB,QAAQ,oBAAoB,aAAa;CAClE,IAAI,mBAAmB,aAAa,kBAClC,MAAM,IAAI,MAAM,+DAA+D;CAEjF,MAAM,sBAAsB,yBAAyB,gBAAgB;CACrE,MAAM,QAAQ,+BAA+B,QAAQ;CACrD,MAAM,UAAmC,CAAC;CAE1C,IAAI,MAAM,OAAO,SAAS,YAAY;EACpC,MAAM,cAAc,MAAM;EAC1B,IAAI,CAAC,aAAa,MAAM,IAAI,MAAM,wCAAwC;EAC1E,QAAQ,KACN,+BACE,YAAY;GACV,MAAM,SAAS,MAAM,MAAM,MAAM,OAAO,MAAM;IAC5C,aAAa,MAAM;IACnB,eAAe,YAAY;IAC3B,cAAc,YAAY;IAC1B,oBAAoB,YAAY;IAChC,QAAQ;GACV,CAAC;GACD,IAAI,OAAO,WAAW,QAAQ,OAAO,KAAK,MAAM,CAAC,CAAC,MAAM,QAAQ,QAAQ,QAAQ,GAC9E,MAAM,IAAI,MAAM,8DAA8D;EAElF,GACA,qBACA,0BACF,CACF;CACF;CAEA,QAAQ,KACN,+BACE,YAAY;EAeV,IAdmB,kCACjB,MAAM,MAAM,MAAM,OAAO,YAAY;GACnC,aAAa,MAAM;GACnB,eAAe,MAAM;GACrB,aAAa,MAAM,iBAAiB;GACpC,UAAU,MAAM;GAChB,QAAQ;EACV,CAAC,GACD;GACE,eAAe,MAAM;GACrB,aAAa,MAAM,iBAAiB;GACpC,OAAO,MAAM,cAAc;EAC7B,CAEW,CAAC,CAAC,MAAM,eAAe,GAClC,MAAM,IAAI,MAAM,0DAA0D;CAE9E,GACA,qBACA,4BACF,CACF;CAGA,MAAM,YAAW,MADK,QAAQ,WAAW,OAAO,EAAA,CAE7C,QAAQ,WAA4C,OAAO,WAAW,UAAU,CAAC,CACjF,KAAK,WAAW,OAAO,MAAM;CAChC,IAAI,SAAS,SAAS,GAAG;EACvB,kCAAkC,UAAU,iBAAiB;EAC7D,MAAM,IAAI,eAAe,UAAU,uCAAuC;CAC5E;CAEA,kCAAkC,UAAU,UAAU;CACtD,OAAO,OAAO,OAAO,EAAE,UAAU,KAAc,CAAC;AAClD;;;ACtCA,MAAM,oCAAoC;AAC1C,MAAM,gCAAgC;;;;;;;;;AAUtC,eAAsB,qCACpB,SAC8D;CAC9D,IAAI,OAAO,QAAQ,YAAY,YAC7B,MAAM,IAAI,UAAU,oDAAoD;CAG1E,MAAM,WAAW,MAAM,QAAQ,KAAK,QAAQ,QAAQ,OAAO;CAC3D,MAAM,cAAc,MAAM,QAAQ,KAAK,aAAa;EAClD,GAAG,QAAQ;EACX;CACF,CAAC;CAED,IAAI;CACJ,IAAI;CACJ,IAAI,kBAAkB;CACtB,IAAI,YAAY;CAChB,IAAI,SAAwD;CAE5D,IAAI;EACF,MAAM,aAAa,MAAM,QAAQ,KAAK,cAAc;GAClD,aAAa,QAAQ,QAAQ;GAC7B,eAAe,QAAQ,QAAQ;GAC/B,aAAa,YAAY;GACzB;GACA,cAAc,QAAQ;EACxB,CAAC;EACD,YAAY;EACZ,QAAQ,MAAM,QAAQ,QAAQ;GAAE;GAAY;GAAa;EAAS,CAAC;EACnE,SAAS;CACX,SAAS,OAAO;EACd,iBAAiB;EACjB,kBAAkB;EAClB,IAAI,WAAW,SAAS;CAC1B;CAEA,IAAI;CACJ,IAAI;EACF,aAAa,MAAM,0BAA0B,SAAS;GACpD,aAAa,QAAQ,QAAQ;GAC7B,eAAe,QAAQ,QAAQ;GAC/B,aAAa,YAAY;GACzB;GACA;EACF,CAAC;CACH,SAAS,iBAAiB;EACxB,IAAI,iBACF,MAAM,IAAI,eACR,CAAC,gBAAgB,eAAe,GAChC,+DACF;EAEF,MAAM;CACR;CAEA,IAAI,iBAAiB,MAAM;CAC3B,OAAO;EAAE;EAAO;EAAU;EAAa;CAAW;AACpD;AAEA,eAAe,0BACb,SACA,OACiD;CACjD,IAAI,UAAU;CACd,SACE,IAAI;EACF,OAAO,MAAM,QAAQ,KAAK,YAAY,KAAK;CAC7C,SAAS,OAAO;EACd,IAAI,CAAC,8BAA8B,KAAK,GAAG,MAAM;EACjD,MAAM,cAAc,QAAQ,eAAe,KAAK,IAAI;EACpD,IAAI,eAAe,GAAG,MAAM;EAC5B,MAAM,uBAAuB,KAAK,IAAI,SAAS,WAAW,CAAC;EAC3D,IAAI,KAAK,IAAI,KAAK,QAAQ,cAAc,MAAM;EAC9C,UAAU,KAAK,IAAI,UAAU,GAAG,6BAA6B;CAC/D;AAEJ;AAEA,SAAS,uBAAuB,SAAgC;CAC9D,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,OAAO,CAAC;AAC9D;;AAGA,SAAS,8BAA8B,OAAyB;CAC9D,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,YAAY;CAClB,IAAI,UAAU,SAAS,4BAA4B,OAAO;CAC1D,OACE,OAAO,UAAU,YAAY,YAAY,gCAAgC,KAAK,UAAU,OAAO;AAEnG;;;;ACvGA,eAAsB,sCACpB,SAC8C;CAC9C,MAAM,SAAS,MAAM,QAAQ,WAAW,WAAW,QAAQ,OAAO;CAClE,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,iDAAiD;CAC9E,IAAI,OAAO,UACT,OAAO,OAAO,OAAO;EAAE,UAAU;EAAO,UAAU,OAAO;EAAU,aAAa;CAAK,CAAC;CAExF,MAAM,mBAAmB,wBACvB,QAAQ,oBAAoB,OAAO,MAAM,QAAQ,gBACnD;CACA,IAAI,mBAAmB,OAAO,MAAM,QAAQ,kBAC1C,MAAM,IAAI,MAAM,+DAA+D;CAIjF,KADY,QAAQ,OAAO,KAAK,IAAA,CACxB,IAAI,OAAO,MAAM,kBACvB,MAAM,IAAI,MAAM,2CAA2C;CAG7D,MAAM,sBAAsB,yBAAyB,gBAAgB;CACrE,MAAM,qBAAqB,IAAI,iCAAiC,QAAQ,UAAU;CAClF,MAAM,cAAc,qCACZ,wBAAwB,OAAO,OAAO,QAAQ,eAAe,GACnE,qBACA,6CACF;CACA,MAAM,iBAAiB,+BACrB,OAAO,kBAAkB;EAavB,8CAA8C,MAZxB,QAAQ,SAAS,KACrC;GACE,aAAa,OAAO,MAAM;GAC1B,qBAAqB,OAAO,MAAM;EACpC,GACA;GACE,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,cAAc;EAChB,CACF,CACqD;EACrD,IAAI,QAAQ,SAAS,SAAS;GAC5B,MAAM,WAAW,MAAM,QAAQ,SAAS,QACtC;IACE,aAAa,OAAO,MAAM;IAC1B,qBAAqB,OAAO,MAAM;GACpC,GACA,EAAE,QAAQ,cAAc,CAC1B;GACA,IAAI,SAAS,aAAa,QAAQ,OAAO,KAAK,QAAQ,CAAC,CAAC,MAAM,QAAQ,QAAQ,UAAU,GACtF,MAAM,IAAI,MAAM,kEAAkE;EAEtF;EACA,OAAO,EAAE,SAAS,KAAc;CAClC,GACA,qBACA,uCACF;CAEA,MAAM,eAAe,+BACnB,YACE,kCACE,MAAM,QAAQ,MAAM,OAAO,YAAY;EACrC,aAAa,OAAO,MAAM;EAC1B,eAAe,OAAO,MAAM,QAAQ;EACpC,aAAa,OAAO,MAAM,QAAQ;EAClC,UAAU,OAAO,MAAM,QAAQ;EAC/B,QAAQ;CACV,CAAC,GACD;EACE,eAAe,OAAO,MAAM,QAAQ;EACpC,aAAa,OAAO,MAAM,QAAQ;EAClC,OAAO,OAAO,MAAM,QAAQ,cAAc;CAC5C,CACF,GACF,qBACA,oCACF;CAEA,MAAM,gBAAgB,OAAO,MAAM,QAAQ,SACvC,+BACE,YAAY;EACV,MAAM,SAAS,OAAO,MAAM,QAAQ;EACpC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,4CAA4C;EACzE,MAAM,SAAS,MAAM,QAAQ,MAAM,OAAO,MAAM;GAC9C,aAAa,OAAO,MAAM;GAC1B,eAAe,OAAO,MAAM,QAAQ;GACpC,cAAc,OAAO;GACrB,oBAAoB,OAAO;GAC3B,QAAQ;EACV,CAAC;EACD,IAAI,OAAO,WAAW,QAAQ,OAAO,KAAK,MAAM,CAAC,CAAC,MAAM,QAAQ,QAAQ,QAAQ,GAC9E,MAAM,IAAI,MAAM,sDAAsD;EAExE,OAAO,EAAE,QAAQ,KAAc;CACjC,GACA,qBACA,kCACF,IACA,KAAA;CAEJ,MAAM,kBAAkB,QAAQ,WAAW,CACzC,cACA,iBAAiB,QAAQ,QAAQ,KAAA,CAAS,CAC5C,CAAU;CACV,MAAM,CAAC,oBAAoB,kBAAkB,MAAM,QAAQ,WAAW,CACpE,aACA,cACF,CAAU;CACV,MAAM,WAAsB,CAAC,oBAAoB,cAAc,CAAC,CAC7D,QAAQ,YAA8C,QAAQ,WAAW,UAAU,CAAC,CACpF,KAAK,YAAY,QAAQ,MAAM;CAClC,MAAM,CAAC,cAAc,iBAAiB,MAAM;CAC5C,KAAK,MAAM,WAAW,CAAC,cAAc,aAAa,GAChD,IAAI,QAAQ,WAAW,YAAY,SAAS,KAAK,QAAQ,MAAM;CAEjE,IAAI,SAAS,SAAS,GACpB,MAAM,IAAI,eAAe,UAAU,+CAA+C;CAGpF,IAAI,aAAa,WAAW,aAC1B,MAAM,IAAI,MAAM,sDAAsD;CAExE,MAAM,QAAQ,aAAa;CAC3B,MAAM,kBAAkB,MAAM,qCAE1B,wCACE;EACE,aAAa,OAAO,MAAM;EAC1B,qBAAqB,OAAO,MAAM;EAClC,eAAe,OAAO,MAAM,QAAQ;CACtC,GACA,OACA,QAAQ,eACV,GACF,qBACA,gDACF;CACA,MAAM,eACJ,OAAO,UAAU,aAAa,MAAM,MAAM,eAAe,IACrD,6BACA;CACN,MAAM,kBAAkB,MAAM,qCAE1B,+BAA+B,QAAQ,iBAAiB;EACtD,aAAa,OAAO,MAAM;EAC1B,SAAS;EACT,OAAO,wBAAwB;GAC7B,MAAM;GACN,aAAa,OAAO,MAAM;GAC1B,SAAS,OAAO,MAAM;GACtB,cAAc,OAAO,MAAM;GAC3B,qBAAqB,OAAO,MAAM;GAClC,8BACE,OAAO,MAAM,oBAAoB,uBAAuB;GAC1D;GACA,gBAAgB;GAChB,uBAAuB,gBAAgB;GACvC,cAAc,OAAO,MAAM,QAAQ,WAAW,KAAA;EAChD,CAAC;CACH,CAAC,GACH,qBACA,gDACF;CACA,MAAM,SAAS,OAAO,MAAM,QAAQ;CACpC,OAAO,MAAM,QAAQ,WAAW,eAAe,QAAQ,SAAS;EAC9D;EACA,OAAO,MAAM;EACb,iBAAiB,gBAAgB;EACjC;EACA,SAAS;GACP,SAAS;GACT,qBAAqB,OAAO,MAAM;EACpC;EACA,OAAO;GACL,QAAQ;GACR,eAAe,OAAO,MAAM,QAAQ;GACpC,aAAa,OAAO,MAAM,QAAQ;EACpC;EACA,GAAI,SACA,EACE,QAAQ;GACN,QAAQ;GACR,eAAe,OAAO,MAAM,QAAQ;GACpC,cAAc,OAAO;GACrB,oBAAoB,OAAO;EAC7B,EACF,IACA,CAAC;CACP,CAAC;AACH;AAEA,eAAe,wBACb,OACA,WAIC;CACD,MAAM,CAAC,WAAW,gBAAgB,MAAM,QAAQ,IAAI,CAClD,qBAAqB,MAAM,oBAAoB,eAAe,SAAS,GACvE,qBAAqB,MAAM,oBAAoB,wBAAwB,SAAS,CAClF,CAAC;CACD,MAAM,OAAO,0CAA0C,MACrD,oBAAoB,WAAW,MAAM,CACvC;CACA,IAAI,MAAM,oBAAoB,cAAc,WAAW,MAAM,qBAC3D,MAAM,IAAI,MAAM,oEAAoE;CAEtF,MAAM,kBAAkB,oBAAoB,cAAc,yBAAyB;CACnF,MAAM,UAAU,2CAA2C,MAAM;EAC/D,GAAG;EACH,QAAQ,MAAM,oBAAoB,uBAAuB;CAC3D,CAAC;CACD,IACE,QAAQ,iBAAiB,MAAM,gBAC/B,QAAQ,cAAc,WAAW,MAAM,uBACvC,KAAK,QAAQ,iBAAiB,MAAM,gBACpC,KAAK,gBAAgB,MAAM,aAE3B,MAAM,IAAI,MAAM,gEAAgE;CAElF,OAAO;EAAE;EAAM;CAAQ;AACzB;AAEA,SAAS,oBAAoB,OAAmB,OAAwC;CACtF,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC;CACzD,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,sBAAsB,MAAM,eAAe,EAAE,OAAO,MAAM,CAAC;CAC7E;CACA,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D,MAAM,IAAI,MAAM,sBAAsB,MAAM,mBAAmB;CAEjE,IAAI,CAAC,OAAO,KAAK,wBAAwB,MAAM,CAAC,CAAC,CAAC,OAAO,OAAO,KAAK,KAAK,CAAC,GACzE,MAAM,IAAI,MAAM,sBAAsB,MAAM,yBAAyB;CAEvE,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtLA,MAAM,kCAAuC,IAAI,IAA4B,CAC3E,WACA,kBACF,CAAC;AAED,MAAM,iCAAsC,IAAI,IAA8B,CAAC,UAAU,SAAS,CAAC;;;;;;;;;;;;;;AAenG,eAAsB,sBACpB,WACA,UAAwC,CAAC,GACP;CAClC,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,IAAI,CAAC,gBAAgB,IAAI,SAAS,GAChC,MAAM,IAAI,MAAM,yCAAyC,WAAW;CAEtE,KAAK,MAAM,CAAC,MAAM,WAAW,CAC3B,CAAC,kBAAkB,cAAc,GACjC,CAAC,kBAAkB,cAAc,CACnC,GACE,IAAI,CAAC,eAAe,IAAI,MAAM,GAC5B,MAAM,IAAI,MAAM,8BAA8B,KAAK,WAAW,QAAQ;CAI1E,MAAM,OAAO,QAAQ,SAAS;CAC9B,MAAM,YAAY,MAAM,eAAe,IAAI;CAC3C,IAAI,cAAc,QAAQ,CAAC,UAAU,YAAY,KAAK,UAAU,eAAe,GAC7E,MAAM,IAAI,MAAM,iDAAiD,WAAW;CAK9E,MAAM,eAAe,MAAM,SAAS,IAAI;CAExC,MAAM,OAAO,WAAW,QAAQ;CAGhC,KAAK,OAAO,mBAAmB,UAAU,GAAG;CAC5C,MAAM,SAAS;EAAE,OAAO;EAAG,aAAa;EAAG,UAAU;EAAG,OAAO;CAAE;CACjE,MAAM,WAAqC,CAAC;CAE5C,MAAM,WAAW,MAAc,QAAsC,WAA0B;EAC7F,MAAM,OAAO,SAAS,MAAM,IAAI;EAChC,SAAS,KACP,OAAO,OAAO,WAAW,KAAA,IAAY;GAAE,MAAM;GAAM;EAAO,IAAI;GAAE,MAAM;GAAM;GAAQ;EAAO,CAAC,CAC9F;EAGA,KAAK,OAAO,aAAa,KAAK,IAAI,OAAO,IAAI,UAAU,GAAG,GAAG;CAC/D;;CAGA,MAAM,iBAAiB,SAA0B;EAC/C,IAAI,mBAAmB,YAAY,SAAS,MAAM,OAAO;EACzD,QAAQ,MAAM,mBAAmB;EACjC,OAAO;CACT;CAEA,MAAM,QAAQ,OAAO,SAAgC;EACnD,MAAM,OAAO,MAAM,eAAe,IAAI;EACtC,IAAI,SAAS,MAAM;GACjB,IAAI,cAAc,IAAI,GAAG;GACzB,MAAM,IAAI,MAAM,qDAAqD,SAAS,MAAM,IAAI,GAAG;EAC7F;EACA,MAAM,OAAO,SAAS,MAAM,IAAI;EAChC,MAAM,OAAO,UAAU,KAAK,MAAM,WAAW,KAAK,YAAY,GAAG,KAAK,eAAe,CAAC;EAEtF,IAAI,KAAK,YAAY,GAAG;GACtB,IAAI;GACJ,IAAI;IACF,UAAU,MAAM,QAAQ,IAAI;GAC9B,SAAS,OAAO;IACd,IAAI,UAAU,KAAK,KAAK,cAAc,IAAI,GAAG;IAC7C,MAAM;GACR;GACA,OAAO,eAAe;GACtB,KAAK,OAAO,cAAc,KAAK,IAAI,KAAK,GAAG;GAC3C,KAAK,MAAM,SAAS,QAAQ,KAAK,GAAG,MAAM,MAAM,KAAK,MAAM,KAAK,CAAC;GACjE;EACF;EAEA,IAAI,KAAK,eAAe,GAAG;GACzB,MAAM,kBAAkB,MAAM,MAAM,IAAI;GACxC;EACF;EAEA,IAAI,CAAC,KAAK,OAAO,GACf,MAAM,IAAI,MAAM,iDAAiD,MAAM;EAEzE,MAAM,OAAO,MAAM,WAAW,IAAI;EAClC,IAAI,SAAS,MAAM;GACjB,IAAI,cAAc,IAAI,GAAG;GACzB,MAAM,IAAI,MAAM,qDAAqD,MAAM;EAC7E;EACA,OAAO,SAAS;EAChB,OAAO,SAAS,KAAK;EACrB,KAAK,OAAO,SAAS,KAAK,IAAI,KAAK,IAAI,KAAK,WAAW,IAAI,KAAK,OAAO,GAAG;CAC5E;CAEA,MAAM,oBAAoB,OAAO,MAAc,MAAc,SAAgC;EAC3F,IAAI;EACJ,IAAI;GACF,SAAS,MAAM,SAAS,IAAI;EAC9B,SAAS,OAAO;GACd,IAAI,UAAU,KAAK,KAAK,cAAc,IAAI,GAAG;GAC7C,MAAM;EACR;EACA,MAAM,UAAU,WAA+C;GAC7D,IAAI,mBAAmB,UACrB,MAAM,IAAI,MACR,uCAAuC,WAAW,MAAM,EAAE,IAAI,KAAK,MAAM,QAC3E;GAEF,QAAQ,MAAM,QAAQ,MAAM;EAC9B;EACA,IAAI,WAAW,MAAM,GAAG,OAAO,OAAO,kBAAkB;EACxD,IAAI,CAAC,SAAS,MAAM,QAAQ,QAAQ,IAAI,GAAG,MAAM,CAAC,GAAG,OAAO,OAAO,sBAAsB;EACzF,IAAI;EACJ,IAAI;GACF,iBAAiB,MAAM,SAAS,IAAI;EACtC,QAAQ;GAEN,OAAO,OAAO,oBAAoB;EACpC;EACA,IAAI,CAAC,SAAS,cAAc,cAAc,GAAG,OAAO,OAAO,+BAA+B;EAC1F,OAAO,YAAY;EACnB,KAAK,OAAO,YAAY,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG;CACtD;CAEA,MAAM,MAAM,IAAI;CAChB,OAAO,OAAO,OAAO;EACnB;EACA,QAAQ,UAAU,KAAK,OAAO,KAAK;EACnC,OAAO,OAAO;EACd,aAAa,OAAO;EACpB,UAAU,OAAO;EACjB,OAAO,OAAO;EACd,UAAU,OAAO,OAAO,QAAQ;CAClC,CAAC;AACH;;;;;;;;;;;;;;AAeA,eAAsB,kBACpB,OACkC;CAClC,MAAM,SAAS,QAAQ,MAAM,MAAM;CACnC,MAAM,cAAc,QAAQ,MAAM,WAAW;CAC7C,IAAI,WAAW,eAAe,SAAS,QAAQ,WAAW,GACxD,MAAM,IAAI,MAAM,iDAAiD;CAEnE,MAAM,mBAAmB,MAAM,eAAe,WAAW;CACzD,IAAI,qBAAqB,QAAQ,CAAC,iBAAiB,YAAY,GAC7D,MAAM,IAAI,MACR,6DAA6D,MAAM,aACrE;CAGF,MAAM,aAAa,MAAM,sBAAsB,QAAQ,EACrD,GAAI,MAAM,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,MAAM,UAAU,EACxE,CAAC;CACD,KAAK,MAAM,SAAS,MAAM,QAAQ,MAAM,EAAA,CAAG,KAAK,GAAG;EACjD,IAAK,MAAM,eAAe,KAAK,aAAa,IAAI,CAAC,MAAO,MACtD,MAAM,IAAI,MAAM,qDAAqD,MAAM;EAE7E,MAAM,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,aAAa,IAAI,GAAG;GACpD,WAAW;GACX,OAAO;GACP,cAAc;GACd,kBAAkB;EACpB,CAAC;CACH;CACA,OAAO;AACT;;AAGA,eAAe,WACb,MAC8D;CAC9D,IAAI;CACJ,IAAI;EACF,aAAa,MAAM,KACjB,MACAA,UAAY,YACT,OAAOA,UAAY,eAAe,WAAWA,UAAY,aAAa,EAC3E;CACF,SAAS,OAAO;EACd,IAAI,UAAU,KAAK,GAAG,OAAO;EAC7B,MAAM;CACR;CACA,IAAI;EACF,MAAM,OAAO,WAAW,QAAQ;EAChC,MAAM,SAAS,OAAO,YAAY,OAAO,IAAI;EAC7C,IAAI,QAAQ;EACZ,OAAO,MAAM;GACX,MAAM,EAAE,cAAc,MAAM,WAAW,KAAK,QAAQ,GAAG,OAAO,YAAY,IAAI;GAC9E,IAAI,cAAc,GAAG;GACrB,SAAS;GACT,KAAK,OAAO,OAAO,SAAS,GAAG,SAAS,CAAC;EAC3C;EAGA,OAAO;GAAE,QAAQ,UAAU,KAAK,OAAO,KAAK;GAAqB,YAAY;EAAM;CACrF,UAAU;EACR,MAAM,WAAW,MAAM;CACzB;AACF;;;AAIA,SAAS,UACP,MACA,WACA,aACA,gBACQ;CACR,MAAM,OAAO,OAAO,IAAI;CACxB,IAAI,cAAc,oBAAoB,OAAO,OAAO,OAAO,GAAK;CAChE,IAAI,aAAa,OAAO;CACxB,IAAI,gBAAgB,OAAO;CAC3B,QAAQ,OAAO,QAAW,IAAI,QAAQ;AACxC;AAEA,SAAS,WAAW,QAA8C;CAChE,QAAQ,QAAR;EACE,KAAK,oBACH,OAAO;EACT,KAAK,wBACH,OAAO;EACT,KAAK,iCACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,SAAS,SAAS,MAAc,MAAsB;CACpD,OAAO,SAAS,MAAM,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,KAAK;AACtD;AAEA,SAAS,SAAS,MAAc,MAAuB;CACrD,OAAO,SAAS,QAAQ,KAAK,WAAW,GAAG,OAAO,KAAK;AACzD;AAEA,SAAS,UAAU,OAAyB;CAC1C,OAAQ,OAAqC,SAAS;AACxD;AAEA,eAAe,eAAe,MAAiE;CAC7F,IAAI;EACF,OAAO,MAAM,MAAM,IAAI;CACzB,SAAS,OAAO;EACd,IAAI,UAAU,KAAK,GAAG,OAAO;EAC7B,MAAM;CACR;AACF"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["canonicalCandidateBytes","canonicalCandidateBytes","fsConstants"],"sources":["../../src/candidate-execution/builder.ts","../../src/candidate-execution/claim-file-store.ts","../../src/candidate-execution/dispose.ts","../../src/candidate-execution/protected-model-grant.ts","../../src/candidate-execution/recover.ts","../../src/candidate-execution/workspace-tree.ts"],"sourcesContent":["import type { CodeSurface } from '@tangle-network/agent-eval/campaign'\nimport { verifyCodeSurface } from '@tangle-network/agent-eval/campaign'\nimport type {\n AgentCandidateCodeDisabled,\n AgentCandidateCodeNoOp,\n AgentCandidateExecution,\n AgentCandidateGitHubRepository,\n AgentCandidateKnowledge,\n AgentCandidateMemoryPolicy,\n AgentCandidateProfile,\n AgentProfile,\n AgentProfileDiff,\n} from '@tangle-network/agent-interface'\nimport { type AgentCandidateBundleInput, sealAgentCandidateBundle } from './bundle'\nimport { embeddedCandidateArtifact } from './digest'\nimport {\n applyExactAgentProfileDiff,\n freezeGenericAgentCandidateProfile,\n parseExactAgentProfile,\n parseExactAgentProfileDiff,\n parseExactCandidateProfile,\n} from './profile'\n\n/** A complete profile that can be frozen without losing behavior. */\nexport type AgentCandidateProfileSource =\n | {\n kind: 'profile'\n profile: AgentProfile\n }\n | {\n kind: 'profile-diffs'\n base: AgentProfile\n /** Applied in order before the resulting profile is frozen into the bundle. */\n diffs: readonly AgentProfileDiff[]\n }\n | {\n kind: 'candidate-profile'\n /** Already converted to the closed, secret-free candidate profile contract. */\n profile: AgentCandidateProfile\n }\n\n/** The only accepted path from an agent-eval code candidate to executable bytes. */\nexport interface AgentCandidateCodeSurfaceSource {\n kind: 'code-surface'\n surface: CodeSurface\n repository: AgentCandidateGitHubRepository\n /** Optional parent directory used to resolve a relative `surface.worktreeRef`. */\n worktreeDir?: string\n}\n\n/** Explicit control/no-op code or one finalized CodeSurface whose bytes must still verify. */\nexport type AgentCandidateCodeSource =\n | AgentCandidateCodeDisabled\n | AgentCandidateCodeNoOp\n | AgentCandidateCodeSurfaceSource\n\n/** Complete measured surfaces and execution policy compiled into one candidate bundle. */\nexport interface BuildAgentCandidateBundleInput {\n profile: AgentCandidateProfileSource\n code: AgentCandidateCodeSource\n execution: AgentCandidateExecution\n knowledge?: AgentCandidateKnowledge\n memory: AgentCandidateMemoryPolicy\n}\n\n/**\n * Compile one measured profile/code candidate into the immutable execution\n * contract. Code bytes are re-read and verified by agent-eval before they are\n * embedded. The returned bundle is schema-validated, canonically digested, and\n * deeply immutable; call `verifyAgentCandidateBundle` at the execution boundary\n * to re-read external memory, repository, and workspace artifacts.\n */\nexport function buildAgentCandidateBundle(\n input: BuildAgentCandidateBundleInput,\n): ReturnType<typeof sealAgentCandidateBundle> {\n const bundle: AgentCandidateBundleInput = {\n kind: 'agent-candidate-bundle',\n digestAlgorithm: 'rfc8785-sha256',\n profile: compileCandidateProfile(input.profile),\n code: compileCandidateCode(input.code),\n execution: input.execution,\n ...(input.knowledge !== undefined ? { knowledge: input.knowledge } : {}),\n memory: input.memory,\n }\n return sealAgentCandidateBundle(bundle)\n}\n\nfunction compileCandidateProfile(source: AgentCandidateProfileSource): AgentCandidateProfile {\n if (source.kind === 'candidate-profile') {\n return parseExactCandidateProfile(source.profile)\n }\n\n if (source.kind === 'profile') {\n return freezeGenericAgentCandidateProfile(source.profile)\n }\n\n if (source.kind !== 'profile-diffs') {\n throw new Error(\n `unsupported candidate profile source: ${String((source as { kind?: unknown }).kind)}`,\n )\n }\n if (source.diffs.length === 0) {\n throw new Error('profile-diffs source requires at least one AgentProfileDiff')\n }\n let profile = parseExactAgentProfile(source.base, 'base profile')\n for (const [index, inputDiff] of source.diffs.entries()) {\n const diff = parseExactAgentProfileDiff(inputDiff, `profile diff ${index}`)\n profile = applyExactAgentProfileDiff(profile, diff, `profile diff ${index}`)\n }\n return freezeGenericAgentCandidateProfile(profile)\n}\n\nfunction compileCandidateCode(source: AgentCandidateCodeSource): AgentCandidateBundleInput['code'] {\n if (source.kind === 'disabled' || source.kind === 'no-op') return source\n if (source.kind !== 'code-surface') {\n throw new Error(\n `unsupported candidate code source: ${String((source as { kind?: unknown }).kind)}`,\n )\n }\n\n const verified = verifyCodeSurface(source.surface, source.worktreeDir)\n const patch = embeddedCandidateArtifact(verified.patchBytes)\n if (\n patch.sha256 !== source.surface.patch.sha256 ||\n patch.byteLength !== source.surface.patch.byteLength\n ) {\n throw new Error('verified CodeSurface patch bytes do not match its content identity')\n }\n return {\n kind: 'git-patch',\n repository: source.repository,\n baseCommit: source.surface.baseCommit,\n baseTree: source.surface.baseTree,\n candidateTree: source.surface.candidateTree,\n patch: { format: 'git-diff-binary', artifact: patch },\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { linkSync } from 'node:fs'\nimport { mkdir, open, unlink } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { Sha256Digest } from '@tangle-network/agent-interface'\n\nimport {\n type AgentCandidateExecutionAttemptRecord,\n type AgentCandidateExecutionAttemptRef,\n type AgentCandidateExecutionClaim,\n type AgentCandidateExecutionClaimResult,\n type AgentCandidateExecutionClaimStore,\n type AgentCandidateExecutionFinishResult,\n type AgentCandidateExecutionLease,\n type AgentCandidateExecutionPhase,\n type AgentCandidateExecutionPhaseResult,\n type AgentCandidateExecutionRecoveryEvidence,\n type AgentCandidateExecutionStageResult,\n type AgentCandidateExecutionTerminalRecord,\n type AgentCandidateExecutionTerminalResult,\n type AgentCandidateRetryRejection,\n candidateClaimFileInternals,\n} from './claim'\nimport {\n assertRecoveryMatchesStaged,\n assertTerminalAllowedInPhase,\n assertTerminalMatchesClaim,\n assertTerminalMatchesStaged,\n recoveredTerminalRecord,\n rejectedFinish,\n rejectedStage,\n requireStagedTerminal,\n sealTerminalDigest,\n terminalRecord,\n} from './claim-terminal'\nimport { canonicalCandidateBytes } from './digest'\n\nconst {\n assertExpiredLease,\n assertLease,\n assertSameSlot,\n assertUnexpiredLease,\n attemptRecord,\n claimSlot,\n leaseDigest,\n newLease,\n readClaim,\n readClaimIfPresent,\n readTerminal,\n readTerminalIfPresent,\n readTransitionIfPresent,\n rejectedExistingClaim,\n rejectedRetry,\n retryRejection,\n sealAttemptRef,\n sealClaim,\n sealLease,\n} = candidateClaimFileInternals\n\nexport interface FileAgentCandidateExecutionClaimStoreOptions {\n /** Evaluator-owned directory shared by every process allowed to execute candidates. */\n directory: string\n /** Testable evaluator clock; defaults to `Date.now`. */\n now?: () => number\n}\n\n/** Cross-process lifecycle implemented as fsynced, create-if-absent records. */\nexport class FileAgentCandidateExecutionClaimStore implements AgentCandidateExecutionClaimStore {\n private readonly directory: string\n private readonly now: () => number\n\n constructor(options: FileAgentCandidateExecutionClaimStoreOptions) {\n if (options.directory.length === 0) {\n throw new Error('candidate execution claim directory must not be empty')\n }\n this.directory = options.directory\n this.now = options.now ?? Date.now\n }\n\n async tryClaim(\n requested: AgentCandidateExecutionClaim,\n ): Promise<AgentCandidateExecutionClaimResult> {\n const claim = sealClaim(requested)\n await mkdir(this.directory, { recursive: true })\n const claimPath = this.claimPath(claim)\n const existing = await readClaimIfPresent(claimPath)\n if (existing) {\n assertSameSlot(existing.claim, claim, claimPath)\n return rejectedExistingClaim(existing.claim, claim)\n }\n assertUnexpiredLease(claim.leaseExpiresAtMs, this.now())\n const retryFailure = await this.retryFailure(claim)\n if (retryFailure) return rejectedRetry(claim, retryFailure)\n\n const lease = newLease(claim)\n const acquired = await writeRecordIfAbsent(this.directory, claimPath, {\n ...claim,\n phase: 'claimed',\n leaseDigest: leaseDigest(lease),\n })\n if (acquired) return Object.freeze({ acquired: true, claim, lease })\n\n const winner = await readClaim(claimPath)\n assertSameSlot(winner.claim, claim, claimPath)\n return rejectedExistingClaim(winner.claim, claim)\n }\n\n async getAttempt(\n requestedAttempt: AgentCandidateExecutionAttemptRef,\n ): Promise<AgentCandidateExecutionAttemptRecord | undefined> {\n return await this.storedAttempt(sealAttemptRef(requestedAttempt))\n }\n\n async markCandidateMayRun(\n requestedLease: AgentCandidateExecutionLease,\n ): Promise<AgentCandidateExecutionPhaseResult> {\n const lease = sealLease(requestedLease)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const state = await this.transitionState(stored.claim)\n if (state.phase === 'candidate-may-run') {\n return Object.freeze({ marked: false, phase: 'candidate-may-run' })\n }\n if (state.staged) {\n throw new Error('candidate execution terminal was staged before candidate-may-run phase')\n }\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const marked = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(stored.claim, 1),\n {\n kind: 'candidate-execution-phase',\n executionId: stored.claim.executionId,\n attempt: stored.claim.attempt,\n executionPlanDigest: stored.claim.executionPlanDigest,\n phase: 'candidate-may-run',\n },\n this.ownerPublication(stored.claim),\n )\n if (marked) return Object.freeze({ marked: true, phase: 'candidate-may-run' })\n const winner = await this.transitionState(stored.claim)\n if (winner.phase === 'candidate-may-run') {\n return Object.freeze({ marked: false, phase: 'candidate-may-run' })\n }\n throw new Error('candidate execution terminal was staged before candidate-may-run phase')\n }\n\n async stageTerminal(\n requestedLease: AgentCandidateExecutionLease,\n result: AgentCandidateExecutionTerminalResult,\n ): Promise<AgentCandidateExecutionStageResult> {\n const lease = sealLease(requestedLease)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const terminal = terminalRecord(stored.claim, result)\n const state = await this.transitionState(stored.claim)\n if (state.staged) return rejectedStage(state.staged, terminal)\n assertTerminalAllowedInPhase(state.phase, terminal)\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const transition = state.phase === 'claimed' ? 1 : 2\n const staged = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(stored.claim, transition),\n {\n kind: 'candidate-execution-pending-terminal',\n terminal,\n },\n this.ownerPublication(stored.claim),\n )\n if (staged) return Object.freeze({ staged: true, terminal })\n const winner = await this.transitionState(stored.claim)\n if (!winner.staged) {\n throw new Error('candidate execution phase transition won while staging terminal')\n }\n return rejectedStage(winner.staged, terminal)\n }\n\n async finish(\n requestedLease: AgentCandidateExecutionLease,\n requestedTerminalDigest: Sha256Digest,\n ): Promise<AgentCandidateExecutionFinishResult> {\n const lease = sealLease(requestedLease)\n const terminalDigest = sealTerminalDigest(requestedTerminalDigest)\n const claimPath = this.claimPath(lease)\n const stored = await readClaim(claimPath)\n assertSameSlot(stored.claim, lease, claimPath)\n assertLease(stored.leaseDigest, stored.claim.leaseExpiresAtMs, lease)\n const state = await this.transitionState(stored.claim)\n const staged = requireStagedTerminal(state.staged, terminalDigest)\n const terminalPath = this.terminalPath(lease)\n const existing = await readTerminalIfPresent(terminalPath)\n if (existing) {\n assertTerminalMatchesClaim(existing, stored.claim, terminalPath)\n assertTerminalMatchesStaged(existing, staged, terminalPath)\n return rejectedFinish(existing, terminalDigest)\n }\n assertUnexpiredLease(stored.claim.leaseExpiresAtMs, this.now())\n const finished = await writeRecordIfAbsent(\n this.directory,\n terminalPath,\n {\n terminal: staged,\n },\n this.ownerPublication(stored.claim),\n )\n if (finished) return Object.freeze({ finished: true, terminal: staged })\n const winner = await readTerminal(terminalPath)\n assertSameSlot(winner, lease, terminalPath)\n assertTerminalMatchesClaim(winner, stored.claim, terminalPath)\n assertTerminalMatchesStaged(winner, staged, terminalPath)\n return rejectedFinish(winner, terminalDigest)\n }\n\n async recoverExpired(\n requestedAttempt: AgentCandidateExecutionAttemptRef,\n evidence: AgentCandidateExecutionRecoveryEvidence,\n ): Promise<AgentCandidateExecutionFinishResult> {\n const attempt = sealAttemptRef(requestedAttempt)\n const record = await this.storedAttempt(attempt)\n if (!record) throw new Error('candidate execution recovery does not name an acquired attempt')\n const recovered = recoveredTerminalRecord(record.claim, record.phase, evidence)\n if (record.staged) assertRecoveryMatchesStaged(record.staged, recovered)\n const requestedDigest = record.staged?.terminalDigest ?? recovered.terminalDigest\n if (record.terminal) return rejectedFinish(record.terminal, requestedDigest)\n assertExpiredLease(record.claim.leaseExpiresAtMs, this.now())\n\n let staged = record.staged\n if (!staged) {\n const transition = record.phase === 'claimed' ? 1 : 2\n const didStage = await writeRecordIfAbsent(\n this.directory,\n this.transitionPath(record.claim, transition),\n {\n kind: 'candidate-execution-pending-terminal',\n terminal: recovered,\n },\n )\n if (didStage) {\n staged = recovered\n } else {\n const winner = await this.transitionState(record.claim)\n if (!winner.staged) {\n throw new Error(\n 'candidate execution recovery lost terminal staging to a phase transition',\n )\n }\n assertRecoveryMatchesStaged(winner.staged, recovered)\n staged = winner.staged\n }\n }\n\n const terminalPath = this.terminalPath(attempt)\n const didFinish = await writeRecordIfAbsent(this.directory, terminalPath, {\n terminal: staged,\n })\n if (didFinish) return Object.freeze({ finished: true, terminal: staged })\n const winner = await readTerminal(terminalPath)\n assertSameSlot(winner, attempt, terminalPath)\n assertTerminalMatchesClaim(winner, record.claim, terminalPath)\n assertTerminalMatchesStaged(winner, staged, terminalPath)\n return rejectedFinish(winner, staged.terminalDigest)\n }\n\n private async storedAttempt(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ): Promise<AgentCandidateExecutionAttemptRecord | undefined> {\n const claimPath = this.claimPath(claim)\n const stored = await readClaimIfPresent(claimPath)\n if (!stored) return undefined\n assertSameSlot(stored.claim, claim, claimPath)\n const terminalPath = this.terminalPath(claim)\n const terminal = await readTerminalIfPresent(terminalPath)\n // Terminal publication follows its immutable staged outbox, so read that prerequisite later.\n const state = await this.transitionState(stored.claim)\n if (terminal) {\n assertTerminalMatchesClaim(terminal, stored.claim, terminalPath)\n if (!state.staged) {\n throw new Error(\n `candidate execution terminal record at ${terminalPath} has no staged outbox`,\n )\n }\n assertTerminalMatchesStaged(terminal, state.staged, terminalPath)\n }\n return attemptRecord(stored.claim, state.phase, state.staged, terminal)\n }\n\n private async transitionState(claim: AgentCandidateExecutionClaim): Promise<{\n phase: AgentCandidateExecutionPhase\n staged?: AgentCandidateExecutionTerminalRecord\n }> {\n const firstPath = this.transitionPath(claim, 1)\n const first = await readTransitionIfPresent(firstPath, claim)\n if (!first) return { phase: 'claimed' }\n if (first.kind === 'pending') return { phase: 'claimed', staged: first.terminal }\n const secondPath = this.transitionPath(claim, 2)\n const second = await readTransitionIfPresent(secondPath, claim)\n if (!second) return { phase: 'candidate-may-run' }\n if (second.kind !== 'pending') {\n throw new Error(`candidate execution transition at ${secondPath} repeats the phase marker`)\n }\n return { phase: 'candidate-may-run', staged: second.terminal }\n }\n\n private async retryFailure(\n claim: AgentCandidateExecutionClaim,\n ): Promise<AgentCandidateRetryRejection | undefined> {\n if (claim.attempt === 1) return undefined\n return retryRejection(\n claim,\n await this.storedAttempt({\n executionId: claim.executionId,\n attempt: claim.attempt - 1,\n }),\n )\n }\n\n private ownerPublication(claim: AgentCandidateExecutionClaim): {\n authorizePublish: () => true\n } {\n return {\n authorizePublish: () => {\n assertUnexpiredLease(claim.leaseExpiresAtMs, this.now())\n return true\n },\n }\n }\n\n private claimPath(claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>): string {\n return join(this.directory, `${claimSlot(claim)}.claim.json`)\n }\n\n private terminalPath(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ): string {\n return join(this.directory, `${claimSlot(claim)}.terminal.json`)\n }\n\n private transitionPath(\n claim: Pick<AgentCandidateExecutionClaim, 'executionId' | 'attempt'>,\n ordinal: 1 | 2,\n ): string {\n return join(this.directory, `${claimSlot(claim)}.transition-${ordinal}.json`)\n }\n}\n\n/**\n * Candidate records keep this async writer because lease authorization must run after the\n * asynchronous temp-file fsync and immediately before synchronous link publication. The\n * supervisor durability helper is synchronous and has no lease hook, so combining them would\n * either move authorization earlier or add an async race to the claim boundary.\n */\nasync function writeRecordIfAbsent(\n directory: string,\n destination: string,\n record: object,\n options: {\n /** Synchronous authorization checked after temp fsync, immediately before atomic publication. */\n authorizePublish?: () => true\n } = {},\n): Promise<boolean> {\n const temporaryPath = join(directory, `.candidate-execution-${process.pid}-${randomUUID()}.tmp`)\n const handle = await open(temporaryPath, 'wx', 0o600)\n try {\n await handle.writeFile(\n Buffer.concat([Buffer.from(canonicalCandidateBytes(record)), Buffer.from('\\n')]),\n )\n await handle.sync()\n } finally {\n await handle.close()\n }\n\n let written = false\n try {\n if (options.authorizePublish && options.authorizePublish() !== true) {\n throw new Error('candidate execution record publication was not authorized')\n }\n // Authorization and the atomic filesystem call are one synchronous critical\n // section so the event loop cannot advance an injected lease clock between them.\n linkSync(temporaryPath, destination)\n written = true\n await syncDirectory(directory)\n } catch (error) {\n if (!isNodeError(error, 'EEXIST')) throw error\n } finally {\n await unlink(temporaryPath).catch((error: unknown) => {\n if (!isNodeError(error, 'ENOENT')) throw error\n })\n }\n return written\n}\n\nasync function syncDirectory(directory: string): Promise<void> {\n const handle = await open(directory, 'r')\n try {\n await handle.sync()\n } finally {\n await handle.close()\n }\n}\n\nfunction isNodeError(error: unknown, code: string): boolean {\n return (\n error !== null &&\n typeof error === 'object' &&\n 'code' in error &&\n (error as { code?: unknown }).code === code\n )\n}\n","import { candidateCleanupDeadline, withinCandidateCleanupDeadline } from './cleanup'\nimport { sealAgentCandidateModelSettlement } from './model-settlement'\nimport {\n assertPreparedCandidateIntegrity,\n beginPreparedCandidateDisposal,\n consumePreparedCandidateExecution,\n} from './prepared-state'\nimport type { PreparedAgentCandidateExecution } from './types'\n\nexport interface DisposePreparedAgentCandidateOptions {\n cleanupTimeoutMs?: number\n}\n\n/** Revoke reservations held by a prepared candidate that will not be executed. */\nexport async function disposePreparedAgentCandidateExecution(\n prepared: PreparedAgentCandidateExecution,\n options: DisposePreparedAgentCandidateOptions = {},\n): Promise<{ disposed: true }> {\n const initialState = assertPreparedCandidateIntegrity(prepared)\n const cleanupTimeoutMs = options.cleanupTimeoutMs ?? initialState.cleanupTimeoutMs\n if (cleanupTimeoutMs > initialState.cleanupTimeoutMs) {\n throw new Error('disposal cleanup timeout exceeds the frozen preparation bound')\n }\n const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs)\n const state = beginPreparedCandidateDisposal(prepared)\n const cleanup: Array<Promise<unknown>> = []\n\n if (state.memory.mode === 'isolated') {\n const reservation = state.memoryReservation\n if (!reservation) throw new Error('isolated memory reservation is missing')\n cleanup.push(\n withinCandidateCleanupDeadline(\n async () => {\n const closed = await state.ports.memory.close({\n executionId: state.executionId,\n preparationId: reservation.preparationId,\n accessDigest: reservation.accessDigest,\n effectiveNamespace: reservation.effectiveNamespace,\n reason: 'abandoned',\n })\n if (closed.closed !== true || Object.keys(closed).some((key) => key !== 'closed')) {\n throw new Error('abandoned isolated memory access did not acknowledge closure')\n }\n },\n cleanupDeadlineAtMs,\n 'isolated memory disposal',\n ),\n )\n }\n\n cleanup.push(\n withinCandidateCleanupDeadline(\n async () => {\n const settlement = sealAgentCandidateModelSettlement(\n await state.ports.models.settleGrant({\n executionId: state.executionId,\n preparationId: state.preparationId,\n grantDigest: state.modelReservation.digest,\n resolved: state.resolvedModel,\n reason: 'abandoned',\n }),\n {\n preparationId: state.preparationId,\n grantDigest: state.modelReservation.digest,\n model: state.resolvedModel.model,\n },\n )\n if (settlement.usage.modelCalls !== 0) {\n throw new Error('unexecuted model reservation unexpectedly contains calls')\n }\n },\n cleanupDeadlineAtMs,\n 'model reservation disposal',\n ),\n )\n\n const results = await Promise.allSettled(cleanup)\n const failures = results\n .filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n .map((result) => result.reason)\n if (failures.length > 0) {\n consumePreparedCandidateExecution(prepared, 'disposal-failed')\n throw new AggregateError(failures, 'candidate preparation disposal failed')\n }\n\n consumePreparedCandidateExecution(prepared, 'disposed')\n return Object.freeze({ disposed: true as const })\n}\n","import type { AgentCandidateResolvedModel } from '@tangle-network/agent-interface'\n\nimport type {\n AgentCandidateModelGrantActivateInput,\n AgentCandidateModelGrantReserveInput,\n AgentCandidateModelGrantSettleInput,\n} from './protected-model-port'\nimport type {\n AgentCandidateModelPort,\n AgentCandidateProtectedModelActivation,\n AgentCandidateProtectedModelReservation,\n AgentCandidateProtectedModelSettlement,\n} from './types'\n\n/** Reservation fields supplied by a caller before Runtime resolves the model. */\nexport type AgentCandidateModelGrantRunReservationInput = Omit<\n AgentCandidateModelGrantReserveInput,\n 'resolved'\n>\n\n/** Values available only while one protected model grant is active. */\nexport interface ProtectedAgentCandidateModelGrantContext {\n readonly activation: AgentCandidateProtectedModelActivation\n readonly reservation: AgentCandidateProtectedModelReservation\n readonly resolved: AgentCandidateResolvedModel\n}\n\n/** Inputs for one protected grant scoped to one bounded caller unit. */\nexport interface RunProtectedAgentCandidateModelGrantOptions<TResult> {\n /** Runtime port that validates and settles the evaluator-owned grant. */\n readonly port: AgentCandidateModelPort\n /** Provider-neutral model request resolved before any grant is reserved. */\n readonly resolve: Parameters<AgentCandidateModelPort['resolve']>[0]\n /** One bounded unit's immutable identity, attempt, expiry, and limits. */\n readonly reserve: AgentCandidateModelGrantRunReservationInput\n /** Must be no later than the reservation expiry. */\n readonly deadlineAtMs: AgentCandidateModelGrantActivateInput['deadlineAtMs']\n /** Execute exactly one bounded unit while the activated environment is valid. */\n readonly execute: (context: ProtectedAgentCandidateModelGrantContext) => Promise<TResult>\n}\n\n/** Result and sealed settlement returned after one protected grant closes. */\nexport interface RunProtectedAgentCandidateModelGrantResult<TResult> {\n readonly value: TResult\n readonly resolved: AgentCandidateResolvedModel\n readonly reservation: AgentCandidateProtectedModelReservation\n readonly settlement: AgentCandidateProtectedModelSettlement\n}\n\nconst SETTLEMENT_RETRY_INITIAL_DELAY_MS = 25\nconst SETTLEMENT_RETRY_MAX_DELAY_MS = 1_000\n\n/**\n * Run one bounded unit under a protected model grant.\n *\n * Runtime owns the grant lifecycle; callers own the unit boundary and any\n * durable scheduling or accounting around it. A reserved grant is settled\n * after activation failure or callback failure, and the callback error is\n * preserved when settlement also fails.\n */\nexport async function runProtectedAgentCandidateModelGrant<TResult>(\n options: RunProtectedAgentCandidateModelGrantOptions<TResult>,\n): Promise<RunProtectedAgentCandidateModelGrantResult<TResult>> {\n if (typeof options.execute !== 'function') {\n throw new TypeError('protected model grant execute callback is required')\n }\n\n const resolved = await options.port.resolve(options.resolve)\n const reservation = await options.port.reserveGrant({\n ...options.reserve,\n resolved,\n })\n\n let value!: TResult\n let executionError: unknown\n let executionFailed = false\n let activated = false\n let reason: AgentCandidateModelGrantSettleInput['reason'] = 'preparation-failed'\n\n try {\n const activation = await options.port.activateGrant({\n executionId: options.reserve.executionId,\n preparationId: options.reserve.preparationId,\n grantDigest: reservation.digest,\n resolved,\n deadlineAtMs: options.deadlineAtMs,\n })\n activated = true\n value = await options.execute({ activation, reservation, resolved })\n reason = 'completed'\n } catch (error) {\n executionError = error\n executionFailed = true\n if (activated) reason = 'failed'\n }\n\n let settlement: AgentCandidateProtectedModelSettlement\n try {\n settlement = await settleProtectedModelGrant(options, {\n executionId: options.reserve.executionId,\n preparationId: options.reserve.preparationId,\n grantDigest: reservation.digest,\n resolved,\n reason,\n })\n } catch (settlementError) {\n if (executionFailed) {\n throw new AggregateError(\n [executionError, settlementError],\n 'protected model execution failed and its grant did not settle',\n )\n }\n throw settlementError\n }\n\n if (executionFailed) throw executionError\n return { value, resolved, reservation, settlement }\n}\n\nasync function settleProtectedModelGrant<TResult>(\n options: RunProtectedAgentCandidateModelGrantOptions<TResult>,\n input: AgentCandidateModelGrantSettleInput,\n): Promise<AgentCandidateProtectedModelSettlement> {\n let delayMs = SETTLEMENT_RETRY_INITIAL_DELAY_MS\n for (;;) {\n try {\n return await options.port.settleGrant(input)\n } catch (error) {\n if (!isCandidateGrantDrainingError(error)) throw error\n const remainingMs = options.deadlineAtMs - Date.now()\n if (remainingMs <= 0) throw error\n await waitForSettlementRetry(Math.min(delayMs, remainingMs))\n if (Date.now() >= options.deadlineAtMs) throw error\n delayMs = Math.min(delayMs * 2, SETTLEMENT_RETRY_MAX_DELAY_MS)\n }\n }\n}\n\nfunction waitForSettlementRetry(delayMs: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, delayMs))\n}\n\n/** Only the gateway's explicit draining state is retryable; auth and ledger errors fail closed. */\nfunction isCandidateGrantDrainingError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false\n const candidate = error as { code?: unknown; message?: unknown }\n if (candidate.code === 'candidate_grant_draining') return true\n return (\n typeof candidate.message === 'string' && /\\bcandidate_grant_draining\\b/u.test(candidate.message)\n )\n}\n","import type { TraceStore } from '@tangle-network/agent-eval'\nimport type {\n AgentCandidateExecutionPlanMaterial,\n AgentCandidateMaterializationReceipt,\n} from '@tangle-network/agent-interface'\nimport {\n agentCandidateExecutionPlanMaterialSchema,\n agentCandidateMaterializationReceiptSchema,\n} from '@tangle-network/agent-interface'\n\nimport { readVerifiedArtifact } from './artifacts'\nimport type {\n AgentCandidateExecutionAttemptRef,\n AgentCandidateExecutionClaim,\n AgentCandidateExecutionClaimStore,\n AgentCandidateExecutionFinishResult,\n} from './claim'\nimport {\n candidateCleanupDeadline,\n candidateCleanupTimeout,\n withinCandidateCleanupDeadline,\n} from './cleanup'\nimport { canonicalCandidateBytes } from './digest'\nimport { sealAgentCandidateExecutorStopAcknowledgement } from './executor-capture'\nimport { sealAgentCandidateModelSettlement } from './model-settlement'\nimport { persistCandidateModelSettlementEvidence } from './outcome-evidence'\nimport { persistCandidateOutputArtifact } from './output-artifacts'\nimport { RecoveryAgentCandidateTraceStore } from './protected-trace-store'\nimport type {\n AgentCandidateExecutionPorts,\n AgentCandidateExecutorPort,\n AgentCandidateOutputArtifactPort,\n} from './types'\n\nexport interface RecoverExpiredAgentCandidateOptions {\n attempt: AgentCandidateExecutionAttemptRef\n claimStore: AgentCandidateExecutionClaimStore\n executor: AgentCandidateExecutorPort\n traceStore: TraceStore\n ports: Pick<AgentCandidateExecutionPorts, 'models' | 'memory'>\n outputArtifacts: AgentCandidateOutputArtifactPort\n cleanupTimeoutMs?: number\n /** Evaluator clock; must be the same clock used by the claim store. */\n now?: () => number\n}\n\n/** Close an expired crashed attempt from persisted non-secret handles, then record failure. */\nexport async function recoverExpiredAgentCandidateExecution(\n options: RecoverExpiredAgentCandidateOptions,\n): Promise<AgentCandidateExecutionFinishResult> {\n const record = await options.claimStore.getAttempt(options.attempt)\n if (!record) throw new Error('candidate execution recovery attempt is missing')\n if (record.terminal) {\n return Object.freeze({ finished: false, terminal: record.terminal, exactReplay: true })\n }\n const cleanupTimeoutMs = candidateCleanupTimeout(\n options.cleanupTimeoutMs ?? record.claim.cleanup.cleanupTimeoutMs,\n )\n if (cleanupTimeoutMs > record.claim.cleanup.cleanupTimeoutMs) {\n throw new Error('recovery cleanup timeout exceeds the frozen preparation bound')\n }\n\n const now = options.now ?? Date.now\n if (now() < record.claim.leaseExpiresAtMs) {\n throw new Error('candidate execution lease has not expired')\n }\n\n const cleanupDeadlineAtMs = candidateCleanupDeadline(cleanupTimeoutMs)\n const recoveryTraceStore = new RecoveryAgentCandidateTraceStore(options.traceStore)\n const preparation = withinCandidateCleanupDeadline(\n () => readRecoveryPreparation(record.claim, options.outputArtifacts),\n cleanupDeadlineAtMs,\n 'expired candidate preparation evidence read',\n )\n const processClosure = withinCandidateCleanupDeadline(\n async (cleanupSignal) => {\n const stopped = await options.executor.stop(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n {\n traceStore: recoveryTraceStore,\n reason: 'failed',\n signal: cleanupSignal,\n deadlineAtMs: cleanupDeadlineAtMs,\n },\n )\n sealAgentCandidateExecutorStopAcknowledgement(stopped)\n if (options.executor.dispose) {\n const disposed = await options.executor.dispose(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n { signal: cleanupSignal },\n )\n if (disposed.disposed !== true || Object.keys(disposed).some((key) => key !== 'disposed')) {\n throw new Error('expired candidate executor did not acknowledge resource disposal')\n }\n }\n return { stopped: true as const }\n },\n cleanupDeadlineAtMs,\n 'expired candidate process termination',\n )\n\n const modelClosure = withinCandidateCleanupDeadline(\n async () =>\n sealAgentCandidateModelSettlement(\n await options.ports.models.settleGrant({\n executionId: record.claim.executionId,\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n resolved: record.claim.cleanup.resolvedModel,\n reason: 'failed',\n }),\n {\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n model: record.claim.cleanup.resolvedModel.model,\n },\n ),\n cleanupDeadlineAtMs,\n 'expired candidate model settlement',\n )\n\n const memoryClosure = record.claim.cleanup.memory\n ? withinCandidateCleanupDeadline(\n async () => {\n const memory = record.claim.cleanup.memory\n if (!memory) throw new Error('expired candidate memory handle is missing')\n const closed = await options.ports.memory.close({\n executionId: record.claim.executionId,\n preparationId: record.claim.cleanup.preparationId,\n accessDigest: memory.accessDigest,\n effectiveNamespace: memory.effectiveNamespace,\n reason: 'failed',\n })\n if (closed.closed !== true || Object.keys(closed).some((key) => key !== 'closed')) {\n throw new Error('expired candidate memory did not acknowledge closure')\n }\n return { closed: true as const }\n },\n cleanupDeadlineAtMs,\n 'expired candidate memory closure',\n )\n : undefined\n\n const closureOutcomes = Promise.allSettled([\n modelClosure,\n memoryClosure ?? Promise.resolve(undefined),\n ] as const)\n const [preparationOutcome, processOutcome] = await Promise.allSettled([\n preparation,\n processClosure,\n ] as const)\n const failures: unknown[] = [preparationOutcome, processOutcome]\n .filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected')\n .map((outcome) => outcome.reason)\n const [modelOutcome, memoryOutcome] = await closureOutcomes\n for (const outcome of [modelOutcome, memoryOutcome]) {\n if (outcome.status === 'rejected') failures.push(outcome.reason)\n }\n if (failures.length > 0) {\n throw new AggregateError(failures, 'expired candidate cleanup could not be proven')\n }\n\n if (modelOutcome.status !== 'fulfilled') {\n throw new Error('expired candidate model settlement was not recovered')\n }\n const model = modelOutcome.value\n const modelSettlement = await withinCandidateCleanupDeadline(\n () =>\n persistCandidateModelSettlementEvidence(\n {\n executionId: record.claim.executionId,\n executionPlanDigest: record.claim.executionPlanDigest,\n resolvedModel: record.claim.cleanup.resolvedModel,\n },\n model,\n options.outputArtifacts,\n ),\n cleanupDeadlineAtMs,\n 'expired candidate model-settlement persistence',\n )\n const failureClass =\n record.phase === 'claimed' && model.usage.modelCalls === 0\n ? 'pre-model-infrastructure'\n : 'unknown'\n const failureEvidence = await withinCandidateCleanupDeadline(\n () =>\n persistCandidateOutputArtifact(options.outputArtifacts, {\n executionId: record.claim.executionId,\n purpose: 'failure-evidence',\n bytes: canonicalCandidateBytes({\n kind: 'agent-candidate-recovery-failure',\n executionId: record.claim.executionId,\n attempt: record.claim.attempt,\n bundleDigest: record.claim.bundleDigest,\n executionPlanDigest: record.claim.executionPlanDigest,\n materializationReceiptDigest:\n record.claim.preparationEvidence.materializationReceipt.sha256,\n failureClass,\n processStopped: true,\n modelSettlementDigest: modelSettlement.digest,\n memoryClosed: record.claim.cleanup.memory !== undefined,\n }),\n }),\n cleanupDeadlineAtMs,\n 'expired candidate failure-evidence persistence',\n )\n const memory = record.claim.cleanup.memory\n return await options.claimStore.recoverExpired(options.attempt, {\n failureClass,\n usage: model.usage,\n modelSettlement: modelSettlement.artifact,\n failureEvidence,\n process: {\n stopped: true,\n executionPlanDigest: record.claim.executionPlanDigest,\n },\n model: {\n closed: true,\n preparationId: record.claim.cleanup.preparationId,\n grantDigest: record.claim.cleanup.modelGrantDigest,\n },\n ...(memory\n ? {\n memory: {\n closed: true,\n preparationId: record.claim.cleanup.preparationId,\n accessDigest: memory.accessDigest,\n effectiveNamespace: memory.effectiveNamespace,\n },\n }\n : {}),\n })\n}\n\nasync function readRecoveryPreparation(\n claim: AgentCandidateExecutionClaim,\n artifacts: AgentCandidateOutputArtifactPort,\n): Promise<{\n plan: AgentCandidateExecutionPlanMaterial\n receipt: AgentCandidateMaterializationReceipt\n}> {\n const [planBytes, receiptBytes] = await Promise.all([\n readVerifiedArtifact(claim.preparationEvidence.executionPlan, artifacts),\n readVerifiedArtifact(claim.preparationEvidence.materializationReceipt, artifacts),\n ])\n const plan = agentCandidateExecutionPlanMaterialSchema.parse(\n parseCanonicalBytes(planBytes, 'plan'),\n )\n if (claim.preparationEvidence.executionPlan.sha256 !== claim.executionPlanDigest) {\n throw new Error('recovery execution plan artifact does not match the claimed digest')\n }\n const receiptMaterial = parseCanonicalBytes(receiptBytes, 'materialization receipt')\n const receipt = agentCandidateMaterializationReceiptSchema.parse({\n ...receiptMaterial,\n digest: claim.preparationEvidence.materializationReceipt.sha256,\n })\n if (\n receipt.bundleDigest !== claim.bundleDigest ||\n receipt.executionPlan.digest !== claim.executionPlanDigest ||\n plan.runCell.bundleDigest !== claim.bundleDigest ||\n plan.executionId !== claim.executionId\n ) {\n throw new Error('recovery preparation evidence does not match the durable claim')\n }\n return { plan, receipt }\n}\n\nfunction parseCanonicalBytes(bytes: Uint8Array, label: string): Record<string, unknown> {\n let parsed: unknown\n try {\n parsed = JSON.parse(Buffer.from(bytes).toString('utf8'))\n } catch (error) {\n throw new Error(`candidate recovery ${label} is not JSON`, { cause: error })\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`candidate recovery ${label} must be an object`)\n }\n if (!Buffer.from(canonicalCandidateBytes(parsed)).equals(Buffer.from(bytes))) {\n throw new Error(`candidate recovery ${label} bytes are not canonical`)\n }\n return parsed as Record<string, unknown>\n}\n","/**\n * A content digest over a DIRECTORY TREE, and the per-file seed that fills one.\n *\n * The question this answers is \"is this workspace the same workspace\" — the question every launch\n * and every close of a branchable run has to answer, about a tree that a live process is still\n * writing to. That is a different question from the one\n * {@link scanMaterializedWorkspaceManifest} answers, and the difference decides the policies here:\n *\n * - A candidate manifest describes ONE EXACT regular-file workspace. It refuses a symbolic link\n * outright, because `AgentCandidateWorkspaceManifestMaterial` has no representation for one, and\n * it refuses an entry that disappears, because a signed manifest describes a settled tree.\n * - A tree descriptor describes what a RUN PRODUCED. A python venv writes\n * `bin/python -> /usr/bin/python3` as a matter of course, and a work directory can lose an entry\n * between two directory reads. Refusing on either aborts the close, and a run that never wrote\n * its digest can never be branched from.\n *\n * So the two policies are the caller's, one for links and one for vanishing entries, and both\n * default to `'refuse'` — the strict reading, correct for an INPUT seed, where a link that leaves\n * the tree means the seed describes bytes it does not contain. `'exclude'` is the reading a close\n * needs: the entry is never followed, it is recorded, and the exclusion itself is hashed, so two\n * trees that differ only in an excluded entry cannot share a digest.\n *\n * NOTHING is held in memory. A file reaches the tree digest as its own streamed sha-256 plus its\n * length, so the largest file in the tree does not decide whether the tree can be described:\n * `readFile` refuses anything above 2 GiB with `ERR_FS_FILE_TOO_LARGE`, and a single multi-gigabyte\n * artifact is exactly what a run leaves behind.\n *\n * @module\n * @experimental\n */\n\nimport { createHash } from 'node:crypto'\nimport { constants as fsConstants } from 'node:fs'\nimport { cp, lstat, open, readdir, readlink, realpath } from 'node:fs/promises'\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'\nimport type { Sha256Digest } from '@tangle-network/agent-interface'\n\n/**\n * `'tree-v1'` records a file's exact permission bits. `'portable-tree-v1'` records the two modes\n * Git stores — `755` when any execute bit is set, `644` otherwise, and `755` for a directory — so a\n * digest survives a checkout whose umask differs. Both stamp the algorithm into the digest, so one\n * tree cannot produce the same digest under both.\n */\nexport type WorkspaceTreeAlgorithm = 'tree-v1' | 'portable-tree-v1'\n\n/** What a walk does with an entry it refuses to describe: fail, or record and continue. */\nexport type WorkspaceTreeEntryPolicy = 'refuse' | 'exclude'\n\n/** Why one entry contributed its name instead of its content. */\nexport type WorkspaceTreeExclusionReason =\n | 'absolute-symlink'\n | 'symlink-escapes-tree'\n | 'symlink-resolves-outside-tree'\n | 'unresolved-symlink'\n | 'entry-disappeared'\n\n/** One entry the walk recorded but did not describe. Reported rather than dropped: a digest that\n * silently omitted an entry would be a different digest with no way to tell why. */\nexport interface WorkspaceTreeExclusion {\n /** Tree-relative path, `/`-separated. */\n readonly path: string\n readonly reason: WorkspaceTreeExclusionReason\n /** The link target exactly as it was written, for a symbolic-link exclusion. */\n readonly target?: string\n}\n\nexport interface WorkspaceTreeDescriptor {\n readonly algorithm: WorkspaceTreeAlgorithm\n readonly digest: Sha256Digest\n readonly files: number\n readonly directories: number\n /** Links kept INSIDE the tree. An excluded link is counted in `excluded`, never here. */\n readonly symlinks: number\n /** Total described regular-file bytes. */\n readonly bytes: number\n readonly excluded: ReadonlyArray<WorkspaceTreeExclusion>\n}\n\nexport interface DescribeWorkspaceTreeOptions {\n /** Default `'tree-v1'`. */\n readonly algorithm?: WorkspaceTreeAlgorithm\n /**\n * A symbolic link that is absolute, leaves the tree lexically, resolves outside it, or does not\n * resolve at all. `'refuse'` (default) is correct for an input seed. `'exclude'` is correct for a\n * close-time walk over a tree a run wrote. The link is NEVER followed in either policy: an\n * escaping link must not contribute bytes from outside the tree to a content address.\n */\n readonly onEscapingLink?: WorkspaceTreeEntryPolicy\n /**\n * An entry that vanished between the directory read that named it and the walk that reached it.\n * `'refuse'` (default) is correct for a settled tree; `'exclude'` is correct for a workspace a\n * live process still writes to.\n */\n readonly onMissingEntry?: WorkspaceTreeEntryPolicy\n}\n\nexport interface SeedWorkspaceTreeInput {\n /** The tree to copy FROM. Described, then copied entry by entry. */\n readonly source: string\n /** The tree to copy INTO. Must exist, and must not lie inside `source`. */\n readonly destination: string\n /** Default `'tree-v1'`; decides only the digest this returns, never the bytes it writes. */\n readonly algorithm?: WorkspaceTreeAlgorithm\n}\n\nconst TREE_ALGORITHMS: ReadonlySet<string> = new Set<WorkspaceTreeAlgorithm>([\n 'tree-v1',\n 'portable-tree-v1',\n])\n\nconst ENTRY_POLICIES: ReadonlySet<string> = new Set<WorkspaceTreeEntryPolicy>(['refuse', 'exclude'])\n\n/**\n * Describe one directory tree by content, streaming every file.\n *\n * The digest covers, for every entry in sorted order: its kind, its tree-relative path, its mode\n * under the selected algorithm, and then — for a file, its length and its own sha-256; for a kept\n * link, its target; for an excluded entry, the reason and the target. A file's content therefore\n * never enters the tree hash directly, which is what removes any in-memory size ceiling: the tree\n * hash consumes 32 bytes per file however large the file is.\n *\n * A hard-linked regular file is described like any other regular file. Its content is what the\n * digest is about, and a package manager that links a store into `node_modules` is ordinary\n * content, not a reason to refuse a workspace.\n */\nexport async function describeWorkspaceTree(\n directory: string,\n options: DescribeWorkspaceTreeOptions = {},\n): Promise<WorkspaceTreeDescriptor> {\n const algorithm = options.algorithm ?? 'tree-v1'\n const onEscapingLink = options.onEscapingLink ?? 'refuse'\n const onMissingEntry = options.onMissingEntry ?? 'refuse'\n if (!TREE_ALGORITHMS.has(algorithm)) {\n throw new Error(`unsupported workspace tree algorithm: ${algorithm}`)\n }\n for (const [name, policy] of [\n ['onEscapingLink', onEscapingLink],\n ['onMissingEntry', onMissingEntry],\n ] as const) {\n if (!ENTRY_POLICIES.has(policy)) {\n throw new Error(`unsupported workspace tree ${name} policy: ${policy}`)\n }\n }\n\n const root = resolve(directory)\n const rootStats = await lstatIfPresent(root)\n if (rootStats === null || !rootStats.isDirectory() || rootStats.isSymbolicLink()) {\n throw new Error(`workspace tree root must be a real directory: ${directory}`)\n }\n // Resolve the root once. Every physical containment test below compares against the RESOLVED\n // root, so a symlinked prefix — which is what macOS hands out for a temp directory — does not\n // make every entry look like it escapes.\n const physicalRoot = await realpath(root)\n\n const hash = createHash('sha256')\n // The algorithm is part of the digest. Without this, a tree whose modes already are 755/644\n // produces one digest under both algorithms, and two different questions share one answer.\n hash.update(`workspace-tree\\0${algorithm}\\0`)\n const counts = { files: 0, directories: 0, symlinks: 0, bytes: 0 }\n const excluded: WorkspaceTreeExclusion[] = []\n\n const exclude = (path: string, reason: WorkspaceTreeExclusionReason, target?: string): void => {\n const name = treePath(root, path)\n excluded.push(\n Object.freeze(target === undefined ? { path: name, reason } : { path: name, reason, target }),\n )\n // The reason is hashed with the entry. Two trees that differ only in WHY an entry was excluded\n // are different trees, and a refusal must not become a way to hide a difference.\n hash.update(`excluded\\0${name}\\0${reason}\\0${target ?? ''}\\0`)\n }\n\n /** True when the caller asked to continue past a vanished entry, and it was not the root. */\n const recordMissing = (path: string): boolean => {\n if (onMissingEntry === 'refuse' || path === root) return false\n exclude(path, 'entry-disappeared')\n return true\n }\n\n const visit = async (path: string): Promise<void> => {\n const info = await lstatIfPresent(path)\n if (info === null) {\n if (recordMissing(path)) return\n throw new Error(`workspace tree entry disappeared during the walk: ${treePath(root, path)}`)\n }\n const name = treePath(root, path)\n const mode = entryMode(info.mode, algorithm, info.isDirectory(), info.isSymbolicLink())\n\n if (info.isDirectory()) {\n let entries: string[]\n try {\n entries = await readdir(path)\n } catch (error) {\n if (isMissing(error) && recordMissing(path)) return\n throw error\n }\n counts.directories += 1\n hash.update(`directory\\0${name}\\0${mode}\\0`)\n for (const entry of entries.sort()) await visit(join(path, entry))\n return\n }\n\n if (info.isSymbolicLink()) {\n await visitSymbolicLink(path, name, mode)\n return\n }\n\n if (!info.isFile()) {\n throw new Error(`workspace tree contains an unsupported entry: ${name}`)\n }\n const read = await digestFile(path)\n if (read === null) {\n if (recordMissing(path)) return\n throw new Error(`workspace tree entry disappeared during the walk: ${name}`)\n }\n counts.files += 1\n counts.bytes += read.byteLength\n hash.update(`file\\0${name}\\0${mode}\\0${read.byteLength}\\0${read.sha256}\\0`)\n }\n\n const visitSymbolicLink = async (path: string, name: string, mode: string): Promise<void> => {\n let target: string\n try {\n target = await readlink(path)\n } catch (error) {\n if (isMissing(error) && recordMissing(path)) return\n throw error\n }\n const refuse = (reason: WorkspaceTreeExclusionReason): void => {\n if (onEscapingLink === 'refuse') {\n throw new Error(\n `workspace tree contains a link that ${reasonText(reason)}: ${name} -> ${target}`,\n )\n }\n exclude(path, reason, target)\n }\n if (isAbsolute(target)) return refuse('absolute-symlink')\n if (!isWithin(root, resolve(dirname(path), target))) return refuse('symlink-escapes-tree')\n let physicalTarget: string\n try {\n physicalTarget = await realpath(path)\n } catch {\n // A dangling link is a fact about the tree, not a reason to make the run unrecoverable.\n return refuse('unresolved-symlink')\n }\n if (!isWithin(physicalRoot, physicalTarget)) return refuse('symlink-resolves-outside-tree')\n counts.symlinks += 1\n hash.update(`symlink\\0${name}\\0${mode}\\0${target}\\0`)\n }\n\n await visit(root)\n return Object.freeze({\n algorithm,\n digest: `sha256:${hash.digest('hex')}` as Sha256Digest,\n files: counts.files,\n directories: counts.directories,\n symlinks: counts.symlinks,\n bytes: counts.bytes,\n excluded: Object.freeze(excluded),\n })\n}\n\n/**\n * Seed a workspace from a directory, one entry at a time, and return the digest of what was\n * seeded.\n *\n * Nothing is packed: `cp` walks and copies file by file, so a multi-gigabyte seed costs one file\n * handle rather than one archive in memory. Existing destination entries are never overwritten —\n * a seed that could replace a file the workspace already holds would make the resulting tree\n * depend on the order two seeds ran in.\n *\n * Links are copied verbatim, exactly as they were written. Following them would copy bytes from\n * outside the seed into the workspace, which is the same rule {@link describeWorkspaceTree}\n * applies to the digest.\n */\nexport async function seedWorkspaceTree(\n input: SeedWorkspaceTreeInput,\n): Promise<WorkspaceTreeDescriptor> {\n const source = resolve(input.source)\n const destination = resolve(input.destination)\n if (source === destination || isWithin(source, destination)) {\n throw new Error('workspace seed must not contain its destination')\n }\n const destinationStats = await lstatIfPresent(destination)\n if (destinationStats === null || !destinationStats.isDirectory()) {\n throw new Error(\n `workspace seed destination must be an existing directory: ${input.destination}`,\n )\n }\n // Described BEFORE anything is copied, so a seed this refuses leaves the destination untouched.\n const descriptor = await describeWorkspaceTree(source, {\n ...(input.algorithm === undefined ? {} : { algorithm: input.algorithm }),\n })\n for (const name of (await readdir(source)).sort()) {\n if ((await lstatIfPresent(join(destination, name))) !== null) {\n throw new Error(`workspace seed would overwrite an existing entry: ${name}`)\n }\n await cp(join(source, name), join(destination, name), {\n recursive: true,\n force: false,\n errorOnExist: true,\n verbatimSymlinks: true,\n })\n }\n return descriptor\n}\n\n/** Stream one regular file into its own digest, or `null` when it vanished mid-read. */\nasync function digestFile(\n path: string,\n): Promise<{ sha256: Sha256Digest; byteLength: number } | null> {\n let descriptor: Awaited<ReturnType<typeof open>>\n try {\n descriptor = await open(\n path,\n fsConstants.O_RDONLY |\n (typeof fsConstants.O_NOFOLLOW === 'number' ? fsConstants.O_NOFOLLOW : 0),\n )\n } catch (error) {\n if (isMissing(error)) return null\n throw error\n }\n try {\n const hash = createHash('sha256')\n const buffer = Buffer.allocUnsafe(1024 * 1024)\n let total = 0\n while (true) {\n const { bytesRead } = await descriptor.read(buffer, 0, buffer.byteLength, null)\n if (bytesRead === 0) break\n total += bytesRead\n hash.update(buffer.subarray(0, bytesRead))\n }\n // The length comes from the READ, never from `lstat`, so a file that grew between the two is\n // described by the bytes that reached the digest rather than refused for ordinary churn.\n return { sha256: `sha256:${hash.digest('hex')}` as Sha256Digest, byteLength: total }\n } finally {\n await descriptor.close()\n }\n}\n\n/** Git records exactly two file modes; a portable tree records the same two, plus 755 for a\n * directory and 777 for a link, which is what every filesystem reports for one. */\nfunction entryMode(\n mode: number | bigint,\n algorithm: WorkspaceTreeAlgorithm,\n isDirectory: boolean,\n isSymbolicLink: boolean,\n): string {\n const bits = Number(mode)\n if (algorithm !== 'portable-tree-v1') return String(bits & 0o777)\n if (isDirectory) return '755'\n if (isSymbolicLink) return '777'\n return (bits & 0o111) !== 0 ? '755' : '644'\n}\n\nfunction reasonText(reason: WorkspaceTreeExclusionReason): string {\n switch (reason) {\n case 'absolute-symlink':\n return 'is absolute'\n case 'symlink-escapes-tree':\n return 'escapes its tree'\n case 'symlink-resolves-outside-tree':\n return 'resolves outside its tree'\n default:\n return 'does not resolve'\n }\n}\n\nfunction treePath(root: string, path: string): string {\n return relative(root, path).split(sep).join('/') || '.'\n}\n\nfunction isWithin(root: string, path: string): boolean {\n return path === root || path.startsWith(`${root}${sep}`)\n}\n\nfunction isMissing(error: unknown): boolean {\n return (error as { code?: unknown } | null)?.code === 'ENOENT'\n}\n\nasync function lstatIfPresent(path: string): Promise<Awaited<ReturnType<typeof lstat>> | null> {\n try {\n return await lstat(path)\n } catch (error) {\n if (isMissing(error)) return null\n throw error\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { At as workerTraceAnalysisStore,
|
|
1
|
+
import { $i as withBudgetResources, $r as writeAllBytes, At as workerTraceAnalysisStore, Hi as promptCacheTokenClasses, Ji as unmeteredSpend, Li as chargedTokens, Mt as assertValidBudget, Qr as readCommittedJsonLines, Qt as createPeerMailbox, R as scopeRetainedOwnerResourceReader, U as resolveSpawnResourcePaths, Yn as resolveRedactor, Zi as addResourceSpend, Zr as prepareJsonlAppend, _t as FileResultBlobStore, a as pickBestDelivered, bi as detachedFrozen, bt as InMemorySpawnJournal, ci as providerAttemptEvidence, dt as createExecutorRegistry, g as withDriverExecutor, kt as parseWorkerToolTraceArtifact, nn as isLiveNodeStatus, o as runFinalizer, qt as createInbox, r as bestDelivered, rn as isTerminalNodeStatus, rt as freeSlots, s as runTree, tt as errMessage, vt as FileSpawnJournal, wn as runBrainLoop, x as meterRuntimeOwnedProviderAttempt, yt as InMemoryResultBlobStore } from "./supervisor-BIBWUFUr.js";
|
|
2
2
|
import { f as RuntimeRunStateError, m as ValidationError } from "./errors-DodWX-cb.js";
|
|
3
|
-
import { A as writeWorkerCancellation, M as writeWorkerSteerAcknowledgement, b as workerCancellationsDir, c as readWorkerCancelRequests, d as readWorkerSteerRequests, k as writeRunCancellation, l as readWorkerCancellation, o as readRunCancelRequest, r as claimWorkerSteerDelivery, s as readRunCancellation, u as readWorkerSteerAcknowledgement } from "./run-layout-
|
|
3
|
+
import { A as writeWorkerCancellation, M as writeWorkerSteerAcknowledgement, b as workerCancellationsDir, c as readWorkerCancelRequests, d as readWorkerSteerRequests, k as writeRunCancellation, l as readWorkerCancellation, o as readRunCancelRequest, r as claimWorkerSteerDelivery, s as readRunCancellation, u as readWorkerSteerAcknowledgement } from "./run-layout-hKAJGF4g.js";
|
|
4
4
|
import { agentProfileSchema, canonicalCandidateDigest } from "@tangle-network/agent-interface";
|
|
5
5
|
import { argHash, errorStreakDetector, observeAll, repeatedActionDetector } from "@tangle-network/agent-eval";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
@@ -654,6 +654,10 @@ function spawnRefusalReason(reason, shortfalls, pinned) {
|
|
|
654
654
|
}
|
|
655
655
|
/** Build the driver's MCP tools over a live scope. */
|
|
656
656
|
function createCoordinationTools(opts) {
|
|
657
|
+
return createCoordinationToolsForManager(opts);
|
|
658
|
+
}
|
|
659
|
+
/** Internal manager binding; its lifetime fences delivery without cancelling the worker scope. */
|
|
660
|
+
function createCoordinationToolsForManager(opts, lifetime) {
|
|
657
661
|
const deliverable = opts.deliverable;
|
|
658
662
|
const priorSubmission = deliverable === void 0 ? void 0 : opts.priorJournal?.find((record) => record.event.type === "submission");
|
|
659
663
|
let stopped = priorSubmission !== void 0;
|
|
@@ -1177,8 +1181,11 @@ function createCoordinationTools(opts) {
|
|
|
1177
1181
|
let outcome;
|
|
1178
1182
|
let error;
|
|
1179
1183
|
try {
|
|
1180
|
-
|
|
1181
|
-
|
|
1184
|
+
if (lifetime?.aborted) outcome = "scope-stopped";
|
|
1185
|
+
else {
|
|
1186
|
+
delivered = opts.scope.send(instruction.toWorker, message);
|
|
1187
|
+
outcome = deliveryOutcome(instruction.toWorker, delivered);
|
|
1188
|
+
}
|
|
1182
1189
|
} catch (cause) {
|
|
1183
1190
|
outcome = "runtime-error";
|
|
1184
1191
|
error = cause instanceof Error ? cause.message : String(cause);
|
|
@@ -3174,7 +3181,7 @@ function validateDriverPromptCache(promptCache) {
|
|
|
3174
3181
|
* lead journal their terminal records there before the lead settles into this scope. */
|
|
3175
3182
|
const SPAWN_JOURNAL_FILE = "spawn-journal.jsonl";
|
|
3176
3183
|
/**
|
|
3177
|
-
* Apply externally admitted steers once
|
|
3184
|
+
* Apply externally admitted steers once through the owning manager's control path.
|
|
3178
3185
|
*
|
|
3179
3186
|
* The `unknown` acknowledgement lands before authorization or delivery. A crash after that write
|
|
3180
3187
|
* can lose this steer, but a restarted manager never delivers it again. This is the same
|
|
@@ -3193,7 +3200,9 @@ function createSteerAcknowledger(deps) {
|
|
|
3193
3200
|
});
|
|
3194
3201
|
return { async pass(phase) {
|
|
3195
3202
|
for (const request of readWorkerSteerRequests(deps.dir)) {
|
|
3196
|
-
if (
|
|
3203
|
+
if (phase === "turn" && deps.signal?.aborted) return;
|
|
3204
|
+
const rootRequest = request.worker === deps.ownerId && deps.deliverRoot !== void 0;
|
|
3205
|
+
if (!rootRequest && !directChildId(request.worker)) continue;
|
|
3197
3206
|
if (readWorkerSteerAcknowledgement(deps.dir, request.operationId) !== void 0) continue;
|
|
3198
3207
|
if (phase === "final") {
|
|
3199
3208
|
writeWorkerSteerAcknowledgement(deps.dir, {
|
|
@@ -3211,13 +3220,23 @@ function createSteerAcknowledger(deps) {
|
|
|
3211
3220
|
detail: "delivery admitted; outcome not yet known"
|
|
3212
3221
|
})) continue;
|
|
3213
3222
|
try {
|
|
3214
|
-
|
|
3223
|
+
let outcome;
|
|
3224
|
+
if (rootRequest) {
|
|
3225
|
+
const delivered = deps.deliverRoot({
|
|
3226
|
+
steer: request.message,
|
|
3227
|
+
interrupt: request.interrupt
|
|
3228
|
+
});
|
|
3229
|
+
outcome = {
|
|
3230
|
+
delivered,
|
|
3231
|
+
outcome: delivered ? "delivered" : "runtime-has-no-inbox"
|
|
3232
|
+
};
|
|
3233
|
+
} else outcome = await deps.coord.steerWorker(request.worker, request.message, { interrupt: request.interrupt });
|
|
3215
3234
|
const effect = outcome.delivered ? "delivered" : outcome.outcome === "runtime-has-no-inbox" ? "unsupported" : outcome.outcome === "unknown-worker" || outcome.outcome === "already-settled" || outcome.outcome === "scope-stopped" ? "not_live" : "unknown";
|
|
3216
3235
|
writeWorkerSteerAcknowledgement(deps.dir, {
|
|
3217
3236
|
...base(request),
|
|
3218
3237
|
effect,
|
|
3219
3238
|
observedAt: iso(),
|
|
3220
|
-
detail: steerAcknowledgementDetail(outcome)
|
|
3239
|
+
detail: rootRequest ? outcome.delivered ? "the root inbox accepted the steer; consumption is not confirmed" : "the root exposes no accepting inbox at delivery time" : steerAcknowledgementDetail(outcome)
|
|
3221
3240
|
});
|
|
3222
3241
|
} catch (error) {
|
|
3223
3242
|
writeWorkerSteerAcknowledgement(deps.dir, {
|
|
@@ -3251,8 +3270,8 @@ function steerAcknowledgementDetail(outcome) {
|
|
|
3251
3270
|
}
|
|
3252
3271
|
/**
|
|
3253
3272
|
* The worker-cancel ACKNOWLEDGER — the runtime-side half of `run-layout`'s `cancelWorker`
|
|
3254
|
-
* contract
|
|
3255
|
-
*
|
|
3273
|
+
* contract. Router managers check between turns; native managers observe throughout their invocation.
|
|
3274
|
+
* Every manager with a `controlDir` mounts one;
|
|
3256
3275
|
* OWNERSHIP keeps them from colliding: a request naming a node id is owned by the manager whose
|
|
3257
3276
|
* own id is that node's parent, and a label/profile-name reference is owned by the `'run'`-scoped
|
|
3258
3277
|
* (root) manager only — so exactly one acknowledger can ever apply one operation.
|
|
@@ -3402,7 +3421,7 @@ function createCancelAcknowledger(deps) {
|
|
|
3402
3421
|
if (record !== void 0) tracked.set(request.operationId, record);
|
|
3403
3422
|
}
|
|
3404
3423
|
if (record === void 0) {
|
|
3405
|
-
apply(request);
|
|
3424
|
+
if (phase === "turn") apply(request);
|
|
3406
3425
|
continue;
|
|
3407
3426
|
}
|
|
3408
3427
|
if (record.effect === "cancel_requested") reconcile(record);
|
|
@@ -3574,7 +3593,9 @@ function driverAgent(opts) {
|
|
|
3574
3593
|
dir: opts.controlDir,
|
|
3575
3594
|
coord,
|
|
3576
3595
|
now,
|
|
3577
|
-
ownerId: scope.view.root
|
|
3596
|
+
ownerId: scope.view.root,
|
|
3597
|
+
signal: scope.signal,
|
|
3598
|
+
...opts.controlScope === "subtree" ? {} : { deliverRoot: inbox.deliver }
|
|
3578
3599
|
});
|
|
3579
3600
|
for (const w of scope.resume?.waits ?? []) {
|
|
3580
3601
|
const rearmed = scope.wait(w.spec, { label: w.label });
|
|
@@ -3866,6 +3887,6 @@ function safeJson(v) {
|
|
|
3866
3887
|
}
|
|
3867
3888
|
}
|
|
3868
3889
|
//#endregion
|
|
3869
|
-
export {
|
|
3890
|
+
export { downMessageRefusalReasons as A, ANALYST_DEFINITION_BOUNDS as C, coordinationVerbNames as D, canonicalFindingEvent as E, defaultToolDetectors as F, watchTrace as I, parseAuthoredAnalystDefinition as M, questionEscalationTargets as N, createCoordinationTools as O, createEventBus as P, watchRunCancellation as S, analystToolGroupNames as T, renderAnytimeTable as _, allOf as a, FileCoordinationLog as b, createProgressTracker as c, progressStop as d, sampleFromSettled as f, plateauLength as g, bestSoFar as h, finalizeBestDelivered as i, normalizeAnalyzeOnSettle as j, createCoordinationToolsForManager as k, noProgressFor as l, areaUnderCurve as m, createSteerAcknowledger as n, allWorkersStalled as o, anytimeReport as p, driverAgent as r, anyOf as s, createCancelAcknowledger as t, plateau as u, createFileRunContext as v, DEFAULT_AWAIT_EVENT_TIMEOUT_MS as w, applyRunCancellation as x, createInMemoryRunContext as y };
|
|
3870
3891
|
|
|
3871
|
-
//# sourceMappingURL=coordination-driver-
|
|
3892
|
+
//# sourceMappingURL=coordination-driver-BV4AAUns.js.map
|