@sema-agent/settings-schema 15.1.0 → 16.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 +226 -0
- package/README.md +60 -46
- package/conformance/VERSION +1 -1
- package/conformance/cases/c16-deep-nesting-205/expected.json +2 -2
- package/conformance/cases/c16-deep-nesting-205/meta.json +1 -1
- package/conformance/cases/c50-s784-lane-host-legal/expected.json +6 -2
- package/conformance/cases/c50-s784-lane-host-legal/input.json +3 -1
- package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +6 -2
- package/conformance/cases/c51-s784-lane-e2b-legal/input.json +3 -1
- package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +6 -2
- package/conformance/cases/c52-s784-lane-k8s-legal/input.json +3 -1
- package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +6 -2
- package/conformance/cases/c53-s784-lane-ssh-legal/input.json +3 -1
- package/conformance/cases/c54-s784-lane-adb-legal/expected.json +6 -2
- package/conformance/cases/c54-s784-lane-adb-legal/input.json +3 -1
- package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +6 -2
- package/conformance/cases/c55-s784-lane-local-docker-legal/input.json +3 -1
- package/conformance/cases/c56-s784-lane-device-legal/expected.json +8 -2
- package/conformance/cases/c56-s784-lane-device-legal/input.json +5 -2
- package/conformance/cases/c57-s784-g1-enabled-no-lane/meta.json +1 -1
- package/conformance/cases/c58-s784-g2-multitenant-host/input.json +3 -1
- package/conformance/cases/c59-s784-g3-k8s-missing-image/input.json +3 -1
- package/conformance/cases/c60-s784-g3-e2b-missing-key/input.json +3 -1
- package/conformance/cases/c61-s784-g3-other-lane-key/input.json +3 -1
- package/conformance/cases/c62-s784-g7a-session-tidb/input.json +3 -1
- package/conformance/cases/c63-s784-host-two-replicas/input.json +3 -1
- package/conformance/cases/c64-s784-multitenant-local-store/input.json +3 -1
- package/conformance/cases/c65-s784-pg-without-db/input.json +3 -1
- package/conformance/cases/c66-s784-memory-backend-mismatch/input.json +3 -1
- package/conformance/cases/c66-s784-memory-backend-mismatch/meta.json +1 -1
- package/conformance/cases/c68-s784-device-local-store/input.json +6 -1
- package/conformance/cases/cli04-env-value-with-newline/expected.json +6 -2
- package/conformance/cases/cli04-env-value-with-newline/input.json +3 -1
- package/dist/cli.d.ts +1 -1
- package/dist/config-d-file.d.ts +41 -5
- package/dist/config-d-file.js +105 -22
- package/dist/config-document-refusal.d.ts +39 -0
- package/dist/config-document-refusal.js +2 -0
- package/dist/device-relay.d.ts +21 -0
- package/dist/device-relay.js +23 -0
- package/dist/env-model-table.d.ts +2 -9
- package/dist/env-model-table.js +6 -14
- package/dist/execution-lane-index.d.ts +21 -17
- package/dist/execution-lane-index.js +28 -20
- package/dist/execution-lanes.d.ts +20 -5
- package/dist/execution-lanes.js +31 -7
- package/dist/file-store.d.ts +30 -3
- package/dist/file-store.js +89 -32
- package/dist/fleet.d.ts +6 -8
- package/dist/fleet.js +5 -7
- package/dist/hooks.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -3
- package/dist/migration-receipt.d.ts +1 -1
- package/dist/migration-receipt.js +1 -1
- package/dist/one-time-migrations.d.ts +1 -1
- package/dist/one-time-migrations.js +166 -45
- package/dist/remote-exec.js +11 -4
- package/dist/safety-merge-spec.d.ts +1 -1
- package/dist/safety-merge-spec.js +1 -1
- package/dist/types.d.ts +15 -11
- package/dist/types.js +100 -49
- package/dist/url-shape.d.ts +18 -0
- package/dist/url-shape.js +22 -0
- package/docs/API-SURFACE.md +18 -7
- package/docs/CONFORMANCE.md +1 -7
- package/docs/CONSUMER-INTEGRATION.md +4 -4
- package/llms-full.txt +27 -25
- package/llms.txt +10 -8
- package/package.json +1 -1
package/dist/file-store.js
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* - A MISSING file (ENOENT) → the domain is absent → schema defaults fill in (parseDomain tolerates undefined).
|
|
15
15
|
* A present-but-EMPTY/whitespace file is a half-write → THROW (fail-closed, like remote-exec); to mean
|
|
16
16
|
* "absent/defaults" the file must be missing, not empty. A valid `{}` object IS a set domain (→ defaults).
|
|
17
|
+
* - `read()` (16.0.0) is the ONE read that answers both ways: the effective config + its read warnings as data when every
|
|
18
|
+
* document reads, or the typed refusal list of the whole directory + its version when one does not — every document read once.
|
|
17
19
|
* - Non-portable domains are OMITTED on a single machine and resolve to their schema defaults (`{workers:[]}`
|
|
18
20
|
* etc.) — no stubbing needed. 逐域为什么被排除见 {@link NON_PORTABLE_DOMAIN_REASONS}(禁裸排除)。
|
|
19
21
|
* - A RETIRED domain's file (`config.d/runtime.json`, see `RETIRED_DOMAINS`) is read only for its tombstone: carrying facts ⇒
|
|
@@ -24,16 +26,13 @@
|
|
|
24
26
|
* "skip re-apply if version unchanged" works locally. `getEffective().updatedAt` = the max file mtime,
|
|
25
27
|
* passed EXPLICITLY into buildEffective (the determinism refactor) so identical files ⇒ identical bytes.
|
|
26
28
|
*/
|
|
27
|
-
import { readdir,
|
|
29
|
+
import { readdir, stat } from "node:fs/promises";
|
|
28
30
|
import path from "node:path";
|
|
29
|
-
import { buildEffective, DOMAIN_READ_FALLBACK, parseDomainLoud } from "./config-fns.js";
|
|
30
|
-
import { configDPath, readConfigDFile, refuseRetiredDomainFiles } from "./config-d-file.js";
|
|
31
|
-
import { stableHash } from "./hash.js";
|
|
31
|
+
import { RetiredDomainError, buildEffective, DOMAIN_READ_FALLBACK, parseDomainLoud, refuseRetiredDomain } from "./config-fns.js";
|
|
32
|
+
import { RETIRED_DOMAIN_NAMES, configDPath, configDVersionOf, corruptDocumentRaw, readConfigDFile, readConfigDFileReading, refuseRetiredDomainFiles } from "./config-d-file.js";
|
|
32
33
|
import { PORTABLE_DOMAINS } from "./portable-domains.js";
|
|
33
34
|
import { REMOTE_EXEC_DOCUMENT } from "./remote-exec.js";
|
|
34
|
-
import {
|
|
35
|
-
/** The retired domain names (`RETIRED_DOMAINS` keys) — read from `config.d/` for their tombstone only. */
|
|
36
|
-
const RETIRED_DOMAIN_NAMES = Object.keys(RETIRED_DOMAINS);
|
|
35
|
+
import { isDomainName, isRetiredDomainName } from "./types.js";
|
|
37
36
|
// 便携域表的定义住在纯叶 ./portable-domains.ts(14.6.0;零 node 依赖,主桶模块可 import);这里原名转出口,`./node` 子路径逐名不变。
|
|
38
37
|
export { NON_PORTABLE_DOMAIN_REASONS, PORTABLE_DOMAINS } from "./portable-domains.js";
|
|
39
38
|
/** `config.d/` 里**合法存在但不是域文档**的文件名(不进 `"unread-config-file"` 告警)。`remote-exec`
|
|
@@ -87,6 +86,11 @@ export class FileConfigStore {
|
|
|
87
86
|
const onWarning = this.opts.onWarning;
|
|
88
87
|
if (!onWarning)
|
|
89
88
|
return;
|
|
89
|
+
for (const w of await this.#unreadFiles())
|
|
90
|
+
onWarning(w);
|
|
91
|
+
}
|
|
92
|
+
/** {@link #warnUnreadFiles} 的扫描本体:没人读的 `*.json` 逐个一条告警(单读口 `read()` 把它们交成数据,所以它总扫)。 */
|
|
93
|
+
async #unreadFiles() {
|
|
90
94
|
let names;
|
|
91
95
|
try {
|
|
92
96
|
names = await readdir(path.join(this.root, "config.d"));
|
|
@@ -94,8 +98,9 @@ export class FileConfigStore {
|
|
|
94
98
|
catch {
|
|
95
99
|
// 目录读不了(不存在 / 只有 x 没有 r 的目录权限)⇒ 本次扫不了,**不抛**:这条是尽力而为的审计线,
|
|
96
100
|
// 绝不能把一次本来能成功的 getEffective 拖成失败(域文件本身仍按名逐个打开,该失败的自然会失败)。
|
|
97
|
-
return;
|
|
101
|
+
return [];
|
|
98
102
|
}
|
|
103
|
+
const out = [];
|
|
99
104
|
for (const name of names) {
|
|
100
105
|
if (name.startsWith(".") || !name.endsWith(".json") || NON_DOMAIN_CONFIG_FILES.has(name))
|
|
101
106
|
continue;
|
|
@@ -104,10 +109,11 @@ export class FileConfigStore {
|
|
|
104
109
|
continue; // 真被读的域
|
|
105
110
|
if (isRetiredDomainName(base))
|
|
106
111
|
continue; // retired 域:由墓碑判(带事实 ⇒ getEffective 抛),不是「没人读的文件」
|
|
107
|
-
|
|
112
|
+
out.push(isDomainName(base)
|
|
108
113
|
? { kind: "unread-config-file", file: name, domain: base, why: "non-portable-domain" }
|
|
109
114
|
: { kind: "unread-config-file", file: name, why: "not-a-domain" });
|
|
110
115
|
}
|
|
116
|
+
return out;
|
|
111
117
|
}
|
|
112
118
|
/** Raw (unparsed) values for every PORTABLE domain and every retired domain (the latter for the tombstone), keyed by
|
|
113
119
|
* name (absent → undefined). Both feed the version hash: a retired file appearing / changing flips `getEffective`
|
|
@@ -136,22 +142,24 @@ export class FileConfigStore {
|
|
|
136
142
|
}
|
|
137
143
|
/** Read+parse one domain (validated, defaults filled), or `undefined` if the domain is ABSENT — matching
|
|
138
144
|
* the {@link ConfigReader} contract (reader.ts: absent domain → undefined) and the server stores'
|
|
139
|
-
* `has(domain) ? parse : undefined`.
|
|
140
|
-
* with defaults
|
|
141
|
-
*
|
|
145
|
+
* `has(domain) ? parse : undefined`. Only a MISSING file (ENOENT) is absence → undefined. A present `{}` IS a set
|
|
146
|
+
* domain → parsed with defaults. A present file that is empty or whitespace-only (a half-write) throws as a corrupt file,
|
|
147
|
+
* as do bad JSON, a non-object, an unreadable file and one nested too deep (the same reading as getEffective / readBundle).
|
|
148
|
+
* (getEffective still fills defaults for absent domains; getDomain is the per-domain "was this ever set?" probe.) */
|
|
142
149
|
async getDomain(domain) {
|
|
143
150
|
await refuseRetiredDomainFiles(this.root); // every read entry asks the tombstone first (exportBundle reads through here)
|
|
144
151
|
const raw = await this.#readDomainRaw(domain);
|
|
145
152
|
if (raw === undefined)
|
|
146
|
-
return undefined; // missing
|
|
153
|
+
return undefined; // missing file (ENOENT) → domain absent (not schema defaults); a corrupt file threw above
|
|
147
154
|
// 0.19.0(对抗复审 复审 round2 F3):与 buildEffective **同一条** parse-and-warn 判据。此前本方法直接
|
|
148
155
|
// parseDomain,于是 `exportBundle`(它就是逐域走 getDomain 读的)会把一份携带未知键的域**静默剥**
|
|
149
156
|
// 成一份"干净"的 bundle —— 再 import 回去就是一次持久的配置丢失,全程零告警。
|
|
150
157
|
return parseDomainLoud(domain, raw, this.opts.onWarning);
|
|
151
158
|
}
|
|
152
|
-
/** Content hash of a raws snapshot → a stable u53-ish version number (≤ Number.MAX_SAFE_INTEGER).
|
|
159
|
+
/** Content hash of a raws snapshot → a stable u53-ish version number (≤ Number.MAX_SAFE_INTEGER). The one reading is `configDVersionOf`
|
|
160
|
+
* (`./config-d-file`) — `read()` asks the same function, so a clean tree has the same version from either. */
|
|
153
161
|
#versionOf(raws) {
|
|
154
|
-
return
|
|
162
|
+
return configDVersionOf(raws);
|
|
155
163
|
}
|
|
156
164
|
async getEffective(opts) {
|
|
157
165
|
// Every read entry asks the tombstone first (the same check getDomain runs); what it read (absent / `{}`) joins the version hash.
|
|
@@ -170,26 +178,19 @@ export class FileConfigStore {
|
|
|
170
178
|
const hashRaws = { ...retired };
|
|
171
179
|
const domainErrors = [];
|
|
172
180
|
await Promise.all(PORTABLE_DOMAINS.map(async (d) => {
|
|
173
|
-
|
|
174
|
-
|
|
181
|
+
// 与严读同一只文件读法(读数):被拒的读数交 `thrown`(gate 域原样抛)或 `error` 句(其余域单列进 domainErrors)—— 坏文件的指纹就是这一次读到的字节,不是事后的第二次读。
|
|
182
|
+
const reading = await readConfigDFileReading(this.root, d);
|
|
183
|
+
if (reading.status !== "refused") {
|
|
184
|
+
const v = reading.status === "present" ? reading.value : undefined;
|
|
175
185
|
raws[d] = v;
|
|
176
186
|
hashRaws[d] = v;
|
|
187
|
+
return;
|
|
177
188
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// 哨兵进 hash:用文件文本 hash 区分不同坏内容;读不回文本(竞态删除等)退回错误文案。
|
|
184
|
-
let textHash;
|
|
185
|
-
try {
|
|
186
|
-
textHash = stableHash((await readFile(this.domainPath(d), "utf8")).trim());
|
|
187
|
-
}
|
|
188
|
-
catch {
|
|
189
|
-
textHash = stableHash(e instanceof Error ? e.message : String(e));
|
|
190
|
-
}
|
|
191
|
-
hashRaws[d] = { __corruptDomainFile: textHash };
|
|
192
|
-
}
|
|
189
|
+
if (DOMAIN_READ_FALLBACK[d] === "throw")
|
|
190
|
+
throw reading.thrown; // gate 域:READ 容错也不放宽 fail-loud
|
|
191
|
+
domainErrors.push({ domain: d, error: reading.error });
|
|
192
|
+
raws[d] = undefined; // buildEffective 按 absent → schema default 落(fail-closed)
|
|
193
|
+
hashRaws[d] = corruptDocumentRaw(reading); // 哨兵进 hash:不同坏内容不同数(见 corruptDocumentRaw)
|
|
193
194
|
}));
|
|
194
195
|
const updatedAt = await this.#maxMtimeIso();
|
|
195
196
|
const effective = buildEffective(this.#versionOf(hashRaws), (d) => raws[d], updatedAt, this.opts.onWarning);
|
|
@@ -200,4 +201,60 @@ export class FileConfigStore {
|
|
|
200
201
|
async getVersion() {
|
|
201
202
|
return this.#versionOf(await this.#readAllRaw());
|
|
202
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* **单读口**(16.0.0):一次读整棵 `config.d`(全部便携域 + retired 域的墓碑文档,每份只读一次),交一个结局({@link FileConfigRead})——
|
|
206
|
+
* · 每份文档在文件层都读得进 ⇒ `effective`:与严读 `getEffective()` 逐位同;读侧告警交成数据(没人读的文件 + 装配告警,不经 `onWarning`);
|
|
207
|
+
* · 有文档在文件层被拒(空 / 坏 JSON / 不是对象 / 读不出 / 过深;带事实的 retired 域文档是墓碑拒,带迁移编号)⇒ `refused`:整棵目录的拒单与这一次读到的内容版本。
|
|
208
|
+
* 严读与 `readBundle` 读的是同一只文件读法(`./config-d-file` 的读数)—— 同一种坏形同一个词、同一句话;区别只在渲染:严读遇到第一份坏文档就抛,本方法把整个目录读完、逐份交出。
|
|
209
|
+
* 文件层之外的拒(读得出、过不了门控域的 schema)照严读抛 —— 那是判形,不在拒单里。拒单、版本、effective、告警都出自这一次读到的字节:没有「先抛、再重探」的第二次读。
|
|
210
|
+
*/
|
|
211
|
+
async read() {
|
|
212
|
+
const documents = [...RETIRED_DOMAIN_NAMES, ...PORTABLE_DOMAINS];
|
|
213
|
+
const [readings, unread] = await Promise.all([Promise.all(documents.map((d) => readConfigDFileReading(this.root, d))), this.#unreadFiles()]);
|
|
214
|
+
const raws = {};
|
|
215
|
+
const refusals = [];
|
|
216
|
+
documents.forEach((document, i) => {
|
|
217
|
+
const reading = readings[i];
|
|
218
|
+
switch (reading.status) {
|
|
219
|
+
case "absent":
|
|
220
|
+
raws[document] = undefined;
|
|
221
|
+
return;
|
|
222
|
+
case "refused":
|
|
223
|
+
raws[document] = corruptDocumentRaw(reading);
|
|
224
|
+
refusals.push({ document, reason: reading.reason, error: reading.error });
|
|
225
|
+
return;
|
|
226
|
+
case "present":
|
|
227
|
+
raws[document] = reading.value;
|
|
228
|
+
if (isRetiredDomainName(document)) {
|
|
229
|
+
const tombstone = tombstoneOf(document, reading.value);
|
|
230
|
+
if (tombstone !== undefined)
|
|
231
|
+
refusals.push(tombstone);
|
|
232
|
+
}
|
|
233
|
+
return;
|
|
234
|
+
default: {
|
|
235
|
+
const unhandled = reading;
|
|
236
|
+
throw new Error(`FileConfigStore.read: unhandled reading ${String(unhandled)}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
const version = this.#versionOf(raws);
|
|
241
|
+
if (refusals.length > 0)
|
|
242
|
+
return { kind: "refused", refusals, version, warnings: unread };
|
|
243
|
+
const warnings = [...unread];
|
|
244
|
+
const updatedAt = await this.#maxMtimeIso();
|
|
245
|
+
const effective = buildEffective(version, (d) => raws[d], updatedAt, (w) => warnings.push(w));
|
|
246
|
+
return { kind: "effective", effective, warnings };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** 墓碑判一次(与严读同一只判官 `refuseRetiredDomain`、同一句):retired 域文档带事实 ⇒ 一条 `retired_domain` 拒;缺席 / `{}` ⇒ `undefined`。 */
|
|
250
|
+
function tombstoneOf(domain, raw) {
|
|
251
|
+
try {
|
|
252
|
+
refuseRetiredDomain(domain, raw);
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
catch (e) {
|
|
256
|
+
if (e instanceof RetiredDomainError)
|
|
257
|
+
return { document: e.domain, reason: "retired_domain", error: e.message, migration: e.migration };
|
|
258
|
+
throw e;
|
|
259
|
+
}
|
|
203
260
|
}
|
package/dist/fleet.d.ts
CHANGED
|
@@ -166,12 +166,13 @@ export type RestartSignal = z.infer<typeof RestartSignal>;
|
|
|
166
166
|
* `config.gateway_fallback_without_primary` — fallback gateways are declared without a primary;
|
|
167
167
|
* `config.catalog_replaces_env_models` ({@link CATALOG_REPLACES_ENV_MODELS_CODE}) — on the LOCAL config leg, a candidate that
|
|
168
168
|
* manages the model plane would replace a declared env model table (`MODEL_ID` …) while the config root's decision document
|
|
169
|
-
* (`config.env-models.json`, read by `readEnvModelsDecision`) does not say `replaced` — the env models keep serving
|
|
170
|
-
* `config.summarize_model_missing` ({@link SUMMARIZE_MODEL_MISSING_CODE}) — the summarize role, which every task resolves,
|
|
171
|
-
* would land on no servable entry (every task would be refused after adoption).
|
|
169
|
+
* (`config.env-models.json`, read by `readEnvModelsDecision`) does not say `replaced` — the env models keep serving.
|
|
172
170
|
* Source (engine): the first two in `src/model-entry-refusal.ts`, the next two in `src/model-route-endpoint.ts:40,42`
|
|
173
171
|
* (invariant `model-route-endpoint`, judged by the model-plane stage in `src/config-center/apply-effective.ts:664-665`); the
|
|
174
|
-
* last
|
|
172
|
+
* last one is named HERE first (the code is a contract word: this package names it and exports the constant for the engine to read; the engine does not mint it today).
|
|
173
|
+
* 16.0.0 retired `config.summarize_model_missing` (and its constant) from this set: a role seat naming an entry the catalog does not serve
|
|
174
|
+
* reads as unset (it falls back down the role chain and the engine says so once) — no reading refuses a model plane for it, so it was never
|
|
175
|
+
* an engine group refusal. A reader still holding it gets it dropped by {@link readModelRefusals} like any code outside the set.
|
|
175
176
|
*/
|
|
176
177
|
export declare const MODEL_ENTRY_REFUSAL_CODES: readonly ["config.model_no_brain", "config.model_entry_invalid"];
|
|
177
178
|
export declare const ModelEntryRefusalCode: z.ZodEnum<{
|
|
@@ -181,12 +182,9 @@ export declare const ModelEntryRefusalCode: z.ZodEnum<{
|
|
|
181
182
|
export type ModelEntryRefusalCode = z.infer<typeof ModelEntryRefusalCode>;
|
|
182
183
|
/** The env-model-table confirmation gate's group-refusal code (see {@link MODEL_PLANE_REFUSAL_CODES}). */
|
|
183
184
|
export declare const CATALOG_REPLACES_ENV_MODELS_CODE: "config.catalog_replaces_env_models";
|
|
184
|
-
|
|
185
|
-
export declare const SUMMARIZE_MODEL_MISSING_CODE: "config.summarize_model_missing";
|
|
186
|
-
export declare const MODEL_PLANE_REFUSAL_CODES: readonly ["config.default_model_missing", "config.model_refused_name_minted", "config.model_route_endpoint_missing", "config.gateway_fallback_without_primary", "config.catalog_replaces_env_models", "config.summarize_model_missing"];
|
|
185
|
+
export declare const MODEL_PLANE_REFUSAL_CODES: readonly ["config.default_model_missing", "config.model_refused_name_minted", "config.model_route_endpoint_missing", "config.gateway_fallback_without_primary", "config.catalog_replaces_env_models"];
|
|
187
186
|
export declare const ModelPlaneRefusalCode: z.ZodEnum<{
|
|
188
187
|
"config.catalog_replaces_env_models": "config.catalog_replaces_env_models";
|
|
189
|
-
"config.summarize_model_missing": "config.summarize_model_missing";
|
|
190
188
|
"config.default_model_missing": "config.default_model_missing";
|
|
191
189
|
"config.model_refused_name_minted": "config.model_refused_name_minted";
|
|
192
190
|
"config.model_route_endpoint_missing": "config.model_route_endpoint_missing";
|
package/dist/fleet.js
CHANGED
|
@@ -234,26 +234,24 @@ function readSignalBody(body, pick, schema) {
|
|
|
234
234
|
* `config.gateway_fallback_without_primary` — fallback gateways are declared without a primary;
|
|
235
235
|
* `config.catalog_replaces_env_models` ({@link CATALOG_REPLACES_ENV_MODELS_CODE}) — on the LOCAL config leg, a candidate that
|
|
236
236
|
* manages the model plane would replace a declared env model table (`MODEL_ID` …) while the config root's decision document
|
|
237
|
-
* (`config.env-models.json`, read by `readEnvModelsDecision`) does not say `replaced` — the env models keep serving
|
|
238
|
-
* `config.summarize_model_missing` ({@link SUMMARIZE_MODEL_MISSING_CODE}) — the summarize role, which every task resolves,
|
|
239
|
-
* would land on no servable entry (every task would be refused after adoption).
|
|
237
|
+
* (`config.env-models.json`, read by `readEnvModelsDecision`) does not say `replaced` — the env models keep serving.
|
|
240
238
|
* Source (engine): the first two in `src/model-entry-refusal.ts`, the next two in `src/model-route-endpoint.ts:40,42`
|
|
241
239
|
* (invariant `model-route-endpoint`, judged by the model-plane stage in `src/config-center/apply-effective.ts:664-665`); the
|
|
242
|
-
* last
|
|
240
|
+
* last one is named HERE first (the code is a contract word: this package names it and exports the constant for the engine to read; the engine does not mint it today).
|
|
241
|
+
* 16.0.0 retired `config.summarize_model_missing` (and its constant) from this set: a role seat naming an entry the catalog does not serve
|
|
242
|
+
* reads as unset (it falls back down the role chain and the engine says so once) — no reading refuses a model plane for it, so it was never
|
|
243
|
+
* an engine group refusal. A reader still holding it gets it dropped by {@link readModelRefusals} like any code outside the set.
|
|
243
244
|
*/
|
|
244
245
|
export const MODEL_ENTRY_REFUSAL_CODES = ["config.model_no_brain", "config.model_entry_invalid"];
|
|
245
246
|
export const ModelEntryRefusalCode = z.enum(MODEL_ENTRY_REFUSAL_CODES);
|
|
246
247
|
/** The env-model-table confirmation gate's group-refusal code (see {@link MODEL_PLANE_REFUSAL_CODES}). */
|
|
247
248
|
export const CATALOG_REPLACES_ENV_MODELS_CODE = "config.catalog_replaces_env_models";
|
|
248
|
-
/** The summarize invariant's group-refusal code (see {@link MODEL_PLANE_REFUSAL_CODES}); a writer's plan answers `fix_first` with it. */
|
|
249
|
-
export const SUMMARIZE_MODEL_MISSING_CODE = "config.summarize_model_missing";
|
|
250
249
|
export const MODEL_PLANE_REFUSAL_CODES = [
|
|
251
250
|
"config.default_model_missing",
|
|
252
251
|
"config.model_refused_name_minted",
|
|
253
252
|
"config.model_route_endpoint_missing",
|
|
254
253
|
"config.gateway_fallback_without_primary",
|
|
255
254
|
CATALOG_REPLACES_ENV_MODELS_CODE,
|
|
256
|
-
SUMMARIZE_MODEL_MISSING_CODE,
|
|
257
255
|
];
|
|
258
256
|
export const ModelPlaneRefusalCode = z.enum(MODEL_PLANE_REFUSAL_CODES);
|
|
259
257
|
/**
|
package/dist/hooks.d.ts
CHANGED
|
@@ -78,8 +78,8 @@ export declare const HookEventName: z.ZodEnum<{
|
|
|
78
78
|
}>;
|
|
79
79
|
export type HookEventName = z.infer<typeof HookEventName>;
|
|
80
80
|
export declare const HookOwner: z.ZodEnum<{
|
|
81
|
-
engine: "engine";
|
|
82
81
|
shell: "shell";
|
|
82
|
+
engine: "engine";
|
|
83
83
|
}>;
|
|
84
84
|
export type HookOwner = z.infer<typeof HookOwner>;
|
|
85
85
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export * from "./types.js";
|
|
6
6
|
export * from "./execution-lanes.js";
|
|
7
|
+
export * from "./config-document-refusal.js";
|
|
7
8
|
export * from "./url-shape.js";
|
|
9
|
+
export * from "./device-relay.js";
|
|
8
10
|
export * from "./url-credential.js";
|
|
9
11
|
export * from "./default-model.js";
|
|
10
12
|
export { catalogManagesModelPlane, enabledEntryCount } from "./catalog-manages.js";
|
|
@@ -47,4 +49,3 @@ export * from "./control-and-bidi.js";
|
|
|
47
49
|
export * from "./mcp-request-entry.js";
|
|
48
50
|
export { REMOTE_MCP_SERVER_NAME_PREFIX } from "./mcp-server-name.js";
|
|
49
51
|
export * from "./center-refs.js";
|
|
50
|
-
export { isBlankCoordinate } from "./execution-lane-index.js";
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
* web-admin, the worker service, and the TOC desktop/CLI.
|
|
4
4
|
*/
|
|
5
5
|
export * from "./types.js";
|
|
6
|
-
export * from "./execution-lanes.js"; // 7.0.0 M-R2: the ONE lane / store vocabulary (EXECUTION_LANE_WORDS / EXECUTION_LANES / STORE_BACKENDS / SESSION_BACKENDS / MEMORY_ENGINE_BACKENDS) —
|
|
7
|
-
export * from "./
|
|
6
|
+
export * from "./execution-lanes.js"; // 7.0.0 M-R2: the ONE lane / store vocabulary (EXECUTION_LANE_WORDS / EXECUTION_LANES / STORE_BACKENDS / SESSION_BACKENDS / MEMORY_ENGINE_BACKENDS) + THE lane-coordinate blank judge isBlankCoordinate (empty or whitespace-only = absent; the write gate and every consumer ask this one function; whether a key is set, and whether an optional key may be empty, stays the caller's call; the same function object as on the `./execution-lanes` subpath) — a zero-import leaf, pure/browser-safe
|
|
7
|
+
export * from "./config-document-refusal.js"; // 15.2.0: the typed refusal of one config.d document (CONFIG_DOCUMENT_REFUSAL_REASONS = empty / invalid_json / not_object / io / retired_domain; ConfigDocumentRefusal { document, reason, error } + the tombstone arm's migration) — the reading is `inspectBundle` in ./node; pure/browser-safe
|
|
8
|
+
export * from "./url-shape.js"; // 11.0.0: THE URL shape judge (httpUrlFlaws / httpUrlRule / isHierarchicalUrl; 16.0.0 + wsUrlFlaws), pure/browser-safe
|
|
9
|
+
export * from "./device-relay.js"; // 16.0.0: THE value grammar of the device lane's DEVICE_RELAY_URL (DEVICE_RELAY_NONE / deviceRelayFlaws / DEVICE_RELAY_RULE), pure/browser-safe
|
|
8
10
|
export * from "./url-credential.js"; // 14.5.0: THE "does this URL carry a credential" judge (findUrlCredential / findUrlUserinfo / URL_CREDENTIAL_REASONS / CREDENTIAL_PARAM_NAMES …), pure/browser-safe
|
|
9
11
|
export * from "./default-model.js"; // 11.0.0: THE catalog-default resolver (roles.default → active tier ladder → fallback), pure/browser-safe
|
|
10
12
|
export { catalogManagesModelPlane, enabledEntryCount } from "./catalog-manages.js"; // THE "does this models document manage the model plane" judge (raw half: at least one entry not explicitly disabled) + the log count it is derived from, pure/browser-safe
|
|
@@ -47,7 +49,6 @@ export * from "./control-and-bidi.js"; // the one-line echo strip set (C0 + DEL
|
|
|
47
49
|
export * from "./mcp-request-entry.js"; // 14.0.0: the request-plane MCP entry judges (isUsableWireName / isContentOriginWord / readMcpIdentityHeaders / readRequestMcpTransport + the value-shape describers) — one reading for the service legs and the shell pre-check, pure/browser-safe
|
|
48
50
|
export { REMOTE_MCP_SERVER_NAME_PREFIX } from "./mcp-server-name.js"; // the MCP server-name prefix reserved for the remote MCP servers a device executor offers (mount name = prefix + the executor's server name); the predicate and its sentence stay package-private — the request plane's MCP name judges (isUsableMcpServerName / describeBadMcpServerName) read them; the config plane's McpServerSpec.name accepts the prefix (refusing it would be a validation tightening — a major), pure/browser-safe
|
|
49
51
|
export * from "./center-refs.js"; // resolveCenterRefs(refs, lookup) — THE center-roster reference resolver: one verdict word per member (missing_name / not_a_string / read_threw, CENTER_REF_FAULTS), one whole verdict (resolved / unresolved / refs_unreadable, CENTER_REFS_VERDICTS); the refs record is read by the public readPlainStringRecord, the lookup is the caller's, it reads no process.env; pure/browser-safe
|
|
50
|
-
export { isBlankCoordinate } from "./execution-lane-index.js"; // THE lane-coordinate blank judge (empty or whitespace-only = absent; the write gate and every consumer ask this one function; whether a key is set, and whether an optional key may be empty, stays the caller's call); named: the lane tables' derived indexes stay package-private, pure/browser-safe
|
|
51
52
|
// NOTE: the Node-fs-backed helpers (FileConfigStore + the file editor) are NOT in this barrel — they pull
|
|
52
53
|
// `node:fs`/`node:path` and would break a browser/client bundle that only wants the contract (e.g.
|
|
53
54
|
// web-admin's client components import the zod types through here). Import them from the Node-only
|
|
@@ -7,7 +7,7 @@ import type { REMOTE_EXEC_DOCUMENT } from "./remote-exec.js";
|
|
|
7
7
|
import type { DomainName, RetiredDomainName } from "./types.js";
|
|
8
8
|
/** 本版登记的一次性**数据**迁移 id(闭集;每个 id 在 `ONE_TIME_MIGRATIONS` 登记表里恰一行)。收据只许这些 id —— 同表登记的 wire 删码位
|
|
9
9
|
* (`WIRE_RETIREMENT_IDS`,`./one-time-migrations`)不改任何存储形,铸不出收据,不在本集。 */
|
|
10
|
-
export declare const ONE_TIME_MIGRATION_IDS: readonly ["SS-M1", "SS-M2", "SS-M3", "SS-M4", "SS-M5", "SS-M6", "SS-M7", "SS-M8", "SS-M9", "SS-M10", "SS-M11"];
|
|
10
|
+
export declare const ONE_TIME_MIGRATION_IDS: readonly ["SS-M1", "SS-M2", "SS-M3", "SS-M4", "SS-M5", "SS-M6", "SS-M7", "SS-M8", "SS-M9", "SS-M10", "SS-M11", "SS-M12"];
|
|
11
11
|
export type OneTimeMigrationId = (typeof ONE_TIME_MIGRATION_IDS)[number];
|
|
12
12
|
/**
|
|
13
13
|
* 一条收据说迁移**对一个坐标做了什么**(闭集,每词一义):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** 本版登记的一次性**数据**迁移 id(闭集;每个 id 在 `ONE_TIME_MIGRATIONS` 登记表里恰一行)。收据只许这些 id —— 同表登记的 wire 删码位
|
|
2
2
|
* (`WIRE_RETIREMENT_IDS`,`./one-time-migrations`)不改任何存储形,铸不出收据,不在本集。 */
|
|
3
|
-
export const ONE_TIME_MIGRATION_IDS = ["SS-M1", "SS-M2", "SS-M3", "SS-M4", "SS-M5", "SS-M6", "SS-M7", "SS-M8", "SS-M9", "SS-M10", "SS-M11"];
|
|
3
|
+
export const ONE_TIME_MIGRATION_IDS = ["SS-M1", "SS-M2", "SS-M3", "SS-M4", "SS-M5", "SS-M6", "SS-M7", "SS-M8", "SS-M9", "SS-M10", "SS-M11", "SS-M12"];
|
|
4
4
|
/**
|
|
5
5
|
* 一条收据说迁移**对一个坐标做了什么**(闭集,每词一义):
|
|
6
6
|
* - `moved` — 值搬到新位(`to`),义不变;
|
|
@@ -41,7 +41,7 @@ export type StoredDocuments = Readonly<Partial<Record<DomainName | RetiredDomain
|
|
|
41
41
|
export interface StoredDocumentsMigration {
|
|
42
42
|
/** 迁移后的文档集:没改的文档是**同一引用**;被移除的(retired 域)不在;新建的(例:迁出的 `governance` / `limits`)在。 */
|
|
43
43
|
readonly docs: Readonly<Record<string, unknown>>;
|
|
44
|
-
/** 逐条收据(步序 SS-M1 → SS-M2 → SS-M5 → SS-M6 → SS-M8 → SS-M9 → SS-M10 → SS-M7 → SS-
|
|
44
|
+
/** 逐条收据(步序 SS-M1 → SS-M2 → SS-M5 → SS-M6 → SS-M8 → SS-M9 → SS-M10 → SS-M7 → workers 行步〔SS-M12 改写 → SS-M4 改写 → 一次终判〕:纯改写步在前,用新 schema 终判的 workers 行步最后;步内按坐标)。
|
|
45
45
|
* 只有 `refused` 的收据 = 什么都没改。 */
|
|
46
46
|
readonly receipts: readonly MigrationReceipt[];
|
|
47
47
|
}
|