@sema-agent/settings-schema 17.1.0 → 18.0.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 +212 -0
- package/README.md +73 -5
- package/conformance/VERSION +1 -1
- package/conformance/baseline.json +3 -0
- package/conformance/cases/c01-entry-salvage-then-typo/expected.json +4 -1
- package/conformance/cases/c02-hosts-clamp-stacked/expected.json +4 -1
- package/conformance/cases/c03-literal-dotted-top-key/expected.json +4 -1
- package/conformance/cases/c04-all-bad-collection-not-salvaged/expected.json +4 -1
- package/conformance/cases/c07-hooks-is-not-a-config-domain/expected.json +4 -1
- package/conformance/cases/c08-limits-unknown-carried-64/expected.json +4 -1
- package/conformance/cases/c09-limits-unknown-carried-65/expected.json +4 -1
- package/conformance/cases/c10-record-key-secret-redacted-twice/expected.json +4 -1
- package/conformance/cases/c11-unicode-unknown-keys/expected.json +4 -1
- package/conformance/cases/c12-prototype-name-top-keys/expected.json +4 -1
- package/conformance/cases/c13-models-field-null/expected.json +4 -1
- package/conformance/cases/c14-models-field-empty-array/expected.json +4 -1
- package/conformance/cases/c15-models-field-number/expected.json +4 -1
- package/conformance/cases/c16-deep-nesting-205/expected.json +3 -0
- package/conformance/cases/c17-empty-domain-file/expected.json +3 -0
- package/conformance/cases/c18-wire-envelope-not-an-object/expected.json +4 -1
- package/conformance/cases/c19-wire-envelope-no-version/expected.json +4 -1
- package/conformance/cases/c21-governance-empty-object-wins/expected.json +4 -1
- package/conformance/cases/c23-mixed-validity-models/expected.json +4 -1
- package/conformance/cases/c24-valid-entries-with-unknown-keys/expected.json +4 -1
- package/conformance/cases/c25-published-roundtrip-zero-warnings/expected.json +4 -1
- package/conformance/cases/c26-hosts-array-1024/expected.json +4 -1
- package/conformance/cases/c27-hosts-array-1025/expected.json +4 -1
- package/conformance/cases/c28-large-document-over-1mb/expected.json +4 -1
- package/conformance/cases/c29-salvage-then-domain-refine-fails/expected.json +4 -1
- package/conformance/cases/c30-version-triple-a-first/expected.json +4 -1
- package/conformance/cases/c31-version-triple-b-changed/expected.json +4 -1
- package/conformance/cases/c32-version-triple-a-restored/expected.json +4 -1
- package/conformance/cases/c33-limits-nested-carried-key/expected.json +4 -1
- package/conformance/cases/c34-skills-content-vs-manifest/expected.json +7 -1
- package/conformance/cases/c35-portable-domain-file-is-null/expected.json +3 -0
- package/conformance/cases/c36-skills-entry-without-content/expected.json +7 -1
- package/conformance/cases/c37-skills-field-null/expected.json +6 -0
- package/conformance/cases/c38-remote-exec-is-a-non-domain-file/expected.json +4 -1
- package/conformance/cases/c39-hidden-file-in-config-d/expected.json +4 -1
- package/conformance/cases/c40-s712-identity-only-what-reads-out/expected.json +4 -1
- package/conformance/cases/c41-s792-encoded-pem-identity/expected.json +4 -1
- package/conformance/cases/c42-s792-unknown-key-secret-redacted/expected.json +4 -1
- package/conformance/cases/c43-s792-form-and-deep-encoded-pem/expected.json +4 -1
- package/conformance/cases/c44-s792-utf8-escape-glued-token/expected.json +4 -1
- package/conformance/cases/c45-s792-identity-bounds-and-decode-depth/expected.json +4 -1
- package/conformance/cases/c46-s811-host-name-url-userinfo-withheld/expected.json +4 -1
- package/conformance/cases/c47-s811-roles-key-url-userinfo-withheld/expected.json +4 -1
- package/conformance/cases/c48-s935-model-headers-transported/expected.json +4 -1
- package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/expected.json +4 -1
- package/conformance/cases/c50-s784-lane-host-legal/expected.json +4 -1
- package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +4 -1
- package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +4 -1
- package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +4 -1
- package/conformance/cases/c54-s784-lane-adb-legal/expected.json +4 -1
- package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +4 -1
- package/conformance/cases/c56-s784-lane-device-legal/expected.json +4 -1
- package/conformance/cases/c57-s784-g1-enabled-no-lane/expected.json +4 -1
- package/conformance/cases/c58-s784-g2-multitenant-host/expected.json +4 -1
- package/conformance/cases/c59-s784-g3-k8s-missing-image/expected.json +4 -1
- package/conformance/cases/c60-s784-g3-e2b-missing-key/expected.json +4 -1
- package/conformance/cases/c61-s784-g3-other-lane-key/expected.json +4 -1
- package/conformance/cases/c62-s784-g7a-session-tidb/expected.json +4 -1
- package/conformance/cases/c63-s784-host-two-replicas/expected.json +4 -1
- package/conformance/cases/c64-s784-multitenant-local-store/expected.json +4 -1
- package/conformance/cases/c65-s784-pg-without-db/expected.json +4 -1
- package/conformance/cases/c66-s784-memory-backend-mismatch/expected.json +4 -1
- package/conformance/cases/c67-s784-retired-field-loud/expected.json +4 -1
- package/conformance/cases/c68-s784-device-local-store/expected.json +4 -1
- package/conformance/cases/c69-deep-encoded-token-past-every-reading/expected.json +4 -1
- package/conformance/cases/c70-rewritten-token-in-front-of-encoded-pem-header/expected.json +4 -1
- package/conformance/cases/c71-one-scanner-write-reads-display-forms/expected.json +4 -1
- package/conformance/cases/c72-dangling-reference-write-seat-refuses/expected.json +4 -1
- package/conformance/cases/c73-projects-extended-registration-reads/expected.json +4 -1
- package/conformance/cases/c74-projects-over-bound-refused/expected.json +4 -1
- package/conformance/cases/c75-projects-patch-remote-uniqueness/expected.json +4 -1
- package/conformance/cases/c76-projects-entry-salvage-nested/expected.json +4 -1
- package/conformance/cases/c77-prompts-center-artifact-carried/expected.json +4 -1
- package/conformance/cases/c78-prompts-empty-bindings-refused/expected.json +4 -1
- package/conformance/cases/c79-prompts-bad-worker-artifact-not-salvaged/expected.json +4 -1
- package/conformance/cases/c80-prompts-wire-v2-verbatim/expected.json +7 -1
- package/conformance/cases/c81-prompts-declaration-bindings-refused/expected.json +4 -1
- package/conformance/cases/c82-prompts-v1-catalog-refused/expected.json +4 -1
- package/conformance/cases/c83-prompts-bad-overlay-not-salvaged/expected.json +4 -1
- package/conformance/cases/c84-sandbox-git-block-carried-verbatim/expected.json +7 -1
- package/conformance/cases/c85-sandbox-git-refused-block-still-carried/expected.json +7 -1
- package/conformance/cases/c86-a2a-peers-legal/expected.json +135 -0
- package/conformance/cases/c86-a2a-peers-legal/input.json +32 -0
- package/conformance/cases/c86-a2a-peers-legal/meta.json +5 -0
- package/conformance/cases/c87-a2a-credential-refs-not-partially-salvaged/expected.json +123 -0
- package/conformance/cases/c87-a2a-credential-refs-not-partially-salvaged/input.json +39 -0
- package/conformance/cases/c87-a2a-credential-refs-not-partially-salvaged/meta.json +5 -0
- package/conformance/cases/cc01-mcp-toolfaces-non-object/expected.json +4 -1
- package/conformance/cases/cc02-mcp-source-key-is-transported/expected.json +4 -1
- package/conformance/cases/cc03-model-compat-unknown-subkey/expected.json +4 -1
- package/conformance/cases/cli01-model-name-nfc-vs-nfd/expected.json +4 -1
- package/conformance/cases/cli02-control-and-zero-width-chars/expected.json +4 -1
- package/conformance/cases/cli03-credential-pasted-into-unknown-key/expected.json +4 -1
- package/conformance/cases/cli04-env-value-with-newline/expected.json +4 -1
- package/conformance/cases/cli05-long-and-prefix-colliding-names/expected.json +4 -1
- package/conformance/cases/t01-absent-domain-key-not-null/expected.json +4 -1
- package/conformance/cases/t03-prototype-name-key-not-swallowed/expected.json +4 -1
- package/conformance/cases/t04-secret-literal-never-in-warning-value/expected.json +4 -1
- package/conformance/cases/z01-every-domain-empty-object/expected.json +4 -1
- package/conformance/cases/z02-every-domain-unknown-key/expected.json +4 -1
- package/dist/atomic-write.d.ts +4 -3
- package/dist/atomic-write.js +25 -11
- package/dist/catalog-manages.d.ts +8 -3
- package/dist/catalog-manages.js +16 -7
- package/dist/center-refs.d.ts +4 -3
- package/dist/center-refs.js +8 -6
- package/dist/cli.d.ts +1 -1
- package/dist/config-d-file.d.ts +4 -2
- package/dist/config-d-file.js +27 -6
- package/dist/config-fns.d.ts +6 -1
- package/dist/config-fns.js +16 -2
- package/dist/config-root-documents.d.ts +2 -2
- package/dist/config-root-documents.js +1 -1
- package/dist/config-root-node.d.ts +8 -1
- package/dist/config-root-node.js +105 -23
- package/dist/env-model-table.js +3 -3
- package/dist/execution-lanes.d.ts +158 -11
- package/dist/execution-lanes.js +76 -11
- package/dist/file-edit.d.ts +1 -1
- package/dist/file-edit.js +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp-request-entry.d.ts +11 -21
- package/dist/mcp-request-entry.js +21 -38
- package/dist/node.d.ts +4 -1
- package/dist/node.js +6 -2
- package/dist/one-time-migrations.js +1 -1
- package/dist/portable-domains.d.ts +1 -1
- package/dist/portable-domains.js +1 -1
- package/dist/remote-exec.d.ts +5 -0
- package/dist/remote-exec.js +5 -0
- package/dist/reserved-member-name.d.ts +13 -0
- package/dist/reserved-member-name.js +14 -0
- package/dist/retired-envs.js +2 -0
- package/dist/secret-refs.d.ts +1 -1
- package/dist/secret-refs.js +5 -1
- package/dist/settings-units.d.ts +3 -0
- package/dist/settings-units.js +18 -0
- package/dist/types.d.ts +70 -41
- package/dist/types.js +179 -32
- package/dist/url-credential.d.ts +12 -2
- package/dist/url-credential.js +164 -9
- package/dist/wire-name.d.ts +19 -0
- package/dist/wire-name.js +21 -0
- package/docs/API-SURFACE.md +31 -6
- package/docs/CC-DIVERGENCE.md +6 -0
- package/docs/CONSUMER-INTEGRATION.md +127 -7
- package/llms-full.txt +40 -17
- package/llms.txt +9 -9
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 判据与原因句逐字等于消费方请求腿的那一份(钉:`test/mcp-request-entry-14.0.0.test.ts` 逐例搬了消费方既有钉的夹具与期望)。
|
|
11
11
|
* 本模块只答「这一格的形」;拒绝的整句(条目下标、条目名的回显清洗、收尾句)与「拒还是降级」的后果仍是消费方按自己的腿定的 —— 判据一份,后果按腿分。
|
|
12
12
|
* 与最初搬来时相比有三处收严,都是收到与消费方请求腿同严、不是新语义,消费方改 import 这一份之后不再各留一份旧判据:申报名判官另判**首尾空白**;
|
|
13
|
-
* `env` / `headers` 只收**纯数据**的「名 → 串」记录(Map /
|
|
13
|
+
* `env` / `headers` 只收**纯数据**的「名 → 串」记录(Map / 类实例不收;保留成员名 {@link RESERVED_MEMBER_NAMES} 不进副本,交出的是副本);两只回显描述器用消费方的回显口径(剥控制与双向字符、截 64 字、引号形)。
|
|
14
14
|
*
|
|
15
15
|
* ## 依赖的引擎事实(镜像 + 漂移门)
|
|
16
16
|
* · 申报名的线长界 {@link TOOL_WIRE_NAME_MAX_CHARS} = 引擎同名常量(值级对拍:上游漂移门 ⑧);
|
|
@@ -31,6 +31,8 @@ import { isJsonArray, isPlainJsonObject, jsonShapeOf } from "./plain-json-object
|
|
|
31
31
|
import { MCP_CONTENT_ORIGINS } from "./types.js";
|
|
32
32
|
import { RESERVED_MCP_SERVER_NAME_REASON, isReservedMcpServerName } from "./mcp-server-name.js";
|
|
33
33
|
import { startsWithHttpScheme } from "./url-shape.js";
|
|
34
|
+
import { TOOL_WIRE_NAME_MAX_CHARS, hasEdgeWhitespace, isUsableWireName } from "./wire-name.js";
|
|
35
|
+
import { isReservedMemberName } from "./reserved-member-name.js";
|
|
34
36
|
// ── 值的种类描述(拒句只说「你写的是什么形」,不回显值:值可能带凭据、可能任意长)──────────────────────────────────────
|
|
35
37
|
/** 值的**种类词**(不回显值本身):`null` / `array` / `typeof` 词(`object` / `function` / `string` …);读不出的对象 ⇒ 全包唯一的那一句。形状只问座位(总,不抛):两只坏值描述器共用这一只。 */
|
|
36
38
|
function describeKindWord(v) {
|
|
@@ -92,15 +94,15 @@ export function isStringArray(v) {
|
|
|
92
94
|
return captureStringArray(v, "strict") !== undefined;
|
|
93
95
|
}
|
|
94
96
|
/**
|
|
95
|
-
* 纯数据的「名 → 串」记录(空对象合法;数组、`Map
|
|
97
|
+
* 纯数据的「名 → 串」记录(空对象合法;数组、`Map`、类实例、有保留名成员({@link isReservedMemberName})、有非串成员的对象都不是)—— 类型守卫,所以是**严归类**:成员经内核的
|
|
96
98
|
* `ownEntriesOf` 读(整容器读的严归类:每个自有串键一份描述符;访问器成员或不可枚举的成员 ⇒ 不是,getter 一次都不调 —— 守卫为真,调用方随后的普通读读到的就是判过的那一份)。
|
|
97
|
-
* 传输读器读 `env` / `headers`({@link readPlainStringRecord})交出去的是**副本**,按宽归类读(不可枚举的成员照读、访问器调一次);值与成员名的判据(
|
|
99
|
+
* 传输读器读 `env` / `headers`({@link readPlainStringRecord})交出去的是**副本**,按宽归类读(不可枚举的成员照读、访问器调一次);值与成员名的判据(是串、不是保留名)两边同一条。
|
|
98
100
|
*/
|
|
99
101
|
export function isStringRecord(v) {
|
|
100
102
|
if (!isPlainJsonObject(v))
|
|
101
103
|
return false;
|
|
102
104
|
const entries = ownEntriesOf(v);
|
|
103
|
-
return entries.ok && entries.value.every(([name, value]) => name
|
|
105
|
+
return entries.ok && entries.value.every(([name, value]) => !isReservedMemberName(name) && typeof value === "string");
|
|
104
106
|
}
|
|
105
107
|
// ── 调用方写的串的回显口径 ──────────────────────────────────────────────────────────────────────────
|
|
106
108
|
/** 句子里点名一个值的写法:{@link echoCallerText} 外加一对双引号;内部的引号与反斜杠逐字(不转义)。 */
|
|
@@ -108,21 +110,9 @@ function quotedCallerText(text) {
|
|
|
108
110
|
return `"${echoCallerText(text)}"`;
|
|
109
111
|
}
|
|
110
112
|
// ── 申报名的线长界 ──────────────────────────────────────────────────────────────────────────────────
|
|
111
|
-
|
|
112
|
-
export
|
|
113
|
-
|
|
114
|
-
* 首尾带空白吗 —— 「空白」就是 `String.prototype.trim` 剥的那一组(ECMAScript 的 WhiteSpace + LineTerminator:空格 / 制表 / 换行 / NBSP / BOM / 全角空格 / 行段分隔符等)。
|
|
115
|
-
* {@link isUsableWireName} 与 {@link describeBadWireName} 共读这一个定义,判与说不会各按各的口径。
|
|
116
|
-
*/
|
|
117
|
-
const hasEdgeWhitespace = (v) => v.trim() !== v;
|
|
118
|
-
/**
|
|
119
|
-
* 这个申报名能用吗。严判:非串、空串、超 {@link TOOL_WIRE_NAME_MAX_CHARS}、**首尾带空白**一律不可用。不截断、不 trim、不规范化 —— 截短或剥掉一个名字就是**换一个身份**,
|
|
120
|
-
* 而被换掉身份的那台 server 上挂的 allowTools / toolFaces 收窄声明会一起对不上号。首尾空白 = 坏名(它不是另一个名字:名字是 `mcp__<server>__<tool>` 的身份片,
|
|
121
|
-
* 带着空白的一端无从与不带的那个对上号);内部空白(`a b`)照旧是合法名,本判官不扩判。
|
|
122
|
-
*/
|
|
123
|
-
export function isUsableWireName(v) {
|
|
124
|
-
return typeof v === "string" && v.length > 0 && v.length <= TOOL_WIRE_NAME_MAX_CHARS && !hasEdgeWhitespace(v);
|
|
125
|
-
}
|
|
113
|
+
// 判据住在零依赖叶子 `./wire-name`(18.0.0 搬过去:`./types` 的 `a2a` 对端名也问它,而本模块引 `./types` —— 留在这里会成环);公开名照旧经本模块转出,同一个函数对象。
|
|
114
|
+
export { TOOL_WIRE_NAME_MAX_CHARS, isUsableWireName } from "./wire-name.js";
|
|
115
|
+
export { RESERVED_MEMBER_NAMES, isReservedMemberName } from "./reserved-member-name.js"; // 18.0.0: the one reserved-member-name table (schema guard · this reader · the center-refs resolver)
|
|
126
116
|
/**
|
|
127
117
|
* 坏名的**可打印**摘要(进拒句 / 告警元数据):种类、`empty`,或引号形的回显加原因 —— 绝不把任意长度的申报串原样回显。回显口径见 {@link quotedCallerText}
|
|
128
118
|
* (剥控制与双向字符、截 64 字)。串的原因是:超界 ⇒ `N chars > 128`(N 是送来的原长度,不是剥完的);首尾带空白 ⇒ `leading or trailing whitespace`
|
|
@@ -222,7 +212,7 @@ const inheritedIdentityIssue = (key) => ({
|
|
|
222
212
|
* · 软坏形(`args` 不是串数组 / `env` `headers` 不是纯数据的串记录 / `principalHeader` 非串)⇒ 读器**丢这个键**(重放存量提交体时的升级前读法),并把它记进 `lost`
|
|
223
213
|
* (受理新提交的门据它响亮拒)。`assertionHeader` 不在 `lost` 里:两个身份头的键组合与 `assertionHeader` 的值形由调用方在读之前对原始传输判。
|
|
224
214
|
* · `env` / `headers` 只收**纯数据**的记录({@link readPlainStringRecord}):必须是朴素 JSON 对象(`./plain-json-object` 的判据;`Map`、`Set`、类实例整张不收),每个自有成员的值都是串;
|
|
225
|
-
* 交出的是**副本**(不是调用方的对象,改原对象不影响读后的形)
|
|
215
|
+
* 交出的是**副本**(不是调用方的对象,改原对象不影响读后的形)。名叫保留名({@link RESERVED_MEMBER_NAMES})的成员不进副本、每个单独记进 `lost`。
|
|
226
216
|
* 坏形的 `lost` 条目带机读位(见 {@link McpEntryKeyIssue})。
|
|
227
217
|
* url 的拒句不回显值:它常规地带凭据(userinfo)。
|
|
228
218
|
*/
|
|
@@ -323,12 +313,8 @@ function snapshotTransport(tr) {
|
|
|
323
313
|
return { ok: true, value: { kind: "other", value: kind.value } };
|
|
324
314
|
}
|
|
325
315
|
// ── 「名 → 串」记录的读法(`env` / `headers`)────────────────────────────────────────────────────────
|
|
326
|
-
/**
|
|
327
|
-
|
|
328
|
-
* 公开,因为读器交出 `reservedMember: true` 时消费方要点名它 —— 名字只在这里定一次。
|
|
329
|
-
*/
|
|
330
|
-
export const PLAIN_STRING_RECORD_RESERVED_MEMBER = "__proto__";
|
|
331
|
-
const RESERVED_MEMBER_FAULT = `no member of a declaration may be named "${PLAIN_STRING_RECORD_RESERVED_MEMBER}"`;
|
|
316
|
+
/** 保留成员名的原因句(一个名一句;名字取自那一张表 {@link RESERVED_MEMBER_NAMES})。 */
|
|
317
|
+
const reservedMemberFault = (name) => `no member of a declaration may be named "${name}"`;
|
|
332
318
|
/**
|
|
333
319
|
* 「名 → 串」记录读不交(或交时点名保留名)的**原因词**,闭集,三个词、一张表:
|
|
334
320
|
* 整张一词(`not_plain_record`)· 成员级一词(`member_not_string`:值读成了别的种类,或读成员时抛了 —— 句子分说)· 名字级一词(`member_name_reserved`)。
|
|
@@ -361,8 +347,8 @@ function notPlainDetail(shape, v) {
|
|
|
361
347
|
* 读一份「名 → 串」记录 —— **公开读口**:传输读器读 `env` / `headers` 用的就是它,消费方读自己的「名 → 串」记录(中心名册的引用表)调同一只,不抄镜像。从不抛。记录交不交:是朴素 JSON 对象(座位的判据,见 `./plain-json-object`:原型是 `null`,或原型自己的原型是 `null`;纯数据 —— `Map`、`Set`、类实例、建在原型上的记录都不是),
|
|
362
348
|
* 且每个成员的值都是串。成员 = `Object.getOwnPropertyNames` 的每一个名字(不可枚举的也算 —— 引擎的收据按全部自有属性名读),值经内核 `readKey` 读(一份描述符:数据属性取值,访问器调一次,不问 `get` 陷阱;访问器或描述符 trap 抛了同判为坏 —— 词与「值不是串」同是 `member_not_string`,句子说读不出)。
|
|
363
349
|
* 读原型与成员名时代理 trap 抛了 ⇒ 整张不交(读器对调用方递来的任何对象都不抛;`JSON` 存体里不会有代理,这条只落在直接调读器的嵌入方身上)。
|
|
364
|
-
* 交出去的是副本(原型 `Object.prototype`、成员全可枚举)
|
|
365
|
-
*
|
|
350
|
+
* 交出去的是副本(原型 `Object.prototype`、成员全可枚举),调用方的对象不被交出去、也不被改;名叫保留名({@link isReservedMemberName})的成员不进副本,`reservedMembers` 记下它们。
|
|
351
|
+
* 名叫保留名而值也坏的成员,句子一次说全两件事(名坏在前、值坏并列):调用方照值改完再撞第二条是两步才改对。
|
|
366
352
|
*/
|
|
367
353
|
export function readPlainStringRecord(v) {
|
|
368
354
|
// 形状归座位旁的分类(不在这里再推一遍;座位总 —— 读形状就抛的对象答 `uninspectable`)。成员名的读取(`ownKeys` 陷阱抛)读不出的对象也不是纯数据。
|
|
@@ -377,7 +363,7 @@ export function readPlainStringRecord(v) {
|
|
|
377
363
|
// 累加器是零原型的袋、成员用 `Object.defineProperty` + 零原型描述符写(定义语义,不走 [[Set]]),最后用对象展开(同为定义语义)铸成普通对象:原型上被污染成只读的同名键不让读器抛,
|
|
378
364
|
// 原型上的数字键 setter 吞不掉成员(此前 `entries.push` + `Object.fromEntries` 被继承的数字键 getter / setter 弄抛)
|
|
379
365
|
const members = Object.create(null);
|
|
380
|
-
|
|
366
|
+
const reservedMembers = names.filter(isReservedMemberName); // `filter` 走 CreateDataProperty,不走 [[Set]](继承的数字键 setter 吞不掉)
|
|
381
367
|
for (const name of names) {
|
|
382
368
|
// 成员经内核读(契约见函数头注):一份描述符里取值 —— 数据属性取值、访问器调一次、从不问 Proxy 的 `get` 陷阱;成员在两次读之间被删掉 ⇒ 不是串(不读继承来的值)
|
|
383
369
|
const read = readKey(v, name);
|
|
@@ -385,28 +371,25 @@ export function readPlainStringRecord(v) {
|
|
|
385
371
|
const value = read.presence === "own" ? read.value : undefined;
|
|
386
372
|
if (unreadable || typeof value !== "string") {
|
|
387
373
|
const valueFault = unreadable ? "could not be read (its getter threw)" : `must be a string — got ${describeValueShape(value)}`;
|
|
388
|
-
const reserved = name === PLAIN_STRING_RECORD_RESERVED_MEMBER;
|
|
389
374
|
// 词:名坏优先(句子里值坏并列说全);名没问题时,读不出与值不是串同词,句子分说
|
|
390
|
-
const fault =
|
|
375
|
+
const fault = isReservedMemberName(name) ? "member_name_reserved" : "member_not_string";
|
|
391
376
|
return {
|
|
392
377
|
ok: false,
|
|
393
378
|
fault,
|
|
394
379
|
member: echoCallerText(name),
|
|
395
|
-
detail: `its member "${echoCallerText(name)}" ${
|
|
380
|
+
detail: `its member "${echoCallerText(name)}" ${isReservedMemberName(name) ? `is not allowed (${reservedMemberFault(name)}) and its value ${valueFault}` : valueFault}`,
|
|
396
381
|
};
|
|
397
382
|
}
|
|
398
|
-
if (name
|
|
399
|
-
reservedMember = true;
|
|
400
|
-
else
|
|
383
|
+
if (!isReservedMemberName(name))
|
|
401
384
|
Object.defineProperty(members, name, dataDescriptor(value));
|
|
402
385
|
}
|
|
403
|
-
return { ok: true, record: { ...members },
|
|
386
|
+
return { ok: true, record: { ...members }, reservedMembers };
|
|
404
387
|
}
|
|
405
388
|
/** 把诊断条目铸成数组:`undefined`(这一处没有诊断)略去。`filter` 的结果走 `CreateDataProperty`,不走 `[[Set]]` —— `lost` 是「门拒什么」的读数,不能被继承的数字键 setter 吞掉。 */
|
|
406
389
|
const issuesOf = (...candidates) => candidates.filter((c) => c !== undefined);
|
|
407
390
|
/**
|
|
408
391
|
* `transport.env` / `transport.headers` 的读法(两键同一只):缺席 ⇒ 缺席;记录不交 ⇒ 一处诊断点名**这个键**(不交的是整张记录;坏在某个成员时句子与 `member` 点名它);
|
|
409
|
-
* 交 ⇒
|
|
392
|
+
* 交 ⇒ 纯数据副本,名叫保留名的成员每个单记一处诊断、路径 `<键>.<保留名>`。
|
|
410
393
|
*/
|
|
411
394
|
function readTransportRecord(path, raw) {
|
|
412
395
|
if (raw === undefined)
|
|
@@ -420,6 +403,6 @@ function readTransportRecord(path, raw) {
|
|
|
420
403
|
}
|
|
421
404
|
return {
|
|
422
405
|
record: read.record,
|
|
423
|
-
issues: read.
|
|
406
|
+
issues: read.reservedMembers.map((name) => ({ path: `${path}.${name}`, reason: reservedMemberFault(name), member: name, fault: "member_name_reserved" })),
|
|
424
407
|
};
|
|
425
408
|
}
|
package/dist/node.d.ts
CHANGED
|
@@ -8,8 +8,11 @@ export * from "./file-store.js";
|
|
|
8
8
|
export * from "./file-edit.js";
|
|
9
9
|
export * from "./bundle.js";
|
|
10
10
|
export * from "./local-load.js";
|
|
11
|
+
export { readConfigDFileReadingSync, type ConfigDDocumentName, type ConfigDFileReason, type ConfigDReading, type ConfigDRefused } from "./config-d-file.js";
|
|
11
12
|
export * from "./scheduler-store-node.js";
|
|
12
13
|
export { migrateConfigDirectory, migrateConfigDocuments, // 14.5.0:同一段「迁 → 整域终判」的同步口(入参是已有的存量文档,无 io)—— 目录形调的就是它的内核
|
|
13
14
|
type ConfigDirectoryDocument, type ConfigDirectoryIo, type ConfigDirectoryMigration, type ConfigDirectoryRefusal, type ConfigDocumentsMigration, type MigrateConfigDirectoryOptions, type MigrateConfigDocumentsOptions, } from "./config-dir-migration.js";
|
|
14
15
|
export { nodeConfigDirectoryIo } from "./config-dir-io.js";
|
|
15
|
-
export { migrateEnvModelsDecision, nodeConfigRootIo, readEnvModelsDecision,
|
|
16
|
+
export { migrateEnvModelsDecision, nodeConfigRootIo, readEnvModelsDecision, readEnvModelsDecisionSync, // 同步孪生:同一个字节读法 / 缺席律 / 答案表(壳在同步具名锁里写模型池要在锁里读决定)
|
|
17
|
+
readMigrationMarker, writeEnvModelsDecision, writeEnvModelsDecisionSync, // 同步孪生:同一份写计划 + 同一对同步原子写原语
|
|
18
|
+
type ConfigRootIo, type EnvModelsDecisionWrite, type EnvModelsMigration, type EnvModelsMint, } from "./config-root-node.js";
|
package/dist/node.js
CHANGED
|
@@ -8,10 +8,14 @@ export * from "./file-store.js";
|
|
|
8
8
|
export * from "./file-edit.js";
|
|
9
9
|
export * from "./bundle.js";
|
|
10
10
|
export * from "./local-load.js";
|
|
11
|
+
// 一份 `config.d/<名>.json` 的读数(缺席 / 在场 / 被拒)的**同步读口**:与包内异步读口同一只纯判、同一个缺席尾(壳在同步具名锁里读 `config.d` 文档用它,不自读文本);纯判本身与异步读口不出门。显式列名。
|
|
12
|
+
export { readConfigDFileReadingSync } from "./config-d-file.js";
|
|
11
13
|
export * from "./scheduler-store-node.js"; // R7 self-wake scheduler store — fs binding of the ./scheduler-store contract
|
|
12
14
|
// 目录形的一次性迁移(读目录 → 迁 → 整域终判 → 原子写 → 删 retired 域文件)—— 语义只此一处,命令行是它的渲染器、引擎起服调同一只。显式列名:该模块的包内私有件(出门形/拼路径)不外泄。
|
|
13
15
|
export { migrateConfigDirectory, migrateConfigDocuments, // 14.5.0:同一段「迁 → 整域终判」的同步口(入参是已有的存量文档,无 io)—— 目录形调的就是它的内核
|
|
14
16
|
} from "./config-dir-migration.js";
|
|
15
17
|
export { nodeConfigDirectoryIo } from "./config-dir-io.js"; // 上面那只函数的真 I/O 绑定:node:fs + 本包唯一的原子写器(config-document 模式规则)
|
|
16
|
-
// 配置根上的决定文档(config.env-models.json)与按 id 的运行记录(config.migration.<id>.json)的两只读者、决定文档的唯一写函数(
|
|
17
|
-
export { migrateEnvModelsDecision, nodeConfigRootIo, readEnvModelsDecision,
|
|
18
|
+
// 配置根上的决定文档(config.env-models.json)与按 id 的运行记录(config.migration.<id>.json)的两只读者、决定文档的唯一写函数(运行记录由迁移独占创建;决定文档的读写各有同步孪生),与一次性迁移 SS-M11 的迁移体(名字与闭集答案表在包根)。显式列名。
|
|
19
|
+
export { migrateEnvModelsDecision, nodeConfigRootIo, readEnvModelsDecision, readEnvModelsDecisionSync, // 同步孪生:同一个字节读法 / 缺席律 / 答案表(壳在同步具名锁里写模型池要在锁里读决定)
|
|
20
|
+
readMigrationMarker, writeEnvModelsDecision, writeEnvModelsDecisionSync, // 同步孪生:同一份写计划 + 同一对同步原子写原语
|
|
21
|
+
} from "./config-root-node.js";
|
|
@@ -138,7 +138,7 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
138
138
|
releasedOn: "2026-10-10",
|
|
139
139
|
removableAfter: "2026-11-09",
|
|
140
140
|
rewrites: "every NON_SECRET_URL seat in a domain document (derived from the domain schemas, not listed by hand — today models.models[].baseUrl, " +
|
|
141
|
-
"mcp.servers[].transport.url, execution.sessionMirror.engineUrl, workers.workers[].coords.gitApiBaseUrl): `#` and everything after it are removed " +
|
|
141
|
+
"mcp.servers[].transport.url, a2a.peers[].url, a2a.peers[].cardUrl, execution.sessionMirror.engineUrl, workers.workers[].coords.gitApiBaseUrl): `#` and everything after it are removed " +
|
|
142
142
|
"(a fragment never goes on the wire); the same walk covers config.d/remote-exec.json, derived from its schema the same way " +
|
|
143
143
|
"(today the k8s apiUrl and s3Snapshot.endpoint) — the command-line migrate reads and rewrites it as one more document",
|
|
144
144
|
removal: "the next major after the window: delete the SS-M7 step and its schema walk; the NON_SECRET_URL fragment rule loses its SS-M7 clause",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 同形**。当年 `limits` 域就是这样在单机腿静默丢了一整片限额发布(远端腿同批可用,所以更难看出来)。
|
|
13
13
|
* 今日的兜底:漏登记的文件会被 `FileConfigStore`(`./node`)的 `"unread-config-file"` 警告点名(fail-loud,
|
|
14
14
|
* 见 getEffective),但那只在消费方接了 `onWarning` 时才响 —— **登记仍是第一现场的义务**。 */
|
|
15
|
-
export declare const PORTABLE_DOMAINS: readonly ["models", "rosters", "skills", "mcp", "plugins", "scenarios", "collab", "governance", "execution", "prompts", "limits"];
|
|
15
|
+
export declare const PORTABLE_DOMAINS: readonly ["models", "rosters", "skills", "mcp", "plugins", "scenarios", "collab", "governance", "execution", "prompts", "limits", "a2a"];
|
|
16
16
|
export type PortableDomain = (typeof PORTABLE_DOMAINS)[number];
|
|
17
17
|
/**
|
|
18
18
|
* 非便携域的**排除理由表**(#282 件5 附带裁定:禁裸排除)。
|
package/dist/portable-domains.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 同形**。当年 `limits` 域就是这样在单机腿静默丢了一整片限额发布(远端腿同批可用,所以更难看出来)。
|
|
13
13
|
* 今日的兜底:漏登记的文件会被 `FileConfigStore`(`./node`)的 `"unread-config-file"` 警告点名(fail-loud,
|
|
14
14
|
* 见 getEffective),但那只在消费方接了 `onWarning` 时才响 —— **登记仍是第一现场的义务**。 */
|
|
15
|
-
export const PORTABLE_DOMAINS = ["models", "rosters", "skills", "mcp", "plugins", "scenarios", "collab", "governance", "execution", "prompts", "limits"];
|
|
15
|
+
export const PORTABLE_DOMAINS = ["models", "rosters", "skills", "mcp", "plugins", "scenarios", "collab", "governance", "execution", "prompts", "limits", "a2a"];
|
|
16
16
|
/**
|
|
17
17
|
* 非便携域的**排除理由表**(#282 件5 附带裁定:禁裸排除)。
|
|
18
18
|
*
|
package/dist/remote-exec.d.ts
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* - `host` run tools DIRECTLY on this machine, no container (the TOC default, like a local coding
|
|
13
13
|
* agent). No isolation.
|
|
14
14
|
* - `local-docker` containers on THIS machine's docker (isolation for parallel/untrusted fan-out).
|
|
15
|
+
* Either:
|
|
16
|
+
* - `none` (18.0.0) no execution environment for the agent's tools — the file form of `REMOTE_EXEC=none`. No fields:
|
|
17
|
+
* there is nothing to configure.
|
|
15
18
|
*
|
|
16
19
|
* 7.0.0: every `provider` word here is an execution lane word (`EXECUTION_LANE_WORDS`, `execution-lanes.ts` — the ONE
|
|
17
20
|
* vocabulary; `test/execution-lanes-7.0.0.test.ts` pins `provider ⊆ EXECUTION_LANE_WORDS`, at runtime and at compile time).
|
|
@@ -90,5 +93,7 @@ export declare const RemoteExecSpec: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
90
93
|
serial: z.ZodString;
|
|
91
94
|
adbPath: z.ZodOptional<z.ZodString>;
|
|
92
95
|
mountPath: z.ZodOptional<z.ZodString>;
|
|
96
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
97
|
+
provider: z.ZodLiteral<"none">;
|
|
93
98
|
}, z.core.$strip>], "provider">;
|
|
94
99
|
export type RemoteExecSpec = z.infer<typeof RemoteExecSpec>;
|
package/dist/remote-exec.js
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* - `host` run tools DIRECTLY on this machine, no container (the TOC default, like a local coding
|
|
13
13
|
* agent). No isolation.
|
|
14
14
|
* - `local-docker` containers on THIS machine's docker (isolation for parallel/untrusted fan-out).
|
|
15
|
+
* Either:
|
|
16
|
+
* - `none` (18.0.0) no execution environment for the agent's tools — the file form of `REMOTE_EXEC=none`. No fields:
|
|
17
|
+
* there is nothing to configure.
|
|
15
18
|
*
|
|
16
19
|
* 7.0.0: every `provider` word here is an execution lane word (`EXECUTION_LANE_WORDS`, `execution-lanes.ts` — the ONE
|
|
17
20
|
* vocabulary; `test/execution-lanes-7.0.0.test.ts` pins `provider ⊆ EXECUTION_LANE_WORDS`, at runtime and at compile time).
|
|
@@ -147,6 +150,8 @@ export const RemoteExecSpec = z.discriminatedUnion("provider", [
|
|
|
147
150
|
adbPath: execStr.optional(),
|
|
148
151
|
mountPath: execStr.optional(),
|
|
149
152
|
}),
|
|
153
|
+
// ── none (18.0.0): no execution environment for the agent's tools (REMOTE_EXEC=none). Zero fields — nothing to configure, no secrets.
|
|
154
|
+
z.object({ provider: z.literal("none") }),
|
|
150
155
|
], {
|
|
151
156
|
// A retired lane word as `provider` (no matching discriminator) gets the tombstone's way out; any other miss keeps zod's sentence.
|
|
152
157
|
// `provider` is read from the input's OWN keys (the input is the caller's object: an inherited / polluted `provider` is not the word they wrote; a proxy that cannot be read has no word to refuse)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 包内私有叶子模块(运行期零依赖,浏览器安全;不进 `package.json` 的 exports,主桶经 `./mcp-request-entry` 转出这里的公开名):
|
|
3
|
+
* **一个名字能不能作「名 → 串」记录的成员名**的唯一判据 —— 原型链上的三个名字永远不能:`__proto__`(按赋值拷贝会变成原型;zod 的 record 读键前先跳过它、不判它的值)、
|
|
4
|
+
* `constructor` / `prototype`(读方对普通对象做 `obj[名]` 时撞上原型成员)。
|
|
5
|
+
* 三个读口问它,同一张表、同一个答案:域 schema 的凭据引用集合(`./types` 的 `credentialRefs`:在场 ⇒ 集合坏)· 公开的记录读器(`./mcp-request-entry` 的 `readPlainStringRecord` /
|
|
6
|
+
* `isStringRecord`,请求面传输的 `env` / `headers` 同读:剔出副本并点名)· 中心引用解析口(`./center-refs`,经记录读器:在场 ⇒ `refs_unreadable`)。
|
|
7
|
+
* 住在叶子里,是因为 `./types` 与 `./mcp-request-entry` 都要它,而后者反过来引 `./types`。
|
|
8
|
+
*/
|
|
9
|
+
/** 保留成员名,闭集。 */
|
|
10
|
+
export declare const RESERVED_MEMBER_NAMES: readonly ["__proto__", "constructor", "prototype"];
|
|
11
|
+
export type ReservedMemberName = (typeof RESERVED_MEMBER_NAMES)[number];
|
|
12
|
+
/** 这个名字是保留成员名吗(大小写敏感:`Constructor` / `X-Prototype` 不是)。 */
|
|
13
|
+
export declare function isReservedMemberName(name: string): name is ReservedMemberName;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 包内私有叶子模块(运行期零依赖,浏览器安全;不进 `package.json` 的 exports,主桶经 `./mcp-request-entry` 转出这里的公开名):
|
|
3
|
+
* **一个名字能不能作「名 → 串」记录的成员名**的唯一判据 —— 原型链上的三个名字永远不能:`__proto__`(按赋值拷贝会变成原型;zod 的 record 读键前先跳过它、不判它的值)、
|
|
4
|
+
* `constructor` / `prototype`(读方对普通对象做 `obj[名]` 时撞上原型成员)。
|
|
5
|
+
* 三个读口问它,同一张表、同一个答案:域 schema 的凭据引用集合(`./types` 的 `credentialRefs`:在场 ⇒ 集合坏)· 公开的记录读器(`./mcp-request-entry` 的 `readPlainStringRecord` /
|
|
6
|
+
* `isStringRecord`,请求面传输的 `env` / `headers` 同读:剔出副本并点名)· 中心引用解析口(`./center-refs`,经记录读器:在场 ⇒ `refs_unreadable`)。
|
|
7
|
+
* 住在叶子里,是因为 `./types` 与 `./mcp-request-entry` 都要它,而后者反过来引 `./types`。
|
|
8
|
+
*/
|
|
9
|
+
/** 保留成员名,闭集。 */
|
|
10
|
+
export const RESERVED_MEMBER_NAMES = ["__proto__", "constructor", "prototype"];
|
|
11
|
+
/** 这个名字是保留成员名吗(大小写敏感:`Constructor` / `X-Prototype` 不是)。 */
|
|
12
|
+
export function isReservedMemberName(name) {
|
|
13
|
+
return RESERVED_MEMBER_NAMES.includes(name);
|
|
14
|
+
}
|
package/dist/retired-envs.js
CHANGED
|
@@ -75,6 +75,8 @@ export const RETIRED_ENVS = [
|
|
|
75
75
|
["HOST_EXEC_SPOOL_DISABLED", "HOST_EXEC_SPOOL_ENABLED", "replaced", negativeAliasWhy("HOST_EXEC_SPOOL_DISABLED", "HOST_EXEC_SPOOL_ENABLED")],
|
|
76
76
|
// 无人值守腿的模式旋钮退役:这些腿的答集是常量,不是旋钮。
|
|
77
77
|
["UNATTENDED_PERMISSION_MODE", "since server 7.109.0 the unattended legs (leader workers and their repair legs, run-local, and their durable resumes) always run permissionMode \"default\" with an approver that answers by ask class: a machine answers only \"ordinary\" asks, and every other class goes to the leg's approver seat (run-local's terminal prompt) or parks / is refused — there is no mode to choose", "removed"],
|
|
78
|
+
// 执行车道总开关:每个部署都点名自己的车道之后它恒真(「点名了没有」只剩一个答者 REMOTE_EXEC),留着 = 两个键答一个问题;「没有执行环境」也是一个声明(REMOTE_EXEC=none)。
|
|
79
|
+
["REQUIRE_EXECUTION_LANE", "REMOTE_EXEC", "replaced", "every deployment names its execution lane; REMOTE_EXEC=none declares one with no execution environment"],
|
|
78
80
|
];
|
|
79
81
|
// 冻结:拿到导出的人改不了拒启判据(读拒句的与投影 wire 的是同一个数组对象)。
|
|
80
82
|
for (const row of RETIRED_ENVS)
|
package/dist/secret-refs.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface EnvRef {
|
|
|
18
18
|
envName: string;
|
|
19
19
|
refs: EnvRefUse[];
|
|
20
20
|
}
|
|
21
|
-
/** Every env-NAME referenced across models / workers / mcp, grouped + sorted by name.
|
|
21
|
+
/** Every env-NAME referenced across models / workers / mcp / a2a, grouped + sorted by name.
|
|
22
22
|
* (integrations domain DELETED in 0.6.0 — OA/Gitea coordinates ride worker.env/secretEnv, EXPERT-REDESIGN §9.) */
|
|
23
23
|
export declare function collectEnvRefs(eff: EffectiveConfig): EnvRef[];
|
|
24
24
|
/**
|
package/dist/secret-refs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Every env-NAME referenced across models / workers / mcp, grouped + sorted by name.
|
|
1
|
+
/** Every env-NAME referenced across models / workers / mcp / a2a, grouped + sorted by name.
|
|
2
2
|
* (integrations domain DELETED in 0.6.0 — OA/Gitea coordinates ride worker.env/secretEnv, EXPERT-REDESIGN §9.) */
|
|
3
3
|
export function collectEnvRefs(eff) {
|
|
4
4
|
const map = new Map();
|
|
@@ -33,6 +33,10 @@ export function collectEnvRefs(eff) {
|
|
|
33
33
|
for (const [key, envName] of Object.entries(refs ?? {}))
|
|
34
34
|
add(envName, "mcp", `server "${s.name}" ${kind}.${key}`);
|
|
35
35
|
}
|
|
36
|
+
// 18.0.0: an A2A peer's header references are env-NAMEs the reading side must provide, like an http MCP server's.
|
|
37
|
+
for (const p of eff.a2a.peers)
|
|
38
|
+
for (const [key, envName] of Object.entries(p.headerRefs ?? {}))
|
|
39
|
+
add(envName, "a2a", `peer "${p.name}" headerRefs.${key}`);
|
|
36
40
|
return [...map.entries()].map(([envName, refs]) => ({ envName, refs })).sort((a, b) => a.envName.localeCompare(b.envName));
|
|
37
41
|
}
|
|
38
42
|
/**
|
package/dist/settings-units.d.ts
CHANGED
|
@@ -75,6 +75,9 @@ export declare function unitTighten(unit: SettingsUnitName, member?: string): Ti
|
|
|
75
75
|
* are `"manual"` ⇒ `"default"` (permissionMode) and `"disable"` ⇒ `true` (kill-switches); `"bypassPermissions"` is `launch_only`.
|
|
76
76
|
* The last step of every reading is the unit comparator's own domain: whatever reads, compares (file header).
|
|
77
77
|
* Addressing is {@link unitTighten}'s (same RangeErrors: a `members` unit needs a declared member, …).
|
|
78
|
+
* `unreadable` on a `member` / `members` unit is NOT absence, and the reading carries no direction: what the caller does with it depends on the member's
|
|
79
|
+
* `memberAdmission(category, member).direction` (`loosen` ⇒ may be dropped, loudly; `tighten` ⇒ must be kept and answered strictest on its own surface) —
|
|
80
|
+
* see WHEN A MEMBER DOES NOT READ in the file header.
|
|
78
81
|
*/
|
|
79
82
|
export declare function readSettingsUnit(unit: SettingsUnitName, raw: unknown, member?: string): {
|
|
80
83
|
readonly ok: true;
|
package/dist/settings-units.js
CHANGED
|
@@ -38,6 +38,21 @@
|
|
|
38
38
|
* owner, the comparator; a reading only adds what it needs on top (non-empty list elements, the hooks judge, …). So a value the
|
|
39
39
|
* shape half accepts but the comparator cannot place — a hooks document the hooks judge loads while a key it strips hides data
|
|
40
40
|
* nested deeper than `MAX_HASH_DEPTH`, or an `undefined` — is `unreadable`, never "read but not comparable".
|
|
41
|
+
* WHEN A MEMBER DOES NOT READ (the disposition law). On a `member` / `members` unit, `unreadable` is NOT absence: absence is "the document does
|
|
42
|
+
* not set this member", `unreadable` is "the document sets it, in a form the contract cannot place". The two facts a caller needs to dispose of
|
|
43
|
+
* it are already tables, and neither is carried by the reading (a reading has no `direction`: a `whole` unit has no direction source, so the field
|
|
44
|
+
* could only be optional and every consumer would still branch on its absence — and it would be a second reader of a member row's `direction`):
|
|
45
|
+
* the member's direction is `memberAdmission(category, member).direction`, and the category's failure direction is `SAFETY_MERGE_SPEC[category].fail`.
|
|
46
|
+
* For a member of a category whose `fail` is `closed` (today every category that declares members: `permissions`, `sandboxNetwork`, `killSwitches`):
|
|
47
|
+
* · a `loosen` member — the caller MAY drop it (dropping grants less), loudly: it says which member of which layer was dropped and why;
|
|
48
|
+
* · a `tighten` member — the caller must NOT drop it and must NOT read it as absent: it keeps the member and answers on ITS surface with the
|
|
49
|
+
* strictest answer it has (the rules surface refuses every call it cannot place; a kill-switch counts as ON; a sandbox switch takes its strict
|
|
50
|
+
* pole), because dropping a tighten member reads a restriction its author wrote — in a form the contract cannot place — as no restriction at all;
|
|
51
|
+
* the contract cannot tell what it was meant to forbid, and the strictest answer is the only one that cannot be looser than what the author meant.
|
|
52
|
+
* The package enforces nothing here (the surfaces are the consumers'); what it pins is that both inputs exist for every such member and that every
|
|
53
|
+
* out-of-domain value reads `unreadable` without throwing. Not covered, and not settled here: the `whole` units (`permissionMode`, `additionalDirectories`,
|
|
54
|
+
* `hooks`, `env`, `model`, `outputStyle`) have no direction column; whether "unreadable = absent" closes for them depends on the order of the
|
|
55
|
+
* unit's own value domain, which is a design question of its own.
|
|
41
56
|
* The env DOCUMENT's literal grammar (boolean words, csv + empty-set sentinel, a "≤ 0 means off" cap) is not here: it belongs to
|
|
42
57
|
* the engine's env catalog, whose one implementation is the server's.
|
|
43
58
|
*/
|
|
@@ -165,6 +180,9 @@ function shapedReading(unit, row, rule, raw) {
|
|
|
165
180
|
* are `"manual"` ⇒ `"default"` (permissionMode) and `"disable"` ⇒ `true` (kill-switches); `"bypassPermissions"` is `launch_only`.
|
|
166
181
|
* The last step of every reading is the unit comparator's own domain: whatever reads, compares (file header).
|
|
167
182
|
* Addressing is {@link unitTighten}'s (same RangeErrors: a `members` unit needs a declared member, …).
|
|
183
|
+
* `unreadable` on a `member` / `members` unit is NOT absence, and the reading carries no direction: what the caller does with it depends on the member's
|
|
184
|
+
* `memberAdmission(category, member).direction` (`loosen` ⇒ may be dropped, loudly; `tighten` ⇒ must be kept and answered strictest on its own surface) —
|
|
185
|
+
* see WHEN A MEMBER DOES NOT READ in the file header.
|
|
168
186
|
*/
|
|
169
187
|
export function readSettingsUnit(unit, raw, member) {
|
|
170
188
|
const t = unitTarget(unit, member);
|
package/dist/types.d.ts
CHANGED
|
@@ -1428,17 +1428,9 @@ export declare const WorkerSpec: z.ZodObject<{
|
|
|
1428
1428
|
runtime: z.ZodObject<{
|
|
1429
1429
|
execution: z.ZodOptional<z.ZodObject<{
|
|
1430
1430
|
lane: z.ZodOptional<z.ZodNever>;
|
|
1431
|
-
lanes: z.
|
|
1432
|
-
host: "host";
|
|
1433
|
-
e2b: "e2b";
|
|
1434
|
-
k8s: "k8s";
|
|
1435
|
-
ssh: "ssh";
|
|
1436
|
-
adb: "adb";
|
|
1437
|
-
"local-docker": "local-docker";
|
|
1438
|
-
device: "device";
|
|
1439
|
-
}>>;
|
|
1431
|
+
lanes: z.ZodPreprocess<z.ZodPipe<z.ZodUnknown, z.ZodTransform<("none" | "host" | "e2b" | "k8s" | "ssh" | "adb" | "local-docker" | "device")[], unknown>>, unknown>;
|
|
1440
1432
|
coords: z.ZodPrefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1441
|
-
secretRefs: z.ZodPrefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1433
|
+
secretRefs: z.ZodPrefault<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1442
1434
|
}, z.core.$strip>>;
|
|
1443
1435
|
store: z.ZodOptional<z.ZodObject<{
|
|
1444
1436
|
backend: z.ZodEnum<{
|
|
@@ -1492,7 +1484,7 @@ export declare const WorkerSpec: z.ZodObject<{
|
|
|
1492
1484
|
tidbPasswordEnv: z.ZodOptional<z.ZodNever>;
|
|
1493
1485
|
}, z.core.$strip>;
|
|
1494
1486
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1495
|
-
secretEnv: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1487
|
+
secretEnv: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1496
1488
|
recreateNonce: z.ZodOptional<z.ZodString>;
|
|
1497
1489
|
lifecycle: z.ZodOptional<z.ZodObject<{
|
|
1498
1490
|
kind: z.ZodDefault<z.ZodEnum<{
|
|
@@ -1597,17 +1589,9 @@ export declare const WorkersConfig: z.ZodObject<{
|
|
|
1597
1589
|
runtime: z.ZodObject<{
|
|
1598
1590
|
execution: z.ZodOptional<z.ZodObject<{
|
|
1599
1591
|
lane: z.ZodOptional<z.ZodNever>;
|
|
1600
|
-
lanes: z.
|
|
1601
|
-
host: "host";
|
|
1602
|
-
e2b: "e2b";
|
|
1603
|
-
k8s: "k8s";
|
|
1604
|
-
ssh: "ssh";
|
|
1605
|
-
adb: "adb";
|
|
1606
|
-
"local-docker": "local-docker";
|
|
1607
|
-
device: "device";
|
|
1608
|
-
}>>;
|
|
1592
|
+
lanes: z.ZodPreprocess<z.ZodPipe<z.ZodUnknown, z.ZodTransform<("none" | "host" | "e2b" | "k8s" | "ssh" | "adb" | "local-docker" | "device")[], unknown>>, unknown>;
|
|
1609
1593
|
coords: z.ZodPrefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1610
|
-
secretRefs: z.ZodPrefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1594
|
+
secretRefs: z.ZodPrefault<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1611
1595
|
}, z.core.$strip>>;
|
|
1612
1596
|
store: z.ZodOptional<z.ZodObject<{
|
|
1613
1597
|
backend: z.ZodEnum<{
|
|
@@ -1661,7 +1645,7 @@ export declare const WorkersConfig: z.ZodObject<{
|
|
|
1661
1645
|
tidbPasswordEnv: z.ZodOptional<z.ZodNever>;
|
|
1662
1646
|
}, z.core.$strip>;
|
|
1663
1647
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1664
|
-
secretEnv: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1648
|
+
secretEnv: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1665
1649
|
recreateNonce: z.ZodOptional<z.ZodString>;
|
|
1666
1650
|
lifecycle: z.ZodOptional<z.ZodObject<{
|
|
1667
1651
|
kind: z.ZodDefault<z.ZodEnum<{
|
|
@@ -1844,15 +1828,28 @@ export declare const SkillsManifestSchema: z.ZodObject<{
|
|
|
1844
1828
|
contentHash: z.ZodString;
|
|
1845
1829
|
}, z.core.$strip>>>;
|
|
1846
1830
|
}, z.core.$strip>;
|
|
1831
|
+
/**
|
|
1832
|
+
* 18.0.0 —— **凭据引用集合不可部分抢救**(按 schema 身份的集合)。成员是「名 → 宿主 env-NAME」的凭据引用 Record:mcp 的 `envRefs` / `headerRefs`
|
|
1833
|
+
* (a2a 对端的 `headerRefs` 复用后者,因此同在)、车道块的 `secretRefs` 与 worker 的 `secretEnv`。逐条抢救(`salvageEntries`)走到成员**不下钻**、把它当一个值判:
|
|
1834
|
+
* 集合里任一键 / 值坏形 ⇒ 它所属的那一条条目整条 `entry-dropped`,兄弟条目保留。理由:丢掉一条坏引用不是「更窄」,而是让条目带着**一半凭据**活下来 ——
|
|
1835
|
+
* 拨一个远端服务 / 智能体时错误的失败方向(读方对「任一引用的 env 缺席」本来就整条跳过,同一个方向)。
|
|
1836
|
+
* 既有读数只变一处:直接对 `WorkersConfig` 调 `salvageEntries` 时,`secretEnv` 带坏引用的 worker 由「只丢那一条引用、worker 存活」变「整条丢」
|
|
1837
|
+
* (各域读数不变:workers 域不逐条抢救;mcp 的两只住在传输判别联合里,走查不进联合;车道块住在不是集合的 `runtime` 对象里)
|
|
1838
|
+
* —— 由 17.2.0 包的真读数逐行对拍钉住(`test/atomic-salvage-18.0.0.test.ts`,改了读数的那一行逐行登记)。别的集合字段(allowTools / scenarios / allowSkills …)照旧逐条抢救:丢坏元素只会更窄。
|
|
1839
|
+
* 成员读键按自有属性名判:`__proto__` / `constructor` / `prototype` 任一在场 ⇒ 集合坏 ⇒ 条目整条丢(见 `credentialRefs`;zod 的 record 读键前跳过 `__proto__`、不判它的值)。
|
|
1840
|
+
* 新的凭据引用集合必须复用这几只 schema 或由 `credentialRefs` 铸出并登记进这里(按身份判,换一只「形一样」的新 schema 不算成员)。
|
|
1841
|
+
* 登记的是剥掉包装之后的那只 `record`(与抢救走查同一只读法 `unwrapSchema`)。
|
|
1842
|
+
*/
|
|
1843
|
+
export declare const ATOMIC_SALVAGE: ReadonlySet<z.ZodType>;
|
|
1847
1844
|
export declare const McpTransport: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
1848
1845
|
kind: z.ZodLiteral<"stdio">;
|
|
1849
1846
|
command: z.ZodString;
|
|
1850
1847
|
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1851
|
-
envRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1848
|
+
envRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1852
1849
|
}, z.core.$strip>, z.ZodObject<{
|
|
1853
1850
|
kind: z.ZodLiteral<"http">;
|
|
1854
1851
|
url: z.ZodString;
|
|
1855
|
-
headerRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1852
|
+
headerRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1856
1853
|
principalHeader: z.ZodOptional<z.ZodString>;
|
|
1857
1854
|
assertionHeader: z.ZodOptional<z.ZodString>;
|
|
1858
1855
|
}, z.core.$strip>], "kind">;
|
|
@@ -1870,11 +1867,11 @@ export declare const McpServerSpec: z.ZodObject<{
|
|
|
1870
1867
|
kind: z.ZodLiteral<"stdio">;
|
|
1871
1868
|
command: z.ZodString;
|
|
1872
1869
|
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1873
|
-
envRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1870
|
+
envRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1874
1871
|
}, z.core.$strip>, z.ZodObject<{
|
|
1875
1872
|
kind: z.ZodLiteral<"http">;
|
|
1876
1873
|
url: z.ZodString;
|
|
1877
|
-
headerRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1874
|
+
headerRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1878
1875
|
principalHeader: z.ZodOptional<z.ZodString>;
|
|
1879
1876
|
assertionHeader: z.ZodOptional<z.ZodString>;
|
|
1880
1877
|
}, z.core.$strip>], "kind">;
|
|
@@ -1905,11 +1902,11 @@ export declare const McpConfig: z.ZodObject<{
|
|
|
1905
1902
|
kind: z.ZodLiteral<"stdio">;
|
|
1906
1903
|
command: z.ZodString;
|
|
1907
1904
|
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1908
|
-
envRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1905
|
+
envRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1909
1906
|
}, z.core.$strip>, z.ZodObject<{
|
|
1910
1907
|
kind: z.ZodLiteral<"http">;
|
|
1911
1908
|
url: z.ZodString;
|
|
1912
|
-
headerRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1909
|
+
headerRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1913
1910
|
principalHeader: z.ZodOptional<z.ZodString>;
|
|
1914
1911
|
assertionHeader: z.ZodOptional<z.ZodString>;
|
|
1915
1912
|
}, z.core.$strip>], "kind">;
|
|
@@ -1934,6 +1931,32 @@ export declare const McpConfig: z.ZodObject<{
|
|
|
1934
1931
|
}, z.core.$strip>>>;
|
|
1935
1932
|
}, z.core.$strip>;
|
|
1936
1933
|
export type McpConfig = z.infer<typeof McpConfig>;
|
|
1934
|
+
/** 一个常驻出站 A2A 对端。 */
|
|
1935
|
+
export declare const A2aPeerSpec: z.ZodObject<{
|
|
1936
|
+
name: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
1937
|
+
url: z.ZodString;
|
|
1938
|
+
cardUrl: z.ZodOptional<z.ZodString>;
|
|
1939
|
+
headerRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1940
|
+
principalHeader: z.ZodOptional<z.ZodString>;
|
|
1941
|
+
allowSkills: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1942
|
+
scenarios: z.ZodPrefault<z.ZodArray<z.ZodString>>;
|
|
1943
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1944
|
+
}, z.core.$strip>;
|
|
1945
|
+
export type A2aPeerSpec = z.infer<typeof A2aPeerSpec>;
|
|
1946
|
+
/** `a2a` 域:常驻出站 A2A 对端名册。空 / 缺席 = 不拨任何对端。对端名唯一(重名拒,同 mcp)。 */
|
|
1947
|
+
export declare const A2aConfig: z.ZodObject<{
|
|
1948
|
+
peers: z.ZodPrefault<z.ZodArray<z.ZodObject<{
|
|
1949
|
+
name: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
1950
|
+
url: z.ZodString;
|
|
1951
|
+
cardUrl: z.ZodOptional<z.ZodString>;
|
|
1952
|
+
headerRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
1953
|
+
principalHeader: z.ZodOptional<z.ZodString>;
|
|
1954
|
+
allowSkills: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1955
|
+
scenarios: z.ZodPrefault<z.ZodArray<z.ZodString>>;
|
|
1956
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1957
|
+
}, z.core.$strip>>>;
|
|
1958
|
+
}, z.core.$strip>;
|
|
1959
|
+
export type A2aConfig = z.infer<typeof A2aConfig>;
|
|
1937
1960
|
/** A plugin/marketplace ORIGIN string: **https only**(contract freeze [ref] tightening-① /
|
|
1938
1961
|
* [1366]①,0.10.23 单真源修:此前这条规则只落在 web UI 层的表单校验,API 直写仍放行任意形——
|
|
1939
1962
|
* 同一条规则两处真源,API 这处敞了 8 天)。`ssh:`/`scp 形`/`git:`/`file:`/裸 `http:`/`owner/repo`
|
|
@@ -2509,11 +2532,11 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
2509
2532
|
kind: z.ZodLiteral<"stdio">;
|
|
2510
2533
|
command: z.ZodString;
|
|
2511
2534
|
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
2512
|
-
envRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
2535
|
+
envRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
2513
2536
|
}, z.core.$strip>, z.ZodObject<{
|
|
2514
2537
|
kind: z.ZodLiteral<"http">;
|
|
2515
2538
|
url: z.ZodString;
|
|
2516
|
-
headerRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
2539
|
+
headerRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
2517
2540
|
principalHeader: z.ZodOptional<z.ZodString>;
|
|
2518
2541
|
assertionHeader: z.ZodOptional<z.ZodString>;
|
|
2519
2542
|
}, z.core.$strip>], "kind">;
|
|
@@ -2677,17 +2700,9 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
2677
2700
|
runtime: z.ZodObject<{
|
|
2678
2701
|
execution: z.ZodOptional<z.ZodObject<{
|
|
2679
2702
|
lane: z.ZodOptional<z.ZodNever>;
|
|
2680
|
-
lanes: z.
|
|
2681
|
-
host: "host";
|
|
2682
|
-
e2b: "e2b";
|
|
2683
|
-
k8s: "k8s";
|
|
2684
|
-
ssh: "ssh";
|
|
2685
|
-
adb: "adb";
|
|
2686
|
-
"local-docker": "local-docker";
|
|
2687
|
-
device: "device";
|
|
2688
|
-
}>>;
|
|
2703
|
+
lanes: z.ZodPreprocess<z.ZodPipe<z.ZodUnknown, z.ZodTransform<("none" | "host" | "e2b" | "k8s" | "ssh" | "adb" | "local-docker" | "device")[], unknown>>, unknown>;
|
|
2689
2704
|
coords: z.ZodPrefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
2690
|
-
secretRefs: z.ZodPrefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
2705
|
+
secretRefs: z.ZodPrefault<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
2691
2706
|
}, z.core.$strip>>;
|
|
2692
2707
|
store: z.ZodOptional<z.ZodObject<{
|
|
2693
2708
|
backend: z.ZodEnum<{
|
|
@@ -2741,7 +2756,7 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
2741
2756
|
tidbPasswordEnv: z.ZodOptional<z.ZodNever>;
|
|
2742
2757
|
}, z.core.$strip>;
|
|
2743
2758
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
2744
|
-
secretEnv: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
2759
|
+
secretEnv: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
2745
2760
|
recreateNonce: z.ZodOptional<z.ZodString>;
|
|
2746
2761
|
lifecycle: z.ZodOptional<z.ZodObject<{
|
|
2747
2762
|
kind: z.ZodDefault<z.ZodEnum<{
|
|
@@ -3083,6 +3098,18 @@ export declare const DOMAIN_SCHEMAS: {
|
|
|
3083
3098
|
runStaleSec: z.ZodOptional<z.ZodNumber>;
|
|
3084
3099
|
toolResultTtlSec: z.ZodOptional<z.ZodNumber>;
|
|
3085
3100
|
}, z.core.$loose>;
|
|
3101
|
+
readonly a2a: z.ZodObject<{
|
|
3102
|
+
peers: z.ZodPrefault<z.ZodArray<z.ZodObject<{
|
|
3103
|
+
name: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
3104
|
+
url: z.ZodString;
|
|
3105
|
+
cardUrl: z.ZodOptional<z.ZodString>;
|
|
3106
|
+
headerRefs: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodString>, unknown>>;
|
|
3107
|
+
principalHeader: z.ZodOptional<z.ZodString>;
|
|
3108
|
+
allowSkills: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
3109
|
+
scenarios: z.ZodPrefault<z.ZodArray<z.ZodString>>;
|
|
3110
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
3111
|
+
}, z.core.$strip>>>;
|
|
3112
|
+
}, z.core.$strip>;
|
|
3086
3113
|
};
|
|
3087
3114
|
export type DomainName = keyof typeof DOMAIN_SCHEMAS;
|
|
3088
3115
|
export type DomainConfig = {
|
|
@@ -3130,6 +3157,8 @@ export interface EffectiveConfig {
|
|
|
3130
3157
|
/** cost/限流族的热更新发布位(0.19.0,消费方 #322 批1)。域缺席 ⇒ `{}`(每一键都 ABSENT =
|
|
3131
3158
|
* web-admin 不管 ⇒ 消费方回 env 底);11.0.0 起五个限额键的唯一位。 */
|
|
3132
3159
|
limits: LimitsConfig;
|
|
3160
|
+
/** 常驻出站 A2A 对端名册(18.0.0)。域缺席 ⇒ `{ peers: [] }`(缺席 ≡ 空表:不拨任何对端);header 值只以 env-NAME 引用出现,读方从自己的环境取值。 */
|
|
3161
|
+
a2a: A2aConfig;
|
|
3133
3162
|
}
|
|
3134
3163
|
/** One provenance source in a key's resolution trail. Two orthogonal axes: the TOC file LAYER, or the TOB
|
|
3135
3164
|
* PRINCIPAL dimension. `applied:false` + `reason` mark a source whose attempt was REJECTED by the monotone
|