@sema-agent/server 7.146.0 → 7.147.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/MIGRATION.md +384 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +170 -66
- package/deploy/facts/lanes.json +7 -0
- package/deploy/sema-up/README.md +2 -2
- package/deploy/sema-up/chart/templates/_helpers.tpl +22 -0
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
- package/deploy/sema-up/chart/templates/server.yaml +5 -4
- package/deploy/sema-up/chart/values.yaml +1 -1
- package/deploy/sema-up/cluster-up.sh +2 -1
- package/deploy/sema-up/lib/flagshape.sh +4 -0
- package/deploy/sema-up/lib/lanes.json +2 -5
- package/deploy/sema-up/sema-up.sh +12 -9
- package/deploy/sema-up/stack/compose.yaml +5 -4
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -3
- package/dist/approval-card.d.ts +4 -4
- package/dist/approval.d.ts +3 -3
- package/dist/audit.js +2 -2
- package/dist/bench/s1/live-deps.js +3 -1
- package/dist/boot/crash-last.js +2 -1
- package/dist/boot/device-lane.js +5 -5
- package/dist/boot/engine-lease.d.ts +12 -11
- package/dist/boot/execution-env.d.ts +2 -1
- package/dist/boot/execution-env.js +45 -33
- package/dist/boot/execution-lane.d.ts +37 -9
- package/dist/boot/execution-lane.js +74 -20
- package/dist/boot/exit-boundary.d.ts +1 -1
- package/dist/boot/exit-last.js +2 -1
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/leader.js +1 -1
- package/dist/boot/memory-boundary.d.ts +11 -11
- package/dist/boot/memory-boundary.js +3 -3
- package/dist/boot/memory-consolidation.d.ts +13 -24
- package/dist/boot/memory-consolidation.js +0 -13
- package/dist/boot/org-memory.js +3 -2
- package/dist/boot/parked-revive-gate.d.ts +1 -1
- package/dist/boot/parked-revive-gate.js +1 -1
- package/dist/boot/reapers.js +1 -1
- package/dist/boot/resolve-spec.js +91 -111
- package/dist/boot/retention-lane.d.ts +4 -42
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +8 -2
- package/dist/boot/stage-01-config.d.ts +1 -1
- package/dist/boot/stage-01-config.js +6 -2
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
- package/dist/boot/stage-02-web-admin-pull.js +10 -8
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +2 -2
- package/dist/boot/stage-05-execution-env.js +3 -3
- package/dist/boot/stage-06-runners.d.ts +3 -3
- package/dist/boot/stage-06-runners.js +1 -3
- package/dist/boot/stage-07-capability-layer.d.ts +3 -3
- package/dist/boot/stage-07-capability-layer.js +4 -9
- package/dist/boot/stage-08-reapers.d.ts +3 -3
- package/dist/boot/stage-09-leader.d.ts +4 -3
- package/dist/boot/stage-10-http-server.d.ts +4 -3
- package/dist/boot/stage-10-http-server.js +2 -1
- package/dist/boot/stores.d.ts +9 -0
- package/dist/boot/stores.js +18 -7
- package/dist/boot/web-admin.js +3 -3
- package/dist/capabilities/center-plugins.d.ts +2 -0
- package/dist/capabilities/center-plugins.js +6 -2
- package/dist/capabilities/composite-members.d.ts +1 -0
- package/dist/capabilities/composite-members.js +1 -0
- package/dist/capabilities/execution-lane.d.ts +7 -7
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +1 -1
- package/dist/capabilities/scenarios.d.ts +32 -18
- package/dist/capabilities/scenarios.js +13 -9
- package/dist/capabilities/settings-contract.d.ts +29 -0
- package/dist/capabilities/settings-contract.js +14 -0
- package/dist/capabilities/skills.d.ts +5 -5
- package/dist/capability-facts.d.ts +38 -0
- package/dist/capability-facts.js +34 -1
- package/dist/center-credential-renewer.js +3 -2
- package/dist/config-catalog.js +6 -5
- package/dist/config-invariants.d.ts +18 -3
- package/dist/config-invariants.js +36 -19
- package/dist/config-lkg.d.ts +1 -1
- package/dist/config-lkg.js +5 -6
- package/dist/config-provider.js +2 -0
- package/dist/config-types.d.ts +190 -186
- package/dist/config.d.ts +68 -5
- package/dist/config.js +80 -54
- package/dist/degenerate-instrument.js +1 -1
- package/dist/deploy-facts.js +3 -2
- package/dist/deployment-shape.d.ts +21 -12
- package/dist/deployment-shape.js +24 -6
- package/dist/env-facts.d.ts +7 -5
- package/dist/env-facts.js +10 -6
- package/dist/execution-config-root.d.ts +5 -5
- package/dist/execution-config-root.js +5 -5
- package/dist/execution-env-purpose.d.ts +14 -0
- package/dist/execution-env-purpose.js +29 -0
- package/dist/execution-lane-caps.d.ts +49 -86
- package/dist/execution-lane-caps.js +52 -62
- package/dist/execution-placement.d.ts +18 -2
- package/dist/execution-placement.js +19 -0
- package/dist/file-history-disclosure.d.ts +2 -2
- package/dist/fleet/drain-entry.d.ts +17 -10
- package/dist/fleet/drain-entry.js +1 -1
- package/dist/fleet/serving-lease.js +3 -4
- package/dist/history-anchor.d.ts +22 -0
- package/dist/history-anchor.js +14 -0
- package/dist/hooks/command-spawn.d.ts +1 -4
- package/dist/hooks/command-spawn.js +0 -11
- package/dist/hooks/hook-runner.d.ts +52 -8
- package/dist/hooks/hook-runner.js +160 -36
- package/dist/http/approval-sweeps.d.ts +2 -5
- package/dist/http/approval-sweeps.js +3 -2
- package/dist/http/checkpoint-ctx.d.ts +17 -0
- package/dist/http/checkpoint-ctx.js +6 -0
- package/dist/http/claim-latency.d.ts +10 -0
- package/dist/http/claim-latency.js +12 -0
- package/dist/http/dispatch.js +1 -1
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/execution-context.d.ts +3 -1
- package/dist/http/execution-context.js +4 -0
- package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/memory-store-refusal-reply.d.ts +3 -3
- package/dist/http/memory-store-refusal-reply.js +3 -0
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +7 -4
- package/dist/http/principal-gate.d.ts +3 -14
- package/dist/http/principal-gate.js +0 -13
- package/dist/http/request-guards.d.ts +1 -1
- package/dist/http/resume-legs.d.ts +7 -10
- package/dist/http/resume-legs.js +79 -50
- package/dist/http/rewind-files-reply.d.ts +34 -0
- package/dist/http/rewind-files-reply.js +36 -0
- package/dist/http/route-ctx.d.ts +32 -16
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/approvals-assistant.js +5 -25
- package/dist/http/routes/capabilities.js +8 -2
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -1
- package/dist/http/routes/projects.d.ts +70 -0
- package/dist/http/routes/projects.js +86 -0
- package/dist/http/routes/rules.js +30 -2
- package/dist/http/routes/runs.js +8 -8
- package/dist/http/routes/session-sync.js +27 -10
- package/dist/http/routes/sessions.d.ts +7 -1
- package/dist/http/routes/sessions.js +104 -2
- package/dist/http/routes/tasks.js +9 -3
- package/dist/http/server.d.ts +24 -10
- package/dist/http/server.js +17 -6
- package/dist/http/stored-body-replay.d.ts +5 -3
- package/dist/http/stored-body-replay.js +10 -1
- package/dist/http/wire-types.d.ts +19 -10
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/instruction-source-notice.d.ts +1 -1
- package/dist/memory-embedder-reembed.d.ts +38 -0
- package/dist/memory-embedder-reembed.js +20 -0
- package/dist/memory-incident-sink.d.ts +0 -28
- package/dist/memory-incident-sink.js +5 -0
- package/dist/memory-scope.d.ts +2 -2
- package/dist/memory-scope.js +1 -1
- package/dist/memory-store-refusal.d.ts +17 -4
- package/dist/memory-store-refusal.js +1 -1
- package/dist/memory-sync-client.d.ts +2 -0
- package/dist/memory-sync-client.js +13 -11
- package/dist/memory-sync.js +1 -1
- package/dist/model-compat.d.ts +35 -21
- package/dist/model-compat.js +49 -21
- package/dist/model-entry-refusal.d.ts +11 -1
- package/dist/model-entry-refusal.js +7 -0
- package/dist/namespaced-rule-name.d.ts +18 -1
- package/dist/namespaced-rule-name.js +12 -0
- package/dist/observability/fail-open.d.ts +17 -9
- package/dist/observability/fail-open.js +17 -9
- package/dist/observability/metrics.d.ts +2 -0
- package/dist/observability/metrics.js +2 -0
- package/dist/observability/secret-env-scrub.d.ts +30 -4
- package/dist/observability/secret-env-scrub.js +15 -3
- package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
- package/dist/orchestration/workflow-agent-session-index.js +1 -6
- package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
- package/dist/orchestration/workflow-completion-inbox.js +63 -45
- package/dist/org-memory-admission.d.ts +5 -2
- package/dist/org-memory-admission.js +25 -10
- package/dist/parked-decide.d.ts +33 -26
- package/dist/parked-decide.js +36 -44
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +37 -4
- package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
- package/dist/plugins/approval-ask-store-memory.js +11 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
- package/dist/plugins/approval-ask-store-sql.js +3 -1
- package/dist/plugins/blob-backend.d.ts +38 -195
- package/dist/plugins/blob-backend.js +33 -229
- package/dist/plugins/caching-session-store.d.ts +9 -4
- package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
- package/dist/plugins/checkpoint-index-columns.js +3 -2
- package/dist/plugins/checkpoint-store-face.d.ts +1 -1
- package/dist/plugins/device-store-sql.d.ts +2 -2
- package/dist/plugins/device-store-sql.js +5 -10
- package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
- package/dist/plugins/execution-lane-rename-m40.js +10 -0
- package/dist/plugins/execution-placement-sql.d.ts +63 -88
- package/dist/plugins/execution-placement-sql.js +94 -54
- package/dist/plugins/file-run-store.d.ts +26 -12
- package/dist/plugins/file-run-store.js +63 -63
- package/dist/plugins/imported-layer-root-retirement.d.ts +17 -8
- package/dist/plugins/imported-layer-root-retirement.js +4 -8
- package/dist/plugins/inbox-payload-column.d.ts +14 -0
- package/dist/plugins/inbox-payload-column.js +13 -0
- package/dist/plugins/local-checkpoint-store.d.ts +5 -0
- package/dist/plugins/local-checkpoint-store.js +11 -7
- package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
- package/dist/plugins/local-data-dir-modes-m39.js +182 -0
- package/dist/plugins/local-engine-high-water.d.ts +11 -0
- package/dist/plugins/local-engine-high-water.js +59 -0
- package/dist/plugins/local-session-store.d.ts +91 -25
- package/dist/plugins/local-session-store.js +124 -45
- package/dist/plugins/local-task-attachment-store.d.ts +2 -0
- package/dist/plugins/local-task-attachment-store.js +10 -11
- package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
- package/dist/plugins/memory-embedder-fingerprint.js +52 -12
- package/dist/plugins/memory-embedder.d.ts +1 -1
- package/dist/plugins/memory-embedder.js +2 -2
- package/dist/plugins/memory-engine-pg.d.ts +4 -3
- package/dist/plugins/memory-engine-pg.js +4 -4
- package/dist/plugins/memory-engine-sql-apply.d.ts +13 -4
- package/dist/plugins/memory-engine-sql-apply.js +1 -1
- package/dist/plugins/memory-engine-tidb.d.ts +8 -5
- package/dist/plugins/memory-engine-tidb.js +7 -8
- package/dist/plugins/one-time-migrations.d.ts +145 -35
- package/dist/plugins/one-time-migrations.js +272 -120
- package/dist/plugins/owner-only-file-mode.d.ts +29 -0
- package/dist/plugins/owner-only-file-mode.js +141 -0
- package/dist/plugins/permission-rule-store-file.d.ts +8 -8
- package/dist/plugins/permission-rule-store-file.js +14 -2
- package/dist/plugins/pg-pool.d.ts +2 -1
- package/dist/plugins/pg-pool.js +11 -4
- package/dist/plugins/release-version.d.ts +20 -0
- package/dist/plugins/release-version.js +28 -0
- package/dist/plugins/remote-env-adb.d.ts +20 -4
- package/dist/plugins/remote-env-adb.js +39 -11
- package/dist/plugins/remote-env-e2b.d.ts +12 -3
- package/dist/plugins/remote-env-e2b.js +6 -4
- package/dist/plugins/remote-env-host.d.ts +9 -1
- package/dist/plugins/remote-env-host.js +6 -5
- package/dist/plugins/remote-env-k8s.d.ts +5 -2
- package/dist/plugins/remote-env-k8s.js +15 -4
- package/dist/plugins/remote-env-local-docker.d.ts +4 -1
- package/dist/plugins/remote-env-local-docker.js +3 -3
- package/dist/plugins/remote-env-ssh.d.ts +8 -2
- package/dist/plugins/remote-env-ssh.js +26 -24
- package/dist/plugins/remote-shell.d.ts +59 -30
- package/dist/plugins/remote-shell.js +175 -62
- package/dist/plugins/retention-declaration.d.ts +37 -0
- package/dist/plugins/retention-declaration.js +9 -0
- package/dist/plugins/retention-deployment.d.ts +126 -0
- package/dist/plugins/retention-deployment.js +88 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
- package/dist/plugins/retention-lane-store-sql.js +103 -1
- package/dist/plugins/retention-sql.d.ts +29 -0
- package/dist/plugins/retention-sql.js +8 -0
- package/dist/plugins/schema-consistency.d.ts +0 -6
- package/dist/plugins/schema-consistency.js +1 -2
- package/dist/plugins/schema-ensure-legs.d.ts +1 -1
- package/dist/plugins/schema-ensure-legs.js +11 -1
- package/dist/plugins/session-ext-table.d.ts +74 -0
- package/dist/plugins/session-ext-table.js +121 -0
- package/dist/plugins/session-fork.d.ts +1 -1
- package/dist/plugins/session-row-sql.d.ts +8 -7
- package/dist/plugins/session-row-sql.js +15 -7
- package/dist/plugins/session-store-sql.d.ts +131 -0
- package/dist/plugins/session-store-sql.js +298 -0
- package/dist/plugins/session-workspace-cell.d.ts +2 -2
- package/dist/plugins/session-workspace-cell.js +2 -2
- package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
- package/dist/plugins/shared-memory-store-sql.js +13 -13
- package/dist/plugins/snapshot-bucket-presence.js +1 -1
- package/dist/plugins/sql-driver.d.ts +23 -7
- package/dist/plugins/sql-driver.js +41 -8
- package/dist/plugins/sql-errors.d.ts +5 -2
- package/dist/plugins/sql-errors.js +4 -0
- package/dist/plugins/store-backend.d.ts +35 -8
- package/dist/plugins/store-backend.js +184 -62
- package/dist/plugins/store-contracts.d.ts +9 -2
- package/dist/plugins/store-contracts.js +1 -0
- package/dist/plugins/task-attachment-store.d.ts +6 -8
- package/dist/plugins/task-attachment-store.js +15 -10
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/text-column-capacity.d.ts +21 -0
- package/dist/plugins/text-column-capacity.js +5 -0
- package/dist/plugins/tidb-pool.d.ts +3 -2
- package/dist/plugins/tidb-pool.js +19 -31
- package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
- package/dist/read-face-posture.d.ts +6 -6
- package/dist/read-face-posture.js +2 -2
- package/dist/request-value-closure.d.ts +5 -5
- package/dist/request-value-closure.js +1 -1
- package/dist/rules-consent.d.ts +41 -13
- package/dist/rules-consent.js +101 -53
- package/dist/run-local.js +17 -13
- package/dist/runs.d.ts +48 -30
- package/dist/runs.js +26 -16
- package/dist/runtime-caps-resolver.d.ts +15 -8
- package/dist/runtime-caps-resolver.js +14 -10
- package/dist/sealed-key-layout.d.ts +2 -3
- package/dist/sealed-key-layout.js +0 -1
- package/dist/sealed-key.js +7 -5
- package/dist/security.d.ts +5 -3
- package/dist/sema-config-dir.js +2 -2
- package/dist/server-secret-env.d.ts +2 -0
- package/dist/service-version.d.ts +2 -1
- package/dist/service-version.js +2 -2
- package/dist/session-error-wire.d.ts +1 -1
- package/dist/session-incarnation.d.ts +8 -5
- package/dist/session-resident-background.d.ts +85 -32
- package/dist/session-resident-background.js +75 -7
- package/dist/session-row.d.ts +1 -1
- package/dist/session-sync-kernel.d.ts +1 -1
- package/dist/session-workspace.d.ts +11 -2
- package/dist/session-workspace.js +5 -0
- package/dist/sighup-idle.d.ts +1 -1
- package/dist/store-posture.d.ts +2 -1
- package/dist/stored-request-hooks-m20.d.ts +3 -2
- package/dist/stored-request-hooks-m20.js +19 -14
- package/dist/stores-sql/blob-index-sql.d.ts +148 -0
- package/dist/stores-sql/blob-index-sql.js +154 -0
- package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
- package/dist/stores-sql/checkpoint-store-sql.js +11 -27
- package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
- package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
- package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +23 -76
- package/dist/{plugins → stores-sql}/pg-session-storage.js +80 -209
- package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
- package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
- package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
- package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
- package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
- package/dist/stores-sql/session-write-hooks.d.ts +59 -0
- package/dist/stores-sql/session-write-hooks.js +2 -0
- package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
- package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
- package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +32 -122
- package/dist/{plugins → stores-sql}/tidb-session-store.js +71 -171
- package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.js +1 -1
- package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
- package/dist/stores-sql/windowed-session-storage.js +61 -0
- package/dist/task-a2a.d.ts +7 -1
- package/dist/task-a2a.js +15 -14
- package/dist/task-cwd.d.ts +11 -3
- package/dist/task-cwd.js +17 -1
- package/dist/task-mcp.d.ts +10 -2
- package/dist/task-mcp.js +13 -16
- package/dist/task-settings.d.ts +9 -4
- package/dist/task-settings.js +17 -6
- package/dist/tool-approval.d.ts +21 -8
- package/dist/tool-approval.js +10 -6
- package/dist/trace/core-keyset-guard.d.ts +9 -3
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/exit-seat.d.ts +23 -1
- package/dist/trace/exit-seat.js +3 -0
- package/dist/trace/project.d.ts +33 -16
- package/dist/trace/project.js +12 -9
- package/dist/trace/redact.d.ts +1 -1
- package/dist/trace/redact.js +61 -73
- package/dist/trace/self-minted-wire.d.ts +263 -10
- package/dist/trace/self-minted-wire.js +90 -2
- package/dist/trace/sema-provenance.d.ts +45 -41
- package/dist/trace/sema-provenance.js +81 -10
- package/dist/trace/task-notification-facets.d.ts +70 -2
- package/dist/trace/task-notification-facets.js +71 -1
- package/dist/trace/wire-projection-faces.d.ts +38 -2
- package/dist/trace/wire-projection-faces.js +26 -1
- package/dist/unread-request-members.d.ts +66 -0
- package/dist/unread-request-members.js +41 -0
- package/dist/user-input-ledger.d.ts +2 -2
- package/dist/web-admin-client/apply-effective.js +22 -26
- package/dist/web-admin-client/candidate-gate.d.ts +35 -3
- package/dist/web-admin-client/candidate-gate.js +53 -5
- package/dist/web-admin-client/center-request.d.ts +4 -1
- package/dist/web-admin-client/center-request.js +2 -1
- package/dist/web-admin-client/effective-keys.js +0 -1
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/http-client.d.ts +1 -0
- package/dist/web-admin-client/http-client.js +17 -9
- package/dist/web-admin-client/restart-signal.js +5 -2
- package/dist/web-admin-client/skills-mcp.d.ts +20 -6
- package/dist/web-admin-client/skills-mcp.js +26 -21
- package/dist/web-admin-client/types.d.ts +34 -49
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
- package/package.json +13 -12
- package/scripts/drain-check-local.mjs +2 -28
- package/scripts/drain-check.mysql.sql +2 -18
- package/scripts/drain-check.pg.sql +2 -18
- package/wire-changes/server@7.147.0.json +813 -0
package/dist/http/route-ctx.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ import type { HostDecision } from "../host-decision.js";
|
|
|
19
19
|
import type { EntryProblem } from "../entry-problems.js";
|
|
20
20
|
import type { SessionOwnerCell } from "../security.js";
|
|
21
21
|
import type { SessionNotifyDoor } from "../session-notify-door.js";
|
|
22
|
-
import type { TaskStream, TaskSpec, TaskResult, QuestionAnswer, Checkpoint, CheckpointToken, ResumeOutcome, RunInternals, Runner, EngineNotice } from "@sema-agent/core";
|
|
22
|
+
import type { TaskStream, TaskSpec, TaskResult, QuestionAnswer, Checkpoint, CheckpointToken, ResumeOutcome, RunInternals, Runner, EngineNotice, PendingSteerInput } from "@sema-agent/core";
|
|
23
23
|
import type { FlatServiceDeps, RequestAuth } from "./server.js";
|
|
24
24
|
import type { TaskRequestBody, DecideBinding } from "./wire-types.js";
|
|
25
25
|
import type { IdempotencyCache, SubmitOutcome } from "./idempotency.js";
|
|
@@ -36,6 +36,7 @@ import type { PeerLease } from "../peer-seat.js";
|
|
|
36
36
|
import type { RootedTaskSpec } from "./execution-context.js";
|
|
37
37
|
import type { GateCommitment, GateSettlementEvidence } from "../gate-settlement.js";
|
|
38
38
|
import type { ResumeRestatement } from "./resume-restatement.js";
|
|
39
|
+
import type { RememberLaneCannotRecord } from "../parked-decide.js";
|
|
39
40
|
/** 跨域可变状态 = lens1 §C2 实测的那 8 条「运行期登记簿」,一个对象。
|
|
40
41
|
* [ref]:`cancelledViaVerb`(按 taskId 键控的「这次是取消动词」旁表)删除 —— 中止成因改挂在每条腿自己的
|
|
41
42
|
* {@link RunAbort} 句柄上(`inflightRuns` 的值),同寿同删,不再有一张与腿不同寿的旁表。 */
|
|
@@ -421,6 +422,7 @@ export interface PreparedPlanReview {
|
|
|
421
422
|
readonly sessionId: string;
|
|
422
423
|
readonly token: CheckpointToken;
|
|
423
424
|
readonly cp: Checkpoint;
|
|
425
|
+
/** 这条决断唯一的一次 ctx 读,**已盖过**续跑请求的重述键(缺席 = 存量体原样):存体预判判的、驱动段重建与写回读的都是这一份。 */
|
|
424
426
|
readonly ctx: CheckpointCtx;
|
|
425
427
|
}
|
|
426
428
|
/** 提交/续跑「腿」= 跨域共享的**有状态**长流程(不像 {@link RouteHelpers} 那样只依赖 deps/config:它们要写
|
|
@@ -459,14 +461,8 @@ export interface RouteLegs {
|
|
|
459
461
|
/** 这次决定落在哪一个动作上:调用方点名它看到的那一对(`boundCallId` + `boundInputHash`);缺任一 ⇒ 400 `decide_requires_binding`
|
|
460
462
|
* (判在门型守卫之后,判官 `decidedActionOf`)。本函数从不拿当前停驻行补。 */
|
|
461
463
|
binding: DecideBinding,
|
|
462
|
-
/**
|
|
463
|
-
|
|
464
|
-
* 载入 cp** 的可记工具名(`rememberableToolName`,非 tool_approval / AskUserQuestion / legacy null / [ref] 强制卡 ⇒ `null`
|
|
465
|
-
* = 无可记)一并回传,路由只对这个逐字落店。`overrideSessionId` = parked 腿的 root/host 会话 grant 锚。 */
|
|
466
|
-
onResumeCommitted?: (grant: {
|
|
467
|
-
overrideSessionId?: string;
|
|
468
|
-
rememberableToolName: string | null;
|
|
469
|
-
}) => Promise<void>,
|
|
464
|
+
/** 这次决定带着「本会话放行」请求({@link RememberSessionRequest})⇒ 本函数是它的**唯一铸点**,结局的 `rememberApplied` 是它的答({@link ResumeCheckpointOutcome})。 */
|
|
465
|
+
remember?: RememberSessionRequest,
|
|
470
466
|
/** [ref]:透传给 {@link DriveResumeArgs.acceptEarly}(200 受理语义)。HTTP `/decide` 腿传 `true`;
|
|
471
467
|
* 内部 D-D SLA deny-sweep 不传 —— 它没有在等响应的人,提前受理对它零收益而少一条同步失败面。 */
|
|
472
468
|
acceptEarly?: boolean,
|
|
@@ -477,7 +473,7 @@ export interface RouteLegs {
|
|
|
477
473
|
explicitOperator: boolean;
|
|
478
474
|
},
|
|
479
475
|
/** 续跑请求的重述键(`mcpServers` / `a2aPeers`),门读出并判过的那一份;缺席 = 冻结读法。语义属主 = `resume-restatement.ts` 顶注。 */
|
|
480
|
-
restatement?: ResumeRestatement): Promise<
|
|
476
|
+
restatement?: ResumeRestatement): Promise<ResumeCheckpointOutcome>;
|
|
481
477
|
/** 全 resume 家族的共同下半场(lease admission + 写 run log + fleet 发布)。 */
|
|
482
478
|
driveResumeIntoRunLog(args: DriveResumeArgs): Promise<ResumeLegOutcome>;
|
|
483
479
|
/** assistant 抢占腿的复位(gate-kind 守卫 + 行级属主复核 + 驱动)。 */
|
|
@@ -493,7 +489,9 @@ export interface RouteLegs {
|
|
|
493
489
|
/** 续跑请求的重述键(同 {@link RouteLegs.resumeCheckpoint} 末参)。 */
|
|
494
490
|
restatement?: ResumeRestatement): Promise<ResumeLegOutcome>;
|
|
495
491
|
/** notify-wake 域:唤醒一条 parked checkpoint。 */
|
|
496
|
-
resumeWake(sessionId: string,
|
|
492
|
+
resumeWake(sessionId: string,
|
|
493
|
+
/** 续跑首轮那段话连同框架位,由文本出处在铸点定好(HTTP `/wake` 正文 ⇒ `trusted: false`);语义属主 = `resume-legs.ts` 同名形参顶注。 */
|
|
494
|
+
message: PendingSteerInput | undefined, caller: string | undefined, req: IncomingMessage | undefined,
|
|
497
495
|
/** [ref] 件 S-1:透传给 {@link DriveResumeArgs.acceptEarly}(200 受理语义)。HTTP `/wake` 腿传 `true`
|
|
498
496
|
* —— 本腿走 `mintFreshRun`,受理体里的 `taskId` 因此是**新铸的**那个(壳的 poll 锚)。 */
|
|
499
497
|
acceptEarly?: boolean,
|
|
@@ -522,7 +520,9 @@ export interface RouteLegs {
|
|
|
522
520
|
explicitOperator: boolean;
|
|
523
521
|
},
|
|
524
522
|
/** [ref]:决断方看到的那道门(决断体的 `checkpointId`);不是当前门 ⇒ `409 approval_stale`(`approval_stale` 律,语义属主 = `resume-legs.ts` 的同名形参顶注)。 */
|
|
525
|
-
sighting?: GateSighting
|
|
523
|
+
sighting?: GateSighting,
|
|
524
|
+
/** 续跑请求的重述键(同 {@link RouteLegs.resumeCheckpoint} 末参):盖在这一次 ctx 读上,存体预判按盖过的体判。 */
|
|
525
|
+
restatement?: ResumeRestatement): Promise<{
|
|
526
526
|
readonly ok: false;
|
|
527
527
|
readonly answer: {
|
|
528
528
|
status: number;
|
|
@@ -540,9 +540,7 @@ export interface RouteLegs {
|
|
|
540
540
|
acceptEarly?: boolean,
|
|
541
541
|
/** [ref]:批准之后这条会话继续用的 permission mode(闭集 `PLAN_APPROVE_PERMISSION_MODES_AFTER`;只在把计划带出 plan 的决定
|
|
542
542
|
* —— `approve` / `edit` —— 上有意义,缺席 ⇒ `"default"`)。语义与判据的唯一属主 = `resume-legs.ts` 的同名形参顶注。 */
|
|
543
|
-
permissionModeAfter?: PlanApprovePermissionModeAfter
|
|
544
|
-
/** 续跑请求的重述键(同 {@link RouteLegs.resumeCheckpoint} 末参)。 */
|
|
545
|
-
restatement?: ResumeRestatement): Promise<ResumeLegOutcome>;
|
|
543
|
+
permissionModeAfter?: PlanApprovePermissionModeAfter): Promise<ResumeLegOutcome>;
|
|
546
544
|
/** 会话通知门(`POST /v1/sessions/:id/notify` 与 Runner 之外的后台子代完成共用的那一只;活流登记簿是本服务的,门随服务建一次)。 */
|
|
547
545
|
sessionNotify: SessionNotifyDoor;
|
|
548
546
|
}
|
|
@@ -694,7 +692,7 @@ interface RouteDeclIdentity {
|
|
|
694
692
|
readonly methods: readonly RouteMethod[];
|
|
695
693
|
/**
|
|
696
694
|
* 「这条 GET 开的是一条**只读订阅**」—— 一条 SSE 读面(推送队列 / 账本 tail),它看着别人干活,自己不是活([ref])。
|
|
697
|
-
* 在场 ⇒ 分派器不把它记进在飞(`
|
|
695
|
+
* 在场 ⇒ 分派器不把它记进在飞(`http` 项:`/health.inflight` 报的总数与排空等的、SIGHUP 空闲窗与附着租约读的阻断集都从它起算),只记进附着
|
|
698
696
|
* (`attachedStreams()`:壳还挂在这只引擎上);排空进入那一拍(以及硬停起点)由分派器发一帧 `draining` 终帧后关掉它
|
|
699
697
|
* (`drainState.endSubscriptions`)。闭集 = 八条 GET SSE 读面,逐行理由见各行注;**唯一**一条「在飞腿的流」`POST /v1/tasks/stream`
|
|
700
698
|
* 不带它 —— 那条流就是 sync 腿本身(关流 = 断连语义),照旧算在飞。漏标一条订阅的方向是**多算在飞**(排空多等),不是少等。
|
|
@@ -740,6 +738,24 @@ export interface ResumeLegOutcome {
|
|
|
740
738
|
status: number;
|
|
741
739
|
body: object;
|
|
742
740
|
}
|
|
741
|
+
/**
|
|
742
|
+
* 「本会话不再询问」的请求 —— **两扇门同一只**:`/decide` 体上的 `remember:"session"`、应答口(`POST /v1/tool-approvals/:id/respond`)命中停驻行的
|
|
743
|
+
* `allow_session`。铸点只有一只:{@link RouteLegs.resumeCheckpoint} —— 可记与否从**已属主校验的载入停驻行**判(`standingAnswerDurablyRecordable`,
|
|
744
|
+
* 与运维队列行的 `rememberRefused` 同一只判据)、锚由车道定(任务级 = 这个会话;bg 停驻子代 = 行的 root/host 会话)、落豁免店**只在**这次决定
|
|
745
|
+
* 被证明已结清之后(`decisionCommittedOf`)、`rememberApplied` = 落没落(店抛 ⇒ `false` + warn,这次的放行不回滚)。门自己不写店、不判可记。
|
|
746
|
+
* 两口唯一的差 = `laneCannotRecord`(记不住的车道上怎么答;闭集与理由的属主 = `parked-decide.ts` 的 {@link RememberLaneCannotRecord})。
|
|
747
|
+
*/
|
|
748
|
+
export interface RememberSessionRequest {
|
|
749
|
+
/** 豁免行的签发人(`grantedBy`)= 门已验的身份(`/decide` 的决断方 / 应答口的调用方);匿名开放部署 ⇒ `null`。 */
|
|
750
|
+
readonly grantedBy: string | null;
|
|
751
|
+
readonly laneCannotRecord: RememberLaneCannotRecord;
|
|
752
|
+
}
|
|
753
|
+
/** {@link RouteLegs.resumeCheckpoint} 的结局 = 腿的应答 + 带了「本会话放行」请求时铸点的答(`rememberApplied`:落没落)。键只在证得出提交的两条车道
|
|
754
|
+
* (bg 停驻子代赎回 / 任务级续跑)的结清点上铸;其余出口(拒 / workflow 投递 / 抛)键缺席 ⇒ 门读作「没记住」(`=== true`)。
|
|
755
|
+
* 这一位是进程内的结局位,不进 `body` —— 由门决定挂不挂到回执上(两扇门都只挂在这次真做了授予判定的回执上;幂等回放不挂)。 */
|
|
756
|
+
export type ResumeCheckpointOutcome = ResumeLegOutcome & {
|
|
757
|
+
readonly rememberApplied?: boolean;
|
|
758
|
+
};
|
|
743
759
|
/**
|
|
744
760
|
* **「决定/续跑已受理」那一枚 200 收据的单一铸点**([ref])。
|
|
745
761
|
*
|
package/dist/http/route-table.js
CHANGED
|
@@ -19,6 +19,7 @@ import { handlePrincipalInbox, PRINCIPAL_INBOX_ROUTES } from "./routes/principal
|
|
|
19
19
|
import { handleRules, RULES_ROUTES } from "./routes/rules.js";
|
|
20
20
|
import { handleSessionsList, SESSIONS_LIST_ROUTES } from "./routes/sessions-list.js";
|
|
21
21
|
import { handleAgentRoster, AGENT_ROSTER_ROUTES } from "./routes/agents-roster.js";
|
|
22
|
+
import { handleProjects, PROJECTS_ROUTES } from "./routes/projects.js";
|
|
22
23
|
import { handleSessions, SESSIONS_ROUTES } from "./routes/sessions.js";
|
|
23
24
|
import { handleSessionSync, SESSION_SYNC_ROUTES } from "./routes/session-sync.js";
|
|
24
25
|
import { handleAttachments, ATTACHMENTS_ROUTES } from "./routes/attachments.js";
|
|
@@ -81,6 +82,7 @@ export const ROUTES = [
|
|
|
81
82
|
row({ handler: handlePrincipalInbox, decls: PRINCIPAL_INBOX_ROUTES, position: "post-credential", label: "principal-inbox" }),
|
|
82
83
|
row({ handler: handleSessionsList, decls: SESSIONS_LIST_ROUTES, position: "post-credential", label: "sessions-list" }),
|
|
83
84
|
row({ handler: handleAgentRoster, decls: AGENT_ROSTER_ROUTES, position: "post-credential", label: "agent-roster" }),
|
|
85
|
+
row({ handler: handleProjects, decls: PROJECTS_ROUTES, position: "post-credential", label: "projects" }),
|
|
84
86
|
row({ handler: handleSessions, decls: SESSIONS_ROUTES, position: "post-credential", label: "sessions" }),
|
|
85
87
|
row({ handler: handleSessionSync, decls: SESSION_SYNC_ROUTES, position: "post-credential", label: "session-sync" }),
|
|
86
88
|
row({ handler: handleAttachments, decls: ATTACHMENTS_ROUTES, position: "post-credential", label: "attachments" }),
|
|
@@ -32,7 +32,7 @@ import { recordFailOpen } from "../../observability/fail-open.js";
|
|
|
32
32
|
import { MAX_CHECKPOINT_ID_CHARS, durableRowIdentity } from "../../checkpoint-identity.js";
|
|
33
33
|
import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "../../request-key-closure.js";
|
|
34
34
|
import { fieldConflictFacts } from "../../field-conflict.js";
|
|
35
|
-
import { buildSettlementEvidence
|
|
35
|
+
import { buildSettlementEvidence } from "../../gate-settlement.js";
|
|
36
36
|
import { seatText } from "../../trace/exit-seat.js";
|
|
37
37
|
import { approvalQueueKindOfDoorId } from "../../approval-queue-kind.js";
|
|
38
38
|
import { defaultPeerInboundFace, parsePeerInboundId, peerBoxScope } from "../../peer-inbound-face.js";
|
|
@@ -701,7 +701,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
701
701
|
sendError(res, 404, "not_found.run", "task not found");
|
|
702
702
|
return;
|
|
703
703
|
}
|
|
704
|
-
const plan = await preparePlanReview(run.sessionId, { taskId, principalPresent: principal !== undefined }, { principal: deciderPrincipal, explicitOperator }, sighting);
|
|
704
|
+
const plan = await preparePlanReview(run.sessionId, { taskId, principalPresent: principal !== undefined }, { principal: deciderPrincipal, explicitOperator }, sighting, restated.restatement);
|
|
705
705
|
if (!plan.ok) {
|
|
706
706
|
sendResumeOutcome(res, plan.answer, deps.logger);
|
|
707
707
|
return;
|
|
@@ -725,7 +725,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
725
725
|
return;
|
|
726
726
|
}
|
|
727
727
|
}
|
|
728
|
-
const out = await drivePlanReview(plan.prepared, decision, decision === "edit" ? body.editedPlan : undefined, typeof body.reason === "string" ? body.reason : undefined, hostDecisionFacts(decidedByReading.decider, deciderPrincipal), req, true, isPlanApprovePermissionModeAfter(body.permissionModeAfter) ? body.permissionModeAfter : undefined
|
|
728
|
+
const out = await drivePlanReview(plan.prepared, decision, decision === "edit" ? body.editedPlan : undefined, typeof body.reason === "string" ? body.reason : undefined, hostDecisionFacts(decidedByReading.decider, deciderPrincipal), req, true, isPlanApprovePermissionModeAfter(body.permissionModeAfter) ? body.permissionModeAfter : undefined);
|
|
729
729
|
sendResumeOutcome(res, out, deps.logger);
|
|
730
730
|
return;
|
|
731
731
|
}
|
|
@@ -893,27 +893,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
893
893
|
return;
|
|
894
894
|
}
|
|
895
895
|
}
|
|
896
|
-
|
|
897
|
-
let pendingGrant;
|
|
898
|
-
const grantOnCommit = remember && deps.approvalExemptionStore
|
|
899
|
-
? async (grant) => {
|
|
900
|
-
const canonical = grant.rememberableToolName;
|
|
901
|
-
if (!canonical)
|
|
902
|
-
return;
|
|
903
|
-
pendingGrant = { sessionId: grant.overrideSessionId ?? sessionId, toolName: canonical };
|
|
904
|
-
}
|
|
905
|
-
: undefined;
|
|
906
|
-
const out = await resumeCheckpoint(sessionId, decision, body.reason ?? undefined, hostDecisionFacts(decider, deciderPrincipal), req, answer, binding, grantOnCommit, true, { principal: deciderPrincipal, explicitOperator }, restated.restatement);
|
|
907
|
-
if (pendingGrant !== undefined && decisionCommittedOf(out) && deps.approvalExemptionStore) {
|
|
908
|
-
try {
|
|
909
|
-
await deps.approvalExemptionStore.grant(pendingGrant.sessionId, pendingGrant.toolName, deciderPrincipal ?? null);
|
|
910
|
-
rememberApplied = true;
|
|
911
|
-
deps.logger?.info?.("approval_exemption_granted", { sessionId: pendingGrant.sessionId, toolName: pendingGrant.toolName, grantedBy: deciderPrincipal ?? null });
|
|
912
|
-
}
|
|
913
|
-
catch (e) {
|
|
914
|
-
deps.logger?.warn?.("approval_exemption_grant_failed", { sessionId: pendingGrant.sessionId, toolName: pendingGrant.toolName, error: String(e).slice(0, 200) });
|
|
915
|
-
}
|
|
916
|
-
}
|
|
896
|
+
const out = await resumeCheckpoint(sessionId, decision, body.reason ?? undefined, hostDecisionFacts(decider, deciderPrincipal), req, answer, binding, remember ? { grantedBy: deciderPrincipal ?? null, laneCannotRecord: "refuse" } : undefined, true, { principal: deciderPrincipal, explicitOperator }, restated.restatement);
|
|
917
897
|
const replay = await decideIdempotentReplay(cs, {
|
|
918
898
|
sessionId,
|
|
919
899
|
out,
|
|
@@ -933,7 +913,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
933
913
|
sendResumeOutcome(res, replay, deps.logger);
|
|
934
914
|
return;
|
|
935
915
|
}
|
|
936
|
-
sendResumeOutcome(res, out, deps.logger, remember
|
|
916
|
+
sendResumeOutcome(res, out, deps.logger, remember ? { rememberApplied: out.rememberApplied === true } : undefined);
|
|
937
917
|
return;
|
|
938
918
|
}
|
|
939
919
|
}
|
|
@@ -25,6 +25,7 @@ import { projectWriteProtectionCapability } from "../../write-protection.js";
|
|
|
25
25
|
import { projectStoreCapability } from "../../store-posture.js";
|
|
26
26
|
import { projectWebSearchCapability } from "../../plugins/web-search.js";
|
|
27
27
|
import { projectExecutionLaneCapability } from "../../capabilities/execution-lane.js";
|
|
28
|
+
import { SETTINGS_CONTRACT_CAPABILITY } from "../../capabilities/settings-contract.js";
|
|
28
29
|
import { judgeSandboxGitPlane, sandboxGitPlanePremisesOf } from "../../sandbox-git-plane.js";
|
|
29
30
|
import { MCP_ASSERTION_HEADER_SENT, MCP_REQUEST_TRANSPORT_KINDS } from "../../mcp-assertion-header.js";
|
|
30
31
|
import { gateCompositeMembers } from "../../capabilities/composite-members.js";
|
|
@@ -96,10 +97,10 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
96
97
|
? {
|
|
97
98
|
enabled: true,
|
|
98
99
|
protocolVersion: DEVICE_PROTOCOL_VERSION,
|
|
99
|
-
maxInflightPerDevice: deps.config.remoteExec
|
|
100
|
+
maxInflightPerDevice: deps.config.remoteExec.provider === "device" ? (deps.config.remoteExec.maxInflightPerDevice ?? 4) : 4,
|
|
100
101
|
wsPath: DEVICE_WS_PATH,
|
|
101
102
|
management: facts.deviceManagement(deps).available,
|
|
102
|
-
...(deps.config.remoteExec
|
|
103
|
+
...(deps.config.remoteExec.provider === "device" && deps.config.remoteExec.relay.kind === "url" ? { relayUrl: deps.config.remoteExec.relay.url } : {}),
|
|
103
104
|
}
|
|
104
105
|
: false,
|
|
105
106
|
sessionEvents: facts.sessionEventStream(deps).available,
|
|
@@ -151,6 +152,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
151
152
|
subagentResume: facts.subagentSteer(deps).available,
|
|
152
153
|
taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: DEPLOYMENT_SHAPE_PREDICATES.callerCwd.holds(deps.config), hooks: taskHooksHonored(deps.config), pluginHooks: taskHooksHonored(deps.config), managedHookGroups: taskHooksHonored(deps.config), httpHookAllowlists: taskHooksHonored(deps.config), tightenOnlySeats: true, approvalFrameFamilies: true, autoCompactEnabled: true },
|
|
153
154
|
settings: { permissions: { allowGrant: true, allowLayer: true, layers: true, layeredAllow: true, callerTrust: callerTrust(req, deps.config).trust } },
|
|
155
|
+
settingsContract: SETTINGS_CONTRACT_CAPABILITY,
|
|
154
156
|
permissionModeAuto: {
|
|
155
157
|
accepted: true,
|
|
156
158
|
classifierSeat: deps.autoModeFace?.seatMounted === true,
|
|
@@ -204,6 +206,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
204
206
|
sessionReadRedaction: true,
|
|
205
207
|
sideQuery: true,
|
|
206
208
|
agentRoster: facts.agentRoster(deps).available,
|
|
209
|
+
projects: facts.projectRegistry(deps).available,
|
|
207
210
|
retention: retentionAdvertisement(deps.config),
|
|
208
211
|
peerLane: Boolean(deps.peerDirectory),
|
|
209
212
|
sessionList: facts.sessionList(deps).available,
|
|
@@ -217,6 +220,8 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
217
220
|
rewindFiles: Boolean(deps.fileHistoryStore),
|
|
218
221
|
restoreFiles: Boolean(deps.fileHistoryStore),
|
|
219
222
|
rewindFilesTo: Boolean(deps.fileHistoryStore && deps.resumeAnchorStore && headReadOf(deps.sessionStorage)),
|
|
223
|
+
sessionRewindFiles: facts.sessionRewindFiles(deps).available,
|
|
224
|
+
sessionRewindFilesPreview: facts.sessionRewindFilesPreview(deps).available,
|
|
220
225
|
fileHistoryCapture: fileHistoryCaptureOf(deps.fileHistoryStore, deps.config.fileHistoryCapture),
|
|
221
226
|
scheduler: facts.hostScheduler(deps.config).available,
|
|
222
227
|
sessionSync: facts.sessionSync(deps).available,
|
|
@@ -298,6 +303,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
298
303
|
...(m.maxTokens ? { maxOutputTokens: m.maxTokens } : {}),
|
|
299
304
|
...((levels) => (levels !== undefined ? { supportedEffortLevels: [...levels] } : {}))(reasoningEffortLevelsOf(m)),
|
|
300
305
|
...(m.compat !== undefined ? { compat: m.compat } : {}),
|
|
306
|
+
...(m.thinkingLevelMap !== undefined ? { thinkingLevelMap: m.thinkingLevelMap } : {}),
|
|
301
307
|
...mentionBit(name),
|
|
302
308
|
routePairing: routePairingOf(deps, name, m),
|
|
303
309
|
}));
|
|
@@ -163,7 +163,7 @@ export async function handleDevices(req, res, match, ctx) {
|
|
|
163
163
|
}
|
|
164
164
|
if ((await readClosedBody(req, res, readJson, [])) === null)
|
|
165
165
|
return;
|
|
166
|
-
const ttlSeconds = (deps.config.remoteExec
|
|
166
|
+
const ttlSeconds = (deps.config.remoteExec.provider === "device" ? deps.config.remoteExec.enrollTokenTtlSec : undefined) ?? DEFAULT_ENROLL_TOKEN_TTL_SEC;
|
|
167
167
|
const issued = await enrollment.issueEnrollToken({ target: domain, createdBy: domain.subject, ttlSeconds });
|
|
168
168
|
if (!issued.ok) {
|
|
169
169
|
sendDeviceRejection(res, issued.reject);
|
|
@@ -105,7 +105,7 @@ export declare function buildClearanceRowWire(r: OriginClearanceRow): {
|
|
|
105
105
|
requestId: string;
|
|
106
106
|
reason: string;
|
|
107
107
|
at: number;
|
|
108
|
-
status: "done" | "
|
|
108
|
+
status: "done" | "pending" | "failed";
|
|
109
109
|
originUnknownKeys?: string[] | undefined;
|
|
110
110
|
clearanceId: string;
|
|
111
111
|
entryId: string;
|
|
@@ -119,7 +119,8 @@ export async function handleNotifyWake(req, res, match, ctx) {
|
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
121
|
const restatement = readResumeRestatement(wakeBody);
|
|
122
|
-
const
|
|
122
|
+
const message = typeof wakeBody.message === "string" ? { text: wakeBody.message, trusted: false } : undefined;
|
|
123
|
+
const out = await resumeWake(wakeSession, message, principal, req, true, undefined, undefined, restatement);
|
|
123
124
|
sendResumeOutcome(res, out, deps.logger);
|
|
124
125
|
return;
|
|
125
126
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 项目登记簿的**读面** —— `GET /v1/projects`、`GET /v1/projects/:id`。
|
|
3
|
+
*
|
|
4
|
+
* ## 律(三句)
|
|
5
|
+
* · **一个项目 = settings-schema 的一只 `ProjectRegistration`**:形与判官只在 settings-schema;本仓把判过的登记原样放在 `config.projects` 一张表里
|
|
6
|
+
* (`web-admin-client/apply-effective.ts` 的 stage 是唯一写者),本面只读那一张。行 = `{ id, …登记的原键原名 }` —— 不铸 `name` / `repos` /
|
|
7
|
+
* `createdAt` 之类的别名(端侧要别的叫法自己投影),逐键处置在 {@link PROJECT_ROW_DISPOSITIONS} 一张表里(settings-schema 给登记加键 ⇒ 这里 tsc 红,
|
|
8
|
+
* 先表态再上 wire)。
|
|
9
|
+
* · **登记簿只由配置中心下发**:settings-schema 的本地读取集不收 `projects` 域 ⇒ 没有中心腿在应用配置的部署上没有登记簿 —— 两口 501
|
|
10
|
+
* `capability.unavailable`,能力位 `capabilities.projects`(布尔)读同一只事实(`capability-facts.ts` 的 `projectRegistry`)答 `false`;
|
|
11
|
+
* 有登记簿时答 `true`。本面不开写动词(写到哪里由另一张设计定;写面到货时另立一位,本位不改义)。
|
|
12
|
+
* · **可见性 fail-closed**:身份判在登记簿在场判**之前**(否则「这台有没有登记簿」先于 401 泄出去);fleet 调用方(`fleetViewOf` 读档)看全部;
|
|
13
|
+
* 带验过主体的调用方只看 `registeredBy` 恰是自己的登记;看不见的与不存在的同码同句(404 `not_found.project`,不给存在性预言机)。
|
|
14
|
+
*
|
|
15
|
+
* 归档:`archivedAt` 在场 = 已归档。列表缺省不列,`?archived=true` 只列已归档的,`?archived=false` 与缺省同;单项读不论归档与否都答(会话行引用它)。
|
|
16
|
+
*/
|
|
17
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
18
|
+
import type { ProjectRegistration } from "@sema-agent/settings-schema";
|
|
19
|
+
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
20
|
+
/** 404 的唯一句(不存在与看不见同句)。 */
|
|
21
|
+
export declare const PROJECT_NOT_FOUND_MESSAGE = "no such project";
|
|
22
|
+
/** 投影根:这只登记的 id(登记簿的键 —— 不是登记的成员)。 */
|
|
23
|
+
interface ProjectRowRoot {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 项目行的**逐键处置**(表序 = 出口序)。登记的每个键原样出门;`contextItems` 逐条按成员处置(闭集三形,成员同为 `kind` / `value`)。
|
|
28
|
+
* `id` 是本面铸的唯一键:登记簿的键,行上要有它才能回指 `GET /v1/projects/:id` 与提交体 `projectId`。
|
|
29
|
+
*/
|
|
30
|
+
export declare const PROJECT_ROW_DISPOSITIONS: {
|
|
31
|
+
readonly id: {
|
|
32
|
+
readonly mint: (_reg: ProjectRegistration, root: ProjectRowRoot) => string;
|
|
33
|
+
};
|
|
34
|
+
readonly displayName: "forward";
|
|
35
|
+
readonly goal: "forward";
|
|
36
|
+
readonly contextItems: {
|
|
37
|
+
readonly nested: {
|
|
38
|
+
readonly kind: "forward";
|
|
39
|
+
readonly value: "forward";
|
|
40
|
+
};
|
|
41
|
+
readonly rows: "each";
|
|
42
|
+
};
|
|
43
|
+
readonly gitRemotes: "forward";
|
|
44
|
+
readonly defaultScopes: "forward";
|
|
45
|
+
readonly notes: "forward";
|
|
46
|
+
readonly icon: "forward";
|
|
47
|
+
readonly color: "forward";
|
|
48
|
+
readonly registeredBy: "forward";
|
|
49
|
+
readonly registeredAt: "forward";
|
|
50
|
+
readonly archivedAt: "forward";
|
|
51
|
+
};
|
|
52
|
+
/** 项目行的键全集(处置表的键 = wire 上可能出现的每一个键;自铸登记表 `trace/self-minted-wire.ts` 的 `projectRowKey` 按它 `satisfies`)。 */
|
|
53
|
+
export type ProjectRowKey = keyof typeof PROJECT_ROW_DISPOSITIONS;
|
|
54
|
+
/** 一只登记 → wire 行(唯一投影)。 */
|
|
55
|
+
export declare function projectRowOf(id: string, registration: ProjectRegistration): Record<string, unknown>;
|
|
56
|
+
export declare function handleProjects(req: IncomingMessage, res: ServerResponse, match: RouteMatch<ProjectsRouteId>, ctx: RouteCtx): Promise<void>;
|
|
57
|
+
export declare const PROJECTS_ROUTES: readonly [{
|
|
58
|
+
readonly id: "projects-list";
|
|
59
|
+
readonly path: "/v1/projects";
|
|
60
|
+
readonly methods: readonly ["GET"];
|
|
61
|
+
}, {
|
|
62
|
+
readonly id: "project-get";
|
|
63
|
+
readonly pattern: RegExp;
|
|
64
|
+
readonly label: "/v1/projects/:id";
|
|
65
|
+
readonly methods: readonly ["GET"];
|
|
66
|
+
}];
|
|
67
|
+
/** 本域可分派行的 `id` 闭集。 */
|
|
68
|
+
export type ProjectsRouteId = RouteIdsOf<typeof PROJECTS_ROUTES>;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { PROJECT_ID_REGEX } from "@sema-agent/core";
|
|
2
|
+
import { sendJson, sendError } from "../send.js";
|
|
3
|
+
import { fleetViewOf, sendUnauthorized } from "../principal-gate.js";
|
|
4
|
+
import { assertNever } from "../route-ctx.js";
|
|
5
|
+
import * as facts from "../../capability-facts.js";
|
|
6
|
+
import { projectByTable } from "../../trace/projection-table.js";
|
|
7
|
+
export const PROJECT_NOT_FOUND_MESSAGE = "no such project";
|
|
8
|
+
export const PROJECT_ROW_DISPOSITIONS = {
|
|
9
|
+
id: { mint: (_reg, root) => root.id },
|
|
10
|
+
displayName: "forward",
|
|
11
|
+
goal: "forward",
|
|
12
|
+
contextItems: { nested: { kind: "forward", value: "forward" }, rows: "each" },
|
|
13
|
+
gitRemotes: "forward",
|
|
14
|
+
defaultScopes: "forward",
|
|
15
|
+
notes: "forward",
|
|
16
|
+
icon: "forward",
|
|
17
|
+
color: "forward",
|
|
18
|
+
registeredBy: "forward",
|
|
19
|
+
registeredAt: "forward",
|
|
20
|
+
archivedAt: "forward",
|
|
21
|
+
};
|
|
22
|
+
export function projectRowOf(id, registration) {
|
|
23
|
+
return projectByTable("project", PROJECT_ROW_DISPOSITIONS, registration, { id });
|
|
24
|
+
}
|
|
25
|
+
function readArchivedQuery(raw) {
|
|
26
|
+
switch (raw) {
|
|
27
|
+
case null:
|
|
28
|
+
case "false":
|
|
29
|
+
return false;
|
|
30
|
+
case "true":
|
|
31
|
+
return true;
|
|
32
|
+
default:
|
|
33
|
+
return "invalid";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function handleProjects(req, res, match, ctx) {
|
|
37
|
+
const { deps } = ctx;
|
|
38
|
+
const { safeDecode } = ctx.helpers;
|
|
39
|
+
const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
|
|
40
|
+
if (!fleetWide && gateOwner === null) {
|
|
41
|
+
sendUnauthorized(res, "identity");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const registry = facts.projectRegistry(deps);
|
|
45
|
+
if (!registry.available) {
|
|
46
|
+
sendError(res, 501, "capability.unavailable", "the project registry is not available on this deployment: projects are published only by the configuration center, and no center configuration is applied here");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const visible = (registration) => fleetWide || registration.registeredBy === gateOwner;
|
|
50
|
+
switch (match.decl.id) {
|
|
51
|
+
case "projects-list": {
|
|
52
|
+
const archived = readArchivedQuery(new URLSearchParams(match.search).get("archived"));
|
|
53
|
+
if (archived === "invalid") {
|
|
54
|
+
sendError(res, 400, "request.query_invalid", "archived must be `true` or `false`");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const projects = Object.entries(registry.registry)
|
|
58
|
+
.filter(([, registration]) => visible(registration) && (registration.archivedAt !== undefined) === archived)
|
|
59
|
+
.map(([id, registration]) => projectRowOf(id, registration));
|
|
60
|
+
sendJson(res, 200, { projects });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
case "project-get": {
|
|
64
|
+
const raw = safeDecode(match.params.projectId);
|
|
65
|
+
if (raw === null || !PROJECT_ID_REGEX.test(raw)) {
|
|
66
|
+
sendError(res, 400, "request.id_invalid", "invalid project id (must be a canonical uuid)");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const id = raw.toLowerCase();
|
|
70
|
+
const registration = Object.hasOwn(registry.registry, id) ? registry.registry[id] : undefined;
|
|
71
|
+
if (registration === undefined || !visible(registration)) {
|
|
72
|
+
sendError(res, 404, "not_found.project", PROJECT_NOT_FOUND_MESSAGE);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
sendJson(res, 200, projectRowOf(id, registration));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
default:
|
|
79
|
+
return assertNever(match.decl.id);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export const PROJECTS_ROUTES = [
|
|
83
|
+
{ id: "projects-list", path: "/v1/projects", methods: ["GET"] },
|
|
84
|
+
{ id: "project-get", pattern: /^\/v1\/projects\/(?<projectId>[^/]+)$/, label: "/v1/projects/:id", methods: ["GET"] },
|
|
85
|
+
];
|
|
86
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -142,6 +142,10 @@ export async function handleRules(req, res, match, ctx) {
|
|
|
142
142
|
logger.info("local rule import tightening write failed", { detail: prepared.detail, committed: prepared.committed });
|
|
143
143
|
sendRuleWriteFailure(res, "import-tightening", prepared.committed);
|
|
144
144
|
return;
|
|
145
|
+
case "record-store-refused":
|
|
146
|
+
logger.info("local rule import record store refused", { detail: prepared.detail, committed: prepared.committed });
|
|
147
|
+
sendRuleWriteFailure(res, "import-record", prepared.committed);
|
|
148
|
+
return;
|
|
145
149
|
default: {
|
|
146
150
|
const unknown = prepared;
|
|
147
151
|
throw new Error(`unknown local import refusal: ${JSON.stringify(unknown)}`);
|
|
@@ -189,8 +193,19 @@ export async function handleRules(req, res, match, ctx) {
|
|
|
189
193
|
}
|
|
190
194
|
const prepared = await lane.prepareImport(principal, parsed.data.layers);
|
|
191
195
|
if (!prepared.ok) {
|
|
192
|
-
|
|
193
|
-
|
|
196
|
+
switch (prepared.reason) {
|
|
197
|
+
case "too-many-candidates":
|
|
198
|
+
sendError(res, 413, "request.payload_too_large", "too many allow entries across the submitted settings layers");
|
|
199
|
+
return;
|
|
200
|
+
case "record-store-refused":
|
|
201
|
+
logger.info("rule import record store refused", { detail: prepared.detail, committed: prepared.committed });
|
|
202
|
+
sendRuleWriteFailure(res, "import-record", prepared.committed);
|
|
203
|
+
return;
|
|
204
|
+
default: {
|
|
205
|
+
const unknown = prepared;
|
|
206
|
+
throw new Error(`unknown rule import refusal: ${JSON.stringify(unknown)}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
194
209
|
}
|
|
195
210
|
sendJson(res, 200, { preview: prepared.preview, ...(prepared.ticket !== undefined ? { ticket: prepared.ticket, expiresAtMs: prepared.expiresAtMs } : {}) });
|
|
196
211
|
return;
|
|
@@ -306,6 +321,19 @@ function sendRuleWriteFailure(res, verb, committed) {
|
|
|
306
321
|
throw new Error(`unknown rule-write committed word: ${JSON.stringify(unknownWord)}`);
|
|
307
322
|
}
|
|
308
323
|
}
|
|
324
|
+
case "import-record":
|
|
325
|
+
switch (committed) {
|
|
326
|
+
case "no":
|
|
327
|
+
sendError(res, 503, "state.rule_write_failed", "the import's approval record could not be created (no ticket was issued and no allow rule was written; deny / ask rows of a local batch may already be in force) — send the same request again", { committed });
|
|
328
|
+
return;
|
|
329
|
+
case "unknown":
|
|
330
|
+
sendError(res, 503, "state.rule_write_failed", "the import's approval record may or may not have been created (no ticket was issued and no allow rule was written; deny / ask rows of a local batch may already be in force) — send the same request again", { committed });
|
|
331
|
+
return;
|
|
332
|
+
default: {
|
|
333
|
+
const unknownWord = committed;
|
|
334
|
+
throw new Error(`unknown rule-import committed word: ${JSON.stringify(unknownWord)}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
309
337
|
case "revoke":
|
|
310
338
|
switch (committed) {
|
|
311
339
|
case "no":
|
package/dist/http/routes/runs.js
CHANGED
|
@@ -440,10 +440,10 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
440
440
|
const priority = body.priority;
|
|
441
441
|
const steerIdemRaw = headerStr(req.headers["idempotency-key"]);
|
|
442
442
|
const messageId = steerIdemRaw ? `idem-${idemKeyOf(steerIdemRaw, idemCallerOf(req, ctx), "run").slice(0, 32)}` : uuidv7();
|
|
443
|
-
const
|
|
443
|
+
const operator = explicitOperatorOk(principal, deps.config);
|
|
444
444
|
const steerInput = () => ({
|
|
445
445
|
text,
|
|
446
|
-
trusted,
|
|
446
|
+
trusted: false,
|
|
447
447
|
inputId: messageId,
|
|
448
448
|
...(priority !== undefined ? { priority } : {}),
|
|
449
449
|
});
|
|
@@ -462,7 +462,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
462
462
|
sendError(res, 404, "not_found.run", runNotFoundMessage(taskId));
|
|
463
463
|
return;
|
|
464
464
|
}
|
|
465
|
-
if (!
|
|
465
|
+
if (!operator && !runOwnerOk(req, res, run.owner))
|
|
466
466
|
return;
|
|
467
467
|
if (!runSessionAcceptOk(req, res, run, "run.steer"))
|
|
468
468
|
return;
|
|
@@ -505,7 +505,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
505
505
|
if (acceptance === "refused")
|
|
506
506
|
return;
|
|
507
507
|
try {
|
|
508
|
-
await relayAcceptedInput(deps, acceptance, () => live.steer(text, { trusted, inputId: messageId, ...(priority !== undefined ? { priority } : {}) }));
|
|
508
|
+
await relayAcceptedInput(deps, acceptance, () => live.steer(text, { trusted: false, inputId: messageId, ...(priority !== undefined ? { priority } : {}) }));
|
|
509
509
|
sendJson(res, 200, { taskId, status: "running", delivery: "applied", messageId, ...(priority ? { priority } : {}) });
|
|
510
510
|
return;
|
|
511
511
|
}
|
|
@@ -765,10 +765,10 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
765
765
|
const interruptIdemRaw = headerStr(req.headers["idempotency-key"]);
|
|
766
766
|
const interruptInputId = interruptIdemRaw ? `idem-${idemKeyOf(interruptIdemRaw, idemCallerOf(req, ctx), "run").slice(0, 32)}` : uuidv7();
|
|
767
767
|
const interruptMessageId = interruptInputId;
|
|
768
|
-
const
|
|
768
|
+
const operator = explicitOperatorOk(principal, deps.config);
|
|
769
769
|
if (!interruptBare) {
|
|
770
770
|
try {
|
|
771
|
-
validatePendingSteer({ text, trusted, inputId: interruptInputId });
|
|
771
|
+
validatePendingSteer({ text, trusted: false, inputId: interruptInputId });
|
|
772
772
|
}
|
|
773
773
|
catch (e) {
|
|
774
774
|
if (e instanceof CheckpointError && e.code === "steering.invalid_content") {
|
|
@@ -783,7 +783,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
783
783
|
sendError(res, 404, "not_found.run", runNotFoundMessage(taskId));
|
|
784
784
|
return;
|
|
785
785
|
}
|
|
786
|
-
if (!
|
|
786
|
+
if (!operator && !runOwnerOk(req, res, run.owner))
|
|
787
787
|
return;
|
|
788
788
|
if (!runSessionAcceptOk(req, res, run, "run.interrupt"))
|
|
789
789
|
return;
|
|
@@ -838,7 +838,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
838
838
|
if (acceptance === "refused")
|
|
839
839
|
return;
|
|
840
840
|
try {
|
|
841
|
-
await relayAcceptedInput(deps, acceptance, () => liveStream.steer(text, { trusted, priority: "now", ...(interruptInputId !== undefined ? { inputId: interruptInputId } : {}) }));
|
|
841
|
+
await relayAcceptedInput(deps, acceptance, () => liveStream.steer(text, { trusted: false, priority: "now", ...(interruptInputId !== undefined ? { inputId: interruptInputId } : {}) }));
|
|
842
842
|
}
|
|
843
843
|
catch (e) {
|
|
844
844
|
const code = e.code;
|
|
@@ -38,6 +38,21 @@ export function createSessionSyncLocal() {
|
|
|
38
38
|
};
|
|
39
39
|
return { pendingStagings, importLeases, touchImportLease, cleanupStaging };
|
|
40
40
|
}
|
|
41
|
+
async function firstPhaseRefusal(sessionStorage, sessionId, relation, consented) {
|
|
42
|
+
if (consented || (relation !== "fork" && relation !== "stale"))
|
|
43
|
+
return undefined;
|
|
44
|
+
if (sessionStorage.assertArchiveAnonymous !== undefined && (await readSessionAgent(sessionStorage, sessionId)) === undefined) {
|
|
45
|
+
try {
|
|
46
|
+
await sessionStorage.assertArchiveAnonymous(sessionId);
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
if (e instanceof StampedSessionArchiveError)
|
|
50
|
+
return { kind: "stamped", error: e };
|
|
51
|
+
throw e;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { kind: "needs_consent" };
|
|
55
|
+
}
|
|
41
56
|
export async function handleSessionSync(req, res, match, ctx) {
|
|
42
57
|
const { deps } = ctx;
|
|
43
58
|
const { readJson, readRawBody, safeDecode, rateLimited } = ctx.helpers;
|
|
@@ -358,16 +373,12 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
358
373
|
const anchors = anchorsRead.anchors;
|
|
359
374
|
const dstIds = (await sessionStorage.listEntryIds?.(sessionId)) ?? null;
|
|
360
375
|
const relA = classifySyncRelationshipByIds(entryIds, dstIds);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (e instanceof StampedSessionArchiveError && sendSessionError(res, e, "import"))
|
|
368
|
-
return;
|
|
369
|
-
throw e;
|
|
370
|
-
}
|
|
376
|
+
const refusalA = await firstPhaseRefusal(sessionStorage, sessionId, relA.relation, resolution === "overwrite-dst");
|
|
377
|
+
if (refusalA !== undefined) {
|
|
378
|
+
if (refusalA.kind === "stamped") {
|
|
379
|
+
if (sendSessionError(res, refusalA.error, "import"))
|
|
380
|
+
return;
|
|
381
|
+
throw refusalA.error;
|
|
371
382
|
}
|
|
372
383
|
sendError(res, 409, "conflict", "sync conflict", { relation: relA });
|
|
373
384
|
return;
|
|
@@ -683,6 +694,12 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
683
694
|
}
|
|
684
695
|
const dst = await sessionStorage.exportEntries(sessionId);
|
|
685
696
|
const relation = classifySyncRelationshipByIds(body.entryIds, dst ? dst.map((e) => e.id) : null);
|
|
697
|
+
const refusal = await firstPhaseRefusal(sessionStorage, sessionId, relation.relation, false);
|
|
698
|
+
if (refusal?.kind === "stamped") {
|
|
699
|
+
if (sendSessionError(res, refusal.error, "import"))
|
|
700
|
+
return;
|
|
701
|
+
throw refusal.error;
|
|
702
|
+
}
|
|
686
703
|
sendJson(res, 200, relation);
|
|
687
704
|
return;
|
|
688
705
|
}
|