@sema-agent/settings-schema 13.0.0 → 14.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.
Files changed (141) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/README.md +20 -2
  3. package/conformance/VERSION +1 -1
  4. package/conformance/baseline.json +1 -3
  5. package/conformance/cases/c01-entry-salvage-then-typo/expected.json +1 -3
  6. package/conformance/cases/c02-hosts-clamp-stacked/expected.json +1 -3
  7. package/conformance/cases/c03-literal-dotted-top-key/expected.json +1 -3
  8. package/conformance/cases/c04-all-bad-collection-not-salvaged/expected.json +1 -3
  9. package/conformance/cases/c07-hooks-is-not-a-config-domain/expected.json +1 -3
  10. package/conformance/cases/c08-limits-unknown-carried-64/expected.json +1 -3
  11. package/conformance/cases/c09-limits-unknown-carried-65/expected.json +1 -3
  12. package/conformance/cases/c10-record-key-secret-redacted-twice/expected.json +1 -3
  13. package/conformance/cases/c11-unicode-unknown-keys/expected.json +1 -3
  14. package/conformance/cases/c12-prototype-name-top-keys/expected.json +1 -3
  15. package/conformance/cases/c13-models-field-null/expected.json +1 -3
  16. package/conformance/cases/c14-models-field-empty-array/expected.json +1 -3
  17. package/conformance/cases/c15-models-field-number/expected.json +1 -3
  18. package/conformance/cases/c16-deep-nesting-205/expected.json +1 -3
  19. package/conformance/cases/c17-empty-domain-file/expected.json +1 -3
  20. package/conformance/cases/c18-wire-envelope-not-an-object/expected.json +1 -3
  21. package/conformance/cases/c19-wire-envelope-no-version/expected.json +1 -3
  22. package/conformance/cases/c21-governance-empty-object-wins/expected.json +1 -3
  23. package/conformance/cases/c23-mixed-validity-models/expected.json +1 -3
  24. package/conformance/cases/c24-valid-entries-with-unknown-keys/expected.json +1 -3
  25. package/conformance/cases/c25-published-roundtrip-zero-warnings/expected.json +1 -3
  26. package/conformance/cases/c26-hosts-array-1024/expected.json +1 -3
  27. package/conformance/cases/c27-hosts-array-1025/expected.json +1 -3
  28. package/conformance/cases/c28-large-document-over-1mb/expected.json +1 -3
  29. package/conformance/cases/c29-salvage-then-domain-refine-fails/expected.json +1 -3
  30. package/conformance/cases/c30-version-triple-a-first/expected.json +1 -3
  31. package/conformance/cases/c31-version-triple-b-changed/expected.json +1 -3
  32. package/conformance/cases/c32-version-triple-a-restored/expected.json +1 -3
  33. package/conformance/cases/c33-limits-nested-carried-key/expected.json +1 -3
  34. package/conformance/cases/c34-skills-content-vs-manifest/expected.json +1 -3
  35. package/conformance/cases/c35-portable-domain-file-is-null/expected.json +1 -3
  36. package/conformance/cases/c36-skills-entry-without-content/expected.json +1 -3
  37. package/conformance/cases/c37-skills-field-null/expected.json +1 -3
  38. package/conformance/cases/c38-remote-exec-is-a-non-domain-file/expected.json +1 -3
  39. package/conformance/cases/c39-hidden-file-in-config-d/expected.json +1 -3
  40. package/conformance/cases/c40-s712-identity-only-what-reads-out/expected.json +1 -3
  41. package/conformance/cases/c41-s792-encoded-pem-identity/expected.json +1 -3
  42. package/conformance/cases/c42-s792-unknown-key-secret-redacted/expected.json +1 -3
  43. package/conformance/cases/c43-s792-form-and-deep-encoded-pem/expected.json +1 -3
  44. package/conformance/cases/c44-s792-utf8-escape-glued-token/expected.json +1 -3
  45. package/conformance/cases/c45-s792-identity-bounds-and-decode-depth/expected.json +1 -3
  46. package/conformance/cases/c46-s811-host-name-url-userinfo-withheld/expected.json +1 -3
  47. package/conformance/cases/c47-s811-roles-key-url-userinfo-withheld/expected.json +1 -3
  48. package/conformance/cases/c48-s935-model-headers-transported/expected.json +1 -3
  49. package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/expected.json +1 -3
  50. package/conformance/cases/c50-s784-lane-host-legal/expected.json +1 -3
  51. package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +1 -3
  52. package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +1 -3
  53. package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +1 -3
  54. package/conformance/cases/c54-s784-lane-adb-legal/expected.json +1 -3
  55. package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +1 -3
  56. package/conformance/cases/c56-s784-lane-device-legal/expected.json +1 -3
  57. package/conformance/cases/c57-s784-g1-enabled-no-lane/expected.json +1 -3
  58. package/conformance/cases/c58-s784-g2-multitenant-host/expected.json +1 -3
  59. package/conformance/cases/c59-s784-g3-k8s-missing-image/expected.json +1 -3
  60. package/conformance/cases/c60-s784-g3-e2b-missing-key/expected.json +1 -3
  61. package/conformance/cases/c61-s784-g3-other-lane-key/expected.json +1 -3
  62. package/conformance/cases/c62-s784-g7a-session-tidb/expected.json +1 -3
  63. package/conformance/cases/c63-s784-host-two-replicas/expected.json +1 -3
  64. package/conformance/cases/c64-s784-multitenant-local-store/expected.json +1 -3
  65. package/conformance/cases/c65-s784-pg-without-db/expected.json +1 -3
  66. package/conformance/cases/c66-s784-memory-backend-mismatch/expected.json +1 -3
  67. package/conformance/cases/c67-s784-retired-field-loud/expected.json +1 -3
  68. package/conformance/cases/c68-s784-device-local-store/expected.json +1 -3
  69. package/conformance/cases/c69-deep-encoded-token-past-every-reading/expected.json +1 -3
  70. package/conformance/cases/c70-rewritten-token-in-front-of-encoded-pem-header/expected.json +1 -3
  71. package/conformance/cases/c71-one-scanner-write-reads-display-forms/expected.json +1 -3
  72. package/conformance/cases/c72-dangling-reference-write-seat-refuses/expected.json +1 -3
  73. package/conformance/cases/c73-projects-extended-registration-reads/expected.json +1 -3
  74. package/conformance/cases/c74-projects-over-bound-refused/expected.json +1 -3
  75. package/conformance/cases/c75-projects-patch-remote-uniqueness/expected.json +1 -3
  76. package/conformance/cases/c76-projects-entry-salvage-nested/expected.json +1 -3
  77. package/conformance/cases/c77-prompts-center-artifact-carried/expected.json +252 -0
  78. package/conformance/cases/c77-prompts-center-artifact-carried/input.json +93 -0
  79. package/conformance/cases/c77-prompts-center-artifact-carried/meta.json +5 -0
  80. package/conformance/cases/c78-prompts-empty-bindings-refused/expected.json +82 -0
  81. package/conformance/cases/c78-prompts-empty-bindings-refused/input.json +11 -0
  82. package/conformance/cases/c78-prompts-empty-bindings-refused/meta.json +5 -0
  83. package/conformance/cases/c79-prompts-bad-worker-artifact-not-salvaged/expected.json +82 -0
  84. package/conformance/cases/c79-prompts-bad-worker-artifact-not-salvaged/input.json +129 -0
  85. package/conformance/cases/c79-prompts-bad-worker-artifact-not-salvaged/meta.json +5 -0
  86. package/conformance/cases/c80-prompts-wire-v2-verbatim/expected.json +195 -0
  87. package/conformance/cases/c80-prompts-wire-v2-verbatim/input.json +65 -0
  88. package/conformance/cases/c80-prompts-wire-v2-verbatim/meta.json +5 -0
  89. package/conformance/cases/c81-prompts-declaration-bindings-refused/expected.json +82 -0
  90. package/conformance/cases/c81-prompts-declaration-bindings-refused/input.json +23 -0
  91. package/conformance/cases/c81-prompts-declaration-bindings-refused/meta.json +5 -0
  92. package/conformance/cases/c82-prompts-v1-catalog-refused/expected.json +82 -0
  93. package/conformance/cases/c82-prompts-v1-catalog-refused/input.json +35 -0
  94. package/conformance/cases/c82-prompts-v1-catalog-refused/meta.json +5 -0
  95. package/conformance/cases/c83-prompts-bad-overlay-not-salvaged/expected.json +82 -0
  96. package/conformance/cases/c83-prompts-bad-overlay-not-salvaged/input.json +56 -0
  97. package/conformance/cases/c83-prompts-bad-overlay-not-salvaged/meta.json +5 -0
  98. package/conformance/cases/cc01-mcp-toolfaces-non-object/expected.json +1 -3
  99. package/conformance/cases/cc02-mcp-source-key-is-transported/expected.json +1 -3
  100. package/conformance/cases/cc03-model-compat-unknown-subkey/expected.json +1 -3
  101. package/conformance/cases/cli01-model-name-nfc-vs-nfd/expected.json +1 -3
  102. package/conformance/cases/cli02-control-and-zero-width-chars/expected.json +1 -3
  103. package/conformance/cases/cli03-credential-pasted-into-unknown-key/expected.json +1 -3
  104. package/conformance/cases/cli04-env-value-with-newline/expected.json +1 -3
  105. package/conformance/cases/cli05-long-and-prefix-colliding-names/expected.json +1 -3
  106. package/conformance/cases/t01-absent-domain-key-not-null/expected.json +1 -3
  107. package/conformance/cases/t03-prototype-name-key-not-swallowed/expected.json +1 -3
  108. package/conformance/cases/t04-secret-literal-never-in-warning-value/expected.json +1 -3
  109. package/conformance/cases/z01-every-domain-empty-object/expected.json +2 -6
  110. package/conformance/cases/z02-every-domain-unknown-key/expected.json +2 -6
  111. package/dist/config-fns.d.ts +7 -3
  112. package/dist/config-fns.js +19 -16
  113. package/dist/conformance/derive.js +2 -2
  114. package/dist/hooks-config.d.ts +9 -1
  115. package/dist/hooks-config.js +23 -15
  116. package/dist/index.d.ts +1 -0
  117. package/dist/index.js +1 -0
  118. package/dist/mcp-request-entry.d.ts +93 -0
  119. package/dist/mcp-request-entry.js +157 -0
  120. package/dist/migration-receipt.d.ts +1 -1
  121. package/dist/migration-receipt.js +1 -1
  122. package/dist/node.d.ts +0 -1
  123. package/dist/node.js +0 -1
  124. package/dist/one-time-migrations.d.ts +1 -1
  125. package/dist/one-time-migrations.js +39 -0
  126. package/dist/safety-merge-spec.d.ts +6 -6
  127. package/dist/types.d.ts +438 -355
  128. package/dist/types.js +161 -136
  129. package/dist/url-shape.d.ts +8 -0
  130. package/dist/url-shape.js +10 -0
  131. package/docs/API-SURFACE.md +1409 -0
  132. package/docs/CC-DIVERGENCE.md +42 -0
  133. package/docs/CONFORMANCE.md +344 -0
  134. package/docs/CONSUMER-INTEGRATION.md +283 -0
  135. package/docs/openapi-auth.yaml +357 -0
  136. package/docs/openapi-scopes.yaml +281 -0
  137. package/llms-full.txt +659 -0
  138. package/llms.txt +179 -0
  139. package/package.json +5 -2
  140. package/dist/prompts-digest.d.ts +0 -16
  141. package/dist/prompts-digest.js +0 -49
package/llms.txt ADDED
@@ -0,0 +1,179 @@
1
+ <!--
2
+ llms.txt — 消费方(使用者)视角索引 · @sema-agent/settings-schema
3
+ 重写日期: 2026-10-17 | 包版本: 14.0.0
4
+ 生成方式: 无生成脚本——按当前树的 src/*.ts 导出面 + package.json + README/CHANGELOG 手写事实版;
5
+ 每条断言附证据坐标(文件:符号),刻意不用行号(行号随每版腐烂,符号名由 typecheck/test 钉住)。
6
+ 刷新触发: package.json 版号变更(test/docs-hygiene.test.ts D 组钉「包版本:」与 package.json 相等、
7
+ 域数/hook 事件数/subpath 数与运行时表相等)。自包含全文见 llms-full.txt。
8
+ -->
9
+
10
+ # @sema-agent/settings-schema
11
+
12
+ > 一个**纯配置契约 + resolver + 本地 loader** 的 npm 包(公网 npmjs,ESM only,Node >=20.3.0,唯一运行时
13
+ > 依赖 zod ^4.4.0)。它是 sema 栈配置域的**单一真值**:16 个配置域的 zod schema、`EffectiveConfig` 确定性合并、
14
+ > per-worker roster 解析、跨域引用完整性、`remoteExec` 执行层契约、本地 `config.d/*.json` 读写,外加 hooks /
15
+ > fleet / scheduler-store / safety-merge-spec / auth·scopes wire 五族纯契约。被 web-admin 产品(舰队管理台)、
16
+ > worker 服务、TOC 桌面/CLI 共同消费。**纯被消费**——无服务、永不携带 secret 值;唯一的 bin 是 7.0.0 的一次性迁移
17
+ > `npx @sema-agent/settings-schema migrate-workers <file>`。
18
+ > (package.json: description/exports/engines;README「What's in it」)
19
+ >
20
+ > 改名声明:`1.0.0` 起包名 `@sema-agent/settings-schema`;≤`0.19.0` 为 `@sema-agent/registry-core`(冻结)。
21
+ > 纯改名零语义变更;消费方迁移 = 依赖名 + 版号段 `^1.0.0` + import 前缀,21 个 subpath 后缀不动。(README 顶部)
22
+
23
+ ## 核心能力(它能为我做什么)
24
+
25
+ - **16 个配置域**的 zod schema 与类型(`DOMAIN_SCHEMAS` / `DOMAINS` / `isDomainName`):models · rosters · skills ·
26
+ mcp · plugins · scenarios · systems · collab · workers · hosts · governance · entitlement · execution ·
27
+ projects · prompts · limits。`runtime` 域 11.0.0 起 retired(墓碑 `RETIRED_DOMAINS`:读写遇带事实的 runtime 文档响亮拒,
28
+ 存量由一次性迁移 SS-M1 搬进 governance / limits —— `./one-time-migrations`)。(src/types.ts: `DOMAIN_SCHEMAS`)
29
+ - **域内坏条目逐条丢**(2.0.0):一条写坏的目录条目只丢它自己,同域其余条目照常生效,并逐条发
30
+ `entry-dropped` 点名(坐标形见下条;S-712 起可带 `identity?: { name?, id?, enabled? }` = 被丢条目原文里
31
+ 读得出的身份,类型不对 / `isDisclosableIdentity` 说不可披露 ⇒ 不带该键;6.3.0 起身份须是白名单闭形
32
+ `DISCLOSABLE_IDENTITY_RE` = `^[A-Za-z0-9._:/@+-]{1,256}$` 里的标识符 ∧ `redactSecrets` 原样放行;10.1.0 起每条 `entry-dropped` 还带
33
+ `reasonCode` = 为什么丢的机读闭集词 `DROPPED_ENTRY_REASON_CODES`:`entry-schema-invalid` / `entry-key-invalid` / `entry-unreadable`,
34
+ `DroppedEntry.reasonCode` 同源)。**读策略两张闭集表各答一个问题**(12.3.0):`DOMAIN_ENTRY_SALVAGE`(`salvage` / `none`)答「读时能否逐条丢」,
35
+ `DOMAIN_READ_FALLBACK`(`default` / `throw`,名 / 值 / 义不变)只答「整域读不进之后默认化还是抛」;闸域(rosters/governance/entitlement/
36
+ execution/workers/limits)两张都说不,`projects` 逐条抢救、整域仍 throw。**域读两面两函数**(12.3.0):文档面(`parseDomain` /
37
+ `parseDomainLoud`:写入席、导出、`getDomain`)永不抢救;视图面(`parseDomainSalvaged` / `buildEffective`)按表抢救 —— 两函数共用同一只内部体
38
+ (严 parse + 未知键告警),好文档上逐字同值同告警。抢救按 schema 递归到幸存条目体内的集合(坐标以父路径为前缀:
39
+ `["projects", <id>, "contextItems", 1]`;零幸存者律每层成立)。(src/config-fns.ts: `salvageEntries` / `parseDomainSalvaged` / `DOMAIN_ENTRY_SALVAGE`)
40
+ - **告警坐标是结构化段**(3.0.0 BREAKING):`ConfigPath = readonly (string | number)[]` —— 字符串段 = 对象键
41
+ (逐字,含 `.` 也逐字),数字段 = 数组下标。点号串是有损编码(字面叫 `models.1.k` 的顶层键与 `models[1].k`
42
+ 同串),段形把「这一段是下标还是键名」这个位带回来。出门(日志 / UI)由单铸的 `formatConfigPath` stringify
43
+ (逐字出门会与另一种段同形的一律带引号:空串、含 `.` / `"` / 控制字符、以及文本是规范十进制的字符串键
44
+ —— `models."1".k` 与下标 `models.1.k` 分得清);**没有 parse 反函数**。
45
+ (src/config-fns.ts: `ConfigPath` / `formatConfigPath`)
46
+ - **告警点名的是原文档的下标**(2.1.0):读路径上有两个压缩点(hosts 的 grandfather 夹紧、逐条容错的抢救),
47
+ 数组被剔过条目后诊断看见的是压缩后的下标(原第 2 条报成第 1 条)。律只有一条:**每个压缩点自带
48
+ 位移表,哪一层压缩就把从它下方上来的告警回写一次**;两层同时压缩时内层先、外层后,坐标一路回到运维手里
49
+ 那份文档。3.0.0 起这条律的判据也只有一条(数字段 ∧ 它前面那段前缀在位移表里;12.3.0 起逐段做、每一层被压缩的数组各回写一次,
50
+ 位移表的键 = 被压缩数组的原文档全路径出门串,顶层数组就是字段名),段数门与规范十进制门已删。
51
+ 没有路径真的变 ⇒ 原告警对象引用不变。
52
+ (src/config-fns.ts: `rebaseWarningPaths` / `EntrySalvageResult.keptIndex` / `GrandfatherHostsReadResult.keptIndex`)
53
+ - **解析透明键登记表** `PARSE_TRANSPARENT_KEYS`(2.0.0):本包收下但**不校验其形**的键一处列全,每行写清
54
+ 谁校验(引擎摄入侧 / 消费方)。「解析透明」按**行为**定义(喂一组代表性值全收),所以 `extraBody` 不在表里
55
+ ——它有自己的形门(必须是纯 JSON 对象),开放的只是对象里的键名词表。今日 8 员:
56
+ `models.models[].compat`(1.10.0,镜像引擎 `OpenAICompletionsCompat` 五键 `thinkingFormat`/
57
+ `reasoningEffortLevels`/`maxTokensField`/`requiresReasoningContentOnAssistantMessages`/
58
+ `supportsReasoningEffort`;真需求 = vLLM/Qwen 类缺省开思考的网关要 `chat_template_kwargs.enable_thinking=false`,
59
+ 而 `extraBody` 穿不过引擎保留键表)、`models.models[].headers`(6.4.0,部署 ↔ 供应商的 per-model 附加请求头,
60
+ 例 `{"anthropic-beta":"context-1m-2025-08-07"}`;头名闭集白名单 × 读它的线路 × 值形的判据唯一属主是 server,
61
+ 坏声明 ⇒ 该条目整条不可用;本包不复述那张表)、`mcp.servers[].source`(1.7.0,声明方自述的分组标签,开集,只做显示
62
+ 分组不进信任轴)、`mcp.servers[].toolFaces`(1.9.0,按远端工具名 key 的 face 覆盖层,形归引擎摄入侧)、
63
+ `mcp.servers[].toolAxes` / `authForm` / `entryKind`(12.2.0,连接器条目的三只声明键,本包只承载;`toolAxes` 的形判官 = 引擎 `readMcpToolAxes` 一只,另两键的语义归读它的消费方)、
64
+ `entitlement.subjects[].overrides[].value`。`compat`/`headers`/`extraBody` 仍走同一只自由形安全判据(secret 形/
65
+ 访问器/循环/非 JSON/过深 ⇒ 拒 —— 那是安全边界,不是形校验)。(src/types.ts: `PARSE_TRANSPARENT_KEYS`)
66
+ - **`mcp.servers[].transport.assertionHeader`**(12.2.0 新增,http 形可选):承载连接器断言的 HTTP 头名,头名过 `principalHeader` /
67
+ `headerRefs` 键同一只判官;与 `principalHeader` **互斥**(同设 ⇒ 解析期拒,拒句点名条目名与两键,判一处在条目层);stdio 形上与
68
+ `principalHeader` 同判(键被剥并报 `unknown-keys-dropped`)。本包只判形,断言怎么铸 / 验归消费方。(src/types.ts: `McpTransport` / `McpServerSpec`)
69
+ - **`mcp.servers[].contentOrigin`**(1.4.0 新增):MCP 工具产出的信任出处声明,闭词表
70
+ `MCP_CONTENT_ORIGINS = ["local","execution","external"]`(表外值 parse 拒,不做大小写折叠);缺席 = 引擎
71
+ 预声明行为。与 `source` 分轴:信任走它,显示分组走 `source`。(src/types.ts: `MCP_CONTENT_ORIGINS`)
72
+ - 把零散域**合并成一个 `EffectiveConfig`**(`buildEffective`,确定性:`updatedAt` 必传;`onWarning` 收
73
+ 降级/剥键/承运/未读文件五类告警),或在**消费端边界容错读 wire 载荷**(`readEffectiveWire`)。
74
+ (src/config-fns.ts: `buildEffective` / `readEffectiveWire` / `EffectiveReadWarning`)
75
+ - 把全局 config + worker 名**解析成该 worker 的 wire 载荷**(`resolveEffectiveForWorker`:models 按 roster
76
+ 收窄、skills 转 manifest、rosters/entitlement 剥离)。(src/resolve-roster.ts)
77
+ - 从本地 `config.d/*.json` + `.env` **一把加载**(`loadLocalConfig(root)`,worker 服务与 CLI 共用零漂移);
78
+ 单域坏文件可**容错**(`FileConfigStore.getEffective({tolerant:true})`)。(src/local-load.ts;src/file-store.ts)
79
+ - **secret 边界**:密钥字段一律 env-NAME(`ENV_NAME` 正则强制,拒 secret 形状字面量),浏览器端封箱的
80
+ sealed-box 形(`SealedApiKey`);`collectEnvRefs` 列出全部引用。自由文本写口(`extraBody` / `compat` / `headers` / URL / mcp 参数 / 插件源 / ssh 登录 /
81
+ worker env / 车道坐标 / 覆盖值)经同一只 `containsSecretToken` 拒 secret 形状;10.0.0 起私钥 PEM 头在串中**任意位置**都拒(此前只认串首;读原文 + 前三层百分号解码),
82
+ 头的位置与展示侧 `redactSecrets` 同判,读法宽度仍窄于展示侧(四层及更深的编码、`+` 代空格的头写侧仍放行)。(src/types.ts: `ENV_NAME` / `containsSecretToken` / `PRIVATE_KEY_PEM_HEADER` /
83
+ `SealedApiKey`;src/secret-refs.ts)
84
+ - `remoteExec` 执行层契约:6 个 provider(host / local-docker / e2b / k8s / ssh / adb),判别字段 `provider`;
85
+ 每个 provider 词 ⊆ 车道词表(7.0.0 删 `remote-docker`:引擎零读点)。(src/remote-exec.ts: `RemoteExecSpec`)
86
+ - **执行车道 + 存储的词表正本**(7.0.0,纯数据):`EXECUTION_LANE_WORDS`(host / e2b / k8s / ssh / adb / local-docker / device)、
87
+ `EXECUTION_LANES`(每车道 `tenantSeparation`〔supported 行另带依据 `tenantSeparationBasis`:isolation / principal-binding,11.0.0 判别联合〕+ 它读的 env 名四栏)、退役车道值墓碑 `RETIRED_LANE_WORDS` + 拒句 `retiredLaneWordRefusal(word)`(11.0.0)、`STORE_BACKENDS` / `SESSION_BACKENDS` / `MEMORY_ENGINE_BACKENDS`。
88
+ WorkerSpec 的 `runtime.execution` / `runtime.store` 两块按这张表判(写闸 = `WorkerSpec.safeParse`,拒因在 zod issue 里);
89
+ 6.x 存量 workers 文档在 `parseDomain` 之前跑一次 `migrateWorkersDomain`(或 bin `npx @sema-agent/settings-schema migrate-workers`;7.0.1 起 stdout = 结论行 `outcome=… written=…` + JSON,没写时 `wouldChange` 取代 `changed`)。
90
+ (src/execution-lanes.ts;src/types.ts: `WorkerSpec`;src/migrate-workers.ts)
91
+ - **hooks 契约**:33 个 hook 事件的全集 + owner 表 + 逐事件输入/输出形 + 配置面:hook 条目五种 type(`HOOK_ENTRY_TYPES`,含 `mcp_tool`)与**一只**
92
+ 坏形分类器 `classifyHooksConfig(settingsDoc)`(非守卫事件坏块逐个剔、守卫事件 PreToolUse / PermissionRequest 任何坏处或守卫迹象 ⇒ 整份拒;码 + 坐标 + 坏字段名 `field`(坏块是匹配器 / 条目 ⇒ 它上面出问题的键,块不是对象才缺席)、零句子、零 zod 自含;
93
+ 闭包里 JS 内建之外只有一个自由名 `HOOK_EVENTS` —— 整函数抄走的生成器(client-core)须把本包运行期导出 `HOOK_EVENTS`(上游常量)注入抄本作用域,不许贴字面事件表),
94
+ `HooksConfig` / `HookEntry` 等 zod 面是它的投影;事件与 type 两张闭集与上游的漂移由常驻门看住(上游有而本包没有的词 ⇒ 门红并点名)。http 钩子 header 里 `$VAR` / `${VAR}` 的展开也只有一只读法(名单内展开、名单外与凭据名置空并回报)。(src/hooks.ts: `HOOK_EVENTS` / `interpolateHookEnvVars`)
95
+ - **跨会话两键**(1.6.0 新增,`settings.json` 面;6.0.0 词表随 core 7.30.0 改):`crossSessionInbound`(wake/next-turn/hold/refuse + `default`=未设;`accept` 已退役,文件层响亮拒)
96
+ 与 `dialogExpiry`(60s/5m/10m/never,缺省 5m);另出两只层读取器,坏值 `ok:false` 不静默折缺省。
97
+ (src/cross-session.ts: `CrossSessionSettings` / `readCrossSessionInbound` / `readDialogExpiry`)
98
+ - **安全合并表** `SAFETY_MERGE_SPEC` + 信任阶梯 `trustRank` / `isAtLeast` + 成员级准入 `memberAdmission`。
99
+ (src/safety-merge-spec.ts)
100
+ - **设置源表 + 层准入**:`SETTINGS_SOURCES`(合并序)/ `SETTINGS_SOURCE_CONTRACT`(信任档 + 是否仓库可控;本地层与项目层同 `project` 档)/
101
+ `WORKSPACE_TRUST_STATES` / `layerAdmission(source, workspace, category, member?, value?)`(地板先判;仓库可控层未受信只收 tighten)/
102
+ `settingsSourceContract(source)`(源表唯一查口:本包要层档的函数都经它,不收调用方给的档;层只带源名)。(src/settings-sources.ts)
103
+ - **URL 名单一条模式的判法**(13.0.0):一条律两只出口 —— `urlAllowPatternMatches`(命中面 ⊆ CC `g9`,补上游四洞:写明缺省端口照判、`*` 协议只通配
104
+ http/https/ws/wss 且 `ws+unix:` 套接字段逐字、解析不出的模式不放、解码出的字面 `*` 不当通配)/ `urlDenyPatternMatches`(⊇ `g9` ∪ 整串 glob)。
105
+ 偏离登 `docs/CC-DIVERGENCE.md`。(src/url-pattern.ts)
106
+ - **http hook 两张名单**(13.0.0):类目 `SAFETY_MERGE_SPEC.httpHookAllowlists`(地板 global);`readHttpHookAllowlistLayer(source, settings)`(坏形读成 `[]`)·
107
+ `httpHookUrlVerdict(url, layers, workspace)` → `HttpHookUrlBlock{list, rule, sources}` 或 `undefined`(每张准入名单都须放行 = 跨层取交)·
108
+ `httpHookEnvVarsAllowed(hookVars, layers, workspace)`(取交);准入 ⇔ `layerAdmission(源, 工作区读数, "httpHookAllowlists") === "admitted"`。
109
+ (src/http-hook-allowlists.ts)
110
+ - **MCP 名单判决**(13.0.0):`mcpServerPolicyVerdict(server, layers)` → `McpPolicyBlock{name, list, rule, target, written, sources}` 或 `undefined`;
111
+ 判按展开后目标、回显只按展开前写法(stdio 只给可执行名 + 参数个数);托管层 = 源表档 `managed` 的源(层只带源名)。(src/mcp-server-policy.ts)
112
+ - **请求面 MCP 条目判官**(14.0.0,`src/mcp-request-entry.ts`):`isUsableWireName` / `describeBadWireName`(引擎线上名长界 `TOOL_WIRE_NAME_MAX_CHARS` 的镜像)·
113
+ `isContentOriginWord` / `describeBadContentOrigin` · `readMcpIdentityHeaders` · `readRequestMcpTransport`(硬坏形 `ok:false` 点名键路径;软坏形读器丢键并记进 `lost`)
114
+ + 值种类描述件 —— 服务端请求腿与壳的发送前预检同读一份(判据与原因句逐字同)。`toolFaces` 声明在本包解析透明,形归引擎摄入侧判,本包不镜像工具面词表。
115
+ - **prompts 域单轴**(14.0.0):只装中心 artifact(存储 `PromptsConfig = { artifact?, workers? }` / 下发 `EffectivePromptsWire = { schemaVersion: 2, artifact }` /
116
+ 唯一选择读法 `promptArtifactFor`);本包镜像 artifact v3 的结构与上界,语义交引擎 verify;13.x 两轴是墓碑,存量经一次性迁移 SS-M10。
117
+ - **界面语言设置片段**(13.0.0):`UI_LANGUAGE_SETTING`(`semaUiLanguage`,`en` / `zh`,类 `ui`,用户设置)+ `readUiLanguage`(词表外 `ok:false`,不猜)。
118
+ (src/ui-language.ts)
119
+ - **fleet 契约**(drain / 实例发现 / 派发策略 / 配额租约 / 用量上报;S-741 重启信号 `RestartSignal` 定义一次,
120
+ 11.0.0 起它是引擎状态,两出口只在 `engineSignal` 里读(`readEngineSignal(body)?.restart`;平铺 `restart` 是方言、不读,平铺读口已删),在场 ⇔ 需要重启;
121
+ S-768 模型拒因同法定义一次:wire 形 `ModelRefusalsWire` = `{ entries: 名 → 码, plane?: 组拒码 }`(码是开放串),
122
+ `readModelRefusals(body)` 一只读口读两出口并按闭集 `MODEL_ENTRY_REFUSAL_CODES`(2)/ `MODEL_PLANE_REFUSAL_CODES`(4)收窄成
123
+ `ModelRefusalsSignal`,集外码 = 没说;心跳 `InstanceAnnouncement.modelRefusals?` 上形坏 / 集外码都不拖垮心跳;缺席读 `version`,
124
+ 老引擎缺席 = 不可知;8.1.0 additive:`RestartSignal.withheld?`、引擎自铸信号的闭形 `EngineSignal` + `readEngineSignal(health)`
125
+ (`undefined` = 没有这只信号,不是就绪)、服务租约 API 型 `ServingLeaseRequest` / `ServingLeaseResponse`(`granted` / `denied` / `unknown` 三词闭集,
126
+ `unknown` 不是 `denied` 的一种;`generation` = 非负整数规范十进制串,`isCanonicalGeneration` / `compareGeneration`;web-admin 能力位 `WebAdminCapabilities { servingLease?: true }`,缺席 = 不续租不围栏)、排空口型 `DrainRequest` / `DrainReceipt`、env 名常量 `FLEET_GENERATION_ENV`(进保留 env 名表;实例身份由引擎每进程自铸,无 env 名)、`clampServingLeaseTtlMs`;
127
+ 8.2.0 additive:租约四态闭集 `LEASE_STATES` / `LeaseState`(none | granted | expired | denied)、`EngineSignal.leaseState?`、心跳 `InstanceAnnouncement` 不再剥
128
+ `generation` / `leaseState` / `leaseUntil`(形坏的那一键落成缺席,心跳照收)、端点常量 `FLEET_PATHS`(instances / usage / quotaLeases / servingLease / hostPlanner,路径模板)与
129
+ 活性路由组 `FLEET_LIVE_PATHS`(心跳 / 续租 / HostPlanner 读口)+ 随包 JSON 资产 `./fleet-paths.json`、能力位唯一载体的键名 `HEARTBEAT_REPLY_CAPABILITIES_KEY`(心跳 2xx 答复体);
130
+ 11.0.0:`EngineSignal` 两出口(`/health` 与心跳)整只承载在一个键 `ENGINE_SIGNAL_KEY`(`"engineSignal"`)下,`readEngineSignal(body)` 只读这个键;
131
+ 判官只读信号:`judgeReadiness(signal)` / `judgeRoutability(row, nowMs)` → `{ routable }` 或 `{ routable:false, code ∈ NOT_ROUTABLE_CODES, why }`,
132
+ `isReadyForTraffic` / `isRoutable` 是它们的布尔形;没有信号(旧引擎)= `no-engine-signal`,不可路由;布尔对 `draining` / `drainingSince` 标 `@deprecated`、本包零读点、退役已登记;
133
+ 8.3.0 additive:env 名常量 `FLEET_SCOPE_ENV`(`"FLEET_SCOPE"`,成员所属租户 scope,渲染器写、引擎读;缺席 = 默认 scope `GLOBAL_SCOPE`;进保留 env 名表);
134
+ 9.0.0 BREAKING:`readCenterCapabilities` 删,换三态读器 `readCapabilityReading(reply): CapabilityReading`(`declared` | `undeclared` | `unreadable`;键在场而形坏 ≠ 没宣告)、`EngineSignal.configTargetVersion` / `configAppliedVersion` 由串改数)、**scheduler-store 契约**(自唤醒
135
+ 存储形 + node 绑定)、**auth / auth-bridge / scopes / wire** 契约(RFC 8628 设备流、RS256 JWKS 鉴权桥、
136
+ 多租户 scope)。(src/fleet.ts;src/scheduler-store*.ts;src/api/*.ts)
137
+ - **web-admin 凭证文件契约**(S-698):`SEMA_WEB_ADMIN_TOKEN_FILE` 的内容是裸行(首行 = bearer,只收可打印 ASCII)或
138
+ `WebAdminCredentialEnvelope` 信封(`user-session`:access / refresh token + RFC 3339 `expiresAt` + `issuer`);
139
+ `parseWebAdminCredentialFile(text)` 三态判别(`{` 开头只按信封读,读不成 = `unreadable`,不回落裸行);
140
+ 连接 env 名一张表 `WEB_ADMIN_ENV`(十键,值 `SEMA_WEB_ADMIN_*`)+ 二选一判官 `judgeWebAdminCredentialDeclaration(env, credential)`(凭证闭集 `WEB_ADMIN_CREDENTIALS`:
141
+ `access` 读 `token` / `tokenFile`,`assertion` 读 `assertionToken` / `assertionTokenFile`;第二参必填;一对里两个都设 ⇒ throw,S-742)。
142
+ (src/web-admin-credential.ts)
143
+ - **目录形一次性迁移**(`./node`):`migrateConfigDirectory(dir, { documents, io, check? })` —— 命令行 `migrate` 背后的唯一实现(读目录 → 迁 → 整域终判 → 原子写 → 删退役域文件);`documents` = 调用方读的域名集(覆盖面外的文件不读不判不写不删),
144
+ `io` 注入四个口,真绑定 `nodeConfigDirectoryIo`(node:fs + 唯一的原子写器);返回闭集 `unreadable` / `no-documents` / `refused` / `noop` / `pending` / `applied`。(src/config-dir-migration.ts · src/config-dir-io.ts)
145
+ - **会话网页链接**:`webAdminSessionUrl(webBaseUrl, { worker, sessionId })` 铸 `<webBaseUrl>/chat?agent=<worker>&session=<sessionId>`(两位必填、逐位 `encodeURIComponent`、基址须是干净的绝对 http(s) URL 且尾斜杠折掉,
146
+ 坏输入抛、不铸半截链接)+ 配对解析 `parseWebAdminSessionUrl(link)`(绝对 / 相对串、`URL`、`URLSearchParams`;缺的那一位缺席)—— 路由与参数名只此一处,谁都别手拼。(src/web-admin-session-url.ts)
147
+ - **按 scope 绑定的令牌**(`./api/pull-token`):形与铸法一条规则、令牌族是数据(`WORKER_PULL_TOKEN` = `wpt_` / `wpt2_` / `worker-pull`);
148
+ `mintScopedToken` / `readScopedTokenBinding` / `verifyScopedToken`(重铸 + 常量时间比对;纯 JS HMAC-SHA256)。
149
+ - **`PRINCIPAL_MAX_LENGTH`**(= 190,`./api/auth-bridge`)· **/bug 报告**(`./api/feedback`:`FeedbackSubmitRequest` / `FeedbackWire` / 两个上限)·
150
+ **`Sha256Digest`**(`sha256:<64 位小写 hex>` 一处定义)。
151
+ - **退役 env 名墓碑表**:`RETIRED_ENVS`(renamed / replaced / removed 三族闭集,永久,一跳)+ 拒启句唯一铸点 `retiredEnvRefusal(env)`
152
+ + 目录投影 `buildRetiredEnvWire()`。(src/retired-envs.ts)
153
+
154
+ ## 何时用 / 何时不用
155
+
156
+ - **用**:你在写 web-admin 产品 / worker 服务 / TOC 桌面·CLI,需要校验配置、解析 effective、读本地
157
+ config.d、消费 `RemoteExecSpec` / `HooksConfig` / `SAFETY_MERGE_SPEC` —— 直接 import 这个包,**别各维护一份**。
158
+ - **不用**:你想存/传 secret 值(本包只存 NAME);你想要跑起来的服务或 CLI(纯 lib,无 bin);你想要
159
+ HTTP `/effective` 或 `/api/v1/auth/*` 的服务端实现(在 web-admin,本包只给 wire 形与纯判定函数)。
160
+
161
+ ## 分节链接(详见 llms-full.txt)
162
+
163
+ - 安装 / 引入(公网 npmjs,zod peer)→ §2
164
+ - 心智模型(一份契约两个源;EffectiveConfig vs EffectiveWire)→ §3
165
+ - 公共 API / 对外契约(16 域、纯函数、五族契约、错误形状)→ §4
166
+ - 配置项与环境变量 / secret 边界 → §5
167
+ - 对外入口地图(24 个 subpath:主 barrel `.` / `./node` / `./conformance` / 资产出口 `./package.json` 与 `./fleet-paths.json` / 细分)→ §6
168
+ - 发版纪律(1.x semver)与契约演进 → §7
169
+ - 使用陷阱(open-world 域、三态文件、null≠absent、governance 展开、三态 cap)→ §8
170
+ - 典型场景配方 → §10
171
+ - 限制与不支持 → §12
172
+
173
+ ## Optional
174
+
175
+ - 例子:`examples/toc-e2e.mjs`(可独立复跑的本地消费闭环,`npm run e2e`,须先 build)。
176
+ - 消费方接入答疑:`docs/CONSUMER-INTEGRATION.md`;auth/scopes 的 OpenAPI 镜像:`docs/openapi-auth.yaml` /
177
+ `docs/openapi-scopes.yaml`。
178
+ - 内容寻址 sha256(skills body 懒拉)、FNV-1a 64 `stableHash`(ETag/漂移检测)。
179
+ (src/sha256.ts;src/hash.ts;src/skills-manifest.ts)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/settings-schema",
3
- "version": "13.0.0",
3
+ "version": "14.0.0",
4
4
  "description": "Sema settings schema — pure config contract (zod domains + effective-config + roster resolution + ref-integrity + remoteExec) shared by sema-web-admin, 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",
@@ -125,6 +125,9 @@
125
125
  "dist",
126
126
  "bin",
127
127
  "conformance",
128
+ "docs",
129
+ "llms.txt",
130
+ "llms-full.txt",
128
131
  "README.md",
129
132
  "CHANGELOG.md"
130
133
  ],
@@ -146,7 +149,7 @@
146
149
  "publish:npm": "npm publish --access public --@sema-agent:registry=https://registry.npmjs.org/ --\"//registry.npmjs.org/:_authToken=${NPM_TOKEN}\""
147
150
  },
148
151
  "devDependencies": {
149
- "@sema-agent/core": "7.47.0",
152
+ "@sema-agent/core": "7.53.0",
150
153
  "@types/node": "^22.10.0",
151
154
  "esbuild": "^0.21.5",
152
155
  "typescript": "^5.7.0",
@@ -1,16 +0,0 @@
1
- /** [1057]① prompts contentDigest:canonical JSON(stableStringify 同姿势:键序稳定+深度护栏)全量 sha256,
2
- * **非盐化**(三方可独立复算)。入参=下发形的 `{sections, scenarioOverrides?}`(packId/contentDigest
3
- * 自身不入 hash)。 */
4
- export declare function promptsContentDigest(payload: {
5
- sections: unknown;
6
- scenarioOverrides?: unknown;
7
- }): {
8
- contentDigest: string;
9
- packId: string;
10
- /** [1062]③ 顺带:逐 section 对 `text` 铸的 contentHash(与 core 1.315 校验语义同刻度=
11
- * sha256(text));元素无 string text 位=undefined。web-admin 物化流程=先把这些写回
12
- * declaration.contentHash,再对含 hash 的终形铸整包 digest(本函数对入参原样铸,两步自洽)。 */
13
- sectionHashes: Array<string | undefined>;
14
- };
15
- /** 逐 section 对账锚(core 1.315 `PromptTextDeclaration.contentHash` 同刻度):sha256(text)。 */
16
- export declare function sectionContentHash(text: string): string;
@@ -1,49 +0,0 @@
1
- /**
2
- * @sema-agent/settings-schema/node — prompts 下发包的**内容摘要**([1057]①/[1062]③)。
3
- *
4
- * 这两只是跨仓**对账锚**:web-admin 铸、server 透传、core 的 manifest 归因**独立复算**,三方算出同一个值才
5
- * 对得上账([1050]② operator 对账位)。所以它们只有一件事要守:**一个刻度**。
6
- *
7
- * 4.0.0 从 `scheduler-store-node.ts` 搬到这里(不 breaking —— 仍挂在 `./node` 这条 subpath 上,消费方的
8
- * import 一个字不用改)。两条理由:①它与调度存储(`scheduled_tasks.json` 的原子读写 + 跨进程变更原语)
9
- * 零关系,住在一起只是历史;②搬家顺手把**两个** sha256 铸点合成一只 —— 此前整包 digest 与逐 section
10
- * contentHash 各自 `createHash('sha256')` 一次、各自拼一次 `sha256:` 前缀,哪天有人只改一处就成了两个刻度,
11
- * 而没有一格会红(门:`test/prompts-digest-4.0.0.test.ts` 逐条看着铸点数与出门前缀数)。
12
- *
13
- * 摘要用本包**纯实现**的 sha256(`./sha256.ts`),不是 `node:crypto` —— 那份实现与
14
- * `createHash("sha256").update(s,"utf8").digest("hex")` 逐字节相同(`test/sha256.test.ts` 逐例压着,
15
- * 本模块的门再压一遍摘要值本身),于是整个包的 sha256 只有**一份实现**。
16
- */
17
- import { stableStringify } from './hash.js';
18
- import { sha256Hex } from './sha256.js';
19
- import { PROMPT_PACK_ID_PREFIX } from './types.js';
20
- /**
21
- * 本模块**唯一**的 sha256 铸点:一段 utf8 文本 → `{ hex, anchor }`。`anchor` = 出门形 `sha256:<hex>`
22
- * (自描述算法,与 skills 的内容地址同形),`hex` 给需要裸 hex 的那一处(packId 取前 12 位)。
23
- * 两个出门形从**同一次**摘要派生 —— 这正是本模块存在的理由。
24
- */
25
- function contentAnchor(text) {
26
- const hex = sha256Hex(text);
27
- return { hex, anchor: `sha256:${hex}` };
28
- }
29
- /** [1057]① prompts contentDigest:canonical JSON(stableStringify 同姿势:键序稳定+深度护栏)全量 sha256,
30
- * **非盐化**(三方可独立复算)。入参=下发形的 `{sections, scenarioOverrides?}`(packId/contentDigest
31
- * 自身不入 hash)。 */
32
- export function promptsContentDigest(payload) {
33
- const canonical = stableStringify({
34
- sections: payload.sections,
35
- ...(payload.scenarioOverrides !== undefined ? { scenarioOverrides: payload.scenarioOverrides } : {}),
36
- });
37
- const { hex, anchor } = contentAnchor(canonical);
38
- const sectionHashes = Array.isArray(payload.sections)
39
- ? payload.sections.map((s) => {
40
- const t = s?.text;
41
- return typeof t === 'string' ? sectionContentHash(t) : undefined;
42
- })
43
- : [];
44
- return { contentDigest: anchor, packId: `${PROMPT_PACK_ID_PREFIX}${hex.slice(0, 12)}`, sectionHashes };
45
- }
46
- /** 逐 section 对账锚(core 1.315 `PromptTextDeclaration.contentHash` 同刻度):sha256(text)。 */
47
- export function sectionContentHash(text) {
48
- return contentAnchor(text).anchor;
49
- }