@sema-agent/server 7.150.0 → 7.151.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 +185 -0
- package/USAGE.md +53 -25
- package/deploy/sema-up/README.md +7 -1
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
- package/deploy/sema-up/chart/templates/server.yaml +5 -3
- package/deploy/sema-up/chart/values-full-single.yaml +3 -1
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +1 -0
- package/deploy/sema-up/kube-up.sh +1 -1
- package/deploy/sema-up/lib/flagshape.sh +1 -1
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-machine.d.ts +1 -1
- package/dist/approval-card.d.ts +2 -2
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/auth-bridge.d.ts +20 -0
- package/dist/auth-bridge.js +9 -0
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/bake-runner/main.d.ts +4 -2
- package/dist/bind-host.d.ts +2 -3
- package/dist/bind-host.js +2 -4
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +8 -14
- package/dist/boot/execution-env.js +54 -17
- package/dist/boot/execution-lane.js +32 -5
- package/dist/boot/late-binds.d.ts +8 -4
- package/dist/boot/late-binds.js +7 -1
- package/dist/boot/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/reapers.d.ts +5 -0
- package/dist/boot/reapers.js +12 -1
- package/dist/boot/resolve-spec.d.ts +3 -3
- package/dist/boot/resolve-spec.js +31 -22
- package/dist/boot/runner-deps.d.ts +9 -2
- package/dist/boot/runner-deps.js +3 -3
- package/dist/boot/session-age-out.d.ts +36 -0
- package/dist/boot/session-age-out.js +101 -0
- package/dist/boot/session-faces.d.ts +5 -14
- package/dist/boot/session-faces.js +9 -5
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +7 -4
- package/dist/boot/stage-06-runners.js +15 -6
- package/dist/boot/stage-07-capability-layer.d.ts +7 -4
- package/dist/boot/stage-07-capability-layer.js +2 -1
- package/dist/boot/stage-08-reapers.d.ts +7 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +11 -5
- package/dist/boot/stage-09-leader.js +12 -3
- package/dist/boot/stage-10-http-server.d.ts +11 -5
- package/dist/boot/stage-10-http-server.js +3 -6
- package/dist/boot/web-admin.js +3 -1
- package/dist/boot/workflow-orchestration.d.ts +7 -2
- package/dist/boot/workflow-orchestration.js +24 -7
- package/dist/bounded-rotation.d.ts +29 -0
- package/dist/bounded-rotation.js +24 -0
- package/dist/capability-facts.d.ts +22 -13
- package/dist/capability-facts.js +28 -18
- package/dist/center-credential.d.ts +25 -6
- package/dist/center-credential.js +25 -5
- package/dist/config-catalog.d.ts +26 -7
- package/dist/config-catalog.js +14 -11
- package/dist/config-invariants.d.ts +2 -1
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +10 -4
- package/dist/config.d.ts +51 -2
- package/dist/config.js +35 -24
- package/dist/deployment-shape.d.ts +9 -1
- package/dist/deployment-shape.js +2 -1
- package/dist/device-protocol.d.ts +5 -4
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.js +3 -2
- package/dist/device-ws-protocol.d.ts +63 -10
- package/dist/device-ws-protocol.js +56 -25
- package/dist/engine-identity.d.ts +19 -7
- package/dist/engine-identity.js +10 -2
- package/dist/entry-mode-clamp-notice.d.ts +2 -1
- package/dist/execution-env-refusal.d.ts +23 -0
- package/dist/execution-env-refusal.js +5 -0
- package/dist/execution-lane-caps.d.ts +3 -1
- package/dist/field-conflict.d.ts +1 -1
- package/dist/file-history-capture.d.ts +11 -4
- package/dist/file-history-capture.js +9 -6
- package/dist/file-history-disclosure.d.ts +7 -5
- package/dist/file-history-disclosure.js +7 -5
- package/dist/fleet/drain-entry.d.ts +4 -0
- package/dist/hooks/hook-runner.js +2 -2
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/admission.js +17 -2
- package/dist/http/approval-sweeps.js +5 -5
- package/dist/http/checkpoint-ctx.d.ts +2 -0
- package/dist/http/checkpoint-ctx.js +1 -0
- package/dist/http/dispatch.d.ts +2 -1
- package/dist/http/dispatch.js +34 -27
- package/dist/http/durable-run-leg.js +16 -16
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +2 -0
- package/dist/http/owner-access.d.ts +31 -11
- package/dist/http/owner-access.js +37 -6
- package/dist/http/resume-ctx-read.js +25 -3
- package/dist/http/resume-legs.d.ts +2 -1
- package/dist/http/resume-legs.js +259 -79
- package/dist/http/route-ctx.d.ts +18 -8
- package/dist/http/route-table.d.ts +1 -1
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.js +4 -3
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.js +8 -5
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/projects.d.ts +3 -2
- package/dist/http/routes/projects.js +4 -5
- package/dist/http/routes/runs.js +102 -36
- package/dist/http/routes/session-sync.d.ts +4 -3
- package/dist/http/routes/session-sync.js +172 -77
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.js +10 -6
- package/dist/http/routes/tasks.js +30 -16
- package/dist/http/routes/trace-usage.js +2 -2
- package/dist/http/server.d.ts +21 -27
- package/dist/http/server.js +2 -2
- package/dist/http/submit-ctx.js +5 -4
- package/dist/http/wire-types.d.ts +14 -4
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +4 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +0 -1
- package/dist/leader/leader.d.ts +2 -1
- package/dist/leg-facts.d.ts +13 -5
- package/dist/leg-facts.js +2 -1
- package/dist/memory-scope.d.ts +5 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +7 -3
- package/dist/observability/fail-open.js +7 -3
- package/dist/observability/metrics.js +1 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
- package/dist/orchestration/workflow-notify-journal.js +12 -1
- package/dist/orchestration/workflow-park-decision.d.ts +70 -18
- package/dist/orchestration/workflow-park-decision.js +49 -10
- package/dist/orchestration/workflow-park-holder.d.ts +65 -0
- package/dist/orchestration/workflow-park-holder.js +98 -0
- package/dist/orchestration/workflow-record-fence.d.ts +36 -0
- package/dist/orchestration/workflow-record-fence.js +42 -0
- package/dist/owner-faces.d.ts +1 -1
- package/dist/parked-decide.d.ts +104 -53
- package/dist/parked-decide.js +153 -117
- package/dist/peer-directory.d.ts +2 -2
- package/dist/peer-inbound-face.d.ts +2 -6
- package/dist/peer-inbound-face.js +0 -3
- package/dist/permission-mode-admission.d.ts +41 -5
- package/dist/permission-mode-admission.js +29 -3
- package/dist/plugins/adoption-log-sql.d.ts +3 -1
- package/dist/plugins/adoption-log-sql.js +7 -1
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +8 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
- package/dist/plugins/approval-ask-store-memory.js +28 -9
- package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
- package/dist/plugins/approval-ask-store-sql.js +34 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- package/dist/plugins/breaker-state-sql.js +2 -0
- package/dist/plugins/caching-session-store.d.ts +9 -15
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/device-store-sql.js +6 -0
- package/dist/plugins/error-origin.d.ts +18 -0
- package/dist/plugins/error-origin.js +10 -0
- package/dist/plugins/execution-placement-sql.js +6 -6
- package/dist/plugins/image-bake-store-sql.js +6 -0
- package/dist/plugins/image-index-sql.js +4 -0
- package/dist/plugins/landed-attendants.d.ts +212 -0
- package/dist/plugins/landed-attendants.js +161 -0
- package/dist/plugins/leader-run-store-sql.js +4 -0
- package/dist/plugins/local-session-live-reference.d.ts +40 -0
- package/dist/plugins/local-session-live-reference.js +39 -0
- package/dist/plugins/local-session-store.d.ts +71 -33
- package/dist/plugins/local-session-store.js +129 -27
- package/dist/plugins/memory-engine-pg.js +4 -0
- package/dist/plugins/memory-engine-sql-apply.js +5 -2
- package/dist/plugins/memory-engine-tidb.js +4 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
- package/dist/plugins/memory-sync-store-pg.js +5 -0
- package/dist/plugins/memory-sync-store-tidb.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +57 -63
- package/dist/plugins/one-time-migrations.js +162 -90
- package/dist/plugins/org-delivery-quota-store.js +4 -1
- package/dist/plugins/outcome-ledger-sql.js +2 -0
- package/dist/plugins/permission-rule-store-sql.js +11 -4
- package/dist/plugins/pg-cost-quota.js +4 -0
- package/dist/plugins/pg-pool.js +24 -1
- package/dist/plugins/pg-rate-limiter.js +2 -0
- package/dist/plugins/posix-shell-fs.d.ts +6 -1
- package/dist/plugins/posix-shell-fs.js +4 -1
- package/dist/plugins/remote-env-adb.d.ts +19 -15
- package/dist/plugins/remote-env-adb.js +41 -15
- package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
- package/dist/plugins/remote-env-connect-seat.js +72 -0
- package/dist/plugins/remote-env-device.d.ts +22 -5
- package/dist/plugins/remote-env-device.js +106 -8
- package/dist/plugins/remote-env-e2b.d.ts +15 -6
- package/dist/plugins/remote-env-e2b.js +42 -32
- package/dist/plugins/remote-env-file-error.js +6 -2
- package/dist/plugins/remote-env-host.d.ts +17 -0
- package/dist/plugins/remote-env-host.js +30 -38
- package/dist/plugins/remote-env-k8s.d.ts +41 -39
- package/dist/plugins/remote-env-k8s.js +53 -30
- package/dist/plugins/remote-env-local-docker.d.ts +13 -8
- package/dist/plugins/remote-env-local-docker.js +34 -41
- package/dist/plugins/remote-env-ssh.d.ts +18 -12
- package/dist/plugins/remote-env-ssh.js +60 -59
- package/dist/plugins/remote-shell.d.ts +98 -1
- package/dist/plugins/remote-shell.js +218 -0
- package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
- package/dist/plugins/resume-anchor-store-sql.js +12 -5
- package/dist/plugins/retention-lane-store-sql.js +4 -0
- package/dist/plugins/retention-sql.d.ts +20 -2
- package/dist/plugins/retention-sql.js +11 -0
- package/dist/plugins/run-store-sql.d.ts +21 -2
- package/dist/plugins/run-store-sql.js +31 -7
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
- package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
- package/dist/plugins/schema-consistency.d.ts +4 -2
- package/dist/plugins/schema-consistency.js +19 -2
- package/dist/plugins/send-file-ledger.js +3 -0
- package/dist/plugins/serving-requirement.d.ts +26 -7
- package/dist/plugins/serving-requirement.js +11 -4
- package/dist/plugins/session-birth.d.ts +6 -2
- package/dist/plugins/session-capture-record-store-sql.js +2 -0
- package/dist/plugins/session-ext-table.d.ts +14 -1
- package/dist/plugins/session-ext-table.js +5 -1
- package/dist/plugins/session-row-sql.d.ts +49 -2
- package/dist/plugins/session-row-sql.js +56 -13
- package/dist/plugins/session-store-sql.d.ts +34 -18
- package/dist/plugins/session-store-sql.js +98 -17
- package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
- package/dist/plugins/shared-memory-store-sql.js +6 -2
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/sql-driver.js +18 -3
- package/dist/plugins/sql-errors.d.ts +11 -6
- package/dist/plugins/sql-errors.js +5 -6
- package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
- package/dist/plugins/stop-then-start-sentence.js +14 -10
- package/dist/plugins/stop-then-start.d.ts +109 -0
- package/dist/plugins/stop-then-start.js +104 -0
- package/dist/plugins/store-backend.d.ts +40 -13
- package/dist/plugins/store-backend.js +169 -27
- package/dist/plugins/store-boundary.d.ts +57 -0
- package/dist/plugins/store-boundary.js +139 -0
- package/dist/plugins/store-contracts.d.ts +17 -0
- package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
- package/dist/plugins/store-fault-sentence-m53.js +25 -0
- package/dist/plugins/store-fault.d.ts +26 -7
- package/dist/plugins/store-fault.js +18 -2
- package/dist/plugins/task-attachment-store.js +9 -0
- package/dist/plugins/task-list-store-sql.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.js +10 -8
- package/dist/plugins/tidb-cost-quota.js +4 -0
- package/dist/plugins/tidb-pool.js +2 -1
- package/dist/plugins/tidb-rate-limiter.js +4 -0
- package/dist/plugins/user-input-ledger-sql.js +4 -0
- package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
- package/dist/plugins/workflow-run-store-sql.js +64 -4
- package/dist/plugins/workspace-fill.d.ts +4 -7
- package/dist/plugins/workspace-fill.js +2 -1
- package/dist/plugins/write-behind-counter.js +5 -0
- package/dist/project-context.d.ts +0 -2
- package/dist/project-context.js +4 -8
- package/dist/project-registry.d.ts +46 -0
- package/dist/project-registry.js +44 -0
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +4 -0
- package/dist/request-value-closure.js +10 -0
- package/dist/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +37 -8
- package/dist/runs.js +53 -12
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +30 -32
- package/dist/security.js +41 -7
- package/dist/server-secret-env.d.ts +12 -10
- package/dist/server-secret-env.js +24 -15
- package/dist/session-bindings.d.ts +82 -0
- package/dist/session-bindings.js +18 -0
- package/dist/session-children-retire.d.ts +2 -2
- package/dist/session-children-retire.js +2 -6
- package/dist/session-deletion.d.ts +16 -1
- package/dist/session-error-wire.d.ts +3 -3
- package/dist/session-error-wire.js +3 -3
- package/dist/session-incarnation.d.ts +10 -0
- package/dist/session-incarnation.js +10 -1
- package/dist/session-kind.d.ts +57 -0
- package/dist/session-kind.js +22 -0
- package/dist/session-row.d.ts +21 -1
- package/dist/session-row.js +7 -1
- package/dist/session-sync-kernel.d.ts +24 -14
- package/dist/session-sync-kernel.js +3 -6
- package/dist/session-sync.d.ts +4 -98
- package/dist/session-sync.js +1 -71
- package/dist/session-titler.d.ts +10 -3
- package/dist/session-titler.js +19 -6
- package/dist/ssh-host-key.d.ts +5 -0
- package/dist/ssh-host-key.js +3 -0
- package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
- package/dist/stores-sql/file-history-store-sql.js +108 -70
- package/dist/stores-sql/pg-session-storage.d.ts +34 -7
- package/dist/stores-sql/pg-session-storage.js +37 -13
- package/dist/stores-sql/retention-store-sql.d.ts +1 -9
- package/dist/stores-sql/retention-store-sql.js +2 -10
- package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
- package/dist/stores-sql/session-policy-store-sql.js +61 -44
- package/dist/stores-sql/session-write-hooks.d.ts +11 -0
- package/dist/stores-sql/tidb-session-store.d.ts +58 -7
- package/dist/stores-sql/tidb-session-store.js +37 -13
- package/dist/submission-exit.d.ts +3 -2
- package/dist/submission-exit.js +9 -1
- package/dist/task-cwd.d.ts +2 -2
- package/dist/task-settings.d.ts +6 -5
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +140 -6
- package/dist/tool-approval.js +165 -72
- package/dist/trace/self-minted-wire.d.ts +290 -27
- package/dist/trace/self-minted-wire.js +101 -13
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +78 -27
- package/package.json +2 -2
- package/wire-changes/server@7.151.0.json +762 -0
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* ── 读口:逐字投 core `list()` 行 ─────────────────────────────────────────────────────────────────
|
|
11
11
|
* 读的是**进程内**注册表(`defaultTaskRegistry.list`),访问元组 = 会话自己的 `{ owner: sid, sessionId: sid, scope }`
|
|
12
|
-
* (scope =
|
|
12
|
+
* (scope = 会话的引擎租户分区 `sessionTenantScope`,经唯一换算 `engineScopeOfOwner`,与 core 注册铸值同源)⇒ 可见集完全由 core 的 `canAccess` 判(fail-closed:
|
|
13
13
|
* 缺轴即拒;本会话的会话驻留行、task id 即会话 id 的 run 行、本会话发起的 workflow、根会话是本会话的后台 agent)。
|
|
14
14
|
* 键逐个处置(下面的 {@link ROW_KEY_DISPOSITION},core 给行加键 ⇒ 编译红):`task_id` 改名 `id`;`retained` **真才带**
|
|
15
15
|
* (core:缺席 ⇒ 这一行在 `includeRetained:false` 的硬面上会停);`description` 是模型写的描述、缺席时是启动时的命令文本 ——
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
*
|
|
41
41
|
* 🔴 **停止口在无凭据写门内**(`credentialGated: ["POST"]`;车OL F1 = 7.102.0 合并复审 gpt-6 腿 [high]):门的两个合取项它都中
|
|
42
42
|
* —— ① 授权的唯一输入是 principal 头(属主判 `admitSessionRow` 与 operator 臂 `explicitOperatorOk` 读的都是 `gatedSubject`,
|
|
43
|
-
*
|
|
44
|
-
* 进程,`includeRetained:true` 连显式 retain 的活服务一起停)。于是无 service 凭证且未开 `ALLOW_UNAUTHED_WRITES`
|
|
43
|
+
* 没带过门凭据的请求上它收调用方自报的头);② 不可撤销、爆炸半径跨租户(知道会话 id + 自报它的属主 ⇒ 停掉那个会话的后台
|
|
44
|
+
* 进程,`includeRetained:true` 连显式 retain 的活服务一起停)。于是无 service 凭证且未开 `ALLOW_UNAUTHED_WRITES` 的部署上,不带过门凭据的请求打它与
|
|
45
45
|
* 其余改写门同码同句 503 `auth.service_token_required`(在路由之前,`dispatch.ts` 那一道),同一只会话级收敛函数的另一个调用点
|
|
46
46
|
* `DELETE /v1/sessions/:id` 早在同一形下被 `isDestructiveSessionWrite` 拒。读口 `GET …/background` 不进:它有属主门兜底、只读、
|
|
47
47
|
* 只列本会话,与 `GET /v1/rules` 同判。已知同族缺口(不在本口单独打补丁):能力位 `exitFaces` 不含「凭据就绪」这一项,见契约
|
|
@@ -19,7 +19,7 @@ import { sendJson, sendError } from "../send.js";
|
|
|
19
19
|
import { codeFieldOf } from "../../terminal.js";
|
|
20
20
|
import { engineRefusalAnswerOf } from "../engine-refusal.js";
|
|
21
21
|
import { assertNever } from "../route-ctx.js";
|
|
22
|
-
import { fileHistoryCaptureOf } from "../../file-history-capture.js";
|
|
22
|
+
import { fileHistoryCaptureOf, fileHistoryWired } from "../../file-history-capture.js";
|
|
23
23
|
import { projectMemoryEngineCapability } from "../../memory-posture.js";
|
|
24
24
|
import { projectWriteProtectionCapability } from "../../write-protection.js";
|
|
25
25
|
import { projectStoreCapability, unwiredStorePosture } from "../../store-posture.js";
|
|
@@ -27,6 +27,7 @@ import { projectWebSearchCapability } from "../../plugins/web-search.js";
|
|
|
27
27
|
import { projectExecutionLaneCapability } from "../../capabilities/execution-lane.js";
|
|
28
28
|
import { SETTINGS_CONTRACT_CAPABILITY } from "../../capabilities/settings-contract.js";
|
|
29
29
|
import { judgeSandboxGitPlane, sandboxGitPlanePremisesOf } from "../../sandbox-git-plane.js";
|
|
30
|
+
import { SESSION_KINDS } from "../../session-kind.js";
|
|
30
31
|
import { MCP_ASSERTION_HEADER_SENT, MCP_REQUEST_TRANSPORT_KINDS } from "../../mcp-assertion-header.js";
|
|
31
32
|
import { gateCompositeMembers } from "../../capabilities/composite-members.js";
|
|
32
33
|
import { projectApprovalsStreamLiveCapability } from "../../capabilities/approvals-push.js";
|
|
@@ -84,6 +85,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
84
85
|
deps.logger?.warn("auto_mode_face_resolver_fault", { fault: autoModeFault });
|
|
85
86
|
const rulesLaneForCaller = facts.ruleLaneForCaller(deps, gatedPerson(req, deps.config)).available;
|
|
86
87
|
const streamApprovalFact = facts.streamApproval(deps);
|
|
88
|
+
const historyWired = fileHistoryWired(deps.backend);
|
|
87
89
|
sendJson(res, 200, gateCompositeMembers({
|
|
88
90
|
...deps.capabilities,
|
|
89
91
|
...facts.engineCapabilityBits(),
|
|
@@ -213,17 +215,18 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
213
215
|
scenarioSubject: true,
|
|
214
216
|
sessionList: facts.sessionList(deps).available,
|
|
215
217
|
sessionSearch: facts.sessionList(deps).available,
|
|
218
|
+
sessionKinds: facts.sessionKinds(deps).available ? [...SESSION_KINDS] : [],
|
|
216
219
|
sessionFork: facts.sessionFork(deps).available,
|
|
217
220
|
sessionDelete: facts.sessionDelete(deps).available,
|
|
218
|
-
resumeAt:
|
|
221
|
+
resumeAt: deps.backend !== undefined && headReadPresent(deps.sessionStorage),
|
|
219
222
|
promptSuggestions: true,
|
|
220
223
|
sessionPolicy: facts.sessionPolicy(deps).available,
|
|
221
224
|
sessionRulesNamespaceForms: sessionRulesNamespaceFormsHonored(),
|
|
222
|
-
restoreFiles:
|
|
223
|
-
rewindFilesTo:
|
|
225
|
+
restoreFiles: historyWired,
|
|
226
|
+
rewindFilesTo: historyWired && headReadPresent(deps.sessionStorage),
|
|
224
227
|
sessionRewindFiles: facts.sessionRewindFiles(deps).available,
|
|
225
228
|
sessionRewindFilesPreview: facts.sessionRewindFilesPreview(deps).available,
|
|
226
|
-
fileHistoryCapture: fileHistoryCaptureOf(
|
|
229
|
+
fileHistoryCapture: fileHistoryCaptureOf(historyWired, deps.config.fileHistoryCapture),
|
|
227
230
|
scheduler: facts.hostScheduler(deps.config).available,
|
|
228
231
|
sessionSync: facts.sessionSync(deps).available,
|
|
229
232
|
sessionSyncFileHistory: facts.sessionSyncFileHistory(deps).available,
|
|
@@ -3,7 +3,7 @@ import { FLEET_SNAPSHOT_TERMINAL_MAX_ROWS, isTerminalWorkflowRowStatus, recentTe
|
|
|
3
3
|
import { taskNotificationFoldKey } from "../../orchestration/workflow-completion-inbox.js";
|
|
4
4
|
import { sendJson, sendError, sseHeaders } from "../send.js";
|
|
5
5
|
import { gatedSubject, sendPrincipalRefusal } from "../principal-gate.js";
|
|
6
|
-
import { routeListFilter } from "../owner-access.js";
|
|
6
|
+
import { routeListFilter, workflowScopeOf } from "../owner-access.js";
|
|
7
7
|
import { assertNever } from "../route-ctx.js";
|
|
8
8
|
import * as facts from "../../capability-facts.js";
|
|
9
9
|
export async function handleFleet(req, res, match, ctx) {
|
|
@@ -24,22 +24,24 @@ export async function handleFleet(req, res, match, ctx) {
|
|
|
24
24
|
const fleetParams = new URLSearchParams(match.search);
|
|
25
25
|
const callerSession = fleetParams.get("session");
|
|
26
26
|
const observeOnly = fleetParams.get("observe") === "1";
|
|
27
|
-
|
|
27
|
+
const workflowScope = workflowScopeOf(principal);
|
|
28
|
+
const viewer = fleetWide ? null : { rows: principal ?? "default", workflows: workflowScope };
|
|
29
|
+
await streamFleet(req, res, fleet.fleetBus, viewer, callerSession || null, observeOnly ? undefined : deps.workflowCompletionInbox, { store: deps.workflowRunStore, scope: viewer?.workflows ?? null, pullScope: workflowScope, ready: deps.fleetRecoveryDone });
|
|
28
30
|
return;
|
|
29
31
|
}
|
|
30
32
|
default:
|
|
31
33
|
return assertNever(match.decl.id);
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
|
-
function streamFleet(req, res, bus,
|
|
36
|
+
function streamFleet(req, res, bus, viewer, callerSession = null, completionInbox, terminal) {
|
|
35
37
|
return new Promise((resolve) => {
|
|
36
38
|
sseHeaders(res);
|
|
37
|
-
res.write(`event: meta\ndata: ${JSON.stringify({ type: "meta", version: 1, scoped:
|
|
39
|
+
res.write(`event: meta\ndata: ${JSON.stringify({ type: "meta", version: 1, scoped: viewer !== null, sessionScoped: callerSession !== null, ...(callerSession !== null ? { session: callerSession } : {}), bgNotifyFailClosed: true })}\n\n`);
|
|
38
40
|
const seenTasks = new Set();
|
|
39
41
|
const seenWf = new Set();
|
|
40
42
|
const sessionOk = (rowSession) => callerSession === null || rowSession === undefined || rowSession === callerSession;
|
|
41
|
-
const visT = (r) => (
|
|
42
|
-
const visW = (r) => (
|
|
43
|
+
const visT = (r) => (viewer === null || r.scope === viewer.rows) && sessionOk(r.sessionId);
|
|
44
|
+
const visW = (r) => (viewer === null || r.scope === viewer.workflows) && sessionOk(r.sessionId);
|
|
43
45
|
const SCOPED_TASK_KEY_DISPOSITION = {
|
|
44
46
|
id: "keep", parentId: "keep", parentToolCallId: "keep", workflowRunId: "keep", status: "keep",
|
|
45
47
|
startedAt: "keep", elapsedMs: "keep", tokens: "keep",
|
|
@@ -144,7 +146,7 @@ function streamFleet(req, res, bus, callerScope, callerSession = null, completio
|
|
|
144
146
|
break;
|
|
145
147
|
case "hook_notice": {
|
|
146
148
|
const hn = frame.notice;
|
|
147
|
-
const hScopeOk =
|
|
149
|
+
const hScopeOk = viewer === null || hn.ownerScope === viewer.rows;
|
|
148
150
|
const hSessionOk = callerSession === null || hn.ownerSessionId === callerSession;
|
|
149
151
|
if (hScopeOk && hSessionOk) {
|
|
150
152
|
send("hook_notice", { type: "hook_notice", ...hookNoticeWire(hn), ts: frame.ts });
|
|
@@ -153,7 +155,7 @@ function streamFleet(req, res, bus, callerScope, callerSession = null, completio
|
|
|
153
155
|
}
|
|
154
156
|
case "bg_notification": {
|
|
155
157
|
const n = frame.notification;
|
|
156
|
-
const scopeOk =
|
|
158
|
+
const scopeOk = viewer === null || n.ownerScope === viewer.rows;
|
|
157
159
|
const sessionInjectOk = callerSession === null || n.ownerSessionId === callerSession;
|
|
158
160
|
if (scopeOk && sessionInjectOk) {
|
|
159
161
|
const { ownerScope: _os, ownerSessionId: _osid, ...wire } = n;
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* · **登记簿只由配置中心下发**:settings-schema 的本地读取集不收 `projects` 域 ⇒ 没有中心腿在应用配置的部署上没有登记簿 —— 两口 501
|
|
10
10
|
* `capability.unavailable`,能力位 `capabilities.projects`(布尔)读同一只事实(`capability-facts.ts` 的 `projectRegistry`)答 `false`;
|
|
11
11
|
* 有登记簿时答 `true`。本面不开写动词(写到哪里由另一张设计定;写面到货时另立一位,本位不改义)。
|
|
12
|
-
* · **可见性 fail-closed**:身份判在登记簿在场判**之前**(否则「这台有没有登记簿」先于 401 泄出去)
|
|
13
|
-
*
|
|
12
|
+
* · **可见性 fail-closed**:身份判在登记簿在场判**之前**(否则「这台有没有登记簿」先于 401 泄出去);判与按 id 取只有一只(`project-registry.ts`:
|
|
13
|
+
* fleet 调用方(列表面 `list.read` 读档(`listFilterOf`))看全部,带验过主体的调用方只看 `registeredBy` 恰是自己的登记 —— 项目上下文继承与登记簿默认读层种子同读它);
|
|
14
|
+
* 看不见的与不存在的同码同句(404 `not_found.project`,不给存在性预言机)。
|
|
14
15
|
*
|
|
15
16
|
* 归档:`archivedAt` 在场 = 已归档。列表缺省不列,`?archived=true` 只列已归档的,`?archived=false` 与缺省同;单项读不论归档与否都答(会话行引用它)。
|
|
16
17
|
*/
|
|
@@ -4,7 +4,7 @@ import { sendUnauthorized } from "../principal-gate.js";
|
|
|
4
4
|
import { routeListFilter } from "../owner-access.js";
|
|
5
5
|
import { assertNever } from "../route-ctx.js";
|
|
6
6
|
import * as facts from "../../capability-facts.js";
|
|
7
|
-
import {
|
|
7
|
+
import { projectVisibleTo, visibleProjectOf } from "../../project-registry.js";
|
|
8
8
|
import { projectByTable } from "../../trace/projection-table.js";
|
|
9
9
|
export const PROJECT_NOT_FOUND_MESSAGE = "no such project";
|
|
10
10
|
export const PROJECT_ROW_DISPOSITIONS = {
|
|
@@ -49,7 +49,6 @@ export async function handleProjects(req, res, match, ctx) {
|
|
|
49
49
|
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");
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
|
-
const visible = (registration) => projectVisible(registration, viewer);
|
|
53
52
|
switch (match.decl.id) {
|
|
54
53
|
case "projects-list": {
|
|
55
54
|
const archived = readArchivedQuery(new URLSearchParams(match.search).get("archived"));
|
|
@@ -58,7 +57,7 @@ export async function handleProjects(req, res, match, ctx) {
|
|
|
58
57
|
return;
|
|
59
58
|
}
|
|
60
59
|
const projects = Object.entries(registry.registry)
|
|
61
|
-
.filter(([, registration]) =>
|
|
60
|
+
.filter(([, registration]) => projectVisibleTo(viewer, registration) && (registration.archivedAt !== undefined) === archived)
|
|
62
61
|
.map(([id, registration]) => projectRowOf(id, registration));
|
|
63
62
|
sendJson(res, 200, { projects });
|
|
64
63
|
return;
|
|
@@ -70,8 +69,8 @@ export async function handleProjects(req, res, match, ctx) {
|
|
|
70
69
|
return;
|
|
71
70
|
}
|
|
72
71
|
const id = raw.toLowerCase();
|
|
73
|
-
const registration =
|
|
74
|
-
if (registration === undefined
|
|
72
|
+
const registration = visibleProjectOf(registry.registry, id, viewer);
|
|
73
|
+
if (registration === undefined) {
|
|
75
74
|
sendError(res, 404, "not_found.project", PROJECT_NOT_FOUND_MESSAGE);
|
|
76
75
|
return;
|
|
77
76
|
}
|
package/dist/http/routes/runs.js
CHANGED
|
@@ -16,8 +16,8 @@ import { idemCallerOf, idemKeyOf, inflightKeyOf, submissionIdemOf } from "../ide
|
|
|
16
16
|
import { streamSseLog } from "../sse-log.js";
|
|
17
17
|
import { bindSseLifecycle } from "../sse-lifecycle.js";
|
|
18
18
|
import { buildApprovalPreamble, buildApprovalPreambleSseFrames, readClosedWordSeat, storedCardDemandsAPerson } from "../../approval-card.js";
|
|
19
|
-
import { heldAskOf,
|
|
20
|
-
import { ASK_DECISION_CONSUMER_ABSENT, approvalPreambleReplays, outcomeOfDecidedRow, parkSessionOf, presentedApprovalFrameFamily, resolveStreamApprovalGate } from "../../tool-approval.js";
|
|
19
|
+
import { heldAskOf, readDecider, retiredDecisionKeyFacts, DECIDED_BY_NOT_IN_PROOF, POLICY_CANNOT_ALLOW_PERSON_ASK } from "../../host-decision.js";
|
|
20
|
+
import { ASK_DECISION_CONSUMER_ABSENT, approvalPreambleReplays, decidedRowFacts, outcomeOfDecidedRow, parkSessionOf, presentedApprovalFrameFamily, resolveStreamApprovalGate } from "../../tool-approval.js";
|
|
21
21
|
import { MAX_DECISION_NOTE_CHARS, noteLandedOnRow, noteRecordedReceipt } from "../../approval-ask-machine.js";
|
|
22
22
|
import { askRowEndingCause } from "../../approval-deny-reasons.js";
|
|
23
23
|
import { normalizeRunEventType, screenedStoredEventData } from "../../trace/project.js";
|
|
@@ -35,6 +35,7 @@ import { mintAndDriveDurableRun } from "../durable-run-leg.js";
|
|
|
35
35
|
import { SUBMISSION_CLAIM_FACE } from "../execution-context.js";
|
|
36
36
|
import { admitRunById, admitRunByIdem, enter, readVisibleRun, sessionFactsReadOf } from "../owner-access.js";
|
|
37
37
|
import { keyAdmission, ownerCellOf, recoveredSubject } from "../../owner-faces.js";
|
|
38
|
+
import { engineScopeOfOwner } from "../../engine-identity.js";
|
|
38
39
|
import { personOf } from "../../owner-brands.js";
|
|
39
40
|
import { withSubject } from "../../observability/principal-context.js";
|
|
40
41
|
import { readResumeCtx, resumeCtxUnreadableAnswer } from "../resume-ctx-read.js";
|
|
@@ -49,6 +50,11 @@ const STEER_PRIORITY_CHOICES = STEER_PRIORITY_WORDS.length <= 2 ? STEER_PRIORITY
|
|
|
49
50
|
const ASK_PARKING_RETRY_AFTER_SEC = 2;
|
|
50
51
|
const ASK_ACTOR_LABEL_MAX = 256;
|
|
51
52
|
const AskDecisionActorSchema = ActorAssertionWire.strip();
|
|
53
|
+
function mirrorRetryAfter(res, body) {
|
|
54
|
+
const retryAfterSec = body !== null && typeof body === "object" ? body.retryAfterSec : undefined;
|
|
55
|
+
if (typeof retryAfterSec === "number" && Number.isFinite(retryAfterSec) && retryAfterSec >= 0)
|
|
56
|
+
res.setHeader("retry-after", String(Math.ceil(retryAfterSec)));
|
|
57
|
+
}
|
|
52
58
|
const AskDecisionBodySchema = z
|
|
53
59
|
.object({
|
|
54
60
|
decision: z.enum(["approve", "deny"]),
|
|
@@ -885,7 +891,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
885
891
|
if (!gated)
|
|
886
892
|
return;
|
|
887
893
|
const { run } = gated;
|
|
888
|
-
const out = await subagentTaskOutput(target, { owner: runId, scope: run.owner
|
|
894
|
+
const out = await subagentTaskOutput(target, { owner: runId, scope: engineScopeOfOwner(run.owner), ...(run.sessionId ? { sessionId: run.sessionId } : {}) });
|
|
889
895
|
const details = out.details;
|
|
890
896
|
if (details?.error === "not_found" || details?.type !== "background_agent") {
|
|
891
897
|
if (!sendHandleMiss(res, run, deps.instanceId))
|
|
@@ -914,7 +920,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
914
920
|
return;
|
|
915
921
|
const { run } = gatedTail;
|
|
916
922
|
const it = defaultSubagentTailBus.subscribe(target);
|
|
917
|
-
const probe = await subagentTaskOutput(target, { owner: runId, scope: run.owner
|
|
923
|
+
const probe = await subagentTaskOutput(target, { owner: runId, scope: engineScopeOfOwner(run.owner), ...(run.sessionId ? { sessionId: run.sessionId } : {}) });
|
|
918
924
|
const probeDetails = probe.details;
|
|
919
925
|
if (probeDetails?.error === "not_found" || probeDetails?.type !== "background_agent") {
|
|
920
926
|
void it.return?.();
|
|
@@ -982,7 +988,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
982
988
|
return;
|
|
983
989
|
const { run } = gatedB;
|
|
984
990
|
const q = new URLSearchParams(match.search);
|
|
985
|
-
const access = { owner: runId, scope: run.owner
|
|
991
|
+
const access = { owner: runId, scope: engineScopeOfOwner(run.owner), ...(run.sessionId ? { sessionId: run.sessionId } : {}) };
|
|
986
992
|
if (q.get("filter") !== null) {
|
|
987
993
|
sendError(res, 400, "request.param_unsupported", "filter is not accepted on the wire — fetch the output and filter client-side (note: the wire serves the clipped projection)");
|
|
988
994
|
return;
|
|
@@ -1189,10 +1195,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1189
1195
|
}
|
|
1190
1196
|
const body = await readJson(req);
|
|
1191
1197
|
const { status, body: respBody } = await approvalFact.coordinator.respond(id, principal, body, req, { readRootGrantAccepted: facts.readRootGrant(deps).available });
|
|
1192
|
-
|
|
1193
|
-
if (typeof retryAfterSec === "number" && Number.isFinite(retryAfterSec) && retryAfterSec >= 0) {
|
|
1194
|
-
res.setHeader("retry-after", String(Math.ceil(retryAfterSec)));
|
|
1195
|
-
}
|
|
1198
|
+
mirrorRetryAfter(res, respBody);
|
|
1196
1199
|
sendJson(res, status, respBody);
|
|
1197
1200
|
return;
|
|
1198
1201
|
}
|
|
@@ -1205,6 +1208,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1205
1208
|
return;
|
|
1206
1209
|
}
|
|
1207
1210
|
const askStore = streamFact.askStore;
|
|
1211
|
+
const coordinator = streamFact.coordinator;
|
|
1208
1212
|
const principal = gatedSubject(req, deps.config);
|
|
1209
1213
|
if (deps.config.requirePrincipal && principal === undefined) {
|
|
1210
1214
|
sendPrincipalRefusal(res, req, deps.config);
|
|
@@ -1247,7 +1251,8 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1247
1251
|
askNotFound();
|
|
1248
1252
|
return;
|
|
1249
1253
|
}
|
|
1250
|
-
const
|
|
1254
|
+
const callerIsOperator = explicitOperatorOk(principal === undefined ? undefined : personOf(principal), deps.config);
|
|
1255
|
+
const askAdmission = keyAdmission("ask.decide", { subject: principal, operator: callerIsOperator }, ownerCellOf(row0.owner));
|
|
1251
1256
|
if (askAdmission === undefined) {
|
|
1252
1257
|
askNotFound();
|
|
1253
1258
|
return;
|
|
@@ -1259,7 +1264,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1259
1264
|
via: askAdmission === "row" ? "owner" : "operator",
|
|
1260
1265
|
};
|
|
1261
1266
|
const decidedRowIsAuthoritative = (row) => {
|
|
1262
|
-
if (row
|
|
1267
|
+
if (decidedRowFacts(row) === undefined) {
|
|
1263
1268
|
deps.logger?.error?.("ask_decision_row_not_authoritative", {
|
|
1264
1269
|
taskId,
|
|
1265
1270
|
askId,
|
|
@@ -1290,8 +1295,8 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1290
1295
|
const replayDecided = (row) => {
|
|
1291
1296
|
const storedActor = projectDecisionActor(row.decisionActor);
|
|
1292
1297
|
sendJson(res, 200, {
|
|
1293
|
-
askId
|
|
1294
|
-
taskId
|
|
1298
|
+
askId,
|
|
1299
|
+
taskId,
|
|
1295
1300
|
decision: row.decision,
|
|
1296
1301
|
decidedAtMs: row.decidedAtMs,
|
|
1297
1302
|
...(storedActor ? { actor: storedActor } : {}),
|
|
@@ -1299,7 +1304,78 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1299
1304
|
...noteReceipt(row),
|
|
1300
1305
|
});
|
|
1301
1306
|
};
|
|
1302
|
-
const
|
|
1307
|
+
const policyMayNotApprove = (row) => body.decision === "approve" && policyCannotAnswer(heldAskOf(storedCardDemandsAPerson(row.cardJson)), decider.decidedBy);
|
|
1308
|
+
const refusePolicyApprove = () => sendError(res, 400, "request.field_conflict", POLICY_CANNOT_ALLOW_PERSON_ASK, fieldConflictFacts("policy_person_ask", ["decidedBy", "decision"]));
|
|
1309
|
+
const conflictWithFirst = (row) => {
|
|
1310
|
+
const first = projectDecisionActor(row.decisionActor);
|
|
1311
|
+
sendError(res, 409, "conflict.ask_decided", "this ask was already decided — the first decision stands and is echoed here", {
|
|
1312
|
+
decision: row.decision,
|
|
1313
|
+
decidedAtMs: row.decidedAtMs,
|
|
1314
|
+
...(first ? { actor: first } : {}),
|
|
1315
|
+
...decisionNoteEcho(row),
|
|
1316
|
+
});
|
|
1317
|
+
};
|
|
1318
|
+
const answerParked = async (row) => {
|
|
1319
|
+
const answer = await coordinator.decideParkedAsk(askStore, row, {
|
|
1320
|
+
write: { decision: body.decision, decider, ...(body.note !== undefined ? { note: body.note } : {}), actor, ...(body.idempotencyKey !== undefined ? { idempotencyKey: body.idempotencyKey } : {}) },
|
|
1321
|
+
...(body.decision === "approve" && hasUpdatedInput ? { updatedInput: body.updatedInput } : {}),
|
|
1322
|
+
...(principal !== undefined ? { principal } : {}),
|
|
1323
|
+
operator: callerIsOperator,
|
|
1324
|
+
policyMayNotApprove: policyMayNotApprove(row),
|
|
1325
|
+
httpReq: req,
|
|
1326
|
+
}, body.idempotencyKey);
|
|
1327
|
+
switch (answer.kind) {
|
|
1328
|
+
case "standing": {
|
|
1329
|
+
const first = { decision: answer.decision, decidedAtMs: answer.decidedAtMs, decisionActor: answer.actor ?? null, decisionNote: answer.decisionNote ?? null };
|
|
1330
|
+
if (answer.byThisRequest)
|
|
1331
|
+
replayDecided(first);
|
|
1332
|
+
else
|
|
1333
|
+
conflictWithFirst(first);
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
case "refused":
|
|
1337
|
+
if (answer.status === 404) {
|
|
1338
|
+
askNotFound();
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
mirrorRetryAfter(res, answer.body);
|
|
1342
|
+
sendJson(res, answer.status, answer.body);
|
|
1343
|
+
return;
|
|
1344
|
+
case "gone":
|
|
1345
|
+
askNotFound();
|
|
1346
|
+
return;
|
|
1347
|
+
case "policy_refused":
|
|
1348
|
+
refusePolicyApprove();
|
|
1349
|
+
return;
|
|
1350
|
+
case "gate_only":
|
|
1351
|
+
sendError(res, 410, "gone.ask_parked", "the in-stream window closed and this ask was parked onto the durable approval gate — decide it through that gate for the session echoed here", {
|
|
1352
|
+
sessionId: parkSessionOf(row),
|
|
1353
|
+
gateBoundCallId: row.gateBoundCallId,
|
|
1354
|
+
gateBoundInputHash: row.gateBoundInputHash,
|
|
1355
|
+
});
|
|
1356
|
+
return;
|
|
1357
|
+
case "accepted": {
|
|
1358
|
+
const recorded = answer.recorded ?? { decisionNote: null };
|
|
1359
|
+
sendJson(res, 200, {
|
|
1360
|
+
...answer.body,
|
|
1361
|
+
askId,
|
|
1362
|
+
taskId,
|
|
1363
|
+
decision: body.decision,
|
|
1364
|
+
decidedAtMs: answer.recorded?.decidedAtMs ?? Date.now(),
|
|
1365
|
+
actor,
|
|
1366
|
+
accepted: "parked_redeemed",
|
|
1367
|
+
...decisionNoteEcho(recorded),
|
|
1368
|
+
...noteReceipt(recorded),
|
|
1369
|
+
});
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
default: {
|
|
1373
|
+
const unhandled = answer;
|
|
1374
|
+
throw new Error(`unhandled parked ask answer: ${JSON.stringify(unhandled)}`);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
const sendTerminal = async (row) => {
|
|
1303
1379
|
switch (row.state) {
|
|
1304
1380
|
case "DECIDED": {
|
|
1305
1381
|
if (!syncLiveFromDecidedRow(row))
|
|
@@ -1308,21 +1384,11 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1308
1384
|
replayDecided(row);
|
|
1309
1385
|
return;
|
|
1310
1386
|
}
|
|
1311
|
-
|
|
1312
|
-
sendError(res, 409, "conflict.ask_decided", "this ask was already decided — the first decision stands and is echoed here", {
|
|
1313
|
-
decision: row.decision,
|
|
1314
|
-
decidedAtMs: row.decidedAtMs,
|
|
1315
|
-
...(first ? { actor: first } : {}),
|
|
1316
|
-
...decisionNoteEcho(row),
|
|
1317
|
-
});
|
|
1387
|
+
conflictWithFirst(row);
|
|
1318
1388
|
return;
|
|
1319
1389
|
}
|
|
1320
1390
|
case "PARKED":
|
|
1321
|
-
|
|
1322
|
-
sessionId: parkSessionOf(row),
|
|
1323
|
-
gateBoundCallId: row.gateBoundCallId,
|
|
1324
|
-
gateBoundInputHash: row.gateBoundInputHash,
|
|
1325
|
-
});
|
|
1391
|
+
await answerParked(row);
|
|
1326
1392
|
return;
|
|
1327
1393
|
case "DENIED":
|
|
1328
1394
|
case "VOID": {
|
|
@@ -1367,23 +1433,23 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1367
1433
|
}
|
|
1368
1434
|
}
|
|
1369
1435
|
if (row0.state !== "STREAM_PENDING") {
|
|
1370
|
-
sendTerminal(row0);
|
|
1436
|
+
await sendTerminal(row0);
|
|
1371
1437
|
return;
|
|
1372
1438
|
}
|
|
1373
|
-
if (
|
|
1374
|
-
|
|
1439
|
+
if (policyMayNotApprove(row0)) {
|
|
1440
|
+
refusePolicyApprove();
|
|
1375
1441
|
return;
|
|
1376
1442
|
}
|
|
1377
1443
|
let outcome;
|
|
1378
1444
|
const releaseEditMark = body.decision === "approve" && hasUpdatedInput ? deps.toolApproval?.markEditedDecisionInFlight(askId) : undefined;
|
|
1379
1445
|
try {
|
|
1380
|
-
outcome = await
|
|
1446
|
+
outcome = await coordinator.writeAskDecision(askStore, askId, { kind: "live", batchId: row0.batchId }, row0.owner, {
|
|
1381
1447
|
decision: body.decision,
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
...
|
|
1386
|
-
...(
|
|
1448
|
+
decider,
|
|
1449
|
+
actor,
|
|
1450
|
+
...(body.note !== undefined ? { note: body.note } : {}),
|
|
1451
|
+
...(body.idempotencyKey !== undefined ? { idempotencyKey: body.idempotencyKey } : {}),
|
|
1452
|
+
...(hasUpdatedInput ? { updatedInput: body.updatedInput } : {}),
|
|
1387
1453
|
});
|
|
1388
1454
|
}
|
|
1389
1455
|
catch (err) {
|
|
@@ -1443,7 +1509,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1443
1509
|
askNotFound();
|
|
1444
1510
|
return;
|
|
1445
1511
|
}
|
|
1446
|
-
sendTerminal(outcome.row);
|
|
1512
|
+
await sendTerminal(outcome.row);
|
|
1447
1513
|
return;
|
|
1448
1514
|
}
|
|
1449
1515
|
if (!decidedRowIsAuthoritative(outcome.row))
|
|
@@ -13,6 +13,7 @@ import { type ImportAnchor, type StagingHandle } from "../../session-sync-kernel
|
|
|
13
13
|
import type { DurableOwnerKey } from "../../owner-brands.js";
|
|
14
14
|
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
15
15
|
import { type SessionRowPatch } from "../../session-row.js";
|
|
16
|
+
import { type SessionFace } from "../../session-incarnation.js";
|
|
16
17
|
export type PendingStaging = {
|
|
17
18
|
handle: StagingHandle;
|
|
18
19
|
realSessionId: string;
|
|
@@ -33,9 +34,9 @@ export type PendingStaging = {
|
|
|
33
34
|
/** The principal that opened this staging, kept as the handle's owner key (`null` = a fleet caller opened it) — a different caller may not drive it
|
|
34
35
|
* (404, no oracle; compared through `owner-faces.ts` `sameKey` only). */
|
|
35
36
|
openedBy: DurableOwnerKey | null;
|
|
36
|
-
/** The
|
|
37
|
-
* this same
|
|
38
|
-
|
|
37
|
+
/** The live occupant the gate judged when it opened this staging (owner ∧ incarnation, the head read: `undefined` = no live session) — the commit lands only on
|
|
38
|
+
* this same occupant (`StagedCommitOptions.expectedOccupant`, `session-sync-kernel.ts`); `owner` above (the re-stamped importing principal) is derived from its owner for a fleet caller. */
|
|
39
|
+
expectedOccupant: SessionFace | undefined;
|
|
39
40
|
/** 开这张暂存时占下的导入租约的键({@link importLeaseKey});续期与放掉都按它,不再从会话 id 重算。 */
|
|
40
41
|
leaseKey: string;
|
|
41
42
|
};
|