@sema-agent/settings-schema 1.10.0 → 2.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 +137 -3
- package/README.md +29 -2
- package/dist/config-fns.d.ts +72 -4
- package/dist/config-fns.js +204 -6
- package/dist/cross-domain.d.ts +8 -4
- package/dist/cross-domain.js +6 -2
- package/dist/fleet.d.ts +1 -1
- package/dist/fleet.js +1 -1
- package/dist/hooks.d.ts +367 -19
- package/dist/hooks.js +76 -8
- package/dist/remote-exec.d.ts +4 -4
- package/dist/remote-exec.js +1 -1
- package/dist/resolve-roster.d.ts +1 -1
- package/dist/scheduler-store.d.ts +13 -3
- package/dist/scheduler-store.js +13 -3
- package/dist/skills-manifest.js +1 -1
- package/dist/types.d.ts +663 -642
- package/dist/types.js +95 -46
- package/package.json +2 -1
package/dist/types.js
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Detail level is deliberate (the user asked for "详略设计"): `models` is the MVP — fully specified —
|
|
8
8
|
* while `scenarios` / `runtime` carry a real-but-skeletal schema to be fleshed out in later phases
|
|
9
|
-
* (see
|
|
9
|
+
* (see CHANGELOG.md; `integrations`/`access` were deleted in 0.6.0, EXPERT-REDESIGN §9). Adding a
|
|
10
10
|
* field is: extend the zod schema here → the form + the effective-config API pick it up.
|
|
11
11
|
*
|
|
12
|
-
* ⚠️ SECURITY BOUNDARY (see
|
|
12
|
+
* ⚠️ SECURITY BOUNDARY (see the service-integration design note): the config center stores **non-secret**
|
|
13
13
|
* config only. A model's API key / a backend token is NEVER stored here as a value — we store the NAME
|
|
14
14
|
* of the env var that holds it (`apiKeyEnv`, `tokenEnv`), and the agent-service reads the real secret
|
|
15
15
|
* from its own environment. So a leak of this DB never leaks a credential. This is **enforced** by the
|
|
@@ -220,8 +220,7 @@ export function extraBodyUnsafe(v) {
|
|
|
220
220
|
* serialization and persist another (the pre-R10 superRefine+transform stringified TWICE).
|
|
221
221
|
*
|
|
222
222
|
* `field` only NAMES the field in the message — it never changes the judgment. What this does NOT do is validate
|
|
223
|
-
* SHAPE:
|
|
224
|
-
* all-or-nothing, so a shape rejection here would blank the whole catalog. */
|
|
223
|
+
* SHAPE: whose job that is, per key, is {@link PARSE_TRANSPARENT_KEYS}. */
|
|
225
224
|
function vetFreeFormJson(v, field) {
|
|
226
225
|
let rawUnsafe;
|
|
227
226
|
try {
|
|
@@ -294,6 +293,56 @@ export const SealedApiKey = z.object({
|
|
|
294
293
|
* 解密不依赖它,非 center 写面(本地 TOC 手写配置)缺省合法。 */
|
|
295
294
|
setAt: z.string().min(1).optional(),
|
|
296
295
|
});
|
|
296
|
+
/**
|
|
297
|
+
* **解析透明键登记表** —— 本包收下但**不校验其形**的键,一处列全,连同「谁校验」。
|
|
298
|
+
*
|
|
299
|
+
* 成案:1.7.0 / 1.7.1 连着两次,在一个展示用的键上设形判据,让一条坏值抹掉了**整域**(彼时整域
|
|
300
|
+
* all-or-nothing);此后的缓解是逐键改成 `z.unknown()` 并在各自的 JSDoc 里**各复述一遍**同一段理由 ——
|
|
301
|
+
* 五行同义散文 ×3,没有任何一处能回答「一共有几个这样的键、分别归谁校验」。那正是「修法给每个新键加一条
|
|
302
|
+
* 特判」的形。这张表把那段理由收成一处:键在这里登记,JSDoc 只留一行指过来。
|
|
303
|
+
*
|
|
304
|
+
* 1.11.0 起整域 all-or-nothing 已按类改成逐条容错(坏条目逐条丢、同域其余条目存活),所以「设形判据
|
|
305
|
+
* 会抹掉整域」这条**理由本身已经弱化** —— 但登记表要回答的问题没变:这些键的形归谁校验。新键要不要
|
|
306
|
+
* 解析透明,按「本包是不是那张形表的属主」判,不再按「怕连坐」判。
|
|
307
|
+
*
|
|
308
|
+
* 「解析透明」按**行为**定义(不按 schema 的形名):喂一组有代表性的值全收 = 本包对它的形没有任何主张。
|
|
309
|
+
* 所以 `ModelEntry.extraBody` **不在**本表里 —— 它有自己的形门(必须是纯 JSON 对象,要摊进请求体);
|
|
310
|
+
* 它开放的只是对象里的键名词表(各家 provider 的请求参数表),那是另一回事,写在它自己的 JSDoc 里。
|
|
311
|
+
*
|
|
312
|
+
* 门:`test/parse-transparent-keys.test.ts` 从 `DOMAIN_SCHEMAS` **派生**出所有解析透明的叶子,与本表
|
|
313
|
+
* 双向对拍 —— 多登记一行(键已经不透明了)红,少登记一行(新键静默溜进来)也红;派生遇到不认识的
|
|
314
|
+
* schema 形 fail-loud,不「没认出来就当没有」。
|
|
315
|
+
*/
|
|
316
|
+
export const PARSE_TRANSPARENT_KEYS = [
|
|
317
|
+
{
|
|
318
|
+
domain: "models",
|
|
319
|
+
path: "models[].compat",
|
|
320
|
+
since: "1.10.0",
|
|
321
|
+
validatedBy: "engine-ingest",
|
|
322
|
+
why: "镜像引擎的 per-model wire-compat 声明(thinkingFormat 等五键);那张词表随引擎走,本包复述一份必漂。",
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
domain: "mcp",
|
|
326
|
+
path: "servers[].source",
|
|
327
|
+
since: "1.7.2",
|
|
328
|
+
validatedBy: "consumer",
|
|
329
|
+
why: "声明面的分组标签,开放集(部署方自己的词同样合法);标签规则(非空、≤80 字)只在消费方的投影处一处,它丢坏标签的键、保留服务器本身。",
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
domain: "mcp",
|
|
333
|
+
path: "servers[].toolFaces",
|
|
334
|
+
since: "1.9.0",
|
|
335
|
+
validatedBy: "engine-ingest",
|
|
336
|
+
why: "按远端工具名 key 的 face 覆盖层,形归引擎摄入侧(不合 schema 的工具不挂并通告一次);本包复述那张表必漂。",
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
domain: "entitlement",
|
|
340
|
+
path: "subjects[].overrides[].value",
|
|
341
|
+
since: "0.6.x",
|
|
342
|
+
validatedBy: "consumer",
|
|
343
|
+
why: "它的形由同一条 override 的 `key` 决定(一个 key 一种形),执法点在读那个 key 的消费方;在这里写死形等于把所有可覆盖键的形表搬进本包。",
|
|
344
|
+
},
|
|
345
|
+
];
|
|
297
346
|
export const ModelEntry = z.object({
|
|
298
347
|
/** Catalog key + `@name` mention handle (stable, url/word-safe), e.g. "model-a". */
|
|
299
348
|
name: z.string().min(1).regex(/^[a-z0-9][a-z0-9._-]*$/i, "letters/digits/._- , no spaces"),
|
|
@@ -343,7 +392,9 @@ export const ModelEntry = z.object({
|
|
|
343
392
|
// before our check). The getter-free descriptor walk (extraBodyUnsafe) validates the RAW value without
|
|
344
393
|
// invoking any getter; a Proxy that fakes its descriptors is caught by re-scanning the JSON clone; and the
|
|
345
394
|
// .transform persists that CLONE (concrete plain JSON) so a non-idempotent toJSON can't differ at persist.
|
|
346
|
-
// Round 2-5 hardening.
|
|
395
|
+
// Round 2-5 hardening. NOT in {@link PARSE_TRANSPARENT_KEYS}: this key DOES have a shape gate here (it must
|
|
396
|
+
// be a plain JSON object — it is spread into a request body). What is open is the KEY VOCABULARY inside that
|
|
397
|
+
// object: those are each provider's request params, and this package is not their owner.
|
|
347
398
|
extraBody: z
|
|
348
399
|
.unknown()
|
|
349
400
|
.optional()
|
|
@@ -371,17 +422,13 @@ export const ModelEntry = z.object({
|
|
|
371
422
|
* gateway that thinks by DEFAULT can only be turned off with `chat_template_kwargs.enable_thinking=false`,
|
|
372
423
|
* which `extraBody` cannot carry (the engine reserves those request keys) — and without this key a catalog
|
|
373
424
|
* entry that declares it is stripped at parse, so the declaration never reaches the engine at all.
|
|
425
|
+
* ABSENT = key not minted = today's behaviour, zero migration.
|
|
374
426
|
*
|
|
375
|
-
* **Parse-transparent**
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
* The ONE rejection that remains is the free-form SAFETY judgment shared with `extraBody`
|
|
382
|
-
* ({@link vetFreeFormJson}): a secret-shaped key/value, an accessor, a cycle, non-JSON, or too deep to hash
|
|
383
|
-
* later. That is not shape validation — it is the boundary every free-form value must clear to enter the
|
|
384
|
-
* persisted config and `stableHash` (R18). */
|
|
427
|
+
* **Parse-transparent** — who validates the shape, and why not here: {@link PARSE_TRANSPARENT_KEYS}
|
|
428
|
+
* (`models.models[].compat`). The ONE rejection that remains is the free-form SAFETY judgment shared with
|
|
429
|
+
* `extraBody` ({@link vetFreeFormJson}): a secret-shaped key/value, an accessor, a cycle, non-JSON, or too
|
|
430
|
+
* deep to hash later. That is not shape validation — it is the boundary every free-form value must clear to
|
|
431
|
+
* enter the persisted config and `stableHash` (R18). */
|
|
385
432
|
compat: z
|
|
386
433
|
.unknown()
|
|
387
434
|
.optional()
|
|
@@ -510,11 +557,11 @@ export const ModelsConfig = z
|
|
|
510
557
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: `activeTierGroup "${cfg.activeTierGroup}" is not a tier group name`, path: ["activeTierGroup"] });
|
|
511
558
|
}
|
|
512
559
|
});
|
|
513
|
-
// ── Domain: rosters (per-worker model roster —
|
|
560
|
+
// ── Domain: rosters (per-worker model roster — the multi-roster design note) ───────────
|
|
514
561
|
// A named VIEW over the global `models` catalog: which models a worker exposes + its role map + @-allowlist.
|
|
515
562
|
// A worker references one by name (WorkerSpec.roster); GET /effective?worker=<name> resolves it. Models stay
|
|
516
563
|
// single-sourced in the `models` domain — a roster only references them by name (cross-domain ref checked at
|
|
517
|
-
// resolution/PUT, see
|
|
564
|
+
// resolution/PUT, see the multi-roster design note §6). This is what lets one sema-registry serve heterogeneous
|
|
518
565
|
// instances (OA vs review 各持异构模型) instead of a single global roster.
|
|
519
566
|
export const RosterEntry = z.object({
|
|
520
567
|
name: z.string().min(1).regex(/^[a-z0-9][a-z0-9._-]*$/i, "letters/digits/._- , no spaces"),
|
|
@@ -545,7 +592,7 @@ export const RostersConfig = z
|
|
|
545
592
|
seen.add(r.name);
|
|
546
593
|
// intra-roster consistency: a role target / an @-allowlist entry pinned to a model NAME must be one
|
|
547
594
|
// this roster exposes (when it's a subset). Cross-domain (the name exists in the catalog) is checked at
|
|
548
|
-
// PUT time — see
|
|
595
|
+
// PUT time — see the multi-roster design note. (Both layers matter: this catches subset-internal inconsistency even
|
|
549
596
|
// when models is the full catalog is left to the PUT check.)
|
|
550
597
|
if (r.models.length) {
|
|
551
598
|
const allowed = new Set(r.models);
|
|
@@ -587,6 +634,9 @@ export const ScenarioEntry = z.object({
|
|
|
587
634
|
// registry field would become an ambiguous precedence channel」):配置域 prompt 单入口=center
|
|
588
635
|
// prompts binding(scenario 维度);引擎 API 层 TaskSpec.systemPrompt 保留(不同层,勿混)。
|
|
589
636
|
// 现网无用户直删;z.object 非 strict ⇒ 存量数据带 prompt 被 strip,parse 不炸。
|
|
637
|
+
// 落日(1.11.0):本条是**纯墓碑**(零代码,靠 strip 生效),没有要删的兼容码;它留在这里的唯一作用
|
|
638
|
+
// 是让下一个读到这段 schema 的人知道 `prompt` 这个名字曾经在这里、别再铸回来。0.19.0 起存量文档带
|
|
639
|
+
// 它会被 `unknown-keys-dropped` 点名,所以「还有人在写它」是可观察的,不靠记忆。
|
|
590
640
|
enabled: z.boolean().default(true),
|
|
591
641
|
notes: z.string().optional(),
|
|
592
642
|
});
|
|
@@ -1026,6 +1076,8 @@ export const EntitlementOverride = z
|
|
|
1026
1076
|
.object({
|
|
1027
1077
|
principal: z.string().min(1),
|
|
1028
1078
|
key: z.string().min(1),
|
|
1079
|
+
/** The override's value — its SHAPE follows its `key`, so it is parse-transparent here and validated by
|
|
1080
|
+
* whoever enforces that key: {@link PARSE_TRANSPARENT_KEYS} (`entitlement.subjects[].overrides[].value`). */
|
|
1029
1081
|
value: z.unknown(),
|
|
1030
1082
|
effectiveFrom: z.string().optional(),
|
|
1031
1083
|
effectiveUntil: z.string().optional(),
|
|
@@ -1282,10 +1334,11 @@ export const ExecutionPolicy = z.object({
|
|
|
1282
1334
|
/** projectId 形状:lowercase 规范 UUID。**宽读严写**(core 口径):读面/claim 收 generic
|
|
1283
1335
|
* UUID(外部/历史铸造的 v4 也认——marker 是身份不是格式声明);铸造侧(core formatProjectMarker /
|
|
1284
1336
|
* center mint 端点)统一产 **uuidv7**。36 字符,天然满足 design/142 §1.2 段编码 64 上限。
|
|
1285
|
-
* SINGLE-SOURCE
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1337
|
+
* SINGLE-SOURCE 纪律:本常量是引擎那条正则的**自持镜像**(本仓不带引擎运行时依赖轴),对拍走 dev-only
|
|
1338
|
+
* conformance(never a runtime import,EffectiveKey/coreTypes 先例)。
|
|
1339
|
+
* 1.11.0:drift-lock 已建(`test/upstream-drift.test.ts` ③)—— pattern 必须与引擎逐字相同,唯一成文的差是
|
|
1340
|
+
* flags:本常量刻意**不带** `i`,因为它是登记簿 Record 的**键**,大小写不同的同一个 UUID 会变成两条登记行
|
|
1341
|
+
* (同一 project 双注册);引擎侧是识别语义(读 marker / 找回身份),放宽合理。 */
|
|
1289
1342
|
export const PROJECT_ID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
1290
1343
|
export const ProjectRegistration = z.object({
|
|
1291
1344
|
/** 人读名(展示/管理面用;不是身份,改名自由——身份=Record 键 projectId)。 */
|
|
@@ -1424,7 +1477,7 @@ export const CollabConfig = z.object({ templates: z.array(CollabTemplate).defaul
|
|
|
1424
1477
|
seen.add(t.id);
|
|
1425
1478
|
});
|
|
1426
1479
|
});
|
|
1427
|
-
// ── Domain: workers (声明式编排 — service design/22,
|
|
1480
|
+
// ── Domain: workers (声明式编排 — service design/22, the orchestrator design note) ──────
|
|
1428
1481
|
// 每个 worker = 一个 worker 服务实例的声明(一份 env profile)。sema-registry 存 DESIRED(逻辑参数
|
|
1429
1482
|
// + secret 的 env-NAME 引用,**绝不存 secret 值**);一个 per-host reconciler 拉取后在宿主机本地解析
|
|
1430
1483
|
// secret → 渲染 docker compose → up/down 收敛。worker spec ↔ service env 的精确映射见 worker-env.ts。
|
|
@@ -1653,12 +1706,12 @@ export const WorkerSpec = z.object({
|
|
|
1653
1706
|
auto: z.boolean().default(false),
|
|
1654
1707
|
requires: z.array(z.string().min(1)).default([]),
|
|
1655
1708
|
/** SOFT anti-affinity group: auto workers sharing this key are spread across hosts when possible
|
|
1656
|
-
* (preferred, never blocks placement — design
|
|
1709
|
+
* (preferred, never blocks placement — the scheduling design note). 不填 = 无 spread 约束。 */
|
|
1657
1710
|
spread: z.string().min(1).optional(),
|
|
1658
1711
|
})
|
|
1659
1712
|
.optional(),
|
|
1660
1713
|
/**
|
|
1661
|
-
* per-worker roster 引用 (
|
|
1714
|
+
* per-worker roster 引用 (the multi-roster design note)。指向 `rosters` 域里一个命名 roster;该 worker 的 service 拉
|
|
1662
1715
|
* `GET /api/config/effective?worker=<name>` 时,sema-registry 用这个 roster 解析它专属的 models/roles/@白名单。
|
|
1663
1716
|
* 不填 → 该 worker 拿全局 models(向后兼容)。**不进 `workerSpecHash`**(改 roster 只让 service 重拉、不重建容器)。
|
|
1664
1717
|
*/
|
|
@@ -1801,13 +1854,13 @@ export const HostStatus = z.object({
|
|
|
1801
1854
|
/** 探测时刻(ISO)——机器视图 hover 注明数据口径与此时间(§2-5:是分配额口径的底数,非实时负载)。 */
|
|
1802
1855
|
ts: z.string().min(1),
|
|
1803
1856
|
});
|
|
1804
|
-
// ── Domain: skills (中心化 skill 分发 —
|
|
1857
|
+
// ── Domain: skills (中心化 skill 分发 — the mcp/skills design note, Roadmap B1) ─────────
|
|
1805
1858
|
// A skill is a prompt-level capability: frontmatter (name/description/scenarios) + markdown `content`
|
|
1806
1859
|
// the service feeds into the agent's model context when the skill is invoked (core progressive disclosure
|
|
1807
1860
|
// — NOT the base system prompt). Still centrally-delivered agent instructions. The center stores the FULL skill
|
|
1808
1861
|
// (incl. content, admin-edited); /effective ships a MANIFEST (content → contentHash) and the service
|
|
1809
1862
|
// lazily pulls the body by hash (slice 2). Targeting is by `scenarios[]`, filtered service-side exactly
|
|
1810
|
-
// like the in-image `skillsForScenario` (
|
|
1863
|
+
// like the in-image `skillsForScenario` (the mcp/skills design note §3.1, §6 Q2). Applied at service boot/reconcile,
|
|
1811
1864
|
// NOT hot (restart-to-apply, same as models/roles). ⚠️ content is centrally-delivered agent instructions
|
|
1812
1865
|
// (injected into the model on invoke) → writing this domain is gated to `publisher` + the publish gate
|
|
1813
1866
|
// (§3.3, DOMAIN_WRITE_ROLE in store.ts).
|
|
@@ -1818,7 +1871,7 @@ export const SkillSpec = z.object({
|
|
|
1818
1871
|
description: z.string().default(""),
|
|
1819
1872
|
/** Scenarios this skill applies to; empty = all scenarios (service-side filter, same as skillsForScenario). */
|
|
1820
1873
|
scenarios: z.array(z.string().min(1)).default([]),
|
|
1821
|
-
/** Per-roster targeting (v2,
|
|
1874
|
+
/** Per-roster targeting (v2, the mcp/skills design note §6 Q2): roster NAMEs this skill is for. Empty = all rosters.
|
|
1822
1875
|
* Filtered at GET /effective?worker=<name> by the worker's roster; the unscoped global pull ships all. */
|
|
1823
1876
|
rosters: z.array(z.string().min(1)).default([]),
|
|
1824
1877
|
/** The markdown body injected into the model context on invoke (progressive disclosure). Stored in full here; shipped as a hash in /effective. */
|
|
@@ -1845,7 +1898,7 @@ export const SkillsConfig = z
|
|
|
1845
1898
|
export const SkillsManifestSchema = z.object({
|
|
1846
1899
|
skills: z.array(SkillSpec.omit({ content: true }).extend({ contentHash: z.string().min(1) })).default([]),
|
|
1847
1900
|
});
|
|
1848
|
-
// ── Domain: mcp (MCP server 注册表 —
|
|
1901
|
+
// ── Domain: mcp (MCP server 注册表 — the mcp/skills design note, Roadmap B1) ────────────
|
|
1849
1902
|
// sema-registry = an MCP-server REGISTRY: a scenario mounts a subset by `scenarios[]`. Maps onto core's
|
|
1850
1903
|
// `McpServerSpec = { name, transport: {kind:"stdio",command,args?,env?} | {kind:"http",url,headers?}, allowTools?, contentOrigin?, source? }`.
|
|
1851
1904
|
// SECRET BOUNDARY (§3.1, design/15): a transport's env/header VALUES may be secret → the center stores only
|
|
@@ -1942,23 +1995,19 @@ export const McpServerSpec = z.object({
|
|
|
1942
1995
|
* consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
|
|
1943
1996
|
* `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
|
|
1944
1997
|
* no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
|
|
1945
|
-
* no label (`.optional()`, no default — a label has no default tier).
|
|
1946
|
-
*
|
|
1947
|
-
*
|
|
1948
|
-
*
|
|
1949
|
-
*
|
|
1950
|
-
*
|
|
1951
|
-
*
|
|
1952
|
-
* no gate / policy / trust
|
|
1953
|
-
* effect (the trust axis is `contentOrigin` above, which stays a closed table). Before this key existed
|
|
1954
|
-
* both legs stripped it (default-strip object); this is the declaration half of the consumer-side fix
|
|
1955
|
-
* (ticket B-036 / S-143), the projection half lives in the consumer. */
|
|
1998
|
+
* no label (`.optional()`, no default — a label has no default tier). Display-only: no gate / policy /
|
|
1999
|
+
* trust effect (the trust axis is `contentOrigin` above, which stays a closed table). Before this key
|
|
2000
|
+
* existed both legs stripped it (default-strip object); this is the declaration half of the
|
|
2001
|
+
* consumer-side fix, the projection half lives in the consumer.
|
|
2002
|
+
*
|
|
2003
|
+
* **Parse-transparent** — who validates the shape, and why not here: {@link PARSE_TRANSPARENT_KEYS}
|
|
2004
|
+
* (`mcp.servers[].source`). */
|
|
1956
2005
|
source: z.unknown().optional(),
|
|
1957
|
-
/** 1.9.0 ——
|
|
2006
|
+
/** 1.9.0 —— 引擎的 `toolFaces` 覆盖层:按远端工具名 key 的 face 声明
|
|
1958
2007
|
* (`{ family?, pathTarget?: {param, aliases?, access, skillScopeEligible?}, renderHints?, ruleFace? }`)。
|
|
1959
|
-
*
|
|
1960
|
-
*
|
|
1961
|
-
*
|
|
2008
|
+
* 缺席 = 不铸键。
|
|
2009
|
+
*
|
|
2010
|
+
* **解析透明** —— 形归谁校验、为什么不放这里:{@link PARSE_TRANSPARENT_KEYS}(`mcp.servers[].toolFaces`)。 */
|
|
1962
2011
|
toolFaces: z.unknown().optional(),
|
|
1963
2012
|
notes: z.string().optional(),
|
|
1964
2013
|
});
|
|
@@ -2196,7 +2245,7 @@ export const DOMAIN_SCHEMAS = {
|
|
|
2196
2245
|
};
|
|
2197
2246
|
// ── Effective-config PROVENANCE (the unified shape TOC `sema config --effective` and TOB `/effective?principal=`
|
|
2198
2247
|
// step-5 trace both emit, so "why is this value what it is" renders identically across both seats). Settled
|
|
2199
|
-
// via the center control-plane design gate③ (
|
|
2248
|
+
// via the center control-plane design gate③ (see the center control-plane design note §R2-T/§10). A pure
|
|
2200
2249
|
// CONTRACT type — no runtime dep on the engine; the axis VALUES (enforcement/lockBehavior) mirror @sema-agent/
|
|
2201
2250
|
// core's safety vocabulary, validated by a dev-only conformance test (never a runtime import).
|
|
2202
2251
|
/** One provenance source in a key's resolution trail. Two orthogonal axes: the TOC file LAYER, or the TOB
|
|
@@ -2226,7 +2275,7 @@ export const EffectiveKey = z.object({
|
|
|
2226
2275
|
* rollback-able). Lets user changes share the one audit stream the Audit page already renders. */
|
|
2227
2276
|
export const RBAC_AUDIT = "rbac";
|
|
2228
2277
|
/** Audit category for secret write-through (value injected into the orchestrator secret source) — name + action
|
|
2229
|
-
* ONLY, never the value (config_change.value=null), same discipline as RBAC_AUDIT.
|
|
2278
|
+
* ONLY, never the value (config_change.value=null), same discipline as RBAC_AUDIT. See the self-service-fleet design note §3. */
|
|
2230
2279
|
export const SECRETS_AUDIT = "secrets";
|
|
2231
2280
|
// Single source: derived from DOMAIN_SCHEMAS (insertion order = menu order) so the two can't drift —
|
|
2232
2281
|
// adding a domain to DOMAIN_SCHEMAS is enough. Object.keys preserves declaration order.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/settings-schema",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Sema settings schema — pure config contract (zod domains + effective-config + roster resolution + ref-integrity + remoteExec) shared by sema-registry, sema-server, and the TOC desktop/CLI. One source of truth. (Renamed at 1.0.0 from @sema-agent/registry-core — name and docs only, no behavior change; note the range moves 0.19.0 -> 1.0.0, so a dependency must become ^1.0.0. The old names @sema-agent/registry-core <=0.19.0 and @sema-ai/registry-core remain published, frozen, for migration.)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -118,6 +118,7 @@
|
|
|
118
118
|
"test": "vitest run",
|
|
119
119
|
"test:watch": "vitest",
|
|
120
120
|
"e2e": "node examples/toc-e2e.mjs",
|
|
121
|
+
"drift:cc": "node scripts/extract-cc-hook-events.mjs",
|
|
121
122
|
"prepare": "npm run build",
|
|
122
123
|
"prepublishOnly": "npm run build && npm run test",
|
|
123
124
|
"publish:npm": "npm publish --access public --@sema-agent:registry=https://registry.npmjs.org/ --\"//registry.npmjs.org/:_authToken=${NPM_TOKEN}\""
|