@sema-agent/server 7.4.0 → 7.6.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/LICENSE +1 -1
- package/README.md +18 -3
- package/README.zh-CN.md +14 -3
- package/USAGE.md +80 -1
- package/dist/approval-card.d.ts +15 -3
- package/dist/approval-card.js +41 -7
- package/dist/approval-reconciler.d.ts +109 -12
- package/dist/approval-reconciler.js +152 -24
- package/dist/boot/config-center.js +15 -2
- package/dist/boot/coordinators.js +10 -2
- package/dist/boot/execution-env.js +1 -1
- package/dist/boot/org-memory.d.ts +6 -0
- package/dist/boot/org-memory.js +1 -1
- package/dist/boot/parked-revive-gate.d.ts +78 -0
- package/dist/boot/parked-revive-gate.js +114 -0
- package/dist/boot/reapers.d.ts +2 -0
- package/dist/boot/reapers.js +11 -4
- package/dist/boot/resolve-spec.d.ts +3 -19
- package/dist/boot/resolve-spec.js +73 -67
- package/dist/boot/runner-deps.d.ts +23 -1
- package/dist/boot/runner-deps.js +8 -11
- package/dist/boot/workflow-orchestration.d.ts +8 -3
- package/dist/boot/workflow-orchestration.js +23 -1
- package/dist/budget.d.ts +1 -1
- package/dist/budget.js +1 -1
- package/dist/capabilities/repo-tools.d.ts +1 -1
- package/dist/capabilities/repo-tools.js +8 -2
- package/dist/config-center/apply-effective.js +33 -10
- package/dist/config-provider.d.ts +1 -0
- package/dist/config-provider.js +23 -3
- package/dist/config-types.d.ts +27 -9
- package/dist/config.d.ts +6 -1
- package/dist/config.js +61 -15
- package/dist/deployment-governance.d.ts +168 -0
- package/dist/deployment-governance.js +206 -0
- package/dist/env-facts.d.ts +3 -1
- package/dist/env-facts.js +3 -1
- package/dist/fleet/fleet-bus.d.ts +17 -2
- package/dist/fleet/fleet-bus.js +68 -3
- package/dist/fleet/fleet-terminal-window.d.ts +98 -0
- package/dist/fleet/fleet-terminal-window.js +316 -0
- package/dist/governance-ask-marks.d.ts +31 -0
- package/dist/governance-ask-marks.js +122 -0
- package/dist/hooks/hook-runner.d.ts +28 -0
- package/dist/hooks/hook-runner.js +149 -25
- package/dist/http/routes/approvals-assistant.js +6 -7
- package/dist/http/routes/diagnostics.js +10 -5
- package/dist/http/routes/fleet.js +160 -14
- package/dist/http/routes/memory-policy.d.ts +2 -1
- package/dist/http/routes/memory-policy.js +77 -13
- package/dist/http/routes/runs.js +6 -2
- package/dist/http/routes/tasks.js +59 -22
- package/dist/http/routes/trace-usage.js +3 -4
- package/dist/http/send.d.ts +23 -0
- package/dist/http/send.js +23 -0
- package/dist/http/server.d.ts +9 -0
- package/dist/http/server.js +28 -14
- package/dist/http/sse-log.js +3 -4
- package/dist/http/wire-types.d.ts +7 -2
- package/dist/leader/diffout.d.ts +10 -0
- package/dist/leader/diffout.js +14 -2
- package/dist/leader/diffup.js +3 -2
- package/dist/leader/planner.js +7 -0
- package/dist/main.js +39 -31
- package/dist/observability/fail-open.d.ts +17 -2
- package/dist/observability/fail-open.js +19 -4
- package/dist/observability/prompt-manifest.d.ts +5 -1
- package/dist/orchestration/workflow-notify-journal.d.ts +58 -2
- package/dist/orchestration/workflow-notify-journal.js +130 -45
- package/dist/parked-decide.js +9 -4
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -2
- package/dist/plugins/approval-ask-store-memory.js +3 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +60 -5
- package/dist/plugins/approval-ask-store-sql.js +75 -35
- package/dist/plugins/background-agent-store-sql.js +16 -16
- package/dist/plugins/background-shell-support.d.ts +1 -1
- package/dist/plugins/background-shell-support.js +2 -2
- package/dist/plugins/breaker-state-sql.js +2 -2
- package/dist/plugins/checkpoint-store-sql.d.ts +67 -8
- package/dist/plugins/checkpoint-store-sql.js +76 -13
- package/dist/plugins/image-bake-store-sql.d.ts +1 -1
- package/dist/plugins/image-bake-store-sql.js +27 -27
- package/dist/plugins/image-index-sql.js +15 -15
- package/dist/plugins/local-checkpoint-store.d.ts +20 -1
- package/dist/plugins/local-checkpoint-store.js +19 -0
- package/dist/plugins/mailbox-store-sql.d.ts +4 -10
- package/dist/plugins/mailbox-store-sql.js +59 -6
- package/dist/plugins/memory-engine-pg.js +9 -9
- package/dist/plugins/memory-engine-tidb.js +7 -7
- package/dist/plugins/memory-sync-store-pg.js +13 -13
- package/dist/plugins/memory-sync-store-tidb.js +5 -5
- package/dist/plugins/outcome-ledger-sql.js +7 -7
- package/dist/plugins/pg-cost-quota.js +3 -3
- package/dist/plugins/pg-pool.js +84 -75
- package/dist/plugins/pg-rate-limiter.js +3 -3
- package/dist/plugins/pg-session-storage.d.ts +1 -1
- package/dist/plugins/pg-session-storage.js +12 -13
- package/dist/plugins/remote-env-host.js +3 -1
- package/dist/plugins/remote-env-local-docker.js +6 -3
- package/dist/plugins/remote-env-ssh.d.ts +13 -1
- package/dist/plugins/roster-store-sql.js +8 -8
- package/dist/plugins/store-contracts.d.ts +19 -0
- package/dist/plugins/store-contracts.js +42 -0
- package/dist/plugins/task-attachment-store.js +5 -5
- package/dist/plugins/task-list-store-sql.js +1 -1
- package/dist/plugins/tidb-cost-quota.js +1 -1
- package/dist/plugins/tidb-pool.js +83 -60
- package/dist/plugins/tidb-rate-limiter.js +1 -1
- package/dist/plugins/tidb-session-store.js +2 -5
- package/dist/plugins/tool-result-store-sql.js +2 -2
- package/dist/plugins/usage-window-store-sql.js +13 -13
- package/dist/plugins/write-behind-counter.d.ts +10 -2
- package/dist/plugins/write-behind-counter.js +13 -3
- package/dist/resource-suspend.d.ts +3 -1
- package/dist/resource-suspend.js +3 -1
- package/dist/run-local.d.ts +73 -1
- package/dist/run-local.js +146 -5
- package/dist/runs.d.ts +11 -1
- package/dist/runs.js +18 -3
- package/dist/runtime-governance.d.ts +18 -0
- package/dist/runtime-governance.js +90 -3
- package/dist/security.d.ts +12 -0
- package/dist/security.js +12 -0
- package/dist/session-sync-kernel.d.ts +13 -0
- package/dist/session-sync-kernel.js +13 -0
- package/dist/task-settings.d.ts +3 -9
- package/dist/task-settings.js +16 -13
- package/dist/tool-approval.d.ts +33 -6
- package/dist/tool-approval.js +80 -23
- package/dist/trace/core-keyset-guard.d.ts +18 -4
- package/dist/trace/project.d.ts +10 -1
- package/dist/trace/project.js +31 -0
- package/package.json +3 -3
- package/dist/boot/lexical-path-env.d.ts +0 -10
- package/dist/boot/lexical-path-env.js +0 -88
- package/dist/capabilities/oa-tools.d.ts +0 -15
- package/dist/capabilities/oa-tools.js +0 -54
- package/dist/finance/cost-taxonomy.d.ts +0 -34
- package/dist/finance/cost-taxonomy.js +0 -26
- package/dist/plugins/approval-store-sql.d.ts +0 -116
- package/dist/plugins/approval-store-sql.js +0 -151
- package/dist/plugins/file-workflow-journal-store.d.ts +0 -12
- package/dist/plugins/file-workflow-journal-store.js +0 -12
- package/dist/plugins/pg-approval-store.d.ts +0 -9
- package/dist/plugins/pg-approval-store.js +0 -9
- package/dist/plugins/pg-breaker-state.d.ts +0 -8
- package/dist/plugins/pg-breaker-state.js +0 -8
- package/dist/plugins/pg-checkpoint-store.d.ts +0 -10
- package/dist/plugins/pg-checkpoint-store.js +0 -10
- package/dist/plugins/pg-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/pg-file-snapshot-store.js +0 -8
- package/dist/plugins/pg-image-bake.d.ts +0 -12
- package/dist/plugins/pg-image-bake.js +0 -11
- package/dist/plugins/pg-image-index.d.ts +0 -12
- package/dist/plugins/pg-image-index.js +0 -11
- package/dist/plugins/pg-outcome-ledger.d.ts +0 -12
- package/dist/plugins/pg-outcome-ledger.js +0 -11
- package/dist/plugins/pg-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/pg-resume-anchor-store.js +0 -7
- package/dist/plugins/pg-run-store.d.ts +0 -9
- package/dist/plugins/pg-run-store.js +0 -9
- package/dist/plugins/pg-session-policy-store.d.ts +0 -7
- package/dist/plugins/pg-session-policy-store.js +0 -7
- package/dist/plugins/pg-session-store.d.ts +0 -12
- package/dist/plugins/pg-session-store.js +0 -12
- package/dist/plugins/pg-tool-result-store.d.ts +0 -9
- package/dist/plugins/pg-tool-result-store.js +0 -9
- package/dist/plugins/pg-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-journal-store.js +0 -9
- package/dist/plugins/pg-workflow-run-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-run-store.js +0 -9
- package/dist/plugins/tidb-approval-store.d.ts +0 -8
- package/dist/plugins/tidb-approval-store.js +0 -8
- package/dist/plugins/tidb-breaker-state.d.ts +0 -7
- package/dist/plugins/tidb-breaker-state.js +0 -7
- package/dist/plugins/tidb-checkpoint-store.d.ts +0 -9
- package/dist/plugins/tidb-checkpoint-store.js +0 -9
- package/dist/plugins/tidb-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/tidb-file-snapshot-store.js +0 -8
- package/dist/plugins/tidb-image-bake.d.ts +0 -12
- package/dist/plugins/tidb-image-bake.js +0 -11
- package/dist/plugins/tidb-image-index.d.ts +0 -12
- package/dist/plugins/tidb-image-index.js +0 -11
- package/dist/plugins/tidb-outcome-ledger.d.ts +0 -12
- package/dist/plugins/tidb-outcome-ledger.js +0 -12
- package/dist/plugins/tidb-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/tidb-resume-anchor-store.js +0 -7
- package/dist/plugins/tidb-run-store.d.ts +0 -10
- package/dist/plugins/tidb-run-store.js +0 -9
- package/dist/plugins/tidb-session-policy-store.d.ts +0 -7
- package/dist/plugins/tidb-session-policy-store.js +0 -7
- package/dist/plugins/tidb-tool-result-store.d.ts +0 -8
- package/dist/plugins/tidb-tool-result-store.js +0 -10
- package/dist/plugins/tidb-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/tidb-workflow-journal-store.js +0 -9
- package/dist/plugins/tidb-workflow-run-store.d.ts +0 -10
- package/dist/plugins/tidb-workflow-run-store.js +0 -10
- package/dist/plugins/workflow-journal-limits.d.ts +0 -12
- package/dist/plugins/workflow-journal-limits.js +0 -12
- package/dist/sema-registry.d.ts +0 -41
- package/dist/sema-registry.js +0 -40
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* #156 —— 非 host lane(e2b/k8s/ssh/adb/local-docker)写门的**纯路径规则**过渡形所用的裁决 env。
|
|
3
|
-
*
|
|
4
|
-
* ## 它解决的缺口
|
|
5
|
-
*
|
|
6
|
-
* core 的 `createFsWriteGatePolicy` / `createSensitivePathPolicy` 都把写目标交给
|
|
7
|
-
* `canonicalizeTarget(env, …)` 去「问 fs 要真身」。host lane 上那个 env 就是 hand 工具真正写的那块盘,
|
|
8
|
-
* 答案可信。沙箱 lane 不是:per-task 的沙箱 env 由 core 的 `executionEnvFactory` 在 spec **之后**才铸,
|
|
9
|
-
* spec 期手边只有 worker 本机的 fs——拿它去裁沙箱里的路径会答错(exists/symlink 全是别人机器上的事实),
|
|
10
|
-
* 而**错误的 allow 比没有门更糟**。所以 [816]/[820] 当年在沙箱 lane 诚实不挂门(wiring=undefined ⇒
|
|
11
|
-
* 三个模式臂全回落 base 规则,写门整条缺席)。#153 的 ③ 号注把这笔记成了余款,#156 是它的过渡还款。
|
|
12
|
-
*
|
|
13
|
-
* ## 这个 env 是什么
|
|
14
|
-
*
|
|
15
|
-
* 一个**没有文件系统**的 env:除 `absolutePath` 外的每一个 fs 面(exists / canonicalPath / fileInfo /
|
|
16
|
-
* read* / write* / listDir / createDir / …)与 shell 面都继承 core 的 `StubExecutionEnv`,
|
|
17
|
-
* 恒返回 `not_supported` 错误(`readLink` 是可选面,Stub 干脆没有——core 把缺席当「symlink 不可解」,
|
|
18
|
-
* 且该分支在本 env 恒不可达:exists 先错就进了 canonicalizeNewPath)——这不是伪装,这就是本 env 的诚实回答:**spec 期我们确实不知道沙箱里
|
|
19
|
-
* 那块盘上有什么**。`absolutePath` 是唯一被赋予真实语义的一面,而它本来就是纯路径运算(不碰盘):
|
|
20
|
-
* POSIX 绝对路径做词法归一后原样奉还,其余一律「不知道」。
|
|
21
|
-
*
|
|
22
|
-
* ## 由此得到的裁决语义(core dist 亲读推出,`tools/fs/safety.js` canonicalizeTarget)
|
|
23
|
-
*
|
|
24
|
-
* · 绝对路径(`/…`):`absolutePath` ok ⇒ core 进 exists 探测 ⇒ 我们返回错误 ⇒ core 按「该路径尚不存在」
|
|
25
|
-
* 走 `canonicalizeNewPath`,那里逐级 exists 也全错 ⇒ 原样返回我们给的词法绝对路径。于是 canonical key
|
|
26
|
-
* = **词法归一后的路径**,`canonicalPath` / `fileInfo` / `readLink` 三面在这条路上根本不可达。
|
|
27
|
-
* · 相对路径 / `~/…` / Windows 盘符形:`absolutePath` 返回错误 ⇒ `canon.ok=false` ⇒ 写门直接
|
|
28
|
-
* `ask`(fail-closed)。沙箱的 cwd 在 spec 期不可知,这正是我们要的偏置——**不猜沙箱工作目录**。
|
|
29
|
-
* · 反斜杠 UNC 形(`\\host\share\…`)是唯一**不经过**本 env 的形:core 的 `canonicalizeTarget` 在入口
|
|
30
|
-
* 就把它短路成 `ok:true, key=原样`(复审 2026-08-05 dist 亲读+实测)。结果不变——写门无放行域可越,
|
|
31
|
-
* 落 defaultWrite 的 `ask`;sensitive 段匹配按 `[\\/]` 双分隔符切段,`\\host\share\.env` 照样 deny。
|
|
32
|
-
* · sensitivePatterns 的 deny 腿照常施加:它按 canonical key 的**路径段**做 glob 匹配,词法 key 足够,
|
|
33
|
-
* 且在 `combinePolicies` 折叠里 deny 恒胜(session 豁免 / accept 域越不过)。
|
|
34
|
-
* · `isExempt`(会话「本会话不再询问」探针)是 name-keyed 的,不做 fs 裁决,任何 lane 都安全,照接。
|
|
35
|
-
*
|
|
36
|
-
* ## 已知残余面(过渡形的边界,不是疏漏)
|
|
37
|
-
*
|
|
38
|
-
* · **symlink 形**:词法裁决看不见符号链接。沙箱里一个名字普通的软链可以指向守卫段(`.ssh` 等),
|
|
39
|
-
* 我们只会给 `ask` 而不是 `deny`;host lane 上 core 会 canonicalize 出真身并 deny。相应地,core 的
|
|
40
|
-
* `unresolvedSymlink ⇒ deny` 那条腿在本 env 下永不触发。注意豁免会话下的口径(codex 复审 E):
|
|
41
|
-
* name-keyed 豁免不看路径,这类词法无害的软链目标在豁免会话里是 **allow** 而非 ask——这是本残余面
|
|
42
|
-
* 在「操作员已授 don't-ask-again」情形下的完整代价,host lane 同情形仍会 deny。
|
|
43
|
-
* · **exempt/accept 域**:沙箱 lane 既无可信 cwd 也无 scratchpad 对应物,故本过渡形**一个自动放行域都
|
|
44
|
-
* 不铸**(见 resolve-spec 的 wiring)。代价是 acceptEdits 在沙箱 lane 退化成与 default 同形(全 ask);
|
|
45
|
-
* 这是 fail-safe 方向,与 host lane「accept 域解析不出 ⇒ 该域不生效」的哨兵先例同口径。
|
|
46
|
-
* · **`cwd` 字段**:继承 `StubExecutionEnv` 的 `"/"` 占位。本 env 只活在 policy 折叠里,core 的两个
|
|
47
|
-
* policy 都不读 `env.cwd`(相对路径基准走 `rootPath` 形参,而我们不给)——它不代表沙箱的工作目录。
|
|
48
|
-
*
|
|
49
|
-
* ## 终局 seam
|
|
50
|
-
*
|
|
51
|
-
* 正解是让写门在**工具执行时刻**拿到真沙箱 env:core [2751] 已排期给 `HookToolContext` 加一个只读的
|
|
52
|
-
* env 能力窄面(174/#22 窗)。那一面到货后,本过渡形整体退役换正解——届时沙箱 lane 与 host lane 走同
|
|
53
|
-
* 一条真 fs 裁决,上面三条残余面一并消失。
|
|
54
|
-
*/
|
|
55
|
-
import { posix } from "node:path";
|
|
56
|
-
import { FileError, StubExecutionEnv, err, ok } from "@sema-agent/core";
|
|
57
|
-
/** 词法归一:纯字符串运算,折 `.` / `..` / 重复分隔符,不碰 fs。
|
|
58
|
-
* `posix.normalize` 把 `..` 在根部截断(`/../x` → `/x`),与「沙箱根之上没有东西」的语义一致。
|
|
59
|
-
* 尾部分隔符统一剥掉(根 `/` 除外),让同一目标只有一个 key ——前缀判域靠的就是 key 的唯一性。
|
|
60
|
-
* (core 内部有同形的 `normalizeAbsPathLexically`,但未从包根导出;此处是 Node 标准库的等价运算,
|
|
61
|
-
* 不是它的抄本——若日后 core 导出,这里应改为直接复用。) */
|
|
62
|
-
function normalizeAbsolutePathLexically(path) {
|
|
63
|
-
const collapsed = posix.normalize(path.replace(/^\/+/, "/"));
|
|
64
|
-
return collapsed.length > 1 ? collapsed.replace(/\/+$/, "") : collapsed;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* 无文件系统的路径裁决 env(见文件头)。只覆写 `absolutePath` 一面,其余全部继承 `StubExecutionEnv`
|
|
68
|
-
* 的 `not_supported` ——**继承而非逐一手写**是刻意的:core 日后给 `ExecutionEnv` 加必填面时,新面会
|
|
69
|
-
* 随 `StubExecutionEnv` 一起到位并保持同一个诚实答案,不会在这里留下一个悄悄编出来的假答案。
|
|
70
|
-
*/
|
|
71
|
-
export class LexicalPathExecutionEnv extends StubExecutionEnv {
|
|
72
|
-
absolutePath(path) {
|
|
73
|
-
// POSIX 绝对形是沙箱 lane(全 Linux)上 hand 工具的书面契约形。其余一切——相对路径、`~`、
|
|
74
|
-
// `C:\…`——在 spec 期都无法诚实解析成一个沙箱内的绝对路径,返回错误让 core 落 ask。
|
|
75
|
-
// (反斜杠 UNC 形根本到不了这里:core 在 canonicalizeTarget 入口短路,见文件头「由此得到的裁决语义」。)
|
|
76
|
-
// codex 复审 A(2026-08-05):含 NUL 的字符串不是合法 POSIX 路径(任何 fs 面都写不进去),但词法归一
|
|
77
|
-
// 会照样给它铸出 canonical key——`\0` 尾巴让守卫段 glob 失配,豁免会话下还能拿 allow。拒收让 canon
|
|
78
|
-
// 在豁免咨询**之前**就失败 ⇒ 恒 ask。
|
|
79
|
-
if (path.includes("\u0000")) {
|
|
80
|
-
return Promise.resolve(err(new FileError("not_supported", "this environment adjudicates paths lexically and rejects a path containing a NUL byte (not a representable POSIX path)", path)));
|
|
81
|
-
}
|
|
82
|
-
if (!path.startsWith("/")) {
|
|
83
|
-
return Promise.resolve(err(new FileError("not_supported", "this environment adjudicates paths lexically and cannot resolve a non-absolute path (the sandbox working directory is unknown at spec time)", path)));
|
|
84
|
-
}
|
|
85
|
-
return Promise.resolve(ok(normalizeAbsolutePathLexically(path)));
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
//# sourceMappingURL=lexical-path-env.js.map
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ToolSpec } from "@sema-agent/core";
|
|
2
|
-
/**
|
|
3
|
-
* OA scenario — tools are thin HTTP clients to the OA backend's existing APIs (read = /api/v1/*,
|
|
4
|
-
* write = /api/assets/*). The shared service token + the request's principal are forwarded so OA
|
|
5
|
-
* enforces THAT end-user's RBAC + audit (the service never holds per-user creds). Decoupled: the
|
|
6
|
-
* service knows no OA schema/DB — OA stays the source of truth (its /api/v1/meta is self-describing).
|
|
7
|
-
*/
|
|
8
|
-
export interface OaCtx {
|
|
9
|
-
baseUrl: string;
|
|
10
|
-
token: string;
|
|
11
|
-
principal?: string;
|
|
12
|
-
}
|
|
13
|
-
export declare function oaTools(ctx: OaCtx): ToolSpec[];
|
|
14
|
-
export declare const oaPrompt: import("@sema-agent/core").PromptProvider;
|
|
15
|
-
//# sourceMappingURL=oa-tools.d.ts.map
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import { stablePrompt } from "./prompt.js";
|
|
3
|
-
async function oaFetch(ctx, path, init) {
|
|
4
|
-
if (!ctx.baseUrl || !ctx.token)
|
|
5
|
-
return "OA 后端未配置(OA_API_BASEURL / OA_SERVICE_TOKEN)";
|
|
6
|
-
try {
|
|
7
|
-
const res = await fetch(ctx.baseUrl + path, {
|
|
8
|
-
method: init?.method ?? "GET",
|
|
9
|
-
headers: {
|
|
10
|
-
"content-type": "application/json",
|
|
11
|
-
authorization: `Bearer ${ctx.token}`,
|
|
12
|
-
...(ctx.principal ? { "x-agent-principal": ctx.principal } : {}),
|
|
13
|
-
},
|
|
14
|
-
body: init?.body !== undefined ? JSON.stringify(init.body) : undefined,
|
|
15
|
-
});
|
|
16
|
-
const text = await res.text();
|
|
17
|
-
if (!res.ok)
|
|
18
|
-
return `OA ${res.status}: ${text.slice(0, 600)}`;
|
|
19
|
-
return text.slice(0, 60_000);
|
|
20
|
-
}
|
|
21
|
-
catch (e) {
|
|
22
|
-
return `调用 OA 失败:${e.message}`;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
const needWrite = (ctx) => (!ctx.principal ? "缺少身份(principal),无法代表用户写库;请让调用方带上 x-agent-principal。" : null);
|
|
26
|
-
export function oaTools(ctx) {
|
|
27
|
-
const obj = Type.Object({}, { additionalProperties: true });
|
|
28
|
-
return [
|
|
29
|
-
{ name: "oa_schema", effect: "read", description: "取 OA 数据结构(每类资产的字段/必填/条件必填 requiredWhen/联动 showWhen/枚举、生命周期、表名)。建/改前先调它,别凭记忆。", parameters: Type.Object({}), execute: () => oaFetch(ctx, "/api/v1/meta") },
|
|
30
|
-
{ name: "oa_alerts", effect: "read", description: "派生告警:GP 闲置(已注册未变现) / APP 未上架(已接广告未 LIVE)。", parameters: Type.Object({}), execute: () => oaFetch(ctx, "/api/v1/alerts") },
|
|
31
|
-
{ name: "oa_list", effect: "read", description: "列出某类资产。type∈gp/package/ad-platform/ad-unit/email/environment/proxy。可选 q 关键字。", parameters: Type.Object({ type: Type.String(), q: Type.Optional(Type.String()) }), execute: (a) => { const x = a; return oaFetch(ctx, `/api/v1/entities/${encodeURIComponent(x.type)}${x.q ? `?q=${encodeURIComponent(x.q)}` : ""}`); } },
|
|
32
|
-
{ name: "oa_get", effect: "read", description: "取某资产详情(敏感字段为掩码)。", parameters: Type.Object({ type: Type.String(), id: Type.String() }), execute: (a) => { const x = a; return oaFetch(ctx, `/api/v1/entities/${encodeURIComponent(x.type)}/${encodeURIComponent(x.id)}`); } },
|
|
33
|
-
{ name: "oa_lookup", effect: "read", description: "约定字段值反查(同手机/证件=同一实物)。field: phone|idCardNo|bizLicenseNo。", parameters: Type.Object({ field: Type.String(), value: Type.String() }), execute: (a) => { const x = a; return oaFetch(ctx, `/api/v1/lookup?field=${encodeURIComponent(x.field)}&value=${encodeURIComponent(x.value)}`); } },
|
|
34
|
-
{ name: "oa_create", effect: "write", description: "创建实体(走 OA 校验+当前用户 RBAC+审计)。type + data(字段对象,参照 oa_schema)。失败会返回缺失/非法字段。", parameters: Type.Object({ type: Type.String(), data: obj }), execute: (a) => { const e = needWrite(ctx); if (e)
|
|
35
|
-
return e; const x = a; return oaFetch(ctx, `/api/assets/${encodeURIComponent(x.type)}`, { method: "POST", body: x.data ?? {} }); } },
|
|
36
|
-
{ name: "oa_update", effect: "write", description: "改字段(敏感留空=保持原值;状态字段改不动,用 oa_transition)。", parameters: Type.Object({ type: Type.String(), id: Type.String(), data: obj }), execute: (a) => { const e = needWrite(ctx); if (e)
|
|
37
|
-
return e; const x = a; return oaFetch(ctx, `/api/assets/${encodeURIComponent(x.type)}/${encodeURIComponent(x.id)}`, { method: "PATCH", body: x.data ?? {} }); } },
|
|
38
|
-
{ name: "oa_transition", effect: "write", description: "受控状态流转(先 oa_schema 看可用迁移;风险/弃用等需 note)。", parameters: Type.Object({ type: Type.String(), id: Type.String(), to: Type.String(), note: Type.Optional(Type.String()) }), execute: (a) => { const e = needWrite(ctx); if (e)
|
|
39
|
-
return e; const x = a; return oaFetch(ctx, `/api/assets/${encodeURIComponent(x.type)}/${encodeURIComponent(x.id)}/transition`, { method: "POST", body: { to: x.to, note: x.note ?? null } }); } },
|
|
40
|
-
];
|
|
41
|
-
}
|
|
42
|
-
// OA business prompt MOVED OUT — migration complete (design/29, 2026-06-05). Persona / 工作准则 / UI
|
|
43
|
-
// markers (::FORM:: / ::GOTO:: / ::SUGGEST:: / ::ISSUE_FORM::) / 分级确认 / 报bug流程 are OA's business,
|
|
44
|
-
// and OA now injects the WHOLE thing per request via `request.systemPrompt` (it holds the service token,
|
|
45
|
-
// content is stable per OA version → cacheable prefix; page context still rides `objective`). Keeping
|
|
46
|
-
// any of it here would just DUPLICATE OA's prompt, so the base is EMPTY — single source of truth = OA.
|
|
47
|
-
// The service stays business-agnostic: it provides the oa_* tools (referenced by NAME from OA's prompt;
|
|
48
|
-
// they carry their own descriptions) and nothing else. `stablePrompt` keeps STABLE→VARIABLE order —
|
|
49
|
-
// OA's systemPrompt is appended after this (empty) base, before core's <user_memory>.
|
|
50
|
-
// (::ISSUE_FORM:: is parsed/rendered + submitted entirely by OA's frontend via OA /api/ai/issue — the
|
|
51
|
-
// service never touches it; `open_gitea_issue` remains only as the unattended/automated fallback.)
|
|
52
|
-
const OA_SYSTEM = "";
|
|
53
|
-
export const oaPrompt = stablePrompt(OA_SYSTEM);
|
|
54
|
-
//# sourceMappingURL=oa-tools.js.map
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export interface InfraCostRates {
|
|
2
|
-
toolCallMicroUsd: number;
|
|
3
|
-
sandboxSecMicroUsd: number;
|
|
4
|
-
egressGbMicroUsd: number;
|
|
5
|
-
}
|
|
6
|
-
export interface InfraUsage {
|
|
7
|
-
toolCalls: number;
|
|
8
|
-
sandboxWalltimeMs: number;
|
|
9
|
-
egressBytes: number;
|
|
10
|
-
}
|
|
11
|
-
export interface InfraCostBreakdown {
|
|
12
|
-
toolCallMicroUsd: number;
|
|
13
|
-
sandboxWalltimeMicroUsd: number;
|
|
14
|
-
egressMicroUsd: number;
|
|
15
|
-
totalMicroUsd: number;
|
|
16
|
-
}
|
|
17
|
-
export interface LlmCostBreakdown {
|
|
18
|
-
llmRootMicroUsd: number;
|
|
19
|
-
nestedSubagentMicroUsd: number;
|
|
20
|
-
memoryConsolidationMicroUsd: number;
|
|
21
|
-
compactionMicroUsd: number;
|
|
22
|
-
}
|
|
23
|
-
export interface SupervisorCostBreakdown {
|
|
24
|
-
llm: LlmCostBreakdown | null;
|
|
25
|
-
infra: InfraCostBreakdown;
|
|
26
|
-
totalMicroUsd: number;
|
|
27
|
-
}
|
|
28
|
-
export declare function infraCost(usage: InfraUsage, rates: InfraCostRates): InfraCostBreakdown;
|
|
29
|
-
export declare function composeSupervisorCost(llm: LlmCostBreakdown | null, llmTotalMicroUsd: number, infra: InfraCostBreakdown): SupervisorCostBreakdown;
|
|
30
|
-
export declare function hasInfraPricing(r: InfraCostRates): boolean;
|
|
31
|
-
export declare function infraUsageFromEvents(events: ReadonlyArray<{
|
|
32
|
-
type?: string;
|
|
33
|
-
}>, runDurationMs: number): InfraUsage;
|
|
34
|
-
//# sourceMappingURL=cost-taxonomy.d.ts.map
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const nonNeg = (n) => (Number.isFinite(n) && n > 0 ? n : 0);
|
|
2
|
-
export function infraCost(usage, rates) {
|
|
3
|
-
const toolCallMicroUsd = nonNeg(usage.toolCalls) * nonNeg(rates.toolCallMicroUsd);
|
|
4
|
-
const sandboxWalltimeMicroUsd = (nonNeg(usage.sandboxWalltimeMs) / 1000) * nonNeg(rates.sandboxSecMicroUsd);
|
|
5
|
-
const egressMicroUsd = (nonNeg(usage.egressBytes) / 1_000_000_000) * nonNeg(rates.egressGbMicroUsd);
|
|
6
|
-
return {
|
|
7
|
-
toolCallMicroUsd,
|
|
8
|
-
sandboxWalltimeMicroUsd,
|
|
9
|
-
egressMicroUsd,
|
|
10
|
-
totalMicroUsd: toolCallMicroUsd + sandboxWalltimeMicroUsd + egressMicroUsd,
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
export function composeSupervisorCost(llm, llmTotalMicroUsd, infra) {
|
|
14
|
-
return { llm, infra, totalMicroUsd: nonNeg(llmTotalMicroUsd) + infra.totalMicroUsd };
|
|
15
|
-
}
|
|
16
|
-
export function hasInfraPricing(r) {
|
|
17
|
-
return r.toolCallMicroUsd > 0 || r.sandboxSecMicroUsd > 0 || r.egressGbMicroUsd > 0;
|
|
18
|
-
}
|
|
19
|
-
export function infraUsageFromEvents(events, runDurationMs) {
|
|
20
|
-
return {
|
|
21
|
-
toolCalls: events.reduce((n, e) => (e.type === "tool_start" ? n + 1 : n), 0),
|
|
22
|
-
sandboxWalltimeMs: nonNeg(runDurationMs),
|
|
23
|
-
egressBytes: 0,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=cost-taxonomy.js.map
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Durable approval store for the human-in-the-loop write gate (F4) — SINGLE-FILE DUAL-DIALECT
|
|
3
|
-
* (design/158 A12 定型半场). ONE implementation, TWO dialects; the historical `TiDBApprovalStore` /
|
|
4
|
-
* `PgApprovalStore` class names survive as thin ctor subclasses so every consumer (store-backend.ts,
|
|
5
|
-
* src/index.ts, the approval/audit/security-coverage suites) is untouched.
|
|
6
|
-
*
|
|
7
|
-
* When a gated tool call is about to run, a `pending` row is recorded here; the instance running the
|
|
8
|
-
* task polls it for a decision. Because the row is durable and shared, an operator's approve/deny can
|
|
9
|
-
* land on ANY instance — critical under async runs + a load balancer, where the deciding request and
|
|
10
|
-
* the waiting run are usually on different instances.
|
|
11
|
-
*
|
|
12
|
-
* Unlike the run/checkpoint PG store (whose schema is owned centrally by pg-pool.ts), this file also
|
|
13
|
-
* exports a self-contained PG schema (`PG_APPROVAL_SCHEMA` + `ensureSchema`) — the `approval` table is
|
|
14
|
-
* DISJOINT from the other PG stores' tables, so a CREATE IF NOT EXISTS here shadows nothing. Central
|
|
15
|
-
* aggregation into pg-pool.ts composes it alongside the others. Kept in lock-step with the TiDB store
|
|
16
|
-
* by the shared real-DB integration suite (test/pg-approval-store-integration.test.ts).
|
|
17
|
-
*
|
|
18
|
-
* ── Dialect deltas, kept EXPLICIT ────────────────────────────────────────────────────────────────────
|
|
19
|
-
* - `?` placeholders vs `$n`
|
|
20
|
-
* - null-safe scope compare: `<=>` vs `IS NOT DISTINCT FROM` (a NULL scope row — legacy/untenanted
|
|
21
|
-
* run — is matched by a NULL scope arg; one tenant's scope NEVER matches another's — the
|
|
22
|
-
* single-DB fleet read guard, defense-in-depth)
|
|
23
|
-
* - JSON binding: TiDB `JSON.stringify` verbatim vs PG `pgProtocolJsonStringify` (codex R4-H2: the
|
|
24
|
-
* persisted approval `args` is the operator's REVIEW surface and must agree byte-for-byte with the
|
|
25
|
-
* policy-executed args — a lossy/rewriting envelope would let an operator approve one payload while
|
|
26
|
-
* a different one runs)
|
|
27
|
-
* - affectedRows vs rowCount (via SqlDriver)
|
|
28
|
-
* - schema ownership: TiDB DDL lives in tidb-pool.ts SCHEMA_STATEMENTS; PG DDL is this file's own
|
|
29
|
-
* self-contained `PG_APPROVAL_SCHEMA` (see the PG twin's original header — unlike the other PG
|
|
30
|
-
* stores, `approval` is NOT centrally owned by pg-pool.ts's DDL array, only aggregated into its
|
|
31
|
-
* `ensureSchema` composition).
|
|
32
|
-
* - `getStatus` result shape: `RowDataPacket[]` (mysql2 typed query) vs a plain-record `pg` query —
|
|
33
|
-
* normalized to `SqlRow` by the shared driver, so both arms read the same field names.
|
|
34
|
-
*/
|
|
35
|
-
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
36
|
-
import type { Pool as PgPool, PoolClient } from "pg";
|
|
37
|
-
import { type SqlDriver } from "./sql-driver.js";
|
|
38
|
-
export type ApprovalStatus = "pending" | "approved" | "denied" | "expired";
|
|
39
|
-
export interface ApprovalRow {
|
|
40
|
-
id: string;
|
|
41
|
-
taskId: string | null;
|
|
42
|
-
sessionId: string | null;
|
|
43
|
-
owner: string | null;
|
|
44
|
-
/** Single-DB fleet scope guard (defense-in-depth): the run's tenant identity, owner-sourced. Reads filter on it. */
|
|
45
|
-
scope: string | null;
|
|
46
|
-
toolName: string;
|
|
47
|
-
args: unknown;
|
|
48
|
-
status: ApprovalStatus;
|
|
49
|
-
reason: string | null;
|
|
50
|
-
decidedBy: string | null;
|
|
51
|
-
createdAt: string;
|
|
52
|
-
decidedAt: string | null;
|
|
53
|
-
}
|
|
54
|
-
/** PG translation of the `approval` DDL in tidb-pool.ts SCHEMA_STATEMENTS (JSON→JSONB, DATETIME(3)→TIMESTAMPTZ(3),
|
|
55
|
-
* inline KEY→separate CREATE INDEX).
|
|
56
|
-
*
|
|
57
|
-
* SCHEMA POLICY: see the header of pg-pool.ts — the code is the single source of truth, schema changes are
|
|
58
|
-
* drop-and-recreate, and NO new `ALTER TABLE` seams are added here; fold into the CREATE instead. */
|
|
59
|
-
export declare const PG_APPROVAL_SCHEMA: string[];
|
|
60
|
-
/** Idempotent self-contained schema apply (for the integration test; central aggregation is done separately). */
|
|
61
|
-
export declare function ensureSchema(pool: PgPool | PoolClient): Promise<void>;
|
|
62
|
-
/** Dual-dialect durable approval store. See the file header for the dialect-delta ledger. */
|
|
63
|
-
export declare class SqlApprovalStore {
|
|
64
|
-
protected readonly db: SqlDriver;
|
|
65
|
-
constructor(db: SqlDriver);
|
|
66
|
-
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
67
|
-
private q;
|
|
68
|
-
/** JSON column binding: TiDB stores the string verbatim; PG goes through the LOSSLESS protocol envelope
|
|
69
|
-
* (codex R4-H2 — the approval `args` is the operator's review surface and must agree with the
|
|
70
|
-
* policy-executed args at the NUL position). */
|
|
71
|
-
private json;
|
|
72
|
-
createPending(id: string, scope: string | null, ctx: {
|
|
73
|
-
taskId?: string | null;
|
|
74
|
-
sessionId?: string | null;
|
|
75
|
-
owner?: string | null;
|
|
76
|
-
toolName: string;
|
|
77
|
-
args: unknown;
|
|
78
|
-
}): Promise<void>;
|
|
79
|
-
getStatus(id: string, scope: string | null): Promise<{
|
|
80
|
-
status: ApprovalStatus;
|
|
81
|
-
reason: string | null;
|
|
82
|
-
decidedBy: string | null;
|
|
83
|
-
} | undefined>;
|
|
84
|
-
/** Apply a terminal decision, but only to a still-pending row (CAS). Returns whether it applied. The scope
|
|
85
|
-
* guard (null-safe) is carried on the operator path too for consistency with the read paths. */
|
|
86
|
-
decide(id: string, scope: string | null, decision: "approved" | "denied" | "expired", reason: string | null, decidedBy: string | null): Promise<boolean>;
|
|
87
|
-
/** Pending approvals (operator queue), scoped to one tenant (single-DB fleet read guard, null-safe), optionally
|
|
88
|
-
* further filtered to one owner. */
|
|
89
|
-
listPending(scope: string | null, owner?: string): Promise<ApprovalRow[]>;
|
|
90
|
-
get(id: string, scope: string | null): Promise<ApprovalRow | undefined>;
|
|
91
|
-
/** Operator-only CROSS-tenant by-id read (no scope filter). The F4 operator queue serves/decides across
|
|
92
|
-
* tenants by design; the HTTP layer gates this to an operator and then re-binds decide() to the row's OWN
|
|
93
|
-
* scope. Tenants NEVER reach this — they use the scope-bound {@link get}. */
|
|
94
|
-
getById(id: string): Promise<ApprovalRow | undefined>;
|
|
95
|
-
/** Operator-only CROSS-tenant pending list (no scope filter) — the unfiltered operator queue across all
|
|
96
|
-
* tenants. Tenants use the scope-bound {@link listPending}; this is HTTP-gated to an operator.
|
|
97
|
-
* 🔴 identical SQL text on both dialects (no placeholders, nothing dialect-specific) — kept as ONE literal
|
|
98
|
-
* rather than a `q()` pair so a reader isn't misled into looking for a divergence that isn't there. */
|
|
99
|
-
listPendingAll(): Promise<ApprovalRow[]>;
|
|
100
|
-
/** Expire pending approvals older than `olderThanMs` (a never-answered operator request). Deliberately GLOBAL
|
|
101
|
-
* (NOT scope-filtered): staleness expiry is fleet-level maintenance that protects the worker regardless of
|
|
102
|
-
* tenant — a stale row in any scope must be reaped. Scope isolation applies to the per-tenant READ paths, not
|
|
103
|
-
* to this maintenance sweep. */
|
|
104
|
-
expireStale(olderThanMs: number): Promise<number>;
|
|
105
|
-
}
|
|
106
|
-
/** approval row → {@link ApprovalRow} — shared by BOTH dialects. design/158 S8 归位 / A12 收编. */
|
|
107
|
-
export declare function mapRow(r: Record<string, unknown>): ApprovalRow;
|
|
108
|
-
/** MySQL-protocol (TiDB) binding — historical class name + ctor shape preserved. */
|
|
109
|
-
export declare class TiDBApprovalStore extends SqlApprovalStore {
|
|
110
|
-
constructor(pool: MySqlPool);
|
|
111
|
-
}
|
|
112
|
-
/** PostgreSQL binding — historical class name + ctor shape preserved. */
|
|
113
|
-
export declare class PgApprovalStore extends SqlApprovalStore {
|
|
114
|
-
constructor(pool: PgPool);
|
|
115
|
-
}
|
|
116
|
-
//# sourceMappingURL=approval-store-sql.d.ts.map
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { parseJsonStrict as parseJson, toIsoOrNull as iso } from "./sql-row-helpers.js";
|
|
2
|
-
import { pgProtocolJsonStringify } from "./pg-safe-json.js";
|
|
3
|
-
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
4
|
-
/** PG translation of the `approval` DDL in tidb-pool.ts SCHEMA_STATEMENTS (JSON→JSONB, DATETIME(3)→TIMESTAMPTZ(3),
|
|
5
|
-
* inline KEY→separate CREATE INDEX).
|
|
6
|
-
*
|
|
7
|
-
* SCHEMA POLICY: see the header of pg-pool.ts — the code is the single source of truth, schema changes are
|
|
8
|
-
* drop-and-recreate, and NO new `ALTER TABLE` seams are added here; fold into the CREATE instead. */
|
|
9
|
-
export const PG_APPROVAL_SCHEMA = [
|
|
10
|
-
`CREATE TABLE IF NOT EXISTS approval (
|
|
11
|
-
id VARCHAR(64) NOT NULL,
|
|
12
|
-
task_id VARCHAR(64),
|
|
13
|
-
session_id VARCHAR(64),
|
|
14
|
-
owner VARCHAR(190),
|
|
15
|
-
-- Single-DB fleet scope guard (tenant isolation). NULLABLE on purpose: a NULL-scope row is an untenanted
|
|
16
|
-
-- run, and every read/decide path matches it with \`scope IS NOT DISTINCT FROM $n\` (the PG twin of TiDB
|
|
17
|
-
-- \`<=>\`) so NULL matches only NULL and one tenant's scope NEVER matches another's.
|
|
18
|
-
scope VARCHAR(190),
|
|
19
|
-
tool_name VARCHAR(190) NOT NULL,
|
|
20
|
-
args JSONB,
|
|
21
|
-
status VARCHAR(16) NOT NULL,
|
|
22
|
-
reason TEXT,
|
|
23
|
-
decided_by VARCHAR(190),
|
|
24
|
-
created_at TIMESTAMPTZ(3) NOT NULL,
|
|
25
|
-
decided_at TIMESTAMPTZ(3),
|
|
26
|
-
PRIMARY KEY (id)
|
|
27
|
-
)`,
|
|
28
|
-
`CREATE INDEX IF NOT EXISTS idx_approval_owner_status ON approval (owner, status)`,
|
|
29
|
-
`CREATE INDEX IF NOT EXISTS idx_approval_status ON approval (status)`,
|
|
30
|
-
`CREATE INDEX IF NOT EXISTS idx_approval_scope_status ON approval (scope, status)`,
|
|
31
|
-
];
|
|
32
|
-
/** Idempotent self-contained schema apply (for the integration test; central aggregation is done separately). */
|
|
33
|
-
export async function ensureSchema(pool) {
|
|
34
|
-
for (const stmt of PG_APPROVAL_SCHEMA)
|
|
35
|
-
await pool.query(stmt);
|
|
36
|
-
}
|
|
37
|
-
/** Dual-dialect durable approval store. See the file header for the dialect-delta ledger. */
|
|
38
|
-
export class SqlApprovalStore {
|
|
39
|
-
db;
|
|
40
|
-
constructor(db) {
|
|
41
|
-
this.db = db;
|
|
42
|
-
}
|
|
43
|
-
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
44
|
-
q(tidb, pg) {
|
|
45
|
-
return this.db.dialect === "tidb" ? tidb : pg;
|
|
46
|
-
}
|
|
47
|
-
/** JSON column binding: TiDB stores the string verbatim; PG goes through the LOSSLESS protocol envelope
|
|
48
|
-
* (codex R4-H2 — the approval `args` is the operator's review surface and must agree with the
|
|
49
|
-
* policy-executed args at the NUL position). */
|
|
50
|
-
json(value, label) {
|
|
51
|
-
return this.db.dialect === "tidb" ? JSON.stringify(value) : pgProtocolJsonStringify(value, label);
|
|
52
|
-
}
|
|
53
|
-
async createPending(id, scope, ctx) {
|
|
54
|
-
await this.db.query(this.q("INSERT INTO approval (id, task_id, session_id, owner, scope, tool_name, args, status, created_at) " +
|
|
55
|
-
"VALUES (?,?,?,?,?,?,?,'pending',?)", "INSERT INTO approval (id, task_id, session_id, owner, scope, tool_name, args, status, created_at) " +
|
|
56
|
-
"VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,'pending',$8)"), [
|
|
57
|
-
id,
|
|
58
|
-
ctx.taskId ?? null,
|
|
59
|
-
ctx.sessionId ?? null,
|
|
60
|
-
ctx.owner ?? null,
|
|
61
|
-
scope,
|
|
62
|
-
ctx.toolName,
|
|
63
|
-
ctx.args == null ? null : this.json(ctx.args, "approval args"),
|
|
64
|
-
new Date(),
|
|
65
|
-
]);
|
|
66
|
-
}
|
|
67
|
-
async getStatus(id, scope) {
|
|
68
|
-
// null-safe scope match (`<=>` / `IS NOT DISTINCT FROM`): a NULL scope row (legacy / untenanted run) is
|
|
69
|
-
// matched by a NULL scope arg, and a tenant's scope NEVER matches another tenant's — the single-DB fleet
|
|
70
|
-
// read guard (defense-in-depth).
|
|
71
|
-
const { rows } = await this.db.query(this.q("SELECT status, reason, decided_by FROM approval WHERE id = ? AND scope <=> ?", "SELECT status, reason, decided_by FROM approval WHERE id = $1 AND scope IS NOT DISTINCT FROM $2"), [id, scope]);
|
|
72
|
-
const r = rows[0];
|
|
73
|
-
if (!r)
|
|
74
|
-
return undefined;
|
|
75
|
-
return { status: r.status, reason: r.reason ?? null, decidedBy: r.decided_by ?? null };
|
|
76
|
-
}
|
|
77
|
-
/** Apply a terminal decision, but only to a still-pending row (CAS). Returns whether it applied. The scope
|
|
78
|
-
* guard (null-safe) is carried on the operator path too for consistency with the read paths. */
|
|
79
|
-
async decide(id, scope, decision, reason, decidedBy) {
|
|
80
|
-
const res = await this.db.query(this.q("UPDATE approval SET status = ?, reason = ?, decided_by = ?, decided_at = ? WHERE id = ? AND scope <=> ? AND status = 'pending'", "UPDATE approval SET status = $1, reason = $2, decided_by = $3, decided_at = $4 WHERE id = $5 AND scope IS NOT DISTINCT FROM $6 AND status = 'pending'"), [decision, reason, decidedBy, new Date(), id, scope]);
|
|
81
|
-
return res.affected === 1;
|
|
82
|
-
}
|
|
83
|
-
/** Pending approvals (operator queue), scoped to one tenant (single-DB fleet read guard, null-safe), optionally
|
|
84
|
-
* further filtered to one owner. */
|
|
85
|
-
async listPending(scope, owner) {
|
|
86
|
-
const { rows } = owner
|
|
87
|
-
? await this.db.query(this.q("SELECT * FROM approval WHERE status = 'pending' AND scope <=> ? AND owner = ? ORDER BY created_at ASC", "SELECT * FROM approval WHERE status = 'pending' AND scope IS NOT DISTINCT FROM $1 AND owner = $2 ORDER BY created_at ASC"), [scope, owner])
|
|
88
|
-
: await this.db.query(this.q("SELECT * FROM approval WHERE status = 'pending' AND scope <=> ? ORDER BY created_at ASC", "SELECT * FROM approval WHERE status = 'pending' AND scope IS NOT DISTINCT FROM $1 ORDER BY created_at ASC"), [scope]);
|
|
89
|
-
return rows.map(mapRow);
|
|
90
|
-
}
|
|
91
|
-
async get(id, scope) {
|
|
92
|
-
const { rows } = await this.db.query(this.q("SELECT * FROM approval WHERE id = ? AND scope <=> ?", "SELECT * FROM approval WHERE id = $1 AND scope IS NOT DISTINCT FROM $2"), [id, scope]);
|
|
93
|
-
return rows[0] ? mapRow(rows[0]) : undefined;
|
|
94
|
-
}
|
|
95
|
-
/** Operator-only CROSS-tenant by-id read (no scope filter). The F4 operator queue serves/decides across
|
|
96
|
-
* tenants by design; the HTTP layer gates this to an operator and then re-binds decide() to the row's OWN
|
|
97
|
-
* scope. Tenants NEVER reach this — they use the scope-bound {@link get}. */
|
|
98
|
-
async getById(id) {
|
|
99
|
-
const { rows } = await this.db.query(this.q("SELECT * FROM approval WHERE id = ?", "SELECT * FROM approval WHERE id = $1"), [id]);
|
|
100
|
-
return rows[0] ? mapRow(rows[0]) : undefined;
|
|
101
|
-
}
|
|
102
|
-
/** Operator-only CROSS-tenant pending list (no scope filter) — the unfiltered operator queue across all
|
|
103
|
-
* tenants. Tenants use the scope-bound {@link listPending}; this is HTTP-gated to an operator.
|
|
104
|
-
* 🔴 identical SQL text on both dialects (no placeholders, nothing dialect-specific) — kept as ONE literal
|
|
105
|
-
* rather than a `q()` pair so a reader isn't misled into looking for a divergence that isn't there. */
|
|
106
|
-
async listPendingAll() {
|
|
107
|
-
const { rows } = await this.db.query("SELECT * FROM approval WHERE status = 'pending' ORDER BY created_at ASC");
|
|
108
|
-
return rows.map(mapRow);
|
|
109
|
-
}
|
|
110
|
-
/** Expire pending approvals older than `olderThanMs` (a never-answered operator request). Deliberately GLOBAL
|
|
111
|
-
* (NOT scope-filtered): staleness expiry is fleet-level maintenance that protects the worker regardless of
|
|
112
|
-
* tenant — a stale row in any scope must be reaped. Scope isolation applies to the per-tenant READ paths, not
|
|
113
|
-
* to this maintenance sweep. */
|
|
114
|
-
async expireStale(olderThanMs) {
|
|
115
|
-
const cutoff = new Date(Date.now() - olderThanMs);
|
|
116
|
-
const res = await this.db.query(this.q("UPDATE approval SET status = 'expired', reason = 'timed out before decision', decided_at = ? " +
|
|
117
|
-
"WHERE status = 'pending' AND created_at < ?", "UPDATE approval SET status = 'expired', reason = 'timed out before decision', decided_at = $1 " +
|
|
118
|
-
"WHERE status = 'pending' AND created_at < $2"), [new Date(), cutoff]);
|
|
119
|
-
return res.affected;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/** approval row → {@link ApprovalRow} — shared by BOTH dialects. design/158 S8 归位 / A12 收编. */
|
|
123
|
-
export function mapRow(r) {
|
|
124
|
-
return {
|
|
125
|
-
id: String(r.id),
|
|
126
|
-
taskId: r.task_id ?? null,
|
|
127
|
-
sessionId: r.session_id ?? null,
|
|
128
|
-
owner: r.owner ?? null,
|
|
129
|
-
scope: r.scope ?? null,
|
|
130
|
-
toolName: String(r.tool_name),
|
|
131
|
-
args: parseJson(r.args),
|
|
132
|
-
status: r.status,
|
|
133
|
-
reason: r.reason ?? null,
|
|
134
|
-
decidedBy: r.decided_by ?? null,
|
|
135
|
-
createdAt: iso(r.created_at),
|
|
136
|
-
decidedAt: iso(r.decided_at),
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
/** MySQL-protocol (TiDB) binding — historical class name + ctor shape preserved. */
|
|
140
|
-
export class TiDBApprovalStore extends SqlApprovalStore {
|
|
141
|
-
constructor(pool) {
|
|
142
|
-
super(mysqlDriver(pool));
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
/** PostgreSQL binding — historical class name + ctor shape preserved. */
|
|
146
|
-
export class PgApprovalStore extends SqlApprovalStore {
|
|
147
|
-
constructor(pool) {
|
|
148
|
-
super(pgDriver(pool));
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
//# sourceMappingURL=approval-store-sql.js.map
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SVC-2 — FILE-backed durable WorkflowJournalStore for the LOCAL (TOC) backend.
|
|
3
|
-
*
|
|
4
|
-
* Now a RE-EXPORT of core's copy (the write-here-then-core-adopts 剧本): the implementation was written here for server
|
|
5
|
-
* 1.89.0, then adopted verbatim by core (`@sema-agent/core` 1.223.0, file
|
|
6
|
-
* `src/stores/file/workflow-journal-store.ts` — crash-safe per-run JSONL, scope-guarded [CORE-9],
|
|
7
|
-
* idempotent-per-ordinal, oversize skip-journal, traversal-runId load degrade, 0o600/0o700). One source of
|
|
8
|
-
* truth in core; the SQL twins (tidb/pg) stay service-side (dialect = deployment glue). The service test
|
|
9
|
-
* suite (test/file-workflow-journal-store.test.ts) keeps pinning the contract through this re-export.
|
|
10
|
-
*/
|
|
11
|
-
export { FileWorkflowJournalStore } from "@sema-agent/core";
|
|
12
|
-
//# sourceMappingURL=file-workflow-journal-store.d.ts.map
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SVC-2 — FILE-backed durable WorkflowJournalStore for the LOCAL (TOC) backend.
|
|
3
|
-
*
|
|
4
|
-
* Now a RE-EXPORT of core's copy (the write-here-then-core-adopts 剧本): the implementation was written here for server
|
|
5
|
-
* 1.89.0, then adopted verbatim by core (`@sema-agent/core` 1.223.0, file
|
|
6
|
-
* `src/stores/file/workflow-journal-store.ts` — crash-safe per-run JSONL, scope-guarded [CORE-9],
|
|
7
|
-
* idempotent-per-ordinal, oversize skip-journal, traversal-runId load degrade, 0o600/0o700). One source of
|
|
8
|
-
* truth in core; the SQL twins (tidb/pg) stay service-side (dialect = deployment glue). The service test
|
|
9
|
-
* suite (test/file-workflow-journal-store.test.ts) keeps pinning the contract through this re-export.
|
|
10
|
-
*/
|
|
11
|
-
export { FileWorkflowJournalStore } from "@sema-agent/core";
|
|
12
|
-
//# sourceMappingURL=file-workflow-journal-store.js.map
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin re-export shim (design/158 A12 收编 — see src/plugins/approval-store-sql.ts for the
|
|
3
|
-
* implementation, now SINGLE-FILE DUAL-DIALECT alongside the TiDB twin). Class name, ctor arity,
|
|
4
|
-
* and every exported type/const/helper stay EXACTLY as they were so no consumer (pg-pool.ts's
|
|
5
|
-
* central schema composition, store-backend.ts, test/pg-approval-store-integration.test.ts) has
|
|
6
|
-
* to move.
|
|
7
|
-
*/
|
|
8
|
-
export { PgApprovalStore, PG_APPROVAL_SCHEMA, ensureSchema, type ApprovalRow, type ApprovalStatus, } from "./approval-store-sql.js";
|
|
9
|
-
//# sourceMappingURL=pg-approval-store.d.ts.map
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin re-export shim (design/158 A12 收编 — see src/plugins/approval-store-sql.ts for the
|
|
3
|
-
* implementation, now SINGLE-FILE DUAL-DIALECT alongside the TiDB twin). Class name, ctor arity,
|
|
4
|
-
* and every exported type/const/helper stay EXACTLY as they were so no consumer (pg-pool.ts's
|
|
5
|
-
* central schema composition, store-backend.ts, test/pg-approval-store-integration.test.ts) has
|
|
6
|
-
* to move.
|
|
7
|
-
*/
|
|
8
|
-
export { PgApprovalStore, PG_APPROVAL_SCHEMA, ensureSchema, } from "./approval-store-sql.js";
|
|
9
|
-
//# sourceMappingURL=pg-approval-store.js.map
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Re-export shim (design/158 A12 收编) — the real implementation moved to breaker-state-sql.ts
|
|
3
|
-
* (single-file dual-dialect: `SqlBreakerState` + the `TiDBBreakerState`/`PgBreakerState` ctor subclasses).
|
|
4
|
-
* Kept so every consumer's `from "./pg-breaker-state.js"` import (incl. pg-pool.ts's central ensureSchema
|
|
5
|
-
* composition and the real dual-DB integration suite) keeps working unchanged.
|
|
6
|
-
*/
|
|
7
|
-
export { PgBreakerState, PG_BREAKER_STATE_SCHEMA, ensureSchema } from "./breaker-state-sql.js";
|
|
8
|
-
//# sourceMappingURL=pg-breaker-state.d.ts.map
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Re-export shim (design/158 A12 收编) — the real implementation moved to breaker-state-sql.ts
|
|
3
|
-
* (single-file dual-dialect: `SqlBreakerState` + the `TiDBBreakerState`/`PgBreakerState` ctor subclasses).
|
|
4
|
-
* Kept so every consumer's `from "./pg-breaker-state.js"` import (incl. pg-pool.ts's central ensureSchema
|
|
5
|
-
* composition and the real dual-DB integration suite) keeps working unchanged.
|
|
6
|
-
*/
|
|
7
|
-
export { PgBreakerState, PG_BREAKER_STATE_SCHEMA, ensureSchema } from "./breaker-state-sql.js";
|
|
8
|
-
//# sourceMappingURL=pg-breaker-state.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PostgreSQL `CheckpointStore` — the implementation now lives in the single-file dual-dialect
|
|
3
|
-
* `checkpoint-store-sql.ts` (design/158 A12 定型半场), alongside its TiDB twin so the dialect deltas
|
|
4
|
-
* (placeholders, ON CONFLICT, `IS NOT DISTINCT FROM` + its placeholder-arity consequence, the lossless
|
|
5
|
-
* JSON envelope) read side by side instead of drifting across two files.
|
|
6
|
-
*
|
|
7
|
-
* This file is the historical import path: class name and ctor shape unchanged.
|
|
8
|
-
*/
|
|
9
|
-
export { PgCheckpointStore } from "./checkpoint-store-sql.js";
|
|
10
|
-
//# sourceMappingURL=pg-checkpoint-store.d.ts.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PostgreSQL `CheckpointStore` — the implementation now lives in the single-file dual-dialect
|
|
3
|
-
* `checkpoint-store-sql.ts` (design/158 A12 定型半场), alongside its TiDB twin so the dialect deltas
|
|
4
|
-
* (placeholders, ON CONFLICT, `IS NOT DISTINCT FROM` + its placeholder-arity consequence, the lossless
|
|
5
|
-
* JSON envelope) read side by side instead of drifting across two files.
|
|
6
|
-
*
|
|
7
|
-
* This file is the historical import path: class name and ctor shape unchanged.
|
|
8
|
-
*/
|
|
9
|
-
export { PgCheckpointStore } from "./checkpoint-store-sql.js";
|
|
10
|
-
//# sourceMappingURL=pg-checkpoint-store.js.map
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin re-export shim (design/158 A12 定型半场) — the real implementation collapsed into
|
|
3
|
-
* `file-snapshot-store-sql.ts` (single file, dual dialect). Kept so every existing import path
|
|
4
|
-
* (store-backend.ts, the migration script, the contract/integration/minio-equivalence suites) is
|
|
5
|
-
* untouched: same class name, same ctor arity, same exported surface.
|
|
6
|
-
*/
|
|
7
|
-
export { PgFileSnapshotStore } from "./file-snapshot-store-sql.js";
|
|
8
|
-
//# sourceMappingURL=pg-file-snapshot-store.d.ts.map
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin re-export shim (design/158 A12 定型半场) — the real implementation collapsed into
|
|
3
|
-
* `file-snapshot-store-sql.ts` (single file, dual dialect). Kept so every existing import path
|
|
4
|
-
* (store-backend.ts, the migration script, the contract/integration/minio-equivalence suites) is
|
|
5
|
-
* untouched: same class name, same ctor arity, same exported surface.
|
|
6
|
-
*/
|
|
7
|
-
export { PgFileSnapshotStore } from "./file-snapshot-store-sql.js";
|
|
8
|
-
//# sourceMappingURL=pg-file-snapshot-store.js.map
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PostgreSQL BAKE store — the implementation now lives in the single-file dual-dialect
|
|
3
|
-
* `image-bake-store-sql.ts` (design/158 A12 定型半场), alongside its TiDB twin so the dialect deltas
|
|
4
|
-
* (placeholders, ON CONFLICT, jsonb casts, the admission-statement divergence, the PG-only
|
|
5
|
-
* protocol-byte defenses) read side by side instead of drifting across two files.
|
|
6
|
-
*
|
|
7
|
-
* This file is the historical import path: class name, ctor shape, `PG_IMAGE_BAKE_SCHEMA` and
|
|
8
|
-
* `ensureSchema` are unchanged, so pg-pool.ts / store-backend.ts / the integration suite are untouched.
|
|
9
|
-
*/
|
|
10
|
-
export { PgImageBake, PG_IMAGE_BAKE_SCHEMA, ensurePgImageBakeSchema as ensureSchema } from "./image-bake-store-sql.js";
|
|
11
|
-
export type { BakeStatus, BakeState, BakeErrorCode, BakeRecord, BakeEvent, CreateBakeInput, BakeTerminal, } from "./store-contracts.js";
|
|
12
|
-
//# sourceMappingURL=pg-image-bake.d.ts.map
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PostgreSQL BAKE store — the implementation now lives in the single-file dual-dialect
|
|
3
|
-
* `image-bake-store-sql.ts` (design/158 A12 定型半场), alongside its TiDB twin so the dialect deltas
|
|
4
|
-
* (placeholders, ON CONFLICT, jsonb casts, the admission-statement divergence, the PG-only
|
|
5
|
-
* protocol-byte defenses) read side by side instead of drifting across two files.
|
|
6
|
-
*
|
|
7
|
-
* This file is the historical import path: class name, ctor shape, `PG_IMAGE_BAKE_SCHEMA` and
|
|
8
|
-
* `ensureSchema` are unchanged, so pg-pool.ts / store-backend.ts / the integration suite are untouched.
|
|
9
|
-
*/
|
|
10
|
-
export { PgImageBake, PG_IMAGE_BAKE_SCHEMA, ensurePgImageBakeSchema as ensureSchema } from "./image-bake-store-sql.js";
|
|
11
|
-
//# sourceMappingURL=pg-image-bake.js.map
|