@sema-agent/server 7.132.0 → 7.133.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 +266 -0
- package/README.md +8 -9
- package/README.zh-CN.md +7 -6
- package/USAGE.md +174 -55
- package/deploy/sema-up/README.md +19 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
- package/deploy/sema-up/chart/templates/server.yaml +5 -2
- package/deploy/sema-up/stack/compose.yaml +3 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
- package/dist/adoption/plan.d.ts +3 -2
- package/dist/adoption/plan.js +7 -5
- package/dist/adoption/runner.js +3 -10
- package/dist/adoption/sql.d.ts +3 -2
- package/dist/adoption/sql.js +3 -5
- package/dist/adoption/wire.d.ts +4 -1
- package/dist/adoption/wire.js +1 -0
- package/dist/approval-ask-audit-store.d.ts +31 -13
- package/dist/approval-ask-audit-store.js +272 -74
- package/dist/approval-ask-machine.d.ts +15 -0
- package/dist/approval-ask-machine.js +6 -0
- package/dist/approval-ask-retention.d.ts +136 -0
- package/dist/approval-ask-retention.js +102 -0
- package/dist/approval-card.d.ts +79 -19
- package/dist/approval-card.js +44 -13
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval.d.ts +9 -0
- package/dist/approval.js +24 -3
- package/dist/audit.d.ts +27 -10
- package/dist/audit.js +12 -16
- package/dist/bake-runner/main.js +3 -2
- package/dist/boot/deferred-sandbox-path-env.js +1 -1
- package/dist/boot/execution-env.js +9 -7
- package/dist/boot/execution-lane.js +11 -0
- package/dist/boot/leader.js +2 -0
- package/dist/boot/memory-boundary.js +2 -2
- package/dist/boot/memory-consolidation.d.ts +5 -4
- package/dist/boot/memory-consolidation.js +7 -6
- package/dist/boot/org-delivery.d.ts +28 -0
- package/dist/boot/org-delivery.js +20 -0
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +21 -1
- package/dist/boot/resolve-spec.d.ts +3 -0
- package/dist/boot/resolve-spec.js +60 -81
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +4 -2
- package/dist/boot/stage-02-web-admin-pull.js +4 -1
- package/dist/boot/stage-06-runners.d.ts +2 -0
- package/dist/boot/stage-06-runners.js +6 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -0
- package/dist/boot/stage-07-capability-layer.js +24 -3
- package/dist/boot/stage-08-reapers.d.ts +2 -0
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +3 -0
- package/dist/boot/stage-10-http-server.d.ts +3 -0
- package/dist/boot/stage-10-http-server.js +5 -6
- package/dist/boot/stores.js +2 -2
- package/dist/boot/web-admin.d.ts +4 -0
- package/dist/boot/web-admin.js +151 -63
- package/dist/boot/workflow-orchestration.d.ts +2 -0
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/brain.js +8 -3
- package/dist/breaker-key.d.ts +6 -0
- package/dist/breaker-key.js +29 -0
- package/dist/caller-text-echo.d.ts +9 -6
- package/dist/caller-text-echo.js +8 -11
- package/dist/capabilities/center-plugins.d.ts +7 -0
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +21 -0
- package/dist/capabilities/hands-lane.js +10 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -4
- package/dist/capabilities/mcp-probe.js +27 -4
- package/dist/capabilities/scenarios.d.ts +63 -7
- package/dist/capabilities/scenarios.js +39 -7
- package/dist/capability-facts.d.ts +34 -4
- package/dist/capability-facts.js +28 -2
- package/dist/center-config-tier.d.ts +69 -0
- package/dist/center-config-tier.js +42 -0
- package/dist/checkpoint-identity.d.ts +16 -0
- package/dist/checkpoint-identity.js +19 -0
- package/dist/config-catalog.d.ts +17 -10
- package/dist/config-catalog.js +43 -28
- package/dist/config-d-migration.d.ts +3 -1
- package/dist/config-d-migration.js +2 -2
- package/dist/config-dir-trust.d.ts +114 -0
- package/dist/config-dir-trust.js +388 -0
- package/dist/config-invariants.d.ts +18 -5
- package/dist/config-invariants.js +35 -3
- package/dist/config-provider.d.ts +6 -1
- package/dist/config-provider.js +6 -2
- package/dist/config-types.d.ts +71 -14
- package/dist/config-types.js +8 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +121 -59
- package/dist/delegated-session-owner.d.ts +185 -0
- package/dist/delegated-session-owner.js +119 -0
- package/dist/device-protocol.d.ts +5 -3
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.js +21 -2
- package/dist/device-ws-protocol.d.ts +70 -6
- package/dist/device-ws-protocol.js +50 -23
- package/dist/elicitation.js +3 -2
- package/dist/entry-problems.d.ts +34 -0
- package/dist/entry-problems.js +14 -0
- package/dist/execution-lane-caps.d.ts +49 -10
- package/dist/execution-lane-caps.js +43 -4
- package/dist/field-conflict.d.ts +43 -0
- package/dist/field-conflict.js +20 -0
- package/dist/fleet/fleet-bus.d.ts +80 -6
- package/dist/fleet/fleet-bus.js +41 -9
- package/dist/hooks/classic-stations.d.ts +10 -5
- package/dist/hooks/classic-stations.js +4 -4
- package/dist/hooks/command-spawn.d.ts +57 -0
- package/dist/hooks/command-spawn.js +139 -0
- package/dist/hooks/hook-llm.js +2 -2
- package/dist/hooks/hook-runner.d.ts +127 -25
- package/dist/hooks/hook-runner.js +668 -287
- package/dist/hooks/hook-source.d.ts +44 -0
- package/dist/hooks/hook-source.js +40 -0
- package/dist/http/active-run-conflict.d.ts +5 -13
- package/dist/http/active-run-conflict.js +17 -27
- package/dist/http/admission.js +103 -60
- package/dist/http/approval-sweeps.js +55 -18
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +16 -16
- package/dist/http/checkpoint-ctx.js +13 -10
- package/dist/http/claimed-run.d.ts +4 -3
- package/dist/http/device-placement.d.ts +2 -4
- package/dist/http/device-placement.js +2 -1
- package/dist/http/dispatch.js +10 -4
- package/dist/http/durable-run-leg.d.ts +4 -32
- package/dist/http/durable-run-leg.js +34 -10
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +48 -23
- package/dist/http/principal-gate.js +39 -12
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/request-guards.d.ts +16 -23
- package/dist/http/request-guards.js +30 -15
- package/dist/http/resume-ctx-read.d.ts +2 -5
- package/dist/http/resume-ctx-read.js +7 -4
- package/dist/http/resume-legs.d.ts +3 -4
- package/dist/http/resume-legs.js +126 -69
- package/dist/http/retired-service-deps.d.ts +43 -0
- package/dist/http/retired-service-deps.js +18 -0
- package/dist/http/route-ctx.d.ts +44 -28
- package/dist/http/route-ctx.js +4 -0
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/a2a-serve.js +3 -4
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.js +1 -1
- package/dist/http/routes/admin-memory-optout.js +5 -1
- package/dist/http/routes/adoption.js +2 -9
- package/dist/http/routes/approvals-assistant.js +49 -48
- package/dist/http/routes/background.js +3 -2
- package/dist/http/routes/capabilities.js +20 -4
- package/dist/http/routes/config-catalog.d.ts +3 -3
- package/dist/http/routes/config-catalog.js +1 -1
- package/dist/http/routes/devices.js +3 -17
- package/dist/http/routes/diagnostics.js +5 -1
- package/dist/http/routes/images.js +6 -7
- package/dist/http/routes/leader.js +1 -8
- package/dist/http/routes/mcp-reconnect.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +3 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-consolidation.js +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/memory-policy.d.ts +1 -1
- package/dist/http/routes/memory-policy.js +3 -2
- package/dist/http/routes/notify-wake.js +8 -21
- package/dist/http/routes/observability.js +2 -2
- package/dist/http/routes/principal-inbox.d.ts +39 -0
- package/dist/http/routes/principal-inbox.js +76 -0
- package/dist/http/routes/retention-ops.js +2 -9
- package/dist/http/routes/rules.js +5 -18
- package/dist/http/routes/runs.d.ts +5 -0
- package/dist/http/routes/runs.js +33 -106
- package/dist/http/routes/session-sync.js +15 -28
- package/dist/http/routes/sessions.js +30 -40
- package/dist/http/routes/side-query.js +6 -4
- package/dist/http/routes/tasks.js +50 -14
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/send.d.ts +24 -3
- package/dist/http/send.js +14 -2
- package/dist/http/server.d.ts +17 -18
- package/dist/http/server.js +15 -13
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.js +4 -3
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +10 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -1
- package/dist/lane-home-probe.d.ts +78 -9
- package/dist/lane-home-probe.js +78 -12
- package/dist/leader/endpoint.d.ts +4 -1
- package/dist/leader/endpoint.js +11 -10
- package/dist/limit-refusal.d.ts +17 -5
- package/dist/limit-refusal.js +4 -1
- package/dist/mcp-assertion-header.d.ts +31 -10
- package/dist/mcp-assertion-header.js +10 -3
- package/dist/mcp-tool-faces.js +1 -3
- package/dist/memory-project-layer.d.ts +37 -0
- package/dist/memory-project-layer.js +46 -0
- package/dist/memory-scope.d.ts +23 -16
- package/dist/memory-scope.js +24 -8
- package/dist/memory-sync-client.d.ts +27 -13
- package/dist/memory-sync-client.js +107 -18
- package/dist/model-entry-refusal.d.ts +9 -1
- package/dist/model-entry-refusal.js +6 -1
- package/dist/model-plane-face.d.ts +51 -0
- package/dist/model-plane-face.js +24 -0
- package/dist/model-provider.d.ts +5 -0
- package/dist/model-provider.js +4 -2
- package/dist/model-route-endpoint.d.ts +8 -11
- package/dist/model-route-endpoint.js +4 -7
- package/dist/model-route-env.d.ts +22 -0
- package/dist/model-route-env.js +2 -0
- package/dist/model-route-gap.d.ts +60 -30
- package/dist/model-route-gap.js +21 -15
- package/dist/observability/corrupt-read-seat.d.ts +7 -0
- package/dist/observability/corrupt-read-seat.js +9 -0
- package/dist/observability/err-text.d.ts +6 -0
- package/dist/observability/err-text.js +18 -4
- package/dist/observability/fail-open.d.ts +35 -9
- package/dist/observability/fail-open.js +35 -9
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/prompt-manifest.d.ts +3 -17
- package/dist/observability/prompt-manifest.js +45 -42
- package/dist/observability/tool-trace.js +9 -9
- package/dist/operator-ask.d.ts +10 -0
- package/dist/operator-ask.js +3 -0
- package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
- package/dist/orchestration/workflow-agent-session-index.js +9 -13
- package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
- package/dist/orchestration/workflow-completion-inbox.js +13 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
- package/dist/orchestration/workflow-notify-journal.js +27 -34
- package/dist/orchestration/workflow-park-decision.d.ts +89 -0
- package/dist/orchestration/workflow-park-decision.js +118 -0
- package/dist/org-delivery-gate.d.ts +81 -0
- package/dist/org-delivery-gate.js +59 -0
- package/dist/panel-tool-names.d.ts +23 -0
- package/dist/panel-tool-names.js +8 -0
- package/dist/parked-decide.d.ts +39 -6
- package/dist/parked-decide.js +98 -51
- package/dist/parked-revive-surface.d.ts +9 -2
- package/dist/parked-revive-surface.js +11 -8
- package/dist/permission-rule-list.d.ts +1 -1
- package/dist/permission-rule-list.js +2 -2
- package/dist/plugins/approval-ask-store-file.d.ts +16 -1
- package/dist/plugins/approval-ask-store-file.js +21 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
- package/dist/plugins/approval-ask-store-memory.js +34 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
- package/dist/plugins/approval-ask-store-sql.js +37 -1
- package/dist/plugins/blob-backend.d.ts +38 -25
- package/dist/plugins/blob-backend.js +29 -19
- package/dist/plugins/breaker-state-sql.d.ts +2 -2
- package/dist/plugins/breaker-state-sql.js +4 -4
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +14 -0
- package/dist/plugins/checkpoint-store-sql.js +20 -2
- package/dist/plugins/file-history-store-sql.d.ts +5 -2
- package/dist/plugins/file-history-store-sql.js +3 -1
- package/dist/plugins/file-run-store.d.ts +5 -13
- package/dist/plugins/file-run-store.js +9 -0
- package/dist/plugins/fork-routing-session-store.d.ts +9 -1
- package/dist/plugins/fork-routing-session-store.js +12 -1
- package/dist/plugins/host-platform.d.ts +2 -0
- package/dist/plugins/host-platform.js +2 -1
- package/dist/plugins/local-checkpoint-store.d.ts +2 -0
- package/dist/plugins/local-checkpoint-store.js +6 -1
- package/dist/plugins/local-session-store.d.ts +1 -1
- package/dist/plugins/local-session-window.d.ts +39 -0
- package/dist/plugins/local-session-window.js +54 -0
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
- package/dist/plugins/mailbox-store-sql.d.ts +30 -48
- package/dist/plugins/mailbox-store-sql.js +77 -52
- package/dist/plugins/memory-embedder-fingerprint.js +2 -1
- package/dist/plugins/memory-run-store.d.ts +5 -13
- package/dist/plugins/memory-run-store.js +8 -0
- package/dist/plugins/one-time-migrations.d.ts +110 -5
- package/dist/plugins/one-time-migrations.js +320 -8
- package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
- package/dist/plugins/org-delivery-quota-store.js +228 -0
- package/dist/plugins/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +17 -4
- package/dist/plugins/pg-session-storage.js +29 -6
- package/dist/plugins/remote-env-adb.d.ts +6 -12
- package/dist/plugins/remote-env-adb.js +12 -2
- package/dist/plugins/remote-env-k8s.d.ts +8 -12
- package/dist/plugins/remote-env-k8s.js +23 -5
- package/dist/plugins/remote-env-local-docker.d.ts +10 -15
- package/dist/plugins/remote-env-local-docker.js +12 -9
- package/dist/plugins/remote-env-ssh.d.ts +10 -16
- package/dist/plugins/remote-env-ssh.js +17 -11
- package/dist/plugins/run-store-sql.d.ts +16 -14
- package/dist/plugins/run-store-sql.js +22 -2
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-user-file.js +2 -2
- package/dist/plugins/session-epoch-anchor.d.ts +32 -6
- package/dist/plugins/session-epoch-anchor.js +2 -3
- package/dist/plugins/session-store.d.ts +18 -8
- package/dist/plugins/session-store.js +15 -4
- package/dist/plugins/sql-driver.d.ts +74 -11
- package/dist/plugins/sql-driver.js +210 -12
- package/dist/plugins/sql-errors.d.ts +23 -0
- package/dist/plugins/sql-errors.js +21 -0
- package/dist/plugins/store-backend.d.ts +36 -1
- package/dist/plugins/store-backend.js +40 -14
- package/dist/plugins/store-contracts.d.ts +42 -0
- package/dist/plugins/store-contracts.js +1 -0
- package/dist/plugins/tidb-pool.d.ts +6 -1
- package/dist/plugins/tidb-pool.js +44 -10
- package/dist/plugins/tidb-session-storage.d.ts +3 -2
- package/dist/plugins/tidb-session-storage.js +2 -2
- package/dist/plugins/tidb-session-store.d.ts +24 -4
- package/dist/plugins/tidb-session-store.js +28 -4
- package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
- package/dist/plugins/workflow-journal-store-sql.js +19 -6
- package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
- package/dist/plugins/workflow-run-store-sql.js +50 -9
- package/dist/posture-source.d.ts +18 -10
- package/dist/posture-source.js +4 -1
- package/dist/project-identity.d.ts +45 -6
- package/dist/project-identity.js +162 -8
- package/dist/project-layer-key.d.ts +28 -0
- package/dist/project-layer-key.js +29 -0
- package/dist/question.js +3 -2
- package/dist/read-deny-entry.d.ts +25 -0
- package/dist/read-deny-entry.js +12 -0
- package/dist/read-face-posture.d.ts +37 -11
- package/dist/read-face-posture.js +32 -3
- package/dist/request-key-closure.d.ts +7 -0
- package/dist/request-key-closure.js +9 -1
- package/dist/request-value-closure.d.ts +5 -0
- package/dist/request-value-closure.js +11 -3
- package/dist/rule-entry-list.d.ts +26 -2
- package/dist/rule-entry-list.js +72 -12
- package/dist/rules-consent.js +3 -4
- package/dist/run-acceptance.d.ts +19 -3
- package/dist/run-acceptance.js +13 -1
- package/dist/run-local.js +36 -6
- package/dist/runs.d.ts +10 -9
- package/dist/runs.js +21 -3
- package/dist/runtime-caps-resolver.d.ts +16 -6
- package/dist/runtime-caps-resolver.js +18 -5
- package/dist/sandbox-pkg-source.d.ts +19 -1
- package/dist/sandbox-pkg-source.js +29 -7
- package/dist/security.d.ts +87 -9
- package/dist/security.js +52 -9
- package/dist/session-error-wire.d.ts +19 -2
- package/dist/session-error-wire.js +5 -1
- package/dist/session-titled-frame.d.ts +33 -0
- package/dist/session-titled-frame.js +4 -0
- package/dist/session-titler.d.ts +9 -1
- package/dist/session-titler.js +15 -4
- package/dist/spec-fields.js +21 -2
- package/dist/sql-engine-posture.d.ts +3 -1
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +7 -66
- package/dist/task-settings.d.ts +89 -88
- package/dist/task-settings.js +71 -63
- package/dist/text-bidi.d.ts +0 -4
- package/dist/text-bidi.js +1 -3
- package/dist/tighten-only-seats.d.ts +150 -0
- package/dist/tighten-only-seats.js +196 -0
- package/dist/tool-approval.d.ts +303 -87
- package/dist/tool-approval.js +623 -239
- package/dist/trace/core-keyset-guard.d.ts +104 -22
- package/dist/trace/exit-seat.d.ts +28 -0
- package/dist/trace/exit-seat.js +76 -0
- package/dist/trace/ledger-events.d.ts +3 -2
- package/dist/trace/project.d.ts +80 -12
- package/dist/trace/project.js +41 -28
- package/dist/trace/projection-table.d.ts +100 -0
- package/dist/trace/projection-table.js +130 -0
- package/dist/trace/redact.d.ts +54 -0
- package/dist/trace/redact.js +778 -152
- package/dist/trace/self-minted-wire.d.ts +345 -1
- package/dist/trace/self-minted-wire.js +117 -1
- package/dist/trace/wire-projection-faces.d.ts +298 -2
- package/dist/trace/wire-projection-faces.js +154 -13
- package/dist/url-refusal.js +2 -0
- package/dist/web-admin-client/apply-effective.d.ts +12 -0
- package/dist/web-admin-client/apply-effective.js +56 -5
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/read-face.js +5 -9
- package/dist/web-admin-client/skills-mcp.js +4 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
- package/package.json +7 -3
package/dist/task-settings.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { combinePolicies,
|
|
2
|
-
import {
|
|
1
|
+
import { combinePolicies, parseRuleText, resolveReasoningProfile, rankOf, isThinkingLevel, RUN_WORKFLOW_TOOL_NAME, PERMISSION_MODES, isPermissionMode, ruleToolGrammarOf, } from "@sema-agent/core";
|
|
2
|
+
import { judgeUnmatchableToolNames } from "./config.js";
|
|
3
|
+
import { entryProblem } from "./entry-problems.js";
|
|
3
4
|
import { MAX_PERMISSION_RULES_PER_LIST, createRuleListPolicy } from "./permission-rule-list.js";
|
|
4
5
|
import { allowLayerEntryCountIssue, describeAllowLayerOverCap, ruleEntryListShapeOk } from "./rule-entry-list.js";
|
|
5
6
|
import { limitRefusal } from "./limit-refusal.js";
|
|
@@ -9,6 +10,8 @@ import { parseHooksConfig } from "./hooks/hook-runner.js";
|
|
|
9
10
|
import { heldRuleName } from "./tool-rule-names.js";
|
|
10
11
|
import { entryPermissionMode } from "./runtime-governance.js";
|
|
11
12
|
import { policyAskStandingAnswerFacts, standingAnswerDurablyRecordable } from "./tool-approval.js";
|
|
13
|
+
import { createRequestNeverAutoPolicy } from "./approval.js";
|
|
14
|
+
import { readTightenOnlySeats, tightenOnlySeatField, tightenOnlySpecSeats } from "./tighten-only-seats.js";
|
|
12
15
|
export const PERMISSION_MODE_WORDS = PERMISSION_MODES.map((m) => `"${m}"`).join(" | ");
|
|
13
16
|
export function coercePermissionMode(raw) {
|
|
14
17
|
const strict = coercePermissionModeStrict(raw);
|
|
@@ -48,10 +51,6 @@ export function effectiveThinking(reasoningEffort, ultracode) {
|
|
|
48
51
|
const ultra = resolveReasoningProfile("ultra").thinking;
|
|
49
52
|
return explicit && rankOf(explicit) > rankOf(ultra) ? explicit : ultra;
|
|
50
53
|
}
|
|
51
|
-
export function withPermissionMode(settings, mode) {
|
|
52
|
-
const base = settings ?? {};
|
|
53
|
-
return { ...base, permissions: { ...base.permissions, defaultMode: mode } };
|
|
54
|
-
}
|
|
55
54
|
export function effectivePermissionMode(body, settings) {
|
|
56
55
|
const requested = coercePermissionMode(body.permissionMode) ?? settings?.permissions?.defaultMode;
|
|
57
56
|
const kill = settings?.permissions?.disableAutoMode;
|
|
@@ -155,8 +154,8 @@ export function settingsPermissionBucketIssue(perms) {
|
|
|
155
154
|
function acceptedRuleList(v) {
|
|
156
155
|
return Array.isArray(v) && v.length > 0 ? v.slice() : undefined;
|
|
157
156
|
}
|
|
158
|
-
export const TASK_SETTINGS_KEYS = ["env", "hooks", "model", "outputStyle", "permissions", "skillListingBudgetFraction", "skillListingMaxDescChars", "ultracode", "webSearch"];
|
|
159
|
-
export const TASK_SETTINGS_PERMISSION_KEYS = ["allow", "ask", "defaultMode", "deny", "disableAutoMode"];
|
|
157
|
+
export const TASK_SETTINGS_KEYS = ["complianceAdditionalDenies", "env", "hooks", "model", "outputStyle", "permissions", "readDenyPatterns", "skillListingBudgetFraction", "skillListingMaxDescChars", "ultracode", "webSearch", "writeProtectedExtra"];
|
|
158
|
+
export const TASK_SETTINGS_PERMISSION_KEYS = ["allow", "ask", "defaultMode", "deny", "disableAutoMode", "neverAuto"];
|
|
160
159
|
export const TASK_SETTINGS_UNSUPPORTED_KEYS = ["apiKeyHelper", "crossSessionInbound", "dialogExpiry", "sandbox", "statusLine"];
|
|
161
160
|
export const TASK_SETTINGS_UNSUPPORTED_PERMISSION_KEYS = ["additionalDirectories", "disableBypassPermissionsMode"];
|
|
162
161
|
const ACCEPTED_TOP = new Set(TASK_SETTINGS_KEYS);
|
|
@@ -195,6 +194,9 @@ export function taskSettingsKeyIssue(raw) {
|
|
|
195
194
|
export function taskHooksHonored(config) {
|
|
196
195
|
return config.requirePrincipal !== true;
|
|
197
196
|
}
|
|
197
|
+
function tightenOnlySeatDeferredName(name) {
|
|
198
|
+
return tightenOnlySeatField(name).replace(/^settings\./, "");
|
|
199
|
+
}
|
|
198
200
|
export function parseTaskSettings(raw, seats = {}) {
|
|
199
201
|
if (raw === null || raw === undefined || typeof raw !== "object")
|
|
200
202
|
return { deferred: [] };
|
|
@@ -262,6 +264,11 @@ export function parseTaskSettings(raw, seats = {}) {
|
|
|
262
264
|
const maxDesc = s.skillListingMaxDescChars;
|
|
263
265
|
if (skillListingMaxDescOk(maxDesc))
|
|
264
266
|
out.skillListingMaxDescChars = maxDesc;
|
|
267
|
+
const tightenSeats = readTightenOnlySeats(raw);
|
|
268
|
+
for (const name of tightenSeats.rejected)
|
|
269
|
+
deferred.push(tightenOnlySeatDeferredName(name));
|
|
270
|
+
if (Object.keys(tightenSeats.values).length > 0)
|
|
271
|
+
out.tightenOnly = tightenSeats.values;
|
|
265
272
|
return { settings: Object.keys(out).length > 0 ? out : undefined, deferred, ...(hooksReread !== undefined ? { hooksReread } : {}) };
|
|
266
273
|
}
|
|
267
274
|
export function acceptAppendSystemPrompt(v, warn) {
|
|
@@ -280,7 +287,7 @@ export function acceptAppendSystemPrompt(v, warn) {
|
|
|
280
287
|
const RULE_SOURCE_BY_BEHAVIOR = { ask: "settings.permissions.ask", deny: "settings.permissions.deny" };
|
|
281
288
|
const WORKFLOW_ASK_NAMES = [RUN_WORKFLOW_TOOL_NAME];
|
|
282
289
|
const isWorkflowName = (name) => name === RUN_WORKFLOW_TOOL_NAME;
|
|
283
|
-
function createWorkflowAskPolicy(isExempt) {
|
|
290
|
+
export function createWorkflowAskPolicy(isExempt) {
|
|
284
291
|
return {
|
|
285
292
|
async check(req) {
|
|
286
293
|
if (heldRuleName(req, isWorkflowName) === undefined)
|
|
@@ -302,17 +309,31 @@ function createWorkflowAskPolicy(isExempt) {
|
|
|
302
309
|
function rejectUnmatchableSettingsNames(perms, pathBases) {
|
|
303
310
|
const refused = rulePolicyBucketsRefusal(perms, { ...(pathBases !== undefined ? { declared: pathBases } : {}), ...(pathBases?.home !== undefined ? { home: pathBases.home } : {}) });
|
|
304
311
|
if (refused !== undefined)
|
|
305
|
-
throw new
|
|
312
|
+
throw new SettingsRuleRefusalError(refused.message, refused.problems);
|
|
313
|
+
}
|
|
314
|
+
export class SettingsRuleRefusalError extends Error {
|
|
315
|
+
problems;
|
|
316
|
+
constructor(message, problems) {
|
|
317
|
+
super(message);
|
|
318
|
+
this.problems = problems;
|
|
319
|
+
this.name = "SettingsRuleRefusalError";
|
|
320
|
+
}
|
|
306
321
|
}
|
|
322
|
+
export const SETTINGS_RULE_REFUSAL_CODE = "request.unprocessable";
|
|
307
323
|
export const RULE_POLICY_BUCKETS = ["ask", "deny"];
|
|
308
324
|
export function rulePolicyBucketsRefusal(permissions, bases) {
|
|
325
|
+
let first;
|
|
326
|
+
const problems = [];
|
|
309
327
|
for (const bucket of RULE_POLICY_BUCKETS) {
|
|
310
328
|
const names = permissions[bucket];
|
|
311
329
|
if (!names)
|
|
312
330
|
continue;
|
|
313
|
-
const
|
|
314
|
-
if (
|
|
315
|
-
|
|
331
|
+
const judged = judgeUnmatchableToolNames(`permissions.${bucket}`, names, { consumer: "rule-policy", behavior: bucket, ...(bases.declared !== undefined ? { pathBases: bases.declared } : {}) });
|
|
332
|
+
if (judged === undefined)
|
|
333
|
+
continue;
|
|
334
|
+
first ??= { bucket, message: judged.message };
|
|
335
|
+
for (const b of judged.bad)
|
|
336
|
+
problems.push(entryProblem(SETTINGS_RULE_REFUSAL_CODE, `settings.permissions.${bucket}`, b.name, b.reason));
|
|
316
337
|
}
|
|
317
338
|
if (bases.home === undefined) {
|
|
318
339
|
for (const bucket of RULE_POLICY_BUCKETS) {
|
|
@@ -320,73 +341,60 @@ export function rulePolicyBucketsRefusal(permissions, bases) {
|
|
|
320
341
|
for (const name of permissions[bucket] ?? []) {
|
|
321
342
|
const parsed = parseRuleText(name, bucket);
|
|
322
343
|
if ("rule" in parsed && ruleToolGrammarOf(parsed.rule.tool) === "path" && parsed.rule.command.startsWith("~/")) {
|
|
323
|
-
|
|
344
|
+
first ??= {
|
|
324
345
|
bucket,
|
|
325
346
|
message: `${field} has a home-relative path rule (${name}) but this deployment cannot resolve the EXECUTION environment's home directory — ` +
|
|
326
347
|
`the engine never guesses one: without a home base the rule resolves to "unreadable" and every matching call stops to ask, so it guards nothing. ` +
|
|
327
348
|
`Spell the path absolutely (${"Edit(//abs/path/**)"} form), declare the lane's home with REMOTE_EXEC_HOME_DIR, or run the task on a lane whose home this worker knows.`,
|
|
328
349
|
};
|
|
350
|
+
problems.push(entryProblem(SETTINGS_RULE_REFUSAL_CODE, `settings.${field}`, name, "home_unresolvable"));
|
|
329
351
|
}
|
|
330
352
|
}
|
|
331
353
|
}
|
|
332
354
|
}
|
|
333
|
-
return undefined;
|
|
355
|
+
return first === undefined ? undefined : { ...first, problems };
|
|
334
356
|
}
|
|
335
357
|
export const REQUEST_SETTINGS_REFUSAL_PREFIX = "request settings cannot be applied as written: ";
|
|
336
|
-
export function deriveSettingsPolicy(settings,
|
|
358
|
+
export function deriveSettingsPolicy(settings, bases) {
|
|
337
359
|
const perms = settings.permissions;
|
|
338
|
-
|
|
360
|
+
const neverAuto = settings.tightenOnly?.neverAuto;
|
|
361
|
+
if (!perms && neverAuto === undefined)
|
|
339
362
|
return {};
|
|
340
|
-
const { deny, ask, defaultMode } = perms;
|
|
341
|
-
const pathBases = gate?.taskRoot !== undefined || gate?.taskHome !== undefined
|
|
342
|
-
? { ...(gate.taskRoot !== undefined ? { root: gate.taskRoot } : {}), ...(gate.taskHome !== undefined ? { home: gate.taskHome } : {}) }
|
|
343
|
-
: undefined;
|
|
344
|
-
rejectUnmatchableSettingsNames(perms, pathBases);
|
|
345
363
|
const policies = [];
|
|
346
|
-
if (
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
};
|
|
363
|
-
const compose = (...extra) => {
|
|
364
|
-
const all = [...policies, ...extra.filter((p) => p !== undefined)];
|
|
365
|
-
return all.length === 0 ? undefined : all.length === 1 ? all[0] : combinePolicies(...all);
|
|
366
|
-
};
|
|
367
|
-
const basePolicy = compose();
|
|
368
|
-
switch (defaultMode) {
|
|
369
|
-
case "acceptEdits": {
|
|
370
|
-
const p = compose(fsWriteGate(true), createWorkflowAskPolicy(workflowGate?.isExempt));
|
|
371
|
-
return p ? { toolPolicy: p } : {};
|
|
372
|
-
}
|
|
373
|
-
case "default":
|
|
374
|
-
case "auto":
|
|
375
|
-
case "dontAsk":
|
|
376
|
-
case "plan": {
|
|
377
|
-
const p = compose(createWorkflowAskPolicy(workflowGate?.isExempt));
|
|
378
|
-
return p ? { toolPolicy: p } : {};
|
|
379
|
-
}
|
|
380
|
-
case "bypassPermissions":
|
|
381
|
-
case undefined:
|
|
382
|
-
return basePolicy ? { toolPolicy: basePolicy } : {};
|
|
364
|
+
if (perms) {
|
|
365
|
+
const { deny, ask } = perms;
|
|
366
|
+
const pathBases = bases?.taskRoot !== undefined || bases?.taskHome !== undefined
|
|
367
|
+
? { ...(bases.taskRoot !== undefined ? { root: bases.taskRoot } : {}), ...(bases.taskHome !== undefined ? { home: bases.taskHome } : {}) }
|
|
368
|
+
: undefined;
|
|
369
|
+
rejectUnmatchableSettingsNames(perms, pathBases);
|
|
370
|
+
if (deny)
|
|
371
|
+
policies.push(createRuleListPolicy(deny, "deny", RULE_SOURCE_BY_BEHAVIOR.deny, pathBases));
|
|
372
|
+
if (ask)
|
|
373
|
+
policies.push(createRuleListPolicy(ask, "ask", RULE_SOURCE_BY_BEHAVIOR.ask, pathBases));
|
|
374
|
+
}
|
|
375
|
+
if (neverAuto !== undefined) {
|
|
376
|
+
const refused = neverAutoNamesRefusal(neverAuto);
|
|
377
|
+
if (refused !== undefined)
|
|
378
|
+
throw new SettingsRuleRefusalError(refused.message, refused.problems);
|
|
379
|
+
policies.push(createRequestNeverAutoPolicy(neverAuto, tightenOnlySeatField("neverAuto")));
|
|
383
380
|
}
|
|
381
|
+
if (policies.length === 0)
|
|
382
|
+
return {};
|
|
383
|
+
return { toolPolicy: policies.length === 1 ? policies[0] : combinePolicies(...policies) };
|
|
384
|
+
}
|
|
385
|
+
export function neverAutoNamesRefusal(names) {
|
|
386
|
+
const field = tightenOnlySeatField("neverAuto");
|
|
387
|
+
const judged = judgeUnmatchableToolNames(field.replace(/^settings\./, ""), names, { consumer: "tool-name-table", behavior: "deny" });
|
|
388
|
+
if (judged === undefined)
|
|
389
|
+
return undefined;
|
|
390
|
+
return { message: judged.message, problems: judged.bad.map((b) => entryProblem(SETTINGS_RULE_REFUSAL_CODE, field, b.name, b.reason)) };
|
|
384
391
|
}
|
|
385
|
-
export function applyTaskSettings(base, settings,
|
|
386
|
-
const { toolPolicy } = deriveSettingsPolicy(settings,
|
|
392
|
+
export function applyTaskSettings(base, settings, bases) {
|
|
393
|
+
const { toolPolicy } = deriveSettingsPolicy(settings, bases);
|
|
394
|
+
const seatSpec = settings.tightenOnly !== undefined ? tightenOnlySpecSeats(settings.tightenOnly) : {};
|
|
387
395
|
let next = base;
|
|
388
|
-
if (toolPolicy !== undefined)
|
|
389
|
-
next = tightenGoverned(next, { toolPolicy });
|
|
396
|
+
if (toolPolicy !== undefined || Object.keys(seatSpec).length > 0)
|
|
397
|
+
next = tightenGoverned(next, { ...(toolPolicy !== undefined ? { toolPolicy } : {}), ...seatSpec });
|
|
390
398
|
const allow = settings.permissions?.allow;
|
|
391
399
|
if (allow !== undefined)
|
|
392
400
|
next = { ...next, allowedTools: allow };
|
package/dist/text-bidi.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/** bidi ∪ C0/DEL —— **清洗**面用(见文件头注:清洗面比检测面宽是刻意的)。bidi 半场内插 core 的类,C0/DEL 半场是本仓清洗面自己的。 */
|
|
2
|
-
export declare const CONTROL_AND_BIDI_CHARS = "\\u0000-\\u001f\\u007f\\u061C\\u200E\\u200F\\u202A-\\u202E\\u2066-\\u2069";
|
|
3
|
-
/** 清洗用的全局正则(`String.replace` 会在返回前把 `lastIndex` 归零,故模块级常量可安全复用)。 */
|
|
4
|
-
export declare const CONTROL_AND_BIDI_STRIP_RE: RegExp;
|
|
5
1
|
/** 这串文本里**有没有** bidi 控制符(判官 = core 的 {@link carriesBidiControls})。纯谓词:不改一个字节、不做任何清洗(理由见文件头注)。 */
|
|
6
2
|
export declare function hasBidiControls(text: string): boolean;
|
|
7
3
|
//# sourceMappingURL=text-bidi.d.ts.map
|
package/dist/text-bidi.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export const CONTROL_AND_BIDI_CHARS = `\\u0000-\\u001f\\u007f${BIDI_CONTROL_CHARS}`;
|
|
3
|
-
export const CONTROL_AND_BIDI_STRIP_RE = new RegExp(`[${CONTROL_AND_BIDI_CHARS}]`, "g");
|
|
1
|
+
import { carriesBidiControls } from "@sema-agent/core";
|
|
4
2
|
const WHOLE_TEXT_SCAN = { maxNodes: 1, maxChars: Number.MAX_SAFE_INTEGER };
|
|
5
3
|
export function hasBidiControls(text) {
|
|
6
4
|
return carriesBidiControls(text, WHOLE_TEXT_SCAN);
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **请求面「只收紧」座位族** —— 团队仓库里只会收紧的四张列表,在 `settings` 面各有一个每请求座位:一张闭集座位表、一组受理判据、一个能力位。
|
|
3
|
+
*
|
|
4
|
+
* | 座位(`settings.…`) | 去处 | 部署侧的表 |
|
|
5
|
+
* |-------------------------------------|-----------------------------------------------------------------------------------------------|-------------------------------------|
|
|
6
|
+
* | `readDenyPatterns` | core 任务层席 `TaskSpec.readDenyPatterns`(只增不减) | `READ_DENY_PATTERNS` |
|
|
7
|
+
* | `writeProtectedExtra` | core 任务层席 `TaskSpec.writeProtectedAdditions`(只增不减) | `WRITE_PROTECTED_EXTRA` |
|
|
8
|
+
* | `complianceAdditionalDenies` | core 任务层席 `TaskSpec.complianceAdditionalDenies`(只增不减) | `COMPLIANCE_ADDITIONAL_DENIES` |
|
|
9
|
+
* | `permissions.neverAuto` | 本仓审批席的请求叶策略(命中的工具恒问真人;见 `approval.ts` `createRequestNeverAutoPolicy`) | `APPROVAL_NEVER_AUTO` |
|
|
10
|
+
*
|
|
11
|
+
* ## 律
|
|
12
|
+
* · **取并在拥有部署表的那一层做一次**:三座的部署表在 core 的 `RunnerDeps`(`readDenyPatterns` / `writeProtectedPaths` / `compliancePostureResolver`),与任务层列表的并集由 core 在 prepare 取
|
|
13
|
+
* (`CLAMP_SET` 的 addOnly 律:`[]` 不抹任何行、任务层只加不减);`neverAuto` 的部署表在本仓审批席,请求叶与基线名单经 `tightenGoverned` 的 deny-wins 折叠取并。
|
|
14
|
+
* **本仓不在折叠之外手写第二份并集** —— 那是下游改上游席语义(并集规则一份在 core,哪天 core 改身份函数,本仓的副本会静默分岔)。
|
|
15
|
+
* · **空数组 ≡ 缺席**(并集的单位元):读入时不铸键,spec 与不带这个座位的请求字节相同。
|
|
16
|
+
* · **请求面没有放宽臂**:列表只能加行;送空、送别的行,部署的表一行不少。
|
|
17
|
+
* · **条目律借引擎的判官**(同一批 env 腿读的那几只:`compileReadDeny` / `resolveWriteProtectedTable` / `COMPLIANCE_CAPABILITIES`),宿主不自造第二份校验语义;读拒条目的元素文法 env / 中心 / 请求三腿同读
|
|
18
|
+
* `read-deny-entry.ts` 的那一只。受理面在 prepare 之前把坏形响亮拒掉(400),不让它变成 200 之后才失败的一跑。
|
|
19
|
+
* · 受理判据一处({@link tightenOnlySeatIssue}):不是数组 / 超帽 / 坏项 ⇒ 400 `request.field_invalid` + 机读位(`field` / `reason` / `count`+`cap` | `index`),与 S-904 三桶同形。
|
|
20
|
+
* fresh 受理口、`resolveSpec`(两腿)、存体重放预判三处调这一只。
|
|
21
|
+
* · 座位表是闭集:加一座 = 加一行(`TIGHTEN_ONLY_SEAT_NAMES` 与表互为编译期穷举;`wire` 位置必须落在 `task-settings.ts` 的受理列里 —— 下面的编译期门)。
|
|
22
|
+
*
|
|
23
|
+
* 谁调:`task-settings.ts`(`parseTaskSettings` 读入 · `applyTaskSettings` 投影 · 键闭集门)· `http/admission.ts` / `boot/resolve-spec.ts` / `http/stored-body-replay.ts`(受理判据)·
|
|
24
|
+
* `http/routes/capabilities.ts`(能力位 `taskSettings.tightenOnlySeats`)· `request-key-closure.ts`(顶层同名键的拒句指路)。
|
|
25
|
+
*/
|
|
26
|
+
import { type ComplianceCapability, type ReadDenyEntry, type WriteProtectedEntry } from "@sema-agent/core";
|
|
27
|
+
import type { GovernanceOverrides } from "./governance-overrides.js";
|
|
28
|
+
import { type LimitFacts } from "./limit-refusal.js";
|
|
29
|
+
/** 四座(表序;句子说「表序里第一座」)。 */
|
|
30
|
+
export declare const TIGHTEN_ONLY_SEAT_NAMES: readonly ["neverAuto", "readDenyPatterns", "writeProtectedExtra", "complianceAdditionalDenies"];
|
|
31
|
+
export type TightenOnlySeatName = (typeof TIGHTEN_ONLY_SEAT_NAMES)[number];
|
|
32
|
+
/** 每座一个条目的类型(归一后的值;进 spec / 请求叶的就是它,不另投影)。 */
|
|
33
|
+
interface SeatEntryTypes {
|
|
34
|
+
readonly neverAuto: string;
|
|
35
|
+
readonly readDenyPatterns: ReadDenyEntry;
|
|
36
|
+
readonly writeProtectedExtra: WriteProtectedEntry;
|
|
37
|
+
readonly complianceAdditionalDenies: ComplianceCapability;
|
|
38
|
+
}
|
|
39
|
+
/** 读入的产物:每座一份归一后的非空列表(缺席的座不在)。 */
|
|
40
|
+
export type TightenOnlySeatValues = {
|
|
41
|
+
readonly [N in TightenOnlySeatName]?: readonly SeatEntryTypes[N][];
|
|
42
|
+
};
|
|
43
|
+
type SeatValuesDraft = {
|
|
44
|
+
-readonly [N in TightenOnlySeatName]?: readonly SeatEntryTypes[N][];
|
|
45
|
+
};
|
|
46
|
+
/** 三座落 core 任务层席时进 spec 的片段(键 = core 的 `TaskSpec` 席名)。 */
|
|
47
|
+
export type TightenOnlySpecSeats = Pick<GovernanceOverrides, "readDenyPatterns" | "writeProtectedAdditions" | "complianceAdditionalDenies">;
|
|
48
|
+
/** 座位在 `settings` 里的位置:顶层键,或 `permissions` 下的一个成员。 */
|
|
49
|
+
type SeatWire = readonly [key: string] | readonly [container: "permissions", key: string];
|
|
50
|
+
declare const SEAT_WIRE: {
|
|
51
|
+
readonly neverAuto: readonly ["permissions", "neverAuto"];
|
|
52
|
+
readonly readDenyPatterns: readonly ["readDenyPatterns"];
|
|
53
|
+
readonly writeProtectedExtra: readonly ["writeProtectedExtra"];
|
|
54
|
+
readonly complianceAdditionalDenies: readonly ["complianceAdditionalDenies"];
|
|
55
|
+
};
|
|
56
|
+
/** 编译期门:每座的 wire 位置都在 `task-settings.ts` 的受理列里(座位表加一行而受理列没跟 ⇒ 这里红 —— 否则键闭集门会把新座 400 掉)。 */
|
|
57
|
+
type SeatTopKeys = Extract<(typeof SEAT_WIRE)[TightenOnlySeatName], readonly [string]>[0];
|
|
58
|
+
type SeatPermissionKeys = Extract<(typeof SEAT_WIRE)[TightenOnlySeatName], readonly ["permissions", string]>[1];
|
|
59
|
+
/** 一个条目的读数:归一值,或接在坐标后面成句的原因(自带连接符)。 */
|
|
60
|
+
type EntryReading<E> = {
|
|
61
|
+
readonly ok: true;
|
|
62
|
+
readonly value: E;
|
|
63
|
+
} | {
|
|
64
|
+
readonly ok: false;
|
|
65
|
+
readonly after: string;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* 一行座位。方法写成**方法签名**(参数双变):表是异质的,遍历时由 {@link eachSeat} 用同一个 `E` 把一行的读 / 放 / 投影三件事配回去。
|
|
69
|
+
* · `grammar` —— 句子里说「这张表该装什么」;
|
|
70
|
+
* · `readEntry` —— 一个条目的受理判(借引擎的判官);
|
|
71
|
+
* · `get` / `put` —— 归一值在 {@link TightenOnlySeatValues} 里的位置(每行自己拼一次本座的键,类型检查);
|
|
72
|
+
* · `sink` —— 去处:core 任务层席(`toSpec` 给出进 spec 的片段)或本仓审批席。
|
|
73
|
+
*/
|
|
74
|
+
interface SeatRow<E> {
|
|
75
|
+
readonly wire: SeatWire;
|
|
76
|
+
readonly grammar: string;
|
|
77
|
+
readEntry(entry: unknown): EntryReading<E>;
|
|
78
|
+
get(values: TightenOnlySeatValues): readonly E[] | undefined;
|
|
79
|
+
put(draft: SeatValuesDraft, list: readonly E[]): void;
|
|
80
|
+
/** 这一座的条数帽(超了响亮拒 `over_cap`,不截;先于逐条读,拒体有界)。 */
|
|
81
|
+
readonly maxEntries: number;
|
|
82
|
+
/** 整张列表的**成本预算**(可选;只给「引擎匹配代价随条目内容增长」的座):`measure` 数一张列表占多少预算,超 `cap` ⇒ 响亮拒(`over_cap` + `count` + `cap`),不截。 */
|
|
83
|
+
readonly budget?: {
|
|
84
|
+
measure(list: readonly E[]): number;
|
|
85
|
+
readonly cap: number;
|
|
86
|
+
readonly unit: string;
|
|
87
|
+
};
|
|
88
|
+
readonly sink: {
|
|
89
|
+
readonly kind: "core_task_seat";
|
|
90
|
+
toSpec(list: readonly E[]): TightenOnlySpecSeats;
|
|
91
|
+
} | {
|
|
92
|
+
readonly kind: "approval_seat";
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 读拒模式的**成本单位 = 一颗 `*`**:引擎(core `compileSegmentPattern`)把每一颗 `*` 编成一个 `[^/]*`,相邻的星就是相邻的回溯点 ——
|
|
97
|
+
* 一段里 k 颗 `*` 对长度 n 的路径段是 n 的 k 次方级回溯(实测 16 颗连续的星对 17 字的段 ≈ 4 s,跑在事件循环上、任何计时器打不断)。
|
|
98
|
+
* 所以界按**调用方写下的每一颗**计,不按「连续的一串」计。整段 `**` / `id_rsa*` / `*.pem` / `*secret*` / `*_*_key` / `a**b` 都在内。
|
|
99
|
+
*/
|
|
100
|
+
export declare const MAX_READ_DENY_STARS_PER_SEGMENT = 2;
|
|
101
|
+
/** 整张 `readDenyPatterns` 列表的 `*` 总预算:引擎每次判路径对每条模式、每个路径段各跑一遍,一段 2 颗星是段长的平方 —— 总量只界住「乘几遍」(128 颗时 64 条的表对万字段 ≈ 3.9 s)。
|
|
102
|
+
* 不是上界:16 颗的整表(8 条各 2 颗)对对手形的 4000 字段本机实测约 1 s、万字段约 5–6 s;段长的那一维只能在引擎里收(线性时间匹配或路径段长度上限,已向引擎请托)。 */
|
|
103
|
+
export declare const MAX_READ_DENY_STARS_TOTAL = 16;
|
|
104
|
+
/** 每座条数的缺省上限 —— 与 `settings.permissions` 三桶同一只帽(编译口的整表帽;超了响亮拒,不截)。读拒模式另有更紧的一只({@link MAX_READ_DENY_ENTRIES}),每座的帽写在座位表那一行。 */
|
|
105
|
+
export declare const MAX_TIGHTEN_ONLY_SEAT_ENTRIES = 1000;
|
|
106
|
+
/** 整张 `readDenyPatterns` 列表的条数帽:不带星的条目也是每段一遍匹配,条数本身就是成本(其余三座的帽是 {@link MAX_TIGHTEN_ONLY_SEAT_ENTRIES})。 */
|
|
107
|
+
export declare const MAX_READ_DENY_ENTRIES = 32;
|
|
108
|
+
/** 座位表(闭集;`{ [N in 座名]: SeatRow }` 双向穷举:少一座 / 多一座都是编译红)。 */
|
|
109
|
+
export declare const TIGHTEN_ONLY_SEATS: {
|
|
110
|
+
readonly [N in TightenOnlySeatName]: SeatRow<SeatEntryTypes[N]>;
|
|
111
|
+
};
|
|
112
|
+
/** 一座在体内的坐标的**字面类型**(`settings.readDenyPatterns` | … | `settings.permissions.neverAuto`),从 {@link SEAT_WIRE} 派生,不手抄。 */
|
|
113
|
+
export type TightenOnlySeatField = `settings.${SeatTopKeys}` | `settings.permissions.${SeatPermissionKeys}`;
|
|
114
|
+
/** 一座在体内的坐标(`settings.readDenyPatterns` / `settings.permissions.neverAuto`)。 */
|
|
115
|
+
export declare function tightenOnlySeatField(name: TightenOnlySeatName): TightenOnlySeatField;
|
|
116
|
+
/** 拒体的机读位:撞帽 = {@link LimitFacts}(`over_cap` + `count` + `cap`),坏项 = `bad_entry`(+ 首个坏项的下标;整座不是数组时无下标)。 */
|
|
117
|
+
export type TightenOnlySeatIssueFields = LimitFacts | {
|
|
118
|
+
readonly field: string;
|
|
119
|
+
readonly reason: "bad_entry";
|
|
120
|
+
readonly index?: number;
|
|
121
|
+
};
|
|
122
|
+
/** 一次裁决:是哪一座、wire 文案、机读位。 */
|
|
123
|
+
export interface TightenOnlySeatIssue {
|
|
124
|
+
readonly seat: TightenOnlySeatName;
|
|
125
|
+
readonly message: string;
|
|
126
|
+
readonly fields: TightenOnlySeatIssueFields;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 四座的**唯一**受理判据(纯函数)。逐座按表序(整表判只有 {@link readSeat} 一只,本函数与 {@link readTightenOnlySeats} 共用):缺席 / `null` ⇒ 不判;不是数组 ⇒ `bad_entry`(无下标);
|
|
130
|
+
* 超帽 ⇒ `over_cap`(先于逐条读,拒体有界);首个坏条目 ⇒ `bad_entry` + 它的下标;成本预算超了 ⇒ `over_cap`(`count` = 占用,`cap` = 预算)。全合法 ⇒ `null`。空数组合法(单位元)。
|
|
131
|
+
* 句子出口剥控制与双向字符(引擎的原因句可能转载调用方的条目文字)。
|
|
132
|
+
*/
|
|
133
|
+
export declare function tightenOnlySeatIssue(settings: unknown): TightenOnlySeatIssue | null;
|
|
134
|
+
/** 读入的结果:归一后的非空列表(空数组 ≡ 缺席,不铸键);判据说不合法的座**整座丢弃**并报名(`rejected`)—— 只有绕过两道入口的读者走得到,留痕由调用方记。 */
|
|
135
|
+
export interface ReadTightenOnlySeats {
|
|
136
|
+
readonly values: TightenOnlySeatValues;
|
|
137
|
+
readonly rejected: readonly TightenOnlySeatName[];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* 把一份**未验过**的 `settings` 读成四座的归一值(`parseTaskSettings` 的读入腿 —— RESUME 重放也走这里,所以宽容:不抛、坏座整座丢弃并报名)。
|
|
141
|
+
* 与 {@link tightenOnlySeatIssue} 共用 {@link readSeat}(同一只整表判):fresh 提交与续跑在更早处已被它响亮拒过,这里是宽容层。
|
|
142
|
+
*/
|
|
143
|
+
export declare function readTightenOnlySeats(settings: unknown): ReadTightenOnlySeats;
|
|
144
|
+
/**
|
|
145
|
+
* 三座落 core 任务层席的 spec 片段(进 `tightenGoverned` 的 `TaskSpec` 席名 —— 与部署表取并由 core 的 addOnly 律在 prepare 做一次)。没有这三座的值 ⇒ `{}`。
|
|
146
|
+
* `neverAuto` 不在这里(它的去处是审批席的请求叶策略,见 `approval.ts` 的 `createRequestNeverAutoPolicy`)。
|
|
147
|
+
*/
|
|
148
|
+
export declare function tightenOnlySpecSeats(values: TightenOnlySeatValues): TightenOnlySpecSeats;
|
|
149
|
+
export {};
|
|
150
|
+
//# sourceMappingURL=tighten-only-seats.d.ts.map
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { COMPLIANCE_CAPABILITIES, compileReadDeny, resolveWriteProtectedTable } from "@sema-agent/core";
|
|
2
|
+
import { echoCallerText } from "./caller-text-echo.js";
|
|
3
|
+
import { limitRefusal } from "./limit-refusal.js";
|
|
4
|
+
import { MAX_PERMISSION_RULES_PER_LIST } from "./permission-rule-list.js";
|
|
5
|
+
import { readReadDenyEntry } from "./read-deny-entry.js";
|
|
6
|
+
import { stripControlAndBidi } from "@sema-agent/settings-schema";
|
|
7
|
+
export const TIGHTEN_ONLY_SEAT_NAMES = ["neverAuto", "readDenyPatterns", "writeProtectedExtra", "complianceAdditionalDenies"];
|
|
8
|
+
const SEAT_WIRE = {
|
|
9
|
+
neverAuto: ["permissions", "neverAuto"],
|
|
10
|
+
readDenyPatterns: ["readDenyPatterns"],
|
|
11
|
+
writeProtectedExtra: ["writeProtectedExtra"],
|
|
12
|
+
complianceAdditionalDenies: ["complianceAdditionalDenies"],
|
|
13
|
+
};
|
|
14
|
+
const CORE_REASON_ECHO_CHARS = 400;
|
|
15
|
+
function coreReason(e) {
|
|
16
|
+
const text = e instanceof Error ? e.message : String(e);
|
|
17
|
+
return echoCallerText(text.replace(/^(?:readDenyPatterns \(additions\)|writeProtectedPaths): /, ""), { maxChars: CORE_REASON_ECHO_CHARS });
|
|
18
|
+
}
|
|
19
|
+
export const MAX_READ_DENY_STARS_PER_SEGMENT = 2;
|
|
20
|
+
export const MAX_READ_DENY_STARS_TOTAL = 16;
|
|
21
|
+
export const MAX_TIGHTEN_ONLY_SEAT_ENTRIES = MAX_PERMISSION_RULES_PER_LIST;
|
|
22
|
+
export const MAX_READ_DENY_ENTRIES = 32;
|
|
23
|
+
const starsIn = (text) => (text.match(/\*/g) ?? []).length;
|
|
24
|
+
function maxStarsPerSegment(pattern) {
|
|
25
|
+
return pattern.split("/").reduce((max, segment) => Math.max(max, starsIn(segment)), 0);
|
|
26
|
+
}
|
|
27
|
+
function isComplianceCapability(entry) {
|
|
28
|
+
return COMPLIANCE_CAPABILITIES.includes(entry);
|
|
29
|
+
}
|
|
30
|
+
export const TIGHTEN_ONLY_SEATS = {
|
|
31
|
+
neverAuto: {
|
|
32
|
+
wire: SEAT_WIRE.neverAuto,
|
|
33
|
+
grammar: "non-empty tool-name strings",
|
|
34
|
+
readEntry: (entry) => (typeof entry === "string" && entry.length > 0 ? { ok: true, value: entry } : { ok: false, after: " is not a non-empty tool name string" }),
|
|
35
|
+
maxEntries: MAX_TIGHTEN_ONLY_SEAT_ENTRIES,
|
|
36
|
+
get: (values) => values.neverAuto,
|
|
37
|
+
put: (draft, list) => {
|
|
38
|
+
draft.neverAuto = list;
|
|
39
|
+
},
|
|
40
|
+
sink: { kind: "approval_seat" },
|
|
41
|
+
},
|
|
42
|
+
readDenyPatterns: {
|
|
43
|
+
wire: SEAT_WIRE.readDenyPatterns,
|
|
44
|
+
grammar: "read-deny patterns (a string, or an object { pattern, caseSensitive? })",
|
|
45
|
+
readEntry: (entry) => {
|
|
46
|
+
const read = readReadDenyEntry(entry);
|
|
47
|
+
if (!read.ok)
|
|
48
|
+
return { ok: false, after: read.after };
|
|
49
|
+
try {
|
|
50
|
+
compileReadDeny([read.entry]);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
return { ok: false, after: ` is refused by the engine: ${coreReason(e)}` };
|
|
54
|
+
}
|
|
55
|
+
const stars = maxStarsPerSegment(read.entry.pattern);
|
|
56
|
+
if (stars > MAX_READ_DENY_STARS_PER_SEGMENT) {
|
|
57
|
+
return { ok: false, after: ` has a path segment with ${stars} "*" wildcards — at most ${MAX_READ_DENY_STARS_PER_SEGMENT} per segment are accepted in a request, each "*" counted (the engine matches a segment by backtracking and the cost grows with each extra wildcard); merge them, or ask the operator to put the row in READ_DENY_PATTERNS` };
|
|
58
|
+
}
|
|
59
|
+
return { ok: true, value: read.entry };
|
|
60
|
+
},
|
|
61
|
+
maxEntries: MAX_READ_DENY_ENTRIES,
|
|
62
|
+
get: (values) => values.readDenyPatterns,
|
|
63
|
+
put: (draft, list) => {
|
|
64
|
+
draft.readDenyPatterns = list;
|
|
65
|
+
},
|
|
66
|
+
budget: { measure: (list) => list.reduce((sum, entry) => sum + starsIn(typeof entry === "string" ? entry : entry.pattern), 0), cap: MAX_READ_DENY_STARS_TOTAL, unit: `"*" wildcards` },
|
|
67
|
+
sink: { kind: "core_task_seat", toSpec: (list) => ({ readDenyPatterns: [...list] }) },
|
|
68
|
+
},
|
|
69
|
+
writeProtectedExtra: {
|
|
70
|
+
wire: SEAT_WIRE.writeProtectedExtra,
|
|
71
|
+
grammar: "write-protection names (a literal name string, or an object { name, kind })",
|
|
72
|
+
readEntry: (entry) => {
|
|
73
|
+
try {
|
|
74
|
+
const rows = resolveWriteProtectedTable([entry]);
|
|
75
|
+
const row = rows[0];
|
|
76
|
+
if (rows.length !== 1 || row === undefined)
|
|
77
|
+
return { ok: false, after: " does not read as exactly one write-protection row" };
|
|
78
|
+
return { ok: true, value: row };
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
return { ok: false, after: ` is refused by the engine: ${coreReason(e)}` };
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
maxEntries: MAX_TIGHTEN_ONLY_SEAT_ENTRIES,
|
|
85
|
+
get: (values) => values.writeProtectedExtra,
|
|
86
|
+
put: (draft, list) => {
|
|
87
|
+
draft.writeProtectedExtra = list;
|
|
88
|
+
},
|
|
89
|
+
sink: { kind: "core_task_seat", toSpec: (list) => ({ writeProtectedAdditions: [...list] }) },
|
|
90
|
+
},
|
|
91
|
+
complianceAdditionalDenies: {
|
|
92
|
+
wire: SEAT_WIRE.complianceAdditionalDenies,
|
|
93
|
+
grammar: `capability names (${COMPLIANCE_CAPABILITIES.join("|")})`,
|
|
94
|
+
readEntry: (entry) => isComplianceCapability(entry)
|
|
95
|
+
? { ok: true, value: entry }
|
|
96
|
+
: { ok: false, after: ` is not one of ${COMPLIANCE_CAPABILITIES.join("|")}` },
|
|
97
|
+
maxEntries: MAX_TIGHTEN_ONLY_SEAT_ENTRIES,
|
|
98
|
+
get: (values) => values.complianceAdditionalDenies,
|
|
99
|
+
put: (draft, list) => {
|
|
100
|
+
draft.complianceAdditionalDenies = list;
|
|
101
|
+
},
|
|
102
|
+
sink: { kind: "core_task_seat", toSpec: (list) => ({ complianceAdditionalDenies: [...list] }) },
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
function eachSeat(visit) {
|
|
106
|
+
return TIGHTEN_ONLY_SEAT_NAMES.map((name) => visit(name, TIGHTEN_ONLY_SEATS[name]));
|
|
107
|
+
}
|
|
108
|
+
export function tightenOnlySeatField(name) {
|
|
109
|
+
const wire = SEAT_WIRE[name];
|
|
110
|
+
return wire.length === 1 ? `settings.${wire[0]}` : `settings.${wire[0]}.${wire[1]}`;
|
|
111
|
+
}
|
|
112
|
+
function rawListOf(settings, wire) {
|
|
113
|
+
if (settings === null || typeof settings !== "object" || Array.isArray(settings))
|
|
114
|
+
return undefined;
|
|
115
|
+
const top = settings[wire[0]];
|
|
116
|
+
if (wire.length === 1)
|
|
117
|
+
return top;
|
|
118
|
+
if (top === null || typeof top !== "object" || Array.isArray(top))
|
|
119
|
+
return undefined;
|
|
120
|
+
return top[wire[1]];
|
|
121
|
+
}
|
|
122
|
+
function readSeat(name, row, settings) {
|
|
123
|
+
const raw = rawListOf(settings, row.wire);
|
|
124
|
+
if (raw === undefined || raw === null)
|
|
125
|
+
return { kind: "absent" };
|
|
126
|
+
const field = tightenOnlySeatField(name);
|
|
127
|
+
const refuse = (message, fields) => ({ kind: "refused", seat: name, message: sanitized(message), fields });
|
|
128
|
+
if (!Array.isArray(raw)) {
|
|
129
|
+
return refuse(`${field} must be an array of ${row.grammar} — refused rather than ignored, because an ignored list reads as "in effect" to the caller`, { field, reason: "bad_entry" });
|
|
130
|
+
}
|
|
131
|
+
if (raw.length > row.maxEntries) {
|
|
132
|
+
const refusal = limitRefusal(field, "entries", raw.length, row.maxEntries, {
|
|
133
|
+
tail: "Refused rather than truncated: a truncated list silently drops the entries past the cap, and a dropped tightening is one that never happened. Merge entries into broader patterns or trim the list",
|
|
134
|
+
});
|
|
135
|
+
return refuse(refusal.message, refusal.facts);
|
|
136
|
+
}
|
|
137
|
+
const list = [];
|
|
138
|
+
for (let index = 0; index < raw.length; index++) {
|
|
139
|
+
const read = row.readEntry(raw[index]);
|
|
140
|
+
if (!read.ok) {
|
|
141
|
+
const after = read.after.replace(/\.$/, "");
|
|
142
|
+
return refuse(`${field}[${index}]${after} — every entry must be ${row.grammar}. Refused rather than dropped, because a dropped entry reads as "in effect" to the caller`, { field, reason: "bad_entry", index });
|
|
143
|
+
}
|
|
144
|
+
list.push(read.value);
|
|
145
|
+
}
|
|
146
|
+
const budget = row.budget;
|
|
147
|
+
if (budget !== undefined) {
|
|
148
|
+
const count = budget.measure(list);
|
|
149
|
+
if (count > budget.cap) {
|
|
150
|
+
return refuse(`${field} has ${count} ${budget.unit} in total — at most ${budget.cap} are accepted. Refused rather than truncated: a truncated list silently drops the entries past the budget, and a dropped tightening is one that never happened. Merge entries into broader patterns or trim the list`, { field, reason: "over_cap", count, cap: budget.cap });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { kind: "list", list };
|
|
154
|
+
}
|
|
155
|
+
export function tightenOnlySeatIssue(settings) {
|
|
156
|
+
for (const reading of eachSeat((name, row) => readSeat(name, row, settings))) {
|
|
157
|
+
if (reading.kind === "refused")
|
|
158
|
+
return { seat: reading.seat, message: reading.message, fields: reading.fields };
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
function sanitized(message) {
|
|
163
|
+
return stripControlAndBidi(message);
|
|
164
|
+
}
|
|
165
|
+
export function readTightenOnlySeats(settings) {
|
|
166
|
+
const draft = {};
|
|
167
|
+
const rejected = [];
|
|
168
|
+
eachSeat((name, row) => {
|
|
169
|
+
const reading = readSeat(name, row, settings);
|
|
170
|
+
if (reading.kind === "refused")
|
|
171
|
+
rejected.push(name);
|
|
172
|
+
else if (reading.kind === "list" && reading.list.length > 0)
|
|
173
|
+
row.put(draft, reading.list);
|
|
174
|
+
});
|
|
175
|
+
return { values: draft, rejected };
|
|
176
|
+
}
|
|
177
|
+
export function tightenOnlySpecSeats(values) {
|
|
178
|
+
const fragments = eachSeat((_name, row) => {
|
|
179
|
+
const list = row.get(values);
|
|
180
|
+
if (list === undefined || list.length === 0)
|
|
181
|
+
return undefined;
|
|
182
|
+
const sink = row.sink;
|
|
183
|
+
switch (sink.kind) {
|
|
184
|
+
case "core_task_seat":
|
|
185
|
+
return sink.toSpec(list);
|
|
186
|
+
case "approval_seat":
|
|
187
|
+
return undefined;
|
|
188
|
+
default: {
|
|
189
|
+
const unhandled = sink;
|
|
190
|
+
throw new Error(`tighten-only seat sink ${JSON.stringify(unhandled)} has no projection arm`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
return fragments.reduce((acc, fragment) => (fragment === undefined ? acc : { ...acc, ...fragment }), {});
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=tighten-only-seats.js.map
|