@namzu/sdk 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +5 -3
- 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 +18 -5
- package/dist/agents/SupervisorAgent.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/task.d.ts +2 -2
- package/dist/bridge/a2a/task.d.ts.map +1 -1
- 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 +22 -3
- package/dist/contracts/api.d.ts.map +1 -1
- package/dist/contracts/index.d.ts +3 -1
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.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 +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- 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 +302 -0
- package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -0
- package/dist/manager/agent/lifecycle.d.ts +58 -3
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +311 -12
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +8 -1
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +15 -0
- package/dist/manager/run/persistence.js.map +1 -1
- 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 +84 -0
- package/dist/runtime/query/__tests__/context.test.js.map +1 -0
- package/dist/runtime/query/context.d.ts +55 -2
- package/dist/runtime/query/context.d.ts.map +1 -1
- package/dist/runtime/query/context.js +48 -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 +25 -2
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +11 -1
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/session/__tests__/integration/_fixtures.d.ts +115 -0
- package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -0
- package/dist/session/__tests__/integration/_fixtures.js +198 -0
- package/dist/session/__tests__/integration/_fixtures.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 +116 -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 +226 -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 +323 -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 +170 -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 +146 -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 +163 -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 +157 -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 +241 -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 +186 -0
- package/dist/session/__tests__/integration/retention-archive.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 +200 -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 +180 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -0
- package/dist/session/errors.d.ts +60 -0
- package/dist/session/errors.d.ts.map +1 -0
- package/dist/session/errors.js +50 -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 +243 -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 +100 -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 +230 -0
- package/dist/session/handoff/__tests__/single.test.js.map +1 -0
- package/dist/session/handoff/assignment.d.ts +59 -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 +47 -0
- package/dist/session/handoff/broadcast.d.ts.map +1 -0
- package/dist/session/handoff/broadcast.js +296 -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 +62 -0
- package/dist/session/handoff/single.d.ts.map +1 -0
- package/dist/session/handoff/single.js +217 -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 +67 -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 +8 -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 +59 -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/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 +98 -0
- package/dist/session/migration/id-prefix.d.ts.map +1 -0
- package/dist/session/migration/id-prefix.js +116 -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 +252 -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 +269 -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/conversation/memory.d.ts +22 -0
- package/dist/store/conversation/memory.d.ts.map +1 -1
- package/dist/store/conversation/memory.js +22 -0
- package/dist/store/conversation/memory.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 +240 -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 +217 -0
- package/dist/store/session/__tests__/memory.test.js.map +1 -0
- package/dist/store/session/disk.d.ts +85 -0
- package/dist/store/session/disk.d.ts.map +1 -0
- package/dist/store/session/disk.js +757 -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 +11 -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 +48 -0
- package/dist/store/session/memory.d.ts.map +1 -0
- package/dist/store/session/memory.js +322 -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/tools/builtins/__tests__/structuredOutput.example.d.ts +1 -1
- package/dist/types/agent/base.d.ts +28 -1
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +50 -2
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/agent/task.js.map +1 -1
- package/dist/types/conversation/index.d.ts +7 -0
- package/dist/types/conversation/index.d.ts.map +1 -1
- package/dist/types/ids/index.d.ts +26 -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/run/config.d.ts +11 -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 +24 -1
- 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 +18 -0
- package/dist/types/session/ids.d.ts.map +1 -0
- package/dist/types/session/ids.js +12 -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 +188 -0
- package/dist/types/session/store.d.ts.map +1 -0
- package/dist/types/session/store.js +14 -0
- package/dist/types/session/store.js.map +1 -0
- package/dist/utils/id.d.ts +18 -1
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +42 -4
- package/dist/utils/id.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/ReactiveAgent.ts +7 -3
- package/src/agents/RouterAgent.ts +5 -0
- package/src/agents/SupervisorAgent.ts +26 -6
- package/src/bridge/a2a/mapper.ts +7 -0
- package/src/bridge/a2a/task.ts +2 -2
- package/src/bridge/sse/mapper.ts +8 -1
- package/src/constants/a2a/index.ts +2 -2
- package/src/contracts/api.ts +23 -3
- package/src/contracts/index.ts +2 -0
- package/src/gateway/local.ts +6 -0
- package/src/index.ts +14 -0
- package/src/manager/agent/__tests__/lifecycle.test.ts +452 -0
- package/src/manager/agent/lifecycle.ts +434 -19
- package/src/manager/run/persistence.ts +20 -1
- package/src/run/reporter.ts +28 -0
- package/src/runtime/query/__tests__/context.test.ts +101 -0
- package/src/runtime/query/context.ts +106 -10
- package/src/runtime/query/events.ts +8 -0
- package/src/runtime/query/index.ts +41 -3
- package/src/session/__tests__/integration/_fixtures.ts +282 -0
- package/src/session/__tests__/integration/capacity-caps.test.ts +164 -0
- package/src/session/__tests__/integration/e2e-spawn.test.ts +278 -0
- package/src/session/__tests__/integration/event-stream-ordering.test.ts +403 -0
- package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +245 -0
- package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +179 -0
- package/src/session/__tests__/integration/handoff-single-e2e.test.ts +220 -0
- package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +237 -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 +318 -0
- package/src/session/__tests__/integration/retention-archive.test.ts +231 -0
- package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +237 -0
- package/src/session/__tests__/integration/tenant-isolation.test.ts +282 -0
- package/src/session/errors.ts +70 -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 +350 -0
- package/src/session/handoff/__tests__/capacity.test.ts +123 -0
- package/src/session/handoff/__tests__/single.test.ts +316 -0
- package/src/session/handoff/assignment.ts +62 -0
- package/src/session/handoff/broadcast.ts +381 -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 +288 -0
- package/src/session/handoff/version.ts +59 -0
- package/src/session/hierarchy/__tests__/session.test.ts +92 -0
- package/src/session/hierarchy/actor.ts +17 -0
- package/src/session/hierarchy/index.ts +17 -0
- package/src/session/hierarchy/lineage.ts +15 -0
- package/src/session/hierarchy/project.ts +41 -0
- package/src/session/hierarchy/session.ts +97 -0
- package/src/session/hierarchy/sub-session.ts +92 -0
- package/src/session/hierarchy/tenant.ts +13 -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 +146 -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 +316 -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 +341 -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/conversation/memory.ts +23 -0
- package/src/store/session/__tests__/disk.test.ts +346 -0
- package/src/store/session/__tests__/memory.test.ts +327 -0
- package/src/store/session/disk.ts +920 -0
- package/src/store/session/index.ts +14 -0
- package/src/store/session/linkage.ts +80 -0
- package/src/store/session/memory.ts +400 -0
- package/src/store/session/messages.ts +21 -0
- package/src/types/agent/base.ts +31 -1
- package/src/types/agent/task.ts +58 -2
- package/src/types/conversation/index.ts +7 -0
- package/src/types/ids/index.ts +41 -3
- package/src/types/invocation/__tests__/state.test.ts +37 -29
- package/src/types/invocation/index.ts +26 -10
- package/src/types/run/config.ts +12 -1
- package/src/types/run/events.ts +36 -1
- package/src/types/run/index.ts +8 -0
- package/src/types/run/metadata.ts +24 -1
- package/src/types/run/status.ts +33 -0
- package/src/types/session/ids.ts +34 -0
- package/src/types/session/index.ts +28 -0
- package/src/types/session/store.ts +229 -0
- package/src/utils/id.ts +55 -4
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-recipient (broadcast) handoff — atomic fan-out with compensating
|
|
3
|
+
* rollback.
|
|
4
|
+
*
|
|
5
|
+
* See session-hierarchy.md §6.2 (Multi-recipient broadcast flow — atomic),
|
|
6
|
+
* §5.4 (broadcast source-session post-fan-out), §6.5 (capacity enforcement).
|
|
7
|
+
*
|
|
8
|
+
* **Atomicity contract** — one transaction boundary: either the full fan-out
|
|
9
|
+
* commits (source CAS-lock + N assignments + N sub-sessions + N worktrees),
|
|
10
|
+
* or none of it is externally observable. On any step failure the kernel
|
|
11
|
+
* executes a compensating rollback and emits `onBroadcastRollback` with
|
|
12
|
+
* accurate `partialState` counts. The rollback itself is idempotent per
|
|
13
|
+
* roadmap Risk #3.
|
|
14
|
+
*
|
|
15
|
+
* Commit / rollback sequence (pattern doc §6.2):
|
|
16
|
+
* ```
|
|
17
|
+
* COMMIT: idle → locked(CAS) → N assignments → N sub-sessions → N worktrees → awaiting_merge
|
|
18
|
+
* ROLLBACK: ( ← tear down partial worktrees ← delete partial sub-sessions ←
|
|
19
|
+
* delete partial assignments ← release CAS ) emit broadcast.rollback;
|
|
20
|
+
* source → idle
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type { SessionId, TenantId } from '../../types/ids/index.js'
|
|
25
|
+
import type { SubSessionId } from '../../types/session/ids.js'
|
|
26
|
+
import type { SessionStore } from '../../types/session/store.js'
|
|
27
|
+
import { TenantIsolationError } from '../errors.js'
|
|
28
|
+
import type { Session } from '../hierarchy/session.js'
|
|
29
|
+
import type { WorkspaceBackendDriver } from '../workspace/driver.js'
|
|
30
|
+
import type { WorkspaceRef } from '../workspace/ref.js'
|
|
31
|
+
import type { WorkspaceBackendRegistry } from '../workspace/registry.js'
|
|
32
|
+
import type { HandoffAssignment, HandoffOutcome } from './assignment.js'
|
|
33
|
+
import type { CapacityValidator } from './capacity.js'
|
|
34
|
+
import type { HandoffEventSink } from './events.js'
|
|
35
|
+
import { NOOP_RUN_STATUS_RESOLVER, type RunStatusResolver } from './single.js'
|
|
36
|
+
import { HandoffLockRejected, HandoffVersionConflict } from './version.js'
|
|
37
|
+
|
|
38
|
+
export interface BroadcastHandoffDeps {
|
|
39
|
+
store: SessionStore
|
|
40
|
+
workspaceRegistry: WorkspaceBackendRegistry
|
|
41
|
+
capacity: CapacityValidator
|
|
42
|
+
events: HandoffEventSink
|
|
43
|
+
runStatus?: RunStatusResolver
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Per-recipient partial state tracked during fan-out so rollback can
|
|
48
|
+
* compensate exactly what was created. `subSessionId` is populated at the
|
|
49
|
+
* same step that creates the record so rollback can delete it in reverse
|
|
50
|
+
* order alongside the child session.
|
|
51
|
+
*/
|
|
52
|
+
interface RecipientPartial {
|
|
53
|
+
assignmentId: HandoffAssignment['id']
|
|
54
|
+
recipientActor: HandoffAssignment['recipientActor']
|
|
55
|
+
workspace: WorkspaceRef | null
|
|
56
|
+
createdSessionId: SessionId | null
|
|
57
|
+
createdSubSessionId: SubSessionId | null
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Executes a broadcast fan-out. All assignments MUST share the same
|
|
62
|
+
* `sourceSessionId`, `expectedOwnerVersion`, `broadcastId`, and `projectId`.
|
|
63
|
+
* Duplicate recipients (same actor kind + id) are rejected before any write.
|
|
64
|
+
*
|
|
65
|
+
* Returns one {@link HandoffOutcome} per recipient on success. On failure the
|
|
66
|
+
* source session is restored, every provisioned resource is torn down, and
|
|
67
|
+
* the underlying error propagates after `onBroadcastRollback` is emitted.
|
|
68
|
+
*/
|
|
69
|
+
export async function executeBroadcastHandoff(
|
|
70
|
+
deps: BroadcastHandoffDeps,
|
|
71
|
+
assignments: readonly HandoffAssignment[],
|
|
72
|
+
tenantId: TenantId,
|
|
73
|
+
): Promise<readonly HandoffOutcome[]> {
|
|
74
|
+
// 1. Shape validation -----------------------------------------------------
|
|
75
|
+
|
|
76
|
+
if (assignments.length === 0) {
|
|
77
|
+
throw new Error('executeBroadcastHandoff: assignments must not be empty')
|
|
78
|
+
}
|
|
79
|
+
if (assignments.length === 1) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
'executeBroadcastHandoff: single-recipient handoffs must use executeSingleHandoff',
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const first = assignments[0]
|
|
86
|
+
if (!first) throw new Error('executeBroadcastHandoff: assignments[0] undefined')
|
|
87
|
+
|
|
88
|
+
if (first.mode !== 'broadcast') {
|
|
89
|
+
throw new Error(`executeBroadcastHandoff: mode must be 'broadcast' (got '${first.mode}')`)
|
|
90
|
+
}
|
|
91
|
+
if (!first.broadcastId) {
|
|
92
|
+
throw new Error('executeBroadcastHandoff: broadcastId required on every assignment')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const a of assignments) {
|
|
96
|
+
if (a.tenantId !== tenantId) {
|
|
97
|
+
throw new TenantIsolationError({
|
|
98
|
+
requested: tenantId,
|
|
99
|
+
resource: `handoff-assignment(${a.id})`,
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
if (a.sourceSessionId !== first.sourceSessionId) {
|
|
103
|
+
throw new Error('executeBroadcastHandoff: all assignments must share sourceSessionId')
|
|
104
|
+
}
|
|
105
|
+
if (a.broadcastId !== first.broadcastId) {
|
|
106
|
+
throw new Error('executeBroadcastHandoff: all assignments must share broadcastId')
|
|
107
|
+
}
|
|
108
|
+
if (a.expectedOwnerVersion !== first.expectedOwnerVersion) {
|
|
109
|
+
throw new Error('executeBroadcastHandoff: all assignments must share expectedOwnerVersion')
|
|
110
|
+
}
|
|
111
|
+
if (a.projectId !== first.projectId) {
|
|
112
|
+
throw new Error('executeBroadcastHandoff: all assignments must share projectId')
|
|
113
|
+
}
|
|
114
|
+
if (a.mode !== 'broadcast') {
|
|
115
|
+
throw new Error('executeBroadcastHandoff: every assignment must have mode="broadcast"')
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 2. Dedupe recipients — same concern as the collab doc's Codex R: two rows
|
|
120
|
+
// targeting the same actor would produce duplicate sub-sessions + racy
|
|
121
|
+
// worktree paths. Reject before any side effect.
|
|
122
|
+
const seen = new Set<string>()
|
|
123
|
+
for (const a of assignments) {
|
|
124
|
+
const key = recipientKey(a.recipientActor)
|
|
125
|
+
if (seen.has(key)) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
`executeBroadcastHandoff: duplicate recipient detected (${key}). Dedupe before submitting.`,
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
seen.add(key)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 3. Load source + tenant check.
|
|
134
|
+
const source = await deps.store.getSession(first.sourceSessionId, tenantId)
|
|
135
|
+
if (!source) {
|
|
136
|
+
throw new Error(`Source session ${first.sourceSessionId} not found`)
|
|
137
|
+
}
|
|
138
|
+
if (source.tenantId !== tenantId) {
|
|
139
|
+
throw new TenantIsolationError({
|
|
140
|
+
requested: tenantId,
|
|
141
|
+
resource: `session(${source.id})`,
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
if (source.projectId !== first.projectId) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Assignment projectId ${first.projectId} does not match source projectId ${source.projectId}`,
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 4. Status check.
|
|
151
|
+
if (source.status !== 'idle') {
|
|
152
|
+
throw new HandoffLockRejected({
|
|
153
|
+
sessionId: source.id,
|
|
154
|
+
reason:
|
|
155
|
+
source.status === 'active'
|
|
156
|
+
? 'active_run'
|
|
157
|
+
: source.status === 'awaiting_hitl'
|
|
158
|
+
? 'pending_hitl'
|
|
159
|
+
: 'pending_subsession',
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 5. Non-terminal Run fan-in (§5.1).
|
|
164
|
+
const runResolver = deps.runStatus ?? NOOP_RUN_STATUS_RESOLVER
|
|
165
|
+
const blocking = await runResolver.blockingRun(source.id, tenantId)
|
|
166
|
+
if (blocking) {
|
|
167
|
+
throw new HandoffLockRejected({ sessionId: source.id, reason: blocking.reason })
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 6. Capacity — width + depth. Width covers N new children in one shot
|
|
171
|
+
// (§6.5); depth covers `source.depth + 1 ≤ maxDepth`.
|
|
172
|
+
const project = await deps.store.getProject(source.projectId, tenantId)
|
|
173
|
+
if (!project) {
|
|
174
|
+
throw new Error(`Project ${source.projectId} not found`)
|
|
175
|
+
}
|
|
176
|
+
await deps.capacity.validateWidth(
|
|
177
|
+
source.id,
|
|
178
|
+
assignments.length,
|
|
179
|
+
project.config.maxDelegationWidth,
|
|
180
|
+
tenantId,
|
|
181
|
+
)
|
|
182
|
+
await deps.capacity.validateDepth(source.id, project.config.maxDelegationDepth, tenantId)
|
|
183
|
+
|
|
184
|
+
// 7. CAS → source `idle → locked`.
|
|
185
|
+
if (source.ownerVersion !== first.expectedOwnerVersion) {
|
|
186
|
+
throw new HandoffVersionConflict({
|
|
187
|
+
sessionId: source.id,
|
|
188
|
+
expected: first.expectedOwnerVersion,
|
|
189
|
+
actual: source.ownerVersion,
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const locked: Session = { ...source, status: 'locked' }
|
|
194
|
+
await deps.store.updateSession(locked, tenantId)
|
|
195
|
+
emit(deps.events.onLocked, { sessionId: source.id, at: new Date() })
|
|
196
|
+
|
|
197
|
+
// 8. Fan-out provisioning. Track per-recipient partial state so rollback
|
|
198
|
+
// can compensate precisely.
|
|
199
|
+
const partials: RecipientPartial[] = []
|
|
200
|
+
let assignmentsWritten = 0
|
|
201
|
+
let subsessionsCreated = 0
|
|
202
|
+
let worktreesProvisioned = 0
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
const driver: WorkspaceBackendDriver = deps.workspaceRegistry.get('git-worktree')
|
|
206
|
+
|
|
207
|
+
for (const assignment of assignments) {
|
|
208
|
+
// Per-recipient: new isolated workspace → new child session → new
|
|
209
|
+
// sub-session edge. Each sub-op advances the partial-state counters.
|
|
210
|
+
const partial: RecipientPartial = {
|
|
211
|
+
assignmentId: assignment.id,
|
|
212
|
+
recipientActor: assignment.recipientActor,
|
|
213
|
+
workspace: null,
|
|
214
|
+
createdSessionId: null,
|
|
215
|
+
createdSubSessionId: null,
|
|
216
|
+
}
|
|
217
|
+
partials.push(partial)
|
|
218
|
+
|
|
219
|
+
partial.workspace = await driver.create({ label: `broadcast-${assignment.id}` })
|
|
220
|
+
worktreesProvisioned += 1
|
|
221
|
+
|
|
222
|
+
const childSession = await deps.store.createSession(
|
|
223
|
+
{ projectId: source.projectId, currentActor: assignment.recipientActor },
|
|
224
|
+
tenantId,
|
|
225
|
+
)
|
|
226
|
+
partial.createdSessionId = childSession.id
|
|
227
|
+
|
|
228
|
+
const subSession = await deps.store.createSubSession(
|
|
229
|
+
{
|
|
230
|
+
parentSessionId: source.id,
|
|
231
|
+
childSessionId: childSession.id,
|
|
232
|
+
kind: 'user_handoff',
|
|
233
|
+
spawnedBy: assignment.sourceActor,
|
|
234
|
+
},
|
|
235
|
+
tenantId,
|
|
236
|
+
)
|
|
237
|
+
partial.createdSubSessionId = subSession.id
|
|
238
|
+
subsessionsCreated += 1
|
|
239
|
+
|
|
240
|
+
// "Assignments written" is the last per-recipient step — counts any
|
|
241
|
+
// recipient whose full row reached store-durable state.
|
|
242
|
+
assignmentsWritten += 1
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// 9. Commit source: `locked → awaiting_merge` (§5.4 — broadcast source is
|
|
246
|
+
// not `idle` until all recipients terminalize; coordinator role).
|
|
247
|
+
const committed: Session = {
|
|
248
|
+
...source,
|
|
249
|
+
status: 'awaiting_merge',
|
|
250
|
+
ownerVersion: source.ownerVersion + 1,
|
|
251
|
+
}
|
|
252
|
+
await deps.store.updateSession(committed, tenantId)
|
|
253
|
+
|
|
254
|
+
emit(deps.events.onCommitted, {
|
|
255
|
+
sessionId: source.id,
|
|
256
|
+
newVersion: committed.ownerVersion,
|
|
257
|
+
handoffIds: assignments.map((a) => a.id),
|
|
258
|
+
at: new Date(),
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
return partials.map<HandoffOutcome>((p) => {
|
|
262
|
+
if (!p.workspace || !p.createdSessionId) {
|
|
263
|
+
// Unreachable — success path populates both fields on every partial.
|
|
264
|
+
throw new Error(`Broadcast partial for ${p.assignmentId} missing post-commit fields`)
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
assignmentId: p.assignmentId,
|
|
268
|
+
newSessionId: p.createdSessionId,
|
|
269
|
+
workspaceId: p.workspace.id,
|
|
270
|
+
committedOwnerVersion: committed.ownerVersion,
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
} catch (failure) {
|
|
274
|
+
await rollbackBroadcast(deps, source, partials, tenantId, {
|
|
275
|
+
broadcastId: first.broadcastId,
|
|
276
|
+
reason: failure instanceof Error ? failure.message : String(failure),
|
|
277
|
+
assignmentsWritten,
|
|
278
|
+
subsessionsCreated,
|
|
279
|
+
worktreesProvisioned,
|
|
280
|
+
})
|
|
281
|
+
throw failure
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Compensating rollback — idempotent per Risk #3.
|
|
287
|
+
*
|
|
288
|
+
* Order (reverse of commit): tear down worktrees → delete partially created
|
|
289
|
+
* sub-sessions → delete partially created child sessions → release source
|
|
290
|
+
* CAS lock → emit `onBroadcastRollback`. Every sub-op swallows its own
|
|
291
|
+
* secondary error so the primary failure remains the surfaced cause.
|
|
292
|
+
*
|
|
293
|
+
* Phase 8 closed the Phase 4 Known Delta (INTERP #2): previous implementation
|
|
294
|
+
* flipped partial recipient sessions to `status: 'archived'` as a stopgap
|
|
295
|
+
* because the store had no `deleteSession` primitive. The store now exposes
|
|
296
|
+
* `deleteSession` + `deleteSubSession` (idempotent), so rollback is total —
|
|
297
|
+
* no orphan records remain.
|
|
298
|
+
*/
|
|
299
|
+
async function rollbackBroadcast(
|
|
300
|
+
deps: BroadcastHandoffDeps,
|
|
301
|
+
source: Session,
|
|
302
|
+
partials: readonly RecipientPartial[],
|
|
303
|
+
tenantId: TenantId,
|
|
304
|
+
meta: {
|
|
305
|
+
broadcastId: string
|
|
306
|
+
reason: string
|
|
307
|
+
assignmentsWritten: number
|
|
308
|
+
subsessionsCreated: number
|
|
309
|
+
worktreesProvisioned: number
|
|
310
|
+
},
|
|
311
|
+
): Promise<void> {
|
|
312
|
+
// a. Dispose any provisioned worktrees (idempotent by driver contract).
|
|
313
|
+
for (const partial of partials) {
|
|
314
|
+
if (!partial.workspace) continue
|
|
315
|
+
try {
|
|
316
|
+
const driver = deps.workspaceRegistry.get('git-worktree')
|
|
317
|
+
await driver.dispose(partial.workspace)
|
|
318
|
+
} catch {
|
|
319
|
+
// Idempotent — secondary failure must not mask the primary one.
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// b. Delete any partially created sub-sessions (reverse order of creation
|
|
324
|
+
// so child-side constraints release before the session below them).
|
|
325
|
+
for (const partial of partials) {
|
|
326
|
+
if (!partial.createdSubSessionId) continue
|
|
327
|
+
try {
|
|
328
|
+
await deps.store.deleteSubSession(partial.createdSubSessionId, tenantId)
|
|
329
|
+
} catch {
|
|
330
|
+
// Idempotent.
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// c. Delete partially created recipient sessions (total cleanup — pattern
|
|
335
|
+
// doc §6.2: fan-out is atomic, partial state is externally
|
|
336
|
+
// unobservable).
|
|
337
|
+
for (const partial of partials) {
|
|
338
|
+
if (!partial.createdSessionId) continue
|
|
339
|
+
try {
|
|
340
|
+
await deps.store.deleteSession(partial.createdSessionId, tenantId)
|
|
341
|
+
} catch {
|
|
342
|
+
// Idempotent.
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// d. Release source CAS — `locked → idle`, preserving ownerVersion.
|
|
347
|
+
try {
|
|
348
|
+
const reverted: Session = { ...source, status: 'idle' }
|
|
349
|
+
await deps.store.updateSession(reverted, tenantId)
|
|
350
|
+
} catch {
|
|
351
|
+
// Idempotent — the write-tmp-rename primitive is itself idempotent
|
|
352
|
+
// against the same payload.
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
emit(deps.events.onBroadcastRollback, {
|
|
356
|
+
sessionId: source.id,
|
|
357
|
+
broadcastId: meta.broadcastId,
|
|
358
|
+
reason: meta.reason,
|
|
359
|
+
partialState: {
|
|
360
|
+
assignmentsWritten: meta.assignmentsWritten,
|
|
361
|
+
subsessionsCreated: meta.subsessionsCreated,
|
|
362
|
+
worktreesProvisioned: meta.worktreesProvisioned,
|
|
363
|
+
},
|
|
364
|
+
at: new Date(),
|
|
365
|
+
})
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function recipientKey(actor: HandoffAssignment['recipientActor']): string {
|
|
369
|
+
switch (actor.kind) {
|
|
370
|
+
case 'user':
|
|
371
|
+
return `user:${actor.userId}`
|
|
372
|
+
case 'agent':
|
|
373
|
+
return `agent:${actor.agentId}`
|
|
374
|
+
case 'system':
|
|
375
|
+
return `system:${actor.role}`
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function emit<T>(handler: ((ev: T) => void) | undefined, event: T): void {
|
|
380
|
+
if (handler) handler(event)
|
|
381
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation capacity validation — depth + width caps applied at the kernel
|
|
3
|
+
* boundary before any write (session-hierarchy.md §6.5).
|
|
4
|
+
*
|
|
5
|
+
* Both `spawnSubSession()` and `broadcastHandoff()` call this module before
|
|
6
|
+
* committing; violations abort with typed {@link DelegationCapacityExceeded}
|
|
7
|
+
* and no partial writes occur (Convention #0: no workarounds; Convention #5:
|
|
8
|
+
* deny-by-default).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { SessionId, TenantId } from '../../types/ids/index.js'
|
|
12
|
+
import type { SessionStore } from '../../types/session/store.js'
|
|
13
|
+
|
|
14
|
+
/** Capacity dimension under validation. */
|
|
15
|
+
export type CapacityDimension = 'depth' | 'width'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Raised when a spawn / broadcast would exceed the project's configured
|
|
19
|
+
* capacity caps. The check is a precondition — no partial writes occur on
|
|
20
|
+
* violation (session-hierarchy.md §6.5).
|
|
21
|
+
*/
|
|
22
|
+
export class DelegationCapacityExceeded extends Error {
|
|
23
|
+
readonly details: {
|
|
24
|
+
dimension: CapacityDimension
|
|
25
|
+
current: number
|
|
26
|
+
limit: number
|
|
27
|
+
sessionId: SessionId
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
constructor(details: {
|
|
31
|
+
dimension: CapacityDimension
|
|
32
|
+
current: number
|
|
33
|
+
limit: number
|
|
34
|
+
sessionId: SessionId
|
|
35
|
+
}) {
|
|
36
|
+
super(
|
|
37
|
+
`Delegation capacity exceeded: ${details.dimension} ${details.current}/${details.limit} on ${details.sessionId}`,
|
|
38
|
+
)
|
|
39
|
+
this.name = 'DelegationCapacityExceeded'
|
|
40
|
+
this.details = details
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Capacity validator abstraction. Lets the handoff flows inject a validator
|
|
46
|
+
* without carrying the full {@link SessionStore} surface area into their
|
|
47
|
+
* dependency envelope (Convention #9: function-based flow keeps deps narrow).
|
|
48
|
+
*
|
|
49
|
+
* Both methods throw {@link DelegationCapacityExceeded} on violation and
|
|
50
|
+
* return void on success.
|
|
51
|
+
*/
|
|
52
|
+
export interface CapacityValidator {
|
|
53
|
+
/**
|
|
54
|
+
* Asserts `parentSession.depth + 1 ≤ projectMaxDepth`. Depth is computed by
|
|
55
|
+
* walking the ancestry via {@link SessionStore.getAncestry} — root-to-self
|
|
56
|
+
* length minus one equals the session's depth in the delegation tree.
|
|
57
|
+
*/
|
|
58
|
+
validateDepth(
|
|
59
|
+
parentSessionId: SessionId,
|
|
60
|
+
projectMaxDepth: number,
|
|
61
|
+
tenantId: TenantId,
|
|
62
|
+
): Promise<void>
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Asserts `existingDirectChildren + pendingNewChildren ≤ projectMaxWidth`
|
|
66
|
+
* under `parentSessionId`. The width cap applies to a single spawn call —
|
|
67
|
+
* a broadcast of N recipients passes `pendingNewChildren = N`.
|
|
68
|
+
*/
|
|
69
|
+
validateWidth(
|
|
70
|
+
parentSessionId: SessionId,
|
|
71
|
+
pendingNewChildren: number,
|
|
72
|
+
projectMaxWidth: number,
|
|
73
|
+
tenantId: TenantId,
|
|
74
|
+
): Promise<void>
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Default validator backed by {@link SessionStore}. Uses `getAncestry` for
|
|
79
|
+
* depth (root-to-self chain length) and `getChildren` for width (count of
|
|
80
|
+
* existing direct sub-sessions).
|
|
81
|
+
*/
|
|
82
|
+
export class DefaultCapacityValidator implements CapacityValidator {
|
|
83
|
+
constructor(private readonly store: SessionStore) {}
|
|
84
|
+
|
|
85
|
+
async validateDepth(
|
|
86
|
+
parentSessionId: SessionId,
|
|
87
|
+
projectMaxDepth: number,
|
|
88
|
+
tenantId: TenantId,
|
|
89
|
+
): Promise<void> {
|
|
90
|
+
const ancestry = await this.store.getAncestry(parentSessionId, tenantId)
|
|
91
|
+
// depth is 0-indexed — root session has depth 0. New child depth =
|
|
92
|
+
// ancestry length (root-to-parent inclusive).
|
|
93
|
+
const newDepth = ancestry.length
|
|
94
|
+
if (newDepth > projectMaxDepth) {
|
|
95
|
+
throw new DelegationCapacityExceeded({
|
|
96
|
+
dimension: 'depth',
|
|
97
|
+
current: newDepth,
|
|
98
|
+
limit: projectMaxDepth,
|
|
99
|
+
sessionId: parentSessionId,
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async validateWidth(
|
|
105
|
+
parentSessionId: SessionId,
|
|
106
|
+
pendingNewChildren: number,
|
|
107
|
+
projectMaxWidth: number,
|
|
108
|
+
tenantId: TenantId,
|
|
109
|
+
): Promise<void> {
|
|
110
|
+
const existing = await this.store.getChildren(parentSessionId, tenantId)
|
|
111
|
+
const total = existing.length + pendingNewChildren
|
|
112
|
+
if (total > projectMaxWidth) {
|
|
113
|
+
throw new DelegationCapacityExceeded({
|
|
114
|
+
dimension: 'width',
|
|
115
|
+
current: total,
|
|
116
|
+
limit: projectMaxWidth,
|
|
117
|
+
sessionId: parentSessionId,
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HandoffEventSink — pluggable event sink for Phase 4.
|
|
3
|
+
*
|
|
4
|
+
* Phase 4 does NOT extend `RunEvent` with handoff variants (they land in a
|
|
5
|
+
* later phase that wires the full `SessionHierarchyEvent` union referenced
|
|
6
|
+
* by roadmap §1). In the meantime the flow functions invoke this sink so
|
|
7
|
+
* consumers + tests can observe state transitions without a concrete event
|
|
8
|
+
* bus. Every callback is optional; {@link NOOP_HANDOFF_SINK} is the
|
|
9
|
+
* deny-by-default instance to pass when observation is not needed.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { SessionId } from '../../types/ids/index.js'
|
|
13
|
+
import type { HandoffId } from '../../types/session/ids.js'
|
|
14
|
+
|
|
15
|
+
/** Fired when a source session transitions `idle → locked` for handoff. */
|
|
16
|
+
export interface HandoffLockedEvent {
|
|
17
|
+
sessionId: SessionId
|
|
18
|
+
at: Date
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Fired when a compensating rollback returns a source session
|
|
23
|
+
* `locked → idle` (either CAS failure or downstream provisioning failure).
|
|
24
|
+
*/
|
|
25
|
+
export interface HandoffUnlockedEvent {
|
|
26
|
+
sessionId: SessionId
|
|
27
|
+
at: Date
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Fired once per handoff commit. For `single` the `handoffIds` array has one
|
|
32
|
+
* entry; for `broadcast` it contains every recipient's assignment id.
|
|
33
|
+
*/
|
|
34
|
+
export interface HandoffCommittedEvent {
|
|
35
|
+
sessionId: SessionId
|
|
36
|
+
newVersion: number
|
|
37
|
+
handoffIds: readonly HandoffId[]
|
|
38
|
+
at: Date
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Fired when a broadcast fan-out mid-flight rolls back. `partialState` carries
|
|
43
|
+
* the per-stage counts of resources that were provisioned before the failure
|
|
44
|
+
* was detected — consumers can correlate with their own observability signals
|
|
45
|
+
* to verify the rollback is complete.
|
|
46
|
+
*/
|
|
47
|
+
export interface HandoffBroadcastRollbackEvent {
|
|
48
|
+
sessionId: SessionId
|
|
49
|
+
broadcastId: string
|
|
50
|
+
reason: string
|
|
51
|
+
partialState: {
|
|
52
|
+
assignmentsWritten: number
|
|
53
|
+
subsessionsCreated: number
|
|
54
|
+
worktreesProvisioned: number
|
|
55
|
+
}
|
|
56
|
+
at: Date
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Pluggable observer interface. All callbacks optional; consumers implement
|
|
61
|
+
* only what they need (Convention #5 deny-by-default applies to event
|
|
62
|
+
* consumers too — they must opt in explicitly).
|
|
63
|
+
*/
|
|
64
|
+
export interface HandoffEventSink {
|
|
65
|
+
onLocked?(ev: HandoffLockedEvent): void
|
|
66
|
+
onUnlocked?(ev: HandoffUnlockedEvent): void
|
|
67
|
+
onCommitted?(ev: HandoffCommittedEvent): void
|
|
68
|
+
onBroadcastRollback?(ev: HandoffBroadcastRollbackEvent): void
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** No-op sink — inject when the caller does not need handoff observability. */
|
|
72
|
+
export const NOOP_HANDOFF_SINK: HandoffEventSink = Object.freeze({})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Sub-barrel for the handoff state machine (Convention #4).
|
|
2
|
+
// Concrete flow functions + types live in sibling files; re-export the public
|
|
3
|
+
// surface here. See session-hierarchy.md §6.
|
|
4
|
+
|
|
5
|
+
export type { HandoffAssignment, HandoffMode, HandoffOutcome } from './assignment.js'
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
DefaultCapacityValidator,
|
|
9
|
+
DelegationCapacityExceeded,
|
|
10
|
+
} from './capacity.js'
|
|
11
|
+
export type { CapacityDimension, CapacityValidator } from './capacity.js'
|
|
12
|
+
|
|
13
|
+
export { HandoffLockRejected, HandoffVersionConflict } from './version.js'
|
|
14
|
+
export type { HandoffLockRejectedReason } from './version.js'
|
|
15
|
+
|
|
16
|
+
export { NOOP_HANDOFF_SINK } from './events.js'
|
|
17
|
+
export type {
|
|
18
|
+
HandoffBroadcastRollbackEvent,
|
|
19
|
+
HandoffCommittedEvent,
|
|
20
|
+
HandoffEventSink,
|
|
21
|
+
HandoffLockedEvent,
|
|
22
|
+
HandoffUnlockedEvent,
|
|
23
|
+
} from './events.js'
|
|
24
|
+
|
|
25
|
+
export { executeSingleHandoff, NOOP_RUN_STATUS_RESOLVER } from './single.js'
|
|
26
|
+
export type { RunStatusResolver, SingleHandoffDeps } from './single.js'
|
|
27
|
+
|
|
28
|
+
export { executeBroadcastHandoff } from './broadcast.js'
|
|
29
|
+
export type { BroadcastHandoffDeps } from './broadcast.js'
|