@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.
- package/USAGE.md +18 -0
- package/dist/adoption/plan.js +31 -192
- package/dist/adoption/quiesce.js +3 -86
- package/dist/adoption/runner.js +3 -140
- package/dist/adoption/sql.js +0 -74
- package/dist/adoption/wire.js +0 -80
- package/dist/approval-ask-machine.js +0 -75
- package/dist/approval-card.js +0 -323
- package/dist/approval-deny-reasons.js +0 -42
- package/dist/approval-hmac.js +0 -35
- package/dist/approval-reconciler.js +8 -166
- package/dist/approval.js +4 -67
- package/dist/audit.js +1 -44
- package/dist/auth-bridge.js +4 -47
- package/dist/auth-keys.js +0 -23
- package/dist/bake-runner/main.js +4 -65
- package/dist/bake-runner/protocol.js +3 -58
- package/dist/bake-runner/runner.js +5 -91
- package/dist/bench/l8/artifact.js +2 -61
- package/dist/bench/l8/escape.js +0 -25
- package/dist/bench/l8/index.js +0 -14
- package/dist/bench/l8/probes.js +0 -60
- package/dist/bench/l8/run-probes.js +2 -45
- package/dist/bench/s1/arms.js +14 -189
- package/dist/bench/s1/live-deps.js +11 -253
- package/dist/bench/s1/oracle.js +1 -36
- package/dist/bench/s1/repair-oracle-adapter.js +0 -30
- package/dist/bench/s1/reviewer.js +0 -34
- package/dist/bench/s1/row.js +0 -62
- package/dist/bench/s1/run-firm.js +4 -70
- package/dist/bench/s1/runner-ctx.js +0 -40
- package/dist/bench/s1/tasks.js +0 -115
- package/dist/boot/adoption.js +0 -20
- package/dist/boot/budget-tracing.js +3 -55
- package/dist/boot/config-center.js +43 -551
- package/dist/boot/coordinators.js +1 -69
- package/dist/boot/crash-last.js +0 -18
- package/dist/boot/deferred-sandbox-path-env.js +3 -119
- package/dist/boot/execution-env.js +5 -171
- package/dist/boot/governance-seams.js +0 -92
- package/dist/boot/leader.js +0 -69
- package/dist/boot/limit-sync.js +0 -2
- package/dist/boot/memory-boundary.js +3 -91
- package/dist/boot/org-memory.js +1 -25
- package/dist/boot/parked-revive-gate.js +0 -150
- package/dist/boot/permission-rules-audit.js +1 -56
- package/dist/boot/reapers.js +15 -273
- package/dist/boot/resolve-spec.js +9 -768
- package/dist/boot/retention-lane.js +4 -87
- package/dist/boot/runner-deps.js +3 -297
- package/dist/boot/runtime-caps.js +0 -40
- package/dist/boot/session-faces.js +2 -133
- package/dist/boot/shutdown.js +9 -83
- package/dist/boot/side-query-lane.js +2 -137
- package/dist/boot/stores.js +15 -215
- package/dist/boot/task-list-lane.js +0 -18
- package/dist/boot/webfetch-summarize-lane.js +0 -47
- package/dist/boot/workflow-orchestration.js +3 -99
- package/dist/boot-reclaim.js +0 -20
- package/dist/bounded-session-map.js +0 -19
- package/dist/brain.js +2 -139
- package/dist/budget.js +9 -244
- package/dist/capabilities/builtin-tools.js +0 -3
- package/dist/capabilities/center-plugins.js +6 -51
- package/dist/capabilities/center-prompts.js +6 -71
- package/dist/capabilities/code-review-council.js +7 -40
- package/dist/capabilities/collab-workflows.js +1 -44
- package/dist/capabilities/hands-lane.js +0 -65
- package/dist/capabilities/memory-notice.js +0 -70
- package/dist/capabilities/prompt.js +0 -14
- package/dist/capabilities/prompts/code-review.js +0 -14
- package/dist/capabilities/prompts/identity.js +0 -6
- package/dist/capabilities/prompts/team.js +0 -4
- package/dist/capabilities/repo-tools.js +0 -34
- package/dist/capabilities/sandbox-file-send.js +3 -92
- package/dist/capabilities/scenarios.d.ts +0 -1
- package/dist/capabilities/scenarios.js +18 -279
- package/dist/capabilities/select-environment-tool.js +0 -32
- package/dist/capabilities/send-user-file-tool.js +2 -66
- package/dist/capabilities/skills.d.ts +1 -2
- package/dist/capabilities/skills.js +3 -21
- package/dist/capabilities/team.d.ts +3 -11
- package/dist/capabilities/team.js +3 -51
- package/dist/capabilities/tool-defer.js +0 -3
- package/dist/config-center/apply-effective.js +15 -330
- package/dist/config-center/apply-ledger.js +5 -38
- package/dist/config-center/facade.js +0 -41
- package/dist/config-center/hot-keys-registry.js +0 -20
- package/dist/config-center/http-client.js +2 -125
- package/dist/config-center/mcp-revocation.js +2 -34
- package/dist/config-center/read-face.js +0 -59
- package/dist/config-center/restart-signal.js +1 -85
- package/dist/config-center/skills-mcp.d.ts +1 -1
- package/dist/config-center/skills-mcp.js +9 -76
- package/dist/config-center/stage-limits.js +8 -35
- package/dist/config-invariants.js +0 -16
- package/dist/config-lkg.js +0 -42
- package/dist/config-provider.js +3 -186
- package/dist/config-types.js +0 -5
- package/dist/config.js +107 -1145
- package/dist/degenerate-instrument.js +3 -67
- package/dist/deployment-governance.js +0 -124
- package/dist/digest-form.js +0 -12
- package/dist/elicitation.js +3 -86
- package/dist/env-facts.js +7 -75
- package/dist/fleet/fleet-bus.js +34 -507
- package/dist/fleet/fleet-reconciler.js +9 -149
- package/dist/fleet/fleet-terminal-window.js +10 -178
- package/dist/fleet/subagent-tail-bus.js +3 -72
- package/dist/fleet-client.js +10 -70
- package/dist/fleet-lease.js +5 -79
- package/dist/git-api-kind.js +0 -3
- package/dist/governance-ask-marks.js +2 -78
- package/dist/hooks/branch-transcript.js +0 -74
- package/dist/hooks/cc-agent-hook-prompt.js +0 -29
- package/dist/hooks/cc-stop-prompt.js +1 -46
- package/dist/hooks/hook-llm.js +1 -53
- package/dist/hooks/hook-runner.js +20 -414
- package/dist/http/active-run-conflict.js +4 -129
- package/dist/http/cursor-fingerprint.d.ts +5 -0
- package/dist/http/cursor-fingerprint.js +5 -0
- package/dist/http/idempotency.js +0 -37
- package/dist/http/principal-gate.js +3 -40
- package/dist/http/route-ctx.js +0 -9
- package/dist/http/routes/a2a-serve.js +7 -319
- package/dist/http/routes/admin-config-refresh.js +0 -4
- package/dist/http/routes/admin-drain.js +0 -10
- package/dist/http/routes/adoption.js +1 -29
- package/dist/http/routes/agents-roster.js +1 -47
- package/dist/http/routes/approvals-assistant.js +32 -395
- package/dist/http/routes/attachments.js +4 -22
- package/dist/http/routes/capabilities.js +3 -420
- package/dist/http/routes/diagnostics.js +1 -81
- package/dist/http/routes/fleet.js +9 -185
- package/dist/http/routes/images.js +14 -239
- package/dist/http/routes/leader.js +0 -13
- package/dist/http/routes/memory-bundle.js +1 -61
- package/dist/http/routes/memory-policy.js +9 -99
- package/dist/http/routes/notify-wake.js +3 -37
- package/dist/http/routes/observability.js +2 -19
- package/dist/http/routes/retention-ops.js +2 -34
- package/dist/http/routes/rules.js +1 -93
- package/dist/http/routes/runs.js +64 -873
- package/dist/http/routes/session-sync.js +19 -258
- package/dist/http/routes/sessions-list.js +17 -43
- package/dist/http/routes/sessions.js +34 -226
- package/dist/http/routes/shared-memory.js +5 -36
- package/dist/http/routes/side-query.js +1 -87
- package/dist/http/routes/tasks.js +52 -722
- package/dist/http/routes/trace-usage.js +32 -195
- package/dist/http/routes/workflows.js +19 -195
- package/dist/http/run-meta.js +0 -6
- package/dist/http/send.js +0 -32
- package/dist/http/server.js +92 -1597
- package/dist/http/sse-lifecycle.js +2 -13
- package/dist/http/sse-log.js +3 -48
- package/dist/http/tar.js +5 -21
- package/dist/http/verify-rounds.js +0 -5
- package/dist/http/wire-gate.js +0 -9
- package/dist/http/workspace-content.js +0 -10
- package/dist/images/bake-validate.js +1 -70
- package/dist/images/manifest.js +1 -6
- package/dist/index.js +0 -21
- package/dist/key-resolver.js +2 -17
- package/dist/leader/diffout.js +1 -20
- package/dist/leader/diffup.js +0 -47
- package/dist/leader/endpoint.js +2 -57
- package/dist/leader/fanout.js +3 -45
- package/dist/leader/grader-env-factory.js +3 -72
- package/dist/leader/leader.js +5 -156
- package/dist/leader/merge.js +8 -115
- package/dist/leader/planner.js +3 -54
- package/dist/leader/repair-oracle.js +1 -60
- package/dist/leader/repair-wire.js +2 -79
- package/dist/leader/wire.js +8 -307
- package/dist/lsp/e2b-bridge.js +4 -64
- package/dist/lsp/e2b-manager.js +6 -94
- package/dist/lsp/lsp-frames.js +0 -12
- package/dist/lsp/manager.js +4 -96
- package/dist/lsp/ws-transport.js +5 -55
- package/dist/lsp-evict.js +1 -15
- package/dist/main.js +57 -765
- package/dist/memory-bundle-engine.js +0 -55
- package/dist/memory-export.js +0 -4
- package/dist/memory-posture.js +1 -15
- package/dist/memory-scope.js +11 -148
- package/dist/memory-sync-client.js +2 -44
- package/dist/memory-sync.js +1 -80
- package/dist/model-select.js +3 -80
- package/dist/observability/cost-quota.js +1 -17
- package/dist/observability/cost-taxonomy.js +0 -34
- package/dist/observability/fail-open.js +7 -86
- package/dist/observability/logger.js +0 -6
- package/dist/observability/metrics.js +0 -94
- package/dist/observability/otel-exporter.js +3 -13
- package/dist/observability/principal-context.js +0 -9
- package/dist/observability/prompt-manifest.js +1 -37
- package/dist/observability/rate-limit.js +0 -4
- package/dist/observability/secret-env-scrub.js +2 -56
- package/dist/observability/tool-trace.js +1 -70
- package/dist/orchestration/hardened-vm-runner.js +4 -118
- package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
- package/dist/orchestration/hardened-vm-worker.js +0 -27
- package/dist/orchestration/subagent-steer.js +1 -45
- package/dist/orchestration/workflow-agent-steer.js +1 -80
- package/dist/orchestration/workflow-completion-inbox.js +32 -285
- package/dist/orchestration/workflow-notify-journal.js +16 -259
- package/dist/org-memory-admission.js +3 -47
- package/dist/parent-watch.js +2 -48
- package/dist/parked-decide.js +1 -109
- package/dist/per-task-image.js +0 -57
- package/dist/plan-cache-probe.js +3 -27
- package/dist/plugins/adoption-log-sql.js +2 -119
- package/dist/plugins/approval-ask-store-memory.js +3 -38
- package/dist/plugins/approval-ask-store-sql.js +6 -188
- package/dist/plugins/approval-exemption-store.js +2 -28
- package/dist/plugins/background-agent-store-sql.js +4 -105
- package/dist/plugins/background-shell-support.js +14 -122
- package/dist/plugins/blob-backend.js +6 -169
- package/dist/plugins/breaker-state-sql.js +8 -46
- package/dist/plugins/caching-session-store.js +4 -106
- package/dist/plugins/checkpoint-store-sql.js +18 -505
- package/dist/plugins/e2b-orphan-reclaim.js +0 -45
- package/dist/plugins/file-outcome-sink.js +0 -9
- package/dist/plugins/file-resume-anchor-store.js +4 -43
- package/dist/plugins/file-run-store.js +26 -364
- package/dist/plugins/file-snapshot-store-sql.js +10 -181
- package/dist/plugins/fork-routing-session-store.js +8 -111
- package/dist/plugins/host-platform.js +2 -91
- package/dist/plugins/image-bake-store-sql.js +7 -250
- package/dist/plugins/image-index-sql.js +4 -123
- package/dist/plugins/k8s-bg-scripts.js +4 -88
- package/dist/plugins/k8s-exec-protocol.js +0 -41
- package/dist/plugins/leader-run-store-sql.js +0 -101
- package/dist/plugins/local-checkpoint-store.js +8 -128
- package/dist/plugins/local-session-store.js +34 -296
- package/dist/plugins/local-task-attachment-store.js +2 -16
- package/dist/plugins/mailbox-store-sql.js +8 -65
- package/dist/plugins/memory-embedder-fingerprint.js +5 -166
- package/dist/plugins/memory-embedder.js +4 -70
- package/dist/plugins/memory-engine-pg.js +6 -170
- package/dist/plugins/memory-engine-tidb.js +7 -155
- package/dist/plugins/memory-engine-vector-util.js +0 -10
- package/dist/plugins/memory-key-guards.js +0 -34
- package/dist/plugins/memory-origin-law.js +0 -187
- package/dist/plugins/memory-resume-anchor-store.js +0 -17
- package/dist/plugins/memory-run-store.js +12 -89
- package/dist/plugins/memory-session-policy-store.js +0 -17
- package/dist/plugins/memory-sync-store-pg.js +4 -49
- package/dist/plugins/memory-sync-store-tidb.js +3 -35
- package/dist/plugins/outcome-ledger-sql.js +3 -97
- package/dist/plugins/permission-rule-store-file.js +5 -133
- package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
- package/dist/plugins/permission-rule-store-sql.js +50 -307
- package/dist/plugins/pg-cost-quota.js +0 -7
- package/dist/plugins/pg-pool.js +0 -92
- package/dist/plugins/pg-rate-limiter.js +2 -13
- package/dist/plugins/pg-safe-json.js +4 -40
- package/dist/plugins/pg-session-storage.js +25 -189
- package/dist/plugins/posix-shell-fs.js +1 -31
- package/dist/plugins/remote-env-adb.js +12 -101
- package/dist/plugins/remote-env-e2b.js +40 -371
- package/dist/plugins/remote-env-file-error.js +0 -37
- package/dist/plugins/remote-env-host.js +63 -483
- package/dist/plugins/remote-env-k8s.js +32 -326
- package/dist/plugins/remote-env-local-docker.js +24 -157
- package/dist/plugins/remote-env-ssh.js +20 -128
- package/dist/plugins/remote-scratchpad.js +2 -32
- package/dist/plugins/remote-shell.js +1 -32
- package/dist/plugins/resume-anchor-store-sql.js +0 -11
- package/dist/plugins/retention-lane-store-sql.js +0 -108
- package/dist/plugins/retention-store-sql.js +4 -383
- package/dist/plugins/roster-store-sql.js +0 -55
- package/dist/plugins/run-store-sql.js +14 -251
- package/dist/plugins/s3-presign.js +2 -49
- package/dist/plugins/scheduler-support.js +3 -80
- package/dist/plugins/send-file-ledger.js +4 -53
- package/dist/plugins/send-user-file.js +4 -94
- package/dist/plugins/session-placement.js +1 -89
- package/dist/plugins/session-policy-store-sql.js +3 -81
- package/dist/plugins/session-store.js +0 -57
- package/dist/plugins/shared-memory-store-sql.js +4 -167
- package/dist/plugins/sql-driver.js +0 -17
- package/dist/plugins/sql-errors.js +0 -7
- package/dist/plugins/sql-escape.js +0 -8
- package/dist/plugins/sql-row-helpers.js +0 -25
- package/dist/plugins/store-backend.js +42 -222
- package/dist/plugins/store-contracts.js +2 -46
- package/dist/plugins/task-attachment-store.js +3 -49
- package/dist/plugins/task-list-store-sql.js +0 -79
- package/dist/plugins/tidb-cost-quota.js +1 -4
- package/dist/plugins/tidb-pool.js +1 -207
- package/dist/plugins/tidb-rate-limiter.js +3 -9
- package/dist/plugins/tidb-session-storage.js +4 -70
- package/dist/plugins/tidb-session-store.js +19 -341
- package/dist/plugins/tool-result-store-sql.js +4 -179
- package/dist/plugins/usage-window-store-sql.js +0 -8
- package/dist/plugins/web-search.js +10 -132
- package/dist/plugins/workflow-journal-store-sql.js +2 -58
- package/dist/plugins/workflow-run-store-sql.js +6 -91
- package/dist/plugins/worktree-isolation.js +6 -126
- package/dist/plugins/write-behind-counter.js +16 -75
- package/dist/principal-jwt.js +5 -60
- package/dist/project-memory.js +15 -146
- package/dist/prompts-domain-validate.js +1 -51
- package/dist/question.js +2 -111
- package/dist/resource-suspend.js +0 -18
- package/dist/router/route-orchestration.js +0 -77
- package/dist/rules-consent.d.ts +44 -5
- package/dist/rules-consent.js +75 -215
- package/dist/run-local.js +14 -381
- package/dist/runs.js +29 -617
- package/dist/runtime-caps-resolver.js +6 -132
- package/dist/runtime-governance.js +1 -232
- package/dist/sandbox-pkg-source.js +0 -37
- package/dist/sealed-key.js +3 -68
- package/dist/security.js +6 -291
- package/dist/session-leaf-bus.js +0 -32
- package/dist/session-sync-content.js +1 -69
- package/dist/session-sync-kernel.js +3 -60
- package/dist/session-sync.js +3 -66
- package/dist/session-titler.js +7 -41
- package/dist/session-watch.js +9 -73
- package/dist/shared-memory-scope-authorizer.js +0 -18
- package/dist/sighup-idle.js +1 -12
- package/dist/spec-fields.js +4 -143
- package/dist/store-live-probe.js +3 -49
- package/dist/task-a2a.js +1 -126
- package/dist/task-cwd.js +1 -103
- package/dist/task-mcp.js +1 -89
- package/dist/task-settings.js +10 -300
- package/dist/task-workflow.js +8 -75
- package/dist/tool-approval.d.ts +28 -1
- package/dist/tool-approval.js +70 -1430
- package/dist/trace/artifacts.js +5 -20
- package/dist/trace/engine-notice-wire.js +6 -138
- package/dist/trace/ledger-sink.js +7 -96
- package/dist/trace/project.js +4 -448
- package/dist/trace/redact.js +9 -77
- package/dist/turn-activity.js +1 -27
- package/dist/usage-analytics.js +4 -34
- package/dist/wall-clock-jump-guard.js +1 -68
- package/package.json +3 -3
- package/dist/capabilities/scenario-alias.d.ts +0 -27
- 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;
|
|
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);
|
|
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();
|
|
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 +
|