@sema-agent/server 7.105.0 → 7.107.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 +105 -0
- package/README.md +2 -2
- package/USAGE.md +135 -43
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +2 -0
- package/deploy/sema-up/cluster-up.sh +15 -2
- package/deploy/sema-up/kube-up.sh +8 -3
- package/deploy/sema-up/lib/flagshape.sh +29 -0
- package/deploy/sema-up/lib/parse-machines.py +4 -1
- package/deploy/sema-up/sema-up.sh +11 -9
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +3 -1
- package/dist/approval-card.d.ts +1 -1
- package/dist/approval.d.ts +6 -1
- package/dist/approval.js +4 -4
- package/dist/auth-bridge.d.ts +14 -0
- package/dist/auth-bridge.js +7 -0
- package/dist/auto-mode-face.d.ts +49 -40
- package/dist/auto-mode-face.js +6 -68
- package/dist/bench/s1/live-deps.d.ts +9 -2
- package/dist/bench/s1/live-deps.js +13 -8
- package/dist/boot/budget-tracing.js +3 -2
- package/dist/boot/config-center.d.ts +4 -0
- package/dist/boot/config-center.js +95 -37
- package/dist/boot/coordinators.d.ts +1 -0
- package/dist/boot/coordinators.js +3 -1
- package/dist/boot/device-lane.d.ts +2 -1
- package/dist/boot/execution-env.d.ts +11 -0
- package/dist/boot/execution-env.js +30 -6
- package/dist/boot/execution-lane.js +2 -3
- package/dist/boot/leader.d.ts +2 -1
- package/dist/boot/leader.js +2 -0
- package/dist/boot/parked-revive-gate.d.ts +10 -7
- package/dist/boot/parked-revive-gate.js +4 -11
- package/dist/boot/resolve-spec.d.ts +1 -4
- package/dist/boot/resolve-spec.js +44 -21
- package/dist/boot/runner-deps.d.ts +5 -8
- package/dist/boot/runner-deps.js +3 -9
- package/dist/boot/side-query-lane.d.ts +2 -2
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +2 -1
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +3 -2
- package/dist/boot/stage-06-runners.js +2 -5
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +1 -2
- package/dist/boot/stage-08-reapers.d.ts +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -2
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +2 -2
- package/dist/boot/stage-10-http-server.js +11 -7
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/stores.js +6 -4
- package/dist/brain.d.ts +24 -2
- package/dist/brain.js +29 -10
- package/dist/budget.js +3 -0
- package/dist/capabilities/center-wiring.d.ts +64 -0
- package/dist/capabilities/center-wiring.js +24 -0
- package/dist/capabilities/composite-members.d.ts +89 -0
- package/dist/capabilities/composite-members.js +20 -0
- package/dist/capabilities/execution-lane.d.ts +3 -0
- package/dist/capabilities/execution-lane.js +5 -2
- package/dist/config-catalog.d.ts +35 -5
- package/dist/config-catalog.js +92 -26
- package/dist/config-center/apply-effective.d.ts +1 -1
- package/dist/config-center/apply-effective.js +7 -8
- package/dist/config-center/apply-ledger.d.ts +17 -0
- package/dist/config-center/apply-ledger.js +5 -0
- package/dist/config-center/center-request.d.ts +17 -0
- package/dist/config-center/center-request.js +4 -0
- package/dist/config-center/pull-state.d.ts +29 -0
- package/dist/config-center/pull-state.js +2 -0
- package/dist/config-types.d.ts +41 -14
- package/dist/config-types.js +1 -0
- package/dist/config.d.ts +35 -0
- package/dist/config.js +69 -16
- package/dist/cross-session-settings.d.ts +1 -1
- package/dist/deployment-governance.d.ts +12 -1
- package/dist/deployment-governance.js +2 -0
- package/dist/execution-lane-caps.d.ts +30 -2
- package/dist/execution-lane-caps.js +12 -0
- package/dist/fleet-client.d.ts +18 -13
- package/dist/fleet-client.js +32 -22
- package/dist/fleet-lease.d.ts +72 -47
- package/dist/fleet-lease.js +66 -14
- package/dist/governance-http-status.d.ts +0 -1
- package/dist/governance-http-status.js +0 -1
- package/dist/hosted-posture.d.ts +6 -17
- package/dist/hosted-posture.js +11 -6
- package/dist/http/admission.js +14 -9
- package/dist/http/approval-sweeps.js +13 -1
- package/dist/http/dispatch.js +1 -1
- package/dist/http/durable-run-leg.js +2 -0
- package/dist/http/request-guards.d.ts +25 -0
- package/dist/http/request-guards.js +25 -5
- package/dist/http/resume-legs.js +19 -11
- package/dist/http/route-ctx.d.ts +9 -0
- package/dist/http/routes/approvals-assistant.js +0 -1
- package/dist/http/routes/capabilities.js +11 -12
- package/dist/http/routes/config-catalog.js +2 -1
- package/dist/http/routes/diagnostics.js +2 -0
- package/dist/http/routes/tasks.js +4 -1
- package/dist/http/server.d.ts +20 -4
- package/dist/http/session-inherit-env.d.ts +37 -0
- package/dist/http/session-inherit-env.js +6 -0
- package/dist/http/wire-types.d.ts +19 -28
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/key-resolver.d.ts +74 -19
- package/dist/key-resolver.js +65 -7
- package/dist/leader/leader.d.ts +6 -0
- package/dist/leader/leader.js +2 -1
- package/dist/leader/repair-wire.js +2 -1
- package/dist/leader/wire.d.ts +9 -1
- package/dist/leader/wire.js +10 -6
- package/dist/observability/fail-open.d.ts +5 -1
- package/dist/observability/fail-open.js +5 -1
- package/dist/observability/metrics.js +2 -0
- package/dist/observability/permission-rule-events.d.ts +1 -1
- package/dist/observability/permission-rule-events.js +1 -1
- package/dist/observability/run-terminal.d.ts +40 -1
- package/dist/observability/run-terminal.js +2 -5
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/observability/tool-trace.d.ts +2 -0
- package/dist/operator-ask.d.ts +29 -1
- package/dist/operator-ask.js +6 -0
- package/dist/parked-decide.d.ts +14 -1
- package/dist/parked-decide.js +8 -1
- package/dist/plugins/session-policy-store-sql.d.ts +38 -7
- package/dist/plugins/session-policy-store-sql.js +64 -22
- package/dist/plugins/sql-driver.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +12 -3
- package/dist/plugins/store-backend.js +16 -5
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/read-face-posture.d.ts +4 -4
- package/dist/request-key-closure.js +2 -2
- package/dist/request-value-closure.d.ts +17 -5
- package/dist/request-value-closure.js +12 -0
- package/dist/router/route-orchestration.d.ts +11 -0
- package/dist/router/route-orchestration.js +7 -6
- package/dist/run-local.js +4 -2
- package/dist/runs.d.ts +2 -1
- package/dist/runs.js +4 -4
- package/dist/runtime-caps-resolver.d.ts +4 -10
- package/dist/runtime-governance.d.ts +8 -11
- package/dist/runtime-governance.js +10 -41
- package/dist/sealed-key.d.ts +0 -40
- package/dist/sealed-key.js +0 -20
- package/dist/server-secret-env.d.ts +11 -12
- package/dist/session-policy-wire.d.ts +5 -3
- package/dist/session-titler.d.ts +11 -0
- package/dist/session-titler.js +6 -2
- package/dist/sql-engine-posture.d.ts +2 -2
- package/dist/store-posture.d.ts +53 -0
- package/dist/store-posture.js +32 -0
- package/dist/task-settings.d.ts +64 -62
- package/dist/task-settings.js +57 -27
- package/dist/tool-approval.d.ts +51 -22
- package/dist/tool-approval.js +44 -8
- package/dist/tool-declaration-http-status.d.ts +12 -0
- package/dist/tool-declaration-http-status.js +12 -0
- package/dist/trace/core-keyset-guard.d.ts +7 -7
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +5 -0
- package/dist/trace/project.d.ts +7 -5
- package/dist/trace/project.js +51 -3
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/unattended-permission-mode.d.ts +110 -0
- package/dist/unattended-permission-mode.js +65 -0
- package/package.json +3 -3
- package/dist/boot/session-shell-gate-registry.d.ts +0 -39
- package/dist/boot/session-shell-gate-registry.js +0 -21
- package/dist/roster-bound-http-status.d.ts +0 -6
- package/dist/roster-bound-http-status.js +0 -6
|
@@ -29,6 +29,7 @@ PROJECT="${PROJECT:-sema}"
|
|
|
29
29
|
REGION="${REGION:-global}"
|
|
30
30
|
KUBE_MODE="${KUBE_MODE:?KUBE_MODE 未设置(existing|k3s)}"
|
|
31
31
|
DRY_RUN="${DRY_RUN:-false}"
|
|
32
|
+
USERS_GIVEN="${USERS:+1}" # S-600:显式给没给(缺省 single 之前记下;决策见下方 users_decide)
|
|
32
33
|
USERS="${USERS:-single}"
|
|
33
34
|
REGISTRY_ENABLED="${REGISTRY_ENABLED:-true}"
|
|
34
35
|
GIT_MODE="${GIT_MODE:-none}"
|
|
@@ -45,6 +46,10 @@ flag_enum "--users(USERS)" "$USERS" $FLAG_WORDS_USERS
|
|
|
45
46
|
flag_bool "--registry(REGISTRY_ENABLED)" "$REGISTRY_ENABLED"
|
|
46
47
|
flag_enum "--git(GIT_MODE)" "$GIT_MODE" $FLAG_WORDS_GIT
|
|
47
48
|
flag_enum "--region(REGION)" "$REGION" $FLAG_WORDS_REGION
|
|
49
|
+
# S-600:租户形 = 显式 USERS ∨ 上一次落下的部署事实 ∨ single(规则与拒句在 lib/flagshape.sh 的 users_decide)——
|
|
50
|
+
# 在动集群之前判,不带旗的重跑不会把多租部署降成单用户。
|
|
51
|
+
ENVF="$WORK/.env"
|
|
52
|
+
users_decide "$USERS_GIVEN"
|
|
48
53
|
|
|
49
54
|
# ── 0. kubeconfig / 工具解析 ─────────────────────────────────────────────────────
|
|
50
55
|
if [ "$KUBE_MODE" = "k3s" ]; then
|
|
@@ -124,13 +129,12 @@ if [ "$REGISTRY_ENABLED" = "true" ] && [ -z "${SEMA_REGISTRY_IMAGE:-}" ]; then
|
|
|
124
129
|
die "registry=true(默认)需要 SEMA_REGISTRY_IMAGE。下一步:--registry-image=<仓>/sema-registry:<tag>,或 --registry=false"
|
|
125
130
|
fi
|
|
126
131
|
|
|
127
|
-
ENVF="$WORK/.env"
|
|
128
132
|
if [ "$DRY_RUN" = "true" ]; then
|
|
129
133
|
{
|
|
130
134
|
echo "══════ kube-up dry-run(不写文件、不动集群)══════"
|
|
131
135
|
echo " 集群: $NODES 节点(mode=$KUBE_MODE,kubeconfig=$KUBECONFIG)"
|
|
132
136
|
echo " SC: ${STORAGE_CLASS:-默认($DEFAULT_SC)} kata: $KATA_OK(否=沙箱 runc 降级)"
|
|
133
|
-
echo " 形态: pg×$PG_INSTANCES($PG_AA) server×$SERVER_REPLICAS registry=$REGISTRY_ENABLED git=$GIT_MODE"
|
|
137
|
+
echo " 形态: pg×$PG_INSTANCES($PG_AA) server×$SERVER_REPLICAS registry=$REGISTRY_ENABLED git=$GIT_MODE users=$USERS"
|
|
134
138
|
echo " 将执行: CNPG operator $CNPG_VERSION → helm upgrade --install sema-stack -n $NAMESPACE"
|
|
135
139
|
echo " → runner-token 复制 → MinIO 建桶 → $([ "$GIT_MODE" = provision ] && printf 'Gitea 引导(管理员/token/OAuth)→ ')smoke → summary"
|
|
136
140
|
echo " 凭据: $ENVF $([ -f "$ENVF" ] && echo '(已存在:只补缺不轮换)' || echo '(将新建)')"
|
|
@@ -158,6 +162,7 @@ mkdir -p "$WORK"; chmod 700 "$WORK" 2>/dev/null || true
|
|
|
158
162
|
touch "$ENVF"; chmod 600 "$ENVF"
|
|
159
163
|
setk MINIO_PASSWORD "$(openssl rand -hex 24)"
|
|
160
164
|
setk SERVICE_AUTH_TOKEN "$(openssl rand -hex 24)"
|
|
165
|
+
resetk REQUIRE_PRINCIPAL "$(principal_of_users "$USERS")" # S-600:部署事实(下次不带旗重跑据此沿用租户形)
|
|
161
166
|
NEW_REG_PW=false NEW_GIT_PW=false
|
|
162
167
|
if [ "$REGISTRY_ENABLED" = "true" ]; then
|
|
163
168
|
setk_new REGISTRY_ADMIN_PASSWORD "$(openssl rand -hex 24)" && NEW_REG_PW=true
|
|
@@ -191,7 +196,7 @@ helm_values() { # helm_values <giteaBaseUrl> <oauthId> <oauthSecret>
|
|
|
191
196
|
V_MODEL_GATEWAY="$MODEL_GATEWAY_BASEURL" V_MODEL_ID="$MODEL_ID" \
|
|
192
197
|
V_SERVER_IMAGE="$SEMA_SERVER_IMAGE" V_REPLICAS="$SERVER_REPLICAS" \
|
|
193
198
|
V_PG_INSTANCES="$PG_INSTANCES" V_PG_AA="$PG_AA" V_SC="$STORAGE_CLASS" \
|
|
194
|
-
V_RT_CLASS="$RUNTIME_CLASS" V_REQ_PRINCIPAL="$(
|
|
199
|
+
V_RT_CLASS="$RUNTIME_CLASS" V_REQ_PRINCIPAL="$(principal_of_users "$USERS")" \
|
|
195
200
|
V_PKG_SOURCE="$([ "$REGION" = "global" ] && echo global || echo '')" \
|
|
196
201
|
V_REG_ENABLED="$REGISTRY_ENABLED" V_REG_IMAGE="${SEMA_REGISTRY_IMAGE:-}" \
|
|
197
202
|
V_REG_PW="${REGISTRY_ADMIN_PASSWORD:-}" V_REG_SS="${REGISTRY_SESSION_SECRET:-}" V_REG_PT="${REGISTRY_PULL_TOKEN:-}" \
|
|
@@ -18,6 +18,35 @@
|
|
|
18
18
|
# ── 词表(单一属主)──────────────────────────────────────────────────────────────────────────────
|
|
19
19
|
FLAG_WORDS_PROFILE="full-single data-center local-plus full-cluster"
|
|
20
20
|
FLAG_WORDS_USERS="single multi"
|
|
21
|
+
# 租户形 ⇒ 容器上 REQUIRE_PRINCIPAL 的值 —— 这条翻译的**唯一**定义(S-600,7.105.0 从 sema-up.sh 搬来):sema-up 的 compose 生成段 /
|
|
22
|
+
# 事实核对,kube-up 的 helm values,cluster-up 的渲染清单与 helm values 同调这一只(修前 kube-up 另写一份同义翻译,S-619 D5;
|
|
23
|
+
# cluster-up 一份都没有 ⇒ --users=multi 在 --kube=machines 路径上被静默丢成单用户)。只认两词,别的词先过 flag_enum。
|
|
24
|
+
principal_of_users() { [ "$1" = "multi" ] && echo true || echo false; }
|
|
25
|
+
|
|
26
|
+
# users_decide <显式给了 USERS 吗(1 / 空)> —— kube 两条装配路径(kube-up / cluster-up)的租户形决策,与 sema-up 的
|
|
27
|
+
# compose 档同一条规则:**决策 = 显式 USERS ∨ 上一次落在 $ENVF 的部署事实 REQUIRE_PRINCIPAL ∨ single**;显式值与事实
|
|
28
|
+
# 不一致 ⇒ 拒并点名两处(不静默把一台多租部署降成单用户,也不静默把单用户升成多租)。事实 → 租户词只经
|
|
29
|
+
# principal_of_users 反查(两词逐个过正向比,不另写反表);认不出的事实值 ⇒ 拒。设 USERS。
|
|
30
|
+
# S-600 codex 一轮 [high]:machines 路径开始认 --users 之后,一次不带旗的重跑会拿缺省 single 把多租部署的
|
|
31
|
+
# REQUIRE_PRINCIPAL 翻回 false(kube-up 路径此前就同形)—— 事实由两只脚本各自在写凭据的同一处 resetk 落盘。
|
|
32
|
+
# 调用方先 source lib/envf.sh 并定好 ENVF(文件可以还不存在 = 首装,无事实)。
|
|
33
|
+
users_decide() {
|
|
34
|
+
local given="$1" fact fact_users="" u
|
|
35
|
+
fact="$(envf_get REQUIRE_PRINCIPAL)" || exit 1
|
|
36
|
+
[ -n "$fact" ] || return 0
|
|
37
|
+
for u in $FLAG_WORDS_USERS; do [ "$(principal_of_users "$u")" = "$fact" ] && fact_users="$u"; done
|
|
38
|
+
if [ -z "$fact_users" ]; then
|
|
39
|
+
log "⛔ 部署事实 $ENVF 里 REQUIRE_PRINCIPAL=$(flag_show "$fact"):本工具只读自己写出的两形 $(principal_of_users multi) / $(principal_of_users single)"
|
|
40
|
+
log " ↳ 下一步:改成 REQUIRE_PRINCIPAL=$(principal_of_users multi)(多人)或 REQUIRE_PRINCIPAL=$(principal_of_users single)(单人),再重跑"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
if [ -z "$given" ]; then USERS="$fact_users"; return 0; fi
|
|
44
|
+
if [ "$USERS" != "$fact_users" ]; then
|
|
45
|
+
log "⛔ 部署事实冲突:$ENVF 里 REQUIRE_PRINCIPAL=$fact(= --users=$fact_users),本次 --users=$USERS 要写 REQUIRE_PRINCIPAL=$(principal_of_users "$USERS")"
|
|
46
|
+
log " ↳ 下一步:不带 --users 重跑即沿用这台部署的租户形;真要改租户形,先确认身份隔离的影响,再把 $ENVF 里那一行改掉后重跑"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
}
|
|
21
50
|
FLAG_WORDS_REGION="auto cn global"
|
|
22
51
|
FLAG_WORDS_GIT="none provision connect"
|
|
23
52
|
# kube 路径:单机两态走 kube-up.sh,machines(多机 ssh 装配)走 cluster-up.sh。
|
|
@@ -80,7 +80,10 @@ def main(path):
|
|
|
80
80
|
|
|
81
81
|
emit("PROFILE", top.get("profile"))
|
|
82
82
|
emit("REGION", top.get("region", "auto"))
|
|
83
|
-
|
|
83
|
+
# S-600(codex 一轮 [high]):不写 users 就**不发射** —— 修前缺省发射 single,等于替运维表了态,sema-up 于是把它当显式旗,
|
|
84
|
+
# 盖掉 `.env` 里上一次落下的部署事实(多租部署不带旗重跑 ⇒ 被降成单用户,或撞事实冲突拒)。缺省归 sema-up 的决策
|
|
85
|
+
# (显式旗 ∨ 部署事实 ∨ 表缺省 single),不在解析器里另立一份。
|
|
86
|
+
emit("USERS", top.get("users"))
|
|
84
87
|
# server 镜像(registry 引用;海外=docker.io/<ns>/sema-server:<tag>)
|
|
85
88
|
emit("SEMA_SERVER_IMAGE", top.get("server_image"))
|
|
86
89
|
emit("MACHINE_COUNT", str(len(machines)))
|
|
@@ -339,20 +339,21 @@ fi
|
|
|
339
339
|
"full-cluster:k8s 准生产——3 机 ssh 装配 / 已有集群 kubeconfig / 本机装 k3s" \
|
|
340
340
|
"local-plus:本机只跑 agent,连一个已经部署好的 data-center 数据面")
|
|
341
341
|
# ── 两个决策(租户形 / 车道)同一条规则:决策 = 显式旗 ∨ 部署事实 ∨ 表缺省 ─────────────────────
|
|
342
|
-
#
|
|
343
|
-
# data-center 不起 agent
|
|
342
|
+
# 「部署事实」= 同一只 `$WORK/.env`:compose 的 agent 档由本脚本写,full-cluster 由 kube-up / cluster-up 在写凭据的同一处
|
|
343
|
+
# 写(S-600;修前 kube 两条路径不落这条事实 ⇒ 不带旗重跑拿缺省 single 把多租部署降回单用户);data-center 不起 agent。事实 → 决策词只经属主翻译,本脚本不抄第二份:
|
|
344
344
|
# · REQUIRE_PRINCIPAL → --users:只认 sema-up 自己写出的两形 true / false(别的写法 ⇒ 拒;不复刻 server 的布尔词表);
|
|
345
345
|
# · REMOTE_EXEC → --sandbox:`lanes choice-of`(车道表是唯一属主;表里没有的落盘值 ⇒ 拒并列在役词),见车道块。
|
|
346
346
|
# 不带旗重跑 ⇒ 沿用事实(多租部署重跑不必再带 --users=multi);显式旗与事实不一致 ⇒ fact_conflict 拒并点名两处。
|
|
347
347
|
# 🔴 为什么缺省不能先于事实(合并复审两条真案):把表缺省当成意图去和事实比,合法的无旗重跑就被拒;
|
|
348
348
|
# 反过来若只比不拒,保留的多租 `.env` 在缺省 single 下会被车道表判成 host —— 容器拿到 REQUIRE_PRINCIPAL=true ∧ host。
|
|
349
|
-
# 租户形 ⇒ 容器上 REQUIRE_PRINCIPAL
|
|
350
|
-
# (事实 → --users 缺省)
|
|
351
|
-
#
|
|
352
|
-
principal_of_users() { [ "$1" = "multi" ] && echo true || echo false; }
|
|
349
|
+
# 租户形 ⇒ 容器上 REQUIRE_PRINCIPAL 的值:`principal_of_users`(lib/flagshape.sh,三只脚本共用的唯一定义;S-600 起 kube-up /
|
|
350
|
+
# cluster-up 也调它)。正向(生成段 setk、事实核对)与反向(事实 → --users 缺省)都经它:反向是拿两个租户词逐个过这只函数去比,
|
|
351
|
+
# 不另写一张反表(与车道的 `lanes choice-of` 同一姿势)。
|
|
353
352
|
USERS_DEF="single" RP_FACT="" RP_FACT_SRC=""
|
|
354
353
|
case "$PROFILE" in
|
|
355
|
-
full-
|
|
354
|
+
# S-600:full-cluster 也读 —— kube-up / cluster-up 在写凭据的同一处把 REQUIRE_PRINCIPAL 落进同一只 .env(它们自己
|
|
355
|
+
# 单独跑时也按同一条规则判,见 lib/flagshape.sh 的 users_decide)。
|
|
356
|
+
full-single|local-plus|full-cluster)
|
|
356
357
|
deploy_fact REQUIRE_PRINCIPAL; RP_FACT="$FACT_VAL" RP_FACT_SRC="$FACT_SRC"
|
|
357
358
|
if [ -n "$RP_FACT" ]; then
|
|
358
359
|
USERS_DEF=""
|
|
@@ -470,8 +471,9 @@ if [ "$PROFILE" = "full-cluster" ]; then
|
|
|
470
471
|
case "$KUBE_MODE" in
|
|
471
472
|
machines)
|
|
472
473
|
[ "${MACHINE_COUNT:-0}" -ge 1 ] || { log "⛔ --kube=machines 需要 -f machines.yaml(机器清单);模板见 deploy/sema-up/machines.example.yaml"; exit 1; }
|
|
473
|
-
$DRY_RUN && { log "dry-run:将经 cluster-up.sh 对 ${MACHINE_COUNT} 台机器做 k3s HA 装配(ssh)+ helm/render
|
|
474
|
-
|
|
474
|
+
$DRY_RUN && { log "dry-run:将经 cluster-up.sh 对 ${MACHINE_COUNT} 台机器做 k3s HA 装配(ssh)+ helm/render 装栈(users=$USERS);不执行"; exit 0; }
|
|
475
|
+
# S-600:租户形交给 cluster-up(修前不传 ⇒ 这条路径上的主 worker 恒单用户姿态,--users=multi 被静默丢)。
|
|
476
|
+
WORK="$WORK" REGION="$REGION" PROJECT="$PROJECT" USERS="$USERS" \
|
|
475
477
|
MODEL_GATEWAY_BASEURL="$GATEWAY" MODEL_ID="$MODEL" MODEL_API_KEY="${MODEL_KEY:-${MODEL_API_KEY:-}}" \
|
|
476
478
|
exec "$HERE/cluster-up.sh"
|
|
477
479
|
;;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# sema-stack(full-cluster 形态,Phase 1b as-built;cluster-up.sh 渲染 __占位符__ 后 apply)
|
|
2
|
-
# 占位符:__MINIO_PW__ __SVC_TOKEN__ __MODEL_KEY__ __MODEL_GATEWAY__ __MODEL_ID__
|
|
2
|
+
# 占位符:__MINIO_PW__ __SVC_TOKEN__ __MODEL_KEY__ __MODEL_GATEWAY__ __MODEL_ID__ __REQUIRE_PRINCIPAL__
|
|
3
3
|
# __SERVER_IMAGE__ __SERVER_PULL_POLICY__(tar 预灌=Never / registry 拉取=IfNotPresent)
|
|
4
4
|
# 前置(cluster-up.sh 负责):Longhorn 默认 SC、kata-deploy(runtimeclass kata-qemu)、CNPG operator 1.30、
|
|
5
5
|
# runner token 跨 ns 复制成 sema/sema-runner-token-copy、MinIO 建桶 sema-pg-backup
|
|
@@ -169,6 +169,8 @@ spec:
|
|
|
169
169
|
- { name: MODEL_ID, value: "__MODEL_ID__" }
|
|
170
170
|
- { name: MODEL_API_KEY, valueFrom: { secretKeyRef: { name: sema-server-env, key: MODEL_API_KEY } } }
|
|
171
171
|
- { name: MODEL_VISION, value: "false" }
|
|
172
|
+
# S-600:租户姿态与 chart 主 worker 同值(cluster-up 由 --users 渲:multi ⇒ true,否则 false);修前整块缺席 ⇒ 恒单用户
|
|
173
|
+
- { name: REQUIRE_PRINCIPAL, value: "__REQUIRE_PRINCIPAL__" }
|
|
172
174
|
- { name: SANDBOX_PKG_SOURCE, value: "__PKG_SOURCE__" }
|
|
173
175
|
- { name: REMOTE_EXEC, value: k8s }
|
|
174
176
|
# S-599:显式表态「这台有手」(车道被改没了 ⇒ 拒启,不是安静的无手 worker)
|
package/dist/approval-card.d.ts
CHANGED
|
@@ -415,7 +415,7 @@ type ToolApprovalPark = Extract<CorePendingAction, {
|
|
|
415
415
|
*
|
|
416
416
|
* 什么时候经本函数 —— 一句话:**筛点在 core;server 只在「读的是持久层原字节、中间没有 core 投影」的地方亲手调 core 的那一只筛**。
|
|
417
417
|
* inbox 行读 core `CheckpointSummary.{mandate,origin}`(core `summarizeCheckpoint` 已用同一只 `isPersistedRuleMandate` / `isAskOrigin`
|
|
418
|
-
* 筛过)⇒
|
|
418
|
+
* 筛过)⇒ 那一面直投、不经本函数;运维队列行读的是 park 行 `pendingAction` 子树的原字节
|
|
419
419
|
* (两店 `listPending`,中间没有 core 投影)⇒ 经本函数 —— 于是 inbox 行与队列行对同一张 park 行(含手改行 / 世代差的集外词)逐字同答。
|
|
420
420
|
*
|
|
421
421
|
* **不抄词表**([ref]):闭集判定 = core 的成员筛({@link CLOSED_WORD_SEAT_GUARDS});值型 = core 寄存行上那一座的型。本仓对这些词
|
package/dist/approval.d.ts
CHANGED
|
@@ -136,7 +136,12 @@ export interface DurableAskOptions {
|
|
|
136
136
|
neverAuto?: string[];
|
|
137
137
|
/** Per-session approval-exemption probe ("本会话不再询问"): consulted ONLY for require-listed
|
|
138
138
|
* tools, AFTER deny/neverAuto (both always win) and BEFORE the budget path. Canonical-space toolName.
|
|
139
|
-
* A rejected promise is treated as NOT exempt (fail-closed → ask) at the call site below.
|
|
139
|
+
* A rejected promise is treated as NOT exempt (fail-closed → ask) at the call site below.
|
|
140
|
+
* 🔴 S-877 候裁 16:会话授权**两个读位、一只店、按问句的作者分**(收车档 ⑩ 16):本探针兑现**本仓自己的问**(名单门)
|
|
141
|
+
* —— 在它自己的层上「不问」,于是委派子代经父约束链继承到的同一问也不问;引擎自装的问(模式写门 / 形状层)由审批席
|
|
142
|
+
* (`ToolApprovalCoordinator.standingGrantSettles`)兑现。本探针**不能**退役:子代的继承问到达祖先审批席时 core 盖
|
|
143
|
+
* `mandated`(`ruleClearanceOf` 的 inheritedUnresolved / ancestorResolved 门),席的判据依约不退役它 —— 只有本层的
|
|
144
|
+
* 「不问」够得着继承链(钉 test/parked-decide-leg.test.ts「[候裁② 修]remember 全链行为」)。 */
|
|
140
145
|
exempt?: (canonicalToolName: string) => Promise<boolean>;
|
|
141
146
|
/** Audit hook — fired when an exemption short-circuits the ask (the `approval_exempted` log line). */
|
|
142
147
|
onExempted?: (canonicalToolName: string, rawToolName: string) => void;
|
package/dist/approval.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "@sema-agent/core";
|
|
2
|
-
import { operatorAsk } from "./operator-ask.js";
|
|
2
|
+
import { operatorAlwaysHumanAsk, operatorAsk } from "./operator-ask.js";
|
|
3
3
|
import { ASK_USER_QUESTION_TOOL_NAME } from "./approval-content-kind.js";
|
|
4
4
|
import { isExplicitPosture } from "./posture-source.js";
|
|
5
5
|
import { handsOnWorkerFilePlane } from "./execution-lane-caps.js";
|
|
@@ -85,11 +85,11 @@ export function createDurableAskPolicy(opts) {
|
|
|
85
85
|
if (deny(toolName))
|
|
86
86
|
return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
|
|
87
87
|
if (neverAuto(toolName))
|
|
88
|
-
return
|
|
88
|
+
return operatorAlwaysHumanAsk(`APPROVAL_NEVER_AUTO(${toolName})`, `human approval required to run "${req.toolName}"`);
|
|
89
89
|
if (require(toolName)) {
|
|
90
90
|
const remEarly = req.budget?.resourceRemainingMicroUsd;
|
|
91
91
|
if (remEarly !== undefined && remEarly <= 0) {
|
|
92
|
-
return
|
|
92
|
+
return operatorAlwaysHumanAsk("RESOURCE_SUSPEND budget exhausted", `durable resource budget exhausted — human approval required to run "${req.toolName}"`);
|
|
93
93
|
}
|
|
94
94
|
if (opts.exempt && toolName !== ASK_USER_QUESTION_TOOL_NAME) {
|
|
95
95
|
return (async () => {
|
|
@@ -115,7 +115,7 @@ export function createDurableAskPolicy(opts) {
|
|
|
115
115
|
function decideRequired(req, toolName) {
|
|
116
116
|
const rem = req.budget?.resourceRemainingMicroUsd;
|
|
117
117
|
if (rem !== undefined && rem <= 0) {
|
|
118
|
-
return
|
|
118
|
+
return operatorAlwaysHumanAsk("RESOURCE_SUSPEND budget exhausted", `durable resource budget exhausted — human approval required to run "${req.toolName}"`);
|
|
119
119
|
}
|
|
120
120
|
if (toolName !== ASK_USER_QUESTION_TOOL_NAME && budget > 0 && autoApproved < budget) {
|
|
121
121
|
autoApproved++;
|
package/dist/auth-bridge.d.ts
CHANGED
|
@@ -2,6 +2,20 @@ import { type AuthBridgeErrorCode, type VerifiedIdentity } from "@sema-agent/set
|
|
|
2
2
|
import type { Logger } from "./observability/logger.js";
|
|
3
3
|
import type { Metrics } from "./observability/metrics.js";
|
|
4
4
|
export type { VerifiedIdentity } from "@sema-agent/settings-schema/api/auth-bridge";
|
|
5
|
+
/**
|
|
6
|
+
* S-866 ② —— 鉴权桥 issuer 的**唯一**取值(装配 `boot/stage-09-leader.ts` 与 caps `centerWiring.issuer` 同读,不各写一份回退):
|
|
7
|
+
* 显式 `AUTH_BRIDGE_ISSUER`(`config.authBridgeIssuer`)恒赢 ⇒ `source:"explicit"`;缺席则回退中心基址 `configCenter.baseUrl`
|
|
8
|
+
* (配了中心即默认开桥)⇒ `source:"fallback"`;两者都没有 ⇒ `undefined`(桥不装)。
|
|
9
|
+
*/
|
|
10
|
+
export declare function authBridgeIssuerOf(config: {
|
|
11
|
+
readonly authBridgeIssuer?: string | undefined;
|
|
12
|
+
readonly configCenter?: {
|
|
13
|
+
readonly baseUrl: string;
|
|
14
|
+
} | undefined;
|
|
15
|
+
}): {
|
|
16
|
+
readonly issuer: string;
|
|
17
|
+
readonly source: "explicit" | "fallback";
|
|
18
|
+
} | undefined;
|
|
5
19
|
export interface RegistryJwtVerifierOptions {
|
|
6
20
|
/** R4 — 期望 iss(registry 的 SSO_ISSUER;默认=SEMA_REGISTRY_URL,双侧去尾斜杠比较)。 */
|
|
7
21
|
issuer: string;
|
package/dist/auth-bridge.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { createPublicKey, verify as cryptoVerify } from "node:crypto";
|
|
2
2
|
import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC, REGISTRY_JWKS_PATH, RegistryJwks, classifyTimeClaims, jwksWithinOfflineGrace, shouldForceJwksRefresh, toVerifiedIdentity, } from "@sema-agent/settings-schema/api/auth-bridge";
|
|
3
3
|
import { buildDisplaySafeUrl } from "./trace/redact.js";
|
|
4
|
+
export function authBridgeIssuerOf(config) {
|
|
5
|
+
if (config.authBridgeIssuer !== undefined)
|
|
6
|
+
return { issuer: config.authBridgeIssuer, source: "explicit" };
|
|
7
|
+
if (config.configCenter !== undefined)
|
|
8
|
+
return { issuer: config.configCenter.baseUrl, source: "fallback" };
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
4
11
|
const DEFAULT_JWKS_TTL_SEC = 15 * 60;
|
|
5
12
|
const MAX_JWKS_BYTES = 256 * 1024;
|
|
6
13
|
const MAX_TOKEN_CHARS = 16 * 1024;
|
package/dist/auto-mode-face.d.ts
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [ref] ④(黑板 [ref]/[ref]/[ref],core [ref] 合修)—— auto 模式的**可自查读面**:`/v1/capabilities`
|
|
3
|
+
* 的 `permissionModeAuto.{armed, reason, model}` 三键怎么算。
|
|
4
|
+
*
|
|
5
|
+
* ## 病根一句话
|
|
6
|
+
* 壳 07-21 起默认点亮 `permissionMode:"auto"`,而引擎半场从未接通:core 旧武装式是「org 授予」极性
|
|
7
|
+
* (`runtimeCaps.autoMode === true ∧ deps.autoMode`),server 的授予路径只有 center ⇒ 无 center 的本地部署
|
|
8
|
+
* auto **永不武装** = default + 静态白名单(真实用户诊断,六断言全成立)。core [ref] 把谓词换成 CC 250 的
|
|
9
|
+
* 「用户开 + org 拒」极性;core 7.34.0([ref])再把意图收成**一个键** —— 模式词本身:
|
|
10
|
+
*
|
|
11
|
+
* armed ⟺ TaskSpec.permissionMode === "auto" ∧ RunnerDeps.autoMode !== undefined ∧ RuntimeCaps.autoMode !== false
|
|
12
|
+
*
|
|
13
|
+
* 任一合取项落空 ⇒ 引擎把这条腿折成 `default` 并发 `config.permission_mode_unavailable`
|
|
14
|
+
* (`by: "face_absent" | "operator_deny"`;码名按 core `ENGINE_NOTICE_CODES` 亲读)。
|
|
15
|
+
*
|
|
16
|
+
* 本模块按**server 侧可知的同三项**算一份「若此刻提交会不会武装」的裁决,供壳(cli `sema doctor permissions`)
|
|
17
|
+
* 与人自查。三项分别对应三个未武装原因(判序 = 谓词的合取序,先判到的先报):
|
|
18
|
+
* · `mode_not_auto` —— 本次意图不是 auto(`?permissionMode=` 查询串给的;缺席 = 按 auto 意图答);
|
|
19
|
+
* · `deployment_incapable` —— 装配面没挂 `RunnerDeps.autoMode` 分类器席位(生产装配恒挂;桩/一次性 CLI 不挂);
|
|
20
|
+
* · `org_denied` —— per-principal caps 的 `autoMode === false` 且本地 deny 未设(center 显式 deny、center
|
|
21
|
+
* 硬失败的 fail-closed 拒项);
|
|
22
|
+
* · `local_denied` —— 本地 `PERMISSIONS_DISABLE_AUTO_MODE=true`(catalog/settings 键 `permissions.disableAutoMode`);
|
|
23
|
+
* · `settings_denied` —— settings 层 `permissions.disableAutoMode` 取 `"disable"` 或 `true`([ref]:两套已发布拼写同义)
|
|
24
|
+
* 折掉本 run 的 auto([ref] 第六员;run 级面产,
|
|
25
|
+
* capabilities 查询串不带 settings ⇒ 本面不产);
|
|
26
|
+
* · `resolver_fault` —— resolver 抛错(core 同形全拒:autoMode:false + onError phase config)。
|
|
27
|
+
*
|
|
28
|
+
* 🔴 S-877(core 7.34.0 提货):「这台机器上装的 core 用哪套武装极性」的**安装包探针**(按文本扫
|
|
29
|
+
* `dist/core/runner/prepare-task.js` 找 `autoModeRequested`)整只退役 —— 7.34.0 起那个键被引擎按名拒,探针的主判
|
|
30
|
+
* 恒假、佐证恒真 ⇒ 矛盾臂 fatal,整台 server 起服即拒(S-878 探针 7.34.0 读数的 13 只红文件同一根因)。
|
|
31
|
+
* 极性不再是运行期要猜的事实:本仓把 core **精确钉版**(`package.json`,`test/core-dependency-floor.test.ts` 承重),
|
|
32
|
+
* 钉住的那一版的武装谓词就是上面那一行,由类型面(`TaskSpec.permissionMode` / `RunnerDeps.autoMode` /
|
|
33
|
+
* `RuntimeCaps.autoMode`)与 core CHANGELOG 同时陈述。⇒ 旧式臂(「org 授予」极性)与 `engineArmsOnIntent` 座一并删,
|
|
34
|
+
* 规则集少一整支;**不再读任何 dist 文本**。
|
|
35
|
+
*
|
|
36
|
+
* ## 闭集纪律([ref])
|
|
37
|
+
* 六词是 core [ref] seam ⑤ + [ref] PM 裁定的闭集;`AUTO_MODE_UNARMED_REASON_SEMANTICS` 是 `Record<Reason, string>` 锁步表——
|
|
38
|
+
* 词表加员而语义表不加、或反之,都是编译红。本面**不**给壳发 prose(机器码上 wire,人话归壳),语义表只
|
|
39
|
+
* 服务于文档/测试对拍。
|
|
40
|
+
*
|
|
41
|
+
* ## 判据不是「授权了」
|
|
42
|
+
* `entitlementSource`(既有位)说的是「center 源在不在」;`armed` 说的是「按三态谓词此刻会不会武装」。
|
|
43
|
+
* 两者刻意并存:前者告诉壳有没有组织面,后者告诉壳这台机器上 auto 到底是不是 default 的别名。
|
|
44
|
+
*/
|
|
1
45
|
import { type RunnerDeps, type RuntimeCaps } from "@sema-agent/core";
|
|
2
46
|
import type { SettingsPermissionMode } from "./task-settings.js";
|
|
3
47
|
/**
|
|
@@ -37,53 +81,19 @@ export declare const AUTO_MODE_UNARMED_REASONS: readonly ["mode_not_auto", "depl
|
|
|
37
81
|
export type AutoModeUnarmedReason = (typeof AUTO_MODE_UNARMED_REASONS)[number];
|
|
38
82
|
/** 锁步表:词表与语义一一对应(加员/删员任一侧不同步 = tsc 红)。语义只供文档/测试,不上 wire。 */
|
|
39
83
|
export declare const AUTO_MODE_UNARMED_REASON_SEMANTICS: {
|
|
40
|
-
readonly mode_not_auto: "本次意图不是 auto(壳发的 permissionMode 不是 \"auto\"
|
|
41
|
-
readonly deployment_incapable: "装配面没挂 RunnerDeps.autoMode 分类器席位(本部署/本进程形不具备分类器)
|
|
42
|
-
readonly org_denied: "per-principal caps.autoMode === false 且本地 deny 未设:center 显式 deny / center 硬失败 fail-closed
|
|
84
|
+
readonly mode_not_auto: "本次意图不是 auto(壳发的 permissionMode 不是 \"auto\")";
|
|
85
|
+
readonly deployment_incapable: "装配面没挂 RunnerDeps.autoMode 分类器席位(本部署/本进程形不具备分类器)";
|
|
86
|
+
readonly org_denied: "per-principal caps.autoMode === false 且本地 deny 未设:center 显式 deny / center 硬失败 fail-closed 拒项";
|
|
43
87
|
readonly local_denied: "本地 catalog 键 PERMISSIONS_DISABLE_AUTO_MODE=true(center/settings 键名 permissions.disableAutoMode)把 caps.autoMode 折成 false";
|
|
44
88
|
readonly settings_denied: "settings 层 permissions.disableAutoMode 取 disable 或 true(两套已发布拼写同义;用户/managed 层 kill-switch)把本 run 折成非 auto —— capabilities 查询串不带 settings,本词由 run 级面产([6128] PM 裁定第六员)";
|
|
45
89
|
readonly resolver_fault: "per-principal caps resolver 抛错/答非记录(core 同形全拒:autoMode:false + onError phase config)";
|
|
46
90
|
};
|
|
47
|
-
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* 判据([ref] 改,原先用「854b202b 同批的运行时导出 `mailboxCrossProcessMountVerdict`」作代理 —— 那是 385 片2a 的
|
|
51
|
-
* mailbox 面,与 auto 武装**语义无关**,只是恰好同一个 dist;core 若把 [ref] 单独发一个补丁版,代理就答错):
|
|
52
|
-
*
|
|
53
|
-
* · **主判(语义精确)= [ref] 自己的座**:武装点 `dist/core/runner/prepare-task.js` 里是否出现 `autoModeRequested`。
|
|
54
|
-
* 亲验(2026-09-03,`git grep autoModeRequested` 两 ref 对拍):v7.2.0 全树**零**处提及,854b202b 起 prepare-task
|
|
55
|
-
* 有 8 处 —— 单调、且探的就是「武装点读不读意图座」这件事本身。dist 未 mangle(属性名从不被 tsc/esbuild 改名),
|
|
56
|
-
* d.ts 不参与判断(类型面运行期探不到,读 js 才是「引擎真这么跑」)。
|
|
57
|
-
* · **佐证(只在主判为 false 时读)= 同批到货的运行时导出** `mailboxCrossProcessMountVerdict`(包内随发的
|
|
58
|
-
* `node_modules/@sema-agent/core/test/export-surface.snapshot.json`(core 包内随发),core `files` 字段含它 —— 消费账本门 A 的同一真源)。
|
|
59
|
-
* - 座缺席 ∧ 标记缺席 ⇒ 就是 npm 7.2.0 那一档 ⇒ `false`(旧式臂,兼容形);
|
|
60
|
-
* - 座缺席 ∧ 标记**在场** ⇒ **矛盾**:dist 已是 854b202b 之后,而武装点不再提这个座名(core 重构/换文件)
|
|
61
|
-
* ⇒ 判据失效,**抛**(不猜。静默回落旧式臂正是「854 之后的部署悄悄退回 org 授予极性」那一形)。
|
|
62
|
-
* - 座在场 ⇒ `true`,不看佐证([ref] 单发的补丁版合法)。
|
|
63
|
-
*
|
|
64
|
-
* 🔴 不用 `import * as core`(消费账本门禁命名空间导入:每个消费名必须可按名对账);两个文件都经主入口 resolve
|
|
65
|
-
* 定位(package `exports` 映射不暴露这些子路径)。**任何读不到 = 抛**,由 boot 装配点承接成拒启(见
|
|
66
|
-
* {@link coreArmsAutoOnIntent})。
|
|
67
|
-
*
|
|
68
|
-
* @param distDir 测试注入的假 `dist/` 根;生产不传(从安装的 core 主入口解)。
|
|
69
|
-
*/
|
|
70
|
-
export declare function coreArmsAutoOnIntentProbe(distDir?: string): boolean;
|
|
71
|
-
/**
|
|
72
|
-
* {@link coreArmsAutoOnIntentProbe} 的**惰性记忆化**访问器 —— 生产装配点(`main.ts` 的 `autoModeFace` 组装,
|
|
73
|
-
* 早于 `server.listen`)调一次,探针抛就是**boot 期响亮拒启**并带指路。
|
|
74
|
-
*
|
|
75
|
-
* 🔴 为什么必须惰性([ref]):此前是模块顶层 `const … = coreArmsAutoOnIntentProbe()`,而 `main.ts` 顶部 import 本模块
|
|
76
|
-
* ⇒ 探针在 **import 期**求值,读不到快照就在任何日志器/诊断存在之前把整台 server 抛死(一个 npm 安装瑕疵 =
|
|
77
|
-
* 一台起不来且没有遗言的机器)。惰性之后,同一条失败落在 boot 装配点,遗言完整、退出码照旧。
|
|
78
|
-
*/
|
|
79
|
-
export declare function coreArmsAutoOnIntent(): boolean;
|
|
80
|
-
/** 装配面交给读面的四件事实(`main.ts` 从 runnerDeps / 合成后的 caps resolver / 到货位取,读面不自算)。 */
|
|
91
|
+
/** 装配面交给读面的三件事实(`main.ts` 从 runnerDeps / 合成后的 caps resolver 取,读面不自算)。
|
|
92
|
+
* S-877:第四件「引擎半场到货位」(`engineArmsOnIntent`,安装包探针)随极性探针一起退役。 */
|
|
81
93
|
export interface AutoModeFaceDeps {
|
|
82
94
|
/** `RunnerDeps.autoMode !== undefined`——**读**装配点那一位,不写字面 true(与 parked-revive 的
|
|
83
95
|
* `autoModeSeatMounted` 同一纪律:席位哪天改成有条件挂载,这里不能静默错供)。 */
|
|
84
96
|
readonly seatMounted: boolean;
|
|
85
|
-
/** {@link coreArmsAutoOnIntent}(生产装配递探针访问器;测试可递 true 走正控)。false ⇒ `deployment_incapable`。 */
|
|
86
|
-
readonly engineArmsOnIntent: boolean;
|
|
87
97
|
/** 合成后的 per-principal caps resolver(= 递给 `RunnerDeps.runtimeCapsResolver` 的同一只:center 客户端
|
|
88
98
|
* → observer env 基线 → memory grant → 本地 auto deny,单一属主 boot/runtime-caps.ts)。缺席 = 无任何
|
|
89
99
|
* per-principal 源(无 center、无本地 deny)⇒ caps undefined ⇒ 三态之「缺席=不阻」。 */
|
|
@@ -115,7 +125,6 @@ export type AutoModeVerdict = {
|
|
|
115
125
|
export declare function judgeAutoModeArming(face: AutoModeFaceDeps | undefined, input: {
|
|
116
126
|
readonly requestedMode: SettingsPermissionMode | undefined;
|
|
117
127
|
readonly principal: string | undefined;
|
|
118
|
-
readonly entitlementSource: boolean;
|
|
119
128
|
/** 本地 `PERMISSIONS_DISABLE_AUTO_MODE`(= catalog/settings 键 `permissions.disableAutoMode`)是否置 true —— caps false 时分词
|
|
120
129
|
* `local_denied` / `org_denied`(seam ⑤;两者对壳的指路不同:改本机 env vs 找组织)。 */
|
|
121
130
|
readonly localDeny: boolean;
|
package/dist/auto-mode-face.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { z } from "zod";
|
|
5
1
|
import { classifierSeatModel } from "@sema-agent/core";
|
|
6
2
|
import { resolveMainModel } from "./model-select.js";
|
|
7
3
|
export function classifierRouteFor(deps) {
|
|
@@ -15,65 +11,17 @@ export function classifierRouteFor(deps) {
|
|
|
15
11
|
}
|
|
16
12
|
export const AUTO_MODE_UNARMED_REASONS = ["mode_not_auto", "deployment_incapable", "org_denied", "local_denied", "settings_denied", "resolver_fault"];
|
|
17
13
|
export const AUTO_MODE_UNARMED_REASON_SEMANTICS = {
|
|
18
|
-
mode_not_auto: "本次意图不是 auto(壳发的 permissionMode 不是 \"auto\"
|
|
19
|
-
deployment_incapable: "装配面没挂 RunnerDeps.autoMode 分类器席位(本部署/本进程形不具备分类器)
|
|
20
|
-
org_denied: "per-principal caps.autoMode === false 且本地 deny 未设:center 显式 deny / center 硬失败 fail-closed
|
|
14
|
+
mode_not_auto: "本次意图不是 auto(壳发的 permissionMode 不是 \"auto\")",
|
|
15
|
+
deployment_incapable: "装配面没挂 RunnerDeps.autoMode 分类器席位(本部署/本进程形不具备分类器)",
|
|
16
|
+
org_denied: "per-principal caps.autoMode === false 且本地 deny 未设:center 显式 deny / center 硬失败 fail-closed 拒项",
|
|
21
17
|
local_denied: "本地 catalog 键 PERMISSIONS_DISABLE_AUTO_MODE=true(center/settings 键名 permissions.disableAutoMode)把 caps.autoMode 折成 false",
|
|
22
18
|
settings_denied: "settings 层 permissions.disableAutoMode 取 disable 或 true(两套已发布拼写同义;用户/managed 层 kill-switch)把本 run 折成非 auto —— capabilities 查询串不带 settings,本词由 run 级面产([6128] PM 裁定第六员)",
|
|
23
19
|
resolver_fault: "per-principal caps resolver 抛错/答非记录(core 同形全拒:autoMode:false + onError phase config)",
|
|
24
20
|
};
|
|
25
|
-
function armingProbeFailure(what) {
|
|
26
|
-
return new Error(`auto-mode arming probe cannot decide (${what}). This probe answers ONE question — does the INSTALLED @sema-agent/core arm ` +
|
|
27
|
-
`auto mode from the task's INTENT seat (core #521: spec.autoModeRequested ∧ seat ∧ caps !== false), or from the older ` +
|
|
28
|
-
`"org grants it" polarity (runtimeCaps.autoMode === true ∧ seat)? The two polarities are OPPOSITE on the permission axis, ` +
|
|
29
|
-
`so guessing would silently put this deployment on the wrong one — either arming runs the org never granted, or reporting ` +
|
|
30
|
-
`"not armed" at /v1/capabilities while the engine really is arming (#157: no silent fail-open on the permission axis). ` +
|
|
31
|
-
`Refusing to start instead. Fix: reinstall the engine (rm -rf node_modules && npm ci) so the package ships its full dist, ` +
|
|
32
|
-
`or — if core moved/renamed the arming site — update the probe in src/auto-mode-face.ts to read the new one.`);
|
|
33
|
-
}
|
|
34
|
-
export function coreArmsAutoOnIntentProbe(distDir) {
|
|
35
|
-
const dist = distDir ?? dirname(createRequire(import.meta.url).resolve("@sema-agent/core"));
|
|
36
|
-
const armingSite = join(dist, "core", "runner", "prepare-task.js");
|
|
37
|
-
let armingSrc;
|
|
38
|
-
try {
|
|
39
|
-
armingSrc = readFileSync(armingSite, "utf8");
|
|
40
|
-
}
|
|
41
|
-
catch (err) {
|
|
42
|
-
throw armingProbeFailure(`the engine's arming site is unreadable at ${armingSite}: ${err instanceof Error ? err.message : String(err)}`);
|
|
43
|
-
}
|
|
44
|
-
if (armingSrc.includes(CORE_AUTO_MODE_INTENT_SEAT))
|
|
45
|
-
return true;
|
|
46
|
-
const snapPath = join(dist, "..", "test", "export-surface.snapshot.json");
|
|
47
|
-
let snap;
|
|
48
|
-
try {
|
|
49
|
-
const parsed = ExportSurfaceSnapshotSchema.safeParse(JSON.parse(readFileSync(snapPath, "utf8")));
|
|
50
|
-
if (!parsed.success)
|
|
51
|
-
throw new Error(`export-surface snapshot shape mismatch: ${parsed.error.issues.map((i) => i.path.join(".") + ":" + i.message).join("; ")}`);
|
|
52
|
-
snap = parsed.data;
|
|
53
|
-
}
|
|
54
|
-
catch (err) {
|
|
55
|
-
throw armingProbeFailure(`the arming seat is absent from ${armingSite} and the corroborating export-surface snapshot is unreadable at ${snapPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
56
|
-
}
|
|
57
|
-
if (!snap.exports || typeof snap.exports !== "object")
|
|
58
|
-
throw armingProbeFailure(`core export-surface snapshot malformed at ${snapPath}`);
|
|
59
|
-
if (typeof snap.exports.mailboxCrossProcessMountVerdict === "string") {
|
|
60
|
-
throw armingProbeFailure(`contradiction — the installed core's export surface is at/after the batch that shipped #521, but its arming site ` +
|
|
61
|
-
`(${armingSite}) never names \`${CORE_AUTO_MODE_INTENT_SEAT}\`, so the engine either moved the arming site or renamed the seat`);
|
|
62
|
-
}
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
const CORE_AUTO_MODE_INTENT_SEAT = "autoModeRequested";
|
|
66
|
-
let armsOnIntentMemo;
|
|
67
|
-
const ExportSurfaceSnapshotSchema = z.object({ exports: z.record(z.string(), z.string()).optional() }).passthrough();
|
|
68
|
-
export function coreArmsAutoOnIntent() {
|
|
69
|
-
if (armsOnIntentMemo === undefined)
|
|
70
|
-
armsOnIntentMemo = coreArmsAutoOnIntentProbe();
|
|
71
|
-
return armsOnIntentMemo;
|
|
72
|
-
}
|
|
73
21
|
export async function judgeAutoModeArming(face, input) {
|
|
74
22
|
const route = face?.seatMounted ? face.classifierModel?.() : undefined;
|
|
75
23
|
const model = route !== undefined ? { model: route } : {};
|
|
76
|
-
if (
|
|
24
|
+
if (input.requestedMode !== undefined && input.requestedMode !== "auto")
|
|
77
25
|
return { armed: false, reason: "mode_not_auto", ...model };
|
|
78
26
|
if (face === undefined || !face.seatMounted)
|
|
79
27
|
return { armed: false, reason: "deployment_incapable" };
|
|
@@ -84,18 +32,8 @@ export async function judgeAutoModeArming(face, input) {
|
|
|
84
32
|
catch (err) {
|
|
85
33
|
return { armed: false, reason: "resolver_fault", ...model, fault: err instanceof Error ? err.message : String(err) };
|
|
86
34
|
}
|
|
87
|
-
const deniedWord = input.localDeny ? "local_denied" : "org_denied";
|
|
88
|
-
if (face.engineArmsOnIntent) {
|
|
89
|
-
if (caps?.autoMode === false)
|
|
90
|
-
return { armed: false, reason: deniedWord, ...model };
|
|
91
|
-
return { armed: true, ...model };
|
|
92
|
-
}
|
|
93
|
-
if (caps?.autoMode === true)
|
|
94
|
-
return { armed: true, ...model };
|
|
95
35
|
if (caps?.autoMode === false)
|
|
96
|
-
return { armed: false, reason:
|
|
97
|
-
|
|
98
|
-
return { armed: false, reason: "deployment_incapable", ...model };
|
|
99
|
-
return { armed: false, reason: "org_denied", ...model };
|
|
36
|
+
return { armed: false, reason: input.localDeny ? "local_denied" : "org_denied", ...model };
|
|
37
|
+
return { armed: true, ...model };
|
|
100
38
|
}
|
|
101
39
|
//# sourceMappingURL=auto-mode-face.js.map
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
* `infraFailed` (EXCLUDED) — NEVER a fabricated uniform delivered=false loss for the whole TEAM column.
|
|
36
36
|
*/
|
|
37
37
|
import { type TaskSpec } from "@sema-agent/core";
|
|
38
|
+
import { type UnattendedLeg } from "../../unattended-permission-mode.js";
|
|
38
39
|
import type { ProfileDeps, SoloImplSpec, SupImplSpec } from "./arms.js";
|
|
39
40
|
import type { TrapSpec } from "./tasks.js";
|
|
40
41
|
/** Live runtime config — the SAME base model + budget every arm runs on (the §3.2 fairness root). */
|
|
@@ -92,8 +93,14 @@ export declare function buildLiveDeps(rt: LiveRuntimeConfig, trap: TrapSpec, see
|
|
|
92
93
|
/** The per-cell base TaskSpec every arm's leaf projects from. EXPORTED so the shape test measures the REAL spec
|
|
93
94
|
* handed to the runner (the BUDGET-MATCH anchor is spec.limits, not the harness's own RowBudget echo). */
|
|
94
95
|
export declare function benchBaseSpec(rt: LiveRuntimeConfig, cellId: string): (objective: string) => TaskSpec;
|
|
95
|
-
/**
|
|
96
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Project a `SoloImplSpec` (budget already stamped by the harness, all keys in `limits`) onto the bench base TaskSpec.
|
|
98
|
+
* 🔴 7.106.0 合并复审 X3:SOLO 是**无人值守腿**(verify→fix 跑在一只不接 `onAsk` 的 Runner 上,没有审批席)⇒ 经 `withUnattendedLeg` 接
|
|
99
|
+
* 与 TEAM 的 leader worker 同一条腿(模式 = `UNATTENDED_PERMISSION_MODE`、写面 roots、写保护拒层)。修前裸 spec ⇒ core 7.34.0「缺席 =
|
|
100
|
+
* default」让写与非只读命令 headless 拒、终态照旧 completed —— SOLO 与 TEAM 的比较混进了权限差异。SUP 不走这里:它有耐久审批席
|
|
101
|
+
* (checkpoint suspend),它的问要人答,bypass 会把 SUP 的门放掉。
|
|
102
|
+
*/
|
|
103
|
+
export declare function toTaskSpec(base: (objective: string) => TaskSpec, impl: SoloImplSpec, leg: UnattendedLeg): TaskSpec;
|
|
97
104
|
/** Project a `SupImplSpec` onto the bench base TaskSpec PLUS the durable wiring (checkpointStore + ask policy). */
|
|
98
105
|
export declare function toSupTaskSpec(base: (objective: string) => TaskSpec, impl: SupImplSpec, trap: TrapSpec): TaskSpec;
|
|
99
106
|
//# sourceMappingURL=live-deps.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { outwardPlane } from "../../terminal.js";
|
|
2
2
|
import { Runner, runWithVerification, resumeWithVerification, runRepairLoop, combinePolicies, createDurableQuestionPolicy, QUESTION_AWAITS_RESUME, } from "@sema-agent/core";
|
|
3
3
|
import { loadConfig } from "../../config.js";
|
|
4
|
+
import { createUnattendedLeg, unattendedPermissionMode, withUnattendedLeg } from "../../unattended-permission-mode.js";
|
|
4
5
|
import { createBrain } from "../../brain.js";
|
|
5
6
|
import { buildPricing } from "../../budget.js";
|
|
6
7
|
import { RemoteContainerExecutionEnv } from "../../plugins/remote-env-e2b.js";
|
|
@@ -57,7 +58,7 @@ function buildBrainIngredients(rt) {
|
|
|
57
58
|
if (!p || ((p.inputPer1M ?? 0) === 0 && (p.outputPer1M ?? 0) === 0)) {
|
|
58
59
|
throw new Error(`s1 live: zero pricing for ${rt.modelId} — C1 cost axis would be a fabricated $0 (set MODEL_COST_INPUT/OUTPUT)`);
|
|
59
60
|
}
|
|
60
|
-
return { brain, models: config.models, roles: config.roles, pricing };
|
|
61
|
+
return { brain, models: config.models, roles: config.roles, pricing, unattendedPermissionMode: unattendedPermissionMode(config) };
|
|
61
62
|
}
|
|
62
63
|
const sh = (env) => async (cmd) => {
|
|
63
64
|
const r = await env.exec(`bash -lc ${JSON.stringify(cmd)}`);
|
|
@@ -167,8 +168,9 @@ function graderTransport(grader) {
|
|
|
167
168
|
};
|
|
168
169
|
}
|
|
169
170
|
export function buildLiveDeps(rt, trap, seed, cellId) {
|
|
170
|
-
const { brain, models, roles, pricing } = buildBrainIngredients(rt);
|
|
171
|
+
const { brain, models, roles, pricing, unattendedPermissionMode: leaderMode } = buildBrainIngredients(rt);
|
|
171
172
|
const baseSpec = benchBaseSpec(rt, cellId);
|
|
173
|
+
const soloLeg = createUnattendedLeg(leaderMode, {});
|
|
172
174
|
const state = {};
|
|
173
175
|
const ensureWorker = async () => {
|
|
174
176
|
if (!state.worker) {
|
|
@@ -206,7 +208,7 @@ export function buildLiveDeps(rt, trap, seed, cellId) {
|
|
|
206
208
|
const deps = {
|
|
207
209
|
runWithVerification: async (implSpec) => {
|
|
208
210
|
const { runner } = await ensureWorker();
|
|
209
|
-
return runWithVerification(runner, toTaskSpec(baseSpec, implSpec), { maxRounds: rt.maxRounds ?? 2 });
|
|
211
|
+
return runWithVerification(runner, toTaskSpec(baseSpec, implSpec, soloLeg), { maxRounds: rt.maxRounds ?? 2 });
|
|
210
212
|
},
|
|
211
213
|
runWithVerificationSup: async (implSpec) => {
|
|
212
214
|
const { runner } = await ensureWorker();
|
|
@@ -282,7 +284,7 @@ export function buildLiveDeps(rt, trap, seed, cellId) {
|
|
|
282
284
|
rmSync(tmp, { recursive: true, force: true });
|
|
283
285
|
}
|
|
284
286
|
};
|
|
285
|
-
return runLeaderForTrap(rt, brain, models, roles, pricing, trap, cellId, captureIntegratedTreeToBundle);
|
|
287
|
+
return runLeaderForTrap(rt, brain, models, roles, pricing, leaderMode, trap, cellId, captureIntegratedTreeToBundle);
|
|
286
288
|
},
|
|
287
289
|
runOracle: () => runOracle(false),
|
|
288
290
|
};
|
|
@@ -298,21 +300,24 @@ export function benchBaseSpec(rt, cellId) {
|
|
|
298
300
|
limits: { maxTokens: rt.maxTokens ?? 8000, maxCostUsd: rt.maxCostUsd ?? 1.0, maxTurns: rt.maxTurns ?? 12 },
|
|
299
301
|
});
|
|
300
302
|
}
|
|
301
|
-
|
|
303
|
+
function projectImplBudget(base, impl) {
|
|
302
304
|
return { ...base(impl.objective), limits: { ...impl.limits } };
|
|
303
305
|
}
|
|
306
|
+
export function toTaskSpec(base, impl, leg) {
|
|
307
|
+
return withUnattendedLeg(projectImplBudget(base, impl), leg);
|
|
308
|
+
}
|
|
304
309
|
export function toSupTaskSpec(base, impl, trap) {
|
|
305
310
|
const requireApproval = trap.gatedTools ?? ["Bash"];
|
|
306
311
|
const neverAuto = trap.neverAuto ?? [];
|
|
307
312
|
return {
|
|
308
|
-
...
|
|
313
|
+
...projectImplBudget(base, impl),
|
|
309
314
|
checkpointStore: impl.checkpointStore,
|
|
310
315
|
durableApproval: { scope: impl.durableApprovalScope },
|
|
311
316
|
toolPolicy: combinePolicies(createDurableQuestionPolicy(), createDurableAskPolicy({ requireApproval, ...(neverAuto.length > 0 ? { neverAuto } : {}) })),
|
|
312
317
|
onQuestion: QUESTION_AWAITS_RESUME,
|
|
313
318
|
};
|
|
314
319
|
}
|
|
315
|
-
async function runLeaderForTrap(rt, brain, models, roles, pricing, trap, cellId, importIntegratedTreeToWorker) {
|
|
320
|
+
async function runLeaderForTrap(rt, brain, models, roles, pricing, leaderMode, trap, cellId, importIntegratedTreeToWorker) {
|
|
316
321
|
const { mkdtempSync, rmSync, writeFileSync, mkdirSync } = await import("node:fs");
|
|
317
322
|
const { execFileSync, spawn } = await import("node:child_process");
|
|
318
323
|
const { tmpdir } = await import("node:os");
|
|
@@ -365,7 +370,7 @@ async function runLeaderForTrap(rt, brain, models, roles, pricing, trap, cellId,
|
|
|
365
370
|
process.env.LEADER_ENABLED = "true";
|
|
366
371
|
process.env.LEADER_WORKER_BUDGET_USD = String((rt.maxCostUsd ?? 1.0) / 2);
|
|
367
372
|
const run = createLeaderRunner({
|
|
368
|
-
brain, models, roles, pricing, e2bApiKey: rt.e2bApiKey, workspace: W,
|
|
373
|
+
brain, models, roles, pricing, unattendedPermissionMode: leaderMode, e2bApiKey: rt.e2bApiKey, workspace: W,
|
|
369
374
|
...(s1DebugGit() ? { logger: { warn: (m, x) => console.error(`[S1_DEBUG_LEADER warn] ${m}`, x ? JSON.stringify(x).slice(0, 300) : ""), info: (m, x) => console.error(`[S1_DEBUG_LEADER info] ${m}`, x ? JSON.stringify(x).slice(0, 200) : "") } } : {}),
|
|
370
375
|
});
|
|
371
376
|
const teamSeedWrite = (trap.seedFiles ?? [])
|
|
@@ -2,6 +2,7 @@ import { createBrain, createDegradeRouteWatch } from "../brain.js";
|
|
|
2
2
|
import { ModelUsageTracker, PromptManifestTracker, buildPricing, createSideQueryAccountant, createTracer } from "../budget.js";
|
|
3
3
|
import { FleetUsageAccumulator } from "../fleet-client.js";
|
|
4
4
|
import { createFleetLeaseFromEnv } from "../fleet-lease.js";
|
|
5
|
+
import { centerLaneConfigured } from "../config-center/center-request.js";
|
|
5
6
|
import { CostQuota } from "../observability/cost-quota.js";
|
|
6
7
|
import { buildQuotaBounds } from "./limit-sync.js";
|
|
7
8
|
import { assembleFileHistory } from "../file-history-capture.js";
|
|
@@ -25,12 +26,12 @@ export function createBudgetAndTracing(ctx) {
|
|
|
25
26
|
: new CostQuota(bounds.limitMicroUsd, bounds.windowMs);
|
|
26
27
|
const modelUsageTracker = new ModelUsageTracker();
|
|
27
28
|
const promptManifestTracker = new PromptManifestTracker();
|
|
28
|
-
const fleetUsage = config
|
|
29
|
+
const fleetUsage = centerLaneConfigured(config) ? new FleetUsageAccumulator() : undefined;
|
|
29
30
|
const fleetLease = createFleetLeaseFromEnv(config, { logger, metrics });
|
|
30
31
|
const tracer = createTracer(metrics, costQuota, modelUsageTracker, fleetUsage, fleetLease, (m) => config.modelQuotaWeights[m] ?? 1, promptManifestTracker);
|
|
31
32
|
const sideQueryAccounting = createSideQueryAccountant(metrics, costQuota, fleetUsage, fleetLease, (m) => config.modelQuotaWeights[m] ?? 1);
|
|
32
33
|
const toolResultStore = backend?.toolResult ? backend.toolResult() : undefined;
|
|
33
|
-
const sessionPolicyStore = backend ? backend.sessionPolicy() : undefined;
|
|
34
|
+
const sessionPolicyStore = backend ? backend.sessionPolicy(logger) : undefined;
|
|
34
35
|
const { store: fileHistoryStore, erasure: fileHistoryErasure } = assembleFileHistory(backend);
|
|
35
36
|
return {
|
|
36
37
|
brain, degradeRouteWatch, pricing, counterDegradeHook, costQuota, modelUsageTracker, promptManifestTracker,
|