@sema-agent/settings-schema 12.1.0 → 12.2.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,35 @@
6
6
  > `@sema-agent/registry-core`(更早还曾是 `@sema-ai/registry-core`)。本档 `0.19.0` 以下各节里的
7
7
  > 包名是**历史记录**,如实保留不追改。
8
8
 
9
+ ## 12.2.0 — 2026-10-12 — minor:`mcp.servers[]` 条目三只解析透明可选键 `toolAxes` / `authForm` / `entryKind` · http 传输可选 `assertionHeader`(与 `principalHeader` 互斥)
10
+
11
+ > minor:`mcp.servers[]` 条目上多三只**解析透明**的可选键 `toolAxes` / `authForm` / `entryKind`;http 形传输上多一只可选键 `assertionHeader`(HTTP 头名),与 `principalHeader` 互斥。
12
+ > additive:零删、零改名、零改形;导出名不变(导出面登记表 0 行变化);四个键缺席时读数逐字不变。
13
+
14
+ ### 新键:连接器条目的三只声明键 `toolAxes` / `authForm` / `entryKind`(解析透明)
15
+
16
+ 此前这三个键写进 `config.d/mcp.json`(或由中心下发)时,在本地腿与 wire 腿都被剥掉并报 `unknown-keys-dropped`,消费方读到缺席。现在照 `toolFaces`(1.9.0)的先例:
17
+ `z.unknown().optional()`,**解析透明**,登记在 `PARSE_TRANSPARENT_KEYS`(三行,`since: "12.2.0"`,`validatedBy: "consumer"`)—— 本包只承载、原样过(对象 / 数组 / 标量 / `null` 一视同仁),
18
+ 不判形、不判语义;词表与含义归读它的消费方(连接器的挂载读、服务器的投影)。缺席 ⇒ 键不铸(没有默认)。
19
+ 三问 —— **谁需要**:连接器的 hosted / standalone 条目形(启动器写条目、消费方读条目);**谁受伤**:无 —— 四个键都缺席时读数逐字不变;三键在场时此前是被剥并告警、现在逐字保留(把「被剥」当契约的读法没有依据);**补偿**:缺省缺席,不写这三个键的条目逐字不变。
20
+ 钉:`test/mcp-connector-keys-12.2.test.ts`(任意形原样过 · 缺席不铸 · 登记三行 · 本地腿 round-trip 与 `readEffectiveWire`)· `test/parse-transparent-keys.test.ts`(登记表与 schema 双向对拍,自动覆盖三行)。
21
+
22
+ ### 新键:http 传输的 `assertionHeader`,与 `principalHeader` 互斥
23
+
24
+ `transport: { kind: "http", … }` 多一只可选键 `assertionHeader`:服务往这台(hosted 连接器)服务器的请求上用哪个头送**连接器断言**。头名过与 `principalHeader` / `headerRefs` 键**同一只**判官
25
+ (RFC 7230 token、不得是凭据形);本包只判形,断言怎么铸、怎么验归消费方。`principalHeader` 与 `assertionHeader` 回答同一个问题(「这台 http 服务器的请求上用哪个头送身份」)的两个答案,
26
+ 所以**同在一条里 ⇒ 解析期拒**,拒句点名条目名与两个键;互斥只在条目层判一处,三道门(条目 / `McpConfig` / `validateDomain`)同一判,读路径上该条目按逐条容错被丢(`entry-dropped`),同域其余条目存活。
27
+ stdio 形传输上给它:与 `principalHeader` 在 stdio 上的既有处置**同判** —— 解析不拒、键被剥、读路径照常报 `unknown-keys-dropped`(不自造第二套)。
28
+ 三问 —— **谁需要**:连接器的 hosted 条目形(断言头名在条目上声明,不靠约定俗成的暂定名);**谁受伤**:无 —— 新键,缺席时读数逐字不变;写过 `principalHeader` 的条目不受影响(只在两键同设时才拒,而 `assertionHeader` 此前不存在);**补偿**:缺省缺席;只想送终端用户主体的条目继续只设 `principalHeader`。
29
+ 钉:`test/mcp-assertion-header-12.2.test.ts`(单独在场过且缺席不铸 · 同在拒且拒句点名条目与两键 · 头名形与 `principalHeader` 同表差分 · stdio 同判 · 本地腿逐条丢)。
30
+
31
+ ## 12.1.1 — 2026-10-12 — patch:`isAbsoluteHostPath` 认三族绝对形(posix `/…` · Windows 盘符 `X:\\…` / `X:/…` · UNC `\\\\server\\share\\…`),同一条律(零 `..` 段、零 NUL、长度上界);拒句点名三族
32
+
33
+ - **行为修复(宿主路径形判)**。`isAbsoluteHostPath` / `AbsoluteHostPath` 此前只认 `/` 开头(posix 口径),Windows 壳按 CC 同形送 `C:\…` 的任务 `cwd` / `additionalDirectories` / `skill.baseDir` 全被判「非绝对」—— 读它的 server 7.125.0 据此把 Windows 宿主的**每一条提交** 400 掉。
34
+ **Now.** 三族绝对形同一只判官:posix(`/` 开头)· Windows 盘符(`X:\` / `X:/`;裸 `X:` 与 `X:rel` 不绝对)· UNC(`\\server\share`;`\\server` 不够;`\\?\` 设备路径不收);三族同一条律 —— 零 `..` 段(两种分隔符都算)、零 NUL、≤ `ABSOLUTE_HOST_PATH_MAX`。只判形、不碰文件系统、不做族内归一(怎么解析归宿主那一族)。拒句改成点名三族。
35
+ 三问 —— **谁需要**:大脑在云、手在 Windows 本机的用户(壳禁止侧补偿,路径按宿主原形送);**谁受伤**:无 —— posix 读数逐字不变;把「`C:\…` 应被拒」当事实的消费方(没有);**补偿**:无旋钮(形判不是策略)。
36
+ 钉:`test/host-path-11.3.1.test.ts`(盘符 / UNC 真;裸盘符 / `C:rel` / 单反斜杠 / 无 share / 设备路径假;`..` / NUL / 超长跨三族同拒;zod 拒句点名三族)· `test/projects-11.3.0.test.ts` 参照式随律翻(三族)。与 11.3.1(11.x 线热修,dist-tag `line-11`)同一处改。
37
+
9
38
  ## 12.1.0 — 2026-10-12 — minor:新导出 interpolateHookEnvVars(http 钩子 header 的 $VAR / ${VAR} 展开只有一只读法,照 CC 2.1.296:名单内展开、名单外与凭据名置空并回报 blanked 清单、大写名字形、剥 CR / LF / NUL);消费方 server hook runner / cli execHttpHook
10
39
 
11
40
  > minor:新增一只纯函数导出 `interpolateHookEnvVars(headers, allowedEnvVars, env)`(主 barrel 与 `./hooks` 两处),外加它的两个结果类型 `HookEnvInterpolation` / `HookEnvBlank`。
package/README.md CHANGED
@@ -482,7 +482,8 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
482
482
  carries verbatim WITHOUT checking their shape, each row naming who does check it (the engine's ingest side or
483
483
  a consumer's enforcement point). Today: `models[].compat` (1.10.0), `models[].headers` (6.4.0; the header-name
484
484
  allowlist × lane is sema-server's, not restated here), `mcp.servers[].source` (1.7.2), `mcp.servers[].toolFaces`
485
- (1.9.0), and an entitlement override's `value`. `models[].extraBody` is NOT one of them — it has its own shape
485
+ (1.9.0), `mcp.servers[].toolAxes` / `authForm` / `entryKind` (12.2.0; connector-entry declarations, semantics are the consumer's),
486
+ and an entitlement override's `value`. `models[].extraBody` is NOT one of them — it has its own shape
486
487
  gate (a plain JSON object); what it leaves open is the key vocabulary inside. `compat` / `headers` / `extraBody`
487
488
  still clear the one free-form safety judgment (secret-shaped key/value, accessor, cycle, non-JSON, too deep ⇒ rejected).
488
489
  - **Extension namespaces** (`EXTENSION_NAMESPACES`, 1.5.0): keys another writer puts in a domain document by
@@ -1 +1 @@
1
- 12.1.0
1
+ 12.2.0
@@ -5,13 +5,6 @@
5
5
  import { z } from "zod";
6
6
  /** 一条主机绝对路径的长度上界(字符数)。 */
7
7
  export declare const ABSOLUTE_HOST_PATH_MAX = 4096;
8
- /**
9
- * `p` 是不是一条形上合法的**主机绝对路径**:字符串、非空、≤ {@link ABSOLUTE_HOST_PATH_MAX}、不含 NUL、以 `/` 开头(posix 绝对)、没有 `..` 段
10
- * (`/` 与 `\` 都算分隔符 —— `path.isAbsolute` 是语法判,`/a/../../etc` 也「绝对」,而读方 `path.resolve` 会把它解到别处;拒掉它,读到的就是写下的那一条)。
11
- *
12
- * posix 口径是有意的:读这些路径的主机车道今天跑 posix 树,而这一律在 posix 宿主上与 Node 的 `path.isAbsolute` 逐字同判(`C:\x`、`\\host\share`
13
- * 在 posix 上不绝对)。哪天主机车道要接 win 树,换的是这一只(按树的家族判),读方跟着同一只走。
14
- */
15
8
  export declare function isAbsoluteHostPath(p: unknown): p is string;
16
9
  /** {@link isAbsoluteHostPath} 的 zod 座位(一条 issue,定句)。 */
17
10
  export declare const AbsoluteHostPath: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
package/dist/host-path.js CHANGED
@@ -7,16 +7,21 @@ import { buildQuotedIssue, fixed } from "./quoted-issue.js";
7
7
  /** 一条主机绝对路径的长度上界(字符数)。 */
8
8
  export const ABSOLUTE_HOST_PATH_MAX = 4096;
9
9
  /**
10
- * `p` 是不是一条形上合法的**主机绝对路径**:字符串、非空、≤ {@link ABSOLUTE_HOST_PATH_MAX}、不含 NUL、以 `/` 开头(posix 绝对)、没有 `..` 段
10
+ * `p` 是不是一条形上合法的**主机绝对路径**:字符串、非空、≤ {@link ABSOLUTE_HOST_PATH_MAX}、不含 NUL、三族绝对形之一(posix `/` 开头 · Windows 盘符 · UNC)、没有 `..` 段
11
11
  * (`/` 与 `\` 都算分隔符 —— `path.isAbsolute` 是语法判,`/a/../../etc` 也「绝对」,而读方 `path.resolve` 会把它解到别处;拒掉它,读到的就是写下的那一条)。
12
12
  *
13
- * posix 口径是有意的:读这些路径的主机车道今天跑 posix 树,而这一律在 posix 宿主上与 Node 的 `path.isAbsolute` 逐字同判(`C:\x`、`\\host\share`
14
- * 在 posix 上不绝对)。哪天主机车道要接 win 树,换的是这一只(按树的家族判),读方跟着同一只走。
13
+ * 宿主是哪一族由壳决定(大脑在云、手在本机:Windows 壳按 CC 同形送 `C:\…`),所以三族绝对形同一只判官、同一条律:
14
+ * posix(`/` 开头)· Windows 盘符(`X:\` / `X:/`;裸 `X:` 与 `X:rel` 不绝对)· UNC(`\\server\share`;`\\server` 不够)。
15
+ * 读方只拿「形合法」这一个事实,怎么解析归宿主那一族 —— 这里不碰文件系统、不做族内归一。
15
16
  */
17
+ const WIN_DRIVE_ABSOLUTE = /^[A-Za-z]:[\\/]/;
18
+ const WIN_UNC_ABSOLUTE = /^\\\\[^\\/?*]+[\\/][^\\/]+/;
16
19
  export function isAbsoluteHostPath(p) {
17
- return typeof p === "string" && p.length > 0 && p.length <= ABSOLUTE_HOST_PATH_MAX && !p.includes("\0") && p.startsWith("/") && !p.split(/[/\\]/).includes("..");
20
+ return (typeof p === "string" && p.length > 0 && p.length <= ABSOLUTE_HOST_PATH_MAX && !p.includes("\0") &&
21
+ (p.startsWith("/") || WIN_DRIVE_ABSOLUTE.test(p) || WIN_UNC_ABSOLUTE.test(p)) &&
22
+ !p.split(/[/\\]/).includes(".."));
18
23
  }
19
24
  /** {@link isAbsoluteHostPath} 的 zod 座位(一条 issue,定句)。 */
20
25
  export const AbsoluteHostPath = z
21
26
  .string()
22
- .refine(isAbsoluteHostPath, buildQuotedIssue `must be an absolute host path: starts with "/", no ".." segment, no NUL, at most ${fixed(String(ABSOLUTE_HOST_PATH_MAX))} characters`);
27
+ .refine(isAbsoluteHostPath, buildQuotedIssue `must be an absolute host path: posix ("/..."), Windows drive ("C:\\..." or "C:/...") or UNC ("\\\\server\\share\\..."), no ".." segment, no NUL, at most ${fixed(String(ABSOLUTE_HOST_PATH_MAX))} characters`);
package/dist/types.d.ts CHANGED
@@ -1841,6 +1841,7 @@ export declare const McpTransport: z.ZodDiscriminatedUnion<[z.ZodObject<{
1841
1841
  url: z.ZodString;
1842
1842
  headerRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1843
1843
  principalHeader: z.ZodOptional<z.ZodString>;
1844
+ assertionHeader: z.ZodOptional<z.ZodString>;
1844
1845
  }, z.core.$strip>], "kind">;
1845
1846
  export type McpTransport = z.infer<typeof McpTransport>;
1846
1847
  /** The closed word table for {@link McpServerSpec}.contentOrigin — a MIRROR literal of the engine's
@@ -1862,6 +1863,7 @@ export declare const McpServerSpec: z.ZodObject<{
1862
1863
  url: z.ZodString;
1863
1864
  headerRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1864
1865
  principalHeader: z.ZodOptional<z.ZodString>;
1866
+ assertionHeader: z.ZodOptional<z.ZodString>;
1865
1867
  }, z.core.$strip>], "kind">;
1866
1868
  allowTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
1867
1869
  scenarios: z.ZodPrefault<z.ZodArray<z.ZodString>>;
@@ -1875,6 +1877,9 @@ export declare const McpServerSpec: z.ZodObject<{
1875
1877
  }>>;
1876
1878
  source: z.ZodOptional<z.ZodUnknown>;
1877
1879
  toolFaces: z.ZodOptional<z.ZodUnknown>;
1880
+ toolAxes: z.ZodOptional<z.ZodUnknown>;
1881
+ authForm: z.ZodOptional<z.ZodUnknown>;
1882
+ entryKind: z.ZodOptional<z.ZodUnknown>;
1878
1883
  notes: z.ZodOptional<z.ZodString>;
1879
1884
  }, z.core.$strip>;
1880
1885
  export type McpServerSpec = z.infer<typeof McpServerSpec>;
@@ -1891,6 +1896,7 @@ export declare const McpConfig: z.ZodObject<{
1891
1896
  url: z.ZodString;
1892
1897
  headerRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1893
1898
  principalHeader: z.ZodOptional<z.ZodString>;
1899
+ assertionHeader: z.ZodOptional<z.ZodString>;
1894
1900
  }, z.core.$strip>], "kind">;
1895
1901
  allowTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
1896
1902
  scenarios: z.ZodPrefault<z.ZodArray<z.ZodString>>;
@@ -1904,6 +1910,9 @@ export declare const McpConfig: z.ZodObject<{
1904
1910
  }>>;
1905
1911
  source: z.ZodOptional<z.ZodUnknown>;
1906
1912
  toolFaces: z.ZodOptional<z.ZodUnknown>;
1913
+ toolAxes: z.ZodOptional<z.ZodUnknown>;
1914
+ authForm: z.ZodOptional<z.ZodUnknown>;
1915
+ entryKind: z.ZodOptional<z.ZodUnknown>;
1907
1916
  notes: z.ZodOptional<z.ZodString>;
1908
1917
  }, z.core.$strip>>>;
1909
1918
  }, z.core.$strip>;
@@ -2439,6 +2448,7 @@ export declare const DOMAIN_SCHEMAS: {
2439
2448
  url: z.ZodString;
2440
2449
  headerRefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
2441
2450
  principalHeader: z.ZodOptional<z.ZodString>;
2451
+ assertionHeader: z.ZodOptional<z.ZodString>;
2442
2452
  }, z.core.$strip>], "kind">;
2443
2453
  allowTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
2444
2454
  scenarios: z.ZodPrefault<z.ZodArray<z.ZodString>>;
@@ -2452,6 +2462,9 @@ export declare const DOMAIN_SCHEMAS: {
2452
2462
  }>>;
2453
2463
  source: z.ZodOptional<z.ZodUnknown>;
2454
2464
  toolFaces: z.ZodOptional<z.ZodUnknown>;
2465
+ toolAxes: z.ZodOptional<z.ZodUnknown>;
2466
+ authForm: z.ZodOptional<z.ZodUnknown>;
2467
+ entryKind: z.ZodOptional<z.ZodUnknown>;
2455
2468
  notes: z.ZodOptional<z.ZodString>;
2456
2469
  }, z.core.$strip>>>;
2457
2470
  }, z.core.$strip>;
package/dist/types.js CHANGED
@@ -418,6 +418,27 @@ export const PARSE_TRANSPARENT_KEYS = [
418
418
  validatedBy: "engine-ingest",
419
419
  why: "按远端工具名 key 的 face 覆盖层,形归引擎摄入侧(不合 schema 的工具不挂并通告一次);本包复述那张表必漂。",
420
420
  },
421
+ {
422
+ domain: "mcp",
423
+ path: "servers[].toolAxes",
424
+ since: "12.2.0",
425
+ validatedBy: "consumer",
426
+ why: "连接器条目声明的按工具轴覆盖层;轴的词表与形归投影它的消费方(server 两腿进 core spec)与写它的连接器,本包只承载,复述那张表必漂。",
427
+ },
428
+ {
429
+ domain: "mcp",
430
+ path: "servers[].authForm",
431
+ since: "12.2.0",
432
+ validatedBy: "consumer",
433
+ why: "连接器条目声明的认证形;词表与语义归读它的消费方(connectors 挂载读 / server 投影),本包只承载、不判语义。",
434
+ },
435
+ {
436
+ domain: "mcp",
437
+ path: "servers[].entryKind",
438
+ since: "12.2.0",
439
+ validatedBy: "consumer",
440
+ why: "连接器条目声明的条目种类;词表与语义归读它的消费方(connectors 挂载读 / server 投影),本包只承载、不判语义。",
441
+ },
421
442
  {
422
443
  domain: "entitlement",
423
444
  path: "subjects[].overrides[].value",
@@ -2346,7 +2367,8 @@ const McpEnvRefs = z.record(ENV_NAME, ENV_NAME); // target ENV key → ENV_NAME
2346
2367
  // (a headerRefs key `sk-live-…`, or principalHeader `ghp_…`) is stored + shipped verbatim on /effective — the
2347
2368
  // SAME invariant-① gap as worker.env / model.extraBody / mcp stdio command+args (credentials belong on the
2348
2369
  // VALUE side = an env-NAME ref, never the name). The token charset includes `%`, so an encoded secret could ride
2349
- // the name — containsSecretToken percent-decodes, catching it too. ONE shared schema for both header-name fields. R19.
2370
+ // the name — containsSecretToken percent-decodes, catching it too. ONE shared schema for every header-name field
2371
+ // (headerRefs keys, principalHeader, assertionHeader). R19.
2350
2372
  const HTTP_HEADER_NAME = z
2351
2373
  .string()
2352
2374
  .regex(/^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/, "must be an HTTP header NAME")
@@ -2384,6 +2406,14 @@ export const McpTransport = z.discriminatedUnion("kind", [
2384
2406
  * this is dynamic — the caller's principal, set per-request by the worker — so it's a header NAME, not an
2385
2407
  * env-NAME ref (no secret). Empty → the worker forwards no principal (server sees an anonymous call). */
2386
2408
  principalHeader: HTTP_HEADER_NAME.optional(),
2409
+ /** 12.2.0 —— Header NAME the SERVICE fills with the CONNECTOR ASSERTION when proxying a tool call to this (hosted connector)
2410
+ * server. Like `principalHeader` it is a header NAME, not an env-NAME ref (no secret), and it answers the same question
2411
+ * — "which header carries the identity on this request" — with a different answer, so the two are MUTUALLY EXCLUSIVE:
2412
+ * the entry-level check on {@link McpServerSpec} rejects both set. The name goes through the same judge
2413
+ * ({@link HTTP_HEADER_NAME}) as `principalHeader` / `headerRefs` keys. This package judges only the SHAPE: how the assertion
2414
+ * is minted and verified is the consumers' (connectors / server). Absent = no assertion header. On a stdio transport the key
2415
+ * is stripped exactly as `principalHeader` is (the stdio member has no such key). */
2416
+ assertionHeader: HTTP_HEADER_NAME.optional(),
2387
2417
  }),
2388
2418
  ]);
2389
2419
  /** The closed word table for {@link McpServerSpec}.contentOrigin — a MIRROR literal of the engine's
@@ -2443,7 +2473,24 @@ export const McpServerSpec = z.object({
2443
2473
  *
2444
2474
  * **解析透明** —— 形归谁校验、为什么不放这里:{@link PARSE_TRANSPARENT_KEYS}(`mcp.servers[].toolFaces`)。 */
2445
2475
  toolFaces: z.unknown().optional(),
2476
+ /** 12.2.0 —— 连接器条目的按工具轴覆盖层声明。缺席 = 不铸键;语义归消费方(server 两腿投影进引擎 spec),本包只承载。
2477
+ *
2478
+ * **解析透明** —— 形归谁校验、为什么不放这里:{@link PARSE_TRANSPARENT_KEYS}(`mcp.servers[].toolAxes`)。 */
2479
+ toolAxes: z.unknown().optional(),
2480
+ /** 12.2.0 —— 连接器条目的认证形声明。缺席 = 不铸键;语义归消费方,本包只承载。
2481
+ *
2482
+ * **解析透明** —— 形归谁校验、为什么不放这里:{@link PARSE_TRANSPARENT_KEYS}(`mcp.servers[].authForm`)。 */
2483
+ authForm: z.unknown().optional(),
2484
+ /** 12.2.0 —— 连接器条目的种类声明。缺席 = 不铸键;语义归消费方,本包只承载。
2485
+ *
2486
+ * **解析透明** —— 形归谁校验、为什么不放这里:{@link PARSE_TRANSPARENT_KEYS}(`mcp.servers[].entryKind`)。 */
2487
+ entryKind: z.unknown().optional(),
2446
2488
  notes: z.string().optional(),
2489
+ }).superRefine((s, ctx) => {
2490
+ // 身份头二选一(12.2.0):`principalHeader` 与 `assertionHeader` 回答同一个问题「这台 http 服务器的请求上用哪个头送身份」—— 同设 = 两个答案。
2491
+ // 互斥只在这一处判(拒句点名条目名,所以住条目层,不住传输层:传输层看不见 `name`)。
2492
+ if (s.transport.kind === "http" && s.transport.principalHeader !== undefined && s.transport.assertionHeader !== undefined)
2493
+ ctx.addIssue({ code: "custom", ...buildQuotedIssue `mcp server "${s.name}" sets both principalHeader and assertionHeader — an http entry names ONE header for the identity it sends: keep principalHeader (the end-user principal) or assertionHeader (the connector assertion), not both`, path: ["transport", "assertionHeader"] });
2447
2494
  });
2448
2495
  export const McpConfig = z
2449
2496
  .object({ servers: z.array(McpServerSpec).prefault([]) })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/settings-schema",
3
- "version": "12.1.0",
3
+ "version": "12.2.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",