@ornexus/neocortex 4.60.67 → 4.60.68

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.
Files changed (230) hide show
  1. package/dist/release-source.json +1 -1
  2. package/dist/sbom.cdx.json +1194 -1194
  3. package/install.sh +1 -1
  4. package/package.json +2 -2
  5. package/packages/client/dist/adapters/adapter-registry.js +108 -1
  6. package/packages/client/dist/adapters/antigravity-adapter.js +77 -2
  7. package/packages/client/dist/adapters/claude-code-adapter.js +79 -3
  8. package/packages/client/dist/adapters/codex-adapter.js +80 -2
  9. package/packages/client/dist/adapters/cursor-adapter.js +115 -4
  10. package/packages/client/dist/adapters/gemini-adapter.js +71 -2
  11. package/packages/client/dist/adapters/grok-adapter.js +42 -2
  12. package/packages/client/dist/adapters/index.js +22 -1
  13. package/packages/client/dist/adapters/platform-detector.js +212 -1
  14. package/packages/client/dist/adapters/target-adapter.js +12 -0
  15. package/packages/client/dist/adapters/vscode-adapter.js +72 -2
  16. package/packages/client/dist/agent/refresh-stubs.js +417 -2
  17. package/packages/client/dist/agent/update-agent-yaml.js +102 -1
  18. package/packages/client/dist/agent/update-description.js +251 -1
  19. package/packages/client/dist/cache/crypto-utils.js +78 -1
  20. package/packages/client/dist/cache/encrypted-cache.js +108 -1
  21. package/packages/client/dist/cache/in-memory-asset-cache.js +73 -1
  22. package/packages/client/dist/cache/index.js +13 -1
  23. package/packages/client/dist/cache/protected-pi-boundary.js +44 -1
  24. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +127 -2
  25. package/packages/client/dist/checkpoint/index.js +11 -1
  26. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +32 -1
  27. package/packages/client/dist/cli.js +290 -3
  28. package/packages/client/dist/commands/activate.js +394 -8
  29. package/packages/client/dist/commands/architecture-answers.js +274 -7
  30. package/packages/client/dist/commands/architecture-memory-terminal.js +253 -4
  31. package/packages/client/dist/commands/architecture-non-ui-continuation.js +100 -1
  32. package/packages/client/dist/commands/architecture-root-binding.js +51 -1
  33. package/packages/client/dist/commands/cache-status.js +112 -2
  34. package/packages/client/dist/commands/config.js +88 -1
  35. package/packages/client/dist/commands/doctor.js +635 -2
  36. package/packages/client/dist/commands/invoke.js +7140 -142
  37. package/packages/client/dist/commands/legacy-epic-terminal.js +71 -1
  38. package/packages/client/dist/commands/legacy-story-branch.js +96 -1
  39. package/packages/client/dist/commands/legacy-story-pr.js +276 -1
  40. package/packages/client/dist/commands/mutation-qa-checkpoint.js +285 -5
  41. package/packages/client/dist/commands/mutation-qa-gate.js +54 -1
  42. package/packages/client/dist/commands/mutation-qa-git.js +41 -1
  43. package/packages/client/dist/commands/mutation-qa-policy.js +102 -1
  44. package/packages/client/dist/commands/mutation-qa-run.js +219 -3
  45. package/packages/client/dist/commands/mutation-qa-verdict.js +149 -1
  46. package/packages/client/dist/commands/mutation-qa.js +220 -1
  47. package/packages/client/dist/commands/native-agent.js +136 -2
  48. package/packages/client/dist/commands/planning-diagnosis.js +43 -1
  49. package/packages/client/dist/commands/planning-generation.js +53 -1
  50. package/packages/client/dist/commands/planning-memory.js +40 -1
  51. package/packages/client/dist/commands/planning-research.js +42 -1
  52. package/packages/client/dist/commands/private-session.js +75 -1
  53. package/packages/client/dist/commands/property-qa.js +139 -1
  54. package/packages/client/dist/commands/qa-control.js +16 -1
  55. package/packages/client/dist/commands/qa-scan-browser-launch.js +55 -1
  56. package/packages/client/dist/commands/qa-scan-browser-route.js +28 -1
  57. package/packages/client/dist/commands/qa-scan-capture.js +663 -5
  58. package/packages/client/dist/commands/qa-scan-discovery.js +376 -3
  59. package/packages/client/dist/commands/qa-scan-review.js +826 -5
  60. package/packages/client/dist/commands/qa-synthetic-backend-capture.js +266 -1
  61. package/packages/client/dist/commands/qa-synthetic-backend-review.js +297 -1
  62. package/packages/client/dist/commands/qa-synthetic-backend.js +340 -2
  63. package/packages/client/dist/commands/qa-synthetic-broker-port.js +85 -1
  64. package/packages/client/dist/commands/qa-synthetic-browser.js +39 -1
  65. package/packages/client/dist/commands/refactor-characterization.js +671 -21
  66. package/packages/client/dist/commands/refactor-commit.js +399 -13
  67. package/packages/client/dist/commands/refactor-control.js +142 -3
  68. package/packages/client/dist/commands/refactor-cpp-assertions.js +93 -3
  69. package/packages/client/dist/commands/refactor-review.js +283 -5
  70. package/packages/client/dist/commands/refactor-root.js +588 -7
  71. package/packages/client/dist/commands/refresh-memory.js +156 -3
  72. package/packages/client/dist/commands/shared-architecture-non-ui.js +24 -1
  73. package/packages/client/dist/commands/story-checkpoint.js +171 -1
  74. package/packages/client/dist/config/profile-directory.js +13 -1
  75. package/packages/client/dist/config/resolver-selection.js +278 -1
  76. package/packages/client/dist/config/secure-config.js +281 -12
  77. package/packages/client/dist/config.js +223 -2
  78. package/packages/client/dist/constants.js +25 -1
  79. package/packages/client/dist/context/context-collector.js +222 -2
  80. package/packages/client/dist/context/context-sanitizer.js +145 -1
  81. package/packages/client/dist/continuity/autonomous-governance.js +285 -1
  82. package/packages/client/dist/continuity/continuity-client-state-store.js +1587 -1
  83. package/packages/client/dist/continuity/invoke-hooks.js +129 -1
  84. package/packages/client/dist/continuity/migrations/001-initial-schema.js +12 -2
  85. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +12 -2
  86. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +12 -2
  87. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +12 -2
  88. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +12 -2
  89. package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +10 -2
  90. package/packages/client/dist/continuity/native-agent-store.js +69 -1
  91. package/packages/client/dist/continuity/native-agent-types.js +90 -1
  92. package/packages/client/dist/continuity/outbox.js +117 -1
  93. package/packages/client/dist/continuity/runner-bootstrap-policy.js +172 -1
  94. package/packages/client/dist/continuity/sqlite-store.js +2536 -81
  95. package/packages/client/dist/effects/invoke-effect-gateways.js +62 -1
  96. package/packages/client/dist/errors/error-messages.js +228 -2
  97. package/packages/client/dist/errors/frontmatter-diagnostics.js +125 -1
  98. package/packages/client/dist/evidence/collector.js +347 -1
  99. package/packages/client/dist/evidence/index.js +1 -1
  100. package/packages/client/dist/evidence/types.js +2 -0
  101. package/packages/client/dist/fs/atomic-state-replace.js +152 -1
  102. package/packages/client/dist/generated/command-registry.generated.js +4076 -1
  103. package/packages/client/dist/generated/public-projections.generated.js +149 -1
  104. package/packages/client/dist/git/direct-yolo-c01-retry.js +138 -4
  105. package/packages/client/dist/git/direct-yolo-checkpoint.js +1234 -4
  106. package/packages/client/dist/git/git-lifecycle-step-ids.js +14 -1
  107. package/packages/client/dist/git/git-lifecycle-store.js +1938 -9
  108. package/packages/client/dist/git/legacy-story-branch-checkpoint.js +259 -9
  109. package/packages/client/dist/git/legacy-story-branch-setup.js +348 -4
  110. package/packages/client/dist/git/legacy-story-pr.js +3538 -70
  111. package/packages/client/dist/git/secure-filesystem-boundary.js +182 -5
  112. package/packages/client/dist/graph-retrieval/pre-command-hook.js +284 -1
  113. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +237 -1
  114. package/packages/client/dist/i18n/first-run.js +60 -2
  115. package/packages/client/dist/index.js +47 -1
  116. package/packages/client/dist/invocation/invoke-input.js +24 -1
  117. package/packages/client/dist/license/index.js +5 -1
  118. package/packages/client/dist/license/license-client.js +304 -1
  119. package/packages/client/dist/machine/fingerprint.js +163 -2
  120. package/packages/client/dist/machine/index.js +5 -1
  121. package/packages/client/dist/memory/project-memory-path-scope.js +62 -1
  122. package/packages/client/dist/memory/project-memory-writer.js +1007 -40
  123. package/packages/client/dist/memory/shared-project-memory-types.js +253 -2
  124. package/packages/client/dist/migrations/project-identity-capability.js +50 -1
  125. package/packages/client/dist/migrations/project-identity.js +493 -7
  126. package/packages/client/dist/migrations/state-json.js +344 -4
  127. package/packages/client/dist/policy/architecture-policy.js +184 -2
  128. package/packages/client/dist/policy/index.js +7 -1
  129. package/packages/client/dist/policy/shared-policy-types.js +38 -0
  130. package/packages/client/dist/policy/subagent-approval-policy.js +55 -1
  131. package/packages/client/dist/private-execution/clean-baseline.js +279 -2
  132. package/packages/client/dist/private-execution/codex-executor.js +574 -4
  133. package/packages/client/dist/private-execution/codex-host-runtime.js +137 -1
  134. package/packages/client/dist/private-execution/codex-lifecycle-guard.js +97 -1
  135. package/packages/client/dist/private-execution/codex-scoped-permissions.js +128 -1
  136. package/packages/client/dist/private-execution/delivery.js +410 -13
  137. package/packages/client/dist/private-execution/diagnosis-root-review.js +294 -2
  138. package/packages/client/dist/private-execution/frozen-handoff.js +19 -6
  139. package/packages/client/dist/private-execution/implementation-validation.js +106 -2
  140. package/packages/client/dist/private-execution/isolated-admission.js +1432 -23
  141. package/packages/client/dist/private-execution/isolated-session.js +725 -5
  142. package/packages/client/dist/private-execution/isolated-workspace.js +122 -1
  143. package/packages/client/dist/private-execution/pact-consumer-runtime.js +409 -3
  144. package/packages/client/dist/private-execution/pact-test-source.js +258 -1
  145. package/packages/client/dist/private-execution/pact-toolchain.js +290 -3
  146. package/packages/client/dist/private-execution/pact-write-set.js +172 -1
  147. package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +406 -5
  148. package/packages/client/dist/private-execution/planning-generation-checkpoint.js +462 -5
  149. package/packages/client/dist/private-execution/planning-memory-checkpoint.js +139 -3
  150. package/packages/client/dist/private-execution/planning-research-checkpoint.js +325 -4
  151. package/packages/client/dist/private-execution/private-report-store.js +42 -1
  152. package/packages/client/dist/private-execution/property-test-candidate.js +103 -1
  153. package/packages/client/dist/private-execution/property-test-choices.js +147 -3
  154. package/packages/client/dist/private-execution/property-test-plan.js +271 -7
  155. package/packages/client/dist/private-execution/property-test-review.js +258 -4
  156. package/packages/client/dist/private-execution/property-test-runtime.js +372 -9
  157. package/packages/client/dist/private-execution/property-test-source.js +139 -1
  158. package/packages/client/dist/private-execution/root-checkpoint.js +80 -1
  159. package/packages/client/dist/private-execution/root-memory-git-evidence.js +135 -3
  160. package/packages/client/dist/private-execution/root-memory-recovery.js +93 -1
  161. package/packages/client/dist/private-execution/root-memory-request.js +29 -1
  162. package/packages/client/dist/private-execution/root-memory-scope.js +178 -1
  163. package/packages/client/dist/private-execution/root-memory-writer.js +102 -1
  164. package/packages/client/dist/private-execution/session-lease.js +63 -1
  165. package/packages/client/dist/private-execution/shared-private-admission-types.js +50 -1
  166. package/packages/client/dist/private-execution/shared-project-validation.js +66 -1
  167. package/packages/client/dist/private-execution/shared-root-memory-types.js +61 -1
  168. package/packages/client/dist/private-execution/ux-source-validation.js +372 -1
  169. package/packages/client/dist/private-execution/ux-write-set.js +191 -2
  170. package/packages/client/dist/resilience/circuit-breaker.js +170 -1
  171. package/packages/client/dist/resilience/degradation-manager.js +164 -1
  172. package/packages/client/dist/resilience/freshness-indicator.js +100 -1
  173. package/packages/client/dist/resilience/index.js +8 -1
  174. package/packages/client/dist/resilience/recovery-detector.js +74 -1
  175. package/packages/client/dist/resolvers/asset-resolver.js +13 -0
  176. package/packages/client/dist/resolvers/local-resolver.js +255 -8
  177. package/packages/client/dist/resolvers/remote-resolver.js +233 -1
  178. package/packages/client/dist/runner/binary.js +404 -1
  179. package/packages/client/dist/runner/cli.js +1571 -17
  180. package/packages/client/dist/runner/headless/adapters.js +49 -1
  181. package/packages/client/dist/runner/headless/claude-code-adapter.js +79 -1
  182. package/packages/client/dist/runner/headless/continuous-story-workspace.js +1628 -11
  183. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +69 -1
  184. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +110 -2
  185. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +1236 -8
  186. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +318 -2
  187. package/packages/client/dist/runner/headless/fake-adapter.js +62 -1
  188. package/packages/client/dist/runner/headless/managed-profile.js +132 -1
  189. package/packages/client/dist/runner/headless/opencode-adapter.js +145 -2
  190. package/packages/client/dist/runner/headless/prepared-story-bundle.js +43 -1
  191. package/packages/client/dist/runner/headless/resolver.js +231 -1
  192. package/packages/client/dist/runner/headless/run-yolo.js +885 -1
  193. package/packages/client/dist/runner/headless/run-yoloop.js +2574 -2
  194. package/packages/client/dist/runner/headless/types.js +574 -2
  195. package/packages/client/dist/runner/local-console.js +396 -13
  196. package/packages/client/dist/runner/portal-sync-worker.js +1487 -1
  197. package/packages/client/dist/runner/project-identity.js +106 -1
  198. package/packages/client/dist/runner/scheduler.js +995 -7
  199. package/packages/client/dist/runner-cli.js +18 -2
  200. package/packages/client/dist/state/invocation-shape.js +13 -1
  201. package/packages/client/dist/state/project-state-snapshot.js +1677 -1
  202. package/packages/client/dist/state/state-json-repair.js +785 -3
  203. package/packages/client/dist/state/structural-dag-projection.js +118 -1
  204. package/packages/client/dist/telemetry/index.js +5 -1
  205. package/packages/client/dist/telemetry/offline-queue.js +131 -1
  206. package/packages/client/dist/tier/index.js +5 -1
  207. package/packages/client/dist/tier/tier-aware-client.js +405 -1
  208. package/packages/client/dist/types/index.js +38 -1
  209. package/packages/client/dist/version.js +27 -1
  210. package/packages/client/dist/yolo/change-evidence-collector.js +126 -1
  211. package/packages/client/dist/yolo/invoke-envelope-capability.js +62 -1
  212. package/packages/client/dist/yolo/spec-envelope-collector.js +185 -5
  213. package/packages/client/dist/yoloop/discovery-hook.js +300 -2
  214. package/packages/client/dist/yoloop/index.js +8 -1
  215. package/packages/client/dist/yoloop/invoke-hooks.js +669 -12
  216. package/packages/client/dist/yoloop/shared-discover-epics.js +1007 -1
  217. package/packages/client/dist/yoloop/shared-yoloop-types.js +33 -1
  218. package/packages/client/dist/yoloop/target-normalization.js +180 -1
  219. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1723 -1
  220. package/targets-stubs/antigravity/gemini.md +1 -1
  221. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  222. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  223. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  224. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  225. package/targets-stubs/claude-code/neocortex.md +2 -2
  226. package/targets-stubs/codex/AGENTS.md +1 -1
  227. package/targets-stubs/cursor/agent.md +2 -2
  228. package/targets-stubs/gemini-cli/agent.md +2 -2
  229. package/targets-stubs/opencode/neocortex-root.md +1 -1
  230. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1 +1,1587 @@
1
- import{existsSync as se}from"node:fs";import{createHash as ie}from"node:crypto";import{deriveProjectIdentity as de}from"../runner/project-identity.js";import{recordAutonomousGovernance as ce}from"./autonomous-governance.js";import{CONTINUITY_PROCESSING_OUTPUT_SUMMARY_EVENT_TYPE as ue,ContinuitySqliteStoreError as pe,continuitySqliteStorePath as me,isContinuityPublicStage as le,normalizeContinuityStageIteration as Y,openContinuitySqliteStore as Ie,sanitizeContinuityStageHistory as _e}from"./sqlite-store.js";const S=1,g="continuity-v1",z=10,ye=2e3,Ze=z,et=ye,tt=3,nt=1800,fe=1,I=Object.freeze({OK:"continuity-ok",INVALID_SCHEMA_VERSION:"invalid-schema-version",INVALID_CONTRACT_VERSION:"invalid-contract-version",UNKNOWN_OPERATION_REQUIRED:"unknown-operation-required",UNKNOWN_OPERATION_IGNORED:"unknown-operation-ignored",DUPLICATE_OPERATION_ID:"duplicate-operation-id",IDEMPOTENCY_REPLAY:"idempotency-replay",UNSAFE_FIELD_REJECTED:"unsafe-field-rejected",SQLITE_ADAPTER_UNAVAILABLE:"sqlite-adapter-unavailable",SQLITE_INTEGRITY_FAILED:"sqlite-integrity-failed",SQLITE_MUTATION_FAILED:"sqlite-mutation-failed"}),he=new Set(["create_job","update_job_status","append_event","append_receipt","upsert_goal_campaign","upsert_goal_ledger_item","upsert_verifier","upsert_review_gate","schedule_next_tick","acquire_lease","release_lease","compact_context","enqueue_outbox","append_outbox","enqueue_execution_attempt","claim_execution_attempt","heartbeat_execution_attempt","release_execution_attempt","complete_execution_attempt","append_execution_receipt","append_execution_summary"]),Ae=new Set(["schemaVersion","contractVersion","eventType","executionId","jobId","operationId","idempotencyKey","goalId","loopId","campaignId","itemId","ledgerItemIds","verifierId","verifierIds","gateId","reviewGateIds","runnerId","leaseId","status","reasonCode","reasonCodes","runtimeId","modelId","runtimeSource","headlessRuntime","headlessModel","headlessRuntimeReasonCode","originRuntime","originModel","targetRef","attemptId","attemptStatus","directiveHash","timeoutMs","leaseExpiresAt","heartbeatAt","notBeforeAt","maxAttempts","counts","hashes","relativePaths","artifactRefs","evidenceRefs","validationRefs","registryRefs","storyIds","epicIds","debtIds","iteration","currentStage","stageHistory","durationMs","retryCount","nextTickAt","processingOutputSource","publicSummary","redactionEvidence","selectorKind","targetId","targetJobId","relatedJobIds","serverAccessToLocalhost","serverHeldStream","initialCursor","targetResolutionState","targetKind","relatedJobCount","snapshotStatus","snapshotGeneratedAt","renderedSummaryCount","cursorState","currentCursor","nextCursor","cursorAdvanced","eventId","latestEventId","watchStatus","stopReason","syncVersion","transportKind","envelopeId","workspaceId","workspaceLabel","projectId","projectLabel","snapshotId","syncCursor","previousSyncCursor","nextSyncCursor","commandId","receiptId","acknowledgedAt","observedAt","generatedAt","syncStatus","commandStatus","receiptStatus","actorType","actorId","tenantId","commandKind","auditStatus","redactionCount"]),K=/(raw[_-]?(?:logs?|payloads?)|std(?:out|err)|stack(?:[_-]?trace)?|transcript|prompt(?:[_-]?(?:body|text))?|private[_-]?(?:urls?|prompts?)|secret|token|password|protected(?:[_-]?(?:field|body|bodies|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|\bpii\b|authorization|api[_-]?key|license[_-]?key|argv|args|executable(?:[_-]?path)?|binary(?:[_-]?path)?|shell|cwd|command[_-]?path|vendor(?:[_-]?(?:payload|corpus|response|output)))/i,G=/\bhttps?:\/\/\S+/i,be=/(?:^|\s)(?:\/(?:home|Users|media|mnt|tmp|var|etc|private)\/\S+|[A-Za-z]:\\\S+)/i,J=/(ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|-----BEGIN [A-Z ]*PRIVATE KEY-----|authorization\s*:|password\s*=|token\s*=|api[_-]?key\s*=|license[_-]?key\s*=)/i,W=/(raw[_-]?(?:logs?)\s*[:=]|transcript|stack trace|stderr:|stdout:)/i,Q=/(prompt[_-]?body|system prompt|workflow body|step body)/i,X=/(PROTECTED_|_PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|\bPII\b|VENDOR_CORPUS|P180[_-]?SYNTHETIC[_-]?CONTINUITY|P185[_-]?SYNTHETIC[_-]?CONTINUITY|P187[_-]?SYNTHETIC[_-]?(?:CONTINUITY|RUNNER|WATCH)|P190[_-]?SYNTHETIC[_-]?(?:HEADLESS|CONTINUITY)|P192[_-]?SYNTHETIC[_-]?(?:PORTAL|RUNNER|SYNC))/i,k=240,Z=2400,Ce=40,Se=20,ge=40,Ee=20,D=80;class _ extends Error{reasonCodes;redactions;mutationBlocked;constructor(e,n,a={}){super(e),this.name="ContinuityClientStateStoreError",this.reasonCodes=E(n),this.redactions=a.redactions??[],this.mutationBlocked=a.mutationBlocked??!1,this.cause=a.cause}}function at(t){return se(me(t))}function ot(t,e=new Date().toISOString()){return{schemaVersion:S,contractVersion:g,generatedAt:e,hardStop:!0,reasonCodes:E(t),publicSafe:!0}}async function rt(t){const e=await Ie({projectRoot:t.projectRoot,adapter:t.adapter,adapterLoader:t.adapterLoader,now:t.now,strictReadOnly:t.strictReadOnly});return new Re(e,t.now??(()=>new Date().toISOString()),de(t.projectRoot))}class Re{store;now;projectIdentity;constructor(e,n=()=>new Date().toISOString(),a){this.store=e,this.now=n,this.projectIdentity=a}close(){this.store.close()}recordAutonomousGovernance(e,n){try{return ce(this.store,e,n)}catch(a){throw q(a,"Failed to record autonomous governance envelope.")}}collectSnapshot(e={}){try{const n=e.nowIso??this.now(),a=this.store.collectSnapshotRows({nowIso:n,jobLimit:e.jobLimit??20,staleLeaseLimit:e.staleLeaseLimit??10,receiptLimit:e.receiptLimit??10,eventLimit:e.eventLimit??10,snapshotLimit:e.snapshotLimit??5}),i=this.store.listDueJobs({nowIso:n,limit:e.dueJobLimit??10}),d=this.store.listProcessingOutputSummaries({limit:e.processingSummaryLimit??z}),u=Ke(a.receipts).slice(0,20),m=xe({generatedAt:n,counts:a.counts,jobCount:a.jobs.length,dueJobCount:i.length,outboxPending:a.outboxCounts.pending??0,redactions:u});return{schemaVersion:S,contractVersion:g,generatedAt:n,store:{schemaVersion:a.schemaVersion,readable:!0},jobs:a.jobs.map(ee),counts:a.counts,dueJobCount:a.counts.dueJobs??0,dueJobs:i.map(ee),staleLeases:a.staleLeases.map(c=>({leaseId:s(c.lease_id,100),jobId:s(c.job_id,100),runnerId:s(c.runner_id,100),expiresAt:s(c.expires_at,80),publicSafe:!0})),outbox:{total:a.counts.outbox??0,pending:a.outboxCounts.pending??0,failed:a.outboxCounts.failed??0,deadLetter:a.outboxCounts.dead_letter??0,sent:a.outboxCounts.sent??0,acked:a.outboxCounts.acked??0},queue:{depth:a.queue.depth,queued:a.queue.queued,running:a.queue.running,retrying:a.queue.retrying,deadLetter:a.queue.deadLetter,capacity:a.queue.capacity,available:a.queue.available,backpressure:a.queue.backpressure,generatedAt:s(a.queue.generatedAt,80),...a.queue.nextRetryAt?{nextRetryAt:s(a.queue.nextRetryAt,80)}:{},...a.queue.reasonCode?{reasonCode:s(a.queue.reasonCode,80)}:{},publicSafe:!0},lastReceipts:a.receipts.map(c=>({receiptId:s(c.receipt_id,100),jobId:s(c.job_id,100),...c.operation_id?{operationId:s(c.operation_id,100)}:{},status:s(c.status,40),...c.reason_code?{reasonCode:s(c.reason_code,80)}:{},createdAt:s(c.created_at,80),publicSafe:!0})),lastEvents:a.events.map(c=>{const l=P(v(c.metadata_json));return{eventId:s(c.event_id,100),jobId:s(c.job_id,100),operationId:s(c.operation_id,100),type:s(c.type,80),publicSummary:s(c.summary,k),...c.reason_code?{reasonCode:s(c.reason_code,80)}:{},createdAt:s(c.created_at,80),...Object.keys(l).length>0?{metadata:l}:{},publicSafe:!0}}),processingSummaries:d.map(te),headlessExecutionAttempts:a.headlessExecutionAttempts.map(Ne),compactContext:ke(a.stateSnapshots),portalSync:m,redactions:u,publicSafe:!0}}catch(n){throw q(n,"Failed to collect continuity snapshot.")}}collectProcessingOutputSummaryCursor(e={}){try{const n=this.store.pollProcessingOutputSummaries(e);return{summaries:n.summaries.map(te),...n.nextCursor?{nextCursor:n.nextCursor}:{},hasMore:n.hasMore,publicSafe:!0}}catch(n){throw q(n,"Failed to collect processing summary cursor.")}}applyStateUpdate(e){const n=Me(e),a=[],i=[],d=[],u=[];for(const m of n){const c=this.applyOperationLog(m);a.push(...c.appliedOperationIds),i.push(...c.ignoredOperationIds),d.push(...c.reasonCodes),u.push(...c.redactions)}return{ok:!0,appliedOperationIds:E(a),ignoredOperationIds:E(i),reasonCodes:E(d.length>0?d:[I.OK]),redactions:u,publicSafe:!0}}applyOperationLog(e){const n=Ue(e),a=[],i=[...n.ignoredOperationIds],d=[...n.reasonCodes],u=[...n.redactions];try{this.store.runInTransaction(()=>{for(const m of n.operations){if(this.store.hasOperationRef(m.operationId,m.idempotencyKey)){i.push(m.operationId),d.push(I.IDEMPOTENCY_REPLAY);continue}this.applyKnownOperation(m,n.logMetadata),a.push(m.operationId),m.type!=="append_receipt"&&this.recordAppliedAudit(m)}for(const m of n.skippedOperations)this.recordIgnoredAuditIfPossible(m,I.UNKNOWN_OPERATION_IGNORED)})}catch(m){throw q(m,"Failed to apply continuity operation log atomically.")}return{ok:!0,appliedOperationIds:E(a),ignoredOperationIds:E(i),reasonCodes:E(d.length>0?d:[I.OK]),redactions:u,publicSafe:!0}}applyKnownOperation(e,n){switch(e.type){case"create_job":this.applyCreateJob(e,n);return;case"update_job_status":this.applyUpdateJobStatus(e);return;case"append_event":this.applyAppendEvent(e);return;case"append_receipt":this.applyAppendReceipt(e);return;case"upsert_goal_campaign":this.applyUpsertGoalCampaign(e);return;case"schedule_next_tick":this.store.scheduleNextTick({jobId:e.jobId,scheduledAt:r(e,"scheduledAt"),updatedAt:e.createdAt,reasonCode:o(e,"reasonCode")});return;case"acquire_lease":this.store.acquireLease({leaseId:r(e,"leaseId"),jobId:e.jobId,runnerId:r(e,"runnerId"),acquiredAt:r(e,"acquiredAt"),expiresAt:r(e,"expiresAt"),operationId:e.operationId,idempotencyKey:e.idempotencyKey,metadata:f(e.metadata,"operation.metadata")});return;case"release_lease":this.store.releaseLease({leaseId:r(e,"leaseId"),releasedAt:r(e,"releasedAt"),reasonCode:o(e,"reasonCode")});return;case"compact_context":this.applyCompactContext(e);return;case"upsert_goal_ledger_item":this.applyUpsertGoalLedgerItem(e);return;case"upsert_verifier":this.applyUpsertVerifier(e);return;case"upsert_review_gate":this.applyUpsertReviewGate(e);return;case"enqueue_outbox":case"append_outbox":this.applyOutbox(e);return;case"enqueue_execution_attempt":this.applyEnqueueExecutionAttempt(e);return;case"claim_execution_attempt":this.store.claimHeadlessExecutionAttempt({attemptId:r(e,"attemptId"),leaseId:r(e,"leaseId"),runnerId:r(e,"runnerId"),claimedAt:o(e,"claimedAt")??e.createdAt,leaseExpiresAt:r(e,"leaseExpiresAt"),reasonCode:o(e,"reasonCode")});return;case"heartbeat_execution_attempt":this.store.heartbeatHeadlessExecutionAttempt({attemptId:r(e,"attemptId"),leaseId:r(e,"leaseId"),runnerId:r(e,"runnerId"),heartbeatAt:o(e,"heartbeatAt")??e.createdAt,leaseExpiresAt:o(e,"leaseExpiresAt")});return;case"release_execution_attempt":this.store.releaseHeadlessExecutionAttempt({attemptId:r(e,"attemptId"),leaseId:r(e,"leaseId"),releasedAt:o(e,"releasedAt")??e.createdAt,status:o(e,"status"),reasonCode:o(e,"reasonCode"),notBeforeAt:o(e,"notBeforeAt"),retryCount:h(e,"retryCount")});return;case"complete_execution_attempt":this.applyCompleteExecutionAttempt(e);return;case"append_execution_receipt":this.applyAppendExecutionReceipt(e);return;case"append_execution_summary":this.applyAppendExecutionSummary(e);return;default:throw new _(`Unknown continuity operation ${e.type}.`,[I.UNKNOWN_OPERATION_REQUIRED],{mutationBlocked:!0})}}applyCompactContext(e){const n=w(r(e,"summaryHash"),"compact_context.summaryHash"),a=oe(e.retainedRefs,"compact_context.retainedRefs",Ce),i=we(o(e,"publicSummary")??`Context compacted with ${a.length} retained public refs.`),d=Fe(e),u=Be(e),m=oe(e.decisionLogRefs,"compact_context.decisionLogRefs",Ee),c=Ye(e,a,d,u),l=E([...a,...m,...d.map(A=>A.relativePath),...u.map(A=>A.relativePath)]).slice(0,D),U=B(i),N=o(e,"reasonCode")??"context-compacted",j={schemaVersion:S,contractVersion:g,jobId:e.jobId,operationId:e.operationId,reasonCode:N,publicSummary:i,counts:{retainedRefs:a.length,artifactRefs:d.length,evidenceRefs:u.length,decisionLogRefs:m.length,...h(e,"inputTokens")!==void 0?{inputContextUnits:h(e,"inputTokens")}:{},...h(e,"outputTokens")!==void 0?{outputContextUnits:h(e,"outputTokens")}:{},summaryChars:i.length},hashes:{summary:n,persistedSummary:U},relativePaths:l,artifactRefs:d,evidenceRefs:u,validationRefs:m,redactionEvidence:e.redactions??[],checkpoint:c};for(const[A,x]of d.entries())this.store.recordArtifact({artifactId:`artifact-${R(e.operationId)}-${A+1}`,jobId:e.jobId,kind:x.kind,relativePath:x.relativePath,sha256:x.sha256,summary:x.publicSummary,createdAt:e.createdAt,operationId:`${e.operationId}:artifact:${A+1}`,idempotencyKey:e.idempotencyKey?`${e.idempotencyKey}:artifact:${A+1}`:void 0,metadata:{schemaVersion:S,contractVersion:g,jobId:e.jobId,operationId:e.operationId,reasonCode:N,hashes:x.sha256?{artifact:x.sha256}:{},relativePaths:[x.relativePath],publicSummary:x.publicSummary}});this.store.recordStateSnapshot({snapshotId:`snapshot-${R(e.operationId)}`,jobId:e.jobId,kind:"context_compaction",relativePath:d.find(A=>A.kind==="context_summary")?.relativePath,sha256:n,summary:i,capturedAt:e.createdAt,operationId:e.operationId,idempotencyKey:e.idempotencyKey,metadata:j}),this.store.appendEvent({eventId:`event-${R(e.operationId)}-context-compacted`,jobId:e.jobId,operationId:`${e.operationId}:event`,idempotencyKey:e.idempotencyKey?`${e.idempotencyKey}:event`:void 0,sequence:e.sequence,type:"context_compacted",summary:`Context compaction checkpoint ${c.checkpointId} persisted with ${l.length} public refs.`,reasonCode:N,createdAt:e.createdAt,metadata:{schemaVersion:S,contractVersion:g,jobId:e.jobId,operationId:e.operationId,reasonCode:N,counts:j.counts,hashes:j.hashes,relativePaths:l,artifactRefs:d.map(A=>A.relativePath),evidenceRefs:u,publicSummary:i}})}applyCreateJob(e,n){const a=T(e,"job");this.store.recordJob({jobId:r(a,"jobId"),kind:r(a,"kind"),status:r(a,"status"),createdAt:r(a,"createdAt"),updatedAt:r(a,"updatedAt"),summary:o(a,"summary"),reasonCode:o(a,"reasonCode"),nextRunAt:o(a,"nextRunAt"),goalId:o(a,"goalId"),loopId:o(a,"loopId"),campaignId:o(a,"campaignId"),operationId:e.operationId,idempotencyKey:e.idempotencyKey,metadata:f({...p(a,"metadata")??p(e,"metadata")??{...n},...Te(this.projectIdentity)},"job.metadata")})}applyUpdateJobStatus(e){this.store.updateJobStatus({jobId:e.jobId,status:r(e,"status"),updatedAt:e.createdAt,reasonCode:o(e,"reasonCode")})}applyAppendEvent(e){const n=T(e,"event"),a=r(n,"type");if(a===ue){this.applyProcessingOutputSummaryEvent(e,n);return}this.store.appendEvent({eventId:r(n,"eventId"),jobId:r(n,"jobId"),operationId:e.operationId,idempotencyKey:e.idempotencyKey,sequence:e.sequence,type:a,summary:r(n,"summary"),reasonCode:o(n,"reasonCode"),createdAt:r(n,"createdAt"),metadata:f(p(n,"metadata"),"event.metadata")})}applyProcessingOutputSummaryEvent(e,n){const a=p(n,"processingOutputSummary")??n,i=o(a,"executionId")??e.operationId,d=o(a,"jobId")??o(n,"jobId")??e.jobId,u=o(a,"publicSummary")??r(n,"summary"),m=o(a,"createdAt")??o(n,"createdAt")??e.createdAt,c=p(a,"metadata"),l=p(n,"metadata");this.store.recordProcessingOutputSummary({eventId:o(n,"eventId"),executionId:i,jobId:d,idempotencyKey:e.idempotencyKey,goalId:o(a,"goalId")??o(n,"goalId"),loopId:o(a,"loopId")??o(n,"loopId"),publicSummary:u,reasonCode:o(a,"reasonCode")??o(n,"reasonCode"),createdAt:m,source:o(a,"source")??o(n,"source"),metadata:{...l??{},...c??{}}})}applyAppendReceipt(e){const n=T(e,"receipt"),a=o(n,"operationId")??e.operationId;this.store.appendReceipt({receiptId:r(n,"receiptId"),jobId:r(n,"jobId"),operationId:a,idempotencyKey:e.idempotencyKey,status:r(n,"status"),reasonCode:o(n,"reasonCode"),appliedOperationIds:L(n.appliedOperationIds),ignoredOperationIds:L(n.ignoredOperationIds),createdAt:r(n,"createdAt"),metadata:f(p(n,"metadata"),"receipt.metadata")})}applyUpsertGoalCampaign(e){const n=T(e,"campaign");this.store.upsertGoalCampaign({campaignId:r(n,"campaignId"),jobId:r(n,"jobId"),status:r(n,"status"),title:o(n,"title"),publicSummary:o(n,"publicSummary"),reasonCode:o(n,"reasonCode"),createdAt:r(n,"createdAt"),updatedAt:r(n,"updatedAt"),operationId:e.operationId,idempotencyKey:e.idempotencyKey,metadata:f(p(n,"metadata"),"campaign.metadata")})}applyUpsertGoalLedgerItem(e){const n=T(e,"item");this.store.upsertGoalLedgerItem({itemId:r(n,"itemId"),campaignId:r(n,"campaignId"),jobId:r(n,"jobId"),itemType:r(n,"type"),status:r(n,"status"),summary:r(n,"publicSummary"),reasonCode:o(n,"reasonCode"),createdAt:e.createdAt,updatedAt:r(n,"updatedAt"),operationId:e.operationId,idempotencyKey:e.idempotencyKey,metadata:f(p(n,"metadata"),"item.metadata")})}applyUpsertVerifier(e){const n=T(e,"verifier");this.store.upsertGoalVerifier({verifierId:r(n,"verifierId"),campaignId:r(n,"campaignId"),jobId:r(n,"jobId"),kind:r(n,"kind"),status:r(n,"status"),summary:o(n,"publicSummary"),reasonCode:o(n,"reasonCode"),lastCheckedAt:o(n,"lastCheckedAt"),operationId:e.operationId,idempotencyKey:e.idempotencyKey,metadata:f(p(n,"metadata"),"verifier.metadata")})}applyUpsertReviewGate(e){const n=T(e,"reviewGate");this.store.upsertGoalReviewGate({gateId:r(n,"gateId"),campaignId:r(n,"campaignId"),jobId:r(n,"jobId"),status:r(n,"status"),summary:o(n,"publicSummary"),required:He(n,"required")??!0,reasonCode:o(n,"reasonCode"),operationId:e.operationId,idempotencyKey:e.idempotencyKey,metadata:f(p(n,"metadata"),"reviewGate.metadata")})}applyOutbox(e){const n=p(e,"outbox")??e;this.store.enqueueOutbox({outboxId:o(n,"outboxId")??`outbox-${R(e.operationId)}`,jobId:o(n,"jobId")??e.jobId,operationId:e.operationId,idempotencyKey:e.idempotencyKey,type:o(n,"type")===e.type?"continuity_event":r(n,"type"),status:o(n,"status"),payload:f(p(n,"payload")??p(e,"metadata")??{},"outbox.payload"),retryCount:h(n,"retryCount"),nextAttemptAt:o(n,"nextAttemptAt"),lastErrorCode:o(n,"lastErrorCode"),createdAt:o(n,"createdAt")??e.createdAt,updatedAt:o(n,"updatedAt")??e.createdAt})}applyEnqueueExecutionAttempt(e){const n=p(e,"attempt")??e,a=f(p(n,"metadata")??p(e,"metadata"),"executionAttempt.metadata");this.store.enqueueHeadlessExecutionAttempt({attemptId:r(n,"attemptId"),executionId:r(n,"executionId"),jobId:o(n,"jobId")??e.jobId,directiveHash:r(n,"directiveHash"),directiveKind:r(n,"directiveKind"),commandClass:r(n,"commandClass"),targetKind:r(n,"targetKind"),targetRef:r(n,"targetRef"),storyId:o(n,"storyId"),epicId:o(n,"epicId"),runtimeId:o(n,"runtimeId"),modelId:o(n,"modelId"),runtimeSource:o(n,"runtimeSource"),status:o(n,"status"),reasonCode:o(n,"reasonCode"),publicSummary:o(n,"publicSummary"),enqueuedAt:o(n,"enqueuedAt")??e.createdAt,notBeforeAt:o(n,"notBeforeAt"),retryCount:h(n,"retryCount"),maxAttempts:h(n,"maxAttempts"),operationId:e.operationId,idempotencyKey:e.idempotencyKey,counts:p(n,"counts"),hashes:p(n,"hashes"),redactionSummary:Array.isArray(n.redactionSummary)?n.redactionSummary:void 0,relativePaths:L(n.relativePaths),metadata:a})}applyCompleteExecutionAttempt(e){const n=p(e,"completion")??e;this.store.completeHeadlessExecutionAttempt({attemptId:r(n,"attemptId"),executionId:o(n,"executionId"),jobId:o(n,"jobId")??e.jobId,leaseId:o(n,"leaseId"),runnerId:o(n,"runnerId"),status:r(n,"status"),completedAt:o(n,"completedAt")??e.createdAt,durationMs:h(n,"durationMs"),reasonCode:o(n,"reasonCode"),publicSummary:o(n,"publicSummary"),notBeforeAt:o(n,"notBeforeAt"),retryCount:h(n,"retryCount"),counts:p(n,"counts"),hashes:p(n,"hashes"),redactionSummary:Array.isArray(n.redactionSummary)?n.redactionSummary:void 0,relativePaths:L(n.relativePaths),metadata:f(p(n,"metadata"),"executionCompletion.metadata")})}applyAppendExecutionReceipt(e){const n=T(e,"receipt");this.store.recordHeadlessExecutionReceipt({receiptId:r(n,"receiptId"),attemptId:r(n,"attemptId"),executionId:r(n,"executionId"),jobId:o(n,"jobId")??e.jobId,status:r(n,"status"),reasonCode:o(n,"reasonCode"),createdAt:o(n,"createdAt")??e.createdAt,operationId:e.operationId,idempotencyKey:e.idempotencyKey,counts:p(n,"counts"),hashes:p(n,"hashes"),redactionSummary:Array.isArray(n.redactionSummary)?n.redactionSummary:void 0,relativePaths:L(n.relativePaths),metadata:f(p(n,"metadata"),"executionReceipt.metadata")})}applyAppendExecutionSummary(e){const n=p(e,"summary")??e;this.store.recordHeadlessExecutionSummary({eventId:o(n,"eventId"),attemptId:r(n,"attemptId"),executionId:r(n,"executionId"),jobId:o(n,"jobId")??e.jobId,publicSummary:r(n,"publicSummary"),reasonCode:o(n,"reasonCode"),createdAt:o(n,"createdAt")??e.createdAt,runtimeId:o(n,"runtimeId"),modelId:o(n,"modelId"),durationMs:h(n,"durationMs"),counts:p(n,"counts"),hashes:p(n,"hashes"),redactionSummary:Array.isArray(n.redactionSummary)?n.redactionSummary:void 0,relativePaths:L(n.relativePaths),metadata:f(p(n,"metadata"),"executionSummary.metadata")})}recordAppliedAudit(e){this.store.recordOperationAudit({receiptId:`receipt-${R(e.operationId)}`,jobId:e.jobId,operationId:e.operationId,idempotencyKey:`audit-${e.idempotencyKey??e.operationId}`,status:"applied",reasonCode:I.OK,appliedOperationIds:[e.operationId],createdAt:e.createdAt,metadata:{schemaVersion:S,contractVersion:g,jobId:e.jobId,operationId:e.operationId,status:"applied",reasonCode:I.OK}})}recordIgnoredAuditIfPossible(e,n){this.store.jobExists(e.jobId)&&this.store.recordOperationAudit({receiptId:`receipt-${R(e.operationId)}-ignored`,jobId:e.jobId,operationId:e.operationId,idempotencyKey:`audit-${e.idempotencyKey??e.operationId}-ignored`,status:"ignored",reasonCode:n,ignoredOperationIds:[e.operationId],createdAt:e.createdAt,metadata:{schemaVersion:S,contractVersion:g,jobId:e.jobId,operationId:e.operationId,status:"ignored",reasonCode:n}})}}function ee(t){const e=Le(t.metadata_json,t.iteration),n=v(t.metadata_json),a=P(n),i=le(n.currentStage)?n.currentStage:void 0,d=_e(n.stageHistory),u=Y(n.iteration)??Y(t.iteration);return O(e,"goalLedgerItems","goal_ledger_item_count"in t?t.goal_ledger_item_count:void 0),O(e,"blockedGoalLedgerItems","blocked_goal_ledger_item_count"in t?t.blocked_goal_ledger_item_count:void 0),O(e,"securityIssuesBlocked","security_issue_blocked_count"in t?t.security_issue_blocked_count:void 0),O(e,"goalVerifiers","goal_verifier_count"in t?t.goal_verifier_count:void 0),O(e,"failedVerifiers","failed_verifier_count"in t?t.failed_verifier_count:void 0),O(e,"unavailableVerifiers","unavailable_verifier_count"in t?t.unavailable_verifier_count:void 0),O(e,"goalReviewGates","goal_review_gate_count"in t?t.goal_review_gate_count:void 0),O(e,"failedRequiredReviewGates","failed_required_review_gate_count"in t?t.failed_required_review_gate_count:void 0),{jobId:s(t.job_id,80),kind:s(t.kind,40),status:s(t.status,40),publicSummary:s(t.summary??"No public summary recorded.",k),createdAt:s(t.created_at,80),updatedAt:s(t.updated_at,80),...t.next_run_at?{nextRunAt:s(t.next_run_at,80)}:{},...t.reason_code?{reasonCode:s(t.reason_code,80)}:{},...Object.keys(e).length>0?{counts:e}:{},...i?{currentStage:i}:{},...d.length>0?{stageHistory:d}:{},...u!==void 0?{iteration:u}:{},...Oe(a),publicSafe:!0}}function xe(t){const e={jobs:t.counts.jobs??t.jobCount,dueJobs:t.counts.dueJobs??t.dueJobCount,outboxPending:t.outboxPending,redactions:t.redactions.length},n=V({generatedAt:t.generatedAt,counts:e});return{syncVersion:fe,transportKind:"client_snapshot",snapshotId:`snapshot-${R(B(n).replace(/^sha256:/,"").slice(0,16))}`,generatedAt:s(t.generatedAt,80),publicSummary:`Client snapshot contains ${e.jobs} public jobs and ${e.outboxPending} pending outbox records.`,counts:e,hashes:{snapshot:B(n)},redactionEvidence:t.redactions.slice(0,20),publicSafe:!0}}function Oe(t){const e=t.runtimeSource==="explicit"||t.runtimeSource==="origin"||t.runtimeSource==="default"||t.runtimeSource==="fallback"||t.runtimeSource==="unspecified"?t.runtimeSource:void 0;return{...b(t,"runtimeId",80),...b(t,"modelId",120),...e?{runtimeSource:e}:{},...b(t,"headlessRuntime",80),...b(t,"headlessModel",120),...b(t,"headlessRuntimeReasonCode",100),...b(t,"originRuntime",80),...b(t,"originModel",120),...b(t,"workspaceId",120),...b(t,"workspaceLabel",80),...b(t,"projectId",120),...b(t,"projectLabel",80)}}function Te(t){return t?{workspaceId:t.workspaceId,workspaceLabel:t.workspaceLabel,projectId:t.projectId,projectLabel:t.projectLabel}:{}}function b(t,e,n){const a=t[e];return typeof a=="string"?{[e]:s(a,n)}:{}}function te(t){const e=P(v(t.metadata_json)),n=typeof e.goalId=="string"?s(e.goalId,100):void 0,a=typeof e.loopId=="string"?s(e.loopId,100):void 0;return{eventId:s(t.event_id,120),jobId:s(t.job_id,100),...n?{goalId:n}:{},...a?{loopId:a}:{},executionId:s(t.execution_id,120),publicSummary:s(t.public_summary,k),...t.reason_code?{reasonCode:s(t.reason_code,80)}:{},createdAt:s(t.created_at,80),cursor:s(t.cursor,260),...Object.keys(e).length>0?{metadata:e}:{},publicSafe:!0}}function Ne(t){return{attemptId:s(t.attempt_id,120),executionId:s(t.execution_id,120),jobId:s(t.job_id,100),status:s(t.status,40),...t.reason_code?{reasonCode:s(t.reason_code,80)}:{},...t.runtime_id?{runtimeId:s(t.runtime_id,80)}:{},...t.model_id?{modelId:s(t.model_id,120)}:{},retryCount:Math.max(0,Math.floor(t.retry_count)),attemptCount:Math.max(0,Math.floor(t.attempt_count)),maxAttempts:Math.max(1,Math.floor(t.max_attempts)),queuePriority:Math.max(-100,Math.min(100,Math.floor(t.queue_priority))),queueScope:t.queue_scope==="workspace"?"workspace":"project",...typeof t.duration_ms=="number"&&Number.isFinite(t.duration_ms)?{durationMs:Math.max(0,Math.floor(t.duration_ms))}:{},...ne("counts",v(t.counts_json)),...ne("hashes",v(t.hashes_json)),...Pe("redactionSummary",t.redaction_summary_json),...t.lease_id?{leaseId:s(t.lease_id,120)}:{},...t.runner_id?{runnerId:s(t.runner_id,120)}:{},...t.lease_expires_at?{leaseExpiresAt:s(t.lease_expires_at,80)}:{},...t.heartbeat_at?{heartbeatAt:s(t.heartbeat_at,80)}:{},publicSummary:s(t.public_summary??"No public headless execution summary recorded.",k),enqueuedAt:s(t.enqueued_at,80),...t.not_before_at?{notBeforeAt:s(t.not_before_at,80)}:{},...t.next_retry_at?{nextRetryAt:s(t.next_retry_at,80)}:{},...t.dead_lettered_at?{deadLetteredAt:s(t.dead_lettered_at,80)}:{},...t.dead_letter_reason_code?{deadLetterReasonCode:s(t.dead_letter_reason_code,80)}:{},publicSafe:!0}}function O(t,e,n){typeof n=="number"&&Number.isFinite(n)&&n>0&&(t[e]=Math.floor(n))}function Le(t,e){const n={};if(t)try{const a=JSON.parse(t),i=y(a)&&y(a.counts)?a.counts:void 0;if(i)for(const[d,u]of Object.entries(i))typeof u=="number"&&Number.isFinite(u)&&(n[d]=Math.max(0,Math.floor(u)))}catch{}return typeof e=="number"&&Number.isFinite(e)&&(n.iteration=Math.max(0,Math.floor(e))),n}function ke(t){const e=t.map(ve).filter(n=>!!n);return{preferredSource:e.length>0?"compact_summary":"recent_events",summaries:e,publicSafe:!0}}function ve(t){const e=v(t.metadata_json),n=y(e.hashes)?e.hashes:{},a=typeof n.summary=="string"?n.summary:t.sha256??void 0,i=typeof e.reasonCode=="string"?s(e.reasonCode,80):void 0;return{snapshotId:s(t.snapshot_id,120),...t.job_id?{jobId:s(t.job_id,100)}:{},...t.operation_id?{operationId:s(t.operation_id,120)}:{},capturedAt:s(t.captured_at,80),publicSummary:s(t.summary??"Context compacted with public-safe refs.",Z),...a?{summaryHash:s(a,120)}:{},...t.relative_path?{relativePath:s(t.relative_path,240)}:{},retainedRefs:je(e.relativePaths),artifactRefs:$(e.artifactRefs),evidenceRefs:$(e.evidenceRefs),...y(e.checkpoint)?{checkpoint:P(e.checkpoint)}:{},...i?{reasonCode:i}:{},publicSafe:!0}}function v(t){if(!t)return{};try{const e=JSON.parse(t);return y(e)?e:{}}catch{return{}}}function ne(t,e){const n=P(e);return Object.keys(n).length>0?{[t]:n}:{}}function Pe(t,e){if(!e)return{};try{const n=JSON.parse(e),a=$(n);return a.length>0?{[t]:a}:{}}catch{return{}}}function je(t){return Array.isArray(t)?t.filter(e=>typeof e=="string"&&e.length>0).map(e=>s(e,240)).slice(0,D):[]}function $(t){return Array.isArray(t)?t.map(H).filter(e=>e!==void 0).slice(0,D):[]}function P(t){const e={};for(const[n,a]of Object.entries(t).slice(0,20)){if(K.test(n))continue;const i=H(a);i!==void 0&&(e[s(n,80)]=i)}return e}function H(t){if(!M(t)){if(typeof t=="string")return s(t,240);if(typeof t=="number"&&Number.isFinite(t))return Math.floor(t);if(typeof t=="boolean"||t===null)return t;if(Array.isArray(t))return t.map(H).filter(n=>n!==void 0).slice(0,20);if(y(t))return P(t)}}function Me(t){return y(t)?Array.isArray(t.operationLogs)?t.operationLogs.filter(y):y(t.operationLog)?[t.operationLog]:Array.isArray(t.operations)?[t]:[]:[]}function Ue(t){const e=[],n=[],a=[],i=[],d=[],u=new Map;if(t.schemaVersion!==S)throw new _("Invalid continuity operation log schema version.",[I.INVALID_SCHEMA_VERSION],{mutationBlocked:!0});if(t.contractVersion!==g)throw new _("Invalid continuity operation log contract version.",[I.INVALID_CONTRACT_VERSION],{mutationBlocked:!0});if(t.publicSafe!==!0)throw new _("Continuity operation log is not marked public-safe.",[I.UNSAFE_FIELD_REJECTED],{mutationBlocked:!0});const m=f(p(t,"metadata"),"log.metadata");if(!Array.isArray(t.operations))return{operations:[],skippedOperations:a,ignoredOperationIds:i,reasonCodes:e,redactions:n,logMetadata:m};for(const c of[...t.operations].filter(y).sort(De)){const l=Ve(c),U=V(l),N=u.get(l.operationId);if(N!==void 0){if(N===U){i.push(l.operationId),e.push(I.IDEMPOTENCY_REPLAY);continue}throw n.push({field:"operationId",reason:"unknown_required_operation",evidence:"operation-denied",publicSafe:!0}),new _("Duplicate continuity operation ID with conflicting payload.",[I.DUPLICATE_OPERATION_ID],{redactions:n,mutationBlocked:!0})}if(u.set(l.operationId,U),f(l.metadata,"operation.metadata"),!he.has(l.type)){const j=c.required===!0;if(c.forwardCompatible===!0&&!j){a.push(l),i.push(l.operationId),e.push(I.UNKNOWN_OPERATION_IGNORED);continue}throw n.push({field:l.type,reason:"unknown_required_operation",evidence:"operation-denied",publicSafe:!0}),new _(`Unknown required continuity operation ${l.type}.`,[I.UNKNOWN_OPERATION_REQUIRED],{redactions:n,mutationBlocked:!0})}d.push(l)}return{operations:d,skippedOperations:a,ignoredOperationIds:i,reasonCodes:e,redactions:n,logMetadata:m}}function Ve(t){if(t.schemaVersion!==S)throw new _("Invalid continuity operation schema version.",[I.INVALID_SCHEMA_VERSION],{mutationBlocked:!0});if(t.contractVersion!==g)throw new _("Invalid continuity operation contract version.",[I.INVALID_CONTRACT_VERSION],{mutationBlocked:!0});if(t.publicSafe!==!0)throw new _("Continuity operation is not marked public-safe.",[I.UNSAFE_FIELD_REJECTED],{mutationBlocked:!0});const e=r(t,"type"),n=r(t,"operationId"),a=r(t,"jobId"),i=$e(t,"sequence"),d=r(t,"createdAt");return{...t,type:e,operationId:n,jobId:a,schemaVersion:S,contractVersion:g,sequence:i,createdAt:d,idempotencyKey:o(t,"idempotencyKey"),metadata:p(t,"metadata"),publicSafe:!0}}function f(t,e){if(!t)return{};const n={},a=[];for(const[i,d]of Object.entries(t)){const u=qe(i),m=M(d),c=u??m;if(c){a.push({field:`${e}.${i}`,reason:c,evidence:u?"key-denied":"value-denied",publicSafe:!0});continue}n[i]=d}if(a.length>0)throw new _(`Continuity metadata rejected unsafe public fields at ${e}.`,[I.UNSAFE_FIELD_REJECTED],{redactions:a,mutationBlocked:!0});return n}function qe(t){return!Ae.has(t)||K.test(t)?"unsafe_key":null}function M(t){if(typeof t=="string")return G.test(t)?"private_url":be.test(t)?"local_absolute_path":J.test(t)?"secret":Q.test(t)?"prompt_body":W.test(t)?"raw_log":X.test(t)?"protected_field":null;if(t===null||typeof t=="number"||typeof t=="boolean")return null;if(Array.isArray(t)){for(const e of t){const n=M(e);if(n)return n}return null}if(y(t)){for(const[e,n]of Object.entries(t)){if(K.test(e))return"unsafe_key";const a=M(n);if(a)return a}return null}return"unsafe_key"}function Ke(t){const e=[];for(const n of t)if(n.metadata_json)try{const i=JSON.parse(n.metadata_json).redactionEvidence;if(!Array.isArray(i))continue;for(const d of i)y(d)&&(typeof d.field!="string"||typeof d.reason!="string"||typeof d.evidence!="string"||e.push({field:s(d.field,120),reason:d.reason,evidence:d.evidence,publicSafe:!0}))}catch{}return e}function De(t,e){const n=typeof t.sequence=="number"?t.sequence:0,a=typeof e.sequence=="number"?e.sequence:0;if(n!==a)return n-a;const i=String(t.createdAt??"").localeCompare(String(e.createdAt??""));return i!==0?i:String(t.operationId??"").localeCompare(String(e.operationId??""))}function y(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function T(t,e){const n=t[e];if(!y(n))throw new _(`Continuity operation missing object field ${e}.`,[I.INVALID_SCHEMA_VERSION],{mutationBlocked:!0});return n}function p(t,e){const n=t[e];return y(n)?n:void 0}function r(t,e){const n=t[e];if(typeof n!="string"||n.length===0)throw new _(`Continuity operation missing string field ${e}.`,[I.INVALID_SCHEMA_VERSION],{mutationBlocked:!0});return n}function o(t,e){const n=t[e];return typeof n=="string"&&n.length>0?n:void 0}function $e(t,e){const n=t[e];if(typeof n!="number"||!Number.isFinite(n))throw new _(`Continuity operation missing numeric field ${e}.`,[I.INVALID_SCHEMA_VERSION],{mutationBlocked:!0});return n}function h(t,e){const n=t[e];return typeof n=="number"&&Number.isFinite(n)?n:void 0}function He(t,e){const n=t[e];return typeof n=="boolean"?n:void 0}function L(t){return Array.isArray(t)?t.filter(e=>typeof e=="string"&&e.length>0):[]}function ae(t){return Array.isArray(t)?t.filter(y):[]}function we(t){return C(t,Z,"compact_context.publicSummary")}function C(t,e,n){const a=t.trim();if(!a)throw new _(`Continuity compaction missing public text at ${n}.`,[I.INVALID_SCHEMA_VERSION],{mutationBlocked:!0});const i=M(a);if(i)throw new _(`Continuity compaction rejected unsafe public text at ${n}.`,[I.UNSAFE_FIELD_REJECTED],{redactions:[{field:n,reason:i,evidence:"value-denied",publicSafe:!0}],mutationBlocked:!0});return a.length<=e?a:`${a.slice(0,e)}\u2026[TRUNCATED:${a.length-e}]`}function w(t,e){return C(t,120,e)}function oe(t,e,n){return E(L(t).map((a,i)=>F(a,`${e}[${i}]`))).slice(0,n)}function F(t,e){const n=C(t,240,e).replace(/\\/g,"/"),a=n.split("/").filter(Boolean),i=/^[A-Za-z]:\//.test(n);if(n.startsWith("/")||n.startsWith("~")||n.includes("://")||i||a.includes(".."))throw new _(`Continuity compaction rejected non-relative ref at ${e}.`,[I.UNSAFE_FIELD_REJECTED],{redactions:[{field:e,reason:"private_url",evidence:"value-denied",publicSafe:!0}],mutationBlocked:!0});return n}function Fe(t){const e=[],n=p(t,"summaryRef");n&&e.push(re(n,"compact_context.summaryRef","context_summary"));for(const[i,d]of ae(t.artifactRefs).entries())e.push(re(d,`compact_context.artifactRefs[${i}]`));const a=new Set;return e.filter(i=>{const d=`${i.kind}:${i.relativePath}`;return a.has(d)?!1:(a.add(d),!0)}).slice(0,Se)}function re(t,e,n="context_summary"){const a=C(o(t,"kind")??n,60,`${e}.kind`),i=F(r(t,"relativePath"),`${e}.relativePath`),d=o(t,"sha256"),u=o(t,"publicSummary");return{kind:a,relativePath:i,...d?{sha256:w(d,`${e}.sha256`)}:{},...u?{publicSummary:C(u,k,`${e}.publicSummary`)}:{},publicSafe:!0}}function Be(t){return ae(t.evidenceIndex).map((e,n)=>{const a=`compact_context.evidenceIndex[${n}]`,i=F(r(e,"relativePath"),`${a}.relativePath`),d=o(e,"refId")??`evidence-${R(i)}`,u=o(e,"reasonCode")??o(t,"reasonCode")??"context-compacted",m=o(e,"sha256"),c=o(e,"publicSummary");return{refId:C(d,120,`${a}.refId`),relativePath:i,reasonCode:C(u,80,`${a}.reasonCode`),...m?{sha256:w(m,`${a}.sha256`)}:{},...c?{publicSummary:C(c,k,`${a}.publicSummary`)}:{},publicSafe:!0}}).slice(0,ge)}function Ye(t,e,n,a){const i=p(t,"checkpoint")??{},d=o(i,"checkpointId")??`checkpoint-${R(t.operationId)}`,u=o(i,"capturedAt")??t.createdAt,m={checkpointId:C(d,120,"compact_context.checkpoint.checkpointId"),capturedAt:C(u,80,"compact_context.checkpoint.capturedAt"),retainedRefCount:e.length,artifactRefCount:n.length,evidenceRefCount:a.length,publicSafe:!0};for(const c of["eventCursor","receiptCursor"]){const l=o(i,c);l&&(m[c]=C(l,120,`compact_context.checkpoint.${c}`))}for(const c of["recentEventCount","recentReceiptCount"]){const l=h(i,c);l!==void 0&&(m[c]=Math.max(0,Math.floor(l)))}return m}function B(t){return`sha256:${ie("sha256").update(t).digest("hex")}`}function E(t){return Array.from(new Set(t))}function R(t){return t.replace(/[^a-z0-9_.:-]+/gi,"-").slice(0,120)}function s(t,e){const n=ze(t);return n.length<=e?n:`${n.slice(0,e)}\u2026[TRUNCATED:${n.length-e}]`}function ze(t){return G.test(t)||J.test(t)||W.test(t)||Q.test(t)||X.test(t)?"[REDACTED]":t}function V(t){return Array.isArray(t)?`[${t.map(V).join(",")}]`:y(t)?`{${Object.keys(t).sort().map(e=>`${JSON.stringify(e)}:${V(t[e])}`).join(",")}}`:JSON.stringify(t)}function q(t,e){if(t instanceof _)return t;if(t instanceof pe)return new _(t.message,[t.reasonCode],{mutationBlocked:t.mutationBlocked,cause:t});const n=t instanceof Error?t.message:String(t);return new _(`${e} ${n}`,[I.SQLITE_MUTATION_FAILED],{cause:t})}export{g as CONTINUITY_CLIENT_CONTRACT_VERSION,fe as CONTINUITY_CLIENT_PORTAL_SYNC_ENVELOPE_VERSION,I as CONTINUITY_CLIENT_REASON_CODES,S as CONTINUITY_CLIENT_SCHEMA_VERSION,Ze as CONTINUITY_INVOKE_WATCH_DEFAULT_LIMIT,tt as CONTINUITY_INVOKE_WATCH_DEFAULT_MAX_IDLE_POLLS,nt as CONTINUITY_INVOKE_WATCH_DEFAULT_MAX_POLLS,et as CONTINUITY_INVOKE_WATCH_DEFAULT_POLL_INTERVAL_MS,z as CONTINUITY_PROCESSING_SUMMARY_WATCH_DEFAULT_LIMIT,ye as CONTINUITY_PROCESSING_SUMMARY_WATCH_DEFAULT_POLL_INTERVAL_MS,Re as ContinuityClientStateStore,_ as ContinuityClientStateStoreError,at as continuitySqliteExists,ot as createContinuityHardStopSnapshot,rt as openContinuityClientStateStore};
1
+ /**
2
+ * @license FSL-1.1
3
+ * Copyright (c) 2026 OrNexus AI
4
+ *
5
+ * P180.05 -- Thin-client continuity state snapshots and operation-log apply.
6
+ */
7
+ import { existsSync } from 'node:fs';
8
+ import { createHash } from 'node:crypto';
9
+ import { deriveProjectIdentity } from '../runner/project-identity.js';
10
+ import { recordAutonomousGovernance, } from './autonomous-governance.js';
11
+ import { CONTINUITY_PROCESSING_OUTPUT_SUMMARY_EVENT_TYPE, ContinuitySqliteStoreError, continuitySqliteStorePath, isContinuityPublicStage, normalizeContinuityStageIteration, openContinuitySqliteStore, sanitizeContinuityStageHistory, } from './sqlite-store.js';
12
+ export const CONTINUITY_CLIENT_SCHEMA_VERSION = 1;
13
+ export const CONTINUITY_CLIENT_CONTRACT_VERSION = 'continuity-v1';
14
+ export const CONTINUITY_PROCESSING_SUMMARY_WATCH_DEFAULT_LIMIT = 10;
15
+ export const CONTINUITY_PROCESSING_SUMMARY_WATCH_DEFAULT_POLL_INTERVAL_MS = 2_000;
16
+ export const CONTINUITY_INVOKE_WATCH_DEFAULT_LIMIT = CONTINUITY_PROCESSING_SUMMARY_WATCH_DEFAULT_LIMIT;
17
+ export const CONTINUITY_INVOKE_WATCH_DEFAULT_POLL_INTERVAL_MS = CONTINUITY_PROCESSING_SUMMARY_WATCH_DEFAULT_POLL_INTERVAL_MS;
18
+ export const CONTINUITY_INVOKE_WATCH_DEFAULT_MAX_IDLE_POLLS = 3;
19
+ export const CONTINUITY_INVOKE_WATCH_DEFAULT_MAX_POLLS = 1_800;
20
+ export const CONTINUITY_CLIENT_PORTAL_SYNC_ENVELOPE_VERSION = 1;
21
+ export const CONTINUITY_CLIENT_REASON_CODES = Object.freeze({
22
+ OK: 'continuity-ok',
23
+ INVALID_SCHEMA_VERSION: 'invalid-schema-version',
24
+ INVALID_CONTRACT_VERSION: 'invalid-contract-version',
25
+ UNKNOWN_OPERATION_REQUIRED: 'unknown-operation-required',
26
+ UNKNOWN_OPERATION_IGNORED: 'unknown-operation-ignored',
27
+ DUPLICATE_OPERATION_ID: 'duplicate-operation-id',
28
+ IDEMPOTENCY_REPLAY: 'idempotency-replay',
29
+ UNSAFE_FIELD_REJECTED: 'unsafe-field-rejected',
30
+ SQLITE_ADAPTER_UNAVAILABLE: 'sqlite-adapter-unavailable',
31
+ SQLITE_INTEGRITY_FAILED: 'sqlite-integrity-failed',
32
+ SQLITE_MUTATION_FAILED: 'sqlite-mutation-failed',
33
+ });
34
+ const KNOWN_OPERATION_TYPES = new Set([
35
+ 'create_job',
36
+ 'update_job_status',
37
+ 'append_event',
38
+ 'append_receipt',
39
+ 'upsert_goal_campaign',
40
+ 'upsert_goal_ledger_item',
41
+ 'upsert_verifier',
42
+ 'upsert_review_gate',
43
+ 'schedule_next_tick',
44
+ 'acquire_lease',
45
+ 'release_lease',
46
+ 'compact_context',
47
+ 'enqueue_outbox',
48
+ 'append_outbox',
49
+ 'enqueue_execution_attempt',
50
+ 'claim_execution_attempt',
51
+ 'heartbeat_execution_attempt',
52
+ 'release_execution_attempt',
53
+ 'complete_execution_attempt',
54
+ 'append_execution_receipt',
55
+ 'append_execution_summary',
56
+ ]);
57
+ const ALLOWED_METADATA_KEYS = new Set([
58
+ 'schemaVersion',
59
+ 'contractVersion',
60
+ 'eventType',
61
+ 'executionId',
62
+ 'jobId',
63
+ 'operationId',
64
+ 'idempotencyKey',
65
+ 'goalId',
66
+ 'loopId',
67
+ 'campaignId',
68
+ 'itemId',
69
+ 'ledgerItemIds',
70
+ 'verifierId',
71
+ 'verifierIds',
72
+ 'gateId',
73
+ 'reviewGateIds',
74
+ 'runnerId',
75
+ 'leaseId',
76
+ 'status',
77
+ 'reasonCode',
78
+ 'reasonCodes',
79
+ 'runtimeId',
80
+ 'modelId',
81
+ 'runtimeSource',
82
+ 'headlessRuntime',
83
+ 'headlessModel',
84
+ 'headlessRuntimeReasonCode',
85
+ 'originRuntime',
86
+ 'originModel',
87
+ 'targetRef',
88
+ 'attemptId',
89
+ 'attemptStatus',
90
+ 'directiveHash',
91
+ 'timeoutMs',
92
+ 'leaseExpiresAt',
93
+ 'heartbeatAt',
94
+ 'notBeforeAt',
95
+ 'maxAttempts',
96
+ 'counts',
97
+ 'hashes',
98
+ 'relativePaths',
99
+ 'artifactRefs',
100
+ 'evidenceRefs',
101
+ 'validationRefs',
102
+ 'registryRefs',
103
+ 'storyIds',
104
+ 'epicIds',
105
+ 'debtIds',
106
+ 'iteration',
107
+ 'currentStage',
108
+ 'stageHistory',
109
+ 'durationMs',
110
+ 'retryCount',
111
+ 'nextTickAt',
112
+ 'processingOutputSource',
113
+ 'publicSummary',
114
+ 'redactionEvidence',
115
+ 'selectorKind',
116
+ 'targetId',
117
+ 'targetJobId',
118
+ 'relatedJobIds',
119
+ 'serverAccessToLocalhost',
120
+ 'serverHeldStream',
121
+ 'initialCursor',
122
+ 'targetResolutionState',
123
+ 'targetKind',
124
+ 'relatedJobCount',
125
+ 'snapshotStatus',
126
+ 'snapshotGeneratedAt',
127
+ 'renderedSummaryCount',
128
+ 'cursorState',
129
+ 'currentCursor',
130
+ 'nextCursor',
131
+ 'cursorAdvanced',
132
+ 'eventId',
133
+ 'latestEventId',
134
+ 'watchStatus',
135
+ 'stopReason',
136
+ 'syncVersion',
137
+ 'transportKind',
138
+ 'envelopeId',
139
+ 'workspaceId',
140
+ 'workspaceLabel',
141
+ 'projectId',
142
+ 'projectLabel',
143
+ 'snapshotId',
144
+ 'syncCursor',
145
+ 'previousSyncCursor',
146
+ 'nextSyncCursor',
147
+ 'commandId',
148
+ 'receiptId',
149
+ 'acknowledgedAt',
150
+ 'observedAt',
151
+ 'generatedAt',
152
+ 'syncStatus',
153
+ 'commandStatus',
154
+ 'receiptStatus',
155
+ 'actorType',
156
+ 'actorId',
157
+ 'tenantId',
158
+ 'commandKind',
159
+ 'auditStatus',
160
+ 'redactionCount',
161
+ ]);
162
+ const UNSAFE_METADATA_KEY_PATTERN = /(raw[_-]?(?:logs?|payloads?)|std(?:out|err)|stack(?:[_-]?trace)?|transcript|prompt(?:[_-]?(?:body|text))?|private[_-]?(?:urls?|prompts?)|secret|token|password|protected(?:[_-]?(?:field|body|bodies|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|\bpii\b|authorization|api[_-]?key|license[_-]?key|argv|args|executable(?:[_-]?path)?|binary(?:[_-]?path)?|shell|cwd|command[_-]?path|vendor(?:[_-]?(?:payload|corpus|response|output)))/i;
163
+ const ABSOLUTE_URL_VALUE_PATTERN = /\bhttps?:\/\/\S+/i;
164
+ const LOCAL_ABSOLUTE_PATH_VALUE_PATTERN = /(?:^|\s)(?:\/(?:home|Users|media|mnt|tmp|var|etc|private)\/\S+|[A-Za-z]:\\\S+)/i;
165
+ const SECRET_VALUE_PATTERN = /(ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|-----BEGIN [A-Z ]*PRIVATE KEY-----|authorization\s*:|password\s*=|token\s*=|api[_-]?key\s*=|license[_-]?key\s*=)/i;
166
+ const RAW_LOG_VALUE_PATTERN = /(raw[_-]?(?:logs?)\s*[:=]|transcript|stack trace|stderr:|stdout:)/i;
167
+ const PROMPT_VALUE_PATTERN = /(prompt[_-]?body|system prompt|workflow body|step body)/i;
168
+ const PROTECTED_VALUE_PATTERN = /(PROTECTED_|_PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|\bPII\b|VENDOR_CORPUS|P180[_-]?SYNTHETIC[_-]?CONTINUITY|P185[_-]?SYNTHETIC[_-]?CONTINUITY|P187[_-]?SYNTHETIC[_-]?(?:CONTINUITY|RUNNER|WATCH)|P190[_-]?SYNTHETIC[_-]?(?:HEADLESS|CONTINUITY)|P192[_-]?SYNTHETIC[_-]?(?:PORTAL|RUNNER|SYNC))/i;
169
+ const PUBLIC_TEXT_MAX_CHARS = 240;
170
+ const COMPACTION_SUMMARY_MAX_CHARS = 2_400;
171
+ const COMPACTION_RETAINED_REF_LIMIT = 40;
172
+ const COMPACTION_ARTIFACT_REF_LIMIT = 20;
173
+ const COMPACTION_EVIDENCE_REF_LIMIT = 40;
174
+ const COMPACTION_DECISION_LOG_REF_LIMIT = 20;
175
+ const COMPACTION_RELATIVE_PATH_LIMIT = 80;
176
+ export class ContinuityClientStateStoreError extends Error {
177
+ reasonCodes;
178
+ redactions;
179
+ mutationBlocked;
180
+ constructor(message, reasonCodes, options = {}) {
181
+ super(message);
182
+ this.name = 'ContinuityClientStateStoreError';
183
+ this.reasonCodes = unique(reasonCodes);
184
+ this.redactions = options.redactions ?? [];
185
+ this.mutationBlocked = options.mutationBlocked ?? false;
186
+ this.cause = options.cause;
187
+ }
188
+ }
189
+ export function continuitySqliteExists(projectRoot) {
190
+ return existsSync(continuitySqliteStorePath(projectRoot));
191
+ }
192
+ export function createContinuityHardStopSnapshot(reasonCodes, nowIso = new Date().toISOString()) {
193
+ return {
194
+ schemaVersion: CONTINUITY_CLIENT_SCHEMA_VERSION,
195
+ contractVersion: CONTINUITY_CLIENT_CONTRACT_VERSION,
196
+ generatedAt: nowIso,
197
+ hardStop: true,
198
+ reasonCodes: unique(reasonCodes),
199
+ publicSafe: true,
200
+ };
201
+ }
202
+ export async function openContinuityClientStateStore(options) {
203
+ const store = await openContinuitySqliteStore({
204
+ projectRoot: options.projectRoot,
205
+ adapter: options.adapter,
206
+ adapterLoader: options.adapterLoader,
207
+ now: options.now,
208
+ strictReadOnly: options.strictReadOnly,
209
+ });
210
+ return new ContinuityClientStateStore(store, options.now ?? (() => new Date().toISOString()), deriveProjectIdentity(options.projectRoot));
211
+ }
212
+ export class ContinuityClientStateStore {
213
+ store;
214
+ now;
215
+ projectIdentity;
216
+ constructor(store, now = () => new Date().toISOString(), projectIdentity) {
217
+ this.store = store;
218
+ this.now = now;
219
+ this.projectIdentity = projectIdentity;
220
+ }
221
+ close() {
222
+ this.store.close();
223
+ }
224
+ recordAutonomousGovernance(envelope, nowIso) {
225
+ try {
226
+ return recordAutonomousGovernance(this.store, envelope, nowIso);
227
+ }
228
+ catch (error) {
229
+ throw mapContinuityError(error, 'Failed to record autonomous governance envelope.');
230
+ }
231
+ }
232
+ collectSnapshot(options = {}) {
233
+ try {
234
+ const nowIso = options.nowIso ?? this.now();
235
+ const rows = this.store.collectSnapshotRows({
236
+ nowIso,
237
+ jobLimit: options.jobLimit ?? 20,
238
+ staleLeaseLimit: options.staleLeaseLimit ?? 10,
239
+ receiptLimit: options.receiptLimit ?? 10,
240
+ eventLimit: options.eventLimit ?? 10,
241
+ snapshotLimit: options.snapshotLimit ?? 5,
242
+ });
243
+ const dueRows = this.store.listDueJobs({
244
+ nowIso,
245
+ limit: options.dueJobLimit ?? 10,
246
+ });
247
+ const processingSummaryRows = this.store.listProcessingOutputSummaries({
248
+ limit: options.processingSummaryLimit ?? CONTINUITY_PROCESSING_SUMMARY_WATCH_DEFAULT_LIMIT,
249
+ });
250
+ const redactions = collectReceiptRedactions(rows.receipts).slice(0, 20);
251
+ const portalSync = toPortalSyncSnapshotSummary({
252
+ generatedAt: nowIso,
253
+ counts: rows.counts,
254
+ jobCount: rows.jobs.length,
255
+ dueJobCount: dueRows.length,
256
+ outboxPending: rows.outboxCounts.pending ?? 0,
257
+ redactions,
258
+ });
259
+ return {
260
+ schemaVersion: CONTINUITY_CLIENT_SCHEMA_VERSION,
261
+ contractVersion: CONTINUITY_CLIENT_CONTRACT_VERSION,
262
+ generatedAt: nowIso,
263
+ store: {
264
+ schemaVersion: rows.schemaVersion,
265
+ readable: true,
266
+ },
267
+ jobs: rows.jobs.map(toSnapshotJobSummary),
268
+ counts: rows.counts,
269
+ dueJobCount: rows.counts.dueJobs ?? 0,
270
+ dueJobs: dueRows.map(toSnapshotJobSummary),
271
+ staleLeases: rows.staleLeases.map((lease) => ({
272
+ leaseId: boundPublicText(lease.lease_id, 100),
273
+ jobId: boundPublicText(lease.job_id, 100),
274
+ runnerId: boundPublicText(lease.runner_id, 100),
275
+ expiresAt: boundPublicText(lease.expires_at, 80),
276
+ publicSafe: true,
277
+ })),
278
+ outbox: {
279
+ total: rows.counts.outbox ?? 0,
280
+ pending: rows.outboxCounts.pending ?? 0,
281
+ failed: rows.outboxCounts.failed ?? 0,
282
+ deadLetter: rows.outboxCounts.dead_letter ?? 0,
283
+ sent: rows.outboxCounts.sent ?? 0,
284
+ acked: rows.outboxCounts.acked ?? 0,
285
+ },
286
+ queue: {
287
+ depth: rows.queue.depth,
288
+ queued: rows.queue.queued,
289
+ running: rows.queue.running,
290
+ retrying: rows.queue.retrying,
291
+ deadLetter: rows.queue.deadLetter,
292
+ capacity: rows.queue.capacity,
293
+ available: rows.queue.available,
294
+ backpressure: rows.queue.backpressure,
295
+ generatedAt: boundPublicText(rows.queue.generatedAt, 80),
296
+ ...(rows.queue.nextRetryAt ? { nextRetryAt: boundPublicText(rows.queue.nextRetryAt, 80) } : {}),
297
+ ...(rows.queue.reasonCode ? { reasonCode: boundPublicText(rows.queue.reasonCode, 80) } : {}),
298
+ publicSafe: true,
299
+ },
300
+ lastReceipts: rows.receipts.map((receipt) => ({
301
+ receiptId: boundPublicText(receipt.receipt_id, 100),
302
+ jobId: boundPublicText(receipt.job_id, 100),
303
+ ...(receipt.operation_id ? { operationId: boundPublicText(receipt.operation_id, 100) } : {}),
304
+ status: boundPublicText(receipt.status, 40),
305
+ ...(receipt.reason_code ? { reasonCode: boundPublicText(receipt.reason_code, 80) } : {}),
306
+ createdAt: boundPublicText(receipt.created_at, 80),
307
+ publicSafe: true,
308
+ })),
309
+ lastEvents: rows.events.map((event) => {
310
+ const metadata = normalizeSnapshotRecord(parsePublicMetadata(event.metadata_json));
311
+ return {
312
+ eventId: boundPublicText(event.event_id, 100),
313
+ jobId: boundPublicText(event.job_id, 100),
314
+ operationId: boundPublicText(event.operation_id, 100),
315
+ type: boundPublicText(event.type, 80),
316
+ publicSummary: boundPublicText(event.summary, PUBLIC_TEXT_MAX_CHARS),
317
+ ...(event.reason_code ? { reasonCode: boundPublicText(event.reason_code, 80) } : {}),
318
+ createdAt: boundPublicText(event.created_at, 80),
319
+ ...(Object.keys(metadata).length > 0 ? { metadata } : {}),
320
+ publicSafe: true,
321
+ };
322
+ }),
323
+ processingSummaries: processingSummaryRows.map(toProcessingSummaryRef),
324
+ headlessExecutionAttempts: rows.headlessExecutionAttempts.map(toHeadlessExecutionAttemptRef),
325
+ compactContext: toCompactContextSnapshot(rows.stateSnapshots),
326
+ portalSync,
327
+ redactions,
328
+ publicSafe: true,
329
+ };
330
+ }
331
+ catch (error) {
332
+ throw mapContinuityError(error, 'Failed to collect continuity snapshot.');
333
+ }
334
+ }
335
+ collectProcessingOutputSummaryCursor(options = {}) {
336
+ try {
337
+ const result = this.store.pollProcessingOutputSummaries(options);
338
+ return {
339
+ summaries: result.summaries.map(toProcessingSummaryRef),
340
+ ...(result.nextCursor ? { nextCursor: result.nextCursor } : {}),
341
+ hasMore: result.hasMore,
342
+ publicSafe: true,
343
+ };
344
+ }
345
+ catch (error) {
346
+ throw mapContinuityError(error, 'Failed to collect processing summary cursor.');
347
+ }
348
+ }
349
+ applyStateUpdate(update) {
350
+ const logs = normalizeStateUpdate(update);
351
+ const appliedOperationIds = [];
352
+ const ignoredOperationIds = [];
353
+ const reasonCodes = [];
354
+ const redactions = [];
355
+ for (const log of logs) {
356
+ const result = this.applyOperationLog(log);
357
+ appliedOperationIds.push(...result.appliedOperationIds);
358
+ ignoredOperationIds.push(...result.ignoredOperationIds);
359
+ reasonCodes.push(...result.reasonCodes);
360
+ redactions.push(...result.redactions);
361
+ }
362
+ return {
363
+ ok: true,
364
+ appliedOperationIds: unique(appliedOperationIds),
365
+ ignoredOperationIds: unique(ignoredOperationIds),
366
+ reasonCodes: unique(reasonCodes.length > 0 ? reasonCodes : [CONTINUITY_CLIENT_REASON_CODES.OK]),
367
+ redactions,
368
+ publicSafe: true,
369
+ };
370
+ }
371
+ applyOperationLog(log) {
372
+ const planned = planOperationLog(log);
373
+ const appliedOperationIds = [];
374
+ const ignoredOperationIds = [...planned.ignoredOperationIds];
375
+ const reasonCodes = [...planned.reasonCodes];
376
+ const redactions = [...planned.redactions];
377
+ try {
378
+ this.store.runInTransaction(() => {
379
+ for (const operation of planned.operations) {
380
+ if (this.store.hasOperationRef(operation.operationId, operation.idempotencyKey)) {
381
+ ignoredOperationIds.push(operation.operationId);
382
+ reasonCodes.push(CONTINUITY_CLIENT_REASON_CODES.IDEMPOTENCY_REPLAY);
383
+ continue;
384
+ }
385
+ this.applyKnownOperation(operation, planned.logMetadata);
386
+ appliedOperationIds.push(operation.operationId);
387
+ if (operation.type !== 'append_receipt') {
388
+ this.recordAppliedAudit(operation);
389
+ }
390
+ }
391
+ for (const skipped of planned.skippedOperations) {
392
+ this.recordIgnoredAuditIfPossible(skipped, CONTINUITY_CLIENT_REASON_CODES.UNKNOWN_OPERATION_IGNORED);
393
+ }
394
+ });
395
+ }
396
+ catch (error) {
397
+ throw mapContinuityError(error, 'Failed to apply continuity operation log atomically.');
398
+ }
399
+ return {
400
+ ok: true,
401
+ appliedOperationIds: unique(appliedOperationIds),
402
+ ignoredOperationIds: unique(ignoredOperationIds),
403
+ reasonCodes: unique(reasonCodes.length > 0 ? reasonCodes : [CONTINUITY_CLIENT_REASON_CODES.OK]),
404
+ redactions,
405
+ publicSafe: true,
406
+ };
407
+ }
408
+ applyKnownOperation(operation, logMetadata) {
409
+ switch (operation.type) {
410
+ case 'create_job':
411
+ this.applyCreateJob(operation, logMetadata);
412
+ return;
413
+ case 'update_job_status':
414
+ this.applyUpdateJobStatus(operation);
415
+ return;
416
+ case 'append_event':
417
+ this.applyAppendEvent(operation);
418
+ return;
419
+ case 'append_receipt':
420
+ this.applyAppendReceipt(operation);
421
+ return;
422
+ case 'upsert_goal_campaign':
423
+ this.applyUpsertGoalCampaign(operation);
424
+ return;
425
+ case 'schedule_next_tick':
426
+ this.store.scheduleNextTick({
427
+ jobId: operation.jobId,
428
+ scheduledAt: requiredString(operation, 'scheduledAt'),
429
+ updatedAt: operation.createdAt,
430
+ reasonCode: optionalString(operation, 'reasonCode'),
431
+ });
432
+ return;
433
+ case 'acquire_lease':
434
+ this.store.acquireLease({
435
+ leaseId: requiredString(operation, 'leaseId'),
436
+ jobId: operation.jobId,
437
+ runnerId: requiredString(operation, 'runnerId'),
438
+ acquiredAt: requiredString(operation, 'acquiredAt'),
439
+ expiresAt: requiredString(operation, 'expiresAt'),
440
+ operationId: operation.operationId,
441
+ idempotencyKey: operation.idempotencyKey,
442
+ metadata: sanitizeMetadataStrict(operation.metadata, 'operation.metadata'),
443
+ });
444
+ return;
445
+ case 'release_lease':
446
+ this.store.releaseLease({
447
+ leaseId: requiredString(operation, 'leaseId'),
448
+ releasedAt: requiredString(operation, 'releasedAt'),
449
+ reasonCode: optionalString(operation, 'reasonCode'),
450
+ });
451
+ return;
452
+ case 'compact_context':
453
+ this.applyCompactContext(operation);
454
+ return;
455
+ case 'upsert_goal_ledger_item':
456
+ this.applyUpsertGoalLedgerItem(operation);
457
+ return;
458
+ case 'upsert_verifier':
459
+ this.applyUpsertVerifier(operation);
460
+ return;
461
+ case 'upsert_review_gate':
462
+ this.applyUpsertReviewGate(operation);
463
+ return;
464
+ case 'enqueue_outbox':
465
+ case 'append_outbox':
466
+ this.applyOutbox(operation);
467
+ return;
468
+ case 'enqueue_execution_attempt':
469
+ this.applyEnqueueExecutionAttempt(operation);
470
+ return;
471
+ case 'claim_execution_attempt':
472
+ this.store.claimHeadlessExecutionAttempt({
473
+ attemptId: requiredString(operation, 'attemptId'),
474
+ leaseId: requiredString(operation, 'leaseId'),
475
+ runnerId: requiredString(operation, 'runnerId'),
476
+ claimedAt: optionalString(operation, 'claimedAt') ?? operation.createdAt,
477
+ leaseExpiresAt: requiredString(operation, 'leaseExpiresAt'),
478
+ reasonCode: optionalString(operation, 'reasonCode'),
479
+ });
480
+ return;
481
+ case 'heartbeat_execution_attempt':
482
+ this.store.heartbeatHeadlessExecutionAttempt({
483
+ attemptId: requiredString(operation, 'attemptId'),
484
+ leaseId: requiredString(operation, 'leaseId'),
485
+ runnerId: requiredString(operation, 'runnerId'),
486
+ heartbeatAt: optionalString(operation, 'heartbeatAt') ?? operation.createdAt,
487
+ leaseExpiresAt: optionalString(operation, 'leaseExpiresAt'),
488
+ });
489
+ return;
490
+ case 'release_execution_attempt':
491
+ this.store.releaseHeadlessExecutionAttempt({
492
+ attemptId: requiredString(operation, 'attemptId'),
493
+ leaseId: requiredString(operation, 'leaseId'),
494
+ releasedAt: optionalString(operation, 'releasedAt') ?? operation.createdAt,
495
+ status: optionalString(operation, 'status'),
496
+ reasonCode: optionalString(operation, 'reasonCode'),
497
+ notBeforeAt: optionalString(operation, 'notBeforeAt'),
498
+ retryCount: optionalNumber(operation, 'retryCount'),
499
+ });
500
+ return;
501
+ case 'complete_execution_attempt':
502
+ this.applyCompleteExecutionAttempt(operation);
503
+ return;
504
+ case 'append_execution_receipt':
505
+ this.applyAppendExecutionReceipt(operation);
506
+ return;
507
+ case 'append_execution_summary':
508
+ this.applyAppendExecutionSummary(operation);
509
+ return;
510
+ default:
511
+ throw new ContinuityClientStateStoreError(`Unknown continuity operation ${operation.type}.`, [CONTINUITY_CLIENT_REASON_CODES.UNKNOWN_OPERATION_REQUIRED], { mutationBlocked: true });
512
+ }
513
+ }
514
+ applyCompactContext(operation) {
515
+ const summaryHash = normalizeCompactionHash(requiredString(operation, 'summaryHash'), 'compact_context.summaryHash');
516
+ const retainedRefs = normalizeCompactionPaths(operation.retainedRefs, 'compact_context.retainedRefs', COMPACTION_RETAINED_REF_LIMIT);
517
+ const summary = normalizeCompactionSummary(optionalString(operation, 'publicSummary')
518
+ ?? `Context compacted with ${retainedRefs.length} retained public refs.`);
519
+ const artifactRefs = normalizeCompactionArtifactRefs(operation);
520
+ const evidenceRefs = normalizeCompactionEvidenceRefs(operation);
521
+ const decisionLogRefs = normalizeCompactionPaths(operation.decisionLogRefs, 'compact_context.decisionLogRefs', COMPACTION_DECISION_LOG_REF_LIMIT);
522
+ const checkpoint = normalizeCompactionCheckpoint(operation, retainedRefs, artifactRefs, evidenceRefs);
523
+ const relativePaths = unique([
524
+ ...retainedRefs,
525
+ ...decisionLogRefs,
526
+ ...artifactRefs.map((ref) => ref.relativePath),
527
+ ...evidenceRefs.map((ref) => ref.relativePath),
528
+ ]).slice(0, COMPACTION_RELATIVE_PATH_LIMIT);
529
+ const computedSummaryHash = sha256Hex(summary);
530
+ const reasonCode = optionalString(operation, 'reasonCode') ?? 'context-compacted';
531
+ const metadata = {
532
+ schemaVersion: CONTINUITY_CLIENT_SCHEMA_VERSION,
533
+ contractVersion: CONTINUITY_CLIENT_CONTRACT_VERSION,
534
+ jobId: operation.jobId,
535
+ operationId: operation.operationId,
536
+ reasonCode,
537
+ publicSummary: summary,
538
+ counts: {
539
+ retainedRefs: retainedRefs.length,
540
+ artifactRefs: artifactRefs.length,
541
+ evidenceRefs: evidenceRefs.length,
542
+ decisionLogRefs: decisionLogRefs.length,
543
+ ...(optionalNumber(operation, 'inputTokens') !== undefined ? { inputContextUnits: optionalNumber(operation, 'inputTokens') } : {}),
544
+ ...(optionalNumber(operation, 'outputTokens') !== undefined ? { outputContextUnits: optionalNumber(operation, 'outputTokens') } : {}),
545
+ summaryChars: summary.length,
546
+ },
547
+ hashes: {
548
+ summary: summaryHash,
549
+ persistedSummary: computedSummaryHash,
550
+ },
551
+ relativePaths,
552
+ artifactRefs,
553
+ evidenceRefs,
554
+ validationRefs: decisionLogRefs,
555
+ redactionEvidence: operation.redactions ?? [],
556
+ checkpoint,
557
+ };
558
+ for (const [index, artifact] of artifactRefs.entries()) {
559
+ this.store.recordArtifact({
560
+ artifactId: `artifact-${safeId(operation.operationId)}-${index + 1}`,
561
+ jobId: operation.jobId,
562
+ kind: artifact.kind,
563
+ relativePath: artifact.relativePath,
564
+ sha256: artifact.sha256,
565
+ summary: artifact.publicSummary,
566
+ createdAt: operation.createdAt,
567
+ operationId: `${operation.operationId}:artifact:${index + 1}`,
568
+ idempotencyKey: operation.idempotencyKey ? `${operation.idempotencyKey}:artifact:${index + 1}` : undefined,
569
+ metadata: {
570
+ schemaVersion: CONTINUITY_CLIENT_SCHEMA_VERSION,
571
+ contractVersion: CONTINUITY_CLIENT_CONTRACT_VERSION,
572
+ jobId: operation.jobId,
573
+ operationId: operation.operationId,
574
+ reasonCode,
575
+ hashes: artifact.sha256 ? { artifact: artifact.sha256 } : {},
576
+ relativePaths: [artifact.relativePath],
577
+ publicSummary: artifact.publicSummary,
578
+ },
579
+ });
580
+ }
581
+ this.store.recordStateSnapshot({
582
+ snapshotId: `snapshot-${safeId(operation.operationId)}`,
583
+ jobId: operation.jobId,
584
+ kind: 'context_compaction',
585
+ relativePath: artifactRefs.find((ref) => ref.kind === 'context_summary')?.relativePath,
586
+ sha256: summaryHash,
587
+ summary,
588
+ capturedAt: operation.createdAt,
589
+ operationId: operation.operationId,
590
+ idempotencyKey: operation.idempotencyKey,
591
+ metadata,
592
+ });
593
+ this.store.appendEvent({
594
+ eventId: `event-${safeId(operation.operationId)}-context-compacted`,
595
+ jobId: operation.jobId,
596
+ operationId: `${operation.operationId}:event`,
597
+ idempotencyKey: operation.idempotencyKey ? `${operation.idempotencyKey}:event` : undefined,
598
+ sequence: operation.sequence,
599
+ type: 'context_compacted',
600
+ summary: `Context compaction checkpoint ${checkpoint.checkpointId} persisted with ${relativePaths.length} public refs.`,
601
+ reasonCode,
602
+ createdAt: operation.createdAt,
603
+ metadata: {
604
+ schemaVersion: CONTINUITY_CLIENT_SCHEMA_VERSION,
605
+ contractVersion: CONTINUITY_CLIENT_CONTRACT_VERSION,
606
+ jobId: operation.jobId,
607
+ operationId: operation.operationId,
608
+ reasonCode,
609
+ counts: metadata.counts,
610
+ hashes: metadata.hashes,
611
+ relativePaths,
612
+ artifactRefs: artifactRefs.map((ref) => ref.relativePath),
613
+ evidenceRefs,
614
+ publicSummary: summary,
615
+ },
616
+ });
617
+ }
618
+ applyCreateJob(operation, logMetadata) {
619
+ const job = requiredRecord(operation, 'job');
620
+ this.store.recordJob({
621
+ jobId: requiredString(job, 'jobId'),
622
+ kind: requiredString(job, 'kind'),
623
+ status: requiredString(job, 'status'),
624
+ createdAt: requiredString(job, 'createdAt'),
625
+ updatedAt: requiredString(job, 'updatedAt'),
626
+ summary: optionalString(job, 'summary'),
627
+ reasonCode: optionalString(job, 'reasonCode'),
628
+ nextRunAt: optionalString(job, 'nextRunAt'),
629
+ goalId: optionalString(job, 'goalId'),
630
+ loopId: optionalString(job, 'loopId'),
631
+ campaignId: optionalString(job, 'campaignId'),
632
+ operationId: operation.operationId,
633
+ idempotencyKey: operation.idempotencyKey,
634
+ metadata: sanitizeMetadataStrict({
635
+ ...(optionalRecord(job, 'metadata') ?? optionalRecord(operation, 'metadata') ?? { ...logMetadata }),
636
+ ...projectIdentityMetadata(this.projectIdentity),
637
+ }, 'job.metadata'),
638
+ });
639
+ }
640
+ applyUpdateJobStatus(operation) {
641
+ this.store.updateJobStatus({
642
+ jobId: operation.jobId,
643
+ status: requiredString(operation, 'status'),
644
+ updatedAt: operation.createdAt,
645
+ reasonCode: optionalString(operation, 'reasonCode'),
646
+ });
647
+ }
648
+ applyAppendEvent(operation) {
649
+ const event = requiredRecord(operation, 'event');
650
+ const eventType = requiredString(event, 'type');
651
+ if (eventType === CONTINUITY_PROCESSING_OUTPUT_SUMMARY_EVENT_TYPE) {
652
+ this.applyProcessingOutputSummaryEvent(operation, event);
653
+ return;
654
+ }
655
+ this.store.appendEvent({
656
+ eventId: requiredString(event, 'eventId'),
657
+ jobId: requiredString(event, 'jobId'),
658
+ operationId: operation.operationId,
659
+ idempotencyKey: operation.idempotencyKey,
660
+ sequence: operation.sequence,
661
+ type: eventType,
662
+ summary: requiredString(event, 'summary'),
663
+ reasonCode: optionalString(event, 'reasonCode'),
664
+ createdAt: requiredString(event, 'createdAt'),
665
+ metadata: sanitizeMetadataStrict(optionalRecord(event, 'metadata'), 'event.metadata'),
666
+ });
667
+ }
668
+ applyProcessingOutputSummaryEvent(operation, event) {
669
+ const summary = optionalRecord(event, 'processingOutputSummary') ?? event;
670
+ const executionId = optionalString(summary, 'executionId') ?? operation.operationId;
671
+ const jobId = optionalString(summary, 'jobId') ?? optionalString(event, 'jobId') ?? operation.jobId;
672
+ const publicSummary = optionalString(summary, 'publicSummary') ?? requiredString(event, 'summary');
673
+ const createdAt = optionalString(summary, 'createdAt') ?? optionalString(event, 'createdAt') ?? operation.createdAt;
674
+ const summaryMetadata = optionalRecord(summary, 'metadata');
675
+ const eventMetadata = optionalRecord(event, 'metadata');
676
+ this.store.recordProcessingOutputSummary({
677
+ eventId: optionalString(event, 'eventId'),
678
+ executionId,
679
+ jobId,
680
+ idempotencyKey: operation.idempotencyKey,
681
+ goalId: optionalString(summary, 'goalId') ?? optionalString(event, 'goalId'),
682
+ loopId: optionalString(summary, 'loopId') ?? optionalString(event, 'loopId'),
683
+ publicSummary,
684
+ reasonCode: optionalString(summary, 'reasonCode') ?? optionalString(event, 'reasonCode'),
685
+ createdAt,
686
+ source: optionalString(summary, 'source') ?? optionalString(event, 'source'),
687
+ metadata: {
688
+ ...(eventMetadata ?? {}),
689
+ ...(summaryMetadata ?? {}),
690
+ },
691
+ });
692
+ }
693
+ applyAppendReceipt(operation) {
694
+ const receipt = requiredRecord(operation, 'receipt');
695
+ const receiptOperationId = optionalString(receipt, 'operationId') ?? operation.operationId;
696
+ this.store.appendReceipt({
697
+ receiptId: requiredString(receipt, 'receiptId'),
698
+ jobId: requiredString(receipt, 'jobId'),
699
+ operationId: receiptOperationId,
700
+ idempotencyKey: operation.idempotencyKey,
701
+ status: requiredString(receipt, 'status'),
702
+ reasonCode: optionalString(receipt, 'reasonCode'),
703
+ appliedOperationIds: arrayOfStrings(receipt.appliedOperationIds),
704
+ ignoredOperationIds: arrayOfStrings(receipt.ignoredOperationIds),
705
+ createdAt: requiredString(receipt, 'createdAt'),
706
+ metadata: sanitizeMetadataStrict(optionalRecord(receipt, 'metadata'), 'receipt.metadata'),
707
+ });
708
+ }
709
+ applyUpsertGoalCampaign(operation) {
710
+ const campaign = requiredRecord(operation, 'campaign');
711
+ this.store.upsertGoalCampaign({
712
+ campaignId: requiredString(campaign, 'campaignId'),
713
+ jobId: requiredString(campaign, 'jobId'),
714
+ status: requiredString(campaign, 'status'),
715
+ title: optionalString(campaign, 'title'),
716
+ publicSummary: optionalString(campaign, 'publicSummary'),
717
+ reasonCode: optionalString(campaign, 'reasonCode'),
718
+ createdAt: requiredString(campaign, 'createdAt'),
719
+ updatedAt: requiredString(campaign, 'updatedAt'),
720
+ operationId: operation.operationId,
721
+ idempotencyKey: operation.idempotencyKey,
722
+ metadata: sanitizeMetadataStrict(optionalRecord(campaign, 'metadata'), 'campaign.metadata'),
723
+ });
724
+ }
725
+ applyUpsertGoalLedgerItem(operation) {
726
+ const item = requiredRecord(operation, 'item');
727
+ this.store.upsertGoalLedgerItem({
728
+ itemId: requiredString(item, 'itemId'),
729
+ campaignId: requiredString(item, 'campaignId'),
730
+ jobId: requiredString(item, 'jobId'),
731
+ itemType: requiredString(item, 'type'),
732
+ status: requiredString(item, 'status'),
733
+ summary: requiredString(item, 'publicSummary'),
734
+ reasonCode: optionalString(item, 'reasonCode'),
735
+ createdAt: operation.createdAt,
736
+ updatedAt: requiredString(item, 'updatedAt'),
737
+ operationId: operation.operationId,
738
+ idempotencyKey: operation.idempotencyKey,
739
+ metadata: sanitizeMetadataStrict(optionalRecord(item, 'metadata'), 'item.metadata'),
740
+ });
741
+ }
742
+ applyUpsertVerifier(operation) {
743
+ const verifier = requiredRecord(operation, 'verifier');
744
+ this.store.upsertGoalVerifier({
745
+ verifierId: requiredString(verifier, 'verifierId'),
746
+ campaignId: requiredString(verifier, 'campaignId'),
747
+ jobId: requiredString(verifier, 'jobId'),
748
+ kind: requiredString(verifier, 'kind'),
749
+ status: requiredString(verifier, 'status'),
750
+ summary: optionalString(verifier, 'publicSummary'),
751
+ reasonCode: optionalString(verifier, 'reasonCode'),
752
+ lastCheckedAt: optionalString(verifier, 'lastCheckedAt'),
753
+ operationId: operation.operationId,
754
+ idempotencyKey: operation.idempotencyKey,
755
+ metadata: sanitizeMetadataStrict(optionalRecord(verifier, 'metadata'), 'verifier.metadata'),
756
+ });
757
+ }
758
+ applyUpsertReviewGate(operation) {
759
+ const reviewGate = requiredRecord(operation, 'reviewGate');
760
+ this.store.upsertGoalReviewGate({
761
+ gateId: requiredString(reviewGate, 'gateId'),
762
+ campaignId: requiredString(reviewGate, 'campaignId'),
763
+ jobId: requiredString(reviewGate, 'jobId'),
764
+ status: requiredString(reviewGate, 'status'),
765
+ summary: optionalString(reviewGate, 'publicSummary'),
766
+ required: optionalBoolean(reviewGate, 'required') ?? true,
767
+ reasonCode: optionalString(reviewGate, 'reasonCode'),
768
+ operationId: operation.operationId,
769
+ idempotencyKey: operation.idempotencyKey,
770
+ metadata: sanitizeMetadataStrict(optionalRecord(reviewGate, 'metadata'), 'reviewGate.metadata'),
771
+ });
772
+ }
773
+ applyOutbox(operation) {
774
+ const outbox = optionalRecord(operation, 'outbox') ?? operation;
775
+ this.store.enqueueOutbox({
776
+ outboxId: optionalString(outbox, 'outboxId') ?? `outbox-${safeId(operation.operationId)}`,
777
+ jobId: optionalString(outbox, 'jobId') ?? operation.jobId,
778
+ operationId: operation.operationId,
779
+ idempotencyKey: operation.idempotencyKey,
780
+ type: optionalString(outbox, 'type') === operation.type ? 'continuity_event' : requiredString(outbox, 'type'),
781
+ status: optionalString(outbox, 'status'),
782
+ payload: sanitizeMetadataStrict(optionalRecord(outbox, 'payload') ?? optionalRecord(operation, 'metadata') ?? {}, 'outbox.payload'),
783
+ retryCount: optionalNumber(outbox, 'retryCount'),
784
+ nextAttemptAt: optionalString(outbox, 'nextAttemptAt'),
785
+ lastErrorCode: optionalString(outbox, 'lastErrorCode'),
786
+ createdAt: optionalString(outbox, 'createdAt') ?? operation.createdAt,
787
+ updatedAt: optionalString(outbox, 'updatedAt') ?? operation.createdAt,
788
+ });
789
+ }
790
+ applyEnqueueExecutionAttempt(operation) {
791
+ const attempt = optionalRecord(operation, 'attempt') ?? operation;
792
+ const metadata = sanitizeMetadataStrict(optionalRecord(attempt, 'metadata') ?? optionalRecord(operation, 'metadata'), 'executionAttempt.metadata');
793
+ this.store.enqueueHeadlessExecutionAttempt({
794
+ attemptId: requiredString(attempt, 'attemptId'),
795
+ executionId: requiredString(attempt, 'executionId'),
796
+ jobId: optionalString(attempt, 'jobId') ?? operation.jobId,
797
+ directiveHash: requiredString(attempt, 'directiveHash'),
798
+ directiveKind: requiredString(attempt, 'directiveKind'),
799
+ commandClass: requiredString(attempt, 'commandClass'),
800
+ targetKind: requiredString(attempt, 'targetKind'),
801
+ targetRef: requiredString(attempt, 'targetRef'),
802
+ storyId: optionalString(attempt, 'storyId'),
803
+ epicId: optionalString(attempt, 'epicId'),
804
+ runtimeId: optionalString(attempt, 'runtimeId'),
805
+ modelId: optionalString(attempt, 'modelId'),
806
+ runtimeSource: optionalString(attempt, 'runtimeSource'),
807
+ status: optionalString(attempt, 'status'),
808
+ reasonCode: optionalString(attempt, 'reasonCode'),
809
+ publicSummary: optionalString(attempt, 'publicSummary'),
810
+ enqueuedAt: optionalString(attempt, 'enqueuedAt') ?? operation.createdAt,
811
+ notBeforeAt: optionalString(attempt, 'notBeforeAt'),
812
+ retryCount: optionalNumber(attempt, 'retryCount'),
813
+ maxAttempts: optionalNumber(attempt, 'maxAttempts'),
814
+ operationId: operation.operationId,
815
+ idempotencyKey: operation.idempotencyKey,
816
+ counts: optionalRecord(attempt, 'counts'),
817
+ hashes: optionalRecord(attempt, 'hashes'),
818
+ redactionSummary: Array.isArray(attempt.redactionSummary) ? attempt.redactionSummary : undefined,
819
+ relativePaths: arrayOfStrings(attempt.relativePaths),
820
+ metadata,
821
+ });
822
+ }
823
+ applyCompleteExecutionAttempt(operation) {
824
+ const completion = optionalRecord(operation, 'completion') ?? operation;
825
+ this.store.completeHeadlessExecutionAttempt({
826
+ attemptId: requiredString(completion, 'attemptId'),
827
+ executionId: optionalString(completion, 'executionId'),
828
+ jobId: optionalString(completion, 'jobId') ?? operation.jobId,
829
+ leaseId: optionalString(completion, 'leaseId'),
830
+ runnerId: optionalString(completion, 'runnerId'),
831
+ status: requiredString(completion, 'status'),
832
+ completedAt: optionalString(completion, 'completedAt') ?? operation.createdAt,
833
+ durationMs: optionalNumber(completion, 'durationMs'),
834
+ reasonCode: optionalString(completion, 'reasonCode'),
835
+ publicSummary: optionalString(completion, 'publicSummary'),
836
+ notBeforeAt: optionalString(completion, 'notBeforeAt'),
837
+ retryCount: optionalNumber(completion, 'retryCount'),
838
+ counts: optionalRecord(completion, 'counts'),
839
+ hashes: optionalRecord(completion, 'hashes'),
840
+ redactionSummary: Array.isArray(completion.redactionSummary) ? completion.redactionSummary : undefined,
841
+ relativePaths: arrayOfStrings(completion.relativePaths),
842
+ metadata: sanitizeMetadataStrict(optionalRecord(completion, 'metadata'), 'executionCompletion.metadata'),
843
+ });
844
+ }
845
+ applyAppendExecutionReceipt(operation) {
846
+ const receipt = requiredRecord(operation, 'receipt');
847
+ this.store.recordHeadlessExecutionReceipt({
848
+ receiptId: requiredString(receipt, 'receiptId'),
849
+ attemptId: requiredString(receipt, 'attemptId'),
850
+ executionId: requiredString(receipt, 'executionId'),
851
+ jobId: optionalString(receipt, 'jobId') ?? operation.jobId,
852
+ status: requiredString(receipt, 'status'),
853
+ reasonCode: optionalString(receipt, 'reasonCode'),
854
+ createdAt: optionalString(receipt, 'createdAt') ?? operation.createdAt,
855
+ operationId: operation.operationId,
856
+ idempotencyKey: operation.idempotencyKey,
857
+ counts: optionalRecord(receipt, 'counts'),
858
+ hashes: optionalRecord(receipt, 'hashes'),
859
+ redactionSummary: Array.isArray(receipt.redactionSummary) ? receipt.redactionSummary : undefined,
860
+ relativePaths: arrayOfStrings(receipt.relativePaths),
861
+ metadata: sanitizeMetadataStrict(optionalRecord(receipt, 'metadata'), 'executionReceipt.metadata'),
862
+ });
863
+ }
864
+ applyAppendExecutionSummary(operation) {
865
+ const summary = optionalRecord(operation, 'summary') ?? operation;
866
+ this.store.recordHeadlessExecutionSummary({
867
+ eventId: optionalString(summary, 'eventId'),
868
+ attemptId: requiredString(summary, 'attemptId'),
869
+ executionId: requiredString(summary, 'executionId'),
870
+ jobId: optionalString(summary, 'jobId') ?? operation.jobId,
871
+ publicSummary: requiredString(summary, 'publicSummary'),
872
+ reasonCode: optionalString(summary, 'reasonCode'),
873
+ createdAt: optionalString(summary, 'createdAt') ?? operation.createdAt,
874
+ runtimeId: optionalString(summary, 'runtimeId'),
875
+ modelId: optionalString(summary, 'modelId'),
876
+ durationMs: optionalNumber(summary, 'durationMs'),
877
+ counts: optionalRecord(summary, 'counts'),
878
+ hashes: optionalRecord(summary, 'hashes'),
879
+ redactionSummary: Array.isArray(summary.redactionSummary) ? summary.redactionSummary : undefined,
880
+ relativePaths: arrayOfStrings(summary.relativePaths),
881
+ metadata: sanitizeMetadataStrict(optionalRecord(summary, 'metadata'), 'executionSummary.metadata'),
882
+ });
883
+ }
884
+ recordAppliedAudit(operation) {
885
+ this.store.recordOperationAudit({
886
+ receiptId: `receipt-${safeId(operation.operationId)}`,
887
+ jobId: operation.jobId,
888
+ operationId: operation.operationId,
889
+ idempotencyKey: `audit-${operation.idempotencyKey ?? operation.operationId}`,
890
+ status: 'applied',
891
+ reasonCode: CONTINUITY_CLIENT_REASON_CODES.OK,
892
+ appliedOperationIds: [operation.operationId],
893
+ createdAt: operation.createdAt,
894
+ metadata: {
895
+ schemaVersion: CONTINUITY_CLIENT_SCHEMA_VERSION,
896
+ contractVersion: CONTINUITY_CLIENT_CONTRACT_VERSION,
897
+ jobId: operation.jobId,
898
+ operationId: operation.operationId,
899
+ status: 'applied',
900
+ reasonCode: CONTINUITY_CLIENT_REASON_CODES.OK,
901
+ },
902
+ });
903
+ }
904
+ recordIgnoredAuditIfPossible(operation, reasonCode) {
905
+ if (!this.store.jobExists(operation.jobId))
906
+ return;
907
+ this.store.recordOperationAudit({
908
+ receiptId: `receipt-${safeId(operation.operationId)}-ignored`,
909
+ jobId: operation.jobId,
910
+ operationId: operation.operationId,
911
+ idempotencyKey: `audit-${operation.idempotencyKey ?? operation.operationId}-ignored`,
912
+ status: 'ignored',
913
+ reasonCode,
914
+ ignoredOperationIds: [operation.operationId],
915
+ createdAt: operation.createdAt,
916
+ metadata: {
917
+ schemaVersion: CONTINUITY_CLIENT_SCHEMA_VERSION,
918
+ contractVersion: CONTINUITY_CLIENT_CONTRACT_VERSION,
919
+ jobId: operation.jobId,
920
+ operationId: operation.operationId,
921
+ status: 'ignored',
922
+ reasonCode,
923
+ },
924
+ });
925
+ }
926
+ }
927
+ function toSnapshotJobSummary(job) {
928
+ const counts = extractPublicJobCounts(job.metadata_json, job.iteration);
929
+ const rawMetadata = parsePublicMetadata(job.metadata_json);
930
+ const metadata = normalizeSnapshotRecord(rawMetadata);
931
+ // P195.04: read the additive stage projection from the raw metadata so a bounded
932
+ // `stageHistory` array survives the 20-key snapshot normalization; values are
933
+ // re-validated against the public stage allow-list and re-bounded here.
934
+ const currentStage = isContinuityPublicStage(rawMetadata.currentStage) ? rawMetadata.currentStage : undefined;
935
+ const stageHistory = sanitizeContinuityStageHistory(rawMetadata.stageHistory);
936
+ const iteration = normalizeContinuityStageIteration(rawMetadata.iteration)
937
+ ?? normalizeContinuityStageIteration(job.iteration);
938
+ addFiniteCount(counts, 'goalLedgerItems', 'goal_ledger_item_count' in job ? job.goal_ledger_item_count : undefined);
939
+ addFiniteCount(counts, 'blockedGoalLedgerItems', 'blocked_goal_ledger_item_count' in job ? job.blocked_goal_ledger_item_count : undefined);
940
+ addFiniteCount(counts, 'securityIssuesBlocked', 'security_issue_blocked_count' in job ? job.security_issue_blocked_count : undefined);
941
+ addFiniteCount(counts, 'goalVerifiers', 'goal_verifier_count' in job ? job.goal_verifier_count : undefined);
942
+ addFiniteCount(counts, 'failedVerifiers', 'failed_verifier_count' in job ? job.failed_verifier_count : undefined);
943
+ addFiniteCount(counts, 'unavailableVerifiers', 'unavailable_verifier_count' in job ? job.unavailable_verifier_count : undefined);
944
+ addFiniteCount(counts, 'goalReviewGates', 'goal_review_gate_count' in job ? job.goal_review_gate_count : undefined);
945
+ addFiniteCount(counts, 'failedRequiredReviewGates', 'failed_required_review_gate_count' in job ? job.failed_required_review_gate_count : undefined);
946
+ return {
947
+ jobId: boundPublicText(job.job_id, 80),
948
+ kind: boundPublicText(job.kind, 40),
949
+ status: boundPublicText(job.status, 40),
950
+ publicSummary: boundPublicText(job.summary ?? 'No public summary recorded.', PUBLIC_TEXT_MAX_CHARS),
951
+ createdAt: boundPublicText(job.created_at, 80),
952
+ updatedAt: boundPublicText(job.updated_at, 80),
953
+ ...(job.next_run_at ? { nextRunAt: boundPublicText(job.next_run_at, 80) } : {}),
954
+ ...(job.reason_code ? { reasonCode: boundPublicText(job.reason_code, 80) } : {}),
955
+ ...(Object.keys(counts).length > 0 ? { counts } : {}),
956
+ ...(currentStage ? { currentStage } : {}),
957
+ ...(stageHistory.length > 0 ? { stageHistory } : {}),
958
+ ...(iteration !== undefined ? { iteration } : {}),
959
+ ...extractHeadlessJobMetadata(metadata),
960
+ publicSafe: true,
961
+ };
962
+ }
963
+ function toPortalSyncSnapshotSummary(input) {
964
+ const counts = {
965
+ jobs: input.counts.jobs ?? input.jobCount,
966
+ dueJobs: input.counts.dueJobs ?? input.dueJobCount,
967
+ outboxPending: input.outboxPending,
968
+ redactions: input.redactions.length,
969
+ };
970
+ const hashInput = stableStringify({ generatedAt: input.generatedAt, counts });
971
+ return {
972
+ syncVersion: CONTINUITY_CLIENT_PORTAL_SYNC_ENVELOPE_VERSION,
973
+ transportKind: 'client_snapshot',
974
+ snapshotId: `snapshot-${safeId(sha256Hex(hashInput).replace(/^sha256:/, '').slice(0, 16))}`,
975
+ generatedAt: boundPublicText(input.generatedAt, 80),
976
+ publicSummary: `Client snapshot contains ${counts.jobs} public jobs and ${counts.outboxPending} pending outbox records.`,
977
+ counts,
978
+ hashes: { snapshot: sha256Hex(hashInput) },
979
+ redactionEvidence: input.redactions.slice(0, 20),
980
+ publicSafe: true,
981
+ };
982
+ }
983
+ function extractHeadlessJobMetadata(metadata) {
984
+ const runtimeSource = metadata.runtimeSource === 'explicit'
985
+ || metadata.runtimeSource === 'origin'
986
+ || metadata.runtimeSource === 'default'
987
+ || metadata.runtimeSource === 'fallback'
988
+ || metadata.runtimeSource === 'unspecified'
989
+ ? metadata.runtimeSource
990
+ : undefined;
991
+ return {
992
+ ...safeMetadataString(metadata, 'runtimeId', 80),
993
+ ...safeMetadataString(metadata, 'modelId', 120),
994
+ ...(runtimeSource ? { runtimeSource } : {}),
995
+ ...safeMetadataString(metadata, 'headlessRuntime', 80),
996
+ ...safeMetadataString(metadata, 'headlessModel', 120),
997
+ ...safeMetadataString(metadata, 'headlessRuntimeReasonCode', 100),
998
+ ...safeMetadataString(metadata, 'originRuntime', 80),
999
+ ...safeMetadataString(metadata, 'originModel', 120),
1000
+ ...safeMetadataString(metadata, 'workspaceId', 120),
1001
+ ...safeMetadataString(metadata, 'workspaceLabel', 80),
1002
+ ...safeMetadataString(metadata, 'projectId', 120),
1003
+ ...safeMetadataString(metadata, 'projectLabel', 80),
1004
+ };
1005
+ }
1006
+ function projectIdentityMetadata(identity) {
1007
+ return identity
1008
+ ? {
1009
+ workspaceId: identity.workspaceId,
1010
+ workspaceLabel: identity.workspaceLabel,
1011
+ projectId: identity.projectId,
1012
+ projectLabel: identity.projectLabel,
1013
+ }
1014
+ : {};
1015
+ }
1016
+ function safeMetadataString(metadata, key, maxChars) {
1017
+ const value = metadata[key];
1018
+ return typeof value === 'string'
1019
+ ? { [key]: boundPublicText(value, maxChars) }
1020
+ : {};
1021
+ }
1022
+ function toProcessingSummaryRef(row) {
1023
+ const metadata = normalizeSnapshotRecord(parsePublicMetadata(row.metadata_json));
1024
+ const goalId = typeof metadata.goalId === 'string' ? boundPublicText(metadata.goalId, 100) : undefined;
1025
+ const loopId = typeof metadata.loopId === 'string' ? boundPublicText(metadata.loopId, 100) : undefined;
1026
+ return {
1027
+ eventId: boundPublicText(row.event_id, 120),
1028
+ jobId: boundPublicText(row.job_id, 100),
1029
+ ...(goalId ? { goalId } : {}),
1030
+ ...(loopId ? { loopId } : {}),
1031
+ executionId: boundPublicText(row.execution_id, 120),
1032
+ publicSummary: boundPublicText(row.public_summary, PUBLIC_TEXT_MAX_CHARS),
1033
+ ...(row.reason_code ? { reasonCode: boundPublicText(row.reason_code, 80) } : {}),
1034
+ createdAt: boundPublicText(row.created_at, 80),
1035
+ cursor: boundPublicText(row.cursor, 260),
1036
+ ...(Object.keys(metadata).length > 0 ? { metadata } : {}),
1037
+ publicSafe: true,
1038
+ };
1039
+ }
1040
+ function toHeadlessExecutionAttemptRef(row) {
1041
+ return {
1042
+ attemptId: boundPublicText(row.attempt_id, 120),
1043
+ executionId: boundPublicText(row.execution_id, 120),
1044
+ jobId: boundPublicText(row.job_id, 100),
1045
+ status: boundPublicText(row.status, 40),
1046
+ ...(row.reason_code ? { reasonCode: boundPublicText(row.reason_code, 80) } : {}),
1047
+ ...(row.runtime_id ? { runtimeId: boundPublicText(row.runtime_id, 80) } : {}),
1048
+ ...(row.model_id ? { modelId: boundPublicText(row.model_id, 120) } : {}),
1049
+ retryCount: Math.max(0, Math.floor(row.retry_count)),
1050
+ attemptCount: Math.max(0, Math.floor(row.attempt_count)),
1051
+ maxAttempts: Math.max(1, Math.floor(row.max_attempts)),
1052
+ queuePriority: Math.max(-100, Math.min(100, Math.floor(row.queue_priority))),
1053
+ queueScope: row.queue_scope === 'workspace' ? 'workspace' : 'project',
1054
+ ...(typeof row.duration_ms === 'number' && Number.isFinite(row.duration_ms) ? { durationMs: Math.max(0, Math.floor(row.duration_ms)) } : {}),
1055
+ ...optionalPublicRecord('counts', parsePublicMetadata(row.counts_json)),
1056
+ ...optionalPublicRecord('hashes', parsePublicMetadata(row.hashes_json)),
1057
+ ...optionalPublicArray('redactionSummary', row.redaction_summary_json),
1058
+ ...(row.lease_id ? { leaseId: boundPublicText(row.lease_id, 120) } : {}),
1059
+ ...(row.runner_id ? { runnerId: boundPublicText(row.runner_id, 120) } : {}),
1060
+ ...(row.lease_expires_at ? { leaseExpiresAt: boundPublicText(row.lease_expires_at, 80) } : {}),
1061
+ ...(row.heartbeat_at ? { heartbeatAt: boundPublicText(row.heartbeat_at, 80) } : {}),
1062
+ publicSummary: boundPublicText(row.public_summary ?? 'No public headless execution summary recorded.', PUBLIC_TEXT_MAX_CHARS),
1063
+ enqueuedAt: boundPublicText(row.enqueued_at, 80),
1064
+ ...(row.not_before_at ? { notBeforeAt: boundPublicText(row.not_before_at, 80) } : {}),
1065
+ ...(row.next_retry_at ? { nextRetryAt: boundPublicText(row.next_retry_at, 80) } : {}),
1066
+ ...(row.dead_lettered_at ? { deadLetteredAt: boundPublicText(row.dead_lettered_at, 80) } : {}),
1067
+ ...(row.dead_letter_reason_code ? { deadLetterReasonCode: boundPublicText(row.dead_letter_reason_code, 80) } : {}),
1068
+ publicSafe: true,
1069
+ };
1070
+ }
1071
+ function addFiniteCount(counts, key, value) {
1072
+ if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
1073
+ counts[key] = Math.floor(value);
1074
+ }
1075
+ }
1076
+ function extractPublicJobCounts(metadataJson, iteration) {
1077
+ const counts = {};
1078
+ if (metadataJson) {
1079
+ try {
1080
+ const parsed = JSON.parse(metadataJson);
1081
+ const metadataCounts = isRecord(parsed) && isRecord(parsed.counts) ? parsed.counts : undefined;
1082
+ if (metadataCounts) {
1083
+ for (const [key, value] of Object.entries(metadataCounts)) {
1084
+ if (typeof value === 'number' && Number.isFinite(value))
1085
+ counts[key] = Math.max(0, Math.floor(value));
1086
+ }
1087
+ }
1088
+ }
1089
+ catch {
1090
+ // Corrupt metadata JSON is already guarded by SQLite json_valid; ignore any
1091
+ // unexpected parse failure so snapshots remain bounded and public-safe.
1092
+ }
1093
+ }
1094
+ if (typeof iteration === 'number' && Number.isFinite(iteration))
1095
+ counts.iteration = Math.max(0, Math.floor(iteration));
1096
+ return counts;
1097
+ }
1098
+ function toCompactContextSnapshot(rows) {
1099
+ const summaries = rows.map(toCompactContextRef).filter((item) => Boolean(item));
1100
+ return {
1101
+ preferredSource: summaries.length > 0 ? 'compact_summary' : 'recent_events',
1102
+ summaries,
1103
+ publicSafe: true,
1104
+ };
1105
+ }
1106
+ function toCompactContextRef(row) {
1107
+ const metadata = parsePublicMetadata(row.metadata_json);
1108
+ const hashes = isRecord(metadata.hashes) ? metadata.hashes : {};
1109
+ const summaryHash = typeof hashes.summary === 'string' ? hashes.summary : row.sha256 ?? undefined;
1110
+ const reasonCode = typeof metadata.reasonCode === 'string' ? boundPublicText(metadata.reasonCode, 80) : undefined;
1111
+ return {
1112
+ snapshotId: boundPublicText(row.snapshot_id, 120),
1113
+ ...(row.job_id ? { jobId: boundPublicText(row.job_id, 100) } : {}),
1114
+ ...(row.operation_id ? { operationId: boundPublicText(row.operation_id, 120) } : {}),
1115
+ capturedAt: boundPublicText(row.captured_at, 80),
1116
+ publicSummary: boundPublicText(row.summary ?? 'Context compacted with public-safe refs.', COMPACTION_SUMMARY_MAX_CHARS),
1117
+ ...(summaryHash ? { summaryHash: boundPublicText(summaryHash, 120) } : {}),
1118
+ ...(row.relative_path ? { relativePath: boundPublicText(row.relative_path, 240) } : {}),
1119
+ retainedRefs: normalizeSnapshotRefArray(metadata.relativePaths),
1120
+ artifactRefs: normalizeSnapshotUnknownArray(metadata.artifactRefs),
1121
+ evidenceRefs: normalizeSnapshotUnknownArray(metadata.evidenceRefs),
1122
+ ...(isRecord(metadata.checkpoint) ? { checkpoint: normalizeSnapshotRecord(metadata.checkpoint) } : {}),
1123
+ ...(reasonCode ? { reasonCode } : {}),
1124
+ publicSafe: true,
1125
+ };
1126
+ }
1127
+ function parsePublicMetadata(metadataJson) {
1128
+ if (!metadataJson)
1129
+ return {};
1130
+ try {
1131
+ const parsed = JSON.parse(metadataJson);
1132
+ return isRecord(parsed) ? parsed : {};
1133
+ }
1134
+ catch {
1135
+ return {};
1136
+ }
1137
+ }
1138
+ function optionalPublicRecord(key, value) {
1139
+ const normalized = normalizeSnapshotRecord(value);
1140
+ return Object.keys(normalized).length > 0 ? { [key]: normalized } : {};
1141
+ }
1142
+ function optionalPublicArray(key, json) {
1143
+ if (!json)
1144
+ return {};
1145
+ try {
1146
+ const parsed = JSON.parse(json);
1147
+ const normalized = normalizeSnapshotUnknownArray(parsed);
1148
+ return normalized.length > 0 ? { [key]: normalized } : {};
1149
+ }
1150
+ catch {
1151
+ return {};
1152
+ }
1153
+ }
1154
+ function normalizeSnapshotRefArray(value) {
1155
+ return Array.isArray(value)
1156
+ ? value.filter((item) => typeof item === 'string' && item.length > 0).map((item) => boundPublicText(item, 240)).slice(0, COMPACTION_RELATIVE_PATH_LIMIT)
1157
+ : [];
1158
+ }
1159
+ function normalizeSnapshotUnknownArray(value) {
1160
+ if (!Array.isArray(value))
1161
+ return [];
1162
+ return value.map(normalizeSnapshotValue).filter((item) => item !== undefined).slice(0, COMPACTION_RELATIVE_PATH_LIMIT);
1163
+ }
1164
+ function normalizeSnapshotRecord(value) {
1165
+ const output = {};
1166
+ for (const [key, child] of Object.entries(value).slice(0, 20)) {
1167
+ if (UNSAFE_METADATA_KEY_PATTERN.test(key))
1168
+ continue;
1169
+ const normalized = normalizeSnapshotValue(child);
1170
+ if (normalized !== undefined)
1171
+ output[boundPublicText(key, 80)] = normalized;
1172
+ }
1173
+ return output;
1174
+ }
1175
+ function normalizeSnapshotValue(value) {
1176
+ const reason = getUnsafeMetadataValueReason(value);
1177
+ if (reason)
1178
+ return undefined;
1179
+ if (typeof value === 'string')
1180
+ return boundPublicText(value, 240);
1181
+ if (typeof value === 'number' && Number.isFinite(value))
1182
+ return Math.floor(value);
1183
+ if (typeof value === 'boolean' || value === null)
1184
+ return value;
1185
+ if (Array.isArray(value))
1186
+ return value.map(normalizeSnapshotValue).filter((item) => item !== undefined).slice(0, 20);
1187
+ if (isRecord(value))
1188
+ return normalizeSnapshotRecord(value);
1189
+ return undefined;
1190
+ }
1191
+ function normalizeStateUpdate(update) {
1192
+ if (!isRecord(update))
1193
+ return [];
1194
+ if (Array.isArray(update.operationLogs))
1195
+ return update.operationLogs.filter(isRecord);
1196
+ if (isRecord(update.operationLog))
1197
+ return [update.operationLog];
1198
+ if (Array.isArray(update.operations))
1199
+ return [update];
1200
+ return [];
1201
+ }
1202
+ function planOperationLog(log) {
1203
+ const reasonCodes = [];
1204
+ const redactions = [];
1205
+ const skippedOperations = [];
1206
+ const ignoredOperationIds = [];
1207
+ const accepted = [];
1208
+ const seen = new Map();
1209
+ if (log.schemaVersion !== CONTINUITY_CLIENT_SCHEMA_VERSION) {
1210
+ throw new ContinuityClientStateStoreError('Invalid continuity operation log schema version.', [CONTINUITY_CLIENT_REASON_CODES.INVALID_SCHEMA_VERSION], { mutationBlocked: true });
1211
+ }
1212
+ if (log.contractVersion !== CONTINUITY_CLIENT_CONTRACT_VERSION) {
1213
+ throw new ContinuityClientStateStoreError('Invalid continuity operation log contract version.', [CONTINUITY_CLIENT_REASON_CODES.INVALID_CONTRACT_VERSION], { mutationBlocked: true });
1214
+ }
1215
+ if (log.publicSafe !== true) {
1216
+ throw new ContinuityClientStateStoreError('Continuity operation log is not marked public-safe.', [CONTINUITY_CLIENT_REASON_CODES.UNSAFE_FIELD_REJECTED], { mutationBlocked: true });
1217
+ }
1218
+ const logMetadata = sanitizeMetadataStrict(optionalRecord(log, 'metadata'), 'log.metadata');
1219
+ if (!Array.isArray(log.operations))
1220
+ return { operations: [], skippedOperations, ignoredOperationIds, reasonCodes, redactions, logMetadata };
1221
+ for (const rawOperation of [...log.operations].filter(isRecord).sort(compareOperationOrder)) {
1222
+ const operation = normalizeOperation(rawOperation);
1223
+ const canonical = stableStringify(operation);
1224
+ const duplicatePayload = seen.get(operation.operationId);
1225
+ if (duplicatePayload !== undefined) {
1226
+ if (duplicatePayload === canonical) {
1227
+ ignoredOperationIds.push(operation.operationId);
1228
+ reasonCodes.push(CONTINUITY_CLIENT_REASON_CODES.IDEMPOTENCY_REPLAY);
1229
+ continue;
1230
+ }
1231
+ redactions.push({
1232
+ field: 'operationId',
1233
+ reason: 'unknown_required_operation',
1234
+ evidence: 'operation-denied',
1235
+ publicSafe: true,
1236
+ });
1237
+ throw new ContinuityClientStateStoreError('Duplicate continuity operation ID with conflicting payload.', [CONTINUITY_CLIENT_REASON_CODES.DUPLICATE_OPERATION_ID], { redactions, mutationBlocked: true });
1238
+ }
1239
+ seen.set(operation.operationId, canonical);
1240
+ sanitizeMetadataStrict(operation.metadata, 'operation.metadata');
1241
+ if (!KNOWN_OPERATION_TYPES.has(operation.type)) {
1242
+ const required = rawOperation.required === true;
1243
+ if (rawOperation.forwardCompatible === true && !required) {
1244
+ skippedOperations.push(operation);
1245
+ ignoredOperationIds.push(operation.operationId);
1246
+ reasonCodes.push(CONTINUITY_CLIENT_REASON_CODES.UNKNOWN_OPERATION_IGNORED);
1247
+ continue;
1248
+ }
1249
+ redactions.push({
1250
+ field: operation.type,
1251
+ reason: 'unknown_required_operation',
1252
+ evidence: 'operation-denied',
1253
+ publicSafe: true,
1254
+ });
1255
+ throw new ContinuityClientStateStoreError(`Unknown required continuity operation ${operation.type}.`, [CONTINUITY_CLIENT_REASON_CODES.UNKNOWN_OPERATION_REQUIRED], { redactions, mutationBlocked: true });
1256
+ }
1257
+ accepted.push(operation);
1258
+ }
1259
+ return { operations: accepted, skippedOperations, ignoredOperationIds, reasonCodes, redactions, logMetadata };
1260
+ }
1261
+ function normalizeOperation(raw) {
1262
+ if (raw.schemaVersion !== CONTINUITY_CLIENT_SCHEMA_VERSION) {
1263
+ throw new ContinuityClientStateStoreError('Invalid continuity operation schema version.', [CONTINUITY_CLIENT_REASON_CODES.INVALID_SCHEMA_VERSION], { mutationBlocked: true });
1264
+ }
1265
+ if (raw.contractVersion !== CONTINUITY_CLIENT_CONTRACT_VERSION) {
1266
+ throw new ContinuityClientStateStoreError('Invalid continuity operation contract version.', [CONTINUITY_CLIENT_REASON_CODES.INVALID_CONTRACT_VERSION], { mutationBlocked: true });
1267
+ }
1268
+ if (raw.publicSafe !== true) {
1269
+ throw new ContinuityClientStateStoreError('Continuity operation is not marked public-safe.', [CONTINUITY_CLIENT_REASON_CODES.UNSAFE_FIELD_REJECTED], { mutationBlocked: true });
1270
+ }
1271
+ const type = requiredString(raw, 'type');
1272
+ const operationId = requiredString(raw, 'operationId');
1273
+ const jobId = requiredString(raw, 'jobId');
1274
+ const sequence = requiredNumber(raw, 'sequence');
1275
+ const createdAt = requiredString(raw, 'createdAt');
1276
+ return {
1277
+ ...raw,
1278
+ type,
1279
+ operationId,
1280
+ jobId,
1281
+ schemaVersion: CONTINUITY_CLIENT_SCHEMA_VERSION,
1282
+ contractVersion: CONTINUITY_CLIENT_CONTRACT_VERSION,
1283
+ sequence,
1284
+ createdAt,
1285
+ idempotencyKey: optionalString(raw, 'idempotencyKey'),
1286
+ metadata: optionalRecord(raw, 'metadata'),
1287
+ publicSafe: true,
1288
+ };
1289
+ }
1290
+ function sanitizeMetadataStrict(input, path) {
1291
+ if (!input)
1292
+ return {};
1293
+ const metadata = {};
1294
+ const redactions = [];
1295
+ for (const [key, value] of Object.entries(input)) {
1296
+ const keyReason = getUnsafeMetadataKeyReason(key);
1297
+ const valueReason = getUnsafeMetadataValueReason(value);
1298
+ const reason = keyReason ?? valueReason;
1299
+ if (reason) {
1300
+ redactions.push({
1301
+ field: `${path}.${key}`,
1302
+ reason,
1303
+ evidence: keyReason ? 'key-denied' : 'value-denied',
1304
+ publicSafe: true,
1305
+ });
1306
+ continue;
1307
+ }
1308
+ metadata[key] = value;
1309
+ }
1310
+ if (redactions.length > 0) {
1311
+ throw new ContinuityClientStateStoreError(`Continuity metadata rejected unsafe public fields at ${path}.`, [CONTINUITY_CLIENT_REASON_CODES.UNSAFE_FIELD_REJECTED], { redactions, mutationBlocked: true });
1312
+ }
1313
+ return metadata;
1314
+ }
1315
+ function getUnsafeMetadataKeyReason(key) {
1316
+ if (!ALLOWED_METADATA_KEYS.has(key) || UNSAFE_METADATA_KEY_PATTERN.test(key))
1317
+ return 'unsafe_key';
1318
+ return null;
1319
+ }
1320
+ function getUnsafeMetadataValueReason(value) {
1321
+ if (typeof value === 'string') {
1322
+ if (ABSOLUTE_URL_VALUE_PATTERN.test(value))
1323
+ return 'private_url';
1324
+ if (LOCAL_ABSOLUTE_PATH_VALUE_PATTERN.test(value))
1325
+ return 'local_absolute_path';
1326
+ if (SECRET_VALUE_PATTERN.test(value))
1327
+ return 'secret';
1328
+ if (PROMPT_VALUE_PATTERN.test(value))
1329
+ return 'prompt_body';
1330
+ if (RAW_LOG_VALUE_PATTERN.test(value))
1331
+ return 'raw_log';
1332
+ if (PROTECTED_VALUE_PATTERN.test(value))
1333
+ return 'protected_field';
1334
+ return null;
1335
+ }
1336
+ if (value === null || typeof value === 'number' || typeof value === 'boolean')
1337
+ return null;
1338
+ if (Array.isArray(value)) {
1339
+ for (const item of value) {
1340
+ const reason = getUnsafeMetadataValueReason(item);
1341
+ if (reason)
1342
+ return reason;
1343
+ }
1344
+ return null;
1345
+ }
1346
+ if (isRecord(value)) {
1347
+ for (const [key, child] of Object.entries(value)) {
1348
+ if (UNSAFE_METADATA_KEY_PATTERN.test(key))
1349
+ return 'unsafe_key';
1350
+ const reason = getUnsafeMetadataValueReason(child);
1351
+ if (reason)
1352
+ return reason;
1353
+ }
1354
+ return null;
1355
+ }
1356
+ return 'unsafe_key';
1357
+ }
1358
+ function collectReceiptRedactions(receipts) {
1359
+ const redactions = [];
1360
+ for (const receipt of receipts) {
1361
+ if (!receipt.metadata_json)
1362
+ continue;
1363
+ try {
1364
+ const metadata = JSON.parse(receipt.metadata_json);
1365
+ const evidence = metadata.redactionEvidence;
1366
+ if (!Array.isArray(evidence))
1367
+ continue;
1368
+ for (const item of evidence) {
1369
+ if (!isRecord(item))
1370
+ continue;
1371
+ if (typeof item.field !== 'string' || typeof item.reason !== 'string' || typeof item.evidence !== 'string')
1372
+ continue;
1373
+ redactions.push({
1374
+ field: boundPublicText(item.field, 120),
1375
+ reason: item.reason,
1376
+ evidence: item.evidence,
1377
+ publicSafe: true,
1378
+ });
1379
+ }
1380
+ }
1381
+ catch {
1382
+ // Ignore malformed metadata; SQLite json_valid already guards new rows.
1383
+ }
1384
+ }
1385
+ return redactions;
1386
+ }
1387
+ function compareOperationOrder(left, right) {
1388
+ const leftSequence = typeof left.sequence === 'number' ? left.sequence : 0;
1389
+ const rightSequence = typeof right.sequence === 'number' ? right.sequence : 0;
1390
+ if (leftSequence !== rightSequence)
1391
+ return leftSequence - rightSequence;
1392
+ const createdAt = String(left.createdAt ?? '').localeCompare(String(right.createdAt ?? ''));
1393
+ if (createdAt !== 0)
1394
+ return createdAt;
1395
+ return String(left.operationId ?? '').localeCompare(String(right.operationId ?? ''));
1396
+ }
1397
+ function isRecord(value) {
1398
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
1399
+ }
1400
+ function requiredRecord(input, key) {
1401
+ const value = input[key];
1402
+ if (!isRecord(value)) {
1403
+ throw new ContinuityClientStateStoreError(`Continuity operation missing object field ${key}.`, [CONTINUITY_CLIENT_REASON_CODES.INVALID_SCHEMA_VERSION], { mutationBlocked: true });
1404
+ }
1405
+ return value;
1406
+ }
1407
+ function optionalRecord(input, key) {
1408
+ const value = input[key];
1409
+ return isRecord(value) ? value : undefined;
1410
+ }
1411
+ function requiredString(input, key) {
1412
+ const value = input[key];
1413
+ if (typeof value !== 'string' || value.length === 0) {
1414
+ throw new ContinuityClientStateStoreError(`Continuity operation missing string field ${key}.`, [CONTINUITY_CLIENT_REASON_CODES.INVALID_SCHEMA_VERSION], { mutationBlocked: true });
1415
+ }
1416
+ return value;
1417
+ }
1418
+ function optionalString(input, key) {
1419
+ const value = input[key];
1420
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
1421
+ }
1422
+ function requiredNumber(input, key) {
1423
+ const value = input[key];
1424
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
1425
+ throw new ContinuityClientStateStoreError(`Continuity operation missing numeric field ${key}.`, [CONTINUITY_CLIENT_REASON_CODES.INVALID_SCHEMA_VERSION], { mutationBlocked: true });
1426
+ }
1427
+ return value;
1428
+ }
1429
+ function optionalNumber(input, key) {
1430
+ const value = input[key];
1431
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
1432
+ }
1433
+ function optionalBoolean(input, key) {
1434
+ const value = input[key];
1435
+ return typeof value === 'boolean' ? value : undefined;
1436
+ }
1437
+ function arrayOfStrings(value) {
1438
+ return Array.isArray(value) ? value.filter((item) => typeof item === 'string' && item.length > 0) : [];
1439
+ }
1440
+ function arrayOfRecords(value) {
1441
+ return Array.isArray(value) ? value.filter(isRecord) : [];
1442
+ }
1443
+ function normalizeCompactionSummary(value) {
1444
+ return normalizeSafePublicText(value, COMPACTION_SUMMARY_MAX_CHARS, 'compact_context.publicSummary');
1445
+ }
1446
+ function normalizeSafePublicText(value, maxChars, path) {
1447
+ const trimmed = value.trim();
1448
+ if (!trimmed) {
1449
+ throw new ContinuityClientStateStoreError(`Continuity compaction missing public text at ${path}.`, [CONTINUITY_CLIENT_REASON_CODES.INVALID_SCHEMA_VERSION], { mutationBlocked: true });
1450
+ }
1451
+ const reason = getUnsafeMetadataValueReason(trimmed);
1452
+ if (reason) {
1453
+ throw new ContinuityClientStateStoreError(`Continuity compaction rejected unsafe public text at ${path}.`, [CONTINUITY_CLIENT_REASON_CODES.UNSAFE_FIELD_REJECTED], { redactions: [{ field: path, reason, evidence: 'value-denied', publicSafe: true }], mutationBlocked: true });
1454
+ }
1455
+ return trimmed.length <= maxChars ? trimmed : `${trimmed.slice(0, maxChars)}…[TRUNCATED:${trimmed.length - maxChars}]`;
1456
+ }
1457
+ function normalizeCompactionHash(value, path) {
1458
+ return normalizeSafePublicText(value, 120, path);
1459
+ }
1460
+ function normalizeCompactionPaths(value, path, limit) {
1461
+ return unique(arrayOfStrings(value).map((item, index) => normalizeRepoRelativeRef(item, `${path}[${index}]`))).slice(0, limit);
1462
+ }
1463
+ function normalizeRepoRelativeRef(value, path) {
1464
+ const normalized = normalizeSafePublicText(value, 240, path).replace(/\\/g, '/');
1465
+ const segments = normalized.split('/').filter(Boolean);
1466
+ const absoluteWindows = /^[A-Za-z]:\//.test(normalized);
1467
+ if (normalized.startsWith('/') ||
1468
+ normalized.startsWith('~') ||
1469
+ normalized.includes('://') ||
1470
+ absoluteWindows ||
1471
+ segments.includes('..')) {
1472
+ throw new ContinuityClientStateStoreError(`Continuity compaction rejected non-relative ref at ${path}.`, [CONTINUITY_CLIENT_REASON_CODES.UNSAFE_FIELD_REJECTED], { redactions: [{ field: path, reason: 'private_url', evidence: 'value-denied', publicSafe: true }], mutationBlocked: true });
1473
+ }
1474
+ return normalized;
1475
+ }
1476
+ function normalizeCompactionArtifactRefs(operation) {
1477
+ const refs = [];
1478
+ const summaryRef = optionalRecord(operation, 'summaryRef');
1479
+ if (summaryRef)
1480
+ refs.push(normalizeCompactionArtifactRef(summaryRef, 'compact_context.summaryRef', 'context_summary'));
1481
+ for (const [index, ref] of arrayOfRecords(operation.artifactRefs).entries()) {
1482
+ refs.push(normalizeCompactionArtifactRef(ref, `compact_context.artifactRefs[${index}]`));
1483
+ }
1484
+ const seen = new Set();
1485
+ return refs.filter((ref) => {
1486
+ const key = `${ref.kind}:${ref.relativePath}`;
1487
+ if (seen.has(key))
1488
+ return false;
1489
+ seen.add(key);
1490
+ return true;
1491
+ }).slice(0, COMPACTION_ARTIFACT_REF_LIMIT);
1492
+ }
1493
+ function normalizeCompactionArtifactRef(input, path, fallbackKind = 'context_summary') {
1494
+ const kind = normalizeSafePublicText(optionalString(input, 'kind') ?? fallbackKind, 60, `${path}.kind`);
1495
+ const relativePath = normalizeRepoRelativeRef(requiredString(input, 'relativePath'), `${path}.relativePath`);
1496
+ const sha = optionalString(input, 'sha256');
1497
+ const publicSummary = optionalString(input, 'publicSummary');
1498
+ return {
1499
+ kind,
1500
+ relativePath,
1501
+ ...(sha ? { sha256: normalizeCompactionHash(sha, `${path}.sha256`) } : {}),
1502
+ ...(publicSummary ? { publicSummary: normalizeSafePublicText(publicSummary, PUBLIC_TEXT_MAX_CHARS, `${path}.publicSummary`) } : {}),
1503
+ publicSafe: true,
1504
+ };
1505
+ }
1506
+ function normalizeCompactionEvidenceRefs(operation) {
1507
+ return arrayOfRecords(operation.evidenceIndex).map((ref, index) => {
1508
+ const path = `compact_context.evidenceIndex[${index}]`;
1509
+ const relativePath = normalizeRepoRelativeRef(requiredString(ref, 'relativePath'), `${path}.relativePath`);
1510
+ const refId = optionalString(ref, 'refId') ?? `evidence-${safeId(relativePath)}`;
1511
+ const reasonCode = optionalString(ref, 'reasonCode') ?? optionalString(operation, 'reasonCode') ?? 'context-compacted';
1512
+ const sha = optionalString(ref, 'sha256');
1513
+ const publicSummary = optionalString(ref, 'publicSummary');
1514
+ return {
1515
+ refId: normalizeSafePublicText(refId, 120, `${path}.refId`),
1516
+ relativePath,
1517
+ reasonCode: normalizeSafePublicText(reasonCode, 80, `${path}.reasonCode`),
1518
+ ...(sha ? { sha256: normalizeCompactionHash(sha, `${path}.sha256`) } : {}),
1519
+ ...(publicSummary ? { publicSummary: normalizeSafePublicText(publicSummary, PUBLIC_TEXT_MAX_CHARS, `${path}.publicSummary`) } : {}),
1520
+ publicSafe: true,
1521
+ };
1522
+ }).slice(0, COMPACTION_EVIDENCE_REF_LIMIT);
1523
+ }
1524
+ function normalizeCompactionCheckpoint(operation, retainedRefs, artifactRefs, evidenceRefs) {
1525
+ const checkpoint = optionalRecord(operation, 'checkpoint') ?? {};
1526
+ const checkpointId = optionalString(checkpoint, 'checkpointId') ?? `checkpoint-${safeId(operation.operationId)}`;
1527
+ const capturedAt = optionalString(checkpoint, 'capturedAt') ?? operation.createdAt;
1528
+ const normalized = {
1529
+ checkpointId: normalizeSafePublicText(checkpointId, 120, 'compact_context.checkpoint.checkpointId'),
1530
+ capturedAt: normalizeSafePublicText(capturedAt, 80, 'compact_context.checkpoint.capturedAt'),
1531
+ retainedRefCount: retainedRefs.length,
1532
+ artifactRefCount: artifactRefs.length,
1533
+ evidenceRefCount: evidenceRefs.length,
1534
+ publicSafe: true,
1535
+ };
1536
+ for (const key of ['eventCursor', 'receiptCursor']) {
1537
+ const value = optionalString(checkpoint, key);
1538
+ if (value)
1539
+ normalized[key] = normalizeSafePublicText(value, 120, `compact_context.checkpoint.${key}`);
1540
+ }
1541
+ for (const key of ['recentEventCount', 'recentReceiptCount']) {
1542
+ const value = optionalNumber(checkpoint, key);
1543
+ if (value !== undefined)
1544
+ normalized[key] = Math.max(0, Math.floor(value));
1545
+ }
1546
+ return normalized;
1547
+ }
1548
+ function sha256Hex(value) {
1549
+ return `sha256:${createHash('sha256').update(value).digest('hex')}`;
1550
+ }
1551
+ function unique(values) {
1552
+ return Array.from(new Set(values));
1553
+ }
1554
+ function safeId(value) {
1555
+ return value.replace(/[^a-z0-9_.:-]+/gi, '-').slice(0, 120);
1556
+ }
1557
+ function boundPublicText(value, maxChars) {
1558
+ const redacted = redactPublicText(value);
1559
+ return redacted.length <= maxChars ? redacted : `${redacted.slice(0, maxChars)}…[TRUNCATED:${redacted.length - maxChars}]`;
1560
+ }
1561
+ function redactPublicText(value) {
1562
+ if (ABSOLUTE_URL_VALUE_PATTERN.test(value) ||
1563
+ SECRET_VALUE_PATTERN.test(value) ||
1564
+ RAW_LOG_VALUE_PATTERN.test(value) ||
1565
+ PROMPT_VALUE_PATTERN.test(value) ||
1566
+ PROTECTED_VALUE_PATTERN.test(value)) {
1567
+ return '[REDACTED]';
1568
+ }
1569
+ return value;
1570
+ }
1571
+ function stableStringify(value) {
1572
+ if (Array.isArray(value))
1573
+ return `[${value.map(stableStringify).join(',')}]`;
1574
+ if (isRecord(value)) {
1575
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`).join(',')}}`;
1576
+ }
1577
+ return JSON.stringify(value);
1578
+ }
1579
+ function mapContinuityError(error, fallbackMessage) {
1580
+ if (error instanceof ContinuityClientStateStoreError)
1581
+ return error;
1582
+ if (error instanceof ContinuitySqliteStoreError) {
1583
+ return new ContinuityClientStateStoreError(error.message, [error.reasonCode], { mutationBlocked: error.mutationBlocked, cause: error });
1584
+ }
1585
+ const message = error instanceof Error ? error.message : String(error);
1586
+ return new ContinuityClientStateStoreError(`${fallbackMessage} ${message}`, [CONTINUITY_CLIENT_REASON_CODES.SQLITE_MUTATION_FAILED], { cause: error });
1587
+ }