@sema-agent/settings-schema 1.5.0 → 1.7.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 CHANGED
@@ -6,6 +6,42 @@
6
6
  > `@sema-agent/registry-core`(更早还曾是 `@sema-ai/registry-core`)。本档 `0.19.0` 以下各节里的
7
7
  > 包名是**历史记录**,如实保留不追改。
8
8
 
9
+ ## 1.7.0 — 2026-09-06 — `mcp.servers[].source` 分组标签(sema-server B-036 / S-143 源头修的声明面半场;新键=minor)
10
+
11
+ - **`McpServerSpec.source?: string`**(非空、≤80 字;`.optional()` 无默认):声明方自述的层级标签,1:1 对应引擎
12
+ `McpServerSpec.source`(core ≥7.5.0 在 `wiring_manifest.mcp[].source` 逐字回显、single-line + 80 字封顶)。
13
+ **开集**——`plugin`/`user`/`project`/`local` 是 CC 惯用词不是词表,部署自己的分组词同样合法,故刻意不做闭词表
14
+ (信任轴仍是 `contentOrigin` 的闭表)。空串/超长/非字符串在解析处拒;缺席保持缺席。
15
+ - 病:本包 default-strip 对象没有这个键 ⇒ `config.d/mcp.json` 写的 `source` 在本地腿与 wire 腿都被剥掉,引擎读到缺席
16
+ ——与 1.4.0 前的 `contentOrigin` 同形。消费方 sema-server 的投影半场(请求腿 `normalizeServer` + center 腿
17
+ `resolveMcpServers`)随 server 7.62.0。红先:`test/mcp-source-label.test.ts` 五格(①保留 ②缺席 ③坏形拒 ④本地腿
18
+ round-trip ⑤wire 腿)。
19
+
20
+ ## 1.6.0 — 2026-09-05 — `settings.json` 跨会话两键 `crossSessionInbound` / `dialogExpiry`(新模块/新导出=minor)
21
+
22
+ 成案:跨终端会话设计稿(design/385 §4.4/§8)把这两个 settings 键的属主定在 worker 服务侧,而键的**格式契约**
23
+ 按本包定位落这里(与 `hooks` 同姿势:本包出 zod 形,引擎出判定,宿主出装配)。此前 worker 服务的 settings 键闭集门
24
+ 不认这两个键 ⇒ 一份合法的 CC `settings.json` 带上它们会被整请求 400;本节是那条链的上游一格。
25
+
26
+ **新模块 `src/cross-session.ts`(主 barrel 导出,无新 subpath ⇒ `exports` 表 21 项不变)**:
27
+
28
+ - `crossSessionInbound` —— 显式闭集 `CROSS_SESSION_INBOUND_VALUES = ["accept","hold","refuse"]`,**顺序即收紧秩**
29
+ (accept < hold < refuse:层次解析只许沿此序收紧);UI 第四拼写 `CROSS_SESSION_INBOUND_UNSET = "default"`
30
+ = **未设**(不是第四种策略),未设 ⇒ mode-parity。CC describe 逐字锚:「Inbound cross-session peer messages
31
+ (SendMessage from your other sessions)」。
32
+ - `dialogExpiry` —— `DIALOG_EXPIRY_VALUES = ["60s","5m","10m","never"]` + `DIALOG_EXPIRY_DEFAULT = "5m"`。
33
+ CC describe 明写**两个**消费面(远端停靠的审批对话框 / 停审的跨会话消息),本包只声明键形,宿主自陈消费哪一面。
34
+ - zod 受理面 `CrossSessionInboundSetting` / `DialogExpirySetting`;片段 schema `CrossSessionSettings`
35
+ (两键可选 + `.passthrough()` —— 本片段**不是**整份 settings 的闭集门)。
36
+ - 层读取器 `readCrossSessionInbound` / `readDialogExpiry` → `SettingLayerRead<T>` 三态(未设 / 显式值 / 词表外)。
37
+ **坏值方向 = 响亮**:词表外恒 `ok:false` 交调用方拒,与 CC 文件层的 `.catch(undefined)` 静默吞成未设有意分岔
38
+ (一个大小写拼错静默读成「未设」会把用户以为已关的入站车道悄悄打开)。
39
+
40
+ **锁步义务(写进模块头注)**:引擎侧另有一份同词表(判定纯函数的输入域),两份必须逐字相等;等值由同时装了本包
41
+ 与引擎的消费方用一格锁步钉住——本包保持纯度不变量,不 import 引擎。
42
+
43
+ 红先:`test/cross-session-1.6.test.ts` 20 格,落 `src/cross-session.ts` 之前首跑红(模块不存在)。
44
+
9
45
  ## 1.5.0 — 2026-09-04 — 扩展命名空间 + 剥键告警截断标志(sema-server S-118 源头修;新键/新导出=minor)
10
46
 
11
47
  成案:sema-server 修 cli 用户 P1「`/model` 热加载被装饰键整拒」时在下游连打四层补丁(按 kind 放宽→按域→按键路径闭集→
@@ -0,0 +1,78 @@
1
+ /**
2
+ * `settings.json` 的**跨会话两键** —— CC-parity 契约(`crossSessionInbound` / `dialogExpiry`)。
3
+ *
4
+ * 与 `hooks.ts` 同姿势:本包只出**格式契约**(纯 zod、零运行时依赖、浏览器安全),不做任何解释/判定。
5
+ * 判定(层次收紧、mode-parity、hold 因由)归引擎;写行、渲染、下发归各宿主。
6
+ *
7
+ * ## 两键的 CC 锚(逐字核过的语料读数,非转述)
8
+ *
9
+ * - `crossSessionInbound: enum(["accept","hold","refuse"])` —— describe:「Inbound cross-session peer
10
+ * messages (SendMessage from your other sessions)」:`accept` 投递、`hold` 停在收件方的待审队列
11
+ * (模型看不见、不能据此行动)、`refuse` 让本会话整体退出这条车道。**显式值恒赢**;未设 =
12
+ * mode-parity(发送方与收件方的权限档位同类才自动投递,不同类停审)。
13
+ * - `dialogExpiry: enum(["60s","5m","10m","never"])`,缺省 `"5m"` —— describe:「Max time a
14
+ * permission/user dialog forwarded to a remote client stays parked awaiting an answer, and how long a
15
+ * HELD cross-session message awaits approval」。**注意它有两个消费面**:远端停靠的审批对话框,与
16
+ * 停审的跨会话消息;本模块只声明键形,哪个宿主消费哪一面由宿主自陈。
17
+ *
18
+ * ## `"default"` 这第四个拼写
19
+ *
20
+ * 设置 UI 的选择器需要一个「不设」的可写值,CC 用字面量 `"default"`。它**不是第四种策略**:读取器
21
+ * (`readCrossSessionInbound` / `readDialogExpiry`)把它与 `null`/缺席一同折成 `undefined`。所以
22
+ * `CrossSessionInboundSetting` 的受理面是四拼写,而**值域闭集**(`CROSS_SESSION_INBOUND_VALUES`)只有三个。
23
+ *
24
+ * ## 坏值方向 = 响亮,不静默
25
+ *
26
+ * 词表外的值一律 `ok:false`,由调用方拒(HTTP 门 400 / 文件层告警)。CC 在文件层用 `.catch(undefined)`
27
+ * 静默吞成未设;本栈的坏值响亮律与之有意分岔——一个 `crossSessionInbound: "Hold"`(大小写拼错)静默
28
+ * 读成「未设」会把用户以为已经关掉的入站车道悄悄打开,那正是保护型配置最不能有的沉默。
29
+ *
30
+ * ## 与引擎词表的锁步
31
+ *
32
+ * 引擎另有一份同词表(判定纯函数的输入域)。两份**必须逐字相等**;等值由消费方(同时装了本包与引擎
33
+ * 的那一侧)用一格锁步钉住 —— 任一侧加词/改序,那一格先红。本包不 import 引擎(纯度不变量)。
34
+ */
35
+ import { z } from "zod";
36
+ /** 显式三值,**顺序即收紧秩**(accept < hold < refuse):层次解析只许沿此序收紧,永不放宽。 */
37
+ export declare const CROSS_SESSION_INBOUND_VALUES: readonly ["accept", "hold", "refuse"];
38
+ export type CrossSessionInboundValue = (typeof CROSS_SESSION_INBOUND_VALUES)[number];
39
+ /** 设置 UI 的「不设」拼写(见头注)——两键共用同一个字面量。 */
40
+ export declare const CROSS_SESSION_INBOUND_UNSET: "default";
41
+ /** 文件层受理面:三个显式值 + `"default"`(未设)。 */
42
+ export declare const CrossSessionInboundSetting: z.ZodEnum<["accept", "hold", "refuse", "default"]>;
43
+ export type CrossSessionInboundSettingValue = z.infer<typeof CrossSessionInboundSetting>;
44
+ /** 四值闭集(CC 逐字)。`"never"` = 不设期限。 */
45
+ export declare const DIALOG_EXPIRY_VALUES: readonly ["60s", "5m", "10m", "never"];
46
+ export type DialogExpiryValue = (typeof DIALOG_EXPIRY_VALUES)[number];
47
+ /** 未设时生效的值(CC 缺省)。 */
48
+ export declare const DIALOG_EXPIRY_DEFAULT: DialogExpiryValue;
49
+ /** 文件层受理面:四个值 + `"default"`(未设 ⇒ 落 {@link DIALOG_EXPIRY_DEFAULT})。 */
50
+ export declare const DialogExpirySetting: z.ZodEnum<["60s", "5m", "10m", "never", "default"]>;
51
+ export type DialogExpirySettingValue = z.infer<typeof DialogExpirySetting>;
52
+ /**
53
+ * 整份 `settings.json` 里**本片段负责的两键**。刻意 `passthrough`:本片段不是整份 settings 的闭集门
54
+ * (那道门归各宿主的受理面——宿主消费哪些键、拒哪些键,是宿主的事)。它只保证:**这两个键若在场,
55
+ * 值必合法**。
56
+ */
57
+ export declare const CrossSessionSettings: z.ZodObject<{
58
+ crossSessionInbound: z.ZodOptional<z.ZodEnum<["accept", "hold", "refuse", "default"]>>;
59
+ dialogExpiry: z.ZodOptional<z.ZodEnum<["60s", "5m", "10m", "never", "default"]>>;
60
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
61
+ crossSessionInbound: z.ZodOptional<z.ZodEnum<["accept", "hold", "refuse", "default"]>>;
62
+ dialogExpiry: z.ZodOptional<z.ZodEnum<["60s", "5m", "10m", "never", "default"]>>;
63
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
64
+ crossSessionInbound: z.ZodOptional<z.ZodEnum<["accept", "hold", "refuse", "default"]>>;
65
+ dialogExpiry: z.ZodOptional<z.ZodEnum<["60s", "5m", "10m", "never", "default"]>>;
66
+ }, z.ZodTypeAny, "passthrough">>;
67
+ export type CrossSessionSettings = z.infer<typeof CrossSessionSettings>;
68
+ /** 一层读数:`ok:false` = 词表外(调用方响亮拒);`ok:true` 无 `value` = 未设;有 `value` = 显式值。 */
69
+ export type SettingLayerRead<T> = {
70
+ ok: true;
71
+ value?: T;
72
+ } | {
73
+ ok: false;
74
+ };
75
+ /** 读一层的 `crossSessionInbound` 原始值。 */
76
+ export declare function readCrossSessionInbound(raw: unknown): SettingLayerRead<CrossSessionInboundValue>;
77
+ /** 读一层的 `dialogExpiry` 原始值(未设 ⇒ 由消费方落 {@link DIALOG_EXPIRY_DEFAULT},本函数不替它落)。 */
78
+ export declare function readDialogExpiry(raw: unknown): SettingLayerRead<DialogExpiryValue>;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * `settings.json` 的**跨会话两键** —— CC-parity 契约(`crossSessionInbound` / `dialogExpiry`)。
3
+ *
4
+ * 与 `hooks.ts` 同姿势:本包只出**格式契约**(纯 zod、零运行时依赖、浏览器安全),不做任何解释/判定。
5
+ * 判定(层次收紧、mode-parity、hold 因由)归引擎;写行、渲染、下发归各宿主。
6
+ *
7
+ * ## 两键的 CC 锚(逐字核过的语料读数,非转述)
8
+ *
9
+ * - `crossSessionInbound: enum(["accept","hold","refuse"])` —— describe:「Inbound cross-session peer
10
+ * messages (SendMessage from your other sessions)」:`accept` 投递、`hold` 停在收件方的待审队列
11
+ * (模型看不见、不能据此行动)、`refuse` 让本会话整体退出这条车道。**显式值恒赢**;未设 =
12
+ * mode-parity(发送方与收件方的权限档位同类才自动投递,不同类停审)。
13
+ * - `dialogExpiry: enum(["60s","5m","10m","never"])`,缺省 `"5m"` —— describe:「Max time a
14
+ * permission/user dialog forwarded to a remote client stays parked awaiting an answer, and how long a
15
+ * HELD cross-session message awaits approval」。**注意它有两个消费面**:远端停靠的审批对话框,与
16
+ * 停审的跨会话消息;本模块只声明键形,哪个宿主消费哪一面由宿主自陈。
17
+ *
18
+ * ## `"default"` 这第四个拼写
19
+ *
20
+ * 设置 UI 的选择器需要一个「不设」的可写值,CC 用字面量 `"default"`。它**不是第四种策略**:读取器
21
+ * (`readCrossSessionInbound` / `readDialogExpiry`)把它与 `null`/缺席一同折成 `undefined`。所以
22
+ * `CrossSessionInboundSetting` 的受理面是四拼写,而**值域闭集**(`CROSS_SESSION_INBOUND_VALUES`)只有三个。
23
+ *
24
+ * ## 坏值方向 = 响亮,不静默
25
+ *
26
+ * 词表外的值一律 `ok:false`,由调用方拒(HTTP 门 400 / 文件层告警)。CC 在文件层用 `.catch(undefined)`
27
+ * 静默吞成未设;本栈的坏值响亮律与之有意分岔——一个 `crossSessionInbound: "Hold"`(大小写拼错)静默
28
+ * 读成「未设」会把用户以为已经关掉的入站车道悄悄打开,那正是保护型配置最不能有的沉默。
29
+ *
30
+ * ## 与引擎词表的锁步
31
+ *
32
+ * 引擎另有一份同词表(判定纯函数的输入域)。两份**必须逐字相等**;等值由消费方(同时装了本包与引擎
33
+ * 的那一侧)用一格锁步钉住 —— 任一侧加词/改序,那一格先红。本包不 import 引擎(纯度不变量)。
34
+ */
35
+ import { z } from "zod";
36
+ // ── crossSessionInbound ────────────────────────────────────────────────────────────────────────────
37
+ /** 显式三值,**顺序即收紧秩**(accept < hold < refuse):层次解析只许沿此序收紧,永不放宽。 */
38
+ export const CROSS_SESSION_INBOUND_VALUES = ["accept", "hold", "refuse"];
39
+ /** 设置 UI 的「不设」拼写(见头注)——两键共用同一个字面量。 */
40
+ export const CROSS_SESSION_INBOUND_UNSET = "default";
41
+ /** 文件层受理面:三个显式值 + `"default"`(未设)。 */
42
+ export const CrossSessionInboundSetting = z.enum([...CROSS_SESSION_INBOUND_VALUES, CROSS_SESSION_INBOUND_UNSET]);
43
+ // ── dialogExpiry ───────────────────────────────────────────────────────────────────────────────────
44
+ /** 四值闭集(CC 逐字)。`"never"` = 不设期限。 */
45
+ export const DIALOG_EXPIRY_VALUES = ["60s", "5m", "10m", "never"];
46
+ /** 未设时生效的值(CC 缺省)。 */
47
+ export const DIALOG_EXPIRY_DEFAULT = "5m";
48
+ /** 文件层受理面:四个值 + `"default"`(未设 ⇒ 落 {@link DIALOG_EXPIRY_DEFAULT})。 */
49
+ export const DialogExpirySetting = z.enum([...DIALOG_EXPIRY_VALUES, CROSS_SESSION_INBOUND_UNSET]);
50
+ // ── settings 片段 ──────────────────────────────────────────────────────────────────────────────────
51
+ /**
52
+ * 整份 `settings.json` 里**本片段负责的两键**。刻意 `passthrough`:本片段不是整份 settings 的闭集门
53
+ * (那道门归各宿主的受理面——宿主消费哪些键、拒哪些键,是宿主的事)。它只保证:**这两个键若在场,
54
+ * 值必合法**。
55
+ */
56
+ export const CrossSessionSettings = z
57
+ .object({
58
+ crossSessionInbound: CrossSessionInboundSetting.optional(),
59
+ dialogExpiry: DialogExpirySetting.optional(),
60
+ })
61
+ .passthrough();
62
+ function readEnumLayer(raw, values) {
63
+ if (raw === undefined || raw === null || raw === CROSS_SESSION_INBOUND_UNSET)
64
+ return { ok: true };
65
+ return typeof raw === "string" && values.includes(raw) ? { ok: true, value: raw } : { ok: false };
66
+ }
67
+ /** 读一层的 `crossSessionInbound` 原始值。 */
68
+ export function readCrossSessionInbound(raw) {
69
+ return readEnumLayer(raw, CROSS_SESSION_INBOUND_VALUES);
70
+ }
71
+ /** 读一层的 `dialogExpiry` 原始值(未设 ⇒ 由消费方落 {@link DIALOG_EXPIRY_DEFAULT},本函数不替它落)。 */
72
+ export function readDialogExpiry(raw) {
73
+ return readEnumLayer(raw, DIALOG_EXPIRY_VALUES);
74
+ }
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export * from "./cross-domain.js";
14
14
  export * from "./remote-exec.js";
15
15
  export * from "./safety-merge-spec.js";
16
16
  export * from "./scheduler-store.js";
17
+ export * from "./cross-session.js";
17
18
  export * from "./hooks.js";
18
19
  export * from "./fleet.js";
19
20
  export * from "./migrate.js";
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ export * from "./cross-domain.js"; // pure half only (no fleet placement)
14
14
  export * from "./remote-exec.js";
15
15
  export * from "./safety-merge-spec.js"; // #14 per-category safety merge-spec (settings resolver authority)
16
16
  export * from "./scheduler-store.js"; // R7 self-wake scheduler store CONTRACT (pure: type + parse/serialize + SchedulerStore interface; fs binding in ./node)
17
+ export * from "./cross-session.js"; // CC-parity `settings.json` cross-session keys (crossSessionInbound / dialogExpiry) — pure/browser-safe
17
18
  export * from "./hooks.js"; // CC-parity hooks contract (31-event set + owner map + per-event input/output shapes + HooksConfig) & stop attribution (stoppedBy) — pure/browser-safe
18
19
  export * from "./fleet.js"; // scheduling/fleet contract (drain protocol · instance discovery · dispatch policy · quota lease · usage report · quota reset event) — CONTROL-PLANE-SCHEDULING-DESIGN, pure/browser-safe
19
20
  export * from "./migrate.js"; // 0.5→0.6 migration tools (hosts grandfathering + worker.model→catalog migration PLAN — report/draft only, E1; EXPERT-REDESIGN §2-2/§3), pure/browser-safe
package/dist/types.d.ts CHANGED
@@ -7317,6 +7317,17 @@ export declare const McpServerSpec: z.ZodObject<{
7317
7317
  * declared `"local"`, the engine read ABSENT. A value outside the table is REJECTED at parse — a mistyped trust
7318
7318
  * word must never be read as a legal one (the consumer's gate is equally severe: no case-folding). */
7319
7319
  contentOrigin: z.ZodOptional<z.ZodEnum<["local", "execution", "external"]>>;
7320
+ /** Declaration-plane GROUPING LABEL for this server — maps 1:1 onto the engine's `McpServerSpec.source`
7321
+ * (core ≥7.5.0 echoes it verbatim on `wiring_manifest.mcp[].source`, single-line + 80-char cap, so a
7322
+ * consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
7323
+ * `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
7324
+ * no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
7325
+ * no label (`.optional()`, no default — a label has no default tier). Empty / over-cap / non-string is
7326
+ * REJECTED at parse: a malformed label must not enter the ledger silently. Display-only: no gate /
7327
+ * policy / trust effect (the trust axis is `contentOrigin` above, which stays a closed table).
7328
+ * Before this key existed both legs stripped it (default-strip object); this is the declaration half of
7329
+ * the consumer-side fix (ticket B-036 / S-143), the projection half lives in the consumer. */
7330
+ source: z.ZodOptional<z.ZodString>;
7320
7331
  notes: z.ZodOptional<z.ZodString>;
7321
7332
  }, "strip", z.ZodTypeAny, {
7322
7333
  name: string;
@@ -7338,6 +7349,7 @@ export declare const McpServerSpec: z.ZodObject<{
7338
7349
  notes?: string | undefined;
7339
7350
  allowTools?: string[] | undefined;
7340
7351
  contentOrigin?: "local" | "execution" | "external" | undefined;
7352
+ source?: string | undefined;
7341
7353
  }, {
7342
7354
  name: string;
7343
7355
  transport: {
@@ -7358,6 +7370,7 @@ export declare const McpServerSpec: z.ZodObject<{
7358
7370
  allowTools?: string[] | undefined;
7359
7371
  elicitation?: boolean | undefined;
7360
7372
  contentOrigin?: "local" | "execution" | "external" | undefined;
7373
+ source?: string | undefined;
7361
7374
  }>;
7362
7375
  export type McpServerSpec = z.infer<typeof McpServerSpec>;
7363
7376
  export declare const McpConfig: z.ZodEffects<z.ZodObject<{
@@ -7429,6 +7442,17 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7429
7442
  * declared `"local"`, the engine read ABSENT. A value outside the table is REJECTED at parse — a mistyped trust
7430
7443
  * word must never be read as a legal one (the consumer's gate is equally severe: no case-folding). */
7431
7444
  contentOrigin: z.ZodOptional<z.ZodEnum<["local", "execution", "external"]>>;
7445
+ /** Declaration-plane GROUPING LABEL for this server — maps 1:1 onto the engine's `McpServerSpec.source`
7446
+ * (core ≥7.5.0 echoes it verbatim on `wiring_manifest.mcp[].source`, single-line + 80-char cap, so a
7447
+ * consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
7448
+ * `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
7449
+ * no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
7450
+ * no label (`.optional()`, no default — a label has no default tier). Empty / over-cap / non-string is
7451
+ * REJECTED at parse: a malformed label must not enter the ledger silently. Display-only: no gate /
7452
+ * policy / trust effect (the trust axis is `contentOrigin` above, which stays a closed table).
7453
+ * Before this key existed both legs stripped it (default-strip object); this is the declaration half of
7454
+ * the consumer-side fix (ticket B-036 / S-143), the projection half lives in the consumer. */
7455
+ source: z.ZodOptional<z.ZodString>;
7432
7456
  notes: z.ZodOptional<z.ZodString>;
7433
7457
  }, "strip", z.ZodTypeAny, {
7434
7458
  name: string;
@@ -7450,6 +7474,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7450
7474
  notes?: string | undefined;
7451
7475
  allowTools?: string[] | undefined;
7452
7476
  contentOrigin?: "local" | "execution" | "external" | undefined;
7477
+ source?: string | undefined;
7453
7478
  }, {
7454
7479
  name: string;
7455
7480
  transport: {
@@ -7470,6 +7495,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7470
7495
  allowTools?: string[] | undefined;
7471
7496
  elicitation?: boolean | undefined;
7472
7497
  contentOrigin?: "local" | "execution" | "external" | undefined;
7498
+ source?: string | undefined;
7473
7499
  }>, "many">>;
7474
7500
  }, "strip", z.ZodTypeAny, {
7475
7501
  servers: {
@@ -7492,6 +7518,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7492
7518
  notes?: string | undefined;
7493
7519
  allowTools?: string[] | undefined;
7494
7520
  contentOrigin?: "local" | "execution" | "external" | undefined;
7521
+ source?: string | undefined;
7495
7522
  }[];
7496
7523
  }, {
7497
7524
  servers?: {
@@ -7514,6 +7541,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7514
7541
  allowTools?: string[] | undefined;
7515
7542
  elicitation?: boolean | undefined;
7516
7543
  contentOrigin?: "local" | "execution" | "external" | undefined;
7544
+ source?: string | undefined;
7517
7545
  }[] | undefined;
7518
7546
  }>, {
7519
7547
  servers: {
@@ -7536,6 +7564,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7536
7564
  notes?: string | undefined;
7537
7565
  allowTools?: string[] | undefined;
7538
7566
  contentOrigin?: "local" | "execution" | "external" | undefined;
7567
+ source?: string | undefined;
7539
7568
  }[];
7540
7569
  }, {
7541
7570
  servers?: {
@@ -7558,6 +7587,7 @@ export declare const McpConfig: z.ZodEffects<z.ZodObject<{
7558
7587
  allowTools?: string[] | undefined;
7559
7588
  elicitation?: boolean | undefined;
7560
7589
  contentOrigin?: "local" | "execution" | "external" | undefined;
7590
+ source?: string | undefined;
7561
7591
  }[] | undefined;
7562
7592
  }>;
7563
7593
  export type McpConfig = z.infer<typeof McpConfig>;
@@ -10079,6 +10109,17 @@ export declare const DOMAIN_SCHEMAS: {
10079
10109
  * declared `"local"`, the engine read ABSENT. A value outside the table is REJECTED at parse — a mistyped trust
10080
10110
  * word must never be read as a legal one (the consumer's gate is equally severe: no case-folding). */
10081
10111
  contentOrigin: z.ZodOptional<z.ZodEnum<["local", "execution", "external"]>>;
10112
+ /** Declaration-plane GROUPING LABEL for this server — maps 1:1 onto the engine's `McpServerSpec.source`
10113
+ * (core ≥7.5.0 echoes it verbatim on `wiring_manifest.mcp[].source`, single-line + 80-char cap, so a
10114
+ * consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
10115
+ * `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
10116
+ * no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
10117
+ * no label (`.optional()`, no default — a label has no default tier). Empty / over-cap / non-string is
10118
+ * REJECTED at parse: a malformed label must not enter the ledger silently. Display-only: no gate /
10119
+ * policy / trust effect (the trust axis is `contentOrigin` above, which stays a closed table).
10120
+ * Before this key existed both legs stripped it (default-strip object); this is the declaration half of
10121
+ * the consumer-side fix (ticket B-036 / S-143), the projection half lives in the consumer. */
10122
+ source: z.ZodOptional<z.ZodString>;
10082
10123
  notes: z.ZodOptional<z.ZodString>;
10083
10124
  }, "strip", z.ZodTypeAny, {
10084
10125
  name: string;
@@ -10100,6 +10141,7 @@ export declare const DOMAIN_SCHEMAS: {
10100
10141
  notes?: string | undefined;
10101
10142
  allowTools?: string[] | undefined;
10102
10143
  contentOrigin?: "local" | "execution" | "external" | undefined;
10144
+ source?: string | undefined;
10103
10145
  }, {
10104
10146
  name: string;
10105
10147
  transport: {
@@ -10120,6 +10162,7 @@ export declare const DOMAIN_SCHEMAS: {
10120
10162
  allowTools?: string[] | undefined;
10121
10163
  elicitation?: boolean | undefined;
10122
10164
  contentOrigin?: "local" | "execution" | "external" | undefined;
10165
+ source?: string | undefined;
10123
10166
  }>, "many">>;
10124
10167
  }, "strip", z.ZodTypeAny, {
10125
10168
  servers: {
@@ -10142,6 +10185,7 @@ export declare const DOMAIN_SCHEMAS: {
10142
10185
  notes?: string | undefined;
10143
10186
  allowTools?: string[] | undefined;
10144
10187
  contentOrigin?: "local" | "execution" | "external" | undefined;
10188
+ source?: string | undefined;
10145
10189
  }[];
10146
10190
  }, {
10147
10191
  servers?: {
@@ -10164,6 +10208,7 @@ export declare const DOMAIN_SCHEMAS: {
10164
10208
  allowTools?: string[] | undefined;
10165
10209
  elicitation?: boolean | undefined;
10166
10210
  contentOrigin?: "local" | "execution" | "external" | undefined;
10211
+ source?: string | undefined;
10167
10212
  }[] | undefined;
10168
10213
  }>, {
10169
10214
  servers: {
@@ -10186,6 +10231,7 @@ export declare const DOMAIN_SCHEMAS: {
10186
10231
  notes?: string | undefined;
10187
10232
  allowTools?: string[] | undefined;
10188
10233
  contentOrigin?: "local" | "execution" | "external" | undefined;
10234
+ source?: string | undefined;
10189
10235
  }[];
10190
10236
  }, {
10191
10237
  servers?: {
@@ -10208,6 +10254,7 @@ export declare const DOMAIN_SCHEMAS: {
10208
10254
  allowTools?: string[] | undefined;
10209
10255
  elicitation?: boolean | undefined;
10210
10256
  contentOrigin?: "local" | "execution" | "external" | undefined;
10257
+ source?: string | undefined;
10211
10258
  }[] | undefined;
10212
10259
  }>;
10213
10260
  readonly plugins: z.ZodEffects<z.ZodObject<{
package/dist/types.js CHANGED
@@ -1798,7 +1798,7 @@ export const SkillsManifestSchema = z.object({
1798
1798
  });
1799
1799
  // ── Domain: mcp (MCP server 注册表 — docs/MCP-SKILLS.md, Roadmap B1) ────────────
1800
1800
  // sema-registry = an MCP-server REGISTRY: a scenario mounts a subset by `scenarios[]`. Maps onto core's
1801
- // `McpServerSpec = { name, transport: {kind:"stdio",command,args?,env?} | {kind:"http",url,headers?}, allowTools?, contentOrigin? }`.
1801
+ // `McpServerSpec = { name, transport: {kind:"stdio",command,args?,env?} | {kind:"http",url,headers?}, allowTools?, contentOrigin?, source? }`.
1802
1802
  // SECRET BOUNDARY (§3.1, design/15): a transport's env/header VALUES may be secret → the center stores only
1803
1803
  // env-NAME references (`envRefs`/`headerRefs`: target-key → an ENV_NAME in the SERVICE's env). The service's
1804
1804
  // `resolveSpec` reads the real values from its own environment — this DB never holds a credential. Like
@@ -1888,6 +1888,17 @@ export const McpServerSpec = z.object({
1888
1888
  * declared `"local"`, the engine read ABSENT. A value outside the table is REJECTED at parse — a mistyped trust
1889
1889
  * word must never be read as a legal one (the consumer's gate is equally severe: no case-folding). */
1890
1890
  contentOrigin: z.enum(MCP_CONTENT_ORIGINS).optional(),
1891
+ /** Declaration-plane GROUPING LABEL for this server — maps 1:1 onto the engine's `McpServerSpec.source`
1892
+ * (core ≥7.5.0 echoes it verbatim on `wiring_manifest.mcp[].source`, single-line + 80-char cap, so a
1893
+ * consumer can group servers by where they were declared). An OPEN set: CC's `plugin` / `user` /
1894
+ * `project` / `local` are conventions, not a vocabulary — a deployment's own word is equally legal, so
1895
+ * no closed table here (a closed table would reject the operator's grouping word at parse). ABSENT =
1896
+ * no label (`.optional()`, no default — a label has no default tier). Empty / over-cap / non-string is
1897
+ * REJECTED at parse: a malformed label must not enter the ledger silently. Display-only: no gate /
1898
+ * policy / trust effect (the trust axis is `contentOrigin` above, which stays a closed table).
1899
+ * Before this key existed both legs stripped it (default-strip object); this is the declaration half of
1900
+ * the consumer-side fix (ticket B-036 / S-143), the projection half lives in the consumer. */
1901
+ source: z.string().min(1).max(80).optional(),
1891
1902
  notes: z.string().optional(),
1892
1903
  });
1893
1904
  export const McpConfig = z
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/settings-schema",
3
- "version": "1.5.0",
3
+ "version": "1.7.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",