@sema-agent/server 7.117.0 → 7.119.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 +182 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +58 -28
- package/deploy/sema-up/README.md +2 -0
- package/deploy/sema-up/chart/templates/minio.yaml +2 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +1 -0
- package/deploy/sema-up/chart/templates/server.yaml +1 -0
- package/deploy/sema-up/chart/values.yaml +7 -1
- package/deploy/sema-up/cluster-up.sh +20 -8
- package/deploy/sema-up/kube-up.sh +29 -16
- package/deploy/sema-up/lib/buckets.sh +21 -0
- package/deploy/sema-up/lib/health.sh +33 -0
- package/deploy/sema-up/sema-up.sh +14 -9
- package/deploy/sema-up/smoke.sh +16 -6
- package/deploy/sema-up/stack/compose.yaml +1 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -1
- package/dist/approval-ask-audit-store.js +2 -7
- package/dist/approval-card.d.ts +40 -10
- package/dist/approval-card.js +11 -1
- package/dist/approval.d.ts +55 -17
- package/dist/approval.js +74 -33
- package/dist/audit.d.ts +12 -1
- package/dist/audit.js +62 -2
- package/dist/auto-mode-face.d.ts +2 -3
- package/dist/bake-runner/main.js +1 -6
- package/dist/bake-runner/protocol.d.ts +18 -0
- package/dist/bake-runner/protocol.js +22 -2
- package/dist/bake-runner/runner.d.ts +12 -8
- package/dist/bake-runner/runner.js +5 -9
- package/dist/boot/config-center.js +1 -1
- package/dist/boot/coordinators.js +4 -1
- package/dist/boot/device-lane.d.ts +3 -3
- package/dist/boot/device-lane.js +1 -2
- package/dist/boot/leader.d.ts +4 -4
- package/dist/boot/leader.js +1 -2
- package/dist/boot/parked-revive-gate.d.ts +4 -6
- package/dist/boot/parked-revive-gate.js +2 -6
- package/dist/boot/resolve-spec.js +9 -11
- package/dist/boot/runner-deps.js +2 -2
- package/dist/boot/stage-07-capability-layer.js +7 -3
- package/dist/boot/stage-10-http-server.js +3 -2
- package/dist/boot/stores.js +12 -7
- package/dist/capabilities/center-plugins.d.ts +2 -0
- package/dist/capabilities/center-plugins.js +24 -6
- package/dist/capabilities/code-review-council.js +8 -11
- package/dist/capabilities/hands-lane.d.ts +25 -0
- package/dist/capabilities/hands-lane.js +1 -1
- package/dist/capabilities/mcp-probe.d.ts +2 -2
- package/dist/capabilities/scenarios.d.ts +34 -7
- package/dist/capabilities/scenarios.js +33 -6
- package/dist/config-catalog.js +3 -3
- package/dist/config.d.ts +14 -18
- package/dist/config.js +15 -26
- package/dist/deployment-governance.d.ts +5 -7
- package/dist/deployment-governance.js +4 -5
- package/dist/host-decision.d.ts +114 -31
- package/dist/host-decision.js +39 -2
- package/dist/http/admission.js +12 -6
- package/dist/http/approval-sweeps.js +1 -1
- package/dist/http/mcp-dial-deadline.d.ts +35 -0
- package/dist/http/mcp-dial-deadline.js +21 -0
- package/dist/http/memory-compliance-failure-reply.d.ts +11 -5
- package/dist/http/memory-compliance-failure-reply.js +17 -8
- package/dist/http/memory-store-refusal-reply.d.ts +14 -11
- package/dist/http/memory-store-refusal-reply.js +16 -5
- package/dist/http/resume-legs.js +8 -3
- package/dist/http/routes/approvals-assistant.d.ts +25 -3
- package/dist/http/routes/approvals-assistant.js +27 -26
- package/dist/http/routes/capabilities.js +6 -3
- package/dist/http/routes/mcp-reconnect.d.ts +17 -0
- package/dist/http/routes/mcp-reconnect.js +6 -1
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/runs.js +47 -33
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +23 -22
- package/dist/http/routes/workflows.js +2 -0
- package/dist/http/wire-types.d.ts +17 -13
- package/dist/images/manifest.d.ts +7 -1
- package/dist/images/manifest.js +18 -16
- package/dist/memory-store-refusal.d.ts +38 -18
- package/dist/memory-store-refusal.js +25 -7
- package/dist/model-unreachable-notice.d.ts +1 -1
- package/dist/namespaced-rule-name.d.ts +46 -41
- package/dist/namespaced-rule-name.js +36 -22
- package/dist/observability/corrupt-read-seat.d.ts +4 -0
- package/dist/observability/corrupt-read-seat.js +1 -0
- package/dist/observability/fail-open.d.ts +19 -3
- package/dist/observability/fail-open.js +19 -3
- package/dist/operator-ask.d.ts +6 -2
- package/dist/orchestration/workflow-agent-session-index.d.ts +82 -59
- package/dist/orchestration/workflow-agent-session-index.js +80 -14
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -0
- package/dist/orchestration/workflow-completion-inbox.js +39 -17
- package/dist/orchestration/workflow-notify-journal.d.ts +1 -1
- package/dist/orchestration/workflow-notify-journal.js +7 -2
- package/dist/outbound-dispatcher.d.ts +29 -20
- package/dist/outbound-dispatcher.js +105 -16
- package/dist/parked-decide.d.ts +43 -48
- package/dist/parked-decide.js +54 -16
- package/dist/permission-rule-vocab.d.ts +4 -3
- package/dist/permission-rule-vocab.js +1 -1
- package/dist/plugins/approval-ask-store-sql.d.ts +17 -20
- package/dist/plugins/approval-ask-store-sql.js +0 -3
- package/dist/plugins/approval-exemption-store.d.ts +4 -0
- package/dist/plugins/approval-exemption-store.js +1 -0
- package/dist/plugins/blob-backend.d.ts +13 -0
- package/dist/plugins/blob-backend.js +26 -0
- package/dist/plugins/local-session-store.d.ts +78 -47
- package/dist/plugins/local-session-store.js +152 -122
- package/dist/plugins/one-time-migrations.d.ts +11 -0
- package/dist/plugins/one-time-migrations.js +128 -4
- package/dist/plugins/pg-pool.js +1 -1
- package/dist/plugins/snapshot-bucket-presence.d.ts +36 -0
- package/dist/plugins/snapshot-bucket-presence.js +40 -0
- package/dist/plugins/store-backend.d.ts +17 -6
- package/dist/plugins/store-backend.js +46 -16
- package/dist/plugins/store-open-wait.d.ts +33 -0
- package/dist/plugins/store-open-wait.js +73 -0
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/plugins/web-search.d.ts +20 -1
- package/dist/plugins/web-search.js +39 -10
- package/dist/plugins/workflow-run-store-sql.d.ts +7 -6
- package/dist/plugins/workflow-run-store-sql.js +5 -7
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +1 -1
- package/dist/rule-entry-list.d.ts +35 -46
- package/dist/rule-entry-list.js +18 -26
- package/dist/rules-consent.js +3 -0
- package/dist/run-local.js +5 -3
- package/dist/runs.d.ts +1 -1
- package/dist/security.d.ts +5 -3
- package/dist/security.js +4 -0
- package/dist/session-policy-wire.d.ts +13 -12
- package/dist/session-policy-wire.js +11 -11
- package/dist/spec-fields.d.ts +13 -11
- package/dist/spec-fields.js +4 -7
- package/dist/standing-answer-grant.d.ts +14 -2
- package/dist/standing-answer-grant.js +8 -1
- package/dist/store-posture.d.ts +14 -6
- package/dist/store-posture.js +7 -4
- package/dist/task-settings.d.ts +27 -55
- package/dist/task-settings.js +13 -21
- package/dist/tool-approval.d.ts +133 -138
- package/dist/tool-approval.js +175 -66
- package/dist/trace/core-keyset-guard.d.ts +5 -5
- package/dist/trace/redact.d.ts +6 -0
- package/dist/trace/redact.js +9 -9
- package/dist/trace/self-minted-wire.d.ts +16 -2
- package/dist/trace/self-minted-wire.js +7 -0
- package/dist/user-input-ledger.d.ts +30 -14
- package/dist/user-input-ledger.js +25 -14
- package/package.json +2 -2
- package/scripts/drain-check-local.mjs +74 -3
- package/scripts/drain-check.mysql.sql +43 -17
- package/scripts/drain-check.pg.sql +46 -20
|
@@ -31,6 +31,10 @@ unset _self _hops _dir
|
|
|
31
31
|
. "$HERE/lib/shell-access.sh"
|
|
32
32
|
# 取值旗的形(S-621):判据与词表同 sema-up.sh 一处定义。
|
|
33
33
|
. "$HERE/lib/flagshape.sh"
|
|
34
|
+
# 引擎 /health 体里「落在哪个后端」的读法与期望值(smoke.sh / kube-up.sh 同一只)。
|
|
35
|
+
. "$HERE/lib/health.sh"
|
|
36
|
+
# 对象存储桶的唯一表(sema-up.sh / kube-up.sh / smoke.sh 同读这一张)。
|
|
37
|
+
. "$HERE/lib/buckets.sh"
|
|
34
38
|
log() { printf '[cluster-up] %s\n' "$*" >&2; }
|
|
35
39
|
die() { log "⛔ $*"; exit 1; }
|
|
36
40
|
|
|
@@ -419,8 +423,9 @@ PY
|
|
|
419
423
|
# 凭据清单经 stdin 直接 apply,不落远端盘(落 /tmp 失败时会残留)
|
|
420
424
|
rrun 0 k3s kubectl apply -f - < "$RENDERED" >/dev/null
|
|
421
425
|
fi
|
|
422
|
-
rsudo 0 <<'EOF'
|
|
426
|
+
rsudo 0 $(buckets_prefixed local/ $(buckets_k8s)) <<'EOF'
|
|
423
427
|
set -e
|
|
428
|
+
BUCKETS=("$@") # 要建的桶(local/<桶>):清单只在 lib/buckets.sh 一处,经位置参数递给远端
|
|
424
429
|
# runner token 跨 ns 复制要赶在 server 起 pod 前(晚了=CreateContainerConfigError 干等——真踩);
|
|
425
430
|
# SA token secret 由控制器异步填充,先等它有值
|
|
426
431
|
TOK=""
|
|
@@ -431,6 +436,12 @@ done
|
|
|
431
436
|
[ -n "$TOK" ] || { echo "sema-runner-token 未被控制器填充" >&2; exit 1; }
|
|
432
437
|
k3s kubectl create secret generic sema-runner-token-copy -n sema --from-literal=token="$(printf '%s' "$TOK" | base64 -d)" \
|
|
433
438
|
--dry-run=client -o yaml | k3s kubectl apply -f - >/dev/null
|
|
439
|
+
# MinIO 建桶(备份桶+引擎桶)—— 排在等 PG healthy 与等 server rollout **之前**:引擎起服会核快照桶在不在,桶缺时 server 不就绪、rollout 永远等不到,而建桶又排在它后面 ⇒ 互等;
|
|
440
|
+
# MinIO 不依赖 PG,建桶也就不必陪着等 PG(冷启拉镜像 + init 可要几分钟,会把引擎的等桶窗耗掉)
|
|
441
|
+
k3s kubectl rollout status deployment/sema-minio -n sema --timeout=300s >/dev/null
|
|
442
|
+
PW=$(k3s kubectl get secret sema-minio -n sema -o jsonpath='{.data.rootPassword}' | base64 -d)
|
|
443
|
+
k3s kubectl exec deploy/sema-minio -n sema -- sh -c \
|
|
444
|
+
"mc alias set local http://localhost:9000 sema '$PW' >/dev/null && mc mb --ignore-existing ${BUCKETS[*]}" >/dev/null
|
|
434
445
|
# PG healthy(冷启拉镜像+init 可要几分钟)
|
|
435
446
|
for t in $(seq 1 120); do
|
|
436
447
|
s=$(k3s kubectl get cluster sema-pg -n sema -o jsonpath='{.status.phase}' 2>/dev/null || true)
|
|
@@ -438,24 +449,25 @@ for t in $(seq 1 120); do
|
|
|
438
449
|
done
|
|
439
450
|
[ "$s" = "Cluster in healthy state" ] || { k3s kubectl get cluster -n sema; echo "PG 未达 healthy" >&2; exit 1; }
|
|
440
451
|
k3s kubectl rollout status deployment/sema-server -n sema --timeout=300s >/dev/null
|
|
441
|
-
# MinIO 建桶(备份桶+对象桶)
|
|
442
|
-
PW=$(k3s kubectl get secret sema-minio -n sema -o jsonpath='{.data.rootPassword}' | base64 -d)
|
|
443
|
-
k3s kubectl exec deploy/sema-minio -n sema -- sh -c \
|
|
444
|
-
"mc alias set local http://localhost:9000 sema '$PW' >/dev/null && mc mb --ignore-existing local/sema-pg-backup local/workspaces local/blobs" >/dev/null
|
|
445
452
|
echo STACK_OK
|
|
446
453
|
EOF
|
|
447
454
|
|
|
448
455
|
# ── 8. smoke(节点内经 NodePort;外网入口=LB 在云商侧配,打印指引)────────────────
|
|
449
456
|
log "8/8 smoke"
|
|
450
457
|
# NodePort 被 nodeport-addresses 钉在节点网段——loopback 不在其内,必须打 node-ip(真踩 curl exit 7)
|
|
451
|
-
|
|
452
|
-
|
|
458
|
+
# 第一行 = 两个 HTTP 码,其后 = /health 体(后端位在里面:200 + 401 测不出「服务在内存里跑」,验收必须读那一位)
|
|
459
|
+
SMOKE_OUT=$(rsudo 0 <<EOF
|
|
460
|
+
HB=\$(curl -m5 -s -w '\n%{http_code}' "http://$K3S0_IP:$NODEPORT/health" || printf '\n000')
|
|
461
|
+
H="\${HB##*\$'\n'}"
|
|
453
462
|
A=\$(curl -m5 -s -o /dev/null -w '%{http_code}' "http://$K3S0_IP:$NODEPORT/v1/runs" || echo 000)
|
|
454
463
|
echo "health=\$H auth=\$A"
|
|
464
|
+
printf '%s' "\${HB%\$'\n'*}"
|
|
455
465
|
EOF
|
|
456
466
|
)
|
|
467
|
+
SMOKE="${SMOKE_OUT%%$'\n'*}"
|
|
457
468
|
case "$SMOKE" in *"health=200 auth=401"*) : ;; *) die "smoke 失败:$SMOKE(期望 health=200 auth=401)" ;; esac
|
|
458
|
-
|
|
469
|
+
BK_WHY=$(health_backend_check "${SMOKE_OUT#*$'\n'}") || die "smoke 失败:$BK_WHY。下一步:kubectl -n sema logs deploy/sema-server(引擎在库没连上时不会再退内存起服 —— 它会拒启;读到 memory 多半是旧镜像)"
|
|
470
|
+
log "smoke ✓ $SMOKE backend=$SEMA_UP_EXPECT_SESSION_BACKEND"
|
|
459
471
|
cat >&2 <<EOF
|
|
460
472
|
|
|
461
473
|
══════════ cluster-up 完成($MACHINE_COUNT 节点)══════════
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# 输入(sema-up.sh 注入;也可单独跑):
|
|
10
10
|
# WORK(状态目录)PROJECT REGION KUBE_MODE [KUBECONFIG_PATH] [DRY_RUN]
|
|
11
11
|
# USERS REGISTRY_ENABLED GIT_MODE [GIT_URL GIT_TOKEN]
|
|
12
|
-
# SEMA_SERVER_IMAGE(必需)[SEMA_REGISTRY_IMAGE][GITEA_IMAGE]
|
|
12
|
+
# SEMA_SERVER_IMAGE(必需)[SEMA_REGISTRY_IMAGE][GITEA_IMAGE][MINIO_IMAGE(整条引用,换国内源用;缺省 = chart 钉死的 tag)]
|
|
13
13
|
# MODEL_GATEWAY_BASEURL MODEL_ID MODEL_API_KEY
|
|
14
14
|
# [NAMESPACE=sema][STORAGE_CLASS=集群默认][CNPG_VERSION]
|
|
15
15
|
set -euo pipefail
|
|
@@ -33,6 +33,10 @@ unset _self _hops _dir
|
|
|
33
33
|
. "$HERE/lib/shell-access.sh"
|
|
34
34
|
# 取值旗的形(S-621):判据与词表同 sema-up.sh 一处定义。
|
|
35
35
|
. "$HERE/lib/flagshape.sh"
|
|
36
|
+
# 引擎 /health 体里「落在哪个后端」的读法与期望值(smoke.sh / cluster-up.sh 同一只)。
|
|
37
|
+
. "$HERE/lib/health.sh"
|
|
38
|
+
# 对象存储桶的唯一表(sema-up.sh / cluster-up.sh / smoke.sh 同读这一张)。
|
|
39
|
+
. "$HERE/lib/buckets.sh"
|
|
36
40
|
log() { printf '[kube-up] %s\n' "$*" >&2; }
|
|
37
41
|
die() { log "⛔ $*"; exit 1; }
|
|
38
42
|
|
|
@@ -214,6 +218,7 @@ helm_values() { # helm_values <giteaBaseUrl> <oauthId> <oauthSecret>
|
|
|
214
218
|
V_REG_PW="${REGISTRY_ADMIN_PASSWORD:-}" V_REG_SS="${REGISTRY_SESSION_SECRET:-}" V_REG_PT="${REGISTRY_PULL_TOKEN:-}" \
|
|
215
219
|
V_GITEA_ENABLED="$([ "$GIT_MODE" = provision ] && echo true || echo false)" \
|
|
216
220
|
V_GITEA_IMAGE="${GITEA_IMAGE:-gitea/gitea:1.24}" V_NODE_IP="$NODE_IP" \
|
|
221
|
+
V_MINIO_IMAGE="${MINIO_IMAGE:-}" \
|
|
217
222
|
python3 - <<'PY'
|
|
218
223
|
import json, os
|
|
219
224
|
e = os.environ
|
|
@@ -244,6 +249,8 @@ v = {
|
|
|
244
249
|
"gitea": {"enabled": e["V_GITEA_ENABLED"] == "true", "image": e["V_GITEA_IMAGE"],
|
|
245
250
|
"storageClass": e["V_SC"], "domain": e["V_NODE_IP"]},
|
|
246
251
|
}
|
|
252
|
+
# MinIO 镜像:给了才递(默认只在 chart values.yaml 写一处,不在脚本里再抄一份);国内源 = 整条引用
|
|
253
|
+
if e["V_MINIO_IMAGE"]: v["minio"]["image"] = e["V_MINIO_IMAGE"]
|
|
247
254
|
print(json.dumps(v))
|
|
248
255
|
PY
|
|
249
256
|
}
|
|
@@ -317,6 +324,12 @@ done
|
|
|
317
324
|
[ -n "$TOK" ] || die "sema-runner-token 未被控制器填充。下一步:kubectl -n sema-sandbox get secret,sa"
|
|
318
325
|
printf '%s' "$TOK" | base64 -d | $KUBECTL create secret generic sema-runner-token-copy -n "$NAMESPACE" \
|
|
319
326
|
--from-file=token=/dev/stdin --dry-run=client -o yaml | $KUBECTL apply -f - >/dev/null
|
|
327
|
+
$KUBECTL rollout status deployment/sema-minio -n "$NAMESPACE" --timeout=300s >/dev/null
|
|
328
|
+
# MinIO 建桶(幂等;备份桶+引擎桶,清单只在 lib/buckets.sh 一处)。引擎起服会核快照桶在不在,所以建桶排在等 PG healthy 与等 server rollout 之前
|
|
329
|
+
# (MinIO 不依赖 PG;PG 冷启可要几分钟,不该把引擎的等桶窗耗掉)
|
|
330
|
+
$KUBECTL exec deploy/sema-minio -n "$NAMESPACE" -- sh -c \
|
|
331
|
+
"mc alias set local http://localhost:9000 sema \"\$MINIO_ROOT_PASSWORD\" >/dev/null && mc mb --ignore-existing $(buckets_prefixed local/ $(buckets_k8s))" >/dev/null \
|
|
332
|
+
|| die "MinIO 建桶失败。下一步:kubectl -n $NAMESPACE logs deploy/sema-minio"
|
|
320
333
|
# PG healthy(冷启拉镜像+init 可要几分钟)
|
|
321
334
|
s=""
|
|
322
335
|
for t in $(seq 1 120); do
|
|
@@ -324,11 +337,6 @@ for t in $(seq 1 120); do
|
|
|
324
337
|
[ "$s" = "Cluster in healthy state" ] && break; sleep 5
|
|
325
338
|
done
|
|
326
339
|
[ "$s" = "Cluster in healthy state" ] || { $KUBECTL get cluster -n "$NAMESPACE" >&2 || true; die "PG 未达 healthy。下一步:kubectl -n $NAMESPACE describe cluster sema-pg;PVC Pending 时查 StorageClass"; }
|
|
327
|
-
$KUBECTL rollout status deployment/sema-minio -n "$NAMESPACE" --timeout=300s >/dev/null
|
|
328
|
-
# MinIO 建桶(幂等;备份桶+对象桶)
|
|
329
|
-
$KUBECTL exec deploy/sema-minio -n "$NAMESPACE" -- sh -c \
|
|
330
|
-
"mc alias set local http://localhost:9000 sema \"\$MINIO_ROOT_PASSWORD\" >/dev/null && mc mb --ignore-existing local/sema-pg-backup local/workspaces local/blobs local/backups" >/dev/null \
|
|
331
|
-
|| die "MinIO 建桶失败。下一步:kubectl -n $NAMESPACE logs deploy/sema-minio"
|
|
332
340
|
$KUBECTL rollout status deployment/sema-server -n "$NAMESPACE" --timeout=600s >/dev/null || die "sema-server 未就绪。下一步:kubectl -n $NAMESPACE logs deploy/sema-server(常见:镜像拉取失败→imagePullSecrets/私仓凭据)"
|
|
333
341
|
|
|
334
342
|
# ── Gitea 引导(provision:管理员/token/OAuth app;全部 in-pod 动作,不依赖 NodePort 可达)──
|
|
@@ -379,30 +387,35 @@ fi
|
|
|
379
387
|
|
|
380
388
|
# ── smoke(port-forward 直验——kind/远程 kubeconfig 下 NodePort 对本机不可达,别靠它)──
|
|
381
389
|
log "5/6 smoke"
|
|
382
|
-
smoke_pf() { # smoke_pf <svc> <port> <path> → http code
|
|
383
|
-
local pf_pid code
|
|
390
|
+
smoke_pf() { # smoke_pf <svc> <port> <path> → 第一行 http code,其后是响应体(调用方按需取)
|
|
391
|
+
local pf_pid out code body
|
|
384
392
|
$KUBECTL port-forward "svc/$1" -n "$NAMESPACE" "1$2:$2" >/dev/null 2>&1 &
|
|
385
393
|
pf_pid=$!
|
|
386
394
|
sleep 2
|
|
387
|
-
|
|
395
|
+
out=$(curl -m5 -s -w '\n%{http_code}' "http://127.0.0.1:1$2$3" || printf '\n000')
|
|
388
396
|
kill $pf_pid 2>/dev/null; wait $pf_pid 2>/dev/null || true
|
|
389
|
-
|
|
397
|
+
code="${out##*$'\n'}"; body="${out%$'\n'*}"
|
|
398
|
+
[ "$out" = "$code" ] && body="" # 没有换行 = 只有码(假 curl / 空体)
|
|
399
|
+
printf '%s\n%s' "$code" "$body"
|
|
390
400
|
}
|
|
391
|
-
|
|
401
|
+
HR=$(smoke_pf sema-server 8090 /health)
|
|
402
|
+
H="${HR%%$'\n'*}"
|
|
392
403
|
[ "$H" = "200" ] || die "smoke 失败:server /health=$H(期望 200)。下一步:kubectl -n $NAMESPACE logs deploy/sema-server"
|
|
393
|
-
|
|
404
|
+
# /health 200 ≠ 数据落了库:后端位必须是期望的持久后端(durable(pg));读到 memory = 服务在内存里跑、重启即丢,不许判绿
|
|
405
|
+
BK_WHY=$(health_backend_check "${HR#*$'\n'}") || die "smoke 失败:$BK_WHY。下一步:kubectl -n $NAMESPACE logs deploy/sema-server(引擎在库没连上时不会再退内存起服 —— 它会拒启;读到 memory 多半是旧镜像)"
|
|
406
|
+
A=$(smoke_pf sema-server 8090 /v1/runs); A="${A%%$'\n'*}"
|
|
394
407
|
[ "$A" = "401" ] || die "smoke 失败:无 token /v1/runs=$A(期望 401=auth 门在)。SERVICE_AUTH_TOKEN 未生效=裸奔,立刻查"
|
|
395
408
|
R="n/a"
|
|
396
409
|
if [ "$REGISTRY_ENABLED" = "true" ]; then
|
|
397
|
-
R=$(smoke_pf sema-registry 3000 /api/healthz)
|
|
410
|
+
R=$(smoke_pf sema-registry 3000 /api/healthz); R="${R%%$'\n'*}"
|
|
398
411
|
[ "$R" = "200" ] || die "smoke 失败:registry healthz=$R。下一步:kubectl -n $NAMESPACE logs deploy/sema-registry"
|
|
399
412
|
fi
|
|
400
413
|
G="n/a"
|
|
401
414
|
if [ "$GIT_MODE" = "provision" ]; then
|
|
402
|
-
G=$(smoke_pf sema-gitea 3000 /api/healthz)
|
|
415
|
+
G=$(smoke_pf sema-gitea 3000 /api/healthz); G="${G%%$'\n'*}"
|
|
403
416
|
[ "$G" = "200" ] || die "smoke 失败:gitea healthz=$G"
|
|
404
417
|
fi
|
|
405
|
-
log "smoke ✓ health=$H auth=$A registry=$R gitea=$G"
|
|
418
|
+
log "smoke ✓ health=$H backend=$(health_session_backend "${HR#*$'\n'}") auth=$A registry=$R gitea=$G"
|
|
406
419
|
|
|
407
420
|
# ── summary(一屏;凭据一次性显示)────────────────────────────────────────────────
|
|
408
421
|
log "6/6 完成"
|
|
@@ -414,7 +427,7 @@ log "6/6 完成"
|
|
|
414
427
|
echo " 本机不可达 NodePort 时(kind/远程):kubectl -n $NAMESPACE port-forward svc/sema-server 8090:8090"
|
|
415
428
|
# 壳对 NodePort 的明文 http 按设计拒连(非回环要 https)⇒ 经 port-forward 带到本机回环再 connect。
|
|
416
429
|
shell_access_text "$ENVF" "装了 kubectl、能连这个集群的机器上:" "kubectl -n $NAMESPACE port-forward svc/sema-server 8090:8090" "http://127.0.0.1:8090"
|
|
417
|
-
echo " 数据 CNPG sema-pg×$PG_INSTANCES($PG_AA)+ MinIO(
|
|
430
|
+
echo " 数据 CNPG sema-pg×$PG_INSTANCES($PG_AA)+ MinIO(桶:$(buckets_k8s | tr ' ' '/'))"
|
|
418
431
|
if [ "$REGISTRY_ENABLED" = "true" ]; then
|
|
419
432
|
echo " 配置中心 NodePort 30300 → http://$NODE_IP:30300"
|
|
420
433
|
if $NEW_REG_PW; then echo " 首登:${REGISTRY_ADMIN_USER:-zhaoheran} / ${REGISTRY_ADMIN_PASSWORD}(⚠ 只显示这一次,之后看 .env)"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# lib/buckets.sh — 部署侧「要预置哪些对象存储桶」的唯一表。sema-up.sh(compose 建桶 / 外接 S3 建桶 / 汇总)、kube-up.sh、cluster-up.sh(k8s 建桶)与
|
|
2
|
+
# smoke.sh(验桶)都读这一张,不各写一份串:各写一份的下场是清单漏一只桶,而漏桶的症状是起服后每一次对象写 / 每一拍 sweep 都 404。
|
|
3
|
+
#
|
|
4
|
+
# server **不建桶**(docs/DEPLOY-PREREQS.md「对象存储桶」),引擎起服只核一次快照桶在不在、不在就拒启 —— 所以这张表必须包含引擎要用的每一只:
|
|
5
|
+
# · `session-snapshots` = 引擎的 `SESSION_SNAPSHOT_BUCKET` 缺省名(snapshot-BLOB offload + SendUserFile 私有 presigned 轨 / 沙箱 staging);
|
|
6
|
+
# 由测试把这个名与引擎的缺省逐字咬合(引擎改缺省而这里没跟 ⇒ 红);
|
|
7
|
+
# · `sema-public`(SendUserFile 永久公链轨)**不在表里**:它要匿名 GetObject-only 策略,是运维另配的桶,脚本不替人开匿名读。
|
|
8
|
+
SEMA_UP_ENGINE_BUCKETS="workspaces blobs backups session-snapshots"
|
|
9
|
+
# CNPG 的 WAL 归档 / 每日基备桶(只有 k8s 两条路径有 PG 备份;名与 chart values 的 `pg.backup.bucket: s3://<名>/` 同名,由测试咬合)。
|
|
10
|
+
SEMA_UP_PG_BACKUP_BUCKET="sema-pg-backup"
|
|
11
|
+
|
|
12
|
+
# buckets_k8s → 打印 k8s 路径(kube-up / cluster-up)要建的全部桶,空格分隔,每只一次。
|
|
13
|
+
buckets_k8s() { printf '%s %s' "$SEMA_UP_PG_BACKUP_BUCKET" "$SEMA_UP_ENGINE_BUCKETS"; }
|
|
14
|
+
|
|
15
|
+
# buckets_prefixed <前缀> <桶…> → 每个桶名前加前缀(mc 的 `<别名>/<桶>` 写法),空格分隔。桶名是 S3 闭字符集,不含空白,按空白拆是安全的。
|
|
16
|
+
buckets_prefixed() {
|
|
17
|
+
local p="$1" b out=""
|
|
18
|
+
shift
|
|
19
|
+
for b in "$@"; do out="$out$p$b "; done
|
|
20
|
+
printf '%s' "${out% }"
|
|
21
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# lib/health.sh — 「装好的引擎 /health 体说它真落在哪个后端」的唯一读法 + sema-up 部署的期望值。
|
|
2
|
+
# smoke.sh / kube-up.sh / cluster-up.sh 三处验收都调它,不各写一份(各写一份的下场:有一处还只看 HTTP 200,把退到内存的服务判绿)。
|
|
3
|
+
#
|
|
4
|
+
# 事实(出处是引擎,不是推测):
|
|
5
|
+
# · `/health` 体里的 `sessionBackend` 是**装配后**的有效店:`durable(<kind>)`(kind = pg | mysql | local)或 `memory`
|
|
6
|
+
# (引擎侧只有一只读法:src/store-posture.ts 的 `sessionStoreLabelOf`);
|
|
7
|
+
# · sema-up 三条路径(compose / kube / 多机)起的引擎一律 `DB_BACKEND=pg`(stack/compose.yaml、chart/templates/server.yaml、
|
|
8
|
+
# stack/sema-stack-cluster.yaml 逐份写死),所以装好的引擎必须读到 `durable(pg)`。读到 `memory` = 会话 / 停驻 / run 账本在进程内存里、
|
|
9
|
+
# 重启即丢 —— /health 照样 200、401 门照样在,只有这一位说了实话,验收必须看它。
|
|
10
|
+
SEMA_UP_EXPECT_SESSION_BACKEND="durable(pg)"
|
|
11
|
+
|
|
12
|
+
# health_session_backend <health 体> → 打印 `sessionBackend` 的值;体读不成 JSON / 没有这一位 ⇒ 打印空串(调用方按「读不出」处置,不猜)。
|
|
13
|
+
health_session_backend() {
|
|
14
|
+
printf '%s' "$1" | python3 -c 'import json,sys
|
|
15
|
+
try:
|
|
16
|
+
v = json.load(sys.stdin).get("sessionBackend", "")
|
|
17
|
+
print(v if isinstance(v, str) else "")
|
|
18
|
+
except Exception:
|
|
19
|
+
print("")' 2>/dev/null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# health_backend_check <health 体> → 0 = 落在期望的后端;1 = 不是(stdout 打一句人话,供调用方拼进失败行)。
|
|
23
|
+
health_backend_check() {
|
|
24
|
+
local got
|
|
25
|
+
got="$(health_session_backend "$1")"
|
|
26
|
+
if [ "$got" = "$SEMA_UP_EXPECT_SESSION_BACKEND" ]; then return 0; fi
|
|
27
|
+
if [ -z "$got" ]; then
|
|
28
|
+
printf '/health 体里读不出 sessionBackend(期望 %s)' "$SEMA_UP_EXPECT_SESSION_BACKEND"
|
|
29
|
+
else
|
|
30
|
+
printf '/health.sessionBackend=%s,期望 %s' "$got" "$SEMA_UP_EXPECT_SESSION_BACKEND"
|
|
31
|
+
fi
|
|
32
|
+
return 1
|
|
33
|
+
}
|
|
@@ -34,6 +34,8 @@ unset _self _hops _dir
|
|
|
34
34
|
. "$HERE/lib/shell-access.sh"
|
|
35
35
|
# 取值旗的形(S-621):判据与词表(--profile / --users / --region / --git / --kube)的唯一定义;--help 的词表也从这里渲。
|
|
36
36
|
. "$HERE/lib/flagshape.sh"
|
|
37
|
+
# 对象存储桶的唯一表(kube-up.sh / cluster-up.sh / smoke.sh 同读这一张)。
|
|
38
|
+
. "$HERE/lib/buckets.sh"
|
|
37
39
|
# 日志一律打到 stderr(stdout 留给 --interactive=json 的协议行)。定义在最前面:参数一解析完就要判形,那时下面的函数都还没定义。
|
|
38
40
|
log() { printf '[sema-up] %s\n' "$*" >&2; }
|
|
39
41
|
# 执行车道表的唯一读者(S-599)。定义在**最前面**:`--help` 的词表也从表渲(手抄的词表会在加一条
|
|
@@ -647,7 +649,7 @@ if $DRY_RUN; then
|
|
|
647
649
|
[ "$GIT_MODE" = "provision" ] && echo " 2. 先起 Gitea → 引导管理员+access token$([ "$REGISTRY_ENABLED" = "true" ] && printf '+OAuth app(接 registry 登录)')"
|
|
648
650
|
[ -n "$PG_URL$S3_ENDPOINT" ] && echo " 2b. 外接端点连接检测(PG=真 select 1;S3=兼容协议 ls+建桶;证书不校验)"
|
|
649
651
|
echo " 3. docker compose up -d --wait(profiles=$COMPOSE_PROFILES)$([ -n "$DATA_ROOT" ] && printf ';数据卷 bind → %s' "$DATA_ROOT")"
|
|
650
|
-
case ",$COMPOSE_PROFILES," in *,s3,*) echo " 4. MinIO 建桶
|
|
652
|
+
case ",$COMPOSE_PROFILES," in *,s3,*) echo " 4. MinIO 建桶 ${SEMA_UP_ENGINE_BUCKETS// //}(幂等)" ;; esac
|
|
651
653
|
[ "$GIT_MODE" = "connect" ] && echo " +. 验证 $GIT_URL 连通(Gitea→GitHub→通用 git 探测链,证书不校验;Gitea=自动建 OAuth app,其余=打印待人工项)"
|
|
652
654
|
echo " 5. 装后即验(PG/S3$([ "$PROFILE" != "data-center" ] && printf '/引擎 health')$([ "$REGISTRY_ENABLED" = "true" ] && printf '/registry healthz')$([ "$GIT_MODE" = "provision" ] && printf '/gitea healthz'))+ 一屏 summary"
|
|
653
655
|
echo " 端口: $PF_PORTS(bind:数据面 $([ "$PROFILE" = "data-center" ] && echo 0.0.0.0 || echo 127.0.0.1);服务/registry/git 0.0.0.0)"
|
|
@@ -874,9 +876,9 @@ fi
|
|
|
874
876
|
if [ -n "$S3_ENDPOINT" ]; then
|
|
875
877
|
log "外接 S3 连接检测($S3_ENDPOINT)"
|
|
876
878
|
S3OK=$(docker run --rm --entrypoint sh -e MC_HOST_x="$(printf '%s' "$S3_ENDPOINT" | sed "s#://#://$S3_ACCESS_KEY:$S3_SECRET_KEY@#")" \
|
|
877
|
-
"${MC_IMAGE:-minio/mc:latest}" -c
|
|
879
|
+
"${MC_IMAGE:-minio/mc:latest}" -c "mc --insecure ls x/ >/dev/null 2>&1 && mc --insecure mb --ignore-existing $(buckets_prefixed x/ $SEMA_UP_ENGINE_BUCKETS) >/dev/null 2>&1 && echo S3_OK" 2>/dev/null | tail -1)
|
|
878
880
|
[ "$S3OK" = "S3_OK" ] || { log "⛔ 外接 S3 连不上或建桶失败。下一步:核对 endpoint/密钥;需要 S3 兼容协议(MinIO/OSS/COS/R2 等);证书问题已用 --insecure 忽略,若还不通多半是网络/密钥"; exit 1; }
|
|
879
|
-
log "外接 S3 就绪(
|
|
881
|
+
log "外接 S3 就绪(${SEMA_UP_ENGINE_BUCKETS// //} 已确保)"
|
|
880
882
|
fi
|
|
881
883
|
|
|
882
884
|
# ── git=provision:先起 Gitea 并引导(OAuth app 的 client id/secret 要在 registry 起来之前
|
|
@@ -1005,13 +1007,16 @@ fi
|
|
|
1005
1007
|
# D(S-618):up 之前先 `compose config` 渲染对账 —— 容器真正拿到的决策键与本次决策逐值对齐才 up。
|
|
1006
1008
|
reconcile_render
|
|
1007
1009
|
log "装配:docker compose profiles=$COMPOSE_PROFILES project=$PROJECT"
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
# 建桶(幂等,一次性动作归 Layer 0;只对本地 MinIO——外接 S3 已在连接检测时确保)
|
|
1010
|
+
# 建桶(幂等,一次性动作归 Layer 0;只对本地 MinIO——外接 S3 已在连接检测时确保)。🔴 排在**全栈 up 之前**:引擎起服会核快照桶在不在
|
|
1011
|
+
# (缺则拒启),而 `up --wait` 要等引擎健康 —— 桶建在 up 之后,新数据卷上就是引擎等桶、compose 等引擎的互等。所以先只起 MinIO(`--wait` 等它健康)、建桶,再起全栈。
|
|
1011
1012
|
envf_load MINIO_PASSWORD # A:回读生成的 MinIO 口令(建桶用),不 source .env
|
|
1012
1013
|
case ",$COMPOSE_PROFILES," in *,s3,*)
|
|
1013
|
-
|
|
1014
|
+
COMPOSE_PROFILES="$COMPOSE_PROFILES" compose up -d --wait minio \
|
|
1015
|
+
|| { log "⛔ MinIO 启动失败。下一步:docker compose -p $PROJECT logs minio(常见:镜像拉取失败→检查镜像引用/docker login)"; exit 1; }
|
|
1016
|
+
docker run --rm --network "${PROJECT}_default" -e MC_HOST_x="http://sema:${MINIO_PASSWORD}@minio:9000" "${MC_IMAGE:-minio/mc:latest}" mb --ignore-existing $(buckets_prefixed x/ $SEMA_UP_ENGINE_BUCKETS) >/dev/null || { log "⛔ MinIO 建桶失败。下一步:docker compose -p $PROJECT logs minio"; exit 1; } ;;
|
|
1014
1017
|
esac
|
|
1018
|
+
COMPOSE_PROFILES="$COMPOSE_PROFILES" compose up -d --wait --remove-orphans \
|
|
1019
|
+
|| { log "⛔ compose up 失败。下一步:docker compose -p $PROJECT logs(常见:镜像拉取失败→检查镜像引用/docker login;端口占用→--port 换口)"; exit 1; }
|
|
1015
1020
|
|
|
1016
1021
|
# ── 验证(装后即验,§3d smoke 的子集;全量随时可跑 smoke.sh --project=$PROJECT)──────────────
|
|
1017
1022
|
# A:回读验证 / 汇总要用的凭据与登记值(不 source .env);缺的键回读成空,由下游 :- 缺省处置。
|
|
@@ -1066,9 +1071,9 @@ else
|
|
|
1066
1071
|
esac
|
|
1067
1072
|
[ -n "$PG_URL" ] && echo " PG(外接) $EXT_PG_HOST:$EXT_PG_PORT/$EXT_PG_DB(连接检测已过;凭据在 .env)"
|
|
1068
1073
|
case ",$COMPOSE_PROFILES," in *,s3,*)
|
|
1069
|
-
echo " S3/MinIO http://$HOSTIP:$MINIO_PORT(console :$MINIO_CONSOLE_PORT,桶×$V_BK
|
|
1074
|
+
echo " S3/MinIO http://$HOSTIP:$MINIO_PORT(console :$MINIO_CONSOLE_PORT,桶×$V_BK:${SEMA_UP_ENGINE_BUCKETS// //})" ;;
|
|
1070
1075
|
esac
|
|
1071
|
-
[ -n "$S3_ENDPOINT" ] && echo " S3(外接) $S3_ENDPOINT(
|
|
1076
|
+
[ -n "$S3_ENDPOINT" ] && echo " S3(外接) $S3_ENDPOINT(连接检测+引擎桶已确保;密钥在 .env)"
|
|
1072
1077
|
case ",$COMPOSE_PROFILES," in *,agent,*)
|
|
1073
1078
|
echo " 引擎 http://$HOSTIP:$SERVER_PORT(/health: $V_HEALTH;API 凭据=SERVICE_AUTH_TOKEN)"
|
|
1074
1079
|
compose_shell_access_text "$SERVER_PORT" ;;
|
package/deploy/sema-up/smoke.sh
CHANGED
|
@@ -22,6 +22,10 @@ unset _self _hops _dir
|
|
|
22
22
|
. "$HERE/lib/envf.sh"
|
|
23
23
|
# 取值旗的形(S-621):判据同 sema-up.sh 一处定义。
|
|
24
24
|
. "$HERE/lib/flagshape.sh"
|
|
25
|
+
# 引擎 /health 体里「落在哪个后端」的读法与期望值(kube-up / cluster-up 的验收同一只)。
|
|
26
|
+
. "$HERE/lib/health.sh"
|
|
27
|
+
# 对象存储桶的唯一表(sema-up.sh / kube-up.sh / cluster-up.sh 的建桶清单同读这一张)。
|
|
28
|
+
. "$HERE/lib/buckets.sh"
|
|
25
29
|
log() { printf '[smoke] %s\n' "$*" >&2; }
|
|
26
30
|
|
|
27
31
|
PROJECT="" URL="" TOKEN=""
|
|
@@ -68,9 +72,10 @@ if [ -n "$PROJECT" ]; then
|
|
|
68
72
|
# 哨兵判定(cat 回读值核对后 echo),不依赖各 mc 子命令的输出行为
|
|
69
73
|
S3RT=$(docker run --rm --entrypoint sh --network "${PROJECT}_default" -e MC_HOST_x="http://sema:${MINIO_PASSWORD}@minio:9000" "${MC_IMAGE:-minio/mc:latest}" -c 'echo smoke > /tmp/s && mc cp /tmp/s x/blobs/_smoke >/dev/null && [ "$(mc cat x/blobs/_smoke)" = smoke ] && mc rm x/blobs/_smoke >/dev/null && echo S3_ROUNDTRIP_OK' 2>/dev/null | tail -1)
|
|
70
74
|
[ "$S3RT" = "S3_ROUNDTRIP_OK" ] && ok "S3 put/get/rm 往返" || fail "S3" "对象读写失败" "docker compose -p $PROJECT logs minio"
|
|
71
|
-
# ③b
|
|
72
|
-
BKTS=$(docker run --rm --entrypoint sh --network "${PROJECT}_default" -e MC_HOST_x="http://sema:${MINIO_PASSWORD}@minio:9000" "${MC_IMAGE:-minio/mc:latest}" -c
|
|
73
|
-
|
|
75
|
+
# ③b 引擎桶逐个点名(data-center 验收:ls 行数≠桶名对——错桶也会凑数;清单 = lib/buckets.sh 那一张表)
|
|
76
|
+
BKTS=$(docker run --rm --entrypoint sh --network "${PROJECT}_default" -e MC_HOST_x="http://sema:${MINIO_PASSWORD}@minio:9000" "${MC_IMAGE:-minio/mc:latest}" -c "for b in $SEMA_UP_ENGINE_BUCKETS; do mc ls \"x/\$b\" >/dev/null 2>&1 && printf \"%s \" \"\$b\"; done" 2>/dev/null)
|
|
77
|
+
BKTS_WANT="$(printf '%s ' $SEMA_UP_ENGINE_BUCKETS)"
|
|
78
|
+
[ "$BKTS" = "$BKTS_WANT" ] && ok "桶就绪(${SEMA_UP_ENGINE_BUCKETS// //})" || fail "桶" "缺桶:应有 ${SEMA_UP_ENGINE_BUCKETS// //},实有 ${BKTS:-无}" "重跑 sema-up.sh(建桶幂等)"
|
|
74
79
|
fi
|
|
75
80
|
# 外接数据面(--pg-url/--s3-endpoint):有 endpoint 就远程直验(证书不校验)
|
|
76
81
|
if [ -n "${AGENT_PG_HOST:-}" ] && ! $HAS_PG && [ "${DEPLOY_PROFILE:-}" != "local-plus" ]; then
|
|
@@ -100,9 +105,14 @@ except Exception: print("")' 2>/dev/null)
|
|
|
100
105
|
fi
|
|
101
106
|
|
|
102
107
|
if [ -n "$URL" ]; then
|
|
103
|
-
# ④ /health
|
|
104
|
-
H=$(curl -m5 -s "$URL/health"
|
|
105
|
-
case "$H" in *'"status":"ok"'*) ok "/health($URL)" ;; *) fail "/health" "无响应或非 ok:${H:-空}" "服务没起/端口不对/防火墙;docker logs 或 systemctl 看进程" ;; esac
|
|
108
|
+
# ④ /health(整体取回:后端位在体的中后段,截断读会丢它)
|
|
109
|
+
H=$(curl -m5 -s "$URL/health")
|
|
110
|
+
case "$H" in *'"status":"ok"'*) ok "/health($URL)" ;; *) fail "/health" "无响应或非 ok:$(printf '%s' "${H:-空}" | head -c 200)" "服务没起/端口不对/防火墙;docker logs 或 systemctl 看进程" ;; esac
|
|
111
|
+
# ④′ 后端位:/health 200 ≠ 数据落了库 —— 引擎的 sessionBackend 必须是期望的持久后端(durable(pg)),`memory` = 内存里跑、重启即丢
|
|
112
|
+
case "$H" in *'"status":"ok"'*)
|
|
113
|
+
if BK_WHY=$(health_backend_check "$H"); then ok "引擎后端(sessionBackend=$SEMA_UP_EXPECT_SESSION_BACKEND)"
|
|
114
|
+
else fail "引擎后端" "$BK_WHY" "库没连上时引擎不会再退内存起服(拒启);读到 memory 多半是旧镜像或手工起的引擎 —— 看 docker logs / kubectl logs 的 store_sql_open_wait 与拒启句"; fi ;;
|
|
115
|
+
esac
|
|
106
116
|
if [ -n "$TOKEN" ]; then
|
|
107
117
|
# ⑤ auth 门:无 token 必须 401(部署安全底线)
|
|
108
118
|
C=$(curl -m5 -s -o /dev/null -w '%{http_code}' -X POST "$URL/v1/tasks" -H "Content-Type: application/json" -d '{}')
|
|
@@ -77,7 +77,8 @@ spec:
|
|
|
77
77
|
spec:
|
|
78
78
|
containers:
|
|
79
79
|
- name: minio
|
|
80
|
-
image: minio/minio:
|
|
80
|
+
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
|
|
81
|
+
imagePullPolicy: IfNotPresent
|
|
81
82
|
args: ["server", "/data", "--console-address", ":9001"]
|
|
82
83
|
env:
|
|
83
84
|
- { name: MINIO_ROOT_USER, valueFrom: { secretKeyRef: { name: sema-minio, key: rootUser } } }
|
|
@@ -155,6 +156,8 @@ spec:
|
|
|
155
156
|
env:
|
|
156
157
|
- { name: PORT, value: "8090" }
|
|
157
158
|
- { name: DB_BACKEND, value: pg }
|
|
159
|
+
# 引擎 boot 期等库的窗(ms):CNPG 与 server Pod 同时起,库初始化常慢于 server 就绪 —— 窗内重试、到窗仍连不上才拒启(chart 的 server.storeWaitMs 同值)
|
|
160
|
+
- { name: STORE_LOCK_WAIT_MS, value: "300000" }
|
|
158
161
|
- { name: SESSION_BACKEND, value: auto }
|
|
159
162
|
- { name: PG_HOST, value: sema-pg-rw.sema.svc }
|
|
160
163
|
- { name: PG_PORT, value: "5432" }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { AppendLog, ensureDir } from "@sema-agent/core";
|
|
3
|
+
import { AppendLog, ensureDir, isHostDecider } from "@sema-agent/core";
|
|
4
4
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
5
5
|
import { replayJsonlSkipping } from "./observability/corrupt-read-seat.js";
|
|
6
6
|
export const APPROVAL_ASK_AUDIT_DIR = "approval-ask-audit";
|
|
@@ -10,11 +10,6 @@ export const AUDIT_SHUTDOWN_CAUSE_WORDS = { shutdown_before_park: true };
|
|
|
10
10
|
export function buildCheckpointAnchorHash(token) {
|
|
11
11
|
return createHash("sha256").update(token, "utf8").digest("hex").slice(0, 16);
|
|
12
12
|
}
|
|
13
|
-
const HOST_DECIDED_BY_WORDS = ["person", "sla_timeout", "policy"];
|
|
14
|
-
const HOST_DECIDED_BY = new Set(HOST_DECIDED_BY_WORDS);
|
|
15
|
-
function isHostDecidedBy(v) {
|
|
16
|
-
return typeof v === "string" && HOST_DECIDED_BY.has(v);
|
|
17
|
-
}
|
|
18
13
|
function isAuditShutdownCause(v) {
|
|
19
14
|
return typeof v === "string" && Object.hasOwn(AUDIT_SHUTDOWN_CAUSE_WORDS, v);
|
|
20
15
|
}
|
|
@@ -123,7 +118,7 @@ function readLedgerRecord(u, noteOutOfSetSeat) {
|
|
|
123
118
|
const decidedByV = o.decidedBy;
|
|
124
119
|
const legacySettledByV = decidedByV === undefined ? o.settledBy : undefined;
|
|
125
120
|
const legacySettledBy = legacySettledByV === "human" || legacySettledByV === "timeout" || legacySettledByV === "aborted" ? legacySettledByV : undefined;
|
|
126
|
-
const decidedBy =
|
|
121
|
+
const decidedBy = isHostDecider(decidedByV) ? decidedByV : legacySettledBy !== undefined ? "person" : undefined;
|
|
127
122
|
const approver = s("approver");
|
|
128
123
|
const settledAtMs = num("settledAtMs");
|
|
129
124
|
const sessionId = s("sessionId");
|