@namzu/sdk 0.1.8 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -2
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +5 -2
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/RouterAgent.d.ts.map +1 -1
- package/dist/agents/RouterAgent.js +3 -0
- package/dist/agents/RouterAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +21 -5
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/bridge/a2a/index.d.ts +1 -1
- package/dist/bridge/a2a/index.d.ts.map +1 -1
- package/dist/bridge/a2a/index.js +1 -1
- package/dist/bridge/a2a/index.js.map +1 -1
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +6 -0
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/bridge/a2a/message.d.ts +0 -2
- package/dist/bridge/a2a/message.d.ts.map +1 -1
- package/dist/bridge/a2a/message.js +0 -26
- package/dist/bridge/a2a/message.js.map +1 -1
- package/dist/bridge/a2a/task.d.ts +5 -4
- package/dist/bridge/a2a/task.d.ts.map +1 -1
- package/dist/bridge/a2a/task.js +4 -4
- package/dist/bridge/a2a/task.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +6 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/constants/a2a/index.d.ts +2 -2
- package/dist/constants/a2a/index.d.ts.map +1 -1
- package/dist/constants/a2a/index.js.map +1 -1
- package/dist/contracts/api.d.ts +14 -27
- package/dist/contracts/api.d.ts.map +1 -1
- package/dist/contracts/ids.d.ts +1 -1
- package/dist/contracts/ids.d.ts.map +1 -1
- package/dist/contracts/index.d.ts +3 -3
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +1 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/schemas.d.ts +1 -31
- package/dist/contracts/schemas.d.ts.map +1 -1
- package/dist/contracts/schemas.js +1 -7
- package/dist/contracts/schemas.js.map +1 -1
- package/dist/gateway/local.d.ts.map +1 -1
- package/dist/gateway/local.js +6 -0
- package/dist/gateway/local.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/manager/agent/__tests__/lifecycle.test.d.ts +2 -0
- package/dist/manager/agent/__tests__/lifecycle.test.d.ts.map +1 -0
- package/dist/manager/agent/__tests__/lifecycle.test.js +316 -0
- package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -0
- package/dist/manager/agent/lifecycle.d.ts +67 -3
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +375 -14
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/index.d.ts +2 -0
- package/dist/manager/index.d.ts.map +1 -1
- package/dist/manager/index.js +1 -0
- package/dist/manager/index.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +10 -1
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +20 -0
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/manager/thread/__tests__/lifecycle.test.d.ts +2 -0
- package/dist/manager/thread/__tests__/lifecycle.test.d.ts.map +1 -0
- package/dist/manager/thread/__tests__/lifecycle.test.js +216 -0
- package/dist/manager/thread/__tests__/lifecycle.test.js.map +1 -0
- package/dist/manager/thread/lifecycle.d.ts +105 -0
- package/dist/manager/thread/lifecycle.d.ts.map +1 -0
- package/dist/manager/thread/lifecycle.js +186 -0
- package/dist/manager/thread/lifecycle.js.map +1 -0
- package/dist/rag/retriever.js +2 -2
- package/dist/run/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +25 -0
- package/dist/run/reporter.js.map +1 -1
- package/dist/runtime/query/__tests__/context.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/context.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/context.test.js +85 -0
- package/dist/runtime/query/__tests__/context.test.js.map +1 -0
- package/dist/runtime/query/context-cache.d.ts +3 -3
- package/dist/runtime/query/context-cache.d.ts.map +1 -1
- package/dist/runtime/query/context-cache.js +2 -2
- package/dist/runtime/query/context-cache.js.map +1 -1
- package/dist/runtime/query/context.d.ts +45 -1
- package/dist/runtime/query/context.d.ts.map +1 -1
- package/dist/runtime/query/context.js +50 -8
- package/dist/runtime/query/context.js.map +1 -1
- package/dist/runtime/query/events.d.ts.map +1 -1
- package/dist/runtime/query/events.js +8 -0
- package/dist/runtime/query/events.js.map +1 -1
- package/dist/runtime/query/index.d.ts +22 -1
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +11 -0
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/session/__tests__/integration/_fixtures.d.ts +122 -0
- package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -0
- package/dist/session/__tests__/integration/_fixtures.js +215 -0
- package/dist/session/__tests__/integration/_fixtures.js.map +1 -0
- package/dist/session/__tests__/integration/archive-gate.test.d.ts +15 -0
- package/dist/session/__tests__/integration/archive-gate.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/archive-gate.test.js +214 -0
- package/dist/session/__tests__/integration/archive-gate.test.js.map +1 -0
- package/dist/session/__tests__/integration/capacity-caps.test.d.ts +13 -0
- package/dist/session/__tests__/integration/capacity-caps.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/capacity-caps.test.js +123 -0
- package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -0
- package/dist/session/__tests__/integration/e2e-spawn.test.d.ts +18 -0
- package/dist/session/__tests__/integration/e2e-spawn.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/e2e-spawn.test.js +238 -0
- package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -0
- package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts +15 -0
- package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/event-stream-ordering.test.js +330 -0
- package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -0
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts +12 -0
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +182 -0
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -0
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts +18 -0
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +156 -0
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -0
- package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts +15 -0
- package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/handoff-single-e2e.test.js +179 -0
- package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -0
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts +12 -0
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +158 -0
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -0
- package/dist/session/__tests__/integration/migration-filesystem.test.d.ts +11 -0
- package/dist/session/__tests__/integration/migration-filesystem.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/migration-filesystem.test.js +140 -0
- package/dist/session/__tests__/integration/migration-filesystem.test.js.map +1 -0
- package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts +13 -0
- package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/migration-id-prefix.test.js +84 -0
- package/dist/session/__tests__/integration/migration-id-prefix.test.js.map +1 -0
- package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts +14 -0
- package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/prev-artifact-dag.test.js +242 -0
- package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -0
- package/dist/session/__tests__/integration/retention-archive.test.d.ts +12 -0
- package/dist/session/__tests__/integration/retention-archive.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/retention-archive.test.js +187 -0
- package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -0
- package/dist/session/__tests__/integration/spawn-rollback.test.d.ts +26 -0
- package/dist/session/__tests__/integration/spawn-rollback.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/spawn-rollback.test.js +236 -0
- package/dist/session/__tests__/integration/spawn-rollback.test.js.map +1 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts +18 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +201 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.d.ts +14 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.js +189 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -0
- package/dist/session/errors.d.ts +139 -0
- package/dist/session/errors.d.ts.map +1 -0
- package/dist/session/errors.js +107 -0
- package/dist/session/errors.js.map +1 -0
- package/dist/session/events/index.d.ts +4 -0
- package/dist/session/events/index.d.ts.map +1 -0
- package/dist/session/events/index.js +8 -0
- package/dist/session/events/index.js.map +1 -0
- package/dist/session/events/schema-version.d.ts +13 -0
- package/dist/session/events/schema-version.d.ts.map +1 -0
- package/dist/session/events/schema-version.js +12 -0
- package/dist/session/events/schema-version.js.map +1 -0
- package/dist/session/events/types.d.ts +64 -0
- package/dist/session/events/types.d.ts.map +1 -0
- package/dist/session/events/types.js +2 -0
- package/dist/session/events/types.js.map +1 -0
- package/dist/session/handoff/__tests__/broadcast.test.d.ts +2 -0
- package/dist/session/handoff/__tests__/broadcast.test.d.ts.map +1 -0
- package/dist/session/handoff/__tests__/broadcast.test.js +261 -0
- package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -0
- package/dist/session/handoff/__tests__/capacity.test.d.ts +2 -0
- package/dist/session/handoff/__tests__/capacity.test.d.ts.map +1 -0
- package/dist/session/handoff/__tests__/capacity.test.js +103 -0
- package/dist/session/handoff/__tests__/capacity.test.js.map +1 -0
- package/dist/session/handoff/__tests__/single.test.d.ts +2 -0
- package/dist/session/handoff/__tests__/single.test.d.ts.map +1 -0
- package/dist/session/handoff/__tests__/single.test.js +239 -0
- package/dist/session/handoff/__tests__/single.test.js.map +1 -0
- package/dist/session/handoff/assignment.d.ts +71 -0
- package/dist/session/handoff/assignment.d.ts.map +1 -0
- package/dist/session/handoff/assignment.js +11 -0
- package/dist/session/handoff/assignment.js.map +1 -0
- package/dist/session/handoff/broadcast.d.ts +54 -0
- package/dist/session/handoff/broadcast.d.ts.map +1 -0
- package/dist/session/handoff/broadcast.js +311 -0
- package/dist/session/handoff/broadcast.js.map +1 -0
- package/dist/session/handoff/capacity.d.ts +66 -0
- package/dist/session/handoff/capacity.d.ts.map +1 -0
- package/dist/session/handoff/capacity.js +60 -0
- package/dist/session/handoff/capacity.js.map +1 -0
- package/dist/session/handoff/events.d.ts +66 -0
- package/dist/session/handoff/events.d.ts.map +1 -0
- package/dist/session/handoff/events.js +13 -0
- package/dist/session/handoff/events.js.map +1 -0
- package/dist/session/handoff/index.d.ts +12 -0
- package/dist/session/handoff/index.d.ts.map +1 -0
- package/dist/session/handoff/index.js +9 -0
- package/dist/session/handoff/index.js.map +1 -0
- package/dist/session/handoff/single.d.ts +69 -0
- package/dist/session/handoff/single.d.ts.map +1 -0
- package/dist/session/handoff/single.js +229 -0
- package/dist/session/handoff/single.js.map +1 -0
- package/dist/session/handoff/version.d.ts +52 -0
- package/dist/session/handoff/version.d.ts.map +1 -0
- package/dist/session/handoff/version.js +36 -0
- package/dist/session/handoff/version.js.map +1 -0
- package/dist/session/hierarchy/__tests__/session.test.d.ts +2 -0
- package/dist/session/hierarchy/__tests__/session.test.d.ts.map +1 -0
- package/dist/session/hierarchy/__tests__/session.test.js +69 -0
- package/dist/session/hierarchy/__tests__/session.test.js.map +1 -0
- package/dist/session/hierarchy/actor.d.ts +26 -0
- package/dist/session/hierarchy/actor.d.ts.map +1 -0
- package/dist/session/hierarchy/actor.js +2 -0
- package/dist/session/hierarchy/actor.js.map +1 -0
- package/dist/session/hierarchy/index.d.ts +9 -0
- package/dist/session/hierarchy/index.d.ts.map +1 -0
- package/dist/session/hierarchy/index.js +4 -0
- package/dist/session/hierarchy/index.js.map +1 -0
- package/dist/session/hierarchy/lineage.d.ts +15 -0
- package/dist/session/hierarchy/lineage.d.ts.map +1 -0
- package/dist/session/hierarchy/lineage.js +2 -0
- package/dist/session/hierarchy/lineage.js.map +1 -0
- package/dist/session/hierarchy/project.d.ts +40 -0
- package/dist/session/hierarchy/project.d.ts.map +1 -0
- package/dist/session/hierarchy/project.js +2 -0
- package/dist/session/hierarchy/project.js.map +1 -0
- package/dist/session/hierarchy/session.d.ts +71 -0
- package/dist/session/hierarchy/session.d.ts.map +1 -0
- package/dist/session/hierarchy/session.js +51 -0
- package/dist/session/hierarchy/session.js.map +1 -0
- package/dist/session/hierarchy/sub-session.d.ts +76 -0
- package/dist/session/hierarchy/sub-session.d.ts.map +1 -0
- package/dist/session/hierarchy/sub-session.js +2 -0
- package/dist/session/hierarchy/sub-session.js.map +1 -0
- package/dist/session/hierarchy/tenant.d.ts +13 -0
- package/dist/session/hierarchy/tenant.d.ts.map +1 -0
- package/dist/session/hierarchy/tenant.js +2 -0
- package/dist/session/hierarchy/tenant.js.map +1 -0
- package/dist/session/hierarchy/thread.d.ts +54 -0
- package/dist/session/hierarchy/thread.d.ts.map +1 -0
- package/dist/session/hierarchy/thread.js +2 -0
- package/dist/session/hierarchy/thread.js.map +1 -0
- package/dist/session/index.d.ts +10 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +15 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/intervention/__tests__/prev-artifact.test.d.ts +2 -0
- package/dist/session/intervention/__tests__/prev-artifact.test.d.ts.map +1 -0
- package/dist/session/intervention/__tests__/prev-artifact.test.js +179 -0
- package/dist/session/intervention/__tests__/prev-artifact.test.js.map +1 -0
- package/dist/session/intervention/index.d.ts +3 -0
- package/dist/session/intervention/index.d.ts.map +1 -0
- package/dist/session/intervention/index.js +8 -0
- package/dist/session/intervention/index.js.map +1 -0
- package/dist/session/intervention/prev-artifact.d.ts +103 -0
- package/dist/session/intervention/prev-artifact.d.ts.map +1 -0
- package/dist/session/intervention/prev-artifact.js +112 -0
- package/dist/session/intervention/prev-artifact.js.map +1 -0
- package/dist/session/migration/__tests__/filesystem.test.d.ts +2 -0
- package/dist/session/migration/__tests__/filesystem.test.d.ts.map +1 -0
- package/dist/session/migration/__tests__/filesystem.test.js +188 -0
- package/dist/session/migration/__tests__/filesystem.test.js.map +1 -0
- package/dist/session/migration/__tests__/id-prefix.test.d.ts +2 -0
- package/dist/session/migration/__tests__/id-prefix.test.d.ts.map +1 -0
- package/dist/session/migration/__tests__/id-prefix.test.js +83 -0
- package/dist/session/migration/__tests__/id-prefix.test.js.map +1 -0
- package/dist/session/migration/__tests__/marker.test.d.ts +2 -0
- package/dist/session/migration/__tests__/marker.test.d.ts.map +1 -0
- package/dist/session/migration/__tests__/marker.test.js +75 -0
- package/dist/session/migration/__tests__/marker.test.js.map +1 -0
- package/dist/session/migration/errors.d.ts +26 -0
- package/dist/session/migration/errors.d.ts.map +1 -0
- package/dist/session/migration/errors.js +22 -0
- package/dist/session/migration/errors.js.map +1 -0
- package/dist/session/migration/filesystem.d.ts +94 -0
- package/dist/session/migration/filesystem.d.ts.map +1 -0
- package/dist/session/migration/filesystem.js +319 -0
- package/dist/session/migration/filesystem.js.map +1 -0
- package/dist/session/migration/id-prefix.d.ts +93 -0
- package/dist/session/migration/id-prefix.d.ts.map +1 -0
- package/dist/session/migration/id-prefix.js +111 -0
- package/dist/session/migration/id-prefix.js.map +1 -0
- package/dist/session/migration/index.d.ts +8 -0
- package/dist/session/migration/index.d.ts.map +1 -0
- package/dist/session/migration/index.js +8 -0
- package/dist/session/migration/index.js.map +1 -0
- package/dist/session/migration/marker.d.ts +57 -0
- package/dist/session/migration/marker.d.ts.map +1 -0
- package/dist/session/migration/marker.js +111 -0
- package/dist/session/migration/marker.js.map +1 -0
- package/dist/session/retention/__tests__/archive.test.d.ts +2 -0
- package/dist/session/retention/__tests__/archive.test.d.ts.map +1 -0
- package/dist/session/retention/__tests__/archive.test.js +253 -0
- package/dist/session/retention/__tests__/archive.test.js.map +1 -0
- package/dist/session/retention/__tests__/disk-backend.test.d.ts +2 -0
- package/dist/session/retention/__tests__/disk-backend.test.d.ts.map +1 -0
- package/dist/session/retention/__tests__/disk-backend.test.js +154 -0
- package/dist/session/retention/__tests__/disk-backend.test.js.map +1 -0
- package/dist/session/retention/archive-backend-ref.d.ts +18 -0
- package/dist/session/retention/archive-backend-ref.d.ts.map +1 -0
- package/dist/session/retention/archive-backend-ref.js +2 -0
- package/dist/session/retention/archive-backend-ref.js.map +1 -0
- package/dist/session/retention/archive.d.ts +130 -0
- package/dist/session/retention/archive.d.ts.map +1 -0
- package/dist/session/retention/archive.js +203 -0
- package/dist/session/retention/archive.js.map +1 -0
- package/dist/session/retention/backend.d.ts +101 -0
- package/dist/session/retention/backend.d.ts.map +1 -0
- package/dist/session/retention/backend.js +15 -0
- package/dist/session/retention/backend.js.map +1 -0
- package/dist/session/retention/disk-backend.d.ts +59 -0
- package/dist/session/retention/disk-backend.d.ts.map +1 -0
- package/dist/session/retention/disk-backend.js +236 -0
- package/dist/session/retention/disk-backend.js.map +1 -0
- package/dist/session/retention/index.d.ts +9 -0
- package/dist/session/retention/index.d.ts.map +1 -0
- package/dist/session/retention/index.js +6 -0
- package/dist/session/retention/index.js.map +1 -0
- package/dist/session/retention/policy.d.ts +49 -0
- package/dist/session/retention/policy.d.ts.map +1 -0
- package/dist/session/retention/policy.js +21 -0
- package/dist/session/retention/policy.js.map +1 -0
- package/dist/session/summary/__tests__/materialize.test.d.ts +2 -0
- package/dist/session/summary/__tests__/materialize.test.d.ts.map +1 -0
- package/dist/session/summary/__tests__/materialize.test.js +270 -0
- package/dist/session/summary/__tests__/materialize.test.js.map +1 -0
- package/dist/session/summary/deliverable.d.ts +74 -0
- package/dist/session/summary/deliverable.d.ts.map +1 -0
- package/dist/session/summary/deliverable.js +20 -0
- package/dist/session/summary/deliverable.js.map +1 -0
- package/dist/session/summary/index.d.ts +6 -0
- package/dist/session/summary/index.d.ts.map +1 -0
- package/dist/session/summary/index.js +9 -0
- package/dist/session/summary/index.js.map +1 -0
- package/dist/session/summary/materialize.d.ts +82 -0
- package/dist/session/summary/materialize.d.ts.map +1 -0
- package/dist/session/summary/materialize.js +117 -0
- package/dist/session/summary/materialize.js.map +1 -0
- package/dist/session/summary/ref.d.ts +91 -0
- package/dist/session/summary/ref.d.ts.map +1 -0
- package/dist/session/summary/ref.js +51 -0
- package/dist/session/summary/ref.js.map +1 -0
- package/dist/session/workspace/__tests__/git-worktree.test.d.ts +2 -0
- package/dist/session/workspace/__tests__/git-worktree.test.d.ts.map +1 -0
- package/dist/session/workspace/__tests__/git-worktree.test.js +244 -0
- package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -0
- package/dist/session/workspace/__tests__/path-builder.test.d.ts +2 -0
- package/dist/session/workspace/__tests__/path-builder.test.d.ts.map +1 -0
- package/dist/session/workspace/__tests__/path-builder.test.js +37 -0
- package/dist/session/workspace/__tests__/path-builder.test.js.map +1 -0
- package/dist/session/workspace/driver.d.ts +55 -0
- package/dist/session/workspace/driver.d.ts.map +1 -0
- package/dist/session/workspace/driver.js +12 -0
- package/dist/session/workspace/driver.js.map +1 -0
- package/dist/session/workspace/git-worktree.d.ts +65 -0
- package/dist/session/workspace/git-worktree.d.ts.map +1 -0
- package/dist/session/workspace/git-worktree.js +156 -0
- package/dist/session/workspace/git-worktree.js.map +1 -0
- package/dist/session/workspace/index.d.ts +8 -0
- package/dist/session/workspace/index.d.ts.map +1 -0
- package/dist/session/workspace/index.js +7 -0
- package/dist/session/workspace/index.js.map +1 -0
- package/dist/session/workspace/path-builder.d.ts +50 -0
- package/dist/session/workspace/path-builder.d.ts.map +1 -0
- package/dist/session/workspace/path-builder.js +50 -0
- package/dist/session/workspace/path-builder.js.map +1 -0
- package/dist/session/workspace/ref.d.ts +46 -0
- package/dist/session/workspace/ref.d.ts.map +1 -0
- package/dist/session/workspace/ref.js +11 -0
- package/dist/session/workspace/ref.js.map +1 -0
- package/dist/session/workspace/registry.d.ts +26 -0
- package/dist/session/workspace/registry.d.ts.map +1 -0
- package/dist/session/workspace/registry.js +35 -0
- package/dist/session/workspace/registry.js.map +1 -0
- package/dist/store/index.d.ts +0 -2
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +0 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/session/__tests__/disk.test.d.ts +2 -0
- package/dist/store/session/__tests__/disk.test.d.ts.map +1 -0
- package/dist/store/session/__tests__/disk.test.js +267 -0
- package/dist/store/session/__tests__/disk.test.js.map +1 -0
- package/dist/store/session/__tests__/memory.test.d.ts +2 -0
- package/dist/store/session/__tests__/memory.test.d.ts.map +1 -0
- package/dist/store/session/__tests__/memory.test.js +258 -0
- package/dist/store/session/__tests__/memory.test.js.map +1 -0
- package/dist/store/session/disk.d.ts +86 -0
- package/dist/store/session/disk.d.ts.map +1 -0
- package/dist/store/session/disk.js +818 -0
- package/dist/store/session/disk.js.map +1 -0
- package/dist/store/session/index.d.ts +7 -0
- package/dist/store/session/index.d.ts.map +1 -0
- package/dist/store/session/index.js +10 -0
- package/dist/store/session/index.js.map +1 -0
- package/dist/store/session/linkage.d.ts +38 -0
- package/dist/store/session/linkage.d.ts.map +1 -0
- package/dist/store/session/linkage.js +64 -0
- package/dist/store/session/linkage.js.map +1 -0
- package/dist/store/session/memory.d.ts +49 -0
- package/dist/store/session/memory.d.ts.map +1 -0
- package/dist/store/session/memory.js +335 -0
- package/dist/store/session/memory.js.map +1 -0
- package/dist/store/session/messages.d.ts +20 -0
- package/dist/store/session/messages.d.ts.map +1 -0
- package/dist/store/session/messages.js +12 -0
- package/dist/store/session/messages.js.map +1 -0
- package/dist/store/thread/disk.d.ts +41 -0
- package/dist/store/thread/disk.d.ts.map +1 -0
- package/dist/store/thread/disk.js +229 -0
- package/dist/store/thread/disk.js.map +1 -0
- package/dist/store/thread/index.d.ts +4 -0
- package/dist/store/thread/index.d.ts.map +1 -0
- package/dist/store/thread/index.js +6 -0
- package/dist/store/thread/index.js.map +1 -0
- package/dist/store/thread/memory.d.ts +23 -0
- package/dist/store/thread/memory.d.ts.map +1 -0
- package/dist/store/thread/memory.js +90 -0
- package/dist/store/thread/memory.js.map +1 -0
- package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +1 -1
- package/dist/types/agent/base.d.ts +24 -1
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/factory.d.ts +8 -2
- package/dist/types/agent/factory.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +57 -2
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/agent/task.js.map +1 -1
- package/dist/types/ids/index.d.ts +22 -3
- package/dist/types/ids/index.d.ts.map +1 -1
- package/dist/types/ids/index.js +8 -1
- package/dist/types/ids/index.js.map +1 -1
- package/dist/types/invocation/__tests__/state.test.js +36 -29
- package/dist/types/invocation/__tests__/state.test.js.map +1 -1
- package/dist/types/invocation/index.d.ts +20 -4
- package/dist/types/invocation/index.d.ts.map +1 -1
- package/dist/types/invocation/index.js +10 -7
- package/dist/types/invocation/index.js.map +1 -1
- package/dist/types/rag/retrieval.d.ts +4 -3
- package/dist/types/rag/retrieval.d.ts.map +1 -1
- package/dist/types/run/config.d.ts +12 -1
- package/dist/types/run/config.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +26 -1
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/index.d.ts.map +1 -1
- package/dist/types/run/index.js +8 -0
- package/dist/types/run/index.js.map +1 -1
- package/dist/types/run/metadata.d.ts +12 -2
- package/dist/types/run/metadata.d.ts.map +1 -1
- package/dist/types/run/status.d.ts +26 -0
- package/dist/types/run/status.d.ts.map +1 -0
- package/dist/types/run/status.js +2 -0
- package/dist/types/run/status.js.map +1 -0
- package/dist/types/session/ids.d.ts +9 -0
- package/dist/types/session/ids.d.ts.map +1 -0
- package/dist/types/session/ids.js +9 -0
- package/dist/types/session/ids.js.map +1 -0
- package/dist/types/session/index.d.ts +3 -0
- package/dist/types/session/index.d.ts.map +1 -0
- package/dist/types/session/index.js +5 -0
- package/dist/types/session/index.js.map +1 -0
- package/dist/types/session/store.d.ts +210 -0
- package/dist/types/session/store.d.ts.map +1 -0
- package/dist/types/session/store.js +9 -0
- package/dist/types/session/store.js.map +1 -0
- package/dist/types/thread/index.d.ts +2 -0
- package/dist/types/thread/index.d.ts.map +1 -0
- package/dist/types/thread/index.js +5 -0
- package/dist/types/thread/index.js.map +1 -0
- package/dist/types/thread/store.d.ts +86 -0
- package/dist/types/thread/store.d.ts.map +1 -0
- package/dist/types/thread/store.js +22 -0
- package/dist/types/thread/store.js.map +1 -0
- package/dist/utils/id.d.ts +8 -2
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +22 -4
- package/dist/utils/id.js.map +1 -1
- package/package.json +6 -11
- package/src/agents/ReactiveAgent.ts +7 -2
- package/src/agents/RouterAgent.ts +5 -0
- package/src/agents/SupervisorAgent.ts +29 -6
- package/src/bridge/a2a/index.ts +0 -1
- package/src/bridge/a2a/mapper.ts +7 -0
- package/src/bridge/a2a/message.ts +0 -32
- package/src/bridge/a2a/task.ts +9 -8
- package/src/bridge/sse/mapper.ts +8 -1
- package/src/constants/a2a/index.ts +2 -2
- package/src/contracts/api.ts +14 -30
- package/src/contracts/ids.ts +1 -1
- package/src/contracts/index.ts +3 -7
- package/src/contracts/schemas.ts +1 -8
- package/src/gateway/local.ts +6 -0
- package/src/index.ts +14 -4
- package/src/manager/agent/__tests__/lifecycle.test.ts +473 -0
- package/src/manager/agent/lifecycle.ts +515 -21
- package/src/manager/index.ts +3 -0
- package/src/manager/run/persistence.ts +26 -1
- package/src/manager/thread/__tests__/lifecycle.test.ts +286 -0
- package/src/manager/thread/lifecycle.ts +217 -0
- package/src/rag/retriever.ts +2 -2
- package/src/run/reporter.ts +28 -0
- package/src/runtime/query/__tests__/context.test.ts +102 -0
- package/src/runtime/query/context-cache.ts +4 -4
- package/src/runtime/query/context.ts +98 -9
- package/src/runtime/query/events.ts +8 -0
- package/src/runtime/query/index.ts +38 -1
- package/src/session/__tests__/integration/_fixtures.ts +310 -0
- package/src/session/__tests__/integration/archive-gate.test.ts +288 -0
- package/src/session/__tests__/integration/capacity-caps.test.ts +171 -0
- package/src/session/__tests__/integration/e2e-spawn.test.ts +296 -0
- package/src/session/__tests__/integration/event-stream-ordering.test.ts +410 -0
- package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +271 -0
- package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +214 -0
- package/src/session/__tests__/integration/handoff-single-e2e.test.ts +251 -0
- package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +240 -0
- package/src/session/__tests__/integration/migration-filesystem.test.ts +209 -0
- package/src/session/__tests__/integration/migration-id-prefix.test.ts +101 -0
- package/src/session/__tests__/integration/prev-artifact-dag.test.ts +325 -0
- package/src/session/__tests__/integration/retention-archive.test.ts +233 -0
- package/src/session/__tests__/integration/spawn-rollback.test.ts +313 -0
- package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +239 -0
- package/src/session/__tests__/integration/tenant-isolation.test.ts +292 -0
- package/src/session/errors.ts +159 -0
- package/src/session/events/index.ts +16 -0
- package/src/session/events/schema-version.ts +13 -0
- package/src/session/events/types.ts +71 -0
- package/src/session/handoff/__tests__/broadcast.test.ts +378 -0
- package/src/session/handoff/__tests__/capacity.test.ts +129 -0
- package/src/session/handoff/__tests__/single.test.ts +333 -0
- package/src/session/handoff/assignment.ts +74 -0
- package/src/session/handoff/broadcast.ts +406 -0
- package/src/session/handoff/capacity.ts +121 -0
- package/src/session/handoff/events.ts +72 -0
- package/src/session/handoff/index.ts +29 -0
- package/src/session/handoff/single.ts +310 -0
- package/src/session/handoff/version.ts +59 -0
- package/src/session/hierarchy/__tests__/session.test.ts +100 -0
- package/src/session/hierarchy/actor.ts +17 -0
- package/src/session/hierarchy/index.ts +18 -0
- package/src/session/hierarchy/lineage.ts +15 -0
- package/src/session/hierarchy/project.ts +41 -0
- package/src/session/hierarchy/session.ts +109 -0
- package/src/session/hierarchy/sub-session.ts +92 -0
- package/src/session/hierarchy/tenant.ts +13 -0
- package/src/session/hierarchy/thread.ts +55 -0
- package/src/session/index.ts +15 -0
- package/src/session/intervention/__tests__/prev-artifact.test.ts +234 -0
- package/src/session/intervention/index.ts +16 -0
- package/src/session/intervention/prev-artifact.ts +180 -0
- package/src/session/migration/__tests__/filesystem.test.ts +263 -0
- package/src/session/migration/__tests__/id-prefix.test.ts +101 -0
- package/src/session/migration/__tests__/marker.test.ts +84 -0
- package/src/session/migration/errors.ts +23 -0
- package/src/session/migration/filesystem.ts +401 -0
- package/src/session/migration/id-prefix.ts +141 -0
- package/src/session/migration/index.ts +38 -0
- package/src/session/migration/marker.ts +131 -0
- package/src/session/retention/__tests__/archive.test.ts +318 -0
- package/src/session/retention/__tests__/disk-backend.test.ts +180 -0
- package/src/session/retention/archive-backend-ref.ts +17 -0
- package/src/session/retention/archive.ts +281 -0
- package/src/session/retention/backend.ts +107 -0
- package/src/session/retention/disk-backend.ts +304 -0
- package/src/session/retention/index.ts +16 -0
- package/src/session/retention/policy.ts +53 -0
- package/src/session/summary/__tests__/materialize.test.ts +343 -0
- package/src/session/summary/deliverable.ts +84 -0
- package/src/session/summary/index.ts +31 -0
- package/src/session/summary/materialize.ts +169 -0
- package/src/session/summary/ref.ts +104 -0
- package/src/session/workspace/__tests__/git-worktree.test.ts +258 -0
- package/src/session/workspace/__tests__/path-builder.test.ts +51 -0
- package/src/session/workspace/driver.ts +60 -0
- package/src/session/workspace/git-worktree.ts +209 -0
- package/src/session/workspace/index.ts +25 -0
- package/src/session/workspace/path-builder.ts +71 -0
- package/src/session/workspace/ref.ts +50 -0
- package/src/session/workspace/registry.ts +42 -0
- package/src/store/index.ts +0 -3
- package/src/store/session/__tests__/disk.test.ts +397 -0
- package/src/store/session/__tests__/memory.test.ts +402 -0
- package/src/store/session/disk.ts +976 -0
- package/src/store/session/index.ts +13 -0
- package/src/store/session/linkage.ts +80 -0
- package/src/store/session/memory.ts +412 -0
- package/src/store/session/messages.ts +21 -0
- package/src/store/thread/disk.ts +261 -0
- package/src/store/thread/index.ts +7 -0
- package/src/store/thread/memory.ts +104 -0
- package/src/types/agent/base.ts +27 -1
- package/src/types/agent/factory.ts +8 -3
- package/src/types/agent/task.ts +66 -2
- package/src/types/ids/index.ts +34 -3
- package/src/types/invocation/__tests__/state.test.ts +37 -29
- package/src/types/invocation/index.ts +26 -10
- package/src/types/rag/retrieval.ts +4 -3
- package/src/types/run/config.ts +13 -1
- package/src/types/run/events.ts +36 -1
- package/src/types/run/index.ts +8 -0
- package/src/types/run/metadata.ts +12 -2
- package/src/types/run/status.ts +33 -0
- package/src/types/session/ids.ts +23 -0
- package/src/types/session/index.ts +27 -0
- package/src/types/session/store.ts +252 -0
- package/src/types/thread/index.ts +5 -0
- package/src/types/thread/store.ts +92 -0
- package/src/utils/id.ts +34 -4
- package/dist/store/conversation/memory.d.ts +0 -21
- package/dist/store/conversation/memory.d.ts.map +0 -1
- package/dist/store/conversation/memory.js +0 -86
- package/dist/store/conversation/memory.js.map +0 -1
- package/dist/types/conversation/index.d.ts +0 -7
- package/dist/types/conversation/index.d.ts.map +0 -1
- package/dist/types/conversation/index.js +0 -2
- package/dist/types/conversation/index.js.map +0 -1
- package/src/store/conversation/memory.ts +0 -121
- package/src/types/conversation/index.ts +0 -8
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration marker file I/O — ensures the boot-time v0.2.0 re-layout is
|
|
3
|
+
* idempotent and race-safe.
|
|
4
|
+
*
|
|
5
|
+
* Layout:
|
|
6
|
+
* {rootDir}/.migration/v0.2.0 — completion marker (JSON body)
|
|
7
|
+
* {rootDir}/.migration/v0.2.0.tmp — in-flight lock (O_EXCL / `wx` flag)
|
|
8
|
+
*
|
|
9
|
+
* Atomicity contract (Convention #8):
|
|
10
|
+
* - `writeMarker` goes through write-tmp-rename so readers never see a
|
|
11
|
+
* partially serialized body.
|
|
12
|
+
* - `acquireMigrationLock` uses the `wx` flag (O_CREAT | O_EXCL) so
|
|
13
|
+
* concurrent boots detect each other rather than overwriting. Loser
|
|
14
|
+
* cooperates (see filesystem.ts — waits and re-checks the main marker).
|
|
15
|
+
* - `readMarker` tolerates missing / corrupt files: missing → null,
|
|
16
|
+
* corrupt JSON → null (not throw). The migrator treats either as "run
|
|
17
|
+
* again"; a corrupt marker is safer to retry than to honor as valid.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'
|
|
21
|
+
import { dirname } from 'node:path'
|
|
22
|
+
import type { ProjectId } from '../../types/session/ids.js'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Marker payload. `migratedThreads` preserves the legacy → new mapping so
|
|
26
|
+
* later tooling (e.g. `namzu sdk migrate-ids`) can cross-reference.
|
|
27
|
+
*/
|
|
28
|
+
export interface MigrationMarker {
|
|
29
|
+
version: string
|
|
30
|
+
at: Date
|
|
31
|
+
migratedThreads: readonly { legacyThreadId: string; newProjectId: ProjectId }[]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface PersistedMarker {
|
|
35
|
+
version: string
|
|
36
|
+
at: string
|
|
37
|
+
migratedThreads: readonly { legacyThreadId: string; newProjectId: string }[]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Read a marker file. Returns `null` when the file is absent OR when the
|
|
42
|
+
* contents fail JSON.parse — corruption is treated as "migration did not
|
|
43
|
+
* complete cleanly", so the caller re-runs rather than honoring stale data.
|
|
44
|
+
*/
|
|
45
|
+
export async function readMarker(path: string): Promise<MigrationMarker | null> {
|
|
46
|
+
let raw: string
|
|
47
|
+
try {
|
|
48
|
+
raw = await readFile(path, 'utf-8')
|
|
49
|
+
} catch (err) {
|
|
50
|
+
const code = (err as NodeJS.ErrnoException).code
|
|
51
|
+
if (code === 'ENOENT') return null
|
|
52
|
+
throw err
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let parsed: PersistedMarker
|
|
56
|
+
try {
|
|
57
|
+
parsed = JSON.parse(raw) as PersistedMarker
|
|
58
|
+
} catch {
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
typeof parsed !== 'object' ||
|
|
64
|
+
parsed === null ||
|
|
65
|
+
typeof parsed.version !== 'string' ||
|
|
66
|
+
typeof parsed.at !== 'string' ||
|
|
67
|
+
!Array.isArray(parsed.migratedThreads)
|
|
68
|
+
) {
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
version: parsed.version,
|
|
74
|
+
at: new Date(parsed.at),
|
|
75
|
+
migratedThreads: parsed.migratedThreads.map((m) => ({
|
|
76
|
+
legacyThreadId: m.legacyThreadId,
|
|
77
|
+
newProjectId: m.newProjectId as ProjectId,
|
|
78
|
+
})),
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Write a marker atomically via write-tmp-rename. Parent directory is
|
|
84
|
+
* created on demand so callers do not have to mkdir separately.
|
|
85
|
+
*/
|
|
86
|
+
export async function writeMarker(path: string, marker: MigrationMarker): Promise<void> {
|
|
87
|
+
await mkdir(dirname(path), { recursive: true })
|
|
88
|
+
const serialized: PersistedMarker = {
|
|
89
|
+
version: marker.version,
|
|
90
|
+
at: marker.at.toISOString(),
|
|
91
|
+
migratedThreads: marker.migratedThreads.map((m) => ({
|
|
92
|
+
legacyThreadId: m.legacyThreadId,
|
|
93
|
+
newProjectId: m.newProjectId as string,
|
|
94
|
+
})),
|
|
95
|
+
}
|
|
96
|
+
const tmp = `${path}.write.tmp`
|
|
97
|
+
try {
|
|
98
|
+
await writeFile(tmp, JSON.stringify(serialized, null, 2), 'utf-8')
|
|
99
|
+
await rename(tmp, path)
|
|
100
|
+
} catch (err) {
|
|
101
|
+
await unlink(tmp).catch(() => undefined)
|
|
102
|
+
throw err
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Acquire an exclusive lock by creating `tmpPath` with the `wx` flag.
|
|
108
|
+
* EEXIST means another process is mid-migration — callers must treat that
|
|
109
|
+
* as "wait and re-check the main marker" rather than overwriting.
|
|
110
|
+
*
|
|
111
|
+
* Returns on success; throws the raw `NodeJS.ErrnoException` on EEXIST or
|
|
112
|
+
* any other FS failure so the caller can branch on `code`.
|
|
113
|
+
*/
|
|
114
|
+
export async function acquireMigrationLock(tmpPath: string): Promise<void> {
|
|
115
|
+
await mkdir(dirname(tmpPath), { recursive: true })
|
|
116
|
+
await writeFile(tmpPath, JSON.stringify({ at: new Date().toISOString() }), { flag: 'wx' })
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Release the lock. Missing file is tolerated — lock release is idempotent
|
|
121
|
+
* by design so crashed mid-migrations do not wedge subsequent boots.
|
|
122
|
+
*/
|
|
123
|
+
export async function releaseMigrationLock(tmpPath: string): Promise<void> {
|
|
124
|
+
try {
|
|
125
|
+
await unlink(tmpPath)
|
|
126
|
+
} catch (err) {
|
|
127
|
+
const code = (err as NodeJS.ErrnoException).code
|
|
128
|
+
if (code === 'ENOENT') return
|
|
129
|
+
throw err
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import type { ActorRef } from '../../../session/hierarchy/actor.js'
|
|
6
|
+
import type { SubSession } from '../../../session/hierarchy/sub-session.js'
|
|
7
|
+
import { type ExecFile, GitWorktreeDriver } from '../../../session/workspace/git-worktree.js'
|
|
8
|
+
import type { WorkspaceRef } from '../../../session/workspace/ref.js'
|
|
9
|
+
import { WorkspaceBackendRegistry } from '../../../session/workspace/registry.js'
|
|
10
|
+
import { InMemorySessionStore } from '../../../store/session/memory.js'
|
|
11
|
+
import type { AgentId, TenantId, UserId } from '../../../types/ids/index.js'
|
|
12
|
+
import { createUserMessage } from '../../../types/message/index.js'
|
|
13
|
+
import type { ThreadId, WorkspaceId } from '../../../types/session/ids.js'
|
|
14
|
+
import {
|
|
15
|
+
ArchivalManager,
|
|
16
|
+
ArchiveNotConfiguredError,
|
|
17
|
+
SubSessionNotArchivableError,
|
|
18
|
+
} from '../archive.js'
|
|
19
|
+
import { DiskArchiveBackend } from '../disk-backend.js'
|
|
20
|
+
|
|
21
|
+
const TEST_THREAD_ID = 'thd_test' as ThreadId
|
|
22
|
+
|
|
23
|
+
const tenantA = 'tnt_alpha' as TenantId
|
|
24
|
+
|
|
25
|
+
function stubLogger() {
|
|
26
|
+
return {
|
|
27
|
+
debug: vi.fn(),
|
|
28
|
+
info: vi.fn(),
|
|
29
|
+
warn: vi.fn(),
|
|
30
|
+
error: vi.fn(),
|
|
31
|
+
child() {
|
|
32
|
+
return stubLogger()
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function userActor(tenantId: TenantId): ActorRef {
|
|
38
|
+
return { kind: 'user', userId: 'usr_a' as UserId, tenantId }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function agentActor(tenantId: TenantId): ActorRef {
|
|
42
|
+
return { kind: 'agent', agentId: 'agt_a' as AgentId, tenantId }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function seedIdleSubSession(store: InMemorySessionStore) {
|
|
46
|
+
const project = await store.createProject({ tenantId: tenantA, name: 'p' }, tenantA)
|
|
47
|
+
const parent = await store.createSession(
|
|
48
|
+
{ threadId: TEST_THREAD_ID, projectId: project.id, currentActor: userActor(tenantA) },
|
|
49
|
+
tenantA,
|
|
50
|
+
)
|
|
51
|
+
const child = await store.createSession(
|
|
52
|
+
{ threadId: TEST_THREAD_ID, projectId: project.id, currentActor: agentActor(tenantA) },
|
|
53
|
+
tenantA,
|
|
54
|
+
)
|
|
55
|
+
const sub = await store.createSubSession(
|
|
56
|
+
{
|
|
57
|
+
parentSessionId: parent.id,
|
|
58
|
+
childSessionId: child.id,
|
|
59
|
+
kind: 'agent_spawn',
|
|
60
|
+
spawnedBy: userActor(tenantA),
|
|
61
|
+
},
|
|
62
|
+
tenantA,
|
|
63
|
+
)
|
|
64
|
+
// Flip the newly-created sub-session from 'pending' → 'idle' so it's
|
|
65
|
+
// eligible for archival.
|
|
66
|
+
await store.updateSubSession({ ...sub, status: 'idle' }, tenantA)
|
|
67
|
+
return { project, parent, child, sub }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function buildRegistry(): WorkspaceBackendRegistry {
|
|
71
|
+
const exec: ExecFile = async () => ({ stdout: '', stderr: '' })
|
|
72
|
+
const driver = new GitWorktreeDriver({
|
|
73
|
+
repoRoot: '/repo',
|
|
74
|
+
logger: stubLogger(),
|
|
75
|
+
execFile: exec,
|
|
76
|
+
})
|
|
77
|
+
const registry = new WorkspaceBackendRegistry()
|
|
78
|
+
registry.register(driver)
|
|
79
|
+
return registry
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
describe('ArchivalManager', () => {
|
|
83
|
+
let rootDir: string
|
|
84
|
+
let store: InMemorySessionStore
|
|
85
|
+
let backend: DiskArchiveBackend
|
|
86
|
+
|
|
87
|
+
beforeEach(() => {
|
|
88
|
+
rootDir = mkdtempSync(join(tmpdir(), 'namzu-retention-archive-'))
|
|
89
|
+
store = new InMemorySessionStore()
|
|
90
|
+
backend = new DiskArchiveBackend({ rootDir })
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
afterEach(() => {
|
|
94
|
+
rmSync(rootDir, { recursive: true, force: true })
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('archive happy path: idle sub-session → tombstone attached, backend called once', async () => {
|
|
98
|
+
const { sub, child } = await seedIdleSubSession(store)
|
|
99
|
+
await store.appendMessage(child.id, createUserMessage('hi'), tenantA)
|
|
100
|
+
|
|
101
|
+
const storeSpy = vi.spyOn(backend, 'store')
|
|
102
|
+
const manager = new ArchivalManager({
|
|
103
|
+
sessionStore: store,
|
|
104
|
+
workspaceRegistry: buildRegistry(),
|
|
105
|
+
archiveBackend: backend,
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const tombstone = await manager.archive(sub.id, tenantA)
|
|
109
|
+
|
|
110
|
+
expect(tombstone.subSessionId).toBe(sub.id)
|
|
111
|
+
expect(tombstone.archiveRef).toMatch(/^arc_/)
|
|
112
|
+
expect(tombstone.archivedAt).toBeInstanceOf(Date)
|
|
113
|
+
expect(storeSpy).toHaveBeenCalledTimes(1)
|
|
114
|
+
|
|
115
|
+
const after = await store.getSubSession(sub.id, tenantA)
|
|
116
|
+
expect(after?.status).toBe('archived')
|
|
117
|
+
expect(after?.archiveRef).toBe(tombstone.archiveRef)
|
|
118
|
+
expect(after?.archivedAt).toBeInstanceOf(Date)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('rejects non-archivable statuses (running/active → not_idle)', async () => {
|
|
122
|
+
const { sub } = await seedIdleSubSession(store)
|
|
123
|
+
await store.updateSubSession({ ...sub, status: 'active' }, tenantA)
|
|
124
|
+
|
|
125
|
+
const manager = new ArchivalManager({
|
|
126
|
+
sessionStore: store,
|
|
127
|
+
workspaceRegistry: buildRegistry(),
|
|
128
|
+
archiveBackend: backend,
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
await expect(manager.archive(sub.id, tenantA)).rejects.toBeInstanceOf(
|
|
132
|
+
SubSessionNotArchivableError,
|
|
133
|
+
)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('rejects already-archived sub-sessions', async () => {
|
|
137
|
+
const { sub } = await seedIdleSubSession(store)
|
|
138
|
+
const manager = new ArchivalManager({
|
|
139
|
+
sessionStore: store,
|
|
140
|
+
workspaceRegistry: buildRegistry(),
|
|
141
|
+
archiveBackend: backend,
|
|
142
|
+
})
|
|
143
|
+
await manager.archive(sub.id, tenantA)
|
|
144
|
+
|
|
145
|
+
await expect(manager.archive(sub.id, tenantA)).rejects.toMatchObject({
|
|
146
|
+
name: 'SubSessionNotArchivableError',
|
|
147
|
+
details: { reason: 'already_archived' },
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('rejects missing sub-sessions', async () => {
|
|
152
|
+
const manager = new ArchivalManager({
|
|
153
|
+
sessionStore: store,
|
|
154
|
+
workspaceRegistry: buildRegistry(),
|
|
155
|
+
archiveBackend: backend,
|
|
156
|
+
})
|
|
157
|
+
await expect(manager.archive('sub_missing' as SubSession['id'], tenantA)).rejects.toMatchObject(
|
|
158
|
+
{ name: 'SubSessionNotArchivableError', details: { reason: 'missing' } },
|
|
159
|
+
)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('deny-by-default: backend absent → ArchiveNotConfiguredError', async () => {
|
|
163
|
+
const { sub } = await seedIdleSubSession(store)
|
|
164
|
+
const manager = new ArchivalManager({
|
|
165
|
+
sessionStore: store,
|
|
166
|
+
workspaceRegistry: buildRegistry(),
|
|
167
|
+
// archiveBackend intentionally omitted.
|
|
168
|
+
})
|
|
169
|
+
await expect(manager.archive(sub.id, tenantA)).rejects.toBeInstanceOf(ArchiveNotConfiguredError)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('restore reads tombstone, invokes backend.restore, flips status back to idle', async () => {
|
|
173
|
+
const { sub } = await seedIdleSubSession(store)
|
|
174
|
+
const manager = new ArchivalManager({
|
|
175
|
+
sessionStore: store,
|
|
176
|
+
workspaceRegistry: buildRegistry(),
|
|
177
|
+
archiveBackend: backend,
|
|
178
|
+
})
|
|
179
|
+
await manager.archive(sub.id, tenantA)
|
|
180
|
+
|
|
181
|
+
const restoreSpy = vi.spyOn(backend, 'restore')
|
|
182
|
+
await manager.restore(sub.id, tenantA)
|
|
183
|
+
|
|
184
|
+
expect(restoreSpy).toHaveBeenCalledTimes(1)
|
|
185
|
+
const after = await store.getSubSession(sub.id, tenantA)
|
|
186
|
+
expect(after?.status).toBe('idle')
|
|
187
|
+
expect(after?.archiveRef).toBeUndefined()
|
|
188
|
+
expect(after?.archivedAt).toBeUndefined()
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('tombstone is navigable via drill post-archive with status=archived + archiveRef', async () => {
|
|
192
|
+
const { parent, sub } = await seedIdleSubSession(store)
|
|
193
|
+
const manager = new ArchivalManager({
|
|
194
|
+
sessionStore: store,
|
|
195
|
+
workspaceRegistry: buildRegistry(),
|
|
196
|
+
archiveBackend: backend,
|
|
197
|
+
})
|
|
198
|
+
const tombstone = await manager.archive(sub.id, tenantA)
|
|
199
|
+
|
|
200
|
+
const view = await store.drill(parent.id, tenantA)
|
|
201
|
+
expect(view).not.toBeNull()
|
|
202
|
+
expect(view?.children).toHaveLength(1)
|
|
203
|
+
const child = view?.children[0]
|
|
204
|
+
expect(child?.id).toBe(sub.id)
|
|
205
|
+
expect(child?.status).toBe('archived')
|
|
206
|
+
expect(child?.archiveRef).toBe(tombstone.archiveRef)
|
|
207
|
+
expect(child?.archivedAt).toBeInstanceOf(Date)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('workspace disposal failures do not unwind the committed archive', async () => {
|
|
211
|
+
const { sub } = await seedIdleSubSession(store)
|
|
212
|
+
|
|
213
|
+
// Registry with a driver whose `dispose` always throws.
|
|
214
|
+
const registry = new WorkspaceBackendRegistry()
|
|
215
|
+
registry.register({
|
|
216
|
+
kind: 'git-worktree',
|
|
217
|
+
async create() {
|
|
218
|
+
return {
|
|
219
|
+
id: 'wsp_x' as WorkspaceId,
|
|
220
|
+
meta: {
|
|
221
|
+
backend: 'git-worktree',
|
|
222
|
+
repoRoot: '/r',
|
|
223
|
+
branch: 'main',
|
|
224
|
+
worktreePath: '/r/x',
|
|
225
|
+
},
|
|
226
|
+
createdAt: new Date(),
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
async branch(ref) {
|
|
230
|
+
return ref
|
|
231
|
+
},
|
|
232
|
+
async dispose() {
|
|
233
|
+
throw new Error('dispose boom')
|
|
234
|
+
},
|
|
235
|
+
async inspect() {
|
|
236
|
+
return { exists: true, currentRef: 'HEAD', isDirty: false }
|
|
237
|
+
},
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
const workspaceRef: WorkspaceRef = {
|
|
241
|
+
id: 'wsp_y' as WorkspaceId,
|
|
242
|
+
meta: { backend: 'git-worktree', repoRoot: '/r', branch: 'main', worktreePath: '/r/y' },
|
|
243
|
+
createdAt: new Date(),
|
|
244
|
+
}
|
|
245
|
+
// Seed the sub-session with a workspaceId and a resolver that returns
|
|
246
|
+
// the live ref.
|
|
247
|
+
await store.updateSubSession({ ...sub, status: 'idle', workspaceId: workspaceRef.id }, tenantA)
|
|
248
|
+
|
|
249
|
+
const manager = new ArchivalManager({
|
|
250
|
+
sessionStore: store,
|
|
251
|
+
workspaceRegistry: registry,
|
|
252
|
+
archiveBackend: backend,
|
|
253
|
+
workspaceResolver: async () => workspaceRef,
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
// Archive must complete even though dispose throws internally.
|
|
257
|
+
const tombstone = await manager.archive(sub.id, tenantA)
|
|
258
|
+
expect(tombstone.archiveRef).toMatch(/^arc_/)
|
|
259
|
+
|
|
260
|
+
const after = await store.getSubSession(sub.id, tenantA)
|
|
261
|
+
expect(after?.status).toBe('archived')
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
it('SessionMessage round-trip: archive preserves original MessageId + timestamps', async () => {
|
|
265
|
+
// Phase 9 Known Delta #7: ArchivalManager now uses
|
|
266
|
+
// SessionStore.loadSessionMessages for full-fidelity archival (no more
|
|
267
|
+
// synthetic `msg_restored_N` IDs).
|
|
268
|
+
const { sub, child } = await seedIdleSubSession(store)
|
|
269
|
+
const id1 = await store.appendMessage(child.id, createUserMessage('m1'), tenantA)
|
|
270
|
+
const id2 = await store.appendMessage(child.id, createUserMessage('m2'), tenantA)
|
|
271
|
+
|
|
272
|
+
const captured: unknown[] = []
|
|
273
|
+
const capturingBackend: DiskArchiveBackend = Object.assign(
|
|
274
|
+
new DiskArchiveBackend({ rootDir }),
|
|
275
|
+
{
|
|
276
|
+
store: vi.fn(async (bundle: unknown) => {
|
|
277
|
+
captured.push(bundle)
|
|
278
|
+
return {
|
|
279
|
+
archiveRef: 'arc_test_ref',
|
|
280
|
+
archivedAt: new Date(),
|
|
281
|
+
}
|
|
282
|
+
}),
|
|
283
|
+
},
|
|
284
|
+
) as unknown as DiskArchiveBackend
|
|
285
|
+
|
|
286
|
+
const manager = new ArchivalManager({
|
|
287
|
+
sessionStore: store,
|
|
288
|
+
workspaceRegistry: buildRegistry(),
|
|
289
|
+
archiveBackend: capturingBackend,
|
|
290
|
+
})
|
|
291
|
+
await manager.archive(sub.id, tenantA)
|
|
292
|
+
|
|
293
|
+
expect(captured).toHaveLength(1)
|
|
294
|
+
const bundle = captured[0] as {
|
|
295
|
+
messages: Array<{ id: string; at: Date; message: unknown }>
|
|
296
|
+
}
|
|
297
|
+
expect(bundle.messages).toHaveLength(2)
|
|
298
|
+
expect(bundle.messages[0]?.id).toBe(id1)
|
|
299
|
+
expect(bundle.messages[1]?.id).toBe(id2)
|
|
300
|
+
expect(bundle.messages[0]?.id).not.toMatch(/^msg_restored_/)
|
|
301
|
+
expect(bundle.messages[0]?.at).toBeInstanceOf(Date)
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
it('onArchived callback fires exactly once on success with the tombstone', async () => {
|
|
305
|
+
const { sub } = await seedIdleSubSession(store)
|
|
306
|
+
const onArchived = vi.fn()
|
|
307
|
+
const manager = new ArchivalManager({
|
|
308
|
+
sessionStore: store,
|
|
309
|
+
workspaceRegistry: buildRegistry(),
|
|
310
|
+
archiveBackend: backend,
|
|
311
|
+
onArchived,
|
|
312
|
+
})
|
|
313
|
+
const tombstone = await manager.archive(sub.id, tenantA)
|
|
314
|
+
|
|
315
|
+
expect(onArchived).toHaveBeenCalledTimes(1)
|
|
316
|
+
expect(onArchived).toHaveBeenCalledWith(tombstone)
|
|
317
|
+
})
|
|
318
|
+
})
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from 'node:fs'
|
|
2
|
+
import { readFile, readdir } from 'node:fs/promises'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
6
|
+
import type { SessionMessage } from '../../../store/session/messages.js'
|
|
7
|
+
import type { MessageId, SessionId, TenantId } from '../../../types/ids/index.js'
|
|
8
|
+
import { createUserMessage } from '../../../types/message/index.js'
|
|
9
|
+
import type { SubSessionId, SummaryId, WorkspaceId } from '../../../types/session/ids.js'
|
|
10
|
+
import type { SessionSummaryRef } from '../../summary/ref.js'
|
|
11
|
+
import type { WorkspaceRef } from '../../workspace/ref.js'
|
|
12
|
+
import type { ArchiveBackendRef } from '../archive-backend-ref.js'
|
|
13
|
+
import { DiskArchiveBackend } from '../disk-backend.js'
|
|
14
|
+
|
|
15
|
+
const tenantA = 'tnt_alpha' as TenantId
|
|
16
|
+
|
|
17
|
+
function fakeSessionId(): SessionId {
|
|
18
|
+
return 'ses_fake_1' as SessionId
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function fakeSubSessionId(): SubSessionId {
|
|
22
|
+
return 'sub_fake_1' as SubSessionId
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function buildMessages(sessionId: SessionId): SessionMessage[] {
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
id: 'msg_1' as MessageId,
|
|
29
|
+
sessionId,
|
|
30
|
+
tenantId: tenantA,
|
|
31
|
+
message: createUserMessage('hello'),
|
|
32
|
+
at: new Date('2026-04-01T00:00:00Z'),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'msg_2' as MessageId,
|
|
36
|
+
sessionId,
|
|
37
|
+
tenantId: tenantA,
|
|
38
|
+
message: createUserMessage('world'),
|
|
39
|
+
at: new Date('2026-04-01T00:01:00Z'),
|
|
40
|
+
},
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function buildSummary(sessionId: SessionId): SessionSummaryRef {
|
|
45
|
+
return {
|
|
46
|
+
id: 'sum_disk_archive_1' as SummaryId,
|
|
47
|
+
sessionRef: sessionId,
|
|
48
|
+
tenantId: tenantA,
|
|
49
|
+
outcome: { status: 'succeeded' },
|
|
50
|
+
deliverables: [],
|
|
51
|
+
agentSummary: 'done',
|
|
52
|
+
keyDecisions: [{ at: new Date('2026-04-01T00:00:30Z'), summary: 'decided x' }],
|
|
53
|
+
at: new Date('2026-04-01T00:02:00Z'),
|
|
54
|
+
materializedBy: 'kernel',
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function buildWorkspace(): WorkspaceRef {
|
|
59
|
+
return {
|
|
60
|
+
id: 'wsp_archive_1' as WorkspaceId,
|
|
61
|
+
meta: {
|
|
62
|
+
backend: 'git-worktree',
|
|
63
|
+
repoRoot: '/repo',
|
|
64
|
+
branch: 'feature/x',
|
|
65
|
+
worktreePath: '/repo/worktrees/x',
|
|
66
|
+
},
|
|
67
|
+
createdAt: new Date('2026-04-01T00:00:00Z'),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describe('DiskArchiveBackend', () => {
|
|
72
|
+
let rootDir: string
|
|
73
|
+
let backend: DiskArchiveBackend
|
|
74
|
+
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
rootDir = mkdtempSync(join(tmpdir(), 'namzu-archive-disk-'))
|
|
77
|
+
backend = new DiskArchiveBackend({ rootDir })
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
afterEach(() => {
|
|
81
|
+
rmSync(rootDir, { recursive: true, force: true })
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('store + restore round-trip preserves summary, messages, and subsession metadata', async () => {
|
|
85
|
+
const sessionId = fakeSessionId()
|
|
86
|
+
const subSessionId = fakeSubSessionId()
|
|
87
|
+
const messages = buildMessages(sessionId)
|
|
88
|
+
const summaryRef = buildSummary(sessionId)
|
|
89
|
+
const workspace = buildWorkspace()
|
|
90
|
+
|
|
91
|
+
const out = await backend.store({
|
|
92
|
+
subSessionId,
|
|
93
|
+
sessionId,
|
|
94
|
+
tenantId: tenantA,
|
|
95
|
+
workspace,
|
|
96
|
+
summaryRef,
|
|
97
|
+
messages,
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
expect(out.archiveRef).toMatch(/^arc_/)
|
|
101
|
+
expect(out.archivedAt).toBeInstanceOf(Date)
|
|
102
|
+
|
|
103
|
+
const restored = await backend.restore(out.archiveRef)
|
|
104
|
+
expect(restored.subSessionId).toBe(subSessionId)
|
|
105
|
+
expect(restored.sessionId).toBe(sessionId)
|
|
106
|
+
expect(restored.tenantId).toBe(tenantA)
|
|
107
|
+
expect(restored.workspace?.id).toBe(workspace.id)
|
|
108
|
+
expect(restored.summaryRef?.id).toBe(summaryRef.id)
|
|
109
|
+
expect(restored.summaryRef?.at).toBeInstanceOf(Date)
|
|
110
|
+
expect(restored.messages).toHaveLength(2)
|
|
111
|
+
expect(restored.messages[0]?.at).toBeInstanceOf(Date)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('archive location is under {rootDir}/archive/{arc_*}/', async () => {
|
|
115
|
+
const out = await backend.store({
|
|
116
|
+
subSessionId: fakeSubSessionId(),
|
|
117
|
+
sessionId: fakeSessionId(),
|
|
118
|
+
tenantId: tenantA,
|
|
119
|
+
messages: [],
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const archivesRoot = join(rootDir, 'archive')
|
|
123
|
+
const entries = await readdir(archivesRoot)
|
|
124
|
+
expect(entries).toContain(out.archiveRef)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('writes the archive.json marker last (atomic via tmp-rename; no stray .tmp after)', async () => {
|
|
128
|
+
const out = await backend.store({
|
|
129
|
+
subSessionId: fakeSubSessionId(),
|
|
130
|
+
sessionId: fakeSessionId(),
|
|
131
|
+
tenantId: tenantA,
|
|
132
|
+
messages: buildMessages(fakeSessionId()),
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const dir = join(rootDir, 'archive', out.archiveRef)
|
|
136
|
+
const entries = await readdir(dir)
|
|
137
|
+
expect(entries).toContain('archive.json')
|
|
138
|
+
expect(entries).toContain('subsession.json')
|
|
139
|
+
expect(entries).toContain('messages.jsonl')
|
|
140
|
+
// No lingering .tmp files from the write-tmp-rename sequence.
|
|
141
|
+
expect(entries.some((e) => e.endsWith('.tmp'))).toBe(false)
|
|
142
|
+
|
|
143
|
+
const marker = JSON.parse(await readFile(join(dir, 'archive.json'), 'utf-8'))
|
|
144
|
+
expect(marker.archiveRef).toBe(out.archiveRef)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('restore on missing archive throws ArchiveNotFoundError (reason: missing)', async () => {
|
|
148
|
+
await expect(backend.restore('arc_nonexistent' as ArchiveBackendRef)).rejects.toMatchObject({
|
|
149
|
+
name: 'ArchiveNotFoundError',
|
|
150
|
+
details: { reason: 'missing' },
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('multiple archives receive unique refs (no collisions)', async () => {
|
|
155
|
+
const refs = new Set<string>()
|
|
156
|
+
for (let i = 0; i < 5; i++) {
|
|
157
|
+
const out = await backend.store({
|
|
158
|
+
subSessionId: fakeSubSessionId(),
|
|
159
|
+
sessionId: fakeSessionId(),
|
|
160
|
+
tenantId: tenantA,
|
|
161
|
+
messages: [],
|
|
162
|
+
})
|
|
163
|
+
refs.add(out.archiveRef)
|
|
164
|
+
}
|
|
165
|
+
expect(refs.size).toBe(5)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('store without optional fields (no workspace, no summary, no messages) still round-trips', async () => {
|
|
169
|
+
const out = await backend.store({
|
|
170
|
+
subSessionId: fakeSubSessionId(),
|
|
171
|
+
sessionId: fakeSessionId(),
|
|
172
|
+
tenantId: tenantA,
|
|
173
|
+
messages: [],
|
|
174
|
+
})
|
|
175
|
+
const restored = await backend.restore(out.archiveRef)
|
|
176
|
+
expect(restored.workspace).toBeUndefined()
|
|
177
|
+
expect(restored.summaryRef).toBeUndefined()
|
|
178
|
+
expect(restored.messages).toHaveLength(0)
|
|
179
|
+
})
|
|
180
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branded lookup identifier for an archived sub-session in a pluggable
|
|
3
|
+
* {@link ArchiveBackend}. Produced by
|
|
4
|
+
* {@link ArchiveBackend.store} on a successful archival write and consumed by
|
|
5
|
+
* {@link ArchiveBackend.restore} to re-hydrate the bundle.
|
|
6
|
+
*
|
|
7
|
+
* Follows Convention #2 (`<prefix>_<opaque>` template literal brand). Prefix
|
|
8
|
+
* chosen as `arc_` to match the `archive` domain — short, unambiguous, and
|
|
9
|
+
* distinct from every existing prefix (`prj_`, `ses_`, `sub_`, `sum_`, …).
|
|
10
|
+
*
|
|
11
|
+
* The string after the prefix is opaque — backend-specific. A disk backend
|
|
12
|
+
* embeds it in a directory path; an object-store backend may encode a key;
|
|
13
|
+
* callers MUST NOT parse or pattern-match beyond the brand check.
|
|
14
|
+
*
|
|
15
|
+
* See session-hierarchy.md §12.3 Retention and Archival.
|
|
16
|
+
*/
|
|
17
|
+
export type ArchiveBackendRef = `arc_${string}`
|