@sema-agent/server 7.151.0 → 7.152.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 (286) hide show
  1. package/MIGRATION.md +266 -0
  2. package/README.md +15 -3
  3. package/README.zh-CN.md +10 -2
  4. package/USAGE.md +93 -64
  5. package/deploy/sema-up/README.md +5 -4
  6. package/deploy/sema-up/cluster-up.sh +6 -6
  7. package/deploy/sema-up/kube-up.sh +5 -5
  8. package/deploy/sema-up/lib/flagshape.sh +36 -8
  9. package/deploy/sema-up/machines.example.yaml +3 -1
  10. package/deploy/sema-up/sema-up.sh +22 -16
  11. package/dist/approval-ask-audit-store.d.ts +1 -1
  12. package/dist/approval-ask-machine.d.ts +4 -10
  13. package/dist/approval-ask-retention.d.ts +1 -1
  14. package/dist/approval-card.d.ts +10 -12
  15. package/dist/approval-gate-currency.d.ts +8 -8
  16. package/dist/approval-gate-currency.js +3 -4
  17. package/dist/approval-hmac.d.ts +17 -1
  18. package/dist/approval-hmac.js +7 -1
  19. package/dist/approval-queue-kind.d.ts +1 -1
  20. package/dist/approval.d.ts +2 -2
  21. package/dist/approval.js +2 -2
  22. package/dist/bind-host.d.ts +1 -3
  23. package/dist/bind-host.js +2 -3
  24. package/dist/boot/coordinators.d.ts +1 -1
  25. package/dist/boot/coordinators.js +9 -10
  26. package/dist/boot/device-lane.js +2 -0
  27. package/dist/boot/execution-env.d.ts +1 -0
  28. package/dist/boot/execution-env.js +31 -5
  29. package/dist/boot/leader.d.ts +31 -30
  30. package/dist/boot/leader.js +38 -28
  31. package/dist/boot/leg-path-adjudication.d.ts +40 -0
  32. package/dist/boot/leg-path-adjudication.js +18 -0
  33. package/dist/boot/parked-revive-gate.js +3 -15
  34. package/dist/boot/reapers.d.ts +1 -1
  35. package/dist/boot/reapers.js +1 -1
  36. package/dist/boot/resolve-spec.js +12 -26
  37. package/dist/boot/runner-deps.d.ts +39 -35
  38. package/dist/boot/runner-deps.js +92 -89
  39. package/dist/boot/shutdown.d.ts +6 -0
  40. package/dist/boot/shutdown.js +10 -4
  41. package/dist/boot/stage-02-web-admin-pull.js +4 -5
  42. package/dist/boot/stage-05-execution-env.js +2 -1
  43. package/dist/boot/stage-06-runners.d.ts +2 -0
  44. package/dist/boot/stage-06-runners.js +10 -4
  45. package/dist/boot/stage-07-capability-layer.d.ts +1 -0
  46. package/dist/boot/stage-07-capability-layer.js +1 -1
  47. package/dist/boot/stage-08-reapers.d.ts +1 -0
  48. package/dist/boot/stage-09-leader.d.ts +1 -0
  49. package/dist/boot/stage-09-leader.js +2 -2
  50. package/dist/boot/stage-10-http-server.d.ts +8 -0
  51. package/dist/boot/stage-10-http-server.js +11 -15
  52. package/dist/boot/stores.js +7 -4
  53. package/dist/boot/web-admin.js +2 -7
  54. package/dist/capabilities/approvals-push.d.ts +3 -3
  55. package/dist/capabilities/scenarios.d.ts +28 -13
  56. package/dist/capabilities/scenarios.js +2 -2
  57. package/dist/capability-facts.d.ts +22 -20
  58. package/dist/capability-facts.js +18 -34
  59. package/dist/card-rule-offers.d.ts +32 -0
  60. package/dist/card-rule-offers.js +130 -0
  61. package/dist/config-catalog.js +12 -11
  62. package/dist/config-dir-trust.js +4 -2
  63. package/dist/config-invariants.d.ts +18 -7
  64. package/dist/config-invariants.js +51 -8
  65. package/dist/config-lkg.d.ts +5 -19
  66. package/dist/config-lkg.js +8 -62
  67. package/dist/config-provider.d.ts +1 -1
  68. package/dist/config-root-migration.d.ts +2 -2
  69. package/dist/config-types.d.ts +28 -38
  70. package/dist/config.d.ts +7 -5
  71. package/dist/config.js +55 -16
  72. package/dist/control-socket.d.ts +51 -0
  73. package/dist/control-socket.js +115 -0
  74. package/dist/deployment-governance.d.ts +2 -1
  75. package/dist/device-ws-hub.d.ts +7 -0
  76. package/dist/device-ws-hub.js +7 -1
  77. package/dist/elicitation.js +2 -2
  78. package/dist/entry-problems.d.ts +40 -3
  79. package/dist/entry-problems.js +3 -1
  80. package/dist/execution-env-refusal.d.ts +8 -2
  81. package/dist/execution-env-refusal.js +3 -0
  82. package/dist/fleet/engine-signal.d.ts +12 -29
  83. package/dist/fleet/engine-signal.js +1 -7
  84. package/dist/fleet-client.js +2 -5
  85. package/dist/gate-settlement.d.ts +1 -8
  86. package/dist/gate-settlement.js +0 -4
  87. package/dist/history-anchor.js +1 -1
  88. package/dist/hitl-delivery.d.ts +2 -3
  89. package/dist/hitl-delivery.js +0 -2
  90. package/dist/hooks/hook-llm.js +4 -2
  91. package/dist/hooks/hook-runner.d.ts +3 -2
  92. package/dist/hooks/hook-runner.js +16 -1
  93. package/dist/host-decision.d.ts +11 -11
  94. package/dist/http/active-run-conflict.d.ts +35 -2
  95. package/dist/http/active-run-conflict.js +48 -19
  96. package/dist/http/approval-sweeps.d.ts +1 -1
  97. package/dist/http/approval-sweeps.js +5 -2
  98. package/dist/http/checkpoint-ctx.d.ts +2 -0
  99. package/dist/http/checkpoint-ctx.js +1 -0
  100. package/dist/http/dispatch.d.ts +6 -2
  101. package/dist/http/dispatch.js +25 -5
  102. package/dist/http/durable-run-leg.js +0 -1
  103. package/dist/http/health-reader.d.ts +16 -9
  104. package/dist/http/health-reader.js +2 -1
  105. package/dist/http/health-self-report.js +1 -1
  106. package/dist/http/owner-access.d.ts +2 -3
  107. package/dist/http/owner-access.js +3 -4
  108. package/dist/http/principal-gate.d.ts +49 -21
  109. package/dist/http/principal-gate.js +61 -11
  110. package/dist/http/request-channel.d.ts +23 -0
  111. package/dist/http/request-channel.js +9 -0
  112. package/dist/http/request-guards.js +17 -2
  113. package/dist/http/resume-ctx-read.js +20 -3
  114. package/dist/http/resume-legs.d.ts +2 -2
  115. package/dist/http/resume-legs.js +111 -41
  116. package/dist/http/route-ctx.d.ts +73 -7
  117. package/dist/http/route-ctx.js +17 -0
  118. package/dist/http/route-table.d.ts +4 -0
  119. package/dist/http/route-table.js +4 -0
  120. package/dist/http/routes/admin-config-refresh.js +3 -3
  121. package/dist/http/routes/admin-drain.d.ts +3 -0
  122. package/dist/http/routes/admin-drain.js +7 -7
  123. package/dist/http/routes/admin-memory-optout.js +3 -3
  124. package/dist/http/routes/adoption.js +3 -5
  125. package/dist/http/routes/approvals-assistant.d.ts +2 -1
  126. package/dist/http/routes/approvals-assistant.js +95 -48
  127. package/dist/http/routes/capabilities.d.ts +4 -0
  128. package/dist/http/routes/capabilities.js +30 -5
  129. package/dist/http/routes/config-catalog.js +2 -2
  130. package/dist/http/routes/devices.js +1 -1
  131. package/dist/http/routes/diagnostics.d.ts +3 -3
  132. package/dist/http/routes/diagnostics.js +19 -7
  133. package/dist/http/routes/images.js +10 -10
  134. package/dist/http/routes/memory-bundle.js +3 -3
  135. package/dist/http/routes/memory-compliance.js +3 -3
  136. package/dist/http/routes/memory-consolidation.js +2 -2
  137. package/dist/http/routes/memory-origin.js +3 -3
  138. package/dist/http/routes/memory-policy.js +2 -2
  139. package/dist/http/routes/observability.js +3 -3
  140. package/dist/http/routes/retention-ops.js +3 -3
  141. package/dist/http/routes/rules.js +5 -5
  142. package/dist/http/routes/run-permission-mode.d.ts +2 -1
  143. package/dist/http/routes/run-permission-mode.js +2 -2
  144. package/dist/http/routes/runs.d.ts +4 -9
  145. package/dist/http/routes/runs.js +73 -33
  146. package/dist/http/routes/session-sync.d.ts +18 -6
  147. package/dist/http/routes/session-sync.js +38 -36
  148. package/dist/http/routes/sessions.js +20 -9
  149. package/dist/http/routes/tasks.js +28 -37
  150. package/dist/http/routes/workflows.js +1 -1
  151. package/dist/http/server.d.ts +9 -3
  152. package/dist/http/server.js +15 -3
  153. package/dist/http/submit-ctx.d.ts +1 -1
  154. package/dist/http/submit-ctx.js +2 -0
  155. package/dist/human-facing-args.d.ts +33 -0
  156. package/dist/human-facing-args.js +33 -0
  157. package/dist/index.d.ts +1 -1
  158. package/dist/k8s-api-credentials.d.ts +29 -0
  159. package/dist/k8s-api-credentials.js +25 -0
  160. package/dist/lane-home-probe.d.ts +1 -1
  161. package/dist/lane-home-probe.js +2 -1
  162. package/dist/leader/diffup.d.ts +19 -0
  163. package/dist/leader/diffup.js +7 -0
  164. package/dist/leader/leader.d.ts +114 -10
  165. package/dist/leader/leader.js +69 -5
  166. package/dist/leader/repair-wire.js +2 -2
  167. package/dist/leader/run-entry.d.ts +2 -1
  168. package/dist/leader/run-entry.js +1 -1
  169. package/dist/leader/wire.d.ts +42 -132
  170. package/dist/leader/wire.js +81 -67
  171. package/dist/memory-scope.d.ts +20 -9
  172. package/dist/memory-scope.js +15 -3
  173. package/dist/model-entry-headers.d.ts +9 -10
  174. package/dist/model-entry-headers.js +0 -4
  175. package/dist/model-entry-refusal.d.ts +7 -4
  176. package/dist/model-entry-refusal.js +11 -5
  177. package/dist/model-plane-face.d.ts +1 -1
  178. package/dist/model-plane-face.js +3 -1
  179. package/dist/model-route-endpoint.d.ts +13 -7
  180. package/dist/model-route-endpoint.js +14 -11
  181. package/dist/model-select.d.ts +22 -0
  182. package/dist/model-select.js +9 -0
  183. package/dist/model-unreachable-notice.d.ts +11 -0
  184. package/dist/model-unreachable-notice.js +4 -4
  185. package/dist/object-store-buckets.d.ts +640 -6
  186. package/dist/object-store-buckets.js +166 -0
  187. package/dist/observability/fail-open.d.ts +20 -16
  188. package/dist/observability/fail-open.js +20 -16
  189. package/dist/observability/logger.js +3 -1
  190. package/dist/operator-roster.d.ts +68 -0
  191. package/dist/operator-roster.js +32 -0
  192. package/dist/orchestration/workflow-park-decision.d.ts +1 -1
  193. package/dist/outbound-dispatcher.d.ts +71 -8
  194. package/dist/outbound-dispatcher.js +48 -7
  195. package/dist/owner-faces.d.ts +1 -1
  196. package/dist/parked-decide.d.ts +2 -2
  197. package/dist/permission-mode-admission.d.ts +59 -26
  198. package/dist/permission-mode-admission.js +37 -10
  199. package/dist/plugins/approval-ask-store-file.d.ts +4 -0
  200. package/dist/plugins/approval-ask-store-file.js +3 -0
  201. package/dist/plugins/approval-ask-store-memory.d.ts +4 -0
  202. package/dist/plugins/approval-ask-store-memory.js +7 -1
  203. package/dist/plugins/approval-ask-store-sql.d.ts +26 -2
  204. package/dist/plugins/approval-ask-store-sql.js +12 -1
  205. package/dist/plugins/blob-backend.d.ts +83 -7
  206. package/dist/plugins/blob-backend.js +57 -6
  207. package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
  208. package/dist/plugins/checkpoint-index-columns.js +3 -6
  209. package/dist/plugins/checkpoint-store-face.d.ts +119 -61
  210. package/dist/plugins/checkpoint-store-face.js +134 -55
  211. package/dist/plugins/landed-attendants.d.ts +2 -2
  212. package/dist/plugins/local-checkpoint-store.d.ts +13 -3
  213. package/dist/plugins/local-checkpoint-store.js +38 -49
  214. package/dist/plugins/one-time-migrations.d.ts +51 -21
  215. package/dist/plugins/one-time-migrations.js +67 -45
  216. package/dist/plugins/pg-pool.js +11 -9
  217. package/dist/plugins/remote-env-host.d.ts +29 -10
  218. package/dist/plugins/remote-env-host.js +99 -19
  219. package/dist/plugins/remote-env-k8s.d.ts +68 -2
  220. package/dist/plugins/remote-env-k8s.js +107 -24
  221. package/dist/plugins/replica-registration.d.ts +1 -1
  222. package/dist/plugins/replica-registration.js +1 -1
  223. package/dist/plugins/s3-presign.d.ts +23 -0
  224. package/dist/plugins/s3-presign.js +37 -3
  225. package/dist/plugins/scheduler-support.d.ts +2 -2
  226. package/dist/plugins/scheduler-support.js +0 -3
  227. package/dist/plugins/schema-indexes.js +2 -0
  228. package/dist/plugins/send-file-ledger.d.ts +2 -2
  229. package/dist/plugins/send-file-ledger.js +2 -2
  230. package/dist/plugins/send-user-file.d.ts +3 -4
  231. package/dist/plugins/send-user-file.js +56 -52
  232. package/dist/plugins/session-blob-claim-token.d.ts +15 -0
  233. package/dist/plugins/session-blob-claim-token.js +20 -0
  234. package/dist/plugins/session-blob-namespace.d.ts +46 -0
  235. package/dist/plugins/session-blob-namespace.js +116 -0
  236. package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
  237. package/dist/plugins/snapshot-bucket-presence.js +8 -2
  238. package/dist/plugins/sql-json-column.d.ts +1 -1
  239. package/dist/plugins/store-backend.d.ts +44 -2
  240. package/dist/plugins/store-backend.js +75 -53
  241. package/dist/plugins/task-attachment-store.d.ts +2 -1
  242. package/dist/plugins/task-attachment-store.js +5 -1
  243. package/dist/plugins/tidb-pool.js +19 -24
  244. package/dist/plugins/workspace-custody.d.ts +4 -3
  245. package/dist/question.d.ts +2 -1
  246. package/dist/question.js +5 -13
  247. package/dist/request-form.d.ts +6 -1
  248. package/dist/request-form.js +4 -1
  249. package/dist/rule-issue-reading.d.ts +1 -1
  250. package/dist/rules-consent.d.ts +1 -1
  251. package/dist/run-local.js +8 -9
  252. package/dist/runs.d.ts +17 -8
  253. package/dist/runs.js +15 -2
  254. package/dist/runtime-governance.d.ts +2 -2
  255. package/dist/sema-config-dir.d.ts +2 -1
  256. package/dist/session-sync.d.ts +27 -11
  257. package/dist/session-sync.js +15 -7
  258. package/dist/stores-sql/blob-index-sql.d.ts +30 -9
  259. package/dist/stores-sql/blob-index-sql.js +40 -21
  260. package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
  261. package/dist/stores-sql/checkpoint-store-sql.js +70 -146
  262. package/dist/stores-sql/file-history-store-sql.d.ts +64 -16
  263. package/dist/stores-sql/file-history-store-sql.js +100 -28
  264. package/dist/stores-sql/retention-store-sql.js +3 -9
  265. package/dist/task-settings.d.ts +6 -5
  266. package/dist/task-settings.js +3 -3
  267. package/dist/tool-approval.d.ts +342 -518
  268. package/dist/tool-approval.js +498 -1207
  269. package/dist/trace/core-keyset-guard.d.ts +1 -1
  270. package/dist/trace/ledger-events.d.ts +3 -3
  271. package/dist/trace/project.d.ts +2 -3
  272. package/dist/trace/redact.js +3 -2
  273. package/dist/trace/self-minted-wire.d.ts +287 -157
  274. package/dist/trace/self-minted-wire.js +93 -48
  275. package/dist/web-admin-client/apply-effective.js +2 -2
  276. package/dist/web-admin-client/read-warnings.d.ts +2 -2
  277. package/dist/web-admin-client/read-warnings.js +1 -1
  278. package/dist/web-admin-client/types.d.ts +1 -1
  279. package/dist/workspace-space.d.ts +10 -4
  280. package/dist/workspace-space.js +4 -1
  281. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +1 -1
  282. package/package.json +6 -2
  283. package/scripts/embed-minimal.mjs +3 -3
  284. package/wire-changes/server@7.152.0.json +900 -0
  285. package/dist/config-d-migration.d.ts +0 -37
  286. package/dist/config-d-migration.js +0 -60
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 给人看的调用入参 —— **唯一一份读法**。三处读者同调这一只函数:活卡的 `args`(`tool-approval.ts` 的卡帧 / `card_json` / 续跑拒体的 `acceptableForm`)、
3
+ * 停驻行的 `input`(`plugins/checkpoint-store-face.ts` 的 `boundedToolInput`:两孪生都在读时从停驻快照的待决动作投影,不存第二份)、问帧的 `questions`(`question.ts`)。
4
+ *
5
+ * 律(一条):**脱敏 → 序列化 → 按 UTF-8 字节量 → 对一个常量判;卡的种类决定超了怎样。**
6
+ * · 入参**就是**人要决的东西(问:题干与选项;计划:要批的计划正文)⇒ 整份给出、从不折叠。折掉它,人能做的只剩拒答 —— 那就不该把 run 停在他面前;
7
+ * 同一份字节(模型原调用的那一份)本就随 `tool_start.args` 不封顶地进了同一条流与账本,在这里封顶挡不住它,只制造「活面不给看、停驻行给折叠」两种盲。
8
+ * · 其余动作卡 ⇒ 超常量即折叠(活卡 `argsOmitted`、停驻行 `{ truncated: true, bytes }`):盲批的安全答是「不」,动作卡的保留部分在兄弟格上
9
+ * (卡的 `message`、停驻行的 `riskDescriptor.summary` / `touchedPaths`),帽买到的是队列列举 / 流 upsert / `card_json` 少一份大拷贝。
10
+ * · 无卡(引擎没铸卡词:更早的停驻行 / 非审批门;集外词在读点已读作无卡)⇒ 按动作折(有界是 fail-safe 方向)。
11
+ * 序列化不出(BigInt / 抛错的 `toJSON`;环在脱敏遍历里已被断开成 `[circular]`)⇒ 折叠、`bytes: null` —— 没有可给的整份,问 / 计划卡同此。
12
+ *
13
+ * 卡是哪一张只有引擎铸的 `approvalCard` 一个事实源(`approval-content-kind.ts` 的律:不从工具名回推):活卡读 `AskRequest.approvalCard`,停驻行读门上那一格
14
+ * (SQL 孪生 = `approval_card` / `gate_kind` 两列,LOCAL 孪生 = 门本身,同一只 `parkedApprovalCard`);调用方读定后交进来,本模块不读卡。
15
+ * 如实:这是一只函数、三处调用、同一判定,不是「一次判定先于所有落点」—— 各面在自己的时刻对自己手里的那份入参判,同一份入参在各面答同一个结局。
16
+ */
17
+ import type { ToolApprovalCard } from "@sema-agent/core";
18
+ /**
19
+ * 动作卡入参给人看的上限:脱敏后 JSON 的 **UTF-8 字节数**。取值:本版之前停驻行的帽是 8192 个 UTF-16 单元,一个单元至多 3 个 UTF-8 字节(`\uXXXX` 转义 6 单元 6 字节)
20
+ * ⇒ 那一帽下整份的入参最坏 24576 字节 < 本值 —— 停驻行、活卡、问三面相对上一版零收窄。
21
+ */
22
+ export declare const HUMAN_FACING_ARGS_BYTES = 32768;
23
+ /** 一份入参给人看的结局:整份(脱敏后的值)或折叠(`bytes` = 脱敏后 JSON 的 UTF-8 字节数;序列化不出 ⇒ `null`)。纯数据。 */
24
+ export type HumanFacingArgs = {
25
+ readonly kind: "whole";
26
+ readonly value: unknown;
27
+ } | {
28
+ readonly kind: "omitted";
29
+ readonly bytes: number | null;
30
+ };
31
+ /** 见模块头注的律。`card` = 调用方读定的卡(无卡 ⇒ `undefined`)。 */
32
+ export declare function humanFacingArgs(args: unknown, card: ToolApprovalCard | undefined): HumanFacingArgs;
33
+ //# sourceMappingURL=human-facing-args.d.ts.map
@@ -0,0 +1,33 @@
1
+ import { redactDeep } from "./trace/redact.js";
2
+ export const HUMAN_FACING_ARGS_BYTES = 32768;
3
+ const ARGS_ARE_THE_DECISION = {
4
+ question: true,
5
+ plan: true,
6
+ "file-edit": false,
7
+ "file-write": false,
8
+ "notebook-edit": false,
9
+ shell: false,
10
+ fetch: false,
11
+ skill: false,
12
+ workflow: false,
13
+ generic: false,
14
+ "computer-access": false,
15
+ "computer-control": false,
16
+ };
17
+ export function humanFacingArgs(args, card) {
18
+ const redacted = redactDeep(args);
19
+ let text;
20
+ try {
21
+ text = JSON.stringify(redacted);
22
+ }
23
+ catch {
24
+ return { kind: "omitted", bytes: null };
25
+ }
26
+ if (text === undefined)
27
+ return { kind: "omitted", bytes: null };
28
+ if (card !== undefined && ARGS_ARE_THE_DECISION[card])
29
+ return { kind: "whole", value: redacted };
30
+ const bytes = Buffer.byteLength(text, "utf8");
31
+ return bytes > HUMAN_FACING_ARGS_BYTES ? { kind: "omitted", bytes } : { kind: "whole", value: redacted };
32
+ }
33
+ //# sourceMappingURL=human-facing-args.js.map
package/dist/index.d.ts CHANGED
@@ -20,7 +20,7 @@ export { RateLimiter, type RateDecision } from "./observability/rate-limit.js";
20
20
  export { GiteaClient, GitHubClient, createRepoClient, GIT_API_KINDS, isGitApiKind, repoToolsFor, parseRepo, type GitApiKind, type RepoCoords, type RepoReadClient } from "./capabilities/repo-tools.js";
21
21
  export { nowTool } from "./capabilities/builtin-tools.js";
22
22
  export { loadSkills, skillsForScenario, type LoadedSkill } from "./capabilities/skills.js";
23
- export { buildScenarios, selectScenario, createScenarioGate, type Scenario, type ScenarioBundle, type ScenarioContext, type ScenarioDeps, type ScenarioGate, type ScenarioGateLeg, type ScenarioGateSources, type ScenarioRequest, } from "./capabilities/scenarios.js";
23
+ export { buildScenarios, selectScenario, createScenarioGate, type Scenario, type ScenarioBundle, type ScenarioChoice, type ScenarioContext, type ScenarioDeps, type ScenarioGate, type ScenarioGateLeg, type ScenarioGateSources, type ScenarioRequest, type ScenarioSource, } from "./capabilities/scenarios.js";
24
24
  export { createTaskListLane, taskListKeyFor, MAX_TASK_LIST_SESSIONS, type TaskListLane, type TaskListLaneBackend, type TaskListLaneOpts } from "./boot/task-list-lane.js";
25
25
  export { ensureTiDBTaskListSchema, ensurePgTaskListSchema } from "./plugins/task-list-store-sql.js";
26
26
  export { createAuthorizer, principalFrom, HttpError, type AuthContext, type OwnerAwareSessionStore, } from "./security.js";
@@ -0,0 +1,29 @@
1
+ /**
2
+ * k8s 车道的**集群 API 凭据**:缺什么、怎么说、说给谁(纯叶:零值依赖,零 IO)。
3
+ *
4
+ * ## 法
5
+ * 车道声明了(`REMOTE_EXEC=k8s`)而控制面凭据没有 ⇒ 车道上每一条命令都起不来(`shell_unavailable`),而 run 照常 `completed` —— 这是**起服前就知道**的事,
6
+ * 不许走到 run 才说(同一件事实一个出口)。判「凭据在不在」只有一只判官(`plugins/remote-env-k8s.ts` 的 `resolveK8sApiAccess`:显式配置 ∨ in-cluster 服务账号,
7
+ * 适配器每次请求前读的 `creds()` 与下面三处说法读同一只),它答三个事实之一({@link K8sApiCredentialFact});本模块只管每个事实的**一句话**与三处说法:
8
+ * · 起服拒({@link k8sCredentialsMissingBootSentence} + {@link K8sApiCredentialsMissingError},机器码 `config.k8s_api_credentials_missing`):凭据缺 ⇒ 不起;
9
+ * · 运行期拒({@link k8sCredentialsMissingRunSentence} / {@link k8sCredentialsRejectedRunSentence}):起服之后凭据缺(服务账号文件没了)或被集群 401 拒 ⇒
10
+ * 每条 run 的环境铸造前拒,码 `env.sandbox_refused`(`execution-env-refusal.ts`)。
11
+ * 两条出路只写一次({@link EXITS}),三句共用:给凭据,或改车道。
12
+ */
13
+ /** 判官的三个事实:缺集群 API 地址 / 缺 API 令牌 / 缺 CA(且没声明实验室 TLS)。 */
14
+ export type K8sApiCredentialFact = "api_url" | "token" | "ca";
15
+ /** 一个缺失事实的一句话。 */
16
+ export declare function describeMissingK8sCredential(fact: K8sApiCredentialFact): string;
17
+ /** 起服拒的拒句:点名「REMOTE_EXEC=k8s 需要集群 API 凭据」、缺的那一件、后果与两条出路。 */
18
+ export declare function k8sCredentialsMissingBootSentence(fact: K8sApiCredentialFact): string;
19
+ /** 运行期拒(凭据在起服之后读不到):句里不再说「拒启」,说这条 run 被拒。 */
20
+ export declare function k8sCredentialsMissingRunSentence(fact: K8sApiCredentialFact): string;
21
+ /** 运行期拒(集群 API 以 401 拒了车道的凭据)。 */
22
+ export declare function k8sCredentialsRejectedRunSentence(): string;
23
+ /** 起服拒的机器码(`boot/fatal-exit.ts` 把带码异常写成 `<名> [<码>]: …` 标题;`config.*` 族与 `config.store_not_durable` 同形)。 */
24
+ export declare const K8S_API_CREDENTIALS_MISSING_CODE = "config.k8s_api_credentials_missing";
25
+ /** 起服因 k8s 车道声明而集群 API 凭据缺而拒启时的抛出物。 */
26
+ export declare class K8sApiCredentialsMissingError extends Error {
27
+ readonly code = "config.k8s_api_credentials_missing";
28
+ }
29
+ //# sourceMappingURL=k8s-api-credentials.d.ts.map
@@ -0,0 +1,25 @@
1
+ const MISSING_WHAT = {
2
+ api_url: "no cluster API address is set (K8S_API_URL) and the process is not running in a cluster (no KUBERNETES_SERVICE_HOST)",
3
+ token: "no API token is set (K8S_TOKEN) and the mounted service-account token cannot be read",
4
+ ca: "no CA certificate is set (K8S_CA_CERT_B64) and the mounted service-account CA cannot be read, and K8S_INSECURE_TLS is not true",
5
+ };
6
+ export function describeMissingK8sCredential(fact) {
7
+ return MISSING_WHAT[fact];
8
+ }
9
+ const EXITS = "Either give the server the cluster API credentials (K8S_API_URL + K8S_TOKEN, plus K8S_CA_CERT_B64 or K8S_INSECURE_TLS=true for a lab; or run the server in a pod that mounts a service account) " +
10
+ "or declare an execution lane that needs no cluster (REMOTE_EXEC=none, or another lane).";
11
+ export function k8sCredentialsMissingBootSentence(fact) {
12
+ return (`REMOTE_EXEC=k8s needs cluster API credentials, but ${MISSING_WHAT[fact]} — refusing to start rather than serving a lane on which every sandbox command ` +
13
+ `fails (shell_unavailable) while every run still finishes as completed. ${EXITS}`);
14
+ }
15
+ export function k8sCredentialsMissingRunSentence(fact) {
16
+ return `this run is refused: the k8s execution lane needs cluster API credentials, but ${MISSING_WHAT[fact]}. ${EXITS}`;
17
+ }
18
+ export function k8sCredentialsRejectedRunSentence() {
19
+ return `this run is refused: the cluster API rejected the k8s lane's credentials (HTTP 401) — a revoked or expired token, or an API address of another cluster. ${EXITS}`;
20
+ }
21
+ export const K8S_API_CREDENTIALS_MISSING_CODE = "config.k8s_api_credentials_missing";
22
+ export class K8sApiCredentialsMissingError extends Error {
23
+ code = K8S_API_CREDENTIALS_MISSING_CODE;
24
+ }
25
+ //# sourceMappingURL=k8s-api-credentials.js.map
@@ -23,7 +23,7 @@
23
23
  * 读不了家目录的车道(device:设备协议没有读数)不持座 —— 声明就是座,起服披露「来自声明、未实测」(`execution-lane-caps.ts` `buildLaneHomeBootNote`)。
24
24
  * 规则基与 422 门在下单那一刻就要家目录,而那一刻执行环境还没开 —— 它们只读主张(`executionLaneHomeDir`);环境开起来时主张被证,证不了的环境不开。
25
25
  */
26
- import type { ExecutionEnvRefusalCode } from "./execution-env-refusal.js";
26
+ import { type ExecutionEnvRefusalCode } from "./execution-env-refusal.js";
27
27
  /** 探针答案的行首标记:登录脚本 / profile 往 stdout 打的横幅不会被读成家目录 —— 只认带这个标记的那一行(恰一条,见 `markedHome`)。 */
28
28
  export declare const LANE_HOME_PROBE_MARKER = "sema-lane-home=";
29
29
  /**
@@ -1,3 +1,4 @@
1
+ import { executionEnvRefusalError } from "./execution-env-refusal.js";
1
2
  export const LANE_HOME_PROBE_MARKER = "sema-lane-home=";
2
3
  export const LANE_HOME_PROBE_COMMAND = `printf '\\n${LANE_HOME_PROBE_MARKER}%s\\n' "$HOME"`;
3
4
  const SHOWN_MAX = 256;
@@ -62,7 +63,7 @@ export function judgeLaneHome(lane, claim, probe, paths = "posix") {
62
63
  };
63
64
  }
64
65
  export function laneHomeRefusal(verdict) {
65
- return Object.assign(new Error(verdict.refusal), { code: "env.home_unconfirmed" });
66
+ return executionEnvRefusalError("env.home_unconfirmed", verdict.refusal);
66
67
  }
67
68
  export const LANE_HOME_UNDECLARED_EVENT = "execution_lane_home_undeclared";
68
69
  const HOME_ABSENT_COST = "the engine cannot place its home-anchored read-deny rows, so every contents-disclosing recursive read (grep -r, rg, git grep, tar c, …) asks a person on the full shell — " +
@@ -15,6 +15,25 @@
15
15
  * pullDiff stays as the compat path for static (leader-owned) envs — M2 降兼容.
16
16
  */
17
17
  import { type PullDiffResult } from "./diffout.js";
18
+ /** The leader's diff-out store (`MINIO_BUCKET` + the shared `MINIO_*` endpoint and key; `boot/leader.ts` `buildLeaderObjectStore`). */
19
+ export interface LeaderDiffStore {
20
+ endpoint: string;
21
+ bucket: string;
22
+ accessKey: string;
23
+ secretKey: string;
24
+ region?: string;
25
+ }
26
+ /**
27
+ * One worker's diff-out object and its two URLs — the ONE place the key is spelled (`leader-diff/<run>/<workerId>.patch`; one object per worker per
28
+ * leader run, a repair re-run overwrites): the PUT the worker env's upload script sends (`leader-diff/patch:PUT`, the sandbox) and the GET the
29
+ * leader fetches it with on the control plane (`leader-diff/patch:GET`, the server). `workerId` is validateSubtasks-clean (`[A-Za-z0-9._-]+`) ⇒
30
+ * safe as a key segment (the presigner backstop-rejects traversal anyway). `ttlSec` = the worker's deadline plus slack (`leaderResourceConfig`).
31
+ */
32
+ export declare function buildLeaderDiffUrls(s3: LeaderDiffStore, workerId: string, ttlSec: number): {
33
+ readonly key: string;
34
+ readonly putUrl: string;
35
+ readonly getUrl: string;
36
+ };
18
37
  /** The staged upload script. `repoDir`/`workDir` are deployment config; `baseSha` is interpolated into a
19
38
  * shell line, so it is re-validated HERE (fail-closed) — callers should already have applied diffout's
20
39
  * safeRev rules, but this function is the last line before the shell. The patch is written OUTSIDE the repo
@@ -1,6 +1,13 @@
1
1
  import { safeRev, DEFAULT_MAX_DIFF_BYTES } from "./diffout.js";
2
2
  import { OBJECT_STORE_IO_TIMEOUT_MS } from "../plugins/blob-backend.js";
3
3
  import { createEgressFetch } from "../egress-redirect.js";
4
+ import { presignS3Url } from "../plugins/s3-presign.js";
5
+ import { LEADER_DIFF_PREFIX } from "../object-store-buckets.js";
6
+ export function buildLeaderDiffUrls(s3, workerId, ttlSec) {
7
+ const key = `${LEADER_DIFF_PREFIX}/${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}/${workerId}.patch`;
8
+ const base = { endpoint: s3.endpoint, bucket: s3.bucket, accessKey: s3.accessKey, secretKey: s3.secretKey, ...(s3.region ? { region: s3.region } : {}), key, expiresSec: ttlSec };
9
+ return { key, putUrl: presignS3Url({ ...base, op: "leader-diff/patch:PUT", method: "PUT" }), getUrl: presignS3Url({ ...base, op: "leader-diff/patch:GET", method: "GET" }) };
10
+ }
4
11
  export function buildUploadScript(p) {
5
12
  if (!safeRev(p.baseSha))
6
13
  throw new Error(`buildUploadScript: unsafe baseSha ${JSON.stringify(p.baseSha)}`);
@@ -15,8 +15,10 @@
15
15
  import { type RunnerLike, type WorkerReport } from "./fanout.js";
16
16
  import { type ExecStreamLike } from "./diffout.js";
17
17
  import { type MergeDeps, type MergeResult } from "./merge.js";
18
- import { type PermissionMode, type TaskSpec, type VerifyConfig, type CheckpointToken, type TerminalCause, type ToolSpec, type RepairTerminal, type OracleTier, type RepairResult } from "@sema-agent/core";
18
+ import { type PermissionMode, type ToolPolicy, type TaskSpec, type VerifyConfig, type CheckpointToken, type TerminalCause, type ToolSpec, type RepairTerminal, type OracleTier, type RepairResult } from "@sema-agent/core";
19
19
  import { type UnattendedLegSpec } from "../unattended-permission-mode.js";
20
+ import type { CheckpointStoreFull } from "../plugins/store-backend.js";
21
+ import type { CheckpointCtxSealer } from "../http/checkpoint-ctx.js";
20
22
  /** [ref] Slice 6: drive a worker's resource-suspend auto-resume to a terminal (or bound) state. Exported
21
23
  * for unit tests. Loops `resume(token, slice)` WHILE the result's terminal cause is a park on a
22
24
  * `resource_limit` gate. Exits on: a terminal cause that is not a park, a park on any OTHER gate
@@ -77,13 +79,115 @@ export interface LeaderRunEntry {
77
79
  readonly permissionMode?: PermissionMode;
78
80
  }
79
81
  /**
80
- * leader 车道铸 spec 的**唯一**合并口:spec 的词钳在入口体的词之下(`runtime-governance.ts` `entryPermissionMode(spec 的词, 入口词)` —— 与受理门同一只函数;
81
- * 写进 spec 的值就是它的 `effective`),再交给无人值守腿的合并口(`withUnattendedLeg` 的 `default` 钳在那个词之下)。入口体无词 ⇒ spec 原物交给
82
- * `withUnattendedLeg`,与不经本口逐字同。本车道的 spec 今天自己不带模式词(子任务体只有 objective,其余并进的键是预算 / 审批 / 身份)⇒ 入口词在场时写下的就是它;
83
- * 将来带了词,比入口词松的折回入口词、比它紧的留着 —— 与一条提交体过受理门同一个答案,不另写「写」的规则。五个出生点(worker 首跑的工厂 / 静态两条车道、
84
- * 集成修复、模块门修复、单代理修复环)都调它、不直调 `withUnattendedLeg`(`test/leader-entry-floor.test.ts` 按语法树数调用点):「这条腿的词从哪来」只有入口体一个答案。
82
+ * 一条 leader run 的**出生上下文**:run 出生那一拍定下、本 run 铸的每一条腿都从它取 —— 入口体({@link LeaderRunEntry})、提交者的身份格
83
+ * (`engine-identity.ts` `taskSpecIdentityOf` 的产物,出生时读一次 ALS)、部署治理折叠(装配处闭包活 config 交进来,leader 自己不读 config)。
85
84
  */
86
- export declare function withLeaderLeg<S extends Partial<TaskSpec>>(spec: S, entry: LeaderRunEntry): S & UnattendedLegSpec;
85
+ export interface LeaderBirth {
86
+ readonly entry: LeaderRunEntry;
87
+ /** 提交者的身份格(匿名 ⇒ `{}`:键缺席,与提交腿同一读法)。中心按主体的收紧位、治理窗的锅都按它解。 */
88
+ readonly identity: {
89
+ readonly principal?: string;
90
+ };
91
+ /**
92
+ * 部署治理折叠(`runtime-governance.ts` `applyRuntimeGovernance`,与 `resolveSpec` / 停驻赎回腿同一属主):运维 `AUTONOMY` / `commandPolicy` /
93
+ * `MANUAL_MODE_SHELL_GATE` / 守卫集 tighten-only 盖到 spec 上。`legSessionId` = 这条腿的**槽键**(沙盒车道上守卫按它在槽表里取那台真沙盒):
94
+ * 跑在 worker 执行器上的腿(首跑、模块门修复、单代理修复环)= worker 自己的会话号;集成修复腿 = 它那一轮的会话号(`leader/wire.ts` 按同一个键登记)。
95
+ */
96
+ readonly govern: (spec: TaskSpec, legSessionId: string) => TaskSpec;
97
+ /**
98
+ * 审批基线(`deployment-governance.ts` `createApprovalBaselinePolicy` 的两臂,装配处闭包活 config —— 名单热换对之后出生的腿生效)。出生口按这条腿的
99
+ * {@link LeaderLegDurability} 取一臂:耐久腿 `durable`(问答门 + 三张名单,问由停驻服);不耐久腿 `live`(三张名单,问由这条腿的活席服 —— 即无人值守层:
100
+ * 答得了的按类答,答不了的交回引擎的缺席路,这条腿没有停驻设施 ⇒ 拒)。
101
+ */
102
+ readonly baseline: (seat: "durable" | "live") => ToolPolicy;
103
+ /**
104
+ * 这条腿的 per-model 凭据席(`TaskSpec.getApiKeyAndHeaders`)—— 装配处铸(`boot/leader.ts` 的 `createLeaderLegAuth`:与任务面同一只活引用、与 side-query /
105
+ * WebFetch 摘要面同一只席工厂);leader 自己不碰钥链。**每只执行器出生时调一次**(出生口 {@link withLeaderLeg} 对执行器与腿同拍出生的腿调;planner 路由在它的
106
+ * Runner 构造那一拍调):解钥的那一代在这一拍定下,与这只执行器构造时收下的模型目录同代(目录与钥匙表由中心成对换代 ⇒ 在飞的腿不会把新家的钥发到它目录里的旧家)。
107
+ * 跑在已出生执行器上的腿不再调它,沿用那只执行器的席({@link LeaderLegExecutor})。
108
+ * `upstream` = spec 自带的席:每次调用先问它,它没意见才按模型解(不覆盖)。声明了钥匙却拿不到 ⇒ 席抛(与任务面同一只毒丸),那次调用整体失败,绝不回落网关钥。
109
+ */
110
+ readonly auth: (upstream: TaskSpec["getApiKeyAndHeaders"]) => NonNullable<TaskSpec["getApiKeyAndHeaders"]>;
111
+ }
112
+ /**
113
+ * leader worker 审批停驻行的 scope(唯一属主;保留标识见 `principal-shape.ts` 的 `RESERVED_PRINCIPALS`)。出生口给耐久腿的 `durableApproval` 与
114
+ * 取消时的残留过期(`wire.ts` `createLeaderParkExpirer`)读这同一只。
115
+ */
116
+ export declare const LEADER_APPROVAL_SCOPE = "_leader";
117
+ /** 部署的停驻设施(`LeaderWireConfig.durable` 函数席每次产出的一份;键在场 ⟺ 部署接了停驻店)。 */
118
+ export interface LeaderDurableSeat {
119
+ readonly checkpointStore: CheckpointStoreFull;
120
+ /** [ref]:写 worker 续跑上下文的封口(`ServiceDeps.checkpointCtxSealing` 同一只;规则属主 `http/checkpoint-ctx.ts` 末段「凭据位密封」)。
121
+ * worker 的续跑体只有入口词 + 子任务 objective、不带凭据位 ⇒ 实际不封任何值,但写 ctx 的每一笔都经同一只封口(没有不封的第二种写法)。 */
122
+ readonly ctxSealer: CheckpointCtxSealer | undefined;
123
+ readonly ttlMs?: number;
124
+ }
125
+ /**
126
+ * 出生点陈述的这条腿的事实 ——「停驻决完之后,谁接着做这条腿的工作」:
127
+ * · `replay` —— worker 首跑:留续跑体,决完之后由一条单独的续跑 run(HTTP 续跑腿,照写下的体重放)接着做。`resumeCtx` = 续跑上下文那一笔的结局:
128
+ * `landed` = 写进了出生点递给这条腿的停驻店(`park`);`lost` = 写了、店抛了;`unwritten` = 出生点没递停驻设施 ⇒ 不写。递不递由出生点按车道定:
129
+ * 工厂车道 = 部署接了停驻店即递(环境由 worker 自己的 Runner 经工厂铸,停驻时引擎把可恢复的环境句柄写进检查点,续跑腿经部署工厂按句柄接回同一工作区);
130
+ * 静态车道 = {@link staticLaneWorkerPark}(上一发布版的条件,不按本律)。
131
+ * · `in_run` —— 这条腿的续接是本 run 内存里的那一轮(集成修复、模块门修复、单代理修复环):一条单独续跑的 run 交不回去。
132
+ */
133
+ export type LeaderLegFacts = {
134
+ readonly continuation: "replay";
135
+ readonly resumeCtx: "landed";
136
+ readonly park: LeaderDurableSeat;
137
+ } | {
138
+ readonly continuation: "replay";
139
+ readonly resumeCtx: "lost" | "unwritten";
140
+ } | {
141
+ readonly continuation: "in_run";
142
+ };
143
+ /** 一条腿的耐久事实({@link leaderLegDurability} 的产物)。`transient.why` 是给运维的那一句(资源分片停驻不生效的告警原因读它)。 */
144
+ export type LeaderLegDurability = {
145
+ readonly kind: "durable";
146
+ readonly park: LeaderDurableSeat;
147
+ } | {
148
+ readonly kind: "transient";
149
+ readonly why: string;
150
+ };
151
+ /**
152
+ * **一条 leader 腿的耐久事实 —— 唯一读者**。耐久 ⇔ 这条腿由单独的续跑 run 接续 ∧ 它的续跑上下文真落进了出生点递给它的停驻店(没落 ⇒ 停出来的卡
153
+ * 决的时候重建不了这条腿 ⇒ 不耐久)。四个调用点:worker 首跑(工厂 / 静态两条车道共一次)、集成修复、模块门修复、单代理修复环;出生口({@link withLeaderLeg})
154
+ * 按它盖审批基线与停驻设施,worker 首跑按它保温续跑上下文、开资源分片停驻。主车道没有握在手里的环境(它的每一只环境都由工厂铸,环境能不能停驻由引擎读),
155
+ * 所以「递不递停驻设施」这一问只在本车道有。
156
+ */
157
+ export declare function leaderLegDurability(leg: LeaderLegFacts): LeaderLegDurability;
158
+ /**
159
+ * 静态车道 worker 递不递停驻设施 —— **上一发布版的条件原样**:部署接了停驻店 ∧ 任一审批名单在场(每只 worker 现读)。只此一处,worker 首跑的出生点调它一次。
160
+ * 不按 {@link leaderLegDurability} 的律(工厂车道「店在即递」)判:这条车道上两种停驻的续接路不同 —— 资源分片停驻由 leader 在进程内同一只执行器上续(续得上);
161
+ * 审批停驻的赎回走 HTTP 续跑腿、经部署工厂另铸执行环境(worker 的沙盒握在 leader 手里,检查点里没有它的句柄 ⇒ 续不上)。引擎今天只有「给不给停驻店」一个开关,
162
+ * 两种停驻拆不开:照「店在即递」会比上一版多出几种部署形停出决完落新执行环境的卡,照「续不上就不递」又关掉上一版就工作的资源分片停驻 ⇒ 沿用上一版的条件。
163
+ * 已知缺陷(上一版同形,随包文书同句披露):名单在 × 店在时审批问停驻,决完的续跑落在新执行环境上。引擎提供「宿主声明本腿审批停驻不可续」的声明位后,
164
+ * 本条件退役、静态车道并回本读者的律(店在即递 + 声明审批停驻不可续:资源分片照停,审批问不走停驻)。
165
+ */
166
+ export declare function staticLaneWorkerPark(park: LeaderDurableSeat | undefined, approvalListInForce: boolean): LeaderDurableSeat | undefined;
167
+ /**
168
+ * 这条腿跑在哪只执行器上 —— **凭据代随执行器**:执行器构造时把模型目录收成私有副本,这条腿的钥取同一代(否则中心换代之后,新一代的钥会配上旧一代目录里的端点)。
169
+ * · `fresh` —— 执行器与这条腿同拍出生(worker 首跑的工厂 / 静态两条车道、集成修复):出生口此刻从出生上下文取一只席({@link LeaderBirth.auth},折 spec 自带的那一只);
170
+ * · `reuses` —— 腿跑在一只已经出生的 worker 执行器上(模块门修复、单代理修复环):沿用那只 worker 首跑 spec 上的席(它经出生口 `fresh` 出生,已折过子任务自带的席),不再取一代。
171
+ */
172
+ export type LeaderLegExecutor = {
173
+ readonly kind: "fresh";
174
+ } | {
175
+ readonly kind: "reuses";
176
+ readonly worker: Pick<ProvisionedWorker, "spec">;
177
+ };
178
+ /** 出生口收的这条腿:槽键(见 {@link LeaderBirth.govern})+ 耐久事实(见 {@link leaderLegDurability})+ 执行器(凭据代,见 {@link LeaderLegExecutor})。 */
179
+ export interface LeaderLeg {
180
+ readonly slotKey: string;
181
+ readonly durability: LeaderLegDurability;
182
+ readonly executor: LeaderLegExecutor;
183
+ }
184
+ /**
185
+ * leader 车道铸 spec 的**唯一**出生口。顺序即语义:身份格 + 凭据席(随执行器的那一代,{@link LeaderLegExecutor})+ 审批基线与停驻设施(按这条腿的耐久事实)→ 部署治理折叠(同属主,tighten-only 叠在基线上)→
186
+ * 入口词(spec 的词钳在入口体的词之下,`runtime-governance.ts` `entryPermissionMode` —— 与受理门同一只函数)→ 无人值守腿(`withUnattendedLeg` 头注要求它在
187
+ * 治理折叠**之后**)。首跑、修复腿与停驻后的续跑腿(续跑腿经 `resolveSpec` 折同一只治理)因此同一读法。五个出生点(worker 首跑的工厂 / 静态两条车道、
188
+ * 集成修复、模块门修复、单代理修复环)都调它、不直调 `withUnattendedLeg`、不各自盖身份或基线(`test/leader-entry-floor.test.ts` 按语法树数调用点)。
189
+ */
190
+ export declare function withLeaderLeg(spec: TaskSpec, birth: LeaderBirth, leg: LeaderLeg): TaskSpec & UnattendedLegSpec;
87
191
  export interface LeaderDeps {
88
192
  /**
89
193
  * 本 run 的中止信号(取消口 / 陈旧裁决;HTTP 驱动腿恒给,`endpoint.ts` 的 `drive`)。与 core `TaskSpec.signal` 同一约定:缺席 = 不可外部取消(单测 / bench 形)。
@@ -91,9 +195,9 @@ export interface LeaderDeps {
91
195
  * 不再起任何新的计费工作;在跑的腿经 spec 的同一根信号中止(fan-out 共享信号 / 修复腿 / 单代理修复环);合并在 push 咽喉前再核一次(`merge.ts`)。
92
196
  */
93
197
  signal?: AbortSignal;
94
- /** 本 run 的入口体({@link LeaderRunEntry}:运维地板在 run 出生时盖一次)。必填:没有地板的装配写 `{}` —— 缺席不是「没有地板」的合法拼法。
95
- * 模块门修复与单代理修复环这两个出生点从这里取词(经 {@link withLeaderLeg})。 */
96
- entry: LeaderRunEntry;
198
+ /** 本 run 的出生上下文({@link LeaderBirth}:入口体 + 身份格 + 治理折叠,run 出生时定一次)。必填:没有地板的装配写 `entry: {}` —— 缺席不是「没有地板」的合法拼法。
199
+ * 模块门修复与单代理修复环这两个出生点从这里出生(经 {@link withLeaderLeg})。 */
200
+ birth: LeaderBirth;
97
201
  /** Plan a task into N disjoint-file sub-tasks (MVP: simple/hand-authored; adaptive replan = scale). */
98
202
  plan: (task: string) => Promise<SubtaskSpec[]>;
99
203
  /** Provision a leader-owned worker (its env seeded with base at `branch` + an env-bound runner). */
@@ -2,8 +2,9 @@ import { fanOut } from "./fanout.js";
2
2
  import { redactErrorMessage, redactHead } from "../observability/run-terminal.js";
3
3
  import { pullDiff } from "./diffout.js";
4
4
  import { mergeBranches } from "./merge.js";
5
- import { Runner, runWithVerification, resumeWithVerification } from "@sema-agent/core";
5
+ import { Runner, QUESTION_AWAITS_RESUME, runWithVerification, resumeWithVerification } from "@sema-agent/core";
6
6
  import { pausedCauseOf, outwardPlane } from "../terminal.js";
7
+ import { seatText } from "../trace/exit-seat.js";
7
8
  import { voidVerifierPauseCard } from "../verifier-pause-card.js";
8
9
  import { entryPermissionMode } from "../runtime-governance.js";
9
10
  import { withUnattendedLeg } from "../unattended-permission-mode.js";
@@ -18,9 +19,68 @@ export async function autoResumeOnResource(initial, signal, resume, maxSlices =
18
19
  }
19
20
  return vr;
20
21
  }
21
- export function withLeaderLeg(spec, entry) {
22
- const word = entryPermissionMode(spec.permissionMode, entry.permissionMode).effective;
23
- return withUnattendedLeg(word === undefined ? spec : { ...spec, permissionMode: word });
22
+ export const LEADER_APPROVAL_SCOPE = "_leader";
23
+ export function leaderLegDurability(leg) {
24
+ switch (leg.continuation) {
25
+ case "in_run":
26
+ return { kind: "transient", why: "this leg is continued by the leader's own in-run repair round, which a separately resumed run cannot hand its result back to" };
27
+ case "replay":
28
+ switch (leg.resumeCtx) {
29
+ case "landed":
30
+ return { kind: "durable", park: leg.park };
31
+ case "lost":
32
+ return { kind: "transient", why: "the worker's resume context did not land in the checkpoint store, so a decided park could not rebuild this leg" };
33
+ case "unwritten":
34
+ return { kind: "transient", why: "no park facility for this worker (no durable checkpoint store; on the static lane, no approval list in force either)" };
35
+ default: {
36
+ const unhandled = leg;
37
+ throw new Error(`leader leg resume context ${JSON.stringify(unhandled)} has no durability arm`);
38
+ }
39
+ }
40
+ default: {
41
+ const unhandled = leg;
42
+ throw new Error(`leader leg facts ${JSON.stringify(unhandled)} have no durability arm`);
43
+ }
44
+ }
45
+ }
46
+ export function staticLaneWorkerPark(park, approvalListInForce) {
47
+ return approvalListInForce ? park : undefined;
48
+ }
49
+ function legAuthSeat(spec, birth, executor) {
50
+ switch (executor.kind) {
51
+ case "fresh":
52
+ return birth.auth(spec.getApiKeyAndHeaders);
53
+ case "reuses":
54
+ return executor.worker.spec.getApiKeyAndHeaders;
55
+ default: {
56
+ const unhandled = executor;
57
+ throw new Error(`leader leg executor ${JSON.stringify(unhandled)} has no credential seat`);
58
+ }
59
+ }
60
+ }
61
+ function legApprovalSeat(durability, birth) {
62
+ switch (durability.kind) {
63
+ case "durable": {
64
+ const d = durability;
65
+ return {
66
+ toolPolicy: birth.baseline("durable"),
67
+ checkpointStore: d.park.checkpointStore,
68
+ durableApproval: { scope: LEADER_APPROVAL_SCOPE, ...(d.park.ttlMs ? { ttlMs: d.park.ttlMs } : {}) },
69
+ onQuestion: QUESTION_AWAITS_RESUME,
70
+ };
71
+ }
72
+ case "transient":
73
+ return { toolPolicy: birth.baseline("live") };
74
+ default: {
75
+ const unhandled = durability;
76
+ throw new Error(`leader leg durability ${JSON.stringify(unhandled)} has no approval seat`);
77
+ }
78
+ }
79
+ }
80
+ export function withLeaderLeg(spec, birth, leg) {
81
+ const governed = birth.govern({ ...spec, ...birth.identity, getApiKeyAndHeaders: legAuthSeat(spec, birth, leg.executor), ...legApprovalSeat(leg.durability, birth) }, leg.slotKey);
82
+ const word = entryPermissionMode(governed.permissionMode, birth.entry.permissionMode).effective;
83
+ return withUnattendedLeg(word === undefined ? governed : { ...governed, permissionMode: word });
24
84
  }
25
85
  export const LEADER_RUN_STOPPED = "leader run stopped at an abort checkpoint (cancel): no further work was started and nothing was pushed after the stop";
26
86
  export function stoppedResult(reports, route) {
@@ -230,7 +290,11 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
230
290
  }
231
291
  deps.logger?.info?.("module_repair", { workerId: r.workerId, attempt: attempt + 1, reason: redactHead(verdict.reason ?? "", 500) });
232
292
  try {
233
- const rr = await w.runner.runTaskStream(withLeaderLeg({ ...sub.spec, objective: deps.moduleGate.repairObjective(sub, safeVerdictReason), sessionId: `${w.sessionId}-r${attempt + 1}`, ...(signal ? { signal } : {}) }, deps.entry)).result();
293
+ const rr = await w.runner.runTaskStream(withLeaderLeg({ ...sub.spec, objective: deps.moduleGate.repairObjective(sub, safeVerdictReason), sessionId: `${w.sessionId}-r${attempt + 1}`, ...(signal ? { signal } : {}) }, deps.birth, { slotKey: w.sessionId, durability: leaderLegDurability({ continuation: "in_run" }), executor: { kind: "reuses", worker: w } })).result();
294
+ if (rr !== undefined && rr.terminal.kind !== "completed") {
295
+ const plane = outwardPlane(rr.terminal);
296
+ deps.logger?.warn?.("module_repair_incomplete", { workerId: r.workerId, attempt: attempt + 1, status: plane.status, ...(plane.errorMessage !== undefined ? { err: seatText("operator-log-error", plane.errorMessage) } : {}) });
297
+ }
234
298
  if (r.stats && rr?.stats)
235
299
  r.stats = { ...r.stats, tokens: (r.stats.tokens ?? 0) + (rr.stats.tokens ?? 0), costMicroUsd: (r.stats.costMicroUsd ?? 0) + (rr.stats.costMicroUsd ?? 0) };
236
300
  }
@@ -1,6 +1,6 @@
1
1
  import { runRepairLoop, delimitUntrusted, } from "@sema-agent/core";
2
2
  import { mkRepairOracle } from "./repair-oracle.js";
3
- import { withLeaderLeg } from "./leader.js";
3
+ import { leaderLegDurability, withLeaderLeg } from "./leader.js";
4
4
  import { outwardPlane } from "../terminal.js";
5
5
  import { redactHead } from "../observability/run-terminal.js";
6
6
  function statusForTerminal(t) {
@@ -87,7 +87,7 @@ export function attachRepairLoopDeps(deps, resolve) {
87
87
  deps.repairLoop = {
88
88
  run: async (solo, sub) => {
89
89
  const cfg = await resolve(solo, sub);
90
- const implSpec = withLeaderLeg({ ...sub.spec, sessionId: solo.sessionId, ...(deps.signal ? { signal: deps.signal } : {}) }, deps.entry);
90
+ const implSpec = withLeaderLeg({ ...sub.spec, sessionId: solo.sessionId, ...(deps.signal ? { signal: deps.signal } : {}) }, deps.birth, { slotKey: solo.sessionId, durability: leaderLegDurability({ continuation: "in_run" }), executor: { kind: "reuses", worker: solo } });
91
91
  return runRepairLoopForLeader(solo, implSpec, cfg);
92
92
  },
93
93
  };
@@ -16,7 +16,8 @@ import { type Autonomy } from "../runtime-governance.js";
16
16
  import type { LeaderRunEntry } from "./leader.js";
17
17
  /** 一条 leader run 的入口体:地板读一次、入口词经受理门同一只函数(地板缺席 ⇒ `{}`)。调用方读**活** config(热改只影响之后起的 run)。 */
18
18
  export declare function leaderRunEntry(autonomy: Autonomy | undefined): LeaderRunEntry;
19
- /** 拒句:原因(运维的 plan 地板 × 这条车道没有计划审阅通道)+ 两条出路(改走有计划审阅的 run 车道 / 运维换档)。不含任何配置值之外的回显。
19
+ /** 拒句:原因(运维的 plan 地板 × 这条车道没有计划审阅通道)+ 两条出路(改走有计划审阅的 run 车道 / 运维换到 `ask` 档,代价写在句里)。`read-only` 不是出路:
20
+ * 部署治理折叠盖在 leader 每条腿的出生口上,`read-only` 下 worker 写不了。不含任何配置值之外的回显。
20
21
  * 受理口(HTTP 422 的 `error`)与 run 出生处(run 的 `error`)读的是这一份;字节由 `test/api-error-text-freeze.test.ts` 的常量锚格冻。 */
21
22
  export declare const LEADER_PLAN_ENTRY_REFUSAL: string;
22
23
  /**
@@ -6,7 +6,7 @@ export function leaderRunEntry(autonomy) {
6
6
  export const LEADER_PLAN_ENTRY_REFUSAL = "this deployment runs with AUTONOMY=plan, which starts every task in plan mode and lets it out of plan mode only when a person approves its plan through plan review; " +
7
7
  "a leader task's workers have no plan review channel, so they could neither write nor hand their plan to anyone who can approve it. Nothing was started. " +
8
8
  "Submit the work as a run instead (POST /v1/runs, whose plan is reviewed through POST /v1/assistant/tasks/:id/plan_review), " +
9
- "or ask the operator to set AUTONOMY=read-only or AUTONOMY=ask, under which leader tasks run.";
9
+ "or ask the operator to set AUTONOMY=ask, under which leader tasks run, though each shell command a worker runs then needs a person's approval.";
10
10
  export function leaderEntryRefusal(entry) {
11
11
  const mode = entry.permissionMode;
12
12
  if (mode === undefined)