@sema-agent/client-core 0.59.2 → 0.60.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/CHANGELOG.md +192 -0
- package/README.md +3 -2
- package/dist/adapt/toolCards.d.ts +2 -1
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +24 -4
- package/dist/adapter/downstream/eventToSdkMessage.js +42 -70
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +27 -22
- package/dist/adapter/downstream/terminalToSdkResult.js +47 -30
- package/dist/adapter/runStream.js +27 -11
- package/dist/engineCapsCache.d.ts +27 -0
- package/dist/engineCapsCache.js +29 -0
- package/dist/engineErrorCodes.d.ts +12 -0
- package/dist/engineErrorCodes.js +13 -0
- package/dist/gateOutcome.d.ts +157 -0
- package/dist/gateOutcome.js +181 -0
- package/dist/headlessReconnectWire.js +9 -2
- package/dist/hitl/askParkRowRouting.d.ts +2 -0
- package/dist/hitl/askParkRowRouting.js +17 -2
- package/dist/hitl/frameRouter.d.ts +2 -2
- package/dist/hitl/frameRouter.js +49 -35
- package/dist/hitl/hitlBridge.d.ts +49 -2
- package/dist/hitl/hitlBridge.js +22 -1
- package/dist/hitl/parkResolver.d.ts +3 -1
- package/dist/hitl/parkResolver.js +15 -5
- package/dist/hitl/planReviewWire.d.ts +8 -1
- package/dist/hitl/planReviewWire.js +18 -7
- package/dist/hitl/toolApprovalWire.d.ts +37 -3
- package/dist/hitl/toolApprovalWire.js +36 -9
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/printToolResultFrame.d.ts +34 -49
- package/dist/resumeRefusalCopy.d.ts +12 -4
- package/dist/resumeRefusalCopy.js +15 -5
- package/dist/runTerminal.d.ts +194 -0
- package/dist/runTerminal.js +189 -0
- package/dist/sqlEngineCapability.d.ts +11 -1
- package/dist/sqlEngineCapability.js +13 -1
- package/dist/writeProtectionCapability.d.ts +142 -0
- package/dist/writeProtectionCapability.js +224 -0
- package/docs/INTEGRATION-CLIENTS.md +325 -11
- package/package.json +3 -3
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/runTerminal.ts — 一次 run **怎么结束的**:两代 wire 字节 → 一个带标读数(0.60.0)。
|
|
3
|
+
*
|
|
4
|
+
* ── 上游形变(engine ≥7.64.0 / sdk 8.4.0;wire BREAKING)────────────────────────────────────
|
|
5
|
+
* 7.63.0 及以前,终局要从并列的**八个可选平面键**里拼:`status` / `errorCode` / `errorMessage` /
|
|
6
|
+
* `blockedReason` / `checkpointToken` / `checkpointId` / `checkpointGate` / `workspaceRestoreMode`。
|
|
7
|
+
* 哪些组合合法只活在引擎那条 if/else 阶梯里,读的人只能靠**缺席**推断。7.64.0 起它是**形状**:
|
|
8
|
+
* `TaskResult.terminal`(四臂 `completed | failed | blocked | paused`),八个平面键从型面整删。
|
|
9
|
+
*
|
|
10
|
+
* ── 本模块存在的理由:两代字节,一个读器 ─────────────────────────────────────────────────────
|
|
11
|
+
* 🔴 **这不是「留一条旧引擎兼容读」**(那条本批刻意不留:peer 地板抬到 `>=8.4.0`,7.63.0 及以前的
|
|
12
|
+
* 引擎不在本版支持窗内)。本模块的第二代臂认的是**同一台 ≥7.64.0 引擎**在两条路上真会送来的
|
|
13
|
+
* 扁平字节,两条都有出处:
|
|
14
|
+
* ① **读盘面**(上游逐字点名):`GET /v1/runs/:id` 的 `result` 是存储 blob 的**逐字透传**
|
|
15
|
+
* (server 不补 `terminal`),durable 账本回放出来的 `done` 行同理 —— 一台跨 7.64.0 升级过的
|
|
16
|
+
* 部署上,升级**之前**落盘的那些行读出来仍是平面形;
|
|
17
|
+
* ② **拒绝信封**:SSE 提交腿的 409(`conflict.session_active_run`)是 **server 自己的**拒绝帧、
|
|
18
|
+
* 不是引擎结果,这次形变没动它 —— 它带扁平 `status:"failed"` + `errorCode`,不带 `terminal`;
|
|
19
|
+
* ③ **同步提交直接撞上暂停**(engine 7.64.0 真机黑盒 + server 回帖确认):`POST /v1/tasks`
|
|
20
|
+
* 若当场停在一道审批门上,200 回体是 **server 自造的一只形** ——
|
|
21
|
+
* `{ taskId, sessionId, status: "suspended" | "needs_review" }`,**既没有退役的八个平面键、
|
|
22
|
+
* 也没有 `terminal`**,它**不是** `TaskResult`(是独立于它的另一个体)。它既不是历史字节
|
|
23
|
+
* 也不是拒绝信封,是**活流腿上的第三个来源**,而且它说的是一句正面事实(「这条 run park 了」)。
|
|
24
|
+
* 🔴 因此这一形上**连门都没有**(`checkpointGate` / `terminal.paused.gate` 两处皆缺)——
|
|
25
|
+
* 「这是复核还是交互作答」只能从那个 `status` 词读,见 {@link RunTerminalPausedRead.flatStatus}。
|
|
26
|
+
* ⇒ 判别位就是上游钉的那一个:**`"terminal" in result`**。在场 = 因由形,缺席 = 扁平形。
|
|
27
|
+
* 🔴 **「缺席」不许折成 `completed` / `failed`**(真机黑盒点名的那条边界):`terminal` 缺席时,
|
|
28
|
+
* 读器要么按扁平词给出**对应的那一臂**(`suspended` ⇒ paused,不是 completed 也不是 failed),
|
|
29
|
+
* 要么在连词都没有时返回 `null`(见 {@link readRunTerminal} 的 `null` 语义)。**非终态**词
|
|
30
|
+
* (`running` / 未来的排队词)落 `unknown` 臂 —— 那是「这不是一个我认得的终局」,同样**不是**成功。
|
|
31
|
+
* `GET /v1/runs/:id` 对**暂停中**的 run 读不到 `result`,那一格连载体都没有,本读器答 `null`。
|
|
32
|
+
* 🔴 **两代读数在出口上带标**({@link RunTerminalRead.plane}):不带标就等于对消费端说「这两种字节
|
|
33
|
+
* 没有区别」,而它们在**能不能出现新键**这件事上区别很大(平面形是停产的写者留下的历史字节,
|
|
34
|
+
* 永远不会长出新位)。带标也让门可以对「哪一条腿读到了哪一代」下断言。
|
|
35
|
+
*
|
|
36
|
+
* ── 判据纪律 ────────────────────────────────────────────────────────────────────────────────
|
|
37
|
+
* 🔴 **不认识的终态词绝不折成成功**(本仓 [884]A1 / [909]B1 两次实锤事故的常驻结论):四臂之外的
|
|
38
|
+
* `terminal.kind`、平面形里四词之外的 `status`,一律落 {@link RunTerminalRead} 的 `unknown` 臂并
|
|
39
|
+
* **逐字带回那个词**,由消费点渲成「非成功终态」。整个读器只有一条路返回 `null`:**连终态词都
|
|
40
|
+
* 没有**(mock 车道 / 不带 status 的旧合成帧)—— 那一格的既有语义(落成功臂)由消费点保留。
|
|
41
|
+
* 🔴 **`code` 结构上只属于失败**:因由形下 `completed` / `blocked` / `paused` 上**写不出**码。
|
|
42
|
+
* `blocked` / `paused` / `unknown` 三臂仍声明了 `code?`,那一位**只可能**来自平面形盘上字节
|
|
43
|
+
* (旧写者把 `errorCode` 与 `status` 平铺,`review.pending` 就骑在 park 行上)—— 丢掉它等于在
|
|
44
|
+
* 回放历史行时把盘上真有的事实抹掉。因由形上它恒缺席,判据用 `plane`。
|
|
45
|
+
* 🔴 **`token` 席位永不上 wire**:paused 因由与 `failed.nestedPause` 都不带恢复凭据(上游在两条
|
|
46
|
+
* 够得着的路径上摘它)。本读器同样一个字节都不碰它,也不给它留位。
|
|
47
|
+
* 🔴 **不复制上游的投影**:本模块**不**提供「因由 → 五词 `status`」的兼容投影。同一个事实在这条
|
|
48
|
+
* wire 上有两个真源之后,消费端会分成「读因由的」和「读投影的」两派,而下一次形变时后者全部
|
|
49
|
+
* 无声地错(sdk 顶注逐字同规)。要旧词的消费点自己按 `kind` 分支。
|
|
50
|
+
*/
|
|
51
|
+
import type { CheckpointGate } from '@sema-agent/sdk';
|
|
52
|
+
/**
|
|
53
|
+
* 这条读数出自哪一代字节。
|
|
54
|
+
* · `cause` —— 现行的带标因由形(`result.terminal` 在场);
|
|
55
|
+
* · `flat` —— 扁平形。**两个来源同形不可分**,所以刻意共用一个词:①升级前落盘、由读盘面逐字
|
|
56
|
+
* 回放的历史行;②server 自己的 409 拒绝信封(它从来就是扁平的,这次形变没动它)。
|
|
57
|
+
* 🔴 拿 `stats` 在场性去分这两源是**假判据**:本包的抢救腿(从 run row 合成的 done 帧)本来就
|
|
58
|
+
* 可能不带 `stats`(见 `terminalToSdkResult` 的 ADAPTER-1/-2 收口注),那条判据会把它误判成拒绝
|
|
59
|
+
* 信封。两源的**投影处置完全相同**,所以不分反而是诚实的。
|
|
60
|
+
*/
|
|
61
|
+
export type RunTerminalPlane = 'cause' | 'flat';
|
|
62
|
+
/** paused 因由的**结构视图**(`token` 席位不在这里,也不在 wire 上)。 */
|
|
63
|
+
export interface RunTerminalPause {
|
|
64
|
+
/** **哪一道**暂停 —— 谁/什么必须来恢复它。开集读(词表属主是引擎)。 */
|
|
65
|
+
gate?: CheckpointGate;
|
|
66
|
+
/** 这次暂停的**非密**稳定身份;pre-identity 的老 checkpoint 上缺席。 */
|
|
67
|
+
checkpointId?: string;
|
|
68
|
+
/**
|
|
69
|
+
* 被暂停任务的远端工作区**怎么回来**:`snapshot`(VM 挂起成快照)/ `park_only`(环境自陈不可
|
|
70
|
+
* 挂起 —— 机器继续跑、继续花钱)。**缺席 = 进程内暂停**(没有远端工作区被捕获)。
|
|
71
|
+
* 🔴 型面**不收窄成那两个词**:词表属主是引擎,抄一份会把新词吞成缺席。
|
|
72
|
+
*/
|
|
73
|
+
restoreMode?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* paused 臂的整只读数 —— {@link RunTerminalPause} 三座 + 判别位。
|
|
77
|
+
*
|
|
78
|
+
* 🔴 **抽名而不是写成交叉形**(`{…} & RunTerminalPause`):交叉形的左操作数是一个内联匿名形,
|
|
79
|
+
* typeshape 门的 B4 棘轮按设计把它算进「导出签名里的内联匿名形」——而具名 interface 正是那条
|
|
80
|
+
* 棘轮点名的替代品。`extends` 同时保住了三座的**单一真源**(顶层 paused 臂与
|
|
81
|
+
* `failed.nestedPause` 读的是同一个形,两处各写一份必漂)。
|
|
82
|
+
*/
|
|
83
|
+
export interface RunTerminalPausedRead extends RunTerminalPause {
|
|
84
|
+
kind: 'paused';
|
|
85
|
+
plane: RunTerminalPlane;
|
|
86
|
+
/** 见 {@link RunTerminalRead} 顶注:只可能来自扁平形盘上字节。 */
|
|
87
|
+
code?: string;
|
|
88
|
+
/**
|
|
89
|
+
* 扁平形上那个退役的 status 词(`suspended` / `needs_review`)—— **因由形上恒缺席**。
|
|
90
|
+
*
|
|
91
|
+
* 🔴 **它不是「留一条兼容读」,是这一形上唯一存在的信号**(server 回帖确认):同步提交腿命中
|
|
92
|
+
* park 时,server 自造的 200 体 `{taskId, sessionId, status}` **连门都不带** ⇒
|
|
93
|
+
* {@link runTerminalGateKind} 在那一形上恒 `undefined`,「这是复核还是交互作答」除了这个词
|
|
94
|
+
* 再没有第二个来源。把它丢掉 = 那一形的 plan-review 卡与终帧措辞**全部**落到「交互作答」那一句上。
|
|
95
|
+
* 🔴 仍然**不做因由 → 五词 status 的反向投影**:本位只在扁平形上原样带回读到的那一个词,
|
|
96
|
+
* 因由形上不铸(读器一个词都不猜)。
|
|
97
|
+
*/
|
|
98
|
+
flatStatus?: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 一次 run 的终局读数。`kind` 是判别位。
|
|
102
|
+
*
|
|
103
|
+
* ⚠️ 与 sdk `TerminalCause` 的差别只有两处,都是**防御读**逼出来的:①多一条 `unknown` 臂
|
|
104
|
+
* (四臂之外的词不许落成功);②`blocked` / `paused` / `unknown` 上多一个 `code?`(平面形盘上字节
|
|
105
|
+
* 才可能有,见模块顶注)。其余逐位同义。
|
|
106
|
+
*/
|
|
107
|
+
export type RunTerminalRead = {
|
|
108
|
+
kind: 'completed';
|
|
109
|
+
plane: RunTerminalPlane;
|
|
110
|
+
} | {
|
|
111
|
+
kind: 'failed';
|
|
112
|
+
plane: RunTerminalPlane;
|
|
113
|
+
/** 这次失败带的**机器码**(开集,点分命名空间;缺席 = 这次失败本来就没有码)。 */
|
|
114
|
+
code?: string;
|
|
115
|
+
/** 人类可读的失败文本;没有就缺席。 */
|
|
116
|
+
message?: string;
|
|
117
|
+
/**
|
|
118
|
+
* 这次失败**顶替的那次耐久暂停** —— 只在**嵌套硬边界**(verify / cascade)上出现:嵌套腿停在
|
|
119
|
+
* 一道耐久门上而编排器驱动不了 resume,于是在它的边界上如实报 failed,同时把那次 park 的因由
|
|
120
|
+
* 整只带在这里。引擎自己组装的失败上恒缺席;平面形上**结构性缺席**(旧写者没有这个位)。
|
|
121
|
+
*/
|
|
122
|
+
nestedPause?: RunTerminalPause;
|
|
123
|
+
} | {
|
|
124
|
+
kind: 'blocked';
|
|
125
|
+
plane: RunTerminalPlane;
|
|
126
|
+
/** agent 为什么完不成(治理判决不是失败)。缺席 = 引擎没给因由,**不是**「没被挡」。 */
|
|
127
|
+
reason?: string;
|
|
128
|
+
/** 见模块顶注:只可能来自平面形。 */
|
|
129
|
+
code?: string;
|
|
130
|
+
} | RunTerminalPausedRead | {
|
|
131
|
+
/** 四臂之外的终态词、**或一座读不出的因由** —— 两者都**绝不折成成功**。 */
|
|
132
|
+
kind: 'unknown';
|
|
133
|
+
plane: RunTerminalPlane;
|
|
134
|
+
/**
|
|
135
|
+
* 那个本读器不认识的词(因由形取 `terminal.kind`,扁平形取 `status`),逐字。
|
|
136
|
+
* 🔴 **缺席 = 那一座在场但整个读不出**(`terminal` 是 `null` / 数组 / 标量,或它的 `kind`
|
|
137
|
+
* 不是非空串)。这一格与「四臂之外的一个词」是两件事,所以刻意用**这一位的缺席**分开:
|
|
138
|
+
* 前者消费点只能说「一座读不出的终局」,后者能把那个词逐字报出来。
|
|
139
|
+
* ⚠️ 它**不是**「没有终局」——那一格由 {@link readRunTerminal} 返 `null` 表达。
|
|
140
|
+
*/
|
|
141
|
+
word?: string;
|
|
142
|
+
code?: string;
|
|
143
|
+
message?: string;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* `done.result` / run row 的 `result` → 终局读数。**绝不抛**;读不出终态词 ⇒ `null`。
|
|
147
|
+
*
|
|
148
|
+
* 🔴 `null` **只有一个意思**:这份载体上连终态词都没有(mock 车道 / 不带 status 的旧合成帧)。
|
|
149
|
+
* 它**不是**「成功」也**不是**「未知终态」—— 消费点对这一格的既有处置(落成功臂)由消费点自己
|
|
150
|
+
* 保留,本读器不替它下这个断言。
|
|
151
|
+
* 🔴 **「因由座在场但读不出」绝不返 `null`**(异源对抗复审 [medium] 采纳,真病):`terminal: null` /
|
|
152
|
+
* `{}` / `[]` / `{kind: 7}` 这几形若返 `null`,消费点会把它当成「连终态词都没有」而落**成功臂**
|
|
153
|
+
* —— 一条明确 park 着的 run 被投影成空成功,正是 [884]A1 / [909]B1 两次事故的形状。⇒ 这几形
|
|
154
|
+
* 一律落 `unknown` 臂(`word` 缺席 = 那个词本身读不出),消费点照旧渲「非成功终局」。
|
|
155
|
+
* ⚠️ 混合载体(既有坏 `terminal` 又有平面 `status`)同样落这里:判别位是**因由座在场性**,
|
|
156
|
+
* 因由在场就不再回头读平面键(留一条回落 = 同一事实两个真源,而坏的那一份才是当代写者写的)。
|
|
157
|
+
* 🔴 判别位是 **`"terminal" in result`**(上游钉的那一个),不是 `status` 的在场性:拒绝信封与
|
|
158
|
+
* 平面盘上字节**都**带 `status`,拿它当第一步判别位方向是脆的(sdk 顶注逐字点名)。
|
|
159
|
+
*/
|
|
160
|
+
export declare function readRunTerminal(result: unknown): RunTerminalRead | null;
|
|
161
|
+
/**
|
|
162
|
+
* 「这次暂停要的是**一次复核**」的门种 —— **呈现措辞**这条轴上的单一词表(不是路由表)。
|
|
163
|
+
*
|
|
164
|
+
* 🔴 与 `activeRunSelfHeal.PLAN_REVIEW_GATE_KINDS`(`plan_review` / `dry_run_review`)**刻意不同集**,
|
|
165
|
+
* 差别有出处:那张表答的是「**重开臂能不能驱动它**」(两个成员共用同一个 resume 入口
|
|
166
|
+
* `/v1/assistant/tasks/{taskId}/plan_review`),而本表答的是「**跟用户怎么说**」。门种
|
|
167
|
+
* `needs_review`(design/76 dry-run/shadow 的 POST-prediction 复核)没有那个 resume 入口,所以
|
|
168
|
+
* 它不在路由表里 —— 但它同样是**一次复核**而不是「一次交互作答」,措辞轴上必须在。
|
|
169
|
+
* 🔴 两张表的包含关系由常驻门钉死(本表 ⊇ 路由表):路由表加员而本表没跟 ⇒ 新门种的终帧会被说成
|
|
170
|
+
* 「在等一次交互作答」,那正是 [884]A1 那句文案要防的错话。
|
|
171
|
+
* 🔴 **开集读**:表外门种一律落「交互作答」那一句 —— 它是两句里更宽的那一句(指的出路对两族都有效)。
|
|
172
|
+
*/
|
|
173
|
+
export declare const REVIEW_PARK_GATE_KINDS: readonly string[];
|
|
174
|
+
/**
|
|
175
|
+
* 这次暂停停在**哪一种门**上(开集读;缺席 = 门没报 kind)。
|
|
176
|
+
* 消费点要分「plan 复核 park」与「审批/提问 park」时读它,**不要**再去找退役的 `status` 五词。
|
|
177
|
+
*/
|
|
178
|
+
export declare function runTerminalGateKind(read: RunTerminalRead | null): string | undefined;
|
|
179
|
+
/** 这次暂停扣着**哪个工具**(开集读;tool-less park 上缺席)。 */
|
|
180
|
+
export declare function runTerminalGateToolName(read: RunTerminalRead | null): string | undefined;
|
|
181
|
+
/**
|
|
182
|
+
* 这次终局的**机器码**(开集)。`failed` 臂是它的结构归属;`blocked` / `paused` / `unknown` 上
|
|
183
|
+
* 只可能来自扁平形盘上字节(见模块顶注)。`completed` 上恒 `undefined`。
|
|
184
|
+
*/
|
|
185
|
+
export declare function runTerminalCode(read: RunTerminalRead | null): string | undefined;
|
|
186
|
+
/**
|
|
187
|
+
* 这次暂停在等**一次复核**(而不是一次交互作答)吗。**两个来源,缺一不可**:
|
|
188
|
+
* · **因由形** —— 门种 ∈ {@link REVIEW_PARK_GATE_KINDS};
|
|
189
|
+
* · **扁平形** —— {@link RunTerminalPausedRead.flatStatus} 是 `needs_review`。
|
|
190
|
+
* 🔴 这一条不是冗余:server 自造的**同步 park 200 体**上连门都没有(见 `flatStatus` 顶注),
|
|
191
|
+
* 只读门种会让那一形**全部**落到「交互作答」那一句上 —— plan-review 卡不弹、终帧措辞说错话。
|
|
192
|
+
* 非 paused 的读数、以及两个来源都答不出的 paused,一律 `false`(更宽的那一句兜底)。
|
|
193
|
+
*/
|
|
194
|
+
export declare function isReviewPark(read: RunTerminalRead | null): boolean;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/** 非空串窄化(空串按缺席归一 —— 一个空的因由渲不出任何有用的话)。 */
|
|
2
|
+
function str(v) {
|
|
3
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
4
|
+
}
|
|
5
|
+
/** wire 上的门对象 → 结构视图;不成形 ⇒ 缺席(绝不铸一个空门)。 */
|
|
6
|
+
function gateOf(v) {
|
|
7
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
8
|
+
return undefined;
|
|
9
|
+
return v;
|
|
10
|
+
}
|
|
11
|
+
/** paused 三座的共用窄读(顶层 paused 臂与 `failed.nestedPause` 同一把 —— 两处各写一份必漂)。 */
|
|
12
|
+
function pauseOf(v) {
|
|
13
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
14
|
+
return undefined;
|
|
15
|
+
const p = v;
|
|
16
|
+
const gate = gateOf(p.gate);
|
|
17
|
+
const checkpointId = str(p.checkpointId);
|
|
18
|
+
const restoreMode = str(p.restoreMode);
|
|
19
|
+
return {
|
|
20
|
+
...(gate !== undefined ? { gate } : {}),
|
|
21
|
+
...(checkpointId !== undefined ? { checkpointId } : {}),
|
|
22
|
+
...(restoreMode !== undefined ? { restoreMode } : {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 扁平形里映射到 **paused 因由臂**的两个退役 status 词。
|
|
27
|
+
* 🔴 表外词一律走 `unknown` 臂 —— 含历史终态 `timeout`,也含**非终态**词 `running`
|
|
28
|
+
* (那是「这不是一个我认得的终局」,**不是**成功;真机黑盒点名的那条边界)。
|
|
29
|
+
*/
|
|
30
|
+
const FLAT_PAUSED_STATUSES = ['suspended', 'needs_review'];
|
|
31
|
+
/**
|
|
32
|
+
* `done.result` / run row 的 `result` → 终局读数。**绝不抛**;读不出终态词 ⇒ `null`。
|
|
33
|
+
*
|
|
34
|
+
* 🔴 `null` **只有一个意思**:这份载体上连终态词都没有(mock 车道 / 不带 status 的旧合成帧)。
|
|
35
|
+
* 它**不是**「成功」也**不是**「未知终态」—— 消费点对这一格的既有处置(落成功臂)由消费点自己
|
|
36
|
+
* 保留,本读器不替它下这个断言。
|
|
37
|
+
* 🔴 **「因由座在场但读不出」绝不返 `null`**(异源对抗复审 [medium] 采纳,真病):`terminal: null` /
|
|
38
|
+
* `{}` / `[]` / `{kind: 7}` 这几形若返 `null`,消费点会把它当成「连终态词都没有」而落**成功臂**
|
|
39
|
+
* —— 一条明确 park 着的 run 被投影成空成功,正是 [884]A1 / [909]B1 两次事故的形状。⇒ 这几形
|
|
40
|
+
* 一律落 `unknown` 臂(`word` 缺席 = 那个词本身读不出),消费点照旧渲「非成功终局」。
|
|
41
|
+
* ⚠️ 混合载体(既有坏 `terminal` 又有平面 `status`)同样落这里:判别位是**因由座在场性**,
|
|
42
|
+
* 因由在场就不再回头读平面键(留一条回落 = 同一事实两个真源,而坏的那一份才是当代写者写的)。
|
|
43
|
+
* 🔴 判别位是 **`"terminal" in result`**(上游钉的那一个),不是 `status` 的在场性:拒绝信封与
|
|
44
|
+
* 平面盘上字节**都**带 `status`,拿它当第一步判别位方向是脆的(sdk 顶注逐字点名)。
|
|
45
|
+
*/
|
|
46
|
+
export function readRunTerminal(result) {
|
|
47
|
+
if (typeof result !== 'object' || result === null || Array.isArray(result))
|
|
48
|
+
return null;
|
|
49
|
+
const r = result;
|
|
50
|
+
if ('terminal' in r) {
|
|
51
|
+
const t = r.terminal;
|
|
52
|
+
// 🔴 因由座在场但整个读不出 ⇒ `unknown` 臂(**不是** `null`;见顶注:返 `null` 会让消费点把
|
|
53
|
+
// 一条明确 park 着的 run 落进成功臂)。`word` 缺席 = 连那个词都读不出来。
|
|
54
|
+
if (typeof t !== 'object' || t === null || Array.isArray(t))
|
|
55
|
+
return { kind: 'unknown', plane: 'cause' };
|
|
56
|
+
const c = t;
|
|
57
|
+
const kind = str(c.kind);
|
|
58
|
+
if (kind === undefined)
|
|
59
|
+
return { kind: 'unknown', plane: 'cause' };
|
|
60
|
+
switch (kind) {
|
|
61
|
+
case 'completed':
|
|
62
|
+
return { kind: 'completed', plane: 'cause' };
|
|
63
|
+
case 'failed': {
|
|
64
|
+
const code = str(c.code);
|
|
65
|
+
const message = str(c.message);
|
|
66
|
+
const nestedPause = c.nestedPause !== undefined ? pauseOf(c.nestedPause) : undefined;
|
|
67
|
+
return {
|
|
68
|
+
kind: 'failed',
|
|
69
|
+
plane: 'cause',
|
|
70
|
+
...(code !== undefined ? { code } : {}),
|
|
71
|
+
...(message !== undefined ? { message } : {}),
|
|
72
|
+
...(nestedPause !== undefined ? { nestedPause } : {}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
case 'blocked': {
|
|
76
|
+
const reason = str(c.reason);
|
|
77
|
+
return { kind: 'blocked', plane: 'cause', ...(reason !== undefined ? { reason } : {}) };
|
|
78
|
+
}
|
|
79
|
+
case 'paused':
|
|
80
|
+
return { kind: 'paused', plane: 'cause', ...(pauseOf(c) ?? {}) };
|
|
81
|
+
default:
|
|
82
|
+
return { kind: 'unknown', plane: 'cause', word: kind };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// ── 扁平形(读盘回放 / 409 拒绝信封;见模块顶注)────────────────────────────────────────────
|
|
86
|
+
const status = str(r.status);
|
|
87
|
+
if (status === undefined)
|
|
88
|
+
return null;
|
|
89
|
+
const code = str(r.errorCode);
|
|
90
|
+
const message = str(r.errorMessage);
|
|
91
|
+
if (status === 'completed')
|
|
92
|
+
return { kind: 'completed', plane: 'flat' };
|
|
93
|
+
if (status === 'failed') {
|
|
94
|
+
return {
|
|
95
|
+
kind: 'failed',
|
|
96
|
+
plane: 'flat',
|
|
97
|
+
...(code !== undefined ? { code } : {}),
|
|
98
|
+
...(message !== undefined ? { message } : {}),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (status === 'blocked') {
|
|
102
|
+
const reason = str(r.blockedReason);
|
|
103
|
+
return {
|
|
104
|
+
kind: 'blocked',
|
|
105
|
+
plane: 'flat',
|
|
106
|
+
...(reason !== undefined ? { reason } : {}),
|
|
107
|
+
...(code !== undefined ? { code } : {}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (FLAT_PAUSED_STATUSES.includes(status)) {
|
|
111
|
+
const gate = gateOf(r.checkpointGate);
|
|
112
|
+
const checkpointId = str(r.checkpointId);
|
|
113
|
+
const restoreMode = str(r.workspaceRestoreMode);
|
|
114
|
+
return {
|
|
115
|
+
kind: 'paused',
|
|
116
|
+
plane: 'flat',
|
|
117
|
+
// 🔴 见 `flatStatus` 顶注:server 自造的同步 park 体上**连门都没有**,这个词是那一形上
|
|
118
|
+
// 「复核 / 交互作答」的唯一信号。
|
|
119
|
+
flatStatus: status,
|
|
120
|
+
...(code !== undefined ? { code } : {}),
|
|
121
|
+
...(gate !== undefined ? { gate } : {}),
|
|
122
|
+
...(checkpointId !== undefined ? { checkpointId } : {}),
|
|
123
|
+
...(restoreMode !== undefined ? { restoreMode } : {}),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
kind: 'unknown',
|
|
128
|
+
plane: 'flat',
|
|
129
|
+
word: status,
|
|
130
|
+
...(code !== undefined ? { code } : {}),
|
|
131
|
+
...(message !== undefined ? { message } : {}),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 「这次暂停要的是**一次复核**」的门种 —— **呈现措辞**这条轴上的单一词表(不是路由表)。
|
|
136
|
+
*
|
|
137
|
+
* 🔴 与 `activeRunSelfHeal.PLAN_REVIEW_GATE_KINDS`(`plan_review` / `dry_run_review`)**刻意不同集**,
|
|
138
|
+
* 差别有出处:那张表答的是「**重开臂能不能驱动它**」(两个成员共用同一个 resume 入口
|
|
139
|
+
* `/v1/assistant/tasks/{taskId}/plan_review`),而本表答的是「**跟用户怎么说**」。门种
|
|
140
|
+
* `needs_review`(design/76 dry-run/shadow 的 POST-prediction 复核)没有那个 resume 入口,所以
|
|
141
|
+
* 它不在路由表里 —— 但它同样是**一次复核**而不是「一次交互作答」,措辞轴上必须在。
|
|
142
|
+
* 🔴 两张表的包含关系由常驻门钉死(本表 ⊇ 路由表):路由表加员而本表没跟 ⇒ 新门种的终帧会被说成
|
|
143
|
+
* 「在等一次交互作答」,那正是 [884]A1 那句文案要防的错话。
|
|
144
|
+
* 🔴 **开集读**:表外门种一律落「交互作答」那一句 —— 它是两句里更宽的那一句(指的出路对两族都有效)。
|
|
145
|
+
*/
|
|
146
|
+
export const REVIEW_PARK_GATE_KINDS = Object.freeze([
|
|
147
|
+
'plan_review',
|
|
148
|
+
'dry_run_review',
|
|
149
|
+
'needs_review',
|
|
150
|
+
]);
|
|
151
|
+
/**
|
|
152
|
+
* 这次暂停停在**哪一种门**上(开集读;缺席 = 门没报 kind)。
|
|
153
|
+
* 消费点要分「plan 复核 park」与「审批/提问 park」时读它,**不要**再去找退役的 `status` 五词。
|
|
154
|
+
*/
|
|
155
|
+
export function runTerminalGateKind(read) {
|
|
156
|
+
return read !== null && read.kind === 'paused' ? str(read.gate?.kind) : undefined;
|
|
157
|
+
}
|
|
158
|
+
/** 这次暂停扣着**哪个工具**(开集读;tool-less park 上缺席)。 */
|
|
159
|
+
export function runTerminalGateToolName(read) {
|
|
160
|
+
return read !== null && read.kind === 'paused' ? str(read.gate?.toolName) : undefined;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 这次终局的**机器码**(开集)。`failed` 臂是它的结构归属;`blocked` / `paused` / `unknown` 上
|
|
164
|
+
* 只可能来自扁平形盘上字节(见模块顶注)。`completed` 上恒 `undefined`。
|
|
165
|
+
*/
|
|
166
|
+
export function runTerminalCode(read) {
|
|
167
|
+
if (read === null || read.kind === 'completed')
|
|
168
|
+
return undefined;
|
|
169
|
+
return read.code;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* 扁平形上「这是一次复核」的那个退役 status 词。**只有一个**,刻意不写成表:
|
|
173
|
+
* `suspended` 与它是 `FLAT_PAUSED_STATUSES` 的两个成员,而两者的分法就是这一条。
|
|
174
|
+
*/
|
|
175
|
+
const FLAT_REVIEW_STATUS = 'needs_review';
|
|
176
|
+
/**
|
|
177
|
+
* 这次暂停在等**一次复核**(而不是一次交互作答)吗。**两个来源,缺一不可**:
|
|
178
|
+
* · **因由形** —— 门种 ∈ {@link REVIEW_PARK_GATE_KINDS};
|
|
179
|
+
* · **扁平形** —— {@link RunTerminalPausedRead.flatStatus} 是 `needs_review`。
|
|
180
|
+
* 🔴 这一条不是冗余:server 自造的**同步 park 200 体**上连门都没有(见 `flatStatus` 顶注),
|
|
181
|
+
* 只读门种会让那一形**全部**落到「交互作答」那一句上 —— plan-review 卡不弹、终帧措辞说错话。
|
|
182
|
+
* 非 paused 的读数、以及两个来源都答不出的 paused,一律 `false`(更宽的那一句兜底)。
|
|
183
|
+
*/
|
|
184
|
+
export function isReviewPark(read) {
|
|
185
|
+
const kind = runTerminalGateKind(read);
|
|
186
|
+
if (kind !== undefined && REVIEW_PARK_GATE_KINDS.includes(kind))
|
|
187
|
+
return true;
|
|
188
|
+
return read !== null && read.kind === 'paused' && read.flatStatus === FLAT_REVIEW_STATUS;
|
|
189
|
+
}
|
|
@@ -92,8 +92,18 @@ export declare function projectSqlEngineCapability(caps: unknown): SqlEngineRead
|
|
|
92
92
|
* 🔴 **不按 principal 分域**:SQL 姿态是**这台 worker 的连接事实**,与调用者是谁无关
|
|
93
93
|
* (与 `workflows` 那种 per-caller 的位刻意不同)—— 加一个用不上的去重域只会造出一条
|
|
94
94
|
* 「换主体就读不到」的假缺席。
|
|
95
|
+
*
|
|
96
|
+
* 🔴 **`opts.generation` = 关掉「旧探测覆盖新读数」那条竞态的唯一正确供给**(0.60.0;异源对抗复审
|
|
97
|
+
* [medium] 采纳,真病):`kickEngineCapsProbe` 的代际闸在 **probe 返回之后**才跑,而本 tee 是在
|
|
98
|
+
* probe **内部**落地的 ⇒ 一次慢的旧探测能在 `invalidateEngineCaps` + 新探测都走完之后才返回,
|
|
99
|
+
* 把**上一台引擎**的读数重新写回来。宿主在**起探测那一刻**调 `engineCapsGeneration(baseUrl)` 抓号、
|
|
100
|
+
* 在这里原样交回,陈旧那一发就会被整只丢掉。
|
|
101
|
+
* ⚠️ **不传 = 与本位到货之前逐字节同行为**(照写)—— additive 供给,不是强制门;端没跟上之前不会
|
|
102
|
+
* 有任何东西变坏。🔴 **tee 自己抓号是假判据**(陈旧那一发在这里读到的是新代号,永远像当代的)。
|
|
95
103
|
*/
|
|
96
|
-
export declare function noteEngineCapsForSqlEngine(baseUrl: string, caps: unknown
|
|
104
|
+
export declare function noteEngineCapsForSqlEngine(baseUrl: string, caps: unknown, opts?: {
|
|
105
|
+
generation?: number;
|
|
106
|
+
}): void;
|
|
97
107
|
/**
|
|
98
108
|
* 本进程观测到的 SQL 姿态;这一格空缺 ⇒ `{kind:'unobserved'}`(**绝不**折成 `none`)。
|
|
99
109
|
*
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
*/
|
|
44
44
|
import { escapeDisplayControlChars } from './fleetTaskDesc.js';
|
|
45
45
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
46
|
+
import { engineCapsGeneration } from './engineCapsCache.js';
|
|
46
47
|
/**
|
|
47
48
|
* caps 回体 → 本格读数;**畸形一律 `undefined`**(= 这一格不写 ⇒ 读口答 `unobserved`)。
|
|
48
49
|
*
|
|
@@ -88,11 +89,22 @@ const readingByBase = new Map();
|
|
|
88
89
|
* 🔴 **不按 principal 分域**:SQL 姿态是**这台 worker 的连接事实**,与调用者是谁无关
|
|
89
90
|
* (与 `workflows` 那种 per-caller 的位刻意不同)—— 加一个用不上的去重域只会造出一条
|
|
90
91
|
* 「换主体就读不到」的假缺席。
|
|
92
|
+
*
|
|
93
|
+
* 🔴 **`opts.generation` = 关掉「旧探测覆盖新读数」那条竞态的唯一正确供给**(0.60.0;异源对抗复审
|
|
94
|
+
* [medium] 采纳,真病):`kickEngineCapsProbe` 的代际闸在 **probe 返回之后**才跑,而本 tee 是在
|
|
95
|
+
* probe **内部**落地的 ⇒ 一次慢的旧探测能在 `invalidateEngineCaps` + 新探测都走完之后才返回,
|
|
96
|
+
* 把**上一台引擎**的读数重新写回来。宿主在**起探测那一刻**调 `engineCapsGeneration(baseUrl)` 抓号、
|
|
97
|
+
* 在这里原样交回,陈旧那一发就会被整只丢掉。
|
|
98
|
+
* ⚠️ **不传 = 与本位到货之前逐字节同行为**(照写)—— additive 供给,不是强制门;端没跟上之前不会
|
|
99
|
+
* 有任何东西变坏。🔴 **tee 自己抓号是假判据**(陈旧那一发在这里读到的是新代号,永远像当代的)。
|
|
91
100
|
*/
|
|
92
|
-
export function noteEngineCapsForSqlEngine(baseUrl, caps) {
|
|
101
|
+
export function noteEngineCapsForSqlEngine(baseUrl, caps, opts) {
|
|
93
102
|
try {
|
|
94
103
|
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
95
104
|
return;
|
|
105
|
+
// 陈旧代际的那一发整只丢掉(见本函数顶注的 `opts.generation` 段);不传 ⇒ 照写,零行为变化。
|
|
106
|
+
if (opts?.generation !== undefined && opts.generation !== engineCapsGeneration(baseUrl))
|
|
107
|
+
return;
|
|
96
108
|
const reading = projectSqlEngineCapability(caps);
|
|
97
109
|
if (reading === undefined) {
|
|
98
110
|
readingByBase.delete(baseUrl);
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* writeProtectionCapability — **写保护名表**姿态的三端共用读面(0.60.0)。
|
|
3
|
+
*
|
|
4
|
+
* 引擎带一张**字面名表**,落在表行上的可定路径写(Write / Edit / NotebookEdit)从 `allow` 降级成
|
|
5
|
+
* `ask` —— 所以端可以**事先**告诉人「这些路径会弹卡」。两个读面同源同一份 boot 产物:
|
|
6
|
+
* · **租户面** `GET /v1/capabilities` 的 `writeProtection`(engine ≥7.63.0 / S-138;sdk 8.4.0
|
|
7
|
+
* `Capabilities.writeProtection`)—— 只有三位计数/开关,**不含行内容**;
|
|
8
|
+
* · **operator 面** `GET /v1/diagnostics/wiring` 的 `writeProtection` —— 多出**行内容**与来源词。
|
|
9
|
+
*
|
|
10
|
+
* ── 🔴 四态,不是两态([honest-absence-not-fabricated-zero])──────────────────────────────────
|
|
11
|
+
* 与 `sqlEngineCapability` 逐字同一套词汇(通用读口答「这一格上有没有值」,窄读器答「值成不成形」):
|
|
12
|
+
* ① `unobserved` —— **本进程一次 caps 响应都没观测到**(一次性 doctor 就是这一档)。
|
|
13
|
+
* ② `not_reported` —— caps 观测到了,而回体上**没有**这个键 ⇒ 老引擎(<7.63.0)。
|
|
14
|
+
* 🔴 它**不是**「这台部署没有写保护表」—— 恰恰相反:引擎侧**座位缺席时缺省表在岗**
|
|
15
|
+
* (按键名 grep 推断「没装」会推错,上游把这一条写进了本位的顶注)。
|
|
16
|
+
* ③ `none` —— 引擎**明确说** `null`:这个进程说不出来(非 composition root 装配的夹具形)。
|
|
17
|
+
* 同样**不是**「没有表」。
|
|
18
|
+
* ④ `present` —— 三位俱全,原样渲。
|
|
19
|
+
*
|
|
20
|
+
* ── 🔴 三位刻意不合成一个布尔(上游顶注逐字)────────────────────────────────────────────────
|
|
21
|
+
* `armed`(生效表非空 ⇒ 真会弹卡)/ `rows`(生效表行数)/ `replaced`(整表替换旋钮被写过)——
|
|
22
|
+
* 合成之后「引擎缺省表在岗」与「运维换了一张自己的表」同为 true,而两者对运维说的是两件事。
|
|
23
|
+
* ⚠️ `replaced` 把「整表替换成**空**表」也算 true:报 false 会把「运维亲手关掉了表」说成
|
|
24
|
+
* 「缺省表没被动过」。
|
|
25
|
+
*
|
|
26
|
+
* ── 🔴 最小披露:逐行 name/kind 不上租户面 ──────────────────────────────────────────────────
|
|
27
|
+
* 部署自定义行可能含内部路径名,列出来等于告诉想绕过的人「哪些名字不受保护」。行内容只在
|
|
28
|
+
* operator 面({@link projectWriteProtectionPosture}),而那个端点本身是 operator-gated。
|
|
29
|
+
* 🔴 与**模式型** write deny(`SENSITIVE_WRITE_PATTERNS`)是**并列机制**,两个读面分开报、
|
|
30
|
+
* 绝不合成一位:两者的解法不同(一套改模式,一套改名表)。
|
|
31
|
+
*/
|
|
32
|
+
/** 租户面三位(server `WriteProtectionCapability` 逐字同形)。 */
|
|
33
|
+
export interface WriteProtectionCapabilityView {
|
|
34
|
+
/** 生效表非空 ⇒ 引擎真会对表行弹卡。 */
|
|
35
|
+
armed: boolean;
|
|
36
|
+
/** 生效表的**行数**(内容只上 operator 面)。 */
|
|
37
|
+
rows: number;
|
|
38
|
+
/** 整表替换旋钮被写过 ⇒ 缺省表不再原样在岗。与 {@link armed} 刻意不合成。 */
|
|
39
|
+
replaced: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** 四态读数(见文件头)。`unobserved` 由**读口**在这一格空缺时铸,不由投影铸。 */
|
|
42
|
+
export type WriteProtectionReading = {
|
|
43
|
+
kind: 'unobserved';
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'not_reported';
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'none';
|
|
48
|
+
} | {
|
|
49
|
+
kind: 'present';
|
|
50
|
+
view: WriteProtectionCapabilityView;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* caps 回体 → 本格读数;**畸形一律 `undefined`**(= 这一格不写 ⇒ 读口答 `unobserved`)。
|
|
54
|
+
*
|
|
55
|
+
* 🔴 `undefined`(键不在)与 `null`(引擎说不出来)**是两件事**:前者 ⇒ `not_reported`(老引擎),
|
|
56
|
+
* 后者 ⇒ `none`(夹具形进程)。用 `??` / falsy 判会把两者压成一件。
|
|
57
|
+
* 🔴 三位**任一**形不合 ⇒ 整条判畸形。绝不留一个缺位的对象:一行写着「rows: 」的诊断比不渲这一行
|
|
58
|
+
* 更坏(它看起来像一个答案)。
|
|
59
|
+
* ⚠️ `rows` 按**非负有限整数**判,不按真值判:`0` 是合法读数(表在、但生效行为零),折成缺席会让
|
|
60
|
+
* 「表空了」与「没报」在消费端同形。
|
|
61
|
+
*/
|
|
62
|
+
export declare function projectWriteProtectionCapability(caps: unknown): WriteProtectionReading | undefined;
|
|
63
|
+
/** operator 面的一行:一个**字面**名字 + 它怎么匹配。`name` 同时是这一行的稳定身份。 */
|
|
64
|
+
export interface WriteProtectedRowView {
|
|
65
|
+
name: string;
|
|
66
|
+
/** `basename`(目标最后一段)/ `segment`(任意一段)/ `segment-run`(连续若干段);**开集读**。 */
|
|
67
|
+
kind: string;
|
|
68
|
+
}
|
|
69
|
+
/** operator 面读数(`GET /v1/diagnostics/wiring` 的 `writeProtection`)。 */
|
|
70
|
+
export interface WriteProtectionPostureView {
|
|
71
|
+
/** 生效表逐行,逐字来自引擎自己的编译产物。**空数组 = 显式无表**(不是缺席)。 */
|
|
72
|
+
rows: readonly WriteProtectedRowView[];
|
|
73
|
+
/** `default`(两根旋钮都没写)/ `extra`(缺省表 + 增量)/ `replace`(整表替换)/ `off`
|
|
74
|
+
* (整表替换成空表,合法且响亮);**开集读**。 */
|
|
75
|
+
source: string;
|
|
76
|
+
/** 整表替换**丢掉**的缺省行名;只在替换族在场。 */
|
|
77
|
+
droppedDefaultRows?: readonly string[];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* operator 面回体的 `writeProtection` 段 → 读数;不成形 ⇒ `undefined`。
|
|
81
|
+
*
|
|
82
|
+
* 🔴 **空 `rows` 数组是正面事实**(「显式无表」),照铸 `[]` —— 与 `wiring_manifest.mcp[]` 同一条
|
|
83
|
+
* 已定谳的纪律;把它折成缺席等于把引擎明说的一句话读成「不知道」。
|
|
84
|
+
* 🔴 **坏行只丢那一行**(与 mcp 行同判据),但 `source` 读不出 ⇒ **整段缺席**:没有来源词的行表
|
|
85
|
+
* 答不了运维真正要问的那一问(「这是缺省表还是你换过的表」),而半段会被当成完整答案。
|
|
86
|
+
* 🔴 **不校「`droppedDefaultRows` 只在替换族在场」**:那是引擎的段内规矩,server 已按它铸;
|
|
87
|
+
* 包再校一遍只会在上游合法演进的当天把一个真读数判没(与开集词表同规)。
|
|
88
|
+
*/
|
|
89
|
+
export declare function projectWriteProtectionPosture(wiring: unknown): WriteProtectionPostureView | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* 宿主 caps probe 的**读面 tee** 落点(与 `noteEngineCapsForSqlEngine` 并列)。绝不 throw ——
|
|
92
|
+
* 读面腿不许反噬 caps 探测链。
|
|
93
|
+
*
|
|
94
|
+
* 🔴 投影 `undefined`(caps 畸形)⇒ 这一格**被删**而不是留着上一台引擎的旧值。
|
|
95
|
+
* ⚠️ 「同端口 respawn / 版本回滚之后新探测失败或还在飞」是**另一条路**(本 tee 一次都不触发),
|
|
96
|
+
* 由 {@link forgetWriteProtectionReading} 在装配口上收 —— 与 SQL 那一格逐字同形。
|
|
97
|
+
* 🔴 **不按 principal 分域**:写保护表是**这台 worker 的 boot 产物**,与调用者是谁无关。
|
|
98
|
+
*
|
|
99
|
+
* 🔴 **`opts.generation` = 关掉「旧探测覆盖新读数」那条竞态的唯一正确供给**(0.60.0;异源对抗复审
|
|
100
|
+
* [medium] 采纳,真病):`kickEngineCapsProbe` 的代际闸在 **probe 返回之后**才跑,而本 tee 是在
|
|
101
|
+
* probe **内部**落地的 ⇒ 一次慢的旧探测能在 `invalidateEngineCaps` + 新探测都走完之后才返回,
|
|
102
|
+
* 把**上一台引擎**的读数重新写回来。宿主在**起探测那一刻**调 `engineCapsGeneration(baseUrl)` 抓号、
|
|
103
|
+
* 在这里原样交回,陈旧那一发就会被整只丢掉。
|
|
104
|
+
* ⚠️ **不传 = 与本位到货之前逐字节同行为**(照写)—— additive 供给,不是强制门;端没跟上之前不会
|
|
105
|
+
* 有任何东西变坏。🔴 **tee 自己抓号是假判据**(陈旧那一发在这里读到的是新代号,永远像当代的)。
|
|
106
|
+
*/
|
|
107
|
+
export declare function noteEngineCapsForWriteProtection(baseUrl: string, caps: unknown, opts?: {
|
|
108
|
+
generation?: number;
|
|
109
|
+
}): void;
|
|
110
|
+
/** 本进程观测到的写保护姿态;这一格空缺 ⇒ `{kind:'unobserved'}`(**绝不**折成 `none`)。 */
|
|
111
|
+
export declare function observedWriteProtection(baseUrl?: string | undefined): WriteProtectionReading;
|
|
112
|
+
/**
|
|
113
|
+
* 四态 → doctor 那一行的 detail 串。**唯一措辞真源**(三端共用一句话;别在各端的行装配里另写一遍
|
|
114
|
+
* —— 与 `sqlEngineDoctorDetail` / `autoModeDoctorDetail` 同一条纪律)。
|
|
115
|
+
*
|
|
116
|
+
* 🔴 四句话刻意**互不相同、也互不蕴含**:「未观测」「老引擎不报」「进程说不出来」三种「读不出」
|
|
117
|
+
* 对运维是三条不同的下一步,而**没有一条**等于「这台部署没有写保护」。
|
|
118
|
+
* 🔴 `present` 那一句把三位**分开说**(见文件头「刻意不合成」):`armed` 说会不会弹卡,`rows` 说
|
|
119
|
+
* 几行,`replaced` 说缺省表还在不在岗。
|
|
120
|
+
* 🔴 行内容一个字都不渲(最小披露);`source` 是 operator 面的位,不上这一行。
|
|
121
|
+
*/
|
|
122
|
+
export declare function writeProtectionDoctorDetail(reading: WriteProtectionReading): string;
|
|
123
|
+
/**
|
|
124
|
+
* operator 面读数 → 一行 detail(行名是 UNTRUSTED 自由文本 ⇒ 呈前**逐条**消毒 + 封长)。
|
|
125
|
+
*
|
|
126
|
+
* 🔴 只给**行数与来源**加上「头几行的名字」,不整表倾泻:一行诊断不是一个表格,而 operator 面的
|
|
127
|
+
* 真表读法是那个端点本身。
|
|
128
|
+
* 🔴 `rows: []` 渲的是**显式无表**这句正面事实,不是「读不出」。
|
|
129
|
+
*/
|
|
130
|
+
export declare function writeProtectionPostureDetail(posture: WriteProtectionPostureView): string;
|
|
131
|
+
/**
|
|
132
|
+
* **换代失效口**(与 `forgetSqlEngineReading` 并列,由宿主在引擎温切成功后调)。
|
|
133
|
+
*
|
|
134
|
+
* 🔴 代际闸挡不住这一形:那道闸挡的是「旧响应写脏新一代」,而本格的病是反过来的 —— 新一代的探测
|
|
135
|
+
* **根本没成功**,tee 一次都没触发,上一台引擎留在同一端口上的读数继续被当成当代事实答出去。
|
|
136
|
+
* 在 doctor 上它的形态最坏:一句**肯定句**(「这台部署有 12 行写保护」),说的却是一台已经不在
|
|
137
|
+
* 的引擎。处置是**清成未观测**,不是留旧值也不是铸一个 `none`。
|
|
138
|
+
* 空串 ⇒ no-op;绝不 throw(它跑在引擎温切路径上)。
|
|
139
|
+
*/
|
|
140
|
+
export declare function forgetWriteProtectionReading(baseUrl: string | undefined): void;
|
|
141
|
+
/** 测试钩子。 */
|
|
142
|
+
export declare function __resetWriteProtectionReadingsForTests(): void;
|