@sema-agent/server 7.138.0 → 7.140.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 +457 -7
- package/README.md +7 -4
- package/README.zh-CN.md +6 -4
- package/USAGE.md +91 -41
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/lib/lanes.json +3 -2
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +26 -26
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/arms.js +1 -3
- package/dist/bench/s1/live-deps.js +3 -2
- package/dist/bench/s1/row.d.ts +5 -2
- package/dist/bench/s1/row.js +2 -22
- package/dist/bench/s1/run-firm.js +2 -2
- package/dist/boot/adoption.js +1 -1
- package/dist/boot/device-lane.d.ts +8 -3
- package/dist/boot/device-lane.js +7 -2
- package/dist/boot/execution-env.d.ts +4 -2
- package/dist/boot/execution-env.js +28 -34
- package/dist/boot/execution-lane.d.ts +9 -1
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/governance-seams.d.ts +3 -2
- package/dist/boot/governance-seams.js +9 -11
- package/dist/boot/memory-boundary.d.ts +14 -51
- package/dist/boot/memory-boundary.js +10 -20
- package/dist/boot/memory-consolidation.d.ts +15 -11
- package/dist/boot/memory-consolidation.js +25 -14
- package/dist/boot/resolve-spec.d.ts +4 -6
- package/dist/boot/resolve-spec.js +10 -13
- package/dist/boot/retention-lane.d.ts +5 -5
- package/dist/boot/retention-lane.js +0 -6
- package/dist/boot/runner-deps.d.ts +6 -4
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/session-faces.d.ts +0 -3
- package/dist/boot/session-faces.js +15 -8
- package/dist/boot/stage-02-web-admin-pull.js +2 -2
- package/dist/boot/stage-03-store-backend.d.ts +2 -6
- package/dist/boot/stage-03-store-backend.js +2 -3
- package/dist/boot/stage-04-stores.d.ts +2 -6
- package/dist/boot/stage-04-stores.js +5 -5
- package/dist/boot/stage-05-execution-env.d.ts +2 -6
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +2 -6
- package/dist/boot/stage-06-runners.js +2 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -6
- package/dist/boot/stage-08-reapers.d.ts +2 -6
- package/dist/boot/stage-09-leader.d.ts +2 -6
- package/dist/boot/stage-09-leader.js +1 -2
- package/dist/boot/stage-10-http-server.d.ts +2 -6
- package/dist/boot/stage-10-http-server.js +7 -6
- package/dist/boot/stores.d.ts +3 -6
- package/dist/boot/stores.js +27 -40
- package/dist/boot/task-list-lane.d.ts +1 -1
- package/dist/boot/task-list-lane.js +1 -1
- package/dist/boot/web-admin.js +37 -11
- package/dist/capabilities/execution-lane.d.ts +2 -2
- package/dist/capabilities/mcp-probe.js +1 -1
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +15 -7
- package/dist/capability-facts.js +8 -3
- package/dist/config-catalog.js +9 -8
- package/dist/config-invariants.d.ts +23 -3
- package/dist/config-invariants.js +42 -0
- package/dist/config-provider.d.ts +33 -37
- package/dist/config-provider.js +51 -30
- package/dist/config-types.d.ts +21 -7
- package/dist/config.d.ts +33 -0
- package/dist/config.js +46 -16
- package/dist/delegated-session-owner.d.ts +4 -3
- package/dist/delegated-session-owner.js +1 -1
- package/dist/deployment-shape.d.ts +10 -9
- package/dist/deployment-shape.js +4 -4
- package/dist/device-enrollment.d.ts +41 -2
- package/dist/device-enrollment.js +27 -12
- package/dist/device-store.d.ts +58 -85
- package/dist/device-store.js +19 -49
- package/dist/device-ws-hub.js +2 -1
- package/dist/env-name-allowlist-knobs.d.ts +5 -4
- package/dist/exec-cut.d.ts +60 -0
- package/dist/exec-cut.js +36 -0
- package/dist/execution-lane-caps.d.ts +115 -105
- package/dist/execution-lane-caps.js +76 -82
- package/dist/execution-placement.d.ts +259 -0
- package/dist/execution-placement.js +199 -0
- package/dist/field-conflict.d.ts +3 -2
- package/dist/field-conflict.js +1 -0
- package/dist/hosted-posture.d.ts +2 -2
- package/dist/http/admission.js +8 -19
- package/dist/http/checkpoint-ctx.d.ts +21 -12
- package/dist/http/checkpoint-ctx.js +4 -2
- package/dist/http/claimed-run.d.ts +1 -1
- package/dist/http/durable-run-leg.js +9 -5
- package/dist/http/execution-context.d.ts +218 -0
- package/dist/http/execution-context.js +330 -0
- package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
- package/dist/http/memory-compliance-failure-reply.js +5 -0
- package/dist/http/memory-layer-reply.d.ts +30 -0
- package/dist/http/memory-layer-reply.js +24 -0
- package/dist/http/resume-legs.js +63 -36
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/route-ctx.d.ts +14 -8
- package/dist/http/routes/adoption.js +1 -1
- package/dist/http/routes/background.d.ts +29 -1
- package/dist/http/routes/background.js +29 -2
- package/dist/http/routes/devices.d.ts +13 -19
- package/dist/http/routes/devices.js +21 -26
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-compliance.js +8 -1
- package/dist/http/routes/memory-consolidation.js +12 -1
- package/dist/http/routes/memory-origin.js +14 -2
- package/dist/http/routes/memory-policy.js +5 -0
- package/dist/http/routes/session-sync.js +110 -15
- package/dist/http/routes/sessions.d.ts +6 -0
- package/dist/http/routes/sessions.js +143 -22
- package/dist/http/routes/side-query.d.ts +12 -4
- package/dist/http/routes/side-query.js +4 -5
- package/dist/http/routes/tasks.js +41 -33
- package/dist/http/server.d.ts +40 -44
- package/dist/http/server.js +13 -2
- package/dist/http/session-inherit-env.d.ts +3 -4
- package/dist/http/session-inherit-env.js +1 -1
- package/dist/http/wire-types.d.ts +8 -12
- package/dist/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/lane-home-probe.d.ts +68 -42
- package/dist/lane-home-probe.js +53 -30
- package/dist/leader/wire.js +5 -4
- package/dist/memory-bundle-engine.d.ts +16 -9
- package/dist/memory-bundle-engine.js +29 -6
- package/dist/memory-operator-faces.d.ts +85 -30
- package/dist/memory-operator-faces.js +136 -30
- package/dist/memory-project-layer.d.ts +3 -21
- package/dist/memory-project-layer.js +11 -8
- package/dist/memory-scope-stores.d.ts +73 -0
- package/dist/memory-scope-stores.js +86 -0
- package/dist/memory-scope.d.ts +29 -5
- package/dist/memory-scope.js +16 -4
- package/dist/memory-sync-client.d.ts +70 -18
- package/dist/memory-sync-client.js +215 -117
- package/dist/memory-sync.d.ts +1 -1
- package/dist/memory-sync.js +3 -2
- package/dist/observability/cost-taxonomy.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +12 -0
- package/dist/observability/fail-open.js +12 -0
- package/dist/observability/run-terminal.js +0 -1
- package/dist/orchestration/workflow-notify-journal.js +4 -4
- package/dist/org-memory-admission.d.ts +4 -3
- package/dist/org-memory-admission.js +6 -6
- package/dist/parked-decide.d.ts +34 -9
- package/dist/parked-decide.js +12 -19
- package/dist/parked-revive-surface.d.ts +12 -15
- package/dist/parked-revive-surface.js +3 -6
- package/dist/peer-seat.d.ts +13 -7
- package/dist/peer-seat.js +37 -3
- package/dist/plugins/adoption-log-sql.js +4 -4
- package/dist/plugins/approval-ask-store-file.d.ts +7 -0
- package/dist/plugins/approval-ask-store-file.js +11 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
- package/dist/plugins/approval-ask-store-memory.js +12 -0
- package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
- package/dist/plugins/approval-ask-store-sql.js +44 -26
- package/dist/plugins/approval-nonce-store.js +4 -4
- package/dist/plugins/blob-backend.d.ts +4 -4
- package/dist/plugins/blob-backend.js +7 -7
- package/dist/plugins/breaker-state-sql.js +2 -2
- package/dist/plugins/caching-session-store.d.ts +6 -2
- package/dist/plugins/caching-session-store.js +9 -3
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.d.ts +6 -5
- package/dist/plugins/checkpoint-store-sql.js +21 -23
- package/dist/plugins/device-store-sql.d.ts +25 -51
- package/dist/plugins/device-store-sql.js +68 -122
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +151 -0
- package/dist/plugins/execution-placement-sql.js +223 -0
- package/dist/plugins/file-history-store-sql.d.ts +9 -8
- package/dist/plugins/file-history-store-sql.js +9 -9
- package/dist/plugins/file-run-store.d.ts +6 -1
- package/dist/plugins/file-run-store.js +4 -0
- package/dist/plugins/fork-routing-session-store.d.ts +6 -0
- package/dist/plugins/fork-routing-session-store.js +16 -0
- package/dist/plugins/image-bake-store-sql.js +9 -9
- package/dist/plugins/image-index-sql.js +11 -11
- package/dist/plugins/leader-run-store-sql.js +4 -4
- package/dist/plugins/local-session-store.d.ts +149 -50
- package/dist/plugins/local-session-store.js +382 -107
- package/dist/plugins/mailbox-store-sql.d.ts +2 -1
- package/dist/plugins/mailbox-store-sql.js +4 -4
- package/dist/plugins/memory-engine-tidb.js +5 -5
- package/dist/plugins/memory-key-guards.d.ts +4 -0
- package/dist/plugins/memory-key-guards.js +1 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
- package/dist/plugins/memory-run-store.d.ts +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +117 -8
- package/dist/plugins/one-time-migrations.js +408 -38
- package/dist/plugins/org-delivery-quota-store.js +2 -2
- package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
- package/dist/plugins/outcome-ledger-sql.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -19
- package/dist/plugins/permission-rule-store-sql.js +29 -32
- package/dist/plugins/pg-pool.d.ts +7 -3
- package/dist/plugins/pg-session-storage.d.ts +31 -20
- package/dist/plugins/pg-session-storage.js +120 -52
- package/dist/plugins/remote-env-adb.d.ts +18 -19
- package/dist/plugins/remote-env-adb.js +91 -66
- package/dist/plugins/remote-env-device.d.ts +23 -31
- package/dist/plugins/remote-env-device.js +19 -17
- package/dist/plugins/remote-env-e2b.d.ts +27 -21
- package/dist/plugins/remote-env-e2b.js +91 -45
- package/dist/plugins/remote-env-file-error.d.ts +3 -1
- package/dist/plugins/remote-env-file-error.js +9 -3
- package/dist/plugins/remote-env-host.d.ts +31 -34
- package/dist/plugins/remote-env-host.js +91 -72
- package/dist/plugins/remote-env-k8s.d.ts +13 -29
- package/dist/plugins/remote-env-k8s.js +63 -55
- package/dist/plugins/remote-env-local-docker.d.ts +24 -12
- package/dist/plugins/remote-env-local-docker.js +49 -61
- package/dist/plugins/remote-env-ssh.d.ts +11 -19
- package/dist/plugins/remote-env-ssh.js +74 -57
- package/dist/plugins/remote-shell.d.ts +100 -3
- package/dist/plugins/remote-shell.js +166 -2
- package/dist/plugins/resume-anchor-store-sql.js +2 -2
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.js +2 -2
- package/dist/plugins/retention-store-sql.d.ts +10 -7
- package/dist/plugins/retention-store-sql.js +13 -7
- package/dist/plugins/run-store-sql.d.ts +13 -3
- package/dist/plugins/run-store-sql.js +20 -15
- package/dist/plugins/schema-consistency.d.ts +21 -11
- package/dist/plugins/schema-consistency.js +15 -9
- package/dist/plugins/schema-drift-sentence.d.ts +27 -0
- package/dist/plugins/schema-drift-sentence.js +38 -0
- package/dist/plugins/schema-ensure-legs.d.ts +2 -3
- package/dist/plugins/schema-ensure-legs.js +2 -2
- package/dist/plugins/schema-live-columns.d.ts +1 -1
- package/dist/plugins/session-capture-record-store-sql.js +1 -1
- package/dist/plugins/session-fork.d.ts +54 -0
- package/dist/plugins/session-fork.js +38 -1
- package/dist/plugins/session-row-sql.d.ts +22 -0
- package/dist/plugins/session-row-sql.js +81 -0
- package/dist/plugins/session-rules-column.d.ts +1 -1
- package/dist/plugins/session-rules-column.js +1 -1
- package/dist/plugins/session-store.d.ts +1 -1
- package/dist/plugins/session-workspace-cell.d.ts +1 -1
- package/dist/plugins/session-workspace-cell.js +1 -1
- package/dist/plugins/shared-memory-store-sql.js +2 -2
- package/dist/plugins/sql-driver.d.ts +10 -5
- package/dist/plugins/sql-driver.js +6 -6
- package/dist/plugins/sql-errors.js +1 -1
- package/dist/plugins/store-backend.d.ts +5 -7
- package/dist/plugins/store-backend.js +23 -11
- package/dist/plugins/store-contracts.d.ts +25 -5
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.d.ts +12 -7
- package/dist/plugins/tidb-pool.js +13 -7
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.d.ts +57 -26
- package/dist/plugins/tidb-session-store.js +127 -59
- package/dist/plugins/tool-result-store-sql.d.ts +5 -4
- package/dist/plugins/tool-result-store-sql.js +21 -13
- package/dist/plugins/user-input-ledger-sql.js +2 -2
- package/dist/plugins/workflow-journal-store-sql.js +5 -5
- package/dist/plugins/workflow-run-store-sql.js +19 -19
- package/dist/plugins/write-behind-counter.d.ts +2 -3
- package/dist/plugins/write-behind-counter.js +5 -5
- package/dist/project-memory.d.ts +9 -15
- package/dist/project-memory.js +5 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +6 -7
- package/dist/request-value-closure.js +1 -3
- package/dist/resource-suspend.d.ts +14 -12
- package/dist/resource-suspend.js +1 -1
- package/dist/resource-window.d.ts +4 -3
- package/dist/run-local.d.ts +6 -0
- package/dist/run-local.js +34 -35
- package/dist/runs.d.ts +10 -5
- package/dist/runs.js +52 -66
- package/dist/security.d.ts +38 -12
- package/dist/security.js +8 -2
- package/dist/server-secret-env.d.ts +9 -5
- package/dist/session-children-retire.d.ts +27 -9
- package/dist/session-children-retire.js +9 -5
- package/dist/session-incarnation.d.ts +20 -10
- package/dist/session-incarnation.js +5 -3
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-row.d.ts +114 -5
- package/dist/session-row.js +55 -5
- package/dist/session-titler.d.ts +2 -2
- package/dist/sql-engine-posture.d.ts +1 -1
- package/dist/sql-engine-posture.js +1 -1
- package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
- package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
- package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
- package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
- package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-a2a.js +5 -6
- package/dist/task-cwd.d.ts +6 -1
- package/dist/task-mcp.d.ts +22 -9
- package/dist/task-mcp.js +17 -9
- package/dist/terminal.d.ts +27 -0
- package/dist/terminal.js +6 -0
- package/dist/tool-approval.d.ts +6 -0
- package/dist/tool-approval.js +8 -1
- package/dist/trace/project.d.ts +1 -0
- package/dist/trace/project.js +1 -0
- package/dist/trace/redact.d.ts +3 -1
- package/dist/trace/redact.js +80 -28
- package/dist/trace/self-minted-wire.d.ts +169 -2
- package/dist/trace/self-minted-wire.js +54 -1
- package/dist/url-refusal.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +17 -3
- package/dist/web-admin-client/apply-effective.js +20 -10
- package/dist/web-admin-client/candidate-gate.d.ts +11 -7
- package/dist/web-admin-client/candidate-gate.js +1 -1
- package/dist/web-admin-client/http-client.d.ts +5 -4
- package/dist/web-admin-client/http-client.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +7 -17
- package/dist/web-admin-client/read-warnings.js +5 -9
- package/dist/web-admin-client/skills-mcp.js +3 -2
- package/dist/web-admin-client/types.d.ts +6 -0
- package/package.json +3 -3
- package/wire-changes/server@7.139.0.json +348 -0
- package/wire-changes/server@7.140.0.json +184 -0
- package/dist/http/device-placement.d.ts +0 -175
- package/dist/http/device-placement.js +0 -145
|
@@ -3,8 +3,12 @@ import { explicitOperatorOk, gatedPrincipal, sendPrincipalRefusal } from "../pri
|
|
|
3
3
|
import { assertNever } from "../route-ctx.js";
|
|
4
4
|
import * as facts from "../../capability-facts.js";
|
|
5
5
|
import { DEVICE_PLATFORM_OS, DEVICE_PUBKEY_MAX_BYTES, DEVICE_TEXT_LIMITS, assertDeviceIdShape, assertDevicePubkeyShape, assertRootSessionIdShape, isDeviceAbsolutePath, sameDeviceOwner, } from "../../device-store.js";
|
|
6
|
+
import { boundDeviceOf } from "../../execution-placement.js";
|
|
7
|
+
import { defaultTaskRegistry } from "@sema-agent/core";
|
|
8
|
+
import { probeSessionChildren, sessionChildrenScope } from "../../session-children-retire.js";
|
|
9
|
+
import { liveChildrenRefusal } from "./background.js";
|
|
6
10
|
import { DEFAULT_ENROLL_TOKEN_TTL_SEC } from "../../device-enrollment.js";
|
|
7
|
-
import { deviceOwnerDomainOf } from "../
|
|
11
|
+
import { deviceOwnerDomainOf } from "../execution-context.js";
|
|
8
12
|
import { echoKeyName } from "../../request-key-closure.js";
|
|
9
13
|
const DEVICE_NOT_FOUND_MESSAGE = "device not found";
|
|
10
14
|
const NO_DEVICE_DOMAIN_MESSAGE = "device management needs a caller domain: this credential carries no verified tenant scope claim (registry auth-bridge JWT `scope`) and is not an explicit operator — connect through the registry auth bridge, or configure OPERATOR_PRINCIPALS";
|
|
@@ -32,9 +36,6 @@ function deviceListRow(row, online) {
|
|
|
32
36
|
...(row.lastSeenAtMs !== null ? { lastSeenAt: new Date(row.lastSeenAtMs).toISOString() } : {}),
|
|
33
37
|
};
|
|
34
38
|
}
|
|
35
|
-
function boundDeviceOf(row) {
|
|
36
|
-
return { deviceId: row.deviceId, rev: row.rev, boundAt: new Date(row.boundAtMs).toISOString() };
|
|
37
|
-
}
|
|
38
39
|
function sendDeviceRejection(res, rej) {
|
|
39
40
|
if (rej.retryAfterSec !== undefined)
|
|
40
41
|
res.setHeader("retry-after", String(rej.retryAfterSec));
|
|
@@ -112,7 +113,6 @@ function parseEnrollBody(res, body) {
|
|
|
112
113
|
export async function handleDevices(req, res, match, ctx) {
|
|
113
114
|
switch (match.decl.id) {
|
|
114
115
|
case "devices-list":
|
|
115
|
-
case "device-session":
|
|
116
116
|
case "device-session-rebind":
|
|
117
117
|
case "device-enroll-tokens":
|
|
118
118
|
case "device-enroll":
|
|
@@ -248,31 +248,19 @@ export async function handleDevices(req, res, match, ctx) {
|
|
|
248
248
|
return;
|
|
249
249
|
}
|
|
250
250
|
const rootSessionId = decoded;
|
|
251
|
-
if (match.decl.id === "device-session") {
|
|
252
|
-
if (!operator && domain === undefined) {
|
|
253
|
-
sendError(res, 403, "auth.forbidden", NO_DEVICE_DOMAIN_MESSAGE);
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
const binding = await store.getSessionBinding(rootSessionId);
|
|
257
|
-
if (!binding || (!operator && !sameDeviceOwner(binding.owner, domain))) {
|
|
258
|
-
sendDeviceNotFound(res);
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
sendJson(res, 200, { rootSessionId, boundDevice: boundDeviceOf(binding) });
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
251
|
if (!operator && domain === undefined) {
|
|
265
252
|
sendError(res, 403, "auth.forbidden", NO_DEVICE_DOMAIN_MESSAGE);
|
|
266
253
|
return;
|
|
267
254
|
}
|
|
268
|
-
const
|
|
269
|
-
|
|
255
|
+
const placement = await enrollment.readPlacement(rootSessionId);
|
|
256
|
+
const binding = placement === undefined ? undefined : boundDeviceOf(placement.cell);
|
|
257
|
+
if (placement === undefined || !binding || (!operator && !sameDeviceOwner(binding.owner, domain))) {
|
|
270
258
|
sendDeviceNotFound(res);
|
|
271
259
|
return;
|
|
272
260
|
}
|
|
273
261
|
const body = (await readJson(req));
|
|
274
262
|
if (typeof body !== "object" || body === null || typeof body.toDeviceId !== "string" || body.expectedRev === undefined) {
|
|
275
|
-
sendError(res, 400, "request.body_shape", "body must be { toDeviceId: string, expectedRev: number } — expectedRev is the
|
|
263
|
+
sendError(res, 400, "request.body_shape", "body must be { toDeviceId: string, expectedRev: number } — expectedRev is the device rev read from GET /v1/sessions/{sessionId}/execution-placement (explicit prior state; two concurrent operators must not silently stomp each other)");
|
|
276
264
|
return;
|
|
277
265
|
}
|
|
278
266
|
if (typeof body.expectedRev !== "number" || !Number.isInteger(body.expectedRev) || body.expectedRev < 0) {
|
|
@@ -295,16 +283,24 @@ export async function handleDevices(req, res, match, ctx) {
|
|
|
295
283
|
sendError(res, 409, "device.rebind_active_run", "this session has a non-terminal run — rebinding now would leave in-flight work addressed at another workspace; cancel the run (or let it finish), then retry", { activeTaskId });
|
|
296
284
|
return;
|
|
297
285
|
}
|
|
298
|
-
const
|
|
286
|
+
const tree = await probeSessionChildren({ agentStore: deps.backgroundAgentStore, checkpointStore: deps.checkpointStore, registry: defaultTaskRegistry }, rootSessionId, sessionChildrenScope(placement.occupant.owner));
|
|
287
|
+
if (tree.liveChildren.length > 0) {
|
|
288
|
+
sendError(res, 409, "device.rebind_active_run", "this session still has background agents running or waiting on an approval under it — rebinding now would leave them addressed at the old device; retire them (POST retirePath) or let them finish, then retry", liveChildrenRefusal(rootSessionId, tree.liveChildren));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const result = await store.rebindDeviceExecution({ root: rootSessionId, occupant: placement.occupant, owner: binding.owner, expectedRev, targetDeviceId: toDeviceId });
|
|
299
292
|
switch (result.outcome) {
|
|
300
293
|
case "rebound":
|
|
301
294
|
case "idempotent":
|
|
302
|
-
sendJson(res, 200, { rootSessionId, deviceId: result.
|
|
295
|
+
sendJson(res, 200, { rootSessionId, deviceId: result.device.id, rev: result.device.rev, workspaceCarryover: "none" });
|
|
303
296
|
return;
|
|
304
297
|
case "rev_conflict":
|
|
305
|
-
sendError(res, 409, "device.rebind_rev_conflict", "expectedRev does not match the binding's current rev — the session↔device binding changed since it was read; re-read it and retry with currentRev", { currentRev: result.
|
|
298
|
+
sendError(res, 409, "device.rebind_rev_conflict", "expectedRev does not match the binding's current rev — the session↔device binding changed since it was read; re-read it and retry with currentRev", { currentRev: result.device.rev });
|
|
299
|
+
return;
|
|
300
|
+
case "active_run":
|
|
301
|
+
sendError(res, 409, "device.rebind_active_run", "this session has a non-terminal run — rebinding now would leave in-flight work addressed at another workspace; cancel the run (or let it finish), then retry", { activeTaskId: result.activeTaskId });
|
|
306
302
|
return;
|
|
307
|
-
case "
|
|
303
|
+
case "gone":
|
|
308
304
|
case "device_not_found":
|
|
309
305
|
sendDeviceNotFound(res);
|
|
310
306
|
return;
|
|
@@ -321,7 +317,6 @@ export const DEVICES_ROUTES = [
|
|
|
321
317
|
{ id: "device-enroll", path: "/v1/devices/enroll", credentialGated: ["POST"], methods: ["POST"] },
|
|
322
318
|
{ id: "device-revoke", pattern: /^\/v1\/devices\/(?<deviceId>[^/]+)\/revoke$/, label: "/v1/devices/:deviceId/revoke", methods: ["POST"] },
|
|
323
319
|
{ id: "device-session-rebind", pattern: /^\/v1\/devices\/sessions\/(?<rootSessionId>[^/]+)\/rebind$/, label: "/v1/devices/sessions/:id/rebind", methods: ["POST"] },
|
|
324
|
-
{ id: "device-session", pattern: /^\/v1\/devices\/sessions\/(?<rootSessionId>[^/]+)$/, label: "/v1/devices/sessions/:id", credentialGated: ["GET"], methods: ["GET"] },
|
|
325
320
|
{ prefix: "/v1/devices/", credentialGated: ["POST"] },
|
|
326
321
|
];
|
|
327
322
|
//# sourceMappingURL=devices.js.map
|
|
@@ -4,6 +4,7 @@ import { sentMemoryStoreRefusal } from "../memory-store-refusal-reply.js";
|
|
|
4
4
|
import { buildOriginFencedBundle, readOriginAware } from "../../memory-origin-fence.js";
|
|
5
5
|
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
|
|
6
6
|
import { assertNever } from "../route-ctx.js";
|
|
7
|
+
import { sentMemoryLayerRefusal } from "../memory-layer-reply.js";
|
|
7
8
|
import * as facts from "../../capability-facts.js";
|
|
8
9
|
export const MEMORY_BUNDLE_EXPORT_PATH = "/v1/memory/export";
|
|
9
10
|
export const MEMORY_BUNDLE_IMPORT_PATH = "/v1/memory/import";
|
|
@@ -34,6 +35,8 @@ function codeOf(err) {
|
|
|
34
35
|
return typeof code === "string" ? code : undefined;
|
|
35
36
|
}
|
|
36
37
|
function sentClassifiedFailure(res, ctx, face, err) {
|
|
38
|
+
if (sentMemoryLayerRefusal(res, err, { kind: "operator" }))
|
|
39
|
+
return true;
|
|
37
40
|
const code = codeOf(err);
|
|
38
41
|
if (code !== undefined && sentCoreCode(res, code, err instanceof Error ? err.message : String(err)))
|
|
39
42
|
return true;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { erasureInputSmugglesPrototypeKey } from "../../memory-operator-faces.js";
|
|
3
3
|
import { sentMemoryComplianceFailure } from "../memory-compliance-failure-reply.js";
|
|
4
|
+
import { readLayerSeat, sentMemoryLayerRefusal } from "../memory-layer-reply.js";
|
|
4
5
|
import { sendJson, sendError } from "../send.js";
|
|
5
6
|
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
|
|
6
7
|
import { assertNever } from "../route-ctx.js";
|
|
@@ -12,6 +13,8 @@ const EraseRequestSchema = z.object({
|
|
|
12
13
|
allowUnevidenced: z.boolean().optional(),
|
|
13
14
|
});
|
|
14
15
|
function sentClassifiedFailure(res, ctx, face, err) {
|
|
16
|
+
if (sentMemoryLayerRefusal(res, err, { kind: "operator" }))
|
|
17
|
+
return true;
|
|
15
18
|
if (sentMemoryComplianceFailure(res, err, { kind: "operator" }, ctx.deps.logger))
|
|
16
19
|
return true;
|
|
17
20
|
ctx.deps.logger?.warn?.(`memory_compliance_${face}_failed`, { err: String(err) });
|
|
@@ -53,8 +56,12 @@ export async function handleMemoryCompliance(req, res, match, ctx) {
|
|
|
53
56
|
sendError(res, 400, "request.id_invalid", "invalid memory entry id");
|
|
54
57
|
return;
|
|
55
58
|
}
|
|
59
|
+
const query = new URLSearchParams(match.search);
|
|
60
|
+
const at = readLayerSeat(res, query.has("scope"), query.get("scope"));
|
|
61
|
+
if (at === null)
|
|
62
|
+
return;
|
|
56
63
|
try {
|
|
57
|
-
sendJson(res, 200, await faces.provenanceOf(entryId));
|
|
64
|
+
sendJson(res, 200, await (at !== undefined ? faces.provenanceOf(entryId, at) : faces.provenanceOf(entryId)));
|
|
58
65
|
}
|
|
59
66
|
catch (err) {
|
|
60
67
|
if (!sentClassifiedFailure(res, ctx, "provenance", err))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ControlPlaneCorruptError } from "@sema-agent/core";
|
|
3
3
|
import { sendJson, sendError } from "../send.js";
|
|
4
|
+
import { sentMemoryLayerRefusal } from "../memory-layer-reply.js";
|
|
4
5
|
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sendOperatorPrincipalsRequired } from "../principal-gate.js";
|
|
5
6
|
import { assertNever } from "../route-ctx.js";
|
|
6
7
|
import * as facts from "../../capability-facts.js";
|
|
@@ -101,7 +102,15 @@ export async function handleMemoryConsolidation(req, res, match, ctx) {
|
|
|
101
102
|
const q = new URLSearchParams(match.search).get("scope") ?? undefined;
|
|
102
103
|
const decided = decideScope(q, faces.scopes);
|
|
103
104
|
const scope = "scope" in decided ? decided.scope : undefined;
|
|
104
|
-
|
|
105
|
+
let row;
|
|
106
|
+
try {
|
|
107
|
+
row = scope !== undefined ? faces.lastRun(scope) : undefined;
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
if (sentMemoryLayerRefusal(res, err, { kind: "operator" }))
|
|
111
|
+
return;
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
105
114
|
sendJson(res, 200, {
|
|
106
115
|
enabled: true,
|
|
107
116
|
seat: faces.seat,
|
|
@@ -144,6 +153,8 @@ export async function handleMemoryConsolidation(req, res, match, ctx) {
|
|
|
144
153
|
sendJson(res, 200, buildRunSummary(r));
|
|
145
154
|
}
|
|
146
155
|
catch (err) {
|
|
156
|
+
if (sentMemoryLayerRefusal(res, err, { kind: "operator" }))
|
|
157
|
+
return;
|
|
147
158
|
const coreCode = codeOf(err);
|
|
148
159
|
if (coreCode !== undefined) {
|
|
149
160
|
sendError(res, 409, "memory.consolidation_refused", `memory consolidation refused (${coreCode}): ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -3,6 +3,7 @@ import { ControlPlaneCorruptError } from "@sema-agent/core";
|
|
|
3
3
|
import { sendJson, sendError } from "../send.js";
|
|
4
4
|
import { sentMemoryStoreRefusal } from "../memory-store-refusal-reply.js";
|
|
5
5
|
import { buildOriginFence, readOriginAware } from "../../memory-origin-fence.js";
|
|
6
|
+
import { readLayerSeat, sentMemoryLayerRefusal } from "../memory-layer-reply.js";
|
|
6
7
|
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
|
|
7
8
|
import { assertNever } from "../route-ctx.js";
|
|
8
9
|
import * as facts from "../../capability-facts.js";
|
|
@@ -49,6 +50,8 @@ function codeOf(err) {
|
|
|
49
50
|
return typeof code === "string" ? code : undefined;
|
|
50
51
|
}
|
|
51
52
|
function sentClassifiedFailure(res, ctx, face, err) {
|
|
53
|
+
if (sentMemoryLayerRefusal(res, err, { kind: "operator" }))
|
|
54
|
+
return true;
|
|
52
55
|
if (face === "clear") {
|
|
53
56
|
const coreCode = codeOf(err);
|
|
54
57
|
if (coreCode !== undefined && sentClearCode(res, coreCode, err instanceof Error ? err.message : String(err)))
|
|
@@ -157,8 +160,12 @@ export async function handleMemoryOrigin(req, res, match, ctx) {
|
|
|
157
160
|
return;
|
|
158
161
|
}
|
|
159
162
|
case "memory-origin-clearances": {
|
|
163
|
+
const query = new URLSearchParams(match.search);
|
|
164
|
+
const at = readLayerSeat(res, query.has("scope"), query.get("scope"));
|
|
165
|
+
if (at === null)
|
|
166
|
+
return;
|
|
160
167
|
try {
|
|
161
|
-
sendJson(res, 200, { clearances: faces.listClearances().map(buildClearanceRowWire) });
|
|
168
|
+
sendJson(res, 200, { clearances: (at !== undefined ? faces.listClearances(at) : faces.listClearances()).map(buildClearanceRowWire) });
|
|
162
169
|
}
|
|
163
170
|
catch (err) {
|
|
164
171
|
if (!sentClassifiedFailure(res, ctx, "clearances", err))
|
|
@@ -182,8 +189,13 @@ export async function handleMemoryOrigin(req, res, match, ctx) {
|
|
|
182
189
|
sendError(res, 400, "request.body_shape", "invalid memory origin clearance request — expected an object with a non-empty `requestId` and a `reason` string (whether an EMPTY reason is acceptable is the engine's judgment, not this layer's)");
|
|
183
190
|
return;
|
|
184
191
|
}
|
|
192
|
+
const body = raw;
|
|
193
|
+
const at = readLayerSeat(res, Object.prototype.hasOwnProperty.call(body, "scope"), body.scope);
|
|
194
|
+
if (at === null)
|
|
195
|
+
return;
|
|
185
196
|
try {
|
|
186
|
-
const
|
|
197
|
+
const input = { requestId: parsed.data.requestId, reason: parsed.data.reason };
|
|
198
|
+
const receipt = await (at !== undefined ? faces.clear(entryId, input, at) : faces.clear(entryId, input));
|
|
187
199
|
ctx.deps.logger?.info?.("memory_origin_cleared", {
|
|
188
200
|
principal: principal ?? null,
|
|
189
201
|
entryId,
|
|
@@ -5,6 +5,7 @@ import { buildOriginFence, readOriginAware } from "../../memory-origin-fence.js"
|
|
|
5
5
|
import { parseProjectLayerKey } from "../../project-layer-key.js";
|
|
6
6
|
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sendUnauthorized } from "../principal-gate.js";
|
|
7
7
|
import { assertNever } from "../route-ctx.js";
|
|
8
|
+
import { sentMemoryLayerRefusal } from "../memory-layer-reply.js";
|
|
8
9
|
const ORG_PREFIX = "org:";
|
|
9
10
|
export const MEMORY_EXPORT_MAX_LIMIT = 500;
|
|
10
11
|
function encodeExportCursor(c) {
|
|
@@ -121,6 +122,8 @@ export async function handleMemoryPolicy(req, res, match, ctx) {
|
|
|
121
122
|
});
|
|
122
123
|
}
|
|
123
124
|
catch (err) {
|
|
125
|
+
if (sentMemoryLayerRefusal(res, err, { kind: "operator" }))
|
|
126
|
+
return;
|
|
124
127
|
deps.logger?.warn?.("memory_export_failed", { scope, err: String(err) });
|
|
125
128
|
sendError(res, 500, "internal.error", "memory export failed");
|
|
126
129
|
}
|
|
@@ -158,6 +161,8 @@ export async function handleMemoryPolicy(req, res, match, ctx) {
|
|
|
158
161
|
sendJson(res, 200, out);
|
|
159
162
|
}
|
|
160
163
|
catch (err) {
|
|
164
|
+
if (sentMemoryLayerRefusal(res, err, { kind: "operator" }))
|
|
165
|
+
return;
|
|
161
166
|
deps.logger?.warn?.("memory_sync_failed", { scope, peer: parsed.value.peer, err: String(err) });
|
|
162
167
|
sendError(res, 500, "internal.error", "memory sync failed");
|
|
163
168
|
}
|
|
@@ -18,6 +18,10 @@ import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
|
18
18
|
import { readSessionRulesRecords, describeSessionRulesRecordProblem } from "../../session-policy-wire.js";
|
|
19
19
|
import { readSessionPinned, readSessionTitle } from "../../session-row.js";
|
|
20
20
|
import { sessionFaceOfHead } from "../../session-incarnation.js";
|
|
21
|
+
import { defaultTaskRegistry } from "@sema-agent/core";
|
|
22
|
+
import { SessionActiveRunError, SessionForkInProgressError, SessionWriterPresentError } from "../../execution-placement.js";
|
|
23
|
+
import { probeSessionChildren, sessionChildrenScope } from "../../session-children-retire.js";
|
|
24
|
+
import { liveChildrenRefusal } from "./background.js";
|
|
21
25
|
export function createSessionSyncLocal() {
|
|
22
26
|
const pendingStagings = new Map();
|
|
23
27
|
const importLeases = new Map();
|
|
@@ -90,7 +94,46 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
90
94
|
const replaySessionRow = async (row, face) => {
|
|
91
95
|
if (Object.keys(row).length === 0)
|
|
92
96
|
return true;
|
|
93
|
-
|
|
97
|
+
if (face === undefined)
|
|
98
|
+
return false;
|
|
99
|
+
const replayed = await sessionStorage.writeSessionRowCells(sessionId, row, { writer: "replay", row: { row: face } });
|
|
100
|
+
switch (replayed.kind) {
|
|
101
|
+
case "written":
|
|
102
|
+
return true;
|
|
103
|
+
case "absent":
|
|
104
|
+
return false;
|
|
105
|
+
default: {
|
|
106
|
+
const unreachable = replayed;
|
|
107
|
+
throw new Error(`session-sync row replay: no answer for the row write outcome ${JSON.stringify(unreachable)}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const liveChildrenOf = async (face) => face === undefined
|
|
112
|
+
? []
|
|
113
|
+
: (await probeSessionChildren({ agentStore: deps.backgroundAgentStore, checkpointStore: deps.checkpointStore, registry: defaultTaskRegistry }, sessionId, sessionChildrenScope(face.owner))).liveChildren;
|
|
114
|
+
const activityOf = async (face) => {
|
|
115
|
+
const activeTaskId = await deps.runStore?.getActiveTaskId(sessionId);
|
|
116
|
+
if (activeTaskId)
|
|
117
|
+
return { kind: "run", activeTaskId };
|
|
118
|
+
const liveChildren = await liveChildrenOf(face);
|
|
119
|
+
return liveChildren.length > 0 ? { kind: "children", liveChildren } : undefined;
|
|
120
|
+
};
|
|
121
|
+
const sendActivity = (activity, moment) => {
|
|
122
|
+
switch (activity.kind) {
|
|
123
|
+
case "run":
|
|
124
|
+
if (moment === "open")
|
|
125
|
+
sendError(res, 409, "session_active", "session has an active run; sync after it settles", { activeTaskId: activity.activeTaskId });
|
|
126
|
+
else
|
|
127
|
+
sendError(res, 409, "session_active", "session started an active run while the import streamed; sync after it settles", { activeTaskId: activity.activeTaskId });
|
|
128
|
+
return;
|
|
129
|
+
case "children":
|
|
130
|
+
sendError(res, 409, "session_active", "session still has background agents running or waiting on an approval under it; retire them (POST retirePath) or let them finish, then sync", liveChildrenRefusal(sessionId, activity.liveChildren));
|
|
131
|
+
return;
|
|
132
|
+
default: {
|
|
133
|
+
const unhandled = activity;
|
|
134
|
+
throw new Error(`session sync: unknown session activity ${JSON.stringify(unhandled)}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
94
137
|
};
|
|
95
138
|
const canReplayHistory = fileHistoryImportFace(historyStore) !== undefined;
|
|
96
139
|
const replayHistory = async (envelope, allowReplace) => {
|
|
@@ -339,15 +382,56 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
339
382
|
if (!payloadVerified)
|
|
340
383
|
digestSaysDiffer = true;
|
|
341
384
|
}
|
|
385
|
+
const placed = gateFace === undefined ? undefined : await sessionStorage.executionPlacement?.read(sessionId);
|
|
386
|
+
if (placed !== undefined) {
|
|
387
|
+
switch (placed.cell.role) {
|
|
388
|
+
case "absent":
|
|
389
|
+
case "mirror":
|
|
390
|
+
break;
|
|
391
|
+
case "writer":
|
|
392
|
+
sendSessionWriter(res);
|
|
393
|
+
return;
|
|
394
|
+
case "forking":
|
|
395
|
+
sendError(res, 409, "conflict.fork_in_progress", new SessionForkInProgressError(sessionId).message);
|
|
396
|
+
return;
|
|
397
|
+
default: {
|
|
398
|
+
const unknownRole = placed.cell;
|
|
399
|
+
throw new Error(`session sync: unknown execution placement ${JSON.stringify(unknownRole)}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const activeNow = await activityOf(gateFace);
|
|
404
|
+
if (activeNow !== undefined) {
|
|
405
|
+
sendActivity(activeNow, "open");
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
342
408
|
if (relA.relation === "identical" && !digestSaysDiffer) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
409
|
+
const seat = sessionStorage.executionPlacement;
|
|
410
|
+
if (seat !== undefined) {
|
|
411
|
+
if (gateFace === undefined) {
|
|
412
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
const mirrored = await seat.markMirror(sessionId, gateFace);
|
|
416
|
+
switch (mirrored.outcome) {
|
|
417
|
+
case "mirrored":
|
|
418
|
+
break;
|
|
419
|
+
case "writer":
|
|
420
|
+
sendSessionWriter(res);
|
|
421
|
+
return;
|
|
422
|
+
case "gone":
|
|
423
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
424
|
+
return;
|
|
425
|
+
case "active":
|
|
426
|
+
sendActivity({ kind: "run", activeTaskId: mirrored.activeTaskId }, "open");
|
|
348
427
|
return;
|
|
428
|
+
default: {
|
|
429
|
+
const unhandled = mirrored;
|
|
430
|
+
throw new Error(`session sync: unknown mirror outcome ${JSON.stringify(unhandled)}`);
|
|
349
431
|
}
|
|
350
432
|
}
|
|
433
|
+
}
|
|
434
|
+
if (fileHistory !== null && canReplayHistory) {
|
|
351
435
|
const failed = await replayHistory(fileHistory, resolution === "overwrite-dst");
|
|
352
436
|
if (failed !== undefined) {
|
|
353
437
|
sendFileHistoryReplayFailure(res, failed);
|
|
@@ -380,11 +464,6 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
380
464
|
});
|
|
381
465
|
return;
|
|
382
466
|
}
|
|
383
|
-
const activeTaskId = await deps.runStore?.getActiveTaskId(sessionId);
|
|
384
|
-
if (activeTaskId) {
|
|
385
|
-
sendError(res, 409, "session_active", "session has an active run; sync after it settles", { activeTaskId });
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
467
|
const heldLease = importLeases.get(sessionId);
|
|
389
468
|
if (heldLease) {
|
|
390
469
|
const staleSecRaw = deps.config.syncImportLeaseStaleSec;
|
|
@@ -511,8 +590,9 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
511
590
|
let mayPushAtCommit;
|
|
512
591
|
let activeAtCommit;
|
|
513
592
|
try {
|
|
514
|
-
|
|
515
|
-
|
|
593
|
+
const gateAtCommit = await judgeSessionGate();
|
|
594
|
+
mayPushAtCommit = gateAtCommit.mayPush;
|
|
595
|
+
activeAtCommit = mayPushAtCommit ? await activityOf(gateAtCommit.face) : undefined;
|
|
516
596
|
}
|
|
517
597
|
catch (e) {
|
|
518
598
|
await pending.handle.abort().catch(() => undefined);
|
|
@@ -525,10 +605,10 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
525
605
|
sendSessionAbsent();
|
|
526
606
|
return;
|
|
527
607
|
}
|
|
528
|
-
if (activeAtCommit) {
|
|
608
|
+
if (activeAtCommit !== undefined) {
|
|
529
609
|
await pending.handle.abort().catch(() => undefined);
|
|
530
610
|
cleanupStaging(stagingId);
|
|
531
|
-
|
|
611
|
+
sendActivity(activeAtCommit, "streamed");
|
|
532
612
|
return;
|
|
533
613
|
}
|
|
534
614
|
try {
|
|
@@ -567,6 +647,18 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
567
647
|
sendError(res, 409, "conflict", "sync conflict", { relation: e.relation });
|
|
568
648
|
return;
|
|
569
649
|
}
|
|
650
|
+
if (e instanceof SessionWriterPresentError) {
|
|
651
|
+
sendSessionWriter(res);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (e instanceof SessionForkInProgressError) {
|
|
655
|
+
sendError(res, 409, "conflict.fork_in_progress", e.message);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
if (e instanceof SessionActiveRunError) {
|
|
659
|
+
sendActivity({ kind: "run", activeTaskId: e.activeTaskId }, "streamed");
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
570
662
|
if (sendSessionPolicyError(res, e))
|
|
571
663
|
return;
|
|
572
664
|
if (sendSessionError(res, e, "import")) {
|
|
@@ -635,6 +727,9 @@ function sendPullUnreadable(req, res, logger, e) {
|
|
|
635
727
|
}
|
|
636
728
|
}
|
|
637
729
|
}
|
|
730
|
+
function sendSessionWriter(res) {
|
|
731
|
+
sendError(res, 409, "conflict.session_writer", "this session is written on this deployment (its execution placement is a writer here) — an import cannot turn it into a read-only mirror; fork it to push your copy, or pull instead; nothing was written");
|
|
732
|
+
}
|
|
638
733
|
function sendMissingBlob(res) {
|
|
639
734
|
sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
|
|
640
735
|
}
|
|
@@ -74,6 +74,12 @@ export declare const SESSIONS_ROUTES: readonly [{
|
|
|
74
74
|
readonly pattern: RegExp;
|
|
75
75
|
readonly label: "/v1/sessions/:id/$verb";
|
|
76
76
|
readonly methods: readonly ["GET"];
|
|
77
|
+
}, {
|
|
78
|
+
readonly id: "session-execution-placement";
|
|
79
|
+
readonly pattern: RegExp;
|
|
80
|
+
readonly label: "/v1/sessions/:id/execution-placement";
|
|
81
|
+
readonly credentialGated: readonly ["GET"];
|
|
82
|
+
readonly methods: readonly ["GET"];
|
|
77
83
|
}, {
|
|
78
84
|
readonly id: "session-events";
|
|
79
85
|
readonly pattern: RegExp;
|