@sema-agent/settings-schema 6.4.0 → 7.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 (95) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/README.md +34 -2
  3. package/bin/settings-schema.mjs +22 -0
  4. package/conformance/VERSION +1 -1
  5. package/conformance/cases/c50-s784-lane-host-legal/expected.json +102 -0
  6. package/conformance/cases/c50-s784-lane-host-legal/input.json +29 -0
  7. package/conformance/cases/c50-s784-lane-host-legal/meta.json +5 -0
  8. package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +104 -0
  9. package/conformance/cases/c51-s784-lane-e2b-legal/input.json +32 -0
  10. package/conformance/cases/c51-s784-lane-e2b-legal/meta.json +5 -0
  11. package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +106 -0
  12. package/conformance/cases/c52-s784-lane-k8s-legal/input.json +34 -0
  13. package/conformance/cases/c52-s784-lane-k8s-legal/meta.json +5 -0
  14. package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +106 -0
  15. package/conformance/cases/c53-s784-lane-ssh-legal/input.json +34 -0
  16. package/conformance/cases/c53-s784-lane-ssh-legal/meta.json +5 -0
  17. package/conformance/cases/c54-s784-lane-adb-legal/expected.json +102 -0
  18. package/conformance/cases/c54-s784-lane-adb-legal/input.json +29 -0
  19. package/conformance/cases/c54-s784-lane-adb-legal/meta.json +5 -0
  20. package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +103 -0
  21. package/conformance/cases/c55-s784-lane-local-docker-legal/input.json +30 -0
  22. package/conformance/cases/c55-s784-lane-local-docker-legal/meta.json +5 -0
  23. package/conformance/cases/c56-s784-lane-device-legal/expected.json +109 -0
  24. package/conformance/cases/c56-s784-lane-device-legal/input.json +36 -0
  25. package/conformance/cases/c56-s784-lane-device-legal/meta.json +5 -0
  26. package/conformance/cases/c57-s784-g1-enabled-no-lane/expected.json +83 -0
  27. package/conformance/cases/c57-s784-g1-enabled-no-lane/input.json +23 -0
  28. package/conformance/cases/c57-s784-g1-enabled-no-lane/meta.json +5 -0
  29. package/conformance/cases/c58-s784-g2-multitenant-host/expected.json +83 -0
  30. package/conformance/cases/c58-s784-g2-multitenant-host/input.json +34 -0
  31. package/conformance/cases/c58-s784-g2-multitenant-host/meta.json +5 -0
  32. package/conformance/cases/c59-s784-g3-k8s-missing-image/expected.json +83 -0
  33. package/conformance/cases/c59-s784-g3-k8s-missing-image/input.json +26 -0
  34. package/conformance/cases/c59-s784-g3-k8s-missing-image/meta.json +5 -0
  35. package/conformance/cases/c60-s784-g3-e2b-missing-key/expected.json +83 -0
  36. package/conformance/cases/c60-s784-g3-e2b-missing-key/input.json +26 -0
  37. package/conformance/cases/c60-s784-g3-e2b-missing-key/meta.json +5 -0
  38. package/conformance/cases/c61-s784-g3-other-lane-key/expected.json +83 -0
  39. package/conformance/cases/c61-s784-g3-other-lane-key/input.json +30 -0
  40. package/conformance/cases/c61-s784-g3-other-lane-key/meta.json +5 -0
  41. package/conformance/cases/c62-s784-g7a-session-tidb/expected.json +83 -0
  42. package/conformance/cases/c62-s784-g7a-session-tidb/input.json +27 -0
  43. package/conformance/cases/c62-s784-g7a-session-tidb/meta.json +5 -0
  44. package/conformance/cases/c63-s784-host-two-replicas/expected.json +83 -0
  45. package/conformance/cases/c63-s784-host-two-replicas/input.json +27 -0
  46. package/conformance/cases/c63-s784-host-two-replicas/meta.json +5 -0
  47. package/conformance/cases/c64-s784-multitenant-local-store/expected.json +83 -0
  48. package/conformance/cases/c64-s784-multitenant-local-store/input.json +30 -0
  49. package/conformance/cases/c64-s784-multitenant-local-store/meta.json +5 -0
  50. package/conformance/cases/c65-s784-pg-without-db/expected.json +83 -0
  51. package/conformance/cases/c65-s784-pg-without-db/input.json +27 -0
  52. package/conformance/cases/c65-s784-pg-without-db/meta.json +5 -0
  53. package/conformance/cases/c66-s784-memory-backend-mismatch/expected.json +83 -0
  54. package/conformance/cases/c66-s784-memory-backend-mismatch/input.json +36 -0
  55. package/conformance/cases/c66-s784-memory-backend-mismatch/meta.json +5 -0
  56. package/conformance/cases/c67-s784-retired-field-loud/expected.json +83 -0
  57. package/conformance/cases/c67-s784-retired-field-loud/input.json +22 -0
  58. package/conformance/cases/c67-s784-retired-field-loud/meta.json +5 -0
  59. package/conformance/cases/c68-s784-device-local-store/expected.json +83 -0
  60. package/conformance/cases/c68-s784-device-local-store/input.json +26 -0
  61. package/conformance/cases/c68-s784-device-local-store/meta.json +5 -0
  62. package/conformance/cases/cli04-env-value-with-newline/expected.json +13 -2
  63. package/conformance/cases/cli04-env-value-with-newline/input.json +8 -1
  64. package/conformance/cases/cli04-env-value-with-newline/meta.json +1 -1
  65. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/expected.json +49 -0
  66. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/input.json +26 -0
  67. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/meta.json +4 -0
  68. package/conformance/migrate-workers/m02-g5-idempotent/expected.json +38 -0
  69. package/conformance/migrate-workers/m02-g5-idempotent/input.json +33 -0
  70. package/conformance/migrate-workers/m02-g5-idempotent/meta.json +5 -0
  71. package/conformance/migrate-workers/m03-g5-refused-no-lane/expected.json +71 -0
  72. package/conformance/migrate-workers/m03-g5-refused-no-lane/input.json +42 -0
  73. package/conformance/migrate-workers/m03-g5-refused-no-lane/meta.json +4 -0
  74. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/expected.json +52 -0
  75. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/input.json +30 -0
  76. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/meta.json +4 -0
  77. package/dist/cli.d.ts +8 -0
  78. package/dist/cli.js +70 -0
  79. package/dist/execution-lane-index.d.ts +19 -0
  80. package/dist/execution-lane-index.js +23 -0
  81. package/dist/execution-lanes.d.ts +64 -0
  82. package/dist/execution-lanes.js +152 -0
  83. package/dist/file-edit.js +26 -21
  84. package/dist/hooks.d.ts +4 -4
  85. package/dist/index.d.ts +2 -0
  86. package/dist/index.js +2 -0
  87. package/dist/migrate-workers.d.ts +63 -0
  88. package/dist/migrate-workers.js +331 -0
  89. package/dist/remote-exec.d.ts +23 -64
  90. package/dist/remote-exec.js +20 -71
  91. package/dist/secret-refs.d.ts +7 -1
  92. package/dist/secret-refs.js +9 -3
  93. package/dist/types.d.ts +1356 -455
  94. package/dist/types.js +258 -63
  95. package/package.json +9 -1
@@ -0,0 +1,64 @@
1
+ /**
2
+ * 执行车道 + 存储后端的**词表正本**(7.0.0,M-R2 WorkerSpec 结构块)。纯数据常量,零函数、零依赖(叶模块:
3
+ * 本文件不 import 任何东西,`types.ts` 反过来引它)。
4
+ *
5
+ * ## 为什么在这里
6
+ * 车道词、每条车道读哪些 env、哪条车道分租户、存储后端词 —— 这几张表以前在四处各抄一份(引擎的能力表、
7
+ * 部署面的车道清单、中心表单、本包 `RemoteExecSpec`),任何一处改了别处都不红。从本版起**只有这一份**:
8
+ * · 中心写闸 = `WorkerSpec.safeParse`(本包 schema 读这张表判 `runtime.execution` / `runtime.store`);
9
+ * · 中心渲染器按这张表把结构块渲成 env(唯一写者);
10
+ * · 引擎提货时从这张表派生自己的车道词表 / 必需键表 / 租户分离位(引擎只留运行期事实,按导入联合类型穷举);
11
+ * · 部署面车道清单由这张表生成。
12
+ * 写闸与起服读同一张表 ⇒ 不会分叉。
13
+ *
14
+ * ## 行内容的出处(逐行抄自引擎真码,坐标 = server 7.112.0 树)
15
+ * · 车道词与次序:`src/execution-lane-caps.ts` `EXECUTION_LANE_WORDS`(:335)去掉 `in-process` =
16
+ * `REMOTE_EXEC_PROVIDER_WORDS`(:366)。次序照抄,于是引擎改派生之后,拒启句里的 `valid:` 列表与出路列表逐字不变。
17
+ * · `tenantSeparation`:同文件 `executionLaneCaps` 每臂的 `tenantSeparation` 位(:209 host / :230 e2b / :249 k8s /
18
+ * :269 ssh / :288 adb / :308 local-docker / :327 device)。
19
+ * · `requiredEnv ∪ requiredSecretEnv`:`src/config.ts` `REQUIRED_ENVS_BY_LANE`(:1054)逐字;按 `src/config-catalog.ts`
20
+ * 该键那一行的值类型分栏 —— 类型 `secret` / `opaque`(目录自己「绝不回显值」的两类)进 `*SecretEnv`,其余进 `*Env`。
21
+ * · `optionalEnv ∪ optionalSecretEnv`:`src/config.ts` `parseOrchestrationDomain` 的 `REMOTE_EXEC` 三元链里**该车道那一臂**
22
+ * 读的 env 名(:3925 e2b / :3957 k8s / :3991 ssh / :4006 adb / :4014 host / :4026 local-docker / :4055 device;
23
+ * 臂内调用的解析器 `parseSshHostKeyEnv` :1521、`parseDevicePreAuthPerRemoteEnv` :871、`parseDeviceEnrollTokenTtlEnv` :857
24
+ * 读的名也算),去掉必需键,同样按目录值类型分栏。**不收**别的域也读的名:k8s 臂里的 `MINIO_ENDPOINT` /
25
+ * `MINIO_ACCESS_KEY` / `MINIO_SECRET_KEY` / `MINIO_REGION` 同时是存储域对象存储的键(`src/config.ts` :1848 / :1872),
26
+ * 收进车道栏会把它们保留成「k8s 专属」,别的车道就再也设不了快照对象存储。也**不收**臂外的适配器调参键
27
+ * (`HOST_BG_*` / `E2B_BG_*` / `K8S_BG_*` / `HOST_SHELL_PATH` …):它们不是车道坐标,照旧走 `env` 逃生口。
28
+ *
29
+ * ## 不在表里的词
30
+ * · `in-process`:引擎内部「没有 remoteExec」这个状态的名字,不是可声明的车道 —— 显式「无手」的 worker 在模型要用工具时
31
+ * 仍回 completed + 零工具,就是那个病换了个合法名字。要无手 worker 先另立设计、定用户面行为再给词。
32
+ * · `remote-docker`:引擎有一只没接线的适配器工厂,但没有任何读点能把这个词变成一条在跑的车道
33
+ * (`REMOTE_EXEC=remote-docker` 起服即拒;远端 docker 守护进程今天的真形 = `local-docker` + `DOCKER_HOST`)。
34
+ */
35
+ /** 可声明的执行车道闭集(= 引擎 `REMOTE_EXEC` 收的词,逐字同序)。 */
36
+ export declare const EXECUTION_LANE_WORDS: readonly ["host", "e2b", "k8s", "ssh", "adb", "local-docker", "device"];
37
+ export type ExecutionLane = (typeof EXECUTION_LANE_WORDS)[number];
38
+ /** 车道分不分租户(引擎能力表的 `tenantSeparation` 位,两档,没有「不表态」)。
39
+ * `supported` = 每个租户的命令落在各自的目标上;`single-user-only` = 所有任务落同一个共享目标 ⇒ 只许单用户 worker。 */
40
+ export declare const TENANT_SEPARATION_WORDS: readonly ["supported", "single-user-only"];
41
+ export type TenantSeparation = (typeof TENANT_SEPARATION_WORDS)[number];
42
+ /** 一条车道的表行。四栏 env 名两两不交、跨车道也不交(`test/execution-lanes-7.0.0.test.ts` 钉)。
43
+ * - `requiredEnv` / `optionalEnv`:非密坐标 —— 写在 `runtime.execution.coords`(字面值);
44
+ * - `requiredSecretEnv` / `optionalSecretEnv`:密钥 —— 写在 `runtime.execution.secretRefs`(服务变量名 → 宿主 env-NAME,绝不写值)。 */
45
+ export interface ExecutionLaneRow {
46
+ readonly lane: ExecutionLane;
47
+ readonly tenantSeparation: TenantSeparation;
48
+ readonly requiredEnv: readonly string[];
49
+ readonly requiredSecretEnv: readonly string[];
50
+ readonly optionalEnv: readonly string[];
51
+ readonly optionalSecretEnv: readonly string[];
52
+ }
53
+ /** 车道表(次序 = {@link EXECUTION_LANE_WORDS})。整张表深冻结 —— 它是唯一正本,消费方拿到的不许被改。 */
54
+ export declare const EXECUTION_LANES: readonly ExecutionLaneRow[];
55
+ /** 存储后端(→ `DB_BACKEND`)。= server `src/config-types.ts` `DB_BACKEND_WORDS`(:67)逐字同序。 */
56
+ export declare const STORE_BACKENDS: readonly ["mysql", "pg", "local", "memory"];
57
+ export type StoreBackend = (typeof STORE_BACKENDS)[number];
58
+ /** session 店(→ `SESSION_BACKEND`)。= server `src/config.ts` :1760 `enumEnv("SESSION_BACKEND", …)` 的词表逐字同序
59
+ * (`tidb` 不在集内:引擎见之拒启)。 */
60
+ export declare const SESSION_BACKENDS: readonly ["memory", "mysql", "auto"];
61
+ export type SessionBackend = (typeof SESSION_BACKENDS)[number];
62
+ /** 记忆持久面方言(→ `MEMORY_ENGINE_BACKEND`)。= server `src/config.ts` :3436 闭集 / 目录 :468 `enumValues` 逐字同序。 */
63
+ export declare const MEMORY_ENGINE_BACKENDS: readonly ["file", "pg", "tidb"];
64
+ export type MemoryEngineBackend = (typeof MEMORY_ENGINE_BACKENDS)[number];
@@ -0,0 +1,152 @@
1
+ /**
2
+ * 执行车道 + 存储后端的**词表正本**(7.0.0,M-R2 WorkerSpec 结构块)。纯数据常量,零函数、零依赖(叶模块:
3
+ * 本文件不 import 任何东西,`types.ts` 反过来引它)。
4
+ *
5
+ * ## 为什么在这里
6
+ * 车道词、每条车道读哪些 env、哪条车道分租户、存储后端词 —— 这几张表以前在四处各抄一份(引擎的能力表、
7
+ * 部署面的车道清单、中心表单、本包 `RemoteExecSpec`),任何一处改了别处都不红。从本版起**只有这一份**:
8
+ * · 中心写闸 = `WorkerSpec.safeParse`(本包 schema 读这张表判 `runtime.execution` / `runtime.store`);
9
+ * · 中心渲染器按这张表把结构块渲成 env(唯一写者);
10
+ * · 引擎提货时从这张表派生自己的车道词表 / 必需键表 / 租户分离位(引擎只留运行期事实,按导入联合类型穷举);
11
+ * · 部署面车道清单由这张表生成。
12
+ * 写闸与起服读同一张表 ⇒ 不会分叉。
13
+ *
14
+ * ## 行内容的出处(逐行抄自引擎真码,坐标 = server 7.112.0 树)
15
+ * · 车道词与次序:`src/execution-lane-caps.ts` `EXECUTION_LANE_WORDS`(:335)去掉 `in-process` =
16
+ * `REMOTE_EXEC_PROVIDER_WORDS`(:366)。次序照抄,于是引擎改派生之后,拒启句里的 `valid:` 列表与出路列表逐字不变。
17
+ * · `tenantSeparation`:同文件 `executionLaneCaps` 每臂的 `tenantSeparation` 位(:209 host / :230 e2b / :249 k8s /
18
+ * :269 ssh / :288 adb / :308 local-docker / :327 device)。
19
+ * · `requiredEnv ∪ requiredSecretEnv`:`src/config.ts` `REQUIRED_ENVS_BY_LANE`(:1054)逐字;按 `src/config-catalog.ts`
20
+ * 该键那一行的值类型分栏 —— 类型 `secret` / `opaque`(目录自己「绝不回显值」的两类)进 `*SecretEnv`,其余进 `*Env`。
21
+ * · `optionalEnv ∪ optionalSecretEnv`:`src/config.ts` `parseOrchestrationDomain` 的 `REMOTE_EXEC` 三元链里**该车道那一臂**
22
+ * 读的 env 名(:3925 e2b / :3957 k8s / :3991 ssh / :4006 adb / :4014 host / :4026 local-docker / :4055 device;
23
+ * 臂内调用的解析器 `parseSshHostKeyEnv` :1521、`parseDevicePreAuthPerRemoteEnv` :871、`parseDeviceEnrollTokenTtlEnv` :857
24
+ * 读的名也算),去掉必需键,同样按目录值类型分栏。**不收**别的域也读的名:k8s 臂里的 `MINIO_ENDPOINT` /
25
+ * `MINIO_ACCESS_KEY` / `MINIO_SECRET_KEY` / `MINIO_REGION` 同时是存储域对象存储的键(`src/config.ts` :1848 / :1872),
26
+ * 收进车道栏会把它们保留成「k8s 专属」,别的车道就再也设不了快照对象存储。也**不收**臂外的适配器调参键
27
+ * (`HOST_BG_*` / `E2B_BG_*` / `K8S_BG_*` / `HOST_SHELL_PATH` …):它们不是车道坐标,照旧走 `env` 逃生口。
28
+ *
29
+ * ## 不在表里的词
30
+ * · `in-process`:引擎内部「没有 remoteExec」这个状态的名字,不是可声明的车道 —— 显式「无手」的 worker 在模型要用工具时
31
+ * 仍回 completed + 零工具,就是那个病换了个合法名字。要无手 worker 先另立设计、定用户面行为再给词。
32
+ * · `remote-docker`:引擎有一只没接线的适配器工厂,但没有任何读点能把这个词变成一条在跑的车道
33
+ * (`REMOTE_EXEC=remote-docker` 起服即拒;远端 docker 守护进程今天的真形 = `local-docker` + `DOCKER_HOST`)。
34
+ */
35
+ /** 可声明的执行车道闭集(= 引擎 `REMOTE_EXEC` 收的词,逐字同序)。 */
36
+ export const EXECUTION_LANE_WORDS = ["host", "e2b", "k8s", "ssh", "adb", "local-docker", "device"];
37
+ /** 车道分不分租户(引擎能力表的 `tenantSeparation` 位,两档,没有「不表态」)。
38
+ * `supported` = 每个租户的命令落在各自的目标上;`single-user-only` = 所有任务落同一个共享目标 ⇒ 只许单用户 worker。 */
39
+ export const TENANT_SEPARATION_WORDS = ["supported", "single-user-only"];
40
+ /** 逐车道一行。`satisfies Record<ExecutionLane, …>` = 词表加词而这里不加行 ⇒ 编译红。 */
41
+ const LANE_ROWS = {
42
+ /** server `config.ts` :4014 臂(无必需键);`execution-lane-caps.ts` :209 `single-user-only`(所有任务落 worker 宿主)。 */
43
+ host: {
44
+ tenantSeparation: "single-user-only",
45
+ requiredEnv: [],
46
+ requiredSecretEnv: [],
47
+ optionalEnv: ["HOST_WORKSPACE_BASE", "HOST_COMMAND_TIMEOUT_MS"],
48
+ optionalSecretEnv: [],
49
+ },
50
+ /** server `config.ts` :3925 臂;`E2B_API_KEY` 目录 :351 类型 `secret`、`E2B_SANDBOX_ENV` :359 类型 `secret`;
51
+ * `execution-lane-caps.ts` :230 `supported`(每任务一只 microVM)。 */
52
+ e2b: {
53
+ tenantSeparation: "supported",
54
+ requiredEnv: [],
55
+ requiredSecretEnv: ["E2B_API_KEY"],
56
+ optionalEnv: ["E2B_TEMPLATE", "E2B_TIMEOUT_MS", "E2B_LIVENESS_MS", "E2B_ALLOW_NET", "E2B_MOUNT_PATH", "E2B_ORPHAN_RECLAIM"],
57
+ optionalSecretEnv: ["E2B_SANDBOX_ENV"],
58
+ },
59
+ /** server `config.ts` :3957 臂;`K8S_TOKEN` 目录 :412 类型 `secret`、`K8S_CA_CERT_B64` :403 类型 `opaque`;
60
+ * `execution-lane-caps.ts` :249 `supported`(每任务一只 pod)。`MINIO_*` 刻意不收(见文件头)。 */
61
+ k8s: {
62
+ tenantSeparation: "supported",
63
+ requiredEnv: ["K8S_SANDBOX_IMAGE"],
64
+ requiredSecretEnv: [],
65
+ optionalEnv: [
66
+ "K8S_API_URL",
67
+ "K8S_INSECURE_TLS",
68
+ "K8S_NAMESPACE",
69
+ "K8S_RUNTIME_CLASS",
70
+ "K8S_MOUNT_PATH",
71
+ "K8S_TIMEOUT_MS",
72
+ "K8S_MEMORY",
73
+ "K8S_CPU",
74
+ "WORKSPACE_SNAPSHOT_BUCKET",
75
+ "WORKSPACE_SNAPSHOT_PREFIX",
76
+ "WORKSPACE_SNAPSHOT_TTL_SEC",
77
+ ],
78
+ optionalSecretEnv: ["K8S_TOKEN", "K8S_CA_CERT_B64"],
79
+ },
80
+ /** server `config.ts` :3991 臂 + `parseSshHostKeyEnv` :1521;`SSH_PRIVATE_KEY` 目录 :687 类型 `secret`;
81
+ * `execution-lane-caps.ts` :269 `single-user-only`(一台跨任务共享的常驻真机)。 */
82
+ ssh: {
83
+ tenantSeparation: "single-user-only",
84
+ requiredEnv: ["SSH_HOST", "SSH_USER"],
85
+ requiredSecretEnv: ["SSH_PRIVATE_KEY"],
86
+ optionalEnv: ["SSH_PORT", "SSH_MOUNT_PATH", "SSH_HOST_FINGERPRINT", "SSH_KNOWN_HOSTS"],
87
+ optionalSecretEnv: [],
88
+ },
89
+ /** server `config.ts` :4006 臂;`execution-lane-caps.ts` :288 `single-user-only`(一台跨任务共享的设备)。 */
90
+ adb: {
91
+ tenantSeparation: "single-user-only",
92
+ requiredEnv: ["ADB_SERIAL"],
93
+ requiredSecretEnv: [],
94
+ optionalEnv: ["ADB_PATH", "ADB_MOUNT_PATH"],
95
+ optionalSecretEnv: [],
96
+ },
97
+ /** server `config.ts` :4026 臂;`DOCKER_SANDBOX_ENV` 目录 :345 类型 `secret`;`execution-lane-caps.ts` :308 `supported`
98
+ * (每任务一只容器)。`DOCKER_HOST` 在本行:远端 docker 守护进程 = 本车道 + `coords.DOCKER_HOST`。 */
99
+ "local-docker": {
100
+ tenantSeparation: "supported",
101
+ requiredEnv: ["DOCKER_IMAGE"],
102
+ requiredSecretEnv: [],
103
+ optionalEnv: [
104
+ "DOCKER_MOUNT_PATH",
105
+ "DOCKER_PATH",
106
+ "DOCKER_HOST",
107
+ "DOCKER_MEMORY",
108
+ "DOCKER_CPUS",
109
+ "DOCKER_PIDS_LIMIT",
110
+ "DOCKER_DROP_CAPS",
111
+ "DOCKER_NETWORK",
112
+ "DOCKER_COMMAND_TIMEOUT_MS",
113
+ ],
114
+ optionalSecretEnv: ["DOCKER_SANDBOX_ENV"],
115
+ },
116
+ /** server `config.ts` :4055 臂 + `parseDevicePreAuthPerRemoteEnv` :871 / `parseDeviceEnrollTokenTtlEnv` :857(无必需键:设备是运行期
117
+ * 连进来的);`execution-lane-caps.ts` :327 `supported`(发起者自己的设备)。 */
118
+ device: {
119
+ tenantSeparation: "supported",
120
+ requiredEnv: [],
121
+ requiredSecretEnv: [],
122
+ optionalEnv: [
123
+ "DEVICE_DELIVERY_TIMEOUT_MS",
124
+ "DEVICE_RECONNECT_GRACE_MS",
125
+ "DEVICE_EXEC_TIMEOUT_MS",
126
+ "DEVICE_MAX_INFLIGHT_PER_DEVICE",
127
+ "DEVICE_MAX_PREAUTH_PER_REMOTE",
128
+ "DEVICE_ENROLL_TOKEN_TTL_SEC",
129
+ "DEVICE_SUPERSEDE",
130
+ ],
131
+ optionalSecretEnv: [],
132
+ },
133
+ };
134
+ /** 车道表(次序 = {@link EXECUTION_LANE_WORDS})。整张表深冻结 —— 它是唯一正本,消费方拿到的不许被改。 */
135
+ export const EXECUTION_LANES = Object.freeze(EXECUTION_LANE_WORDS.map((lane) => {
136
+ const row = LANE_ROWS[lane];
137
+ return Object.freeze({
138
+ lane,
139
+ tenantSeparation: row.tenantSeparation,
140
+ requiredEnv: Object.freeze([...row.requiredEnv]),
141
+ requiredSecretEnv: Object.freeze([...row.requiredSecretEnv]),
142
+ optionalEnv: Object.freeze([...row.optionalEnv]),
143
+ optionalSecretEnv: Object.freeze([...row.optionalSecretEnv]),
144
+ });
145
+ }));
146
+ /** 存储后端(→ `DB_BACKEND`)。= server `src/config-types.ts` `DB_BACKEND_WORDS`(:67)逐字同序。 */
147
+ export const STORE_BACKENDS = ["mysql", "pg", "local", "memory"];
148
+ /** session 店(→ `SESSION_BACKEND`)。= server `src/config.ts` :1760 `enumEnv("SESSION_BACKEND", …)` 的词表逐字同序
149
+ * (`tidb` 不在集内:引擎见之拒启)。 */
150
+ export const SESSION_BACKENDS = ["memory", "mysql", "auto"];
151
+ /** 记忆持久面方言(→ `MEMORY_ENGINE_BACKEND`)。= server `src/config.ts` :3436 闭集 / 目录 :468 `enumValues` 逐字同序。 */
152
+ export const MEMORY_ENGINE_BACKENDS = ["file", "pg", "tidb"];
package/dist/file-edit.js CHANGED
@@ -95,29 +95,34 @@ export function listRequiredEnvNames(eff, remoteExec, resolvedEnv) {
95
95
  add(r.envName, use.domain, use.detail);
96
96
  if (remoteExec) {
97
97
  const re = remoteExec;
98
- if (re.provider === "e2b") {
99
- add(re.apiKeyEnv, "remoteExec", "e2b.apiKeyEnv");
100
- for (const e of re.sandboxEnv ?? [])
101
- add(e, "remoteExec", "e2b.sandboxEnv[]");
102
- }
103
- else if (re.provider === "k8s") {
104
- add(re.tokenEnv, "remoteExec", "k8s.tokenEnv");
105
- add(re.caCertEnv, "remoteExec", "k8s.caCertEnv");
106
- if (re.s3Snapshot) {
107
- add(re.s3Snapshot.accessKeyEnv, "remoteExec", "k8s.s3Snapshot.accessKeyEnv");
108
- add(re.s3Snapshot.secretKeyEnv, "remoteExec", "k8s.s3Snapshot.secretKeyEnv");
98
+ // Exhaustive over the provider words (7.0.0: ⊆ EXECUTION_LANE_WORDS) — a new provider that carries an env-NAME
99
+ // ref must say so here, or this switch is a compile error (no silent "carries nothing" default).
100
+ switch (re.provider) {
101
+ case "e2b":
102
+ add(re.apiKeyEnv, "remoteExec", "e2b.apiKeyEnv");
103
+ for (const e of re.sandboxEnv ?? [])
104
+ add(e, "remoteExec", "e2b.sandboxEnv[]");
105
+ break;
106
+ case "k8s":
107
+ add(re.tokenEnv, "remoteExec", "k8s.tokenEnv");
108
+ add(re.caCertEnv, "remoteExec", "k8s.caCertEnv");
109
+ if (re.s3Snapshot) {
110
+ add(re.s3Snapshot.accessKeyEnv, "remoteExec", "k8s.s3Snapshot.accessKeyEnv");
111
+ add(re.s3Snapshot.secretKeyEnv, "remoteExec", "k8s.s3Snapshot.secretKeyEnv");
112
+ }
113
+ break;
114
+ case "ssh":
115
+ add(re.privateKeyEnv, "remoteExec", "ssh.privateKeyEnv");
116
+ break;
117
+ case "adb":
118
+ case "host":
119
+ case "local-docker":
120
+ break; // these carry no secret env-NAME refs
121
+ default: {
122
+ const unhandled = re;
123
+ throw new Error(`listRequiredEnvNames: unhandled remoteExec provider ${JSON.stringify(unhandled)}`);
109
124
  }
110
125
  }
111
- else if (re.provider === "ssh") {
112
- add(re.privateKeyEnv, "remoteExec", "ssh.privateKeyEnv");
113
- }
114
- else if (re.provider === "remote-docker") {
115
- add(re.tlsCertEnv, "remoteExec", "remote-docker.tlsCertEnv");
116
- add(re.tlsKeyEnv, "remoteExec", "remote-docker.tlsKeyEnv");
117
- add(re.tlsCaEnv, "remoteExec", "remote-docker.tlsCaEnv");
118
- add(re.sshKeyEnv, "remoteExec", "remote-docker.sshKeyEnv");
119
- }
120
- // adb / host / local-docker carry no secret env-NAME refs.
121
126
  }
122
127
  return [...map.entries()]
123
128
  .map(([envName, refs]) => ({ envName, refs, present: resolvedEnv[envName] !== undefined }))
package/dist/hooks.d.ts CHANGED
@@ -1732,7 +1732,7 @@ export declare const PostModelSwitchHookInput: z.ZodObject<{
1732
1732
  pricing: z.ZodEnum<["configured", "catalog", "default"]>;
1733
1733
  hook_event_name: z.ZodLiteral<"PostModelSwitch">;
1734
1734
  }, "strip", z.ZodTypeAny, {
1735
- source: "command" | "auto" | "resume" | "picker" | "sdk";
1735
+ source: "auto" | "command" | "resume" | "picker" | "sdk";
1736
1736
  to_model: string;
1737
1737
  session_id: string;
1738
1738
  transcript_path: string;
@@ -1749,7 +1749,7 @@ export declare const PostModelSwitchHookInput: z.ZodObject<{
1749
1749
  permission_mode?: string | undefined;
1750
1750
  agent_id?: string | undefined;
1751
1751
  }, {
1752
- source: "command" | "auto" | "resume" | "picker" | "sdk";
1752
+ source: "auto" | "command" | "resume" | "picker" | "sdk";
1753
1753
  to_model: string;
1754
1754
  session_id: string;
1755
1755
  transcript_path: string;
@@ -3173,7 +3173,7 @@ export declare const HookInput: z.ZodDiscriminatedUnion<"hook_event_name", [z.Zo
3173
3173
  pricing: z.ZodEnum<["configured", "catalog", "default"]>;
3174
3174
  hook_event_name: z.ZodLiteral<"PostModelSwitch">;
3175
3175
  }, "strip", z.ZodTypeAny, {
3176
- source: "command" | "auto" | "resume" | "picker" | "sdk";
3176
+ source: "auto" | "command" | "resume" | "picker" | "sdk";
3177
3177
  to_model: string;
3178
3178
  session_id: string;
3179
3179
  transcript_path: string;
@@ -3190,7 +3190,7 @@ export declare const HookInput: z.ZodDiscriminatedUnion<"hook_event_name", [z.Zo
3190
3190
  permission_mode?: string | undefined;
3191
3191
  agent_id?: string | undefined;
3192
3192
  }, {
3193
- source: "command" | "auto" | "resume" | "picker" | "sdk";
3193
+ source: "auto" | "command" | "resume" | "picker" | "sdk";
3194
3194
  to_model: string;
3195
3195
  session_id: string;
3196
3196
  transcript_path: string;
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  * the config center, the worker service, and the TOC desktop/CLI.
4
4
  */
5
5
  export * from "./types.js";
6
+ export * from "./execution-lanes.js";
6
7
  export * from "./hash.js";
7
8
  export * from "./sha256.js";
8
9
  export * from "./skills-manifest.js";
@@ -17,6 +18,7 @@ export * from "./scheduler-store.js";
17
18
  export * from "./cross-session.js";
18
19
  export * from "./hooks.js";
19
20
  export * from "./fleet.js";
21
+ export * from "./migrate-workers.js";
20
22
  export * from "./migrate.js";
21
23
  export * from "./api/auth.js";
22
24
  export * from "./api/auth-bridge.js";
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  * the config center, the worker service, and the TOC desktop/CLI.
4
4
  */
5
5
  export * from "./types.js";
6
+ export * from "./execution-lanes.js"; // 7.0.0 M-R2: the ONE lane / store vocabulary (EXECUTION_LANE_WORDS / EXECUTION_LANES / STORE_BACKENDS / SESSION_BACKENDS / MEMORY_ENGINE_BACKENDS) — pure data, browser-safe
6
7
  export * from "./hash.js";
7
8
  export * from "./sha256.js";
8
9
  export * from "./skills-manifest.js";
@@ -17,6 +18,7 @@ export * from "./scheduler-store.js"; // R7 self-wake scheduler store CONTRACT (
17
18
  export * from "./cross-session.js"; // CC-parity `settings.json` cross-session keys (crossSessionInbound / dialogExpiry) — pure/browser-safe
18
19
  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
19
20
  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
21
+ export * from "./migrate-workers.js"; // 7.0.0 one-time workers-domain migration (env.REMOTE_EXEC / sessionBackend / tidb* → runtime.execution / runtime.store), pure — run it on the RAW document before parseDomain
20
22
  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
21
23
  export * from "./api/auth.js"; // /api/v1/auth/* wire contract (RFC 8628 device flow + rotating refresh + logout + approve) — REGISTRY-REBUILD-DESIGN §2, M1 shipped shapes frozen, pure/browser-safe
22
24
  export * from "./api/auth-bridge.js"; // 鉴权桥 contract: worker verifies registry user JWT (RS256-only, JWKS kid-miss refresh + throttle, offline grace fail-closed) → VerifiedIdentity — design §5, the service verifier's spec
@@ -0,0 +1,63 @@
1
+ /**
2
+ * workers 域的**一次性迁移**(7.0.0,M-R2 WorkerSpec 结构块)—— 持久面唯一允许的过渡,窗口关了就整文件删除
3
+ * (连同 `types.ts` 里「删除项读到即拒」那一只预处理)。纯函数、无 I/O、不改入参;文件形的入口是
4
+ * `settings-schema migrate-workers <file>`(`bin/settings-schema.mjs`,同一只函数)。
5
+ *
6
+ * ## 谁跑、在哪
7
+ * 读前抬升:在 `parseDomain("workers", raw)` / `DOMAIN_SCHEMAS.workers.safeParse` **之前**对**原始 JSON** 跑 —— workers 是
8
+ * 「读即抛」的 gate 域,6.x 存下来的行在 7.0.0 schema 上整域读不出来(删除项响亮拒、enabled 的 worker 缺两块)。中心在它唯一的
9
+ * workers 读口跑一次,结果写回;CLI 给文件后端 / 离线用。
10
+ *
11
+ * ## 规则(每个旧键恰好一种去处)
12
+ * · **车道**:`env.REMOTE_EXEC` 是车道词 ⇒ `runtime.execution.lane`;同车道的 env 键 ⇒ `coords`,同车道的 `secretEnv` 密钥 ⇒
13
+ * `secretRefs`(都按导出表 `EXECUTION_LANES` 的栏判)。别车道的键、`REQUIRE_EXECUTION_LANE` ⇒ **dropped**(引擎只读被点名车道
14
+ * 那一臂;声明了车道就恒渲 true)—— 今天就是惰性的。**enabled 且无 `REMOTE_EXEC` ⇒ refused**:那是「无手照回 completed」的
15
+ * 病例本身,迁移不替运维猜车道。停用且无 `REMOTE_EXEC` ⇒ 不写车道,残留车道键 dropped。
16
+ * · **店**:`sessionBackend` ⇒ `store.session`(`tidb` ⇒ `mysql`,且 `store.backend` 由此为 `mysql`);`memoryBackend` ⇒ **dropped**
17
+ * (它从未到达引擎);`coords.tidbHost` 在 ⇒ `store.backend = mysql`,`coords.tidb*` + `runtime.db` ⇒ `store.db`(缺端口 ⇒ 引擎
18
+ * `MYSQL_PORT` 的缺省 3306),`secretRefs.tidbPasswordEnv` ⇒ `secretRefs.dbPasswordEnv`;没有 host ⇒ `store.backend = local`
19
+ * (设计稿 §3.4:推一次、写死),零散坐标惰性 ⇒ dropped。`env` 逃生口里的 `DB_BACKEND` / `MEMORY_ENGINE` /
20
+ * `MEMORY_ENGINE_BACKEND`(渲染器以前不渲,运维只能写在那里)⇒ 搬进 `store`,显式的 `DB_BACKEND` 优先。停用且旧形没点名任何店
21
+ * (无 host、无 `DB_BACKEND`、无 `tidb` 词)⇒ 不写店,旧字段 dropped。
22
+ * · **表达不了 ⇒ refused**:值写错了栏(密钥以字面值写在 env、坐标来自宿主密钥)、不认识的词、新旧两形并存、`DB_BACKEND=pg`
23
+ * 配 MySQL 族坐标 —— 迁移不搬值进密钥位、不读宿主密钥、不替运维挑赢家、不换库。
24
+ * · **终判 = 7.0.0 schema**:迁出来的每只 worker 都过 `WorkerSpec.safeParse`;不过 ⇒ refused,拒因是 schema 自己的 issue
25
+ * (例:多租户 + host 车道、点了车道却缺必需坐标)。迁移不复述任何一条写闸规则。
26
+ *
27
+ * refused 的 worker **不进**输出 `doc`(中心不加载它、在列表标红点名 `field`;CLI 有 refused 就一字不写),但随 `refused[].original`
28
+ * 逐字带回:`doc` ∪ `refused[].original` 覆盖输入的全部 worker,中心写回前按 `index` 放回(或另存),运维的 spec 不会随迁移消失。
29
+ * 拒因 / dropped 只点名字段,不回显值。
30
+ *
31
+ * ## 幂等
32
+ * 已迁形(没有任何旧键、该有的块都在)⇒ 原样(同一引用)返回、`changed = []`。所以再跑一次 ⇒ 零变化、`doc` 字节相等。
33
+ */
34
+ import { type ConfigPath } from "./config-fns.js";
35
+ /** 一个被丢掉的旧字段(引擎本就不读它 —— 通知一行,不是错误)。`field` 相对该 worker 条目;`index` = 它在输入 `workers` 里的下标。 */
36
+ export interface WorkersMigrationDrop {
37
+ readonly name: string;
38
+ readonly index: number;
39
+ readonly field: ConfigPath;
40
+ }
41
+ /** 一只迁不了的 worker(不进输出 `doc`)。`field` 指到要人改的那一格(相对该 worker 条目;终判失败时是 7.0.0 形里的路径),
42
+ * `reason` 只点名字段、不回显值。`original` = 输入里那一行**逐字**(同一个值,未拷贝未改写)——
43
+ * 🔴 **写回 `doc` 之前必须把每个 `refused[].original` 按 `index` 放回(或另存)**,否则这只 worker 的 spec 随写回从存储里消失,
44
+ * 运维看到的是「worker 不见了」而不是「worker 被标红」。它是调用方自己的数据,原样带回;要记日志,按调用方记那一行的规矩记。 */
45
+ export interface WorkersMigrationRefusal {
46
+ readonly name: string;
47
+ readonly index: number;
48
+ readonly field: ConfigPath;
49
+ readonly reason: string;
50
+ readonly original: unknown;
51
+ }
52
+ /** `migrateWorkersDomain` 的结果。`changed` = 被改写的 worker 名(含只丢了旧字段的)。 */
53
+ export interface WorkersDomainMigration {
54
+ readonly doc: unknown;
55
+ readonly changed: readonly string[];
56
+ readonly dropped: readonly WorkersMigrationDrop[];
57
+ readonly refused: readonly WorkersMigrationRefusal[];
58
+ }
59
+ /**
60
+ * 迁移一份 workers 域**原始**文档(`{ workers: [...] }`)。不是这个形 ⇒ 原样返回(判形是 `parseDomain` 的事,迁移不抛)。
61
+ * 规则、幂等与 refused 的处置见文件头。
62
+ */
63
+ export declare function migrateWorkersDomain(doc: unknown): WorkersDomainMigration;