@sema-agent/settings-schema 11.1.0 → 11.3.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 +151 -0
- package/README.md +14 -1
- package/bin/settings-schema.mjs +5 -9
- package/conformance/VERSION +1 -1
- package/conformance/cases/c73-projects-extended-registration-reads/expected.json +150 -0
- package/conformance/cases/c73-projects-extended-registration-reads/input.json +42 -0
- package/conformance/cases/c73-projects-extended-registration-reads/meta.json +6 -0
- package/conformance/cases/c74-projects-over-bound-refused/expected.json +89 -0
- package/conformance/cases/c74-projects-over-bound-refused/input.json +29 -0
- package/conformance/cases/c74-projects-over-bound-refused/meta.json +5 -0
- package/conformance/cases/c75-projects-patch-remote-uniqueness/expected.json +89 -0
- package/conformance/cases/c75-projects-patch-remote-uniqueness/input.json +35 -0
- package/conformance/cases/c75-projects-patch-remote-uniqueness/meta.json +5 -0
- package/dist/api/feedback.js +2 -3
- package/dist/api/scopes.js +2 -1
- package/dist/atomic-write.d.ts +7 -1
- package/dist/atomic-write.js +43 -5
- package/dist/cli.d.ts +34 -6
- package/dist/cli.js +80 -130
- package/dist/config-d-file.d.ts +11 -0
- package/dist/config-d-file.js +35 -1
- package/dist/config-dir-io.d.ts +2 -0
- package/dist/config-dir-io.js +14 -0
- package/dist/config-dir-migration.d.ts +67 -0
- package/dist/config-dir-migration.js +181 -0
- package/dist/cross-domain.d.ts +8 -3
- package/dist/cross-domain.js +23 -13
- package/dist/file-edit.js +7 -5
- package/dist/file-store.js +2 -1
- package/dist/fleet.js +3 -4
- package/dist/hooks.d.ts +14 -1
- package/dist/hooks.js +61 -16
- package/dist/host-path.d.ts +17 -0
- package/dist/host-path.js +22 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/integer.js +2 -1
- package/dist/local-load.d.ts +1 -1
- package/dist/local-load.js +9 -31
- package/dist/migration-receipt.d.ts +3 -2
- package/dist/node.d.ts +2 -0
- package/dist/node.js +3 -0
- package/dist/one-time-migrations.d.ts +5 -3
- package/dist/one-time-migrations.js +21 -7
- package/dist/previous-web-admin-env.d.ts +15 -0
- package/dist/previous-web-admin-env.js +20 -0
- package/dist/quoted-issue.d.ts +41 -0
- package/dist/quoted-issue.js +35 -0
- package/dist/remote-exec.d.ts +3 -0
- package/dist/remote-exec.js +12 -7
- package/dist/retired-envs.js +13 -2
- package/dist/retired-form.d.ts +6 -1
- package/dist/retired-form.js +10 -2
- package/dist/rfc3339.d.ts +10 -0
- package/dist/rfc3339.js +12 -0
- package/dist/runtime-lift-targets.d.ts +7 -0
- package/dist/runtime-lift-targets.js +7 -0
- package/dist/shell-quote.d.ts +1 -0
- package/dist/shell-quote.js +14 -0
- package/dist/types.d.ts +140 -20
- package/dist/types.js +224 -114
- package/dist/web-admin-credential.d.ts +2 -2
- package/dist/web-admin-credential.js +5 -10
- package/dist/web-admin-env.d.ts +2 -1
- package/dist/web-admin-env.js +2 -1
- package/dist/web-admin-session-url.d.ts +17 -0
- package/dist/web-admin-session-url.js +64 -0
- package/package.json +1 -1
|
@@ -32,8 +32,8 @@ export declare const WEB_ADMIN_CREDENTIAL_ENVELOPE_KIND: "user-session";
|
|
|
32
32
|
* 文件**取当前值,不用内存旧值(另一个写者可能刚轮换过)。
|
|
33
33
|
* · `expiresAt` —— 访问令牌到期时刻(RFC 3339)。
|
|
34
34
|
* · `issuer` —— 签发它的 web-admin 的**基础 URL**(与读方连 web-admin 的根 URL 同形,可带路径前缀):续签只向同源的 web-admin 发,
|
|
35
|
-
* 同不同源由读方比。URL
|
|
36
|
-
* query / fragment
|
|
35
|
+
* 同不同源由读方比。URL 形判据是包内 URL 判官的「非存量座位」那一只 {@link NON_SECRET_URL_NO_MIGRATION}(http(s)、有 host、userinfo 与
|
|
36
|
+
* query / fragment 里不许夹带凭据;issuer 是 wire 输入、不是存量,一次性迁移不碰它,fragment 拒句因此不指路)—— 本包不另写一份更窄的 URL 律。
|
|
37
37
|
*/
|
|
38
38
|
export declare const WebAdminCredentialEnvelope: z.ZodObject<{
|
|
39
39
|
kind: z.ZodLiteral<"user-session">;
|
|
@@ -22,16 +22,11 @@
|
|
|
22
22
|
import { z } from "zod";
|
|
23
23
|
import { looksLikeJwt } from "./api/auth-bridge.js";
|
|
24
24
|
import { NON_SECRET_URL_NO_MIGRATION } from "./types.js";
|
|
25
|
+
import { buildQuotedIssue } from "./quoted-issue.js";
|
|
26
|
+
import { RFC3339_DATE_TIME } from "./rfc3339.js"; // the package's one RFC 3339 date-time judge (a project registration's `archivedAt` reads the same one)
|
|
25
27
|
import { WEB_ADMIN_ENV } from "./web-admin-env.js";
|
|
26
28
|
/** 信封 `kind` 的闭集今只有一员(`SEALED_BOX_ALG` 同式的字面常量:schema 的字面与读方的比较都引它)。 */
|
|
27
29
|
export const WEB_ADMIN_CREDENTIAL_ENVELOPE_KIND = "user-session";
|
|
28
|
-
/** RFC 3339 `date-time` 的**剖面**:zod 的 `z.iso.datetime({offset:true})` 管日历有效性(月日范围、闰年、时分秒范围),
|
|
29
|
-
* 这里的正则自己判另三处 —— 秒必备、数字偏移必须是 `±hh:mm`、偏移的时 00–23 / 分 00–59(`10:00Z`、`+0800` 与 `+99:99`
|
|
30
|
-
* 都不是 RFC 3339,后者 `Date.parse` 读成 NaN)。这三处的判据在本正则,不随 zod 哪一版收不收而变。大写 `T` / `Z`、不收闰秒 `:60`:读方普遍用
|
|
31
|
-
* `Date.parse` 取时刻,这是那组形里它处处读得准的子集。 */
|
|
32
|
-
const RFC3339_DATE_TIME = z.iso
|
|
33
|
-
.datetime({ offset: true })
|
|
34
|
-
.regex(/T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/, "must be an RFC 3339 date-time: seconds and a Z / ±hh:mm offset (hh 00-23, mm 00-59) are required");
|
|
35
30
|
/** 一枚**令牌串**的形 —— 裸行 bearer、信封里的 `accessToken` / `refreshToken` 共用这**一条**律:可打印 ASCII
|
|
36
31
|
* (0x20–0x7E),首尾是可见字符(0x21–0x7E)、中间可有空格(共享令牌可以是一句口令 —— 验修轮 N2:今天走得通的
|
|
37
32
|
* 这种令牌不许被本律拒掉)。控制字符、制表、非 ASCII、不可见字符一律不是令牌:判别器把它判 `unreadable`,而不是
|
|
@@ -50,13 +45,13 @@ const TokenString = z.string().regex(TOKEN_CHARS, "must be a token: printable AS
|
|
|
50
45
|
* 文件**取当前值,不用内存旧值(另一个写者可能刚轮换过)。
|
|
51
46
|
* · `expiresAt` —— 访问令牌到期时刻(RFC 3339)。
|
|
52
47
|
* · `issuer` —— 签发它的 web-admin 的**基础 URL**(与读方连 web-admin 的根 URL 同形,可带路径前缀):续签只向同源的 web-admin 发,
|
|
53
|
-
* 同不同源由读方比。URL
|
|
54
|
-
* query / fragment
|
|
48
|
+
* 同不同源由读方比。URL 形判据是包内 URL 判官的「非存量座位」那一只 {@link NON_SECRET_URL_NO_MIGRATION}(http(s)、有 host、userinfo 与
|
|
49
|
+
* query / fragment 里不许夹带凭据;issuer 是 wire 输入、不是存量,一次性迁移不碰它,fragment 拒句因此不指路)—— 本包不另写一份更窄的 URL 律。
|
|
55
50
|
*/
|
|
56
51
|
export const WebAdminCredentialEnvelope = z
|
|
57
52
|
.object({
|
|
58
53
|
kind: z.literal(WEB_ADMIN_CREDENTIAL_ENVELOPE_KIND),
|
|
59
|
-
accessToken: TokenString.refine(looksLikeJwt,
|
|
54
|
+
accessToken: TokenString.refine(looksLikeJwt, buildQuotedIssue `must be a JWT (three dot-separated segments) — a worker pull token never goes into an envelope`),
|
|
60
55
|
refreshToken: TokenString,
|
|
61
56
|
expiresAt: RFC3339_DATE_TIME,
|
|
62
57
|
issuer: NON_SECRET_URL_NO_MIGRATION,
|
package/dist/web-admin-env.d.ts
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* · `adminToken` —— 引擎以管理身份写 web-admin 时用的令牌(起服上报执行公钥)。
|
|
18
18
|
*
|
|
19
19
|
* 渲染器给每台 worker 写的三键(`url` / `worker` / `token`)同时是 worker env 的**保留名**(`RESERVED_WORKER_ENV`):运维在 worker 规格的
|
|
20
|
-
* `env`
|
|
20
|
+
* `env` 里写它们,会与渲染器写的值打架。断言令牌的值键 `assertionToken` 也是保留名(由编排器注入);两把凭证的文件键(`tokenFile` / `assertionTokenFile`)同样是保留名:
|
|
21
|
+
* 只给不经编排器的手接引擎、由运维直设,与同一份凭证的值键互斥,规格里写任一个都与注入撞。
|
|
21
22
|
*/
|
|
22
23
|
export declare const WEB_ADMIN_ENV: {
|
|
23
24
|
readonly url: "SEMA_WEB_ADMIN_URL";
|
package/dist/web-admin-env.js
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* · `adminToken` —— 引擎以管理身份写 web-admin 时用的令牌(起服上报执行公钥)。
|
|
18
18
|
*
|
|
19
19
|
* 渲染器给每台 worker 写的三键(`url` / `worker` / `token`)同时是 worker env 的**保留名**(`RESERVED_WORKER_ENV`):运维在 worker 规格的
|
|
20
|
-
* `env`
|
|
20
|
+
* `env` 里写它们,会与渲染器写的值打架。断言令牌的值键 `assertionToken` 也是保留名(由编排器注入);两把凭证的文件键(`tokenFile` / `assertionTokenFile`)同样是保留名:
|
|
21
|
+
* 只给不经编排器的手接引擎、由运维直设,与同一份凭证的值键互斥,规格里写任一个都与注入撞。
|
|
21
22
|
*/
|
|
22
23
|
export const WEB_ADMIN_ENV = {
|
|
23
24
|
url: "SEMA_WEB_ADMIN_URL",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** 一个会话在 web-admin 里的坐标:它在哪台 worker 上、会话 id 是什么。 */
|
|
2
|
+
export interface WebAdminSessionTarget {
|
|
3
|
+
readonly worker: string;
|
|
4
|
+
readonly sessionId: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* 铸一个会话的绝对网页链接。`webBaseUrl` 必须是干净的绝对 http(s) 基址(无 userinfo / query / fragment;可带路径前缀;尾斜杠折掉);
|
|
8
|
+
* `worker` 与 `sessionId` 必填,逐位 `encodeURIComponent`(含 `&` `#` `=` `?` 的 id 不会串位)。坏输入一律抛,不铸半截链接;
|
|
9
|
+
* 含孤立代理项的串(坏 UTF-16)由 `encodeURIComponent` 抛 `URIError`,不静默替换。
|
|
10
|
+
*/
|
|
11
|
+
export declare function webAdminSessionUrl(webBaseUrl: string, target: WebAdminSessionTarget): string;
|
|
12
|
+
/**
|
|
13
|
+
* {@link webAdminSessionUrl} 的配对解析:从一个链接读回 `worker` / `sessionId`。输入可以是绝对 URL 串、相对串(`/chat?…`)、`URL` 或
|
|
14
|
+
* `URLSearchParams`(聊天页读当前地址栏的形)。**宽读**:缺的那一位不出现在结果里(空值等于缺席);重复参数取第一个(同 `searchParams.get`);
|
|
15
|
+
* 路径与别的查询参数不看。串解析不出来(不是 URL)⇒ 抛 `TypeError`,不静默当成「没有参数」。
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseWebAdminSessionUrl(link: string | URL | URLSearchParams): Partial<WebAdminSessionTarget>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* web-admin 里**一个会话的网页链接**:模板函数 {@link webAdminSessionUrl} 与它的配对解析 {@link parseWebAdminSessionUrl} —— 一处定义路由与参数名
|
|
3
|
+
* (纯函数、零 I/O,浏览器安全)。链接形:
|
|
4
|
+
*
|
|
5
|
+
* <webBaseUrl>/chat?agent=<worker>&session=<sessionId>
|
|
6
|
+
*
|
|
7
|
+
* 路由属于 web-admin(聊天页只读 `agent` 与 `session` 两个查询参数);谁要给用户一个会话链接 —— 壳、客户端、服务端文档 —— 调模板函数,不按地址形手拼。
|
|
8
|
+
* 聊天页读写地址栏改读配对解析,于是路径和参数名只有这一份。
|
|
9
|
+
*
|
|
10
|
+
* **两位都必填**:只带 `session` 的链接不够 —— 缺 `agent` 时页面按「URL > 本机记住的 > 第一个在线」挑 worker,再去那一台的会话里找这个 id,
|
|
11
|
+
* 会话不在那一台上就落空。所以模板函数拒绝铸只带一位的链接;解析却**宽读**(旧链接、手输的链接可能缺 `agent`),缺的那一位就是缺席。
|
|
12
|
+
* 链接没有 scope 位(跨空间深链不在这一形里);日后加 scope 时作可选第三位、同一函数,不另开函数。
|
|
13
|
+
*/
|
|
14
|
+
import { httpUrlFlaws, httpUrlRule } from "./url-shape.js";
|
|
15
|
+
/** 链接的路径与两个参数名 —— 本文件私有,唯一一处。 */
|
|
16
|
+
const SESSION_LINK_PATH = "/chat";
|
|
17
|
+
const WORKER_PARAM = "agent";
|
|
18
|
+
const SESSION_PARAM = "session";
|
|
19
|
+
function requiredPart(label, value) {
|
|
20
|
+
if (typeof value !== "string" || value.length === 0)
|
|
21
|
+
throw new TypeError(`webAdminSessionUrl: ${label} is required (a non-empty string) — a session link without it cannot be opened`);
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 铸一个会话的绝对网页链接。`webBaseUrl` 必须是干净的绝对 http(s) 基址(无 userinfo / query / fragment;可带路径前缀;尾斜杠折掉);
|
|
26
|
+
* `worker` 与 `sessionId` 必填,逐位 `encodeURIComponent`(含 `&` `#` `=` `?` 的 id 不会串位)。坏输入一律抛,不铸半截链接;
|
|
27
|
+
* 含孤立代理项的串(坏 UTF-16)由 `encodeURIComponent` 抛 `URIError`,不静默替换。
|
|
28
|
+
*/
|
|
29
|
+
export function webAdminSessionUrl(webBaseUrl, target) {
|
|
30
|
+
if (typeof webBaseUrl !== "string")
|
|
31
|
+
throw new TypeError("webAdminSessionUrl: webBaseUrl must be a string (an absolute http(s) URL)");
|
|
32
|
+
const flaws = httpUrlFlaws(webBaseUrl, ["userinfo", "query", "fragment"]);
|
|
33
|
+
if (flaws.length > 0)
|
|
34
|
+
throw new TypeError(`webAdminSessionUrl: webBaseUrl ${httpUrlRule(flaws[0])}`);
|
|
35
|
+
const worker = requiredPart("worker", target?.worker);
|
|
36
|
+
const sessionId = requiredPart("sessionId", target?.sessionId);
|
|
37
|
+
const base = new URL(webBaseUrl).href.replace(/\/+$/, ""); // 解析后的规范形:没有 query / fragment(上面已判),尾斜杠折掉
|
|
38
|
+
return `${base}${SESSION_LINK_PATH}?${WORKER_PARAM}=${encodeURIComponent(worker)}&${SESSION_PARAM}=${encodeURIComponent(sessionId)}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* {@link webAdminSessionUrl} 的配对解析:从一个链接读回 `worker` / `sessionId`。输入可以是绝对 URL 串、相对串(`/chat?…`)、`URL` 或
|
|
42
|
+
* `URLSearchParams`(聊天页读当前地址栏的形)。**宽读**:缺的那一位不出现在结果里(空值等于缺席);重复参数取第一个(同 `searchParams.get`);
|
|
43
|
+
* 路径与别的查询参数不看。串解析不出来(不是 URL)⇒ 抛 `TypeError`,不静默当成「没有参数」。
|
|
44
|
+
*/
|
|
45
|
+
export function parseWebAdminSessionUrl(link) {
|
|
46
|
+
let params;
|
|
47
|
+
if (link instanceof URLSearchParams)
|
|
48
|
+
params = link;
|
|
49
|
+
else if (link instanceof URL)
|
|
50
|
+
params = link.searchParams;
|
|
51
|
+
else {
|
|
52
|
+
if (typeof link !== "string" || !URL.canParse(link, "http://relative.invalid"))
|
|
53
|
+
throw new TypeError("parseWebAdminSessionUrl: link is not a URL (pass an absolute URL, a relative `/chat?…` string, a URL or URLSearchParams)");
|
|
54
|
+
params = new URL(link, "http://relative.invalid").searchParams;
|
|
55
|
+
}
|
|
56
|
+
const out = {};
|
|
57
|
+
const worker = params.get(WORKER_PARAM);
|
|
58
|
+
const sessionId = params.get(SESSION_PARAM);
|
|
59
|
+
if (worker !== null && worker !== "")
|
|
60
|
+
out.worker = worker;
|
|
61
|
+
if (sessionId !== null && sessionId !== "")
|
|
62
|
+
out.sessionId = sessionId;
|
|
63
|
+
return out;
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/settings-schema",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.3.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",
|