@sema-agent/settings-schema 11.2.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 +58 -0
- package/README.md +2 -1
- 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 +6 -0
- package/dist/atomic-write.js +12 -4
- package/dist/cli.d.ts +7 -4
- package/dist/cli.js +52 -10
- package/dist/config-d-file.d.ts +11 -0
- package/dist/config-d-file.js +35 -1
- package/dist/config-dir-io.js +4 -3
- package/dist/config-dir-migration.d.ts +5 -2
- package/dist/config-dir-migration.js +23 -9
- 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/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 +1 -1
- package/dist/one-time-migrations.d.ts +5 -3
- package/dist/one-time-migrations.js +19 -6
- 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/rfc3339.d.ts +10 -0
- package/dist/rfc3339.js +12 -0
- package/dist/types.d.ts +140 -20
- package/dist/types.js +194 -105
- package/dist/web-admin-credential.d.ts +2 -2
- package/dist/web-admin-credential.js +5 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,64 @@
|
|
|
6
6
|
> `@sema-agent/registry-core`(更早还曾是 `@sema-ai/registry-core`)。本档 `0.19.0` 以下各节里的
|
|
7
7
|
> 包名是**历史记录**,如实保留不追改。
|
|
8
8
|
|
|
9
|
+
## 11.3.0 — 2026-10-11 — 六件 additive:运行期成员表三张(AUTONOMY_MODES / COMMAND_DECISIONS / PROMPT_SLOTS)· 项目登记扩形(goal / contextItems / archivedAt / icon / color,displayName 上界 200)+ PATCH 形 · 命令行环境错一臂(I/O 错 rc 2 一句点名路径)· 一次性迁移 SS-M7 走到 remote-exec.json · 每条自铸 custom issue 带结构化句子(QuotedIssueParams)· hookMatcherForm(minor:新导出主桶 19 / hooks 2 / remote-exec 1 / node 1 型,零删零改名)
|
|
10
|
+
|
|
11
|
+
> 本节六件,全部 additive(零删导出、零改名;minor):运行期成员表三张 · 项目登记扩形 + PATCH 形 · 命令行环境错一臂 · 一次性迁移 SS-M7 走到 `remote-exec.json` ·
|
|
12
|
+
> 每条自铸 custom issue 一律带结构化句子 · `hookMatcherForm`。新导出:主桶 19 个(其中 16 个也在 `./types`)、`./hooks` 2 个、`./remote-exec` 1 个、`./node` 1 个型。
|
|
13
|
+
> 消费方:server 7.125.0 提货(读点见各条);web-admin 的 projects 编辑面跟扩形。
|
|
14
|
+
|
|
15
|
+
### 新导出:运行期成员表 `AUTONOMY_MODES` / `COMMAND_DECISIONS` / `PROMPT_SLOTS`
|
|
16
|
+
|
|
17
|
+
与 `REF_CHECKED_DOMAINS` 同形:`as const` 只读数组是正本,zod enum(`AutonomyMode` / `CommandDecision` / `PromptSlot`)与类型都从表派生 ——
|
|
18
|
+
`governance.autonomy`、`commandPolicy[].decision`、提示声明与 catalog 的 `slot` 引用的就是这几只 enum(同词同序,判法不变)。
|
|
19
|
+
- **谁要改**:server 今天经 `GovernanceConfig.shape.autonomy.unwrap().options` / `….commandPolicy.unwrap().element.shape.decision.options` 取词表,提示域校验手抄一份三词槽位表 —— 换成 import 这三张表。
|
|
20
|
+
|
|
21
|
+
### 新导出:项目登记 additive 扩形 —— `goal` / `contextItems` / `archivedAt` / `icon` / `color`,`displayName` 上界 120 → 200;PATCH 形
|
|
22
|
+
|
|
23
|
+
`ProjectRegistration` 原六键不改名,加五个可选键:`goal`(≤ 2000)、`contextItems`(≤ 64 条,`{ kind: "folder" | "file" | "note", value }`;folder / file 的值过
|
|
24
|
+
**与任务 `cwd` 同一只**主机路径形判官 `isAbsoluteHostPath` —— 非空、≤ 4096、无 NUL、以 `/` 开头、无 `..` 段;note ≤ 4000)、`archivedAt`(RFC 3339 时刻,与凭证信封
|
|
25
|
+
`expiresAt` 同一只判)、`icon`(`^[a-z][a-z0-9-]{0,63}$`)、`color`(`^#[0-9a-f]{6}$`)。`displayName` 上界放宽到 200(放宽 = 旧数据全部照读)。
|
|
26
|
+
上界常量导出:`PROJECT_LIMITS`、`ABSOLUTE_HOST_PATH_MAX`、`PROJECT_ICON_REGEX`、`PROJECT_COLOR_REGEX`、`PROJECT_CONTEXT_ITEM_KINDS` —— 读方 import,不手抄数字。
|
|
27
|
+
PATCH 形 `ProjectRegistrationPatch`(strict:`registeredBy` / `registeredAt` 与未知键拒;可选键给 `null` = 清掉,如 `archivedAt: null` 取消归档)+ `applyProjectPatch(doc, id, patch)`:
|
|
28
|
+
它先自己按 PATCH 形判入参(调用方原样递进请求体也改不了 `registeredBy` / `registeredAt`、带不进未知键;失败的坐标是文档坐标 `projects.<id>.…`),
|
|
29
|
+
合并后由**同一只** `ProjectsConfig`(同一个 remote 全局唯一判)整文档再判,被改的项目排在最后判 —— 冲突恒落在被改的项目上、句子点名已占用的项目;成功时保持原键序;
|
|
30
|
+
没登记的 id ⇒ 抛(调用方先答「没有这个项目」)。一致性语料 +3(合法扩形 / 超界拒 / PATCH 形 remote 唯一)。
|
|
31
|
+
- **谁要改**:server 的项目读写面读新键与这些常量、PATCH 走 `applyProjectPatch`;server 受理任务 `cwd` 的形判改调 `isAbsoluteHostPath`(同一条律,posix 宿主上与现判逐字同);
|
|
32
|
+
web-admin 的 projects 编辑面渲染 / 写新键,`displayName` 输入上界跟到 200。
|
|
33
|
+
|
|
34
|
+
### 行为修复:命令行退出码闭集补「环境错」一臂(rc 2)
|
|
35
|
+
|
|
36
|
+
`migrate` 写回阶段的 I/O 错(写盘 / 删文件:权限、磁盘、悬空符号链接……)以前原样抛出 —— Node 打裸栈、进程 rc 1,而 rc 1 是 `outcome=refused`(拒迁)的约定码,
|
|
37
|
+
只看 rc 的脚本会把权限错读成「拒绝迁移」。现在并入 rc 2(与读目录 / 读文件错同一臂):stdout 空,stderr **一行**点名要写的那份文件与原错误句(含 errno 码),不打栈;
|
|
38
|
+
之前已写完的文档留在新形上,修好再跑一次幂等收尾。函数形 `migrateConfigDirectory` 的契约不变(写回阶段的 I/O 错仍原样抛给调用方)。
|
|
39
|
+
读阶段遇**悬空符号链接**(域文件或 `config.d` 目录本身):读口先过原子写器同一只链接判法,句子与写器**同一句**(以前读阶段先撞 ENOENT,句子不提链接)。
|
|
40
|
+
写器那一句的措辞随之改成读写通用(去掉 `writeFileAtomic:` 前缀;判法与抛不抛都不变)。
|
|
41
|
+
|
|
42
|
+
### 行为变:一次性迁移 SS-M7(URL fragment)走到 `config.d/remote-exec.json`
|
|
43
|
+
|
|
44
|
+
`remote-exec.json` 的两个端点(k8s `apiUrl`、`s3Snapshot.endpoint`)与域文档里的 URL 座位改为同一只带迁移指路的判官:规则句不变,fragment 拒句尾多一句 SS-M7 指路;
|
|
45
|
+
座位仍由 schema 派生(`urlSeatPatterns()` 多两行)。命令行 `migrate` 把 `remote-exec.json` 当又一份文档:读(文本判与 `loadRemoteExec` 同一只)、剥 fragment、
|
|
46
|
+
改过的整文档终判、写回(与 `writeRemoteExec` 同一只原子写器、同一种文本形)。收据的 `document` 闭集多一个 `remote-exec`;文档名的唯一拼写导出为 `REMOTE_EXEC_DOCUMENT`;
|
|
47
|
+
`migrateConfigDirectory` 的覆盖面可含它(`./node` 的型 `ConfigDirectoryDocument`)。凭证信封的 `issuer` 是 wire 输入、不是存量,不走迁移,拒句照旧不指路。
|
|
48
|
+
11.0.0 起披露的「`remote-exec.json` 里带 `#` 的端点只能手改」就此收口。
|
|
49
|
+
- **行为变(命令行)**:目录里只有 `remote-exec.json`(外加非文档条目)时,以前报「没有域文档」rc 2,现在读到了文档、零改动 ⇒ `noop` rc 0;
|
|
50
|
+
`remote-exec.json` 是空 / 坏 JSON 时,以前命令行不读它,现在与其它文档一样 ⇒ 读不进 rc 2(这样的文件引擎读侧本就拒)。
|
|
51
|
+
- **谁要改**:server 起服的本地目录迁移若要一并迁 `remote-exec.json`,把它加进覆盖面(读回面本就读它);不加则照旧只由命令行迁。
|
|
52
|
+
|
|
53
|
+
### 新契约:本包自铸的每一条 custom issue 都带结构化句子 `QuotedIssueParams`
|
|
54
|
+
|
|
55
|
+
全包只剩一只铸点:每条 `code: "custom"` 的 issue(`.refine` / `z.custom` / `addIssue` / 合成 issue / 引用完整性 `RefIssue`)都带 `params.template` + `params.operands`
|
|
56
|
+
(值位是洞),`message` 由 `renderQuotedSentence` 从它渲出、铸点不手写第二遍;没有值的定句 `operands` 为空。句子逐字不变。URL 形判官的 issue 的 `params` 是
|
|
57
|
+
`{ template, operands, flaw }`(`flaw` = 判官的规则词,保留);`RefIssue` 加 `params`,`renderRefIssue` 经同一只渲染器。不在此列的(如实):zod 内建码的 issue ——
|
|
58
|
+
`.max(n, 句)` / `.regex(re, 句)`、墓碑字段的 `invalid_type`、联合的错误映射 —— 它们的句子是定句、读 `message`。
|
|
59
|
+
- **谁要改**:server 读 issue 句子的那一处对 custom issue 可以只读 `params`(不再退回 `message`);zod 内建码的 issue 照旧读 `message`。
|
|
60
|
+
|
|
61
|
+
### 新导出:`hookMatcherForm(matcher)` —— `"literal" | "regex" | "invalid"`
|
|
62
|
+
|
|
63
|
+
与 `hookMatcherSelects` 调**同一只解析步**(不另写判形):缺席 / `""` / `"*"`(选中一切)与名字表形 = `literal`(不编、不跑正则),其余编得出的 = `regex`(不锚定),
|
|
64
|
+
编不出 = `invalid`;对任一 matcher,`hookMatcherForm === "invalid"` ⇔ `hookMatcherSelects(…) === "invalid"`。给要在求值前分流的调用方(字面形直接跑、正则形进有预算的求值)。
|
|
65
|
+
- **谁要改**:server 的 hooks 执行器今天自带一只「无回溯形」判断(字符扫描)决定要不要进预算求值,改问这一只后删掉自带的。
|
|
66
|
+
|
|
9
67
|
## 11.2.0 — 2026-10-10 — 六小件:SEMA_REGISTRY_* 八名加回退役墓碑(换名窗期与保留表交集写明)· 断言令牌 / 凭证文件键进保留表 · 会话网页链接模板函数与配对解析 · CLI 命令路径 shell 引用 · 原子写器保留符号链接 · node 侧目录迁移函数导出(minor:新导出与新墓碑行,零删零改名)
|
|
10
68
|
|
|
11
69
|
> 本节六件:上一代连接名 `SEMA_REGISTRY_*` 八名进墓碑表(硬破坏,读侧同代要求)· 断言令牌两键进保留 env 名表 · 会话网页链接模板函数与配对解析 · 命令行印出的命令路径加 shell 引用 ·
|
package/README.md
CHANGED
|
@@ -300,7 +300,8 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
|
|
|
300
300
|
`WebAdminCredentialEnvelope` (strict JSON: `kind: "user-session"` = `WEB_ADMIN_CREDENTIAL_ENVELOPE_KIND`, a JWT
|
|
301
301
|
`accessToken` and a `refreshToken` under the same token law as the bare line, RFC 3339
|
|
302
302
|
`expiresAt` with seconds and a `Z` / `±hh:mm` offset in range, `issuer` = the issuing web-admin's base URL judged
|
|
303
|
-
by the
|
|
303
|
+
by the URL shape judge for seats no one-time migration reaches (`NON_SECRET_URL_NO_MIGRATION` — the issuer is a wire input, not stored
|
|
304
|
+
data) — same-origin is the reader's comparison).
|
|
304
305
|
`parseWebAdminCredentialFile(text)` is the ONE discrimination law — trimmed text starting with `{` is read ONLY
|
|
305
306
|
as an envelope (a failure is `unreadable`, never a fallback to a bare line); anything else is a bare line,
|
|
306
307
|
and a first line that is not a token is `unreadable` too (never sent as a bearer); empty is `unreadable`. The `reason` names envelope fields / zod issue codes / an unknown-key COUNT, never file
|
package/conformance/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
11.
|
|
1
|
+
11.3.0
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
{
|
|
2
|
+
"domains": {
|
|
3
|
+
"outcome": "effective",
|
|
4
|
+
"effective": {
|
|
5
|
+
"collab": {
|
|
6
|
+
"templates": []
|
|
7
|
+
},
|
|
8
|
+
"entitlement": {
|
|
9
|
+
"budgetGroups": [],
|
|
10
|
+
"groupBindings": [],
|
|
11
|
+
"subjects": [],
|
|
12
|
+
"tiers": []
|
|
13
|
+
},
|
|
14
|
+
"execution": {
|
|
15
|
+
"allowedLanes": [
|
|
16
|
+
"host"
|
|
17
|
+
],
|
|
18
|
+
"required": false
|
|
19
|
+
},
|
|
20
|
+
"governance": {},
|
|
21
|
+
"hosts": {
|
|
22
|
+
"hosts": []
|
|
23
|
+
},
|
|
24
|
+
"limits": {},
|
|
25
|
+
"mcp": {
|
|
26
|
+
"servers": []
|
|
27
|
+
},
|
|
28
|
+
"models": {
|
|
29
|
+
"atMention": {
|
|
30
|
+
"mode": "all"
|
|
31
|
+
},
|
|
32
|
+
"models": [],
|
|
33
|
+
"roles": {},
|
|
34
|
+
"tierGroups": []
|
|
35
|
+
},
|
|
36
|
+
"plugins": {
|
|
37
|
+
"plugins": []
|
|
38
|
+
},
|
|
39
|
+
"projects": {
|
|
40
|
+
"projects": {
|
|
41
|
+
"01890a5d-ac96-774b-bcce-b302099a8057": {
|
|
42
|
+
"archivedAt": "2026-10-11T08:00:00.000Z",
|
|
43
|
+
"color": "#1f6feb",
|
|
44
|
+
"contextItems": [
|
|
45
|
+
{
|
|
46
|
+
"kind": "folder",
|
|
47
|
+
"value": "/home/alice/webapp"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"kind": "file",
|
|
51
|
+
"value": "/home/alice/webapp/README.md"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"kind": "note",
|
|
55
|
+
"value": "release gates first"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"defaultScopes": [
|
|
59
|
+
"proj"
|
|
60
|
+
],
|
|
61
|
+
"displayName": "pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp",
|
|
62
|
+
"gitRemotes": [
|
|
63
|
+
"example.com/acme/webapp"
|
|
64
|
+
],
|
|
65
|
+
"goal": "ship the project object",
|
|
66
|
+
"icon": "rocket",
|
|
67
|
+
"notes": "free notes",
|
|
68
|
+
"registeredAt": "2026-10-01T00:00:00.000Z",
|
|
69
|
+
"registeredBy": "alice"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"prompts": {
|
|
74
|
+
"bindings": []
|
|
75
|
+
},
|
|
76
|
+
"rosters": {
|
|
77
|
+
"rosters": []
|
|
78
|
+
},
|
|
79
|
+
"scenarios": {
|
|
80
|
+
"scenarios": []
|
|
81
|
+
},
|
|
82
|
+
"skills": {
|
|
83
|
+
"skills": []
|
|
84
|
+
},
|
|
85
|
+
"systems": {
|
|
86
|
+
"systems": []
|
|
87
|
+
},
|
|
88
|
+
"workers": {
|
|
89
|
+
"workers": []
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"warnings": [],
|
|
93
|
+
"metadata": {
|
|
94
|
+
"version": 17,
|
|
95
|
+
"updatedAt": "2026-10-12T00:00:00.000Z"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"strictWrite": {
|
|
99
|
+
"outcome": "effective",
|
|
100
|
+
"effective": {
|
|
101
|
+
"projects": {
|
|
102
|
+
"projects": {
|
|
103
|
+
"01890a5d-ac96-774b-bcce-b302099a8057": {
|
|
104
|
+
"archivedAt": "2026-10-11T08:00:00.000Z",
|
|
105
|
+
"color": "#1f6feb",
|
|
106
|
+
"contextItems": [
|
|
107
|
+
{
|
|
108
|
+
"kind": "folder",
|
|
109
|
+
"value": "/home/alice/webapp"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"kind": "file",
|
|
113
|
+
"value": "/home/alice/webapp/README.md"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"kind": "note",
|
|
117
|
+
"value": "release gates first"
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"defaultScopes": [
|
|
121
|
+
"proj"
|
|
122
|
+
],
|
|
123
|
+
"displayName": "pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp",
|
|
124
|
+
"gitRemotes": [
|
|
125
|
+
"example.com/acme/webapp"
|
|
126
|
+
],
|
|
127
|
+
"goal": "ship the project object",
|
|
128
|
+
"icon": "rocket",
|
|
129
|
+
"notes": "free notes",
|
|
130
|
+
"registeredAt": "2026-10-01T00:00:00.000Z",
|
|
131
|
+
"registeredBy": "alice"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"warnings": [],
|
|
137
|
+
"metadata": {
|
|
138
|
+
"version": 17,
|
|
139
|
+
"updatedAt": "2026-10-12T00:00:00.000Z"
|
|
140
|
+
},
|
|
141
|
+
"why": "受理:扩形五键与放宽后的 displayName 上界都是本版契约的合法形,严写腿与读腿同答。"
|
|
142
|
+
},
|
|
143
|
+
"wire": {
|
|
144
|
+
"derive": true
|
|
145
|
+
},
|
|
146
|
+
"localRoot": {
|
|
147
|
+
"derive": true,
|
|
148
|
+
"localVersion": 2617555914511015
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 17,
|
|
4
|
+
"updatedAt": "2026-10-12T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"projects": {
|
|
8
|
+
"projects": {
|
|
9
|
+
"01890a5d-ac96-774b-bcce-b302099a8057": {
|
|
10
|
+
"gitRemotes": [
|
|
11
|
+
"example.com/acme/webapp"
|
|
12
|
+
],
|
|
13
|
+
"defaultScopes": [
|
|
14
|
+
"proj"
|
|
15
|
+
],
|
|
16
|
+
"registeredBy": "alice",
|
|
17
|
+
"registeredAt": "2026-10-01T00:00:00.000Z",
|
|
18
|
+
"displayName": "pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp",
|
|
19
|
+
"notes": "free notes",
|
|
20
|
+
"goal": "ship the project object",
|
|
21
|
+
"contextItems": [
|
|
22
|
+
{
|
|
23
|
+
"kind": "folder",
|
|
24
|
+
"value": "/home/alice/webapp"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"kind": "file",
|
|
28
|
+
"value": "/home/alice/webapp/README.md"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"kind": "note",
|
|
32
|
+
"value": "release gates first"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"archivedAt": "2026-10-11T08:00:00.000Z",
|
|
36
|
+
"icon": "rocket",
|
|
37
|
+
"color": "#1f6feb"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contributor": "contract",
|
|
3
|
+
"claim": "项目登记的 additive 扩形:原六键之外带 goal / contextItems(folder / file / note)/ archivedAt / icon / color,displayName 150 字(上界 120 → 200 放宽之后才合法)。读腿与严写腿都原样收、零告警。打的是「读方按旧形把新键剥掉」或「仍按 120 的旧上界拒」两种读法分歧(11.2.0 及更早:150 字的 displayName 整域拒)。",
|
|
4
|
+
"firstRedOn": [],
|
|
5
|
+
"note": "firstRedOn 为空:historical 阶梯(≤ 2.1.0)不覆盖 11.3.0 的新键;对 11.2.0 这一条会红(displayName 150 > 120),那一版不在入库的真跑证据里。"
|
|
6
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"domains": {
|
|
3
|
+
"outcome": "rejected",
|
|
4
|
+
"stage": "validate"
|
|
5
|
+
},
|
|
6
|
+
"strictWrite": {
|
|
7
|
+
"outcome": "rejected",
|
|
8
|
+
"stage": "validate",
|
|
9
|
+
"why": "拒:displayName 超过 200、folder 不是主机绝对路径 —— 与读腿同一只 schema。"
|
|
10
|
+
},
|
|
11
|
+
"wire": {
|
|
12
|
+
"outcome": "rejected",
|
|
13
|
+
"stage": "validate",
|
|
14
|
+
"why": "domains 腿是拒绝态,不派生;wire 腿把同一份文档交给同一个 buildEffective,拒绝层相同"
|
|
15
|
+
},
|
|
16
|
+
"localRoot": {
|
|
17
|
+
"outcome": "effective",
|
|
18
|
+
"effective": {
|
|
19
|
+
"collab": {
|
|
20
|
+
"templates": []
|
|
21
|
+
},
|
|
22
|
+
"entitlement": {
|
|
23
|
+
"budgetGroups": [],
|
|
24
|
+
"groupBindings": [],
|
|
25
|
+
"subjects": [],
|
|
26
|
+
"tiers": []
|
|
27
|
+
},
|
|
28
|
+
"execution": {
|
|
29
|
+
"allowedLanes": [
|
|
30
|
+
"host"
|
|
31
|
+
],
|
|
32
|
+
"required": false
|
|
33
|
+
},
|
|
34
|
+
"governance": {},
|
|
35
|
+
"hosts": {
|
|
36
|
+
"hosts": []
|
|
37
|
+
},
|
|
38
|
+
"limits": {},
|
|
39
|
+
"mcp": {
|
|
40
|
+
"servers": []
|
|
41
|
+
},
|
|
42
|
+
"models": {
|
|
43
|
+
"atMention": {
|
|
44
|
+
"mode": "all"
|
|
45
|
+
},
|
|
46
|
+
"models": [],
|
|
47
|
+
"roles": {},
|
|
48
|
+
"tierGroups": []
|
|
49
|
+
},
|
|
50
|
+
"plugins": {
|
|
51
|
+
"plugins": []
|
|
52
|
+
},
|
|
53
|
+
"projects": {
|
|
54
|
+
"projects": {}
|
|
55
|
+
},
|
|
56
|
+
"prompts": {
|
|
57
|
+
"bindings": []
|
|
58
|
+
},
|
|
59
|
+
"rosters": {
|
|
60
|
+
"rosters": []
|
|
61
|
+
},
|
|
62
|
+
"scenarios": {
|
|
63
|
+
"scenarios": []
|
|
64
|
+
},
|
|
65
|
+
"skills": {
|
|
66
|
+
"skills": []
|
|
67
|
+
},
|
|
68
|
+
"systems": {
|
|
69
|
+
"systems": []
|
|
70
|
+
},
|
|
71
|
+
"workers": {
|
|
72
|
+
"workers": []
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"warnings": [
|
|
76
|
+
{
|
|
77
|
+
"domain": "projects",
|
|
78
|
+
"file": "projects.json",
|
|
79
|
+
"kind": "unread-config-file",
|
|
80
|
+
"why": "non-portable-domain"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"metadata": {
|
|
84
|
+
"version": 2617555914511015,
|
|
85
|
+
"updatedAt": "1970-01-01T00:00:00.000Z"
|
|
86
|
+
},
|
|
87
|
+
"why": "projects 不是便携域:config.d 腿不读它(T3),文件报 unread-config-file、域取默认 —— 本地读腿看不见这份坏登记"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 17,
|
|
4
|
+
"updatedAt": "2026-10-12T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"projects": {
|
|
8
|
+
"projects": {
|
|
9
|
+
"01890a5d-ac96-774b-bcce-b302099a8057": {
|
|
10
|
+
"gitRemotes": [
|
|
11
|
+
"example.com/acme/webapp"
|
|
12
|
+
],
|
|
13
|
+
"defaultScopes": [
|
|
14
|
+
"proj"
|
|
15
|
+
],
|
|
16
|
+
"registeredBy": "alice",
|
|
17
|
+
"registeredAt": "2026-10-01T00:00:00.000Z",
|
|
18
|
+
"displayName": "ppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp",
|
|
19
|
+
"contextItems": [
|
|
20
|
+
{
|
|
21
|
+
"kind": "folder",
|
|
22
|
+
"value": "relative/dir"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"domains": {
|
|
3
|
+
"outcome": "rejected",
|
|
4
|
+
"stage": "validate"
|
|
5
|
+
},
|
|
6
|
+
"strictWrite": {
|
|
7
|
+
"outcome": "rejected",
|
|
8
|
+
"stage": "validate",
|
|
9
|
+
"why": "拒:example.com/acme/shared 已登记给前一个项目;坐标 projects.<后来者>.gitRemotes[1]。"
|
|
10
|
+
},
|
|
11
|
+
"wire": {
|
|
12
|
+
"outcome": "rejected",
|
|
13
|
+
"stage": "validate",
|
|
14
|
+
"why": "domains 腿是拒绝态,不派生;wire 腿把同一份文档交给同一个 buildEffective,拒绝层相同"
|
|
15
|
+
},
|
|
16
|
+
"localRoot": {
|
|
17
|
+
"outcome": "effective",
|
|
18
|
+
"effective": {
|
|
19
|
+
"collab": {
|
|
20
|
+
"templates": []
|
|
21
|
+
},
|
|
22
|
+
"entitlement": {
|
|
23
|
+
"budgetGroups": [],
|
|
24
|
+
"groupBindings": [],
|
|
25
|
+
"subjects": [],
|
|
26
|
+
"tiers": []
|
|
27
|
+
},
|
|
28
|
+
"execution": {
|
|
29
|
+
"allowedLanes": [
|
|
30
|
+
"host"
|
|
31
|
+
],
|
|
32
|
+
"required": false
|
|
33
|
+
},
|
|
34
|
+
"governance": {},
|
|
35
|
+
"hosts": {
|
|
36
|
+
"hosts": []
|
|
37
|
+
},
|
|
38
|
+
"limits": {},
|
|
39
|
+
"mcp": {
|
|
40
|
+
"servers": []
|
|
41
|
+
},
|
|
42
|
+
"models": {
|
|
43
|
+
"atMention": {
|
|
44
|
+
"mode": "all"
|
|
45
|
+
},
|
|
46
|
+
"models": [],
|
|
47
|
+
"roles": {},
|
|
48
|
+
"tierGroups": []
|
|
49
|
+
},
|
|
50
|
+
"plugins": {
|
|
51
|
+
"plugins": []
|
|
52
|
+
},
|
|
53
|
+
"projects": {
|
|
54
|
+
"projects": {}
|
|
55
|
+
},
|
|
56
|
+
"prompts": {
|
|
57
|
+
"bindings": []
|
|
58
|
+
},
|
|
59
|
+
"rosters": {
|
|
60
|
+
"rosters": []
|
|
61
|
+
},
|
|
62
|
+
"scenarios": {
|
|
63
|
+
"scenarios": []
|
|
64
|
+
},
|
|
65
|
+
"skills": {
|
|
66
|
+
"skills": []
|
|
67
|
+
},
|
|
68
|
+
"systems": {
|
|
69
|
+
"systems": []
|
|
70
|
+
},
|
|
71
|
+
"workers": {
|
|
72
|
+
"workers": []
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"warnings": [
|
|
76
|
+
{
|
|
77
|
+
"domain": "projects",
|
|
78
|
+
"file": "projects.json",
|
|
79
|
+
"kind": "unread-config-file",
|
|
80
|
+
"why": "non-portable-domain"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"metadata": {
|
|
84
|
+
"version": 2617555914511015,
|
|
85
|
+
"updatedAt": "1970-01-01T00:00:00.000Z"
|
|
86
|
+
},
|
|
87
|
+
"why": "projects 不是便携域:config.d 腿不读它(T3),文件报 unread-config-file、域取默认"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 17,
|
|
4
|
+
"updatedAt": "2026-10-12T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"projects": {
|
|
8
|
+
"projects": {
|
|
9
|
+
"01890a5d-ac96-774b-bcce-b302099a8057": {
|
|
10
|
+
"gitRemotes": [
|
|
11
|
+
"example.com/acme/shared"
|
|
12
|
+
],
|
|
13
|
+
"defaultScopes": [
|
|
14
|
+
"proj"
|
|
15
|
+
],
|
|
16
|
+
"registeredBy": "alice",
|
|
17
|
+
"registeredAt": "2026-10-01T00:00:00.000Z",
|
|
18
|
+
"displayName": "holder"
|
|
19
|
+
},
|
|
20
|
+
"9b2ee1f0-3f9a-4c1d-8b7e-2a54ff00c9d3": {
|
|
21
|
+
"gitRemotes": [
|
|
22
|
+
"example.com/acme/own",
|
|
23
|
+
"example.com/acme/shared"
|
|
24
|
+
],
|
|
25
|
+
"defaultScopes": [
|
|
26
|
+
"proj"
|
|
27
|
+
],
|
|
28
|
+
"registeredBy": "alice",
|
|
29
|
+
"registeredAt": "2026-10-01T00:00:00.000Z",
|
|
30
|
+
"displayName": "patched"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
package/dist/api/feedback.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
import { INTEGER } from "../integer.js";
|
|
16
|
+
import { buildQuotedIssue, fixed } from "../quoted-issue.js";
|
|
16
17
|
/** 报告的端点,相对 web-admin 根。 */
|
|
17
18
|
export const FEEDBACK_V1_PATH = "/api/v1/feedback";
|
|
18
19
|
/** `description`(去首尾空白后)的上限 —— 报告常带粘贴的报错与栈,所以宽,但有界。 */
|
|
@@ -36,9 +37,7 @@ export const FeedbackSubmitRequest = z.object({
|
|
|
36
37
|
/** 客户端自报的时刻(参考,不信任 —— 回体的 `createdAt` 由服务端盖)。 */
|
|
37
38
|
datetime: z.string(),
|
|
38
39
|
latestAssistantMessageId: z.string().nullable().optional(),
|
|
39
|
-
transcript: z.array(z.unknown()).refine((t) => JSON.stringify(t).length <= FEEDBACK_TRANSCRIPT_MAX_JSON_CHARS, {
|
|
40
|
-
message: `transcript must serialize to at most ${FEEDBACK_TRANSCRIPT_MAX_JSON_CHARS} characters`,
|
|
41
|
-
}),
|
|
40
|
+
transcript: z.array(z.unknown()).refine((t) => JSON.stringify(t).length <= FEEDBACK_TRANSCRIPT_MAX_JSON_CHARS, buildQuotedIssue `transcript must serialize to at most ${fixed(String(FEEDBACK_TRANSCRIPT_MAX_JSON_CHARS))} characters`),
|
|
42
41
|
errors: z.array(FeedbackError).optional(),
|
|
43
42
|
lastApiRequest: z.unknown().optional(),
|
|
44
43
|
subagentTranscripts: z.record(z.string(), z.unknown()).optional(),
|
package/dist/api/scopes.js
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
*/
|
|
46
46
|
import { z } from "zod";
|
|
47
47
|
import { INTEGER } from "../integer.js";
|
|
48
|
+
import { buildQuotedIssue, fixed } from "../quoted-issue.js";
|
|
48
49
|
import { USER_ROLES } from "../config-fns.js";
|
|
49
50
|
import { ACCESS_TOKEN_TTL_SECONDS } from "./auth.js";
|
|
50
51
|
// ── constants ────────────────────────────────────────────────────────────────────────────────────────────
|
|
@@ -137,7 +138,7 @@ export const SCOPE_SWITCH_TOKEN_TTL_SECONDS = ACCESS_TOKEN_TTL_SECONDS;
|
|
|
137
138
|
/** Reserved ids ("global") are rejected AT THE SCHEMA — the default scope pre-exists and is not creatable. */
|
|
138
139
|
export const ScopeCreateRequest = z
|
|
139
140
|
.object({
|
|
140
|
-
id: ScopeId.refine((id) => !isReservedScopeId(id),
|
|
141
|
+
id: ScopeId.refine((id) => !isReservedScopeId(id), buildQuotedIssue `"${fixed(GLOBAL_SCOPE)}" is reserved`),
|
|
141
142
|
name: z.string().min(1).max(200),
|
|
142
143
|
})
|
|
143
144
|
.passthrough();
|
package/dist/atomic-write.d.ts
CHANGED
|
@@ -10,5 +10,11 @@ export declare const ATOMIC_FILE_CLASSES: {
|
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
12
|
export type AtomicFileClass = keyof typeof ATOMIC_FILE_CLASSES;
|
|
13
|
+
/** 悬空符号链接的**唯一一句**(写器与目录迁移的读口抛同一句;不带 errno 码 —— 带了 `ENOENT` 的错会被「ENOENT = 缺席」的读者读成文件不在,
|
|
14
|
+
* 悬空链接恰恰不是缺席)。 */
|
|
15
|
+
export declare function danglingSymlinkSentence(link: string, pointsAt: string): string;
|
|
16
|
+
/** 读写的真目标 —— **一只判法**(写器与目录迁移的读口共用):`target` 是符号链接 ⇒ 解析到它指向的真文件(悬空 ⇒ 抛 {@link danglingSymlinkSentence});
|
|
17
|
+
* 不是链接或不存在 ⇒ 原样(不存在的由调用方的读 / 写照常报)。 */
|
|
18
|
+
export declare function resolveSymlinkTarget(target: string): string;
|
|
13
19
|
/** 原子写 `text`(UTF-8)到 `target`(符号链接则写到它指向的真文件,见文件头);模式按 `kind` 在 {@link ATOMIC_FILE_CLASSES} 里的行。父目录须已存在。 */
|
|
14
20
|
export declare function writeFileAtomic(target: string, text: string, kind: AtomicFileClass): void;
|
package/dist/atomic-write.js
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* 临时文件建在真文件所在目录、rename 到真文件**:链接(及链上每一环)原样保留,真文件的内容更新,模式规则作用在真文件上。临时文件与目标同目录 ⇒ rename 不会跨文件系统;
|
|
18
18
|
* 真文件所在目录写不进、或 rename 因别的原因失败 ⇒ 响亮抛,**绝不**回退成「在链接位置写一个普通文件」(那是静默换形)。路径本身是悬空链接 ⇒ 响亮抛
|
|
19
19
|
* (不在链接位置建普通文件,也不替链接建它指向的文件);成环的链接由 `realpath` 抛 `ELOOP`。目标不存在 ⇒ 新建(没有链接可言;经符号链接的目录写新文件时,文件落在真目录里)。
|
|
20
|
+
* 「链接 ⇒ 真文件、悬空 ⇒ 响亮抛」这一只判法是 {@link resolveSymlinkTarget}:目录迁移的读口(`./config-dir-io`)读目录 / 读文件前也问它,
|
|
21
|
+
* 悬空链接在读阶段与写阶段是**同一句**({@link danglingSymlinkSentence})。
|
|
20
22
|
*/
|
|
21
23
|
import { randomBytes } from "node:crypto";
|
|
22
24
|
import { chmodSync, lstatSync, readlinkSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
@@ -26,8 +28,14 @@ export const ATOMIC_FILE_CLASSES = {
|
|
|
26
28
|
"config-document": { newMode: 0o644, existing: "keep" },
|
|
27
29
|
"scheduler-store": { newMode: 0o600, existing: "reset" },
|
|
28
30
|
};
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
+
/** 悬空符号链接的**唯一一句**(写器与目录迁移的读口抛同一句;不带 errno 码 —— 带了 `ENOENT` 的错会被「ENOENT = 缺席」的读者读成文件不在,
|
|
32
|
+
* 悬空链接恰恰不是缺席)。 */
|
|
33
|
+
export function danglingSymlinkSentence(link, pointsAt) {
|
|
34
|
+
return `${link} is a dangling symbolic link (it points at ${pointsAt}, which does not exist) — nothing is read or written through it; repair or remove the link`;
|
|
35
|
+
}
|
|
36
|
+
/** 读写的真目标 —— **一只判法**(写器与目录迁移的读口共用):`target` 是符号链接 ⇒ 解析到它指向的真文件(悬空 ⇒ 抛 {@link danglingSymlinkSentence});
|
|
37
|
+
* 不是链接或不存在 ⇒ 原样(不存在的由调用方的读 / 写照常报)。 */
|
|
38
|
+
export function resolveSymlinkTarget(target) {
|
|
31
39
|
let link;
|
|
32
40
|
try {
|
|
33
41
|
link = lstatSync(target).isSymbolicLink();
|
|
@@ -44,14 +52,14 @@ function resolveWriteTarget(target) {
|
|
|
44
52
|
}
|
|
45
53
|
catch (e) {
|
|
46
54
|
if (e.code === "ENOENT") {
|
|
47
|
-
throw new Error(
|
|
55
|
+
throw new Error(danglingSymlinkSentence(target, readlinkSync(target)), { cause: e });
|
|
48
56
|
}
|
|
49
57
|
throw e;
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
/** 原子写 `text`(UTF-8)到 `target`(符号链接则写到它指向的真文件,见文件头);模式按 `kind` 在 {@link ATOMIC_FILE_CLASSES} 里的行。父目录须已存在。 */
|
|
53
61
|
export function writeFileAtomic(target, text, kind) {
|
|
54
|
-
const real =
|
|
62
|
+
const real = resolveSymlinkTarget(target);
|
|
55
63
|
const spec = ATOMIC_FILE_CLASSES[kind];
|
|
56
64
|
let kept; // the existing file's mode, when this class keeps it
|
|
57
65
|
switch (spec.existing) {
|