@sema-agent/server 7.43.0 → 7.44.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 (345) hide show
  1. package/USAGE.md +18 -0
  2. package/dist/adoption/plan.js +31 -192
  3. package/dist/adoption/quiesce.js +3 -86
  4. package/dist/adoption/runner.js +3 -140
  5. package/dist/adoption/sql.js +0 -74
  6. package/dist/adoption/wire.js +0 -80
  7. package/dist/approval-ask-machine.js +0 -75
  8. package/dist/approval-card.js +0 -323
  9. package/dist/approval-deny-reasons.js +0 -42
  10. package/dist/approval-hmac.js +0 -35
  11. package/dist/approval-reconciler.js +8 -166
  12. package/dist/approval.js +4 -67
  13. package/dist/audit.js +1 -44
  14. package/dist/auth-bridge.js +4 -47
  15. package/dist/auth-keys.js +0 -23
  16. package/dist/bake-runner/main.js +4 -65
  17. package/dist/bake-runner/protocol.js +3 -58
  18. package/dist/bake-runner/runner.js +5 -91
  19. package/dist/bench/l8/artifact.js +2 -61
  20. package/dist/bench/l8/escape.js +0 -25
  21. package/dist/bench/l8/index.js +0 -14
  22. package/dist/bench/l8/probes.js +0 -60
  23. package/dist/bench/l8/run-probes.js +2 -45
  24. package/dist/bench/s1/arms.js +14 -189
  25. package/dist/bench/s1/live-deps.js +11 -253
  26. package/dist/bench/s1/oracle.js +1 -36
  27. package/dist/bench/s1/repair-oracle-adapter.js +0 -30
  28. package/dist/bench/s1/reviewer.js +0 -34
  29. package/dist/bench/s1/row.js +0 -62
  30. package/dist/bench/s1/run-firm.js +4 -70
  31. package/dist/bench/s1/runner-ctx.js +0 -40
  32. package/dist/bench/s1/tasks.js +0 -115
  33. package/dist/boot/adoption.js +0 -20
  34. package/dist/boot/budget-tracing.js +3 -55
  35. package/dist/boot/config-center.js +43 -551
  36. package/dist/boot/coordinators.js +1 -69
  37. package/dist/boot/crash-last.js +0 -18
  38. package/dist/boot/deferred-sandbox-path-env.js +3 -119
  39. package/dist/boot/execution-env.js +5 -171
  40. package/dist/boot/governance-seams.js +0 -92
  41. package/dist/boot/leader.js +0 -69
  42. package/dist/boot/limit-sync.js +0 -2
  43. package/dist/boot/memory-boundary.js +3 -91
  44. package/dist/boot/org-memory.js +1 -25
  45. package/dist/boot/parked-revive-gate.js +0 -150
  46. package/dist/boot/permission-rules-audit.js +1 -56
  47. package/dist/boot/reapers.js +15 -273
  48. package/dist/boot/resolve-spec.js +9 -768
  49. package/dist/boot/retention-lane.js +4 -87
  50. package/dist/boot/runner-deps.js +3 -297
  51. package/dist/boot/runtime-caps.js +0 -40
  52. package/dist/boot/session-faces.js +2 -133
  53. package/dist/boot/shutdown.js +9 -83
  54. package/dist/boot/side-query-lane.js +2 -137
  55. package/dist/boot/stores.js +15 -215
  56. package/dist/boot/task-list-lane.js +0 -18
  57. package/dist/boot/webfetch-summarize-lane.js +0 -47
  58. package/dist/boot/workflow-orchestration.js +3 -99
  59. package/dist/boot-reclaim.js +0 -20
  60. package/dist/bounded-session-map.js +0 -19
  61. package/dist/brain.js +2 -139
  62. package/dist/budget.js +9 -244
  63. package/dist/capabilities/builtin-tools.js +0 -3
  64. package/dist/capabilities/center-plugins.js +6 -51
  65. package/dist/capabilities/center-prompts.js +6 -71
  66. package/dist/capabilities/code-review-council.js +7 -40
  67. package/dist/capabilities/collab-workflows.js +1 -44
  68. package/dist/capabilities/hands-lane.js +0 -65
  69. package/dist/capabilities/memory-notice.js +0 -70
  70. package/dist/capabilities/prompt.js +0 -14
  71. package/dist/capabilities/prompts/code-review.js +0 -14
  72. package/dist/capabilities/prompts/identity.js +0 -6
  73. package/dist/capabilities/prompts/team.js +0 -4
  74. package/dist/capabilities/repo-tools.js +0 -34
  75. package/dist/capabilities/sandbox-file-send.js +3 -92
  76. package/dist/capabilities/scenarios.d.ts +0 -1
  77. package/dist/capabilities/scenarios.js +18 -279
  78. package/dist/capabilities/select-environment-tool.js +0 -32
  79. package/dist/capabilities/send-user-file-tool.js +2 -66
  80. package/dist/capabilities/skills.d.ts +1 -2
  81. package/dist/capabilities/skills.js +3 -21
  82. package/dist/capabilities/team.d.ts +3 -11
  83. package/dist/capabilities/team.js +3 -51
  84. package/dist/capabilities/tool-defer.js +0 -3
  85. package/dist/config-center/apply-effective.js +15 -330
  86. package/dist/config-center/apply-ledger.js +5 -38
  87. package/dist/config-center/facade.js +0 -41
  88. package/dist/config-center/hot-keys-registry.js +0 -20
  89. package/dist/config-center/http-client.js +2 -125
  90. package/dist/config-center/mcp-revocation.js +2 -34
  91. package/dist/config-center/read-face.js +0 -59
  92. package/dist/config-center/restart-signal.js +1 -85
  93. package/dist/config-center/skills-mcp.d.ts +1 -1
  94. package/dist/config-center/skills-mcp.js +9 -76
  95. package/dist/config-center/stage-limits.js +8 -35
  96. package/dist/config-invariants.js +0 -16
  97. package/dist/config-lkg.js +0 -42
  98. package/dist/config-provider.js +3 -186
  99. package/dist/config-types.js +0 -5
  100. package/dist/config.js +107 -1145
  101. package/dist/degenerate-instrument.js +3 -67
  102. package/dist/deployment-governance.js +0 -124
  103. package/dist/digest-form.js +0 -12
  104. package/dist/elicitation.js +3 -86
  105. package/dist/env-facts.js +7 -75
  106. package/dist/fleet/fleet-bus.js +34 -507
  107. package/dist/fleet/fleet-reconciler.js +9 -149
  108. package/dist/fleet/fleet-terminal-window.js +10 -178
  109. package/dist/fleet/subagent-tail-bus.js +3 -72
  110. package/dist/fleet-client.js +10 -70
  111. package/dist/fleet-lease.js +5 -79
  112. package/dist/git-api-kind.js +0 -3
  113. package/dist/governance-ask-marks.js +2 -78
  114. package/dist/hooks/branch-transcript.js +0 -74
  115. package/dist/hooks/cc-agent-hook-prompt.js +0 -29
  116. package/dist/hooks/cc-stop-prompt.js +1 -46
  117. package/dist/hooks/hook-llm.js +1 -53
  118. package/dist/hooks/hook-runner.js +20 -414
  119. package/dist/http/active-run-conflict.js +4 -129
  120. package/dist/http/cursor-fingerprint.d.ts +5 -0
  121. package/dist/http/cursor-fingerprint.js +5 -0
  122. package/dist/http/idempotency.js +0 -37
  123. package/dist/http/principal-gate.js +3 -40
  124. package/dist/http/route-ctx.js +0 -9
  125. package/dist/http/routes/a2a-serve.js +7 -319
  126. package/dist/http/routes/admin-config-refresh.js +0 -4
  127. package/dist/http/routes/admin-drain.js +0 -10
  128. package/dist/http/routes/adoption.js +1 -29
  129. package/dist/http/routes/agents-roster.js +1 -47
  130. package/dist/http/routes/approvals-assistant.js +32 -395
  131. package/dist/http/routes/attachments.js +4 -22
  132. package/dist/http/routes/capabilities.js +3 -420
  133. package/dist/http/routes/diagnostics.js +1 -81
  134. package/dist/http/routes/fleet.js +9 -185
  135. package/dist/http/routes/images.js +14 -239
  136. package/dist/http/routes/leader.js +0 -13
  137. package/dist/http/routes/memory-bundle.js +1 -61
  138. package/dist/http/routes/memory-policy.js +9 -99
  139. package/dist/http/routes/notify-wake.js +3 -37
  140. package/dist/http/routes/observability.js +2 -19
  141. package/dist/http/routes/retention-ops.js +2 -34
  142. package/dist/http/routes/rules.js +1 -93
  143. package/dist/http/routes/runs.js +64 -873
  144. package/dist/http/routes/session-sync.js +19 -258
  145. package/dist/http/routes/sessions-list.js +17 -43
  146. package/dist/http/routes/sessions.js +34 -226
  147. package/dist/http/routes/shared-memory.js +5 -36
  148. package/dist/http/routes/side-query.js +1 -87
  149. package/dist/http/routes/tasks.js +52 -722
  150. package/dist/http/routes/trace-usage.js +32 -195
  151. package/dist/http/routes/workflows.js +19 -195
  152. package/dist/http/run-meta.js +0 -6
  153. package/dist/http/send.js +0 -32
  154. package/dist/http/server.js +92 -1597
  155. package/dist/http/sse-lifecycle.js +2 -13
  156. package/dist/http/sse-log.js +3 -48
  157. package/dist/http/tar.js +5 -21
  158. package/dist/http/verify-rounds.js +0 -5
  159. package/dist/http/wire-gate.js +0 -9
  160. package/dist/http/workspace-content.js +0 -10
  161. package/dist/images/bake-validate.js +1 -70
  162. package/dist/images/manifest.js +1 -6
  163. package/dist/index.js +0 -21
  164. package/dist/key-resolver.js +2 -17
  165. package/dist/leader/diffout.js +1 -20
  166. package/dist/leader/diffup.js +0 -47
  167. package/dist/leader/endpoint.js +2 -57
  168. package/dist/leader/fanout.js +3 -45
  169. package/dist/leader/grader-env-factory.js +3 -72
  170. package/dist/leader/leader.js +5 -156
  171. package/dist/leader/merge.js +8 -115
  172. package/dist/leader/planner.js +3 -54
  173. package/dist/leader/repair-oracle.js +1 -60
  174. package/dist/leader/repair-wire.js +2 -79
  175. package/dist/leader/wire.js +8 -307
  176. package/dist/lsp/e2b-bridge.js +4 -64
  177. package/dist/lsp/e2b-manager.js +6 -94
  178. package/dist/lsp/lsp-frames.js +0 -12
  179. package/dist/lsp/manager.js +4 -96
  180. package/dist/lsp/ws-transport.js +5 -55
  181. package/dist/lsp-evict.js +1 -15
  182. package/dist/main.js +57 -765
  183. package/dist/memory-bundle-engine.js +0 -55
  184. package/dist/memory-export.js +0 -4
  185. package/dist/memory-posture.js +1 -15
  186. package/dist/memory-scope.js +11 -148
  187. package/dist/memory-sync-client.js +2 -44
  188. package/dist/memory-sync.js +1 -80
  189. package/dist/model-select.js +3 -80
  190. package/dist/observability/cost-quota.js +1 -17
  191. package/dist/observability/cost-taxonomy.js +0 -34
  192. package/dist/observability/fail-open.js +7 -86
  193. package/dist/observability/logger.js +0 -6
  194. package/dist/observability/metrics.js +0 -94
  195. package/dist/observability/otel-exporter.js +3 -13
  196. package/dist/observability/principal-context.js +0 -9
  197. package/dist/observability/prompt-manifest.js +1 -37
  198. package/dist/observability/rate-limit.js +0 -4
  199. package/dist/observability/secret-env-scrub.js +2 -56
  200. package/dist/observability/tool-trace.js +1 -70
  201. package/dist/orchestration/hardened-vm-runner.js +4 -118
  202. package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
  203. package/dist/orchestration/hardened-vm-worker.js +0 -27
  204. package/dist/orchestration/subagent-steer.js +1 -45
  205. package/dist/orchestration/workflow-agent-steer.js +1 -80
  206. package/dist/orchestration/workflow-completion-inbox.js +32 -285
  207. package/dist/orchestration/workflow-notify-journal.js +16 -259
  208. package/dist/org-memory-admission.js +3 -47
  209. package/dist/parent-watch.js +2 -48
  210. package/dist/parked-decide.js +1 -109
  211. package/dist/per-task-image.js +0 -57
  212. package/dist/plan-cache-probe.js +3 -27
  213. package/dist/plugins/adoption-log-sql.js +2 -119
  214. package/dist/plugins/approval-ask-store-memory.js +3 -38
  215. package/dist/plugins/approval-ask-store-sql.js +6 -188
  216. package/dist/plugins/approval-exemption-store.js +2 -28
  217. package/dist/plugins/background-agent-store-sql.js +4 -105
  218. package/dist/plugins/background-shell-support.js +14 -122
  219. package/dist/plugins/blob-backend.js +6 -169
  220. package/dist/plugins/breaker-state-sql.js +8 -46
  221. package/dist/plugins/caching-session-store.js +4 -106
  222. package/dist/plugins/checkpoint-store-sql.js +18 -505
  223. package/dist/plugins/e2b-orphan-reclaim.js +0 -45
  224. package/dist/plugins/file-outcome-sink.js +0 -9
  225. package/dist/plugins/file-resume-anchor-store.js +4 -43
  226. package/dist/plugins/file-run-store.js +26 -364
  227. package/dist/plugins/file-snapshot-store-sql.js +10 -181
  228. package/dist/plugins/fork-routing-session-store.js +8 -111
  229. package/dist/plugins/host-platform.js +2 -91
  230. package/dist/plugins/image-bake-store-sql.js +7 -250
  231. package/dist/plugins/image-index-sql.js +4 -123
  232. package/dist/plugins/k8s-bg-scripts.js +4 -88
  233. package/dist/plugins/k8s-exec-protocol.js +0 -41
  234. package/dist/plugins/leader-run-store-sql.js +0 -101
  235. package/dist/plugins/local-checkpoint-store.js +8 -128
  236. package/dist/plugins/local-session-store.js +34 -296
  237. package/dist/plugins/local-task-attachment-store.js +2 -16
  238. package/dist/plugins/mailbox-store-sql.js +8 -65
  239. package/dist/plugins/memory-embedder-fingerprint.js +5 -166
  240. package/dist/plugins/memory-embedder.js +4 -70
  241. package/dist/plugins/memory-engine-pg.js +6 -170
  242. package/dist/plugins/memory-engine-tidb.js +7 -155
  243. package/dist/plugins/memory-engine-vector-util.js +0 -10
  244. package/dist/plugins/memory-key-guards.js +0 -34
  245. package/dist/plugins/memory-origin-law.js +0 -187
  246. package/dist/plugins/memory-resume-anchor-store.js +0 -17
  247. package/dist/plugins/memory-run-store.js +12 -89
  248. package/dist/plugins/memory-session-policy-store.js +0 -17
  249. package/dist/plugins/memory-sync-store-pg.js +4 -49
  250. package/dist/plugins/memory-sync-store-tidb.js +3 -35
  251. package/dist/plugins/outcome-ledger-sql.js +3 -97
  252. package/dist/plugins/permission-rule-store-file.js +5 -133
  253. package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
  254. package/dist/plugins/permission-rule-store-sql.js +50 -307
  255. package/dist/plugins/pg-cost-quota.js +0 -7
  256. package/dist/plugins/pg-pool.js +0 -92
  257. package/dist/plugins/pg-rate-limiter.js +2 -13
  258. package/dist/plugins/pg-safe-json.js +4 -40
  259. package/dist/plugins/pg-session-storage.js +25 -189
  260. package/dist/plugins/posix-shell-fs.js +1 -31
  261. package/dist/plugins/remote-env-adb.js +12 -101
  262. package/dist/plugins/remote-env-e2b.js +40 -371
  263. package/dist/plugins/remote-env-file-error.js +0 -37
  264. package/dist/plugins/remote-env-host.js +63 -483
  265. package/dist/plugins/remote-env-k8s.js +32 -326
  266. package/dist/plugins/remote-env-local-docker.js +24 -157
  267. package/dist/plugins/remote-env-ssh.js +20 -128
  268. package/dist/plugins/remote-scratchpad.js +2 -32
  269. package/dist/plugins/remote-shell.js +1 -32
  270. package/dist/plugins/resume-anchor-store-sql.js +0 -11
  271. package/dist/plugins/retention-lane-store-sql.js +0 -108
  272. package/dist/plugins/retention-store-sql.js +4 -383
  273. package/dist/plugins/roster-store-sql.js +0 -55
  274. package/dist/plugins/run-store-sql.js +14 -251
  275. package/dist/plugins/s3-presign.js +2 -49
  276. package/dist/plugins/scheduler-support.js +3 -80
  277. package/dist/plugins/send-file-ledger.js +4 -53
  278. package/dist/plugins/send-user-file.js +4 -94
  279. package/dist/plugins/session-placement.js +1 -89
  280. package/dist/plugins/session-policy-store-sql.js +3 -81
  281. package/dist/plugins/session-store.js +0 -57
  282. package/dist/plugins/shared-memory-store-sql.js +4 -167
  283. package/dist/plugins/sql-driver.js +0 -17
  284. package/dist/plugins/sql-errors.js +0 -7
  285. package/dist/plugins/sql-escape.js +0 -8
  286. package/dist/plugins/sql-row-helpers.js +0 -25
  287. package/dist/plugins/store-backend.js +42 -222
  288. package/dist/plugins/store-contracts.js +2 -46
  289. package/dist/plugins/task-attachment-store.js +3 -49
  290. package/dist/plugins/task-list-store-sql.js +0 -79
  291. package/dist/plugins/tidb-cost-quota.js +1 -4
  292. package/dist/plugins/tidb-pool.js +1 -207
  293. package/dist/plugins/tidb-rate-limiter.js +3 -9
  294. package/dist/plugins/tidb-session-storage.js +4 -70
  295. package/dist/plugins/tidb-session-store.js +19 -341
  296. package/dist/plugins/tool-result-store-sql.js +4 -179
  297. package/dist/plugins/usage-window-store-sql.js +0 -8
  298. package/dist/plugins/web-search.js +10 -132
  299. package/dist/plugins/workflow-journal-store-sql.js +2 -58
  300. package/dist/plugins/workflow-run-store-sql.js +6 -91
  301. package/dist/plugins/worktree-isolation.js +6 -126
  302. package/dist/plugins/write-behind-counter.js +16 -75
  303. package/dist/principal-jwt.js +5 -60
  304. package/dist/project-memory.js +15 -146
  305. package/dist/prompts-domain-validate.js +1 -51
  306. package/dist/question.js +2 -111
  307. package/dist/resource-suspend.js +0 -18
  308. package/dist/router/route-orchestration.js +0 -77
  309. package/dist/rules-consent.d.ts +44 -5
  310. package/dist/rules-consent.js +75 -215
  311. package/dist/run-local.js +14 -381
  312. package/dist/runs.js +29 -617
  313. package/dist/runtime-caps-resolver.js +6 -132
  314. package/dist/runtime-governance.js +1 -232
  315. package/dist/sandbox-pkg-source.js +0 -37
  316. package/dist/sealed-key.js +3 -68
  317. package/dist/security.js +6 -291
  318. package/dist/session-leaf-bus.js +0 -32
  319. package/dist/session-sync-content.js +1 -69
  320. package/dist/session-sync-kernel.js +3 -60
  321. package/dist/session-sync.js +3 -66
  322. package/dist/session-titler.js +7 -41
  323. package/dist/session-watch.js +9 -73
  324. package/dist/shared-memory-scope-authorizer.js +0 -18
  325. package/dist/sighup-idle.js +1 -12
  326. package/dist/spec-fields.js +4 -143
  327. package/dist/store-live-probe.js +3 -49
  328. package/dist/task-a2a.js +1 -126
  329. package/dist/task-cwd.js +1 -103
  330. package/dist/task-mcp.js +1 -89
  331. package/dist/task-settings.js +10 -300
  332. package/dist/task-workflow.js +8 -75
  333. package/dist/tool-approval.d.ts +28 -1
  334. package/dist/tool-approval.js +70 -1430
  335. package/dist/trace/artifacts.js +5 -20
  336. package/dist/trace/engine-notice-wire.js +6 -138
  337. package/dist/trace/ledger-sink.js +7 -96
  338. package/dist/trace/project.js +4 -448
  339. package/dist/trace/redact.js +9 -77
  340. package/dist/turn-activity.js +1 -27
  341. package/dist/usage-analytics.js +4 -34
  342. package/dist/wall-clock-jump-guard.js +1 -68
  343. package/package.json +3 -3
  344. package/dist/capabilities/scenario-alias.d.ts +0 -27
  345. package/dist/capabilities/scenario-alias.js +0 -61
@@ -1,9 +1,3 @@
1
- /**
2
- * Sema identity — the branded role layer for the `default` scenario (bundle-data layer; wording
3
- * history: neutralized — no baked model/vendor/protocol facts, because the brain
4
- * stack has both OpenAI-compatible AND Anthropic-compatible legs and any baked substrate claim is the same
5
- * class of lie the neutralization removed. The anti-"I am Claude" design is kept.)
6
- */
7
1
  export const SEMA_IDENTITY = "You are Sema, an AI agent built by the Sema team. You act through tools to get real work done.\n" +
8
2
  "You run on a large language model chosen and configured by your operator — you are NOT Claude, NOT " +
9
3
  "GPT, and NOT made by Anthropic or OpenAI. If asked who you are or which model you are, answer honestly " +
@@ -1,7 +1,3 @@
1
- /**
2
- * Built-in team personas (bundle-data layer) — GENERIC personas only; the business prompt is
3
- * appended at call time by the consumer (team.ts), never baked in here.
4
- */
5
1
  export const TEAM_PERSONAS = {
6
2
  analyst: "You analyze the task: lay out the key considerations, options, and trade-offs. Be concrete.",
7
3
  critic: "You challenge the analysis: surface gaps, wrong assumptions, risks, and stronger alternatives.",
@@ -1,6 +1,5 @@
1
1
  import { Type } from "typebox";
2
2
  import { z } from "zod";
3
- /** Parse `owner/name` or a repo URL (e.g. https://git.example.com/some-org/some-repo.git). */
4
3
  export function parseRepo(input) {
5
4
  const s = input.trim().replace(/\.git$/, "");
6
5
  const m = /^[a-z]+:\/\/[^/]+\/(.+)$/i.exec(s);
@@ -12,11 +11,8 @@ export function parseRepo(input) {
12
11
  }
13
12
  const MAX_FILE_BYTES = 96 * 1024;
14
13
  const MAX_TREE_ENTRIES = 2000;
15
- /** Bound each Git-host call so a slow/hung host can't pin a review lens to its whole deadline. */
16
14
  const REQUEST_TIMEOUT_MS = 15_000;
17
15
  export { GIT_API_KINDS, isGitApiKind } from "../git-api-kind.js";
18
- /** Wire schemas for the Git-host responses we consume (both dialects share these shapes — Gitea copied
19
- * GitHub's). Boundary discipline(宪法 [2704] §2):no bare `as` on `.json()`. */
20
16
  const RepoInfoWire = z.looseObject({ default_branch: z.string().optional() });
21
17
  const TreeWire = z.looseObject({
22
18
  tree: z.array(z.looseObject({ path: z.string(), type: z.string() })).optional(),
@@ -28,10 +24,6 @@ const ContentsWire = z.looseObject({
28
24
  type: z.string().optional(),
29
25
  });
30
26
  const PullMetaWire = z.looseObject({ changed_files: z.number().optional() });
31
- /** Shared guard: `encodeURIComponent` does NOT escape "." — a `..` segment survives the per-segment
32
- * encode and the WHATWG URL parser collapses it when `fetch` builds the request, letting a crafted
33
- * `path` climb out of `/repos/<owner>/<repo>/contents/` to any endpoint the read token can reach.
34
- * The tools are contractually bound to exactly one repo, so reject traversal before it hits fetch. */
35
27
  function pathSegmentsRejectingTraversal(path) {
36
28
  const segments = path.split("/").filter(Boolean);
37
29
  if (segments.some((s) => s === "..")) {
@@ -51,7 +43,6 @@ export function createRepoClient(kind, baseUrl, token, fetchImpl = fetch) {
51
43
  }
52
44
  }
53
45
  }
54
- /** Thin read-only Gitea API client. Built once at startup; bound to a repo per task. */
55
46
  export class GiteaClient {
56
47
  baseUrl;
57
48
  token;
@@ -81,9 +72,6 @@ export class GiteaClient {
81
72
  const { owner, repo } = coords;
82
73
  const body = TreeWire.parse(await (await this.api(`/repos/${owner}/${repo}/git/trees/${encodeURIComponent(ref)}?recursive=true&per_page=${MAX_TREE_ENTRIES}`)).json());
83
74
  const paths = (body.tree ?? []).filter((e) => e.type === "blob").map((e) => e.path);
84
- // The upstream API caps the listing at `per_page` and reports the overflow via `truncated` — it does
85
- // not report how many entries were left out. Surface that (same disclosure-marker family as
86
- // `readFile`/`pullDiff` below) so a review lens never mistakes a capped tree for the whole repo.
87
75
  return body.truncated
88
76
  ? [...paths, `…[truncated, tree has more than ${MAX_TREE_ENTRIES} entries]`]
89
77
  : paths;
@@ -106,19 +94,6 @@ export class GiteaClient {
106
94
  return text.length > MAX_FILE_BYTES * 4 ? text.slice(0, MAX_FILE_BYTES * 4) + "\n…[diff truncated]" : text;
107
95
  }
108
96
  }
109
- /**
110
- * Thin read-only GitHub (github.com / GHE) API client — same four-call surface as `GiteaClient`.
111
- *
112
- * Dialect differences (each one is why `GiteaClient` alone 404s against GitHub):
113
- * - base URL is the API root itself (`https://api.github.com`, GHE `https://ghe.example/api/v3`) —
114
- * no `/api/v1` prefix is appended;
115
- * - auth is `Authorization: Bearer <token>` (Gitea uses `token <token>`);
116
- * - a PR's unified diff comes from `/pulls/{n}` via `Accept: application/vnd.github.v3.diff`
117
- * (Gitea uses a `.diff` URL suffix);
118
- * - the tree API has no `per_page` cap — GitHub returns up to its own limit and reports overflow via
119
- * `truncated`; we additionally cap client-side at MAX_TREE_ENTRIES so the model-facing bound is the
120
- * same for both dialects.
121
- */
122
97
  export class GitHubClient {
123
98
  baseUrl;
124
99
  token;
@@ -148,8 +123,6 @@ export class GitHubClient {
148
123
  const { owner, repo } = coords;
149
124
  const body = TreeWire.parse(await (await this.api(`/repos/${owner}/${repo}/git/trees/${encodeURIComponent(ref)}?recursive=1`)).json());
150
125
  const paths = (body.tree ?? []).filter((e) => e.type === "blob").map((e) => e.path);
151
- // Same disclosure-marker family as GiteaClient.tree: a capped listing must never read as the whole
152
- // repo. Two cap sources here — upstream `truncated`, and our own client-side MAX_TREE_ENTRIES bound.
153
126
  if (paths.length > MAX_TREE_ENTRIES) {
154
127
  return [...paths.slice(0, MAX_TREE_ENTRIES), `…[truncated, tree has more than ${MAX_TREE_ENTRIES} entries]`];
155
128
  }
@@ -163,9 +136,6 @@ export class GitHubClient {
163
136
  const body = ContentsWire.parse(await (await this.api(`/repos/${owner}/${repo}/contents/${segments.map(encodeURIComponent).join("/")}?ref=${encodeURIComponent(ref)}`)).json());
164
137
  if (body.type !== "file" || body.content == null)
165
138
  throw new Error(`not a file: ${path}`);
166
- // GitHub 文档行为(codex F1 定谳):1–100 MB 文件走对象形返回 `content:"", encoding:"none"` ——
167
- // content 非 null 过上面的门,非 base64 臂又会把空串当正文交出 = 「大文件被当空文件评审」的静默
168
- // 完整性失败。显式臂响亮拒(本工具本地帽 96 KiB,>1 MB 内容也装不下,拒绝即诚实)。
169
139
  if (body.encoding === "none") {
170
140
  throw new Error(`file too large for the contents API: ${path} (GitHub returns encoding:"none" for files over 1 MB — this read tool cannot fetch it; review it via the PR diff or skip it)`);
171
141
  }
@@ -176,9 +146,6 @@ export class GitHubClient {
176
146
  }
177
147
  async pullDiff(coords, index) {
178
148
  const { owner, repo } = coords;
179
- // GitHub 在服务端静默截断 PR diff(300 文件 / 1 MB / 20k 行,文档行为;codex F2 定谳)——被截的
180
- // 响应可能远小于本地帽,靠字节数判不出来。先取 PR 元数据拿 changed_files,与 diff 里实际出现的
181
- // 文件数对账,少了就显式披露(上游截断与本地帽是两种截断,分开标)。
182
149
  const meta = PullMetaWire.parse(await (await this.api(`/repos/${owner}/${repo}/pulls/${index}`)).json());
183
150
  const res = await this.api(`/repos/${owner}/${repo}/pulls/${index}`, "application/vnd.github.v3.diff");
184
151
  let text = await res.text();
@@ -189,7 +156,6 @@ export class GitHubClient {
189
156
  return text.length > MAX_FILE_BYTES * 4 ? text.slice(0, MAX_FILE_BYTES * 4) + "\n…[diff truncated]" : text;
190
157
  }
191
158
  }
192
- /** Build the read-only repo tool set bound to one repo (cheap per-task closure; the client is shared). */
193
159
  export function repoToolsFor(client, coords) {
194
160
  const ref = (r) => (r ? Promise.resolve(r) : client.defaultBranch(coords));
195
161
  return [
@@ -1,28 +1,8 @@
1
1
  import { hasDestroy } from "@sema-agent/core";
2
2
  import { shellQuote as shq } from "../plugins/remote-shell.js";
3
- /** Leak backstop (codex review HIGH): core skips destroy on suspend/review paths and a crash may skip it
4
- * entirely — the suspendVM wrap covers the common case, this bound covers the rest. Far above any real
5
- * per-replica concurrency. 修6: at the cap the registry REFUSES the new registration instead of FIFO-evicting
6
- * the oldest entry — every entry here is live-until-destroy/suspend by construction, so there is no
7
- * "terminal/stale" liveness verdict to evict on, and silently breaking an EXISTING live task's send face to
8
- * admit a new one inverts the harm (the old FIFO victim's SendUserFile would report "no sandbox attached"
9
- * while its env kept executing). The refused task gets a TYPED capacity error at send time instead. */
10
3
  export const TASK_ENV_REGISTRY_MAX = 512;
11
- /** Replica-local taskId → live ExecutionEnv(s). Registered by the factory wrap, dropped on destroy/suspend.
12
- *
13
- * 修5 (concurrent-generation guard): deployments WITHOUT a run-store single-active-session claim can race
14
- * two legs of one session through the factory concurrently — previously the second registration silently
15
- * OVERWROTE the first, so leg A's later SendUserFile resolved to leg B's env (wrong-generation read/upload).
16
- * The registry now keeps EVERY live env per key and `get()` fail-louds on ambiguity: neither leg can silently
17
- * read the other's sandbox, and the moment one generation is destroyed/suspended the survivor resolves again.
18
- * (Rejecting the second factory call outright was considered and discarded: a stale never-destroyed entry —
19
- * crash/no-destroy path — would then brick every future leg of that task, and the factory seam must not fail
20
- * env creation for a send-face bookkeeping conflict. Deployments WITH the single-active-session claim
21
- * serialize legs upstream and never see this state.) */
22
4
  export class TaskEnvRegistry {
23
5
  map = new Map();
24
- /** 修6: taskIds whose registration was refused at the cap — lets get() report the TRUE reason (typed
25
- * capacity error, not a misleading "no sandbox attached"). Bounded by the same cap (marker-only). */
26
6
  refusedAtCapacity = new Set();
27
7
  liveCount() {
28
8
  let n = 0;
@@ -30,9 +10,6 @@ export class TaskEnvRegistry {
30
10
  n += envs.length;
31
11
  return n;
32
12
  }
33
- /** Resolve the ONE live env for a task. Throws typed errors on the two governed failure states:
34
- * ambiguity (修5 — concurrent generations both live) and capacity refusal (修6). Returns undefined when
35
- * the task simply has no registered env (caller reports "no sandbox attached"). */
36
13
  get(taskId) {
37
14
  if (taskId === undefined)
38
15
  return undefined;
@@ -47,26 +24,14 @@ export class TaskEnvRegistry {
47
24
  }
48
25
  return undefined;
49
26
  }
50
- /** Wrap the deployment's own factory: register each minted env under the task's CANONICAL id — core hands
51
- * the factory the raw `spec.taskId` but gives tools `hostTaskId = spec.taskId ?? sessionId` (prepare-task
52
- * 262/320/428; the sync `/v1/tasks` leg deliberately sets no spec.taskId), so the registry key MUST apply
53
- * the same fallback or every sync-leg lookup misses (codex review HIGH). Unregister when core calls
54
- * destroy() (identity guard: only the env's OWN entry is dropped — a replacement env for a reused key must
55
- * not be evicted by the old one's late destroy). core SKIPS destroy on durable suspend/review (runtask
56
- * keeps the env for the snapshot) — wrap suspendVM the same way so a suspended task doesn't pin its env
57
- * here forever; the bounded-size backstop covers any remaining no-destroy crash path. */
58
27
  wrapFactory(factory) {
59
28
  return async (ctx) => {
60
29
  const env = await factory(ctx);
61
30
  const taskId = ctx.taskId ?? ctx.sessionId;
62
31
  if (hasDestroy(env)) {
63
32
  const existing = this.map.get(taskId);
64
- // 修6: refuse NEW keys at the cap (never evict a live entry — see TASK_ENV_REGISTRY_MAX). A same-key
65
- // additional registration is always admitted even at the cap: the 修5 ambiguity guard is a correctness
66
- // fence and must not be dodgeable by arriving while the registry is full.
67
33
  if (existing === undefined && this.liveCount() >= TASK_ENV_REGISTRY_MAX) {
68
34
  if (this.refusedAtCapacity.size >= TASK_ENV_REGISTRY_MAX) {
69
- // marker set is itself bounded; beyond it the task degrades to the plain "no sandbox attached" report
70
35
  const oldestMarker = this.refusedAtCapacity.values().next().value;
71
36
  if (oldestMarker !== undefined)
72
37
  this.refusedAtCapacity.delete(oldestMarker);
@@ -78,10 +43,8 @@ export class TaskEnvRegistry {
78
43
  clearMarker();
79
44
  return origDestroy();
80
45
  };
81
- return env; // env itself is untouched — only the send face is refused (typed error at get())
46
+ return env;
82
47
  }
83
- // 修5: append, never overwrite — a live sibling under the same key makes get() fail loud instead of
84
- // silently handing one leg the other leg's sandbox.
85
48
  if (existing === undefined)
86
49
  this.map.set(taskId, [env]);
87
50
  else
@@ -90,7 +53,7 @@ export class TaskEnvRegistry {
90
53
  const envs = this.map.get(taskId);
91
54
  if (envs === undefined)
92
55
  return;
93
- const i = envs.indexOf(env); // identity guard: drop only THIS env's entry
56
+ const i = envs.indexOf(env);
94
57
  if (i >= 0)
95
58
  envs.splice(i, 1);
96
59
  if (envs.length === 0)
@@ -107,7 +70,7 @@ export class TaskEnvRegistry {
107
70
  suspendable.suspendVM = async (...args) => {
108
71
  const r = await origSuspend(...args);
109
72
  if (r.ok)
110
- evict(); // suspended env is dormant — the resume leg registers a fresh one
73
+ evict();
111
74
  return r;
112
75
  };
113
76
  }
@@ -116,22 +79,6 @@ export class TaskEnvRegistry {
116
79
  };
117
80
  }
118
81
  }
119
- /**
120
- * Which REMOTE_EXEC lanes may register the sandbox-send TaskEnvRegistry (and thus mount the sandbox-lane
121
- * SendUserFile source), under which tenancy gate. The judgment per lane (2026-07-14 ssh backfill review):
122
- *
123
- * - e2b / k8s: one task = one disposable sandbox; the sandbox filesystem IS the tenant's task workspace,
124
- * so a sandbox-scoped read is tenant-scoped by construction → open to any tenant.
125
- * - ssh: the peer is ONE persistent real machine SHARED across tasks (factory ignores ctx: every task
126
- * gets the same host+mountPath; destroy=disconnect only, files persist). Tenant A's task can read the
127
- * residue of tenant B's task → the isolation premise FAILS. Multi-tenant here would be an
128
- * arbitrary-host-path-read → public-URL exfil face, so the lane opens ONLY single-user
129
- * (`requirePrincipal !== true`), the exact gate the host lane uses. NOT a lane to "fix later with a
130
- * per-task workspace": tasks legitimately operate outside any workspace on a real host (design/61 —
131
- * batch deployment), so per-task dirs would not restore the boundary anyway.
132
- * - adb / local-docker / host / unset: no registry (host+unset use the local-fs source in main.ts;
133
- * adb/local-docker remain a follow-on).
134
- */
135
82
  export function sandboxSendLaneEnabled(provider, requirePrincipal) {
136
83
  if (provider === "e2b" || provider === "k8s")
137
84
  return true;
@@ -139,11 +86,6 @@ export function sandboxSendLaneEnabled(provider, requirePrincipal) {
139
86
  return requirePrincipal !== true;
140
87
  return false;
141
88
  }
142
- // [2354] clay 令兼容面全清:R10 曾留的 `export { shq }` 兼容转口已删——quoting 唯一真源=
143
- // remote-shell.ts 的 shellQuote(原先仅有的两个消费者是测试文件,已改从真源导入)。
144
- /** Strip the capability URL (and any SigV4 signature) from text before it reaches an error/log — including
145
- * the percent-encoded forms an adapter may echo (the k8s exec transport carries the command in a request
146
- * URI, so an error can quote the URL re-encoded; codex review MED). */
147
89
  export function redactPutUrl(text, url) {
148
90
  return text
149
91
  .split(url)
@@ -151,45 +93,25 @@ export function redactPutUrl(text, url) {
151
93
  .split(encodeURIComponent(url))
152
94
  .join("<presigned-put-url>")
153
95
  .replace(/X-Amz-Signature(=|%3D)[0-9a-f]+/gi, "X-Amz-Signature=<redacted>")
154
- // A PARTIAL URL (adapter truncation/line-wrap) can survive the exact-match passes above — the SigV4
155
- // Credential query param carries the ACCESS KEY ID, scrub it independently (defense in depth).
156
96
  .replace(/X-Amz-Credential(=|%3D)[^&\s"']+/gi, "X-Amz-Credential=<redacted>");
157
97
  }
158
- /**
159
- * The sandbox-lane `send` seam for the SendUserFile tool: in-sandbox stat (existence + regular file +
160
- * size cap, BEFORE any signing) → presign PUT → in-sandbox `curl -T` → finalize the user-facing link.
161
- * Throws typed Errors (redacted) — the tool reports them per file.
162
- */
163
98
  export function createSandboxFileSend(deps) {
164
99
  return async (path, ctx) => {
165
100
  const env = deps.registry.get(ctx.taskId);
166
101
  if (!env) {
167
102
  throw new Error("no sandbox is attached to this task yet — SendUserFile reads from the task sandbox; retry after the environment has started");
168
103
  }
169
- // The path is model-controlled and rides a shell line: shq() covers every POSIX metacharacter, but
170
- // control chars (NUL truncates argv in some transports; \n splits lines in naive adapters) buy nothing
171
- // legitimate — reject outright rather than trust each adapter's quoting edge.
172
104
  if (/[\u0000-\u001f\u007f]/.test(path))
173
105
  throw new Error("file path contains control characters — not a valid sandbox path");
174
106
  if (path.length > 4096)
175
107
  throw new Error("file path exceeds 4096 characters — not a valid sandbox path");
176
- // `curl -T -` means STDIN by convention — a relative path starting with '-' must ride as ./-name so all
177
- // three sites (test operand / stat / curl) name the same real file.
178
108
  const q = shq(path.startsWith("-") ? `./${path}` : path);
179
- // stat first: fail before minting any capability URL. `test -f` = regular file only (no dirs/devices);
180
- // `stat -c %s` = GNU/busybox size (sandbox images are Linux; the ssh lane assumes a LINUX peer — the
181
- // whole fleet is — a macOS peer would exit non-zero here and fail loud, see the module header).
182
- // ExecutionEnv.exec timeout is SECONDS (e2b, k8s AND ssh adapters all multiply by 1000 — codex
183
- // review MED caught ms here; ssh reading = remote-env-ssh.ts `options.timeout * 1000`).
184
109
  const stat = await env.exec(`test -f ${q} && stat -c %s -- ${q}`, { timeout: 30 });
185
110
  if (!stat.ok)
186
111
  throw new Error(`sandbox stat failed: ${stat.error.message}`);
187
112
  if (stat.value.exitCode !== 0) {
188
113
  throw new Error(`file not found in the sandbox (or not a regular file): ${path} — ls first; absolute paths are safest`);
189
114
  }
190
- // Advisory pre-check only (the authoritative size accounting is server-side verifySize below — the
191
- // sandbox owns its filesystem, so nothing it reports is binding): still worth failing early and cheap.
192
- // Strict digit match, not bare parseInt — a digit-prefixed garbled line must fail loud, not truncate.
193
115
  const statOut = stat.value.stdout.trim();
194
116
  if (!/^\d+$/.test(statOut))
195
117
  throw new Error(`sandbox stat returned an unparsable size for ${path}: ${statOut}`);
@@ -199,15 +121,7 @@ export function createSandboxFileSend(deps) {
199
121
  }
200
122
  const filename = path.split(/[/\\]/).pop();
201
123
  const prepared = deps.prepare(filename, ctx.principal);
202
- // Everything from here can echo the capability URL (adapter throws included, not just Result errors —
203
- // codex review MED) — one redacting fence around the whole upload phase.
204
124
  try {
205
- // -f: HTTP >= 400 → exit 22 (no silent half-uploads). NO -s: the progress meter on stderr feeds the
206
- // e2b/k8s adapters' ~120s zero-output liveness watchdog — a silent multi-minute upload would be killed
207
- // as a hang (the k8s snapshot lane solves this with livenessMs:0; a chatty meter is the seam-free way).
208
- // The ssh adapter has NO idle-output watchdog on exec() (total-timeout bound only) — the meter is
209
- // harmless noise there, so one shared command shape serves all three lanes.
210
- // stderr may echo the URL → the redact fence below covers every throw out of this block.
211
125
  const up = await env.exec(`curl -f -T ${q} ${shq(prepared.putUrl)}`, { timeout: 300 });
212
126
  if (!up.ok)
213
127
  throw new Error(`sandbox upload failed: ${up.error.message}`);
@@ -217,9 +131,6 @@ export function createSandboxFileSend(deps) {
217
131
  throw new Error("sandbox upload failed: curl is not available in this sandbox image");
218
132
  throw new Error(`sandbox upload failed (curl exit ${up.value.exitCode})${detail.length > 0 ? `: ${detail}` : ""}`);
219
133
  }
220
- // Server-side accounting is authoritative (codex review HIGH: stat→curl is an exploitable TOCTOU —
221
- // swap/grow the file between the two and the cap is bypassed with a stale size on the card): HEAD the
222
- // real object; over-cap ⇒ deleted inside verifySize; the card carries the verified size.
223
134
  const verifiedSize = await prepared.verifySize(deps.maxBytes);
224
135
  return prepared.finalize(verifiedSize);
225
136
  }
@@ -4,7 +4,6 @@ import type { Logger } from "../observability/logger.js";
4
4
  import { type RepoReadClient } from "./repo-tools.js";
5
5
  import { type LoadedSkill } from "./skills.js";
6
6
  import { type ScenarioHands } from "./hands-lane.js";
7
- export { SCENARIO_ALIASES, canonicalScenarioName, scenarioConfigKeys } from "./scenario-alias.js";
8
7
  /**
9
8
  * Scenario routing — a deployment serves many scenarios from one image. Each request's `scenario`
10
9
  * selects a pre-wired capability bundle: tools (incl. subagent roster) + a whole-harness prompt +