@sema-agent/server 7.125.1 → 7.127.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/MIGRATION.md +229 -2
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/USAGE.md +346 -145
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/chart/templates/networkpolicy-sandbox.yaml +57 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +32 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +3 -2
- package/deploy/sema-up/chart/templates/server.yaml +2 -1
- package/deploy/sema-up/chart/values.yaml +22 -0
- package/deploy/sema-up/cluster-up.sh +10 -10
- package/deploy/sema-up/kube-up.sh +20 -13
- package/deploy/sema-up/lib/dataroot.sh +1 -1
- package/deploy/sema-up/lib/envf.sh +5 -5
- package/deploy/sema-up/lib/flagshape.sh +5 -5
- package/deploy/sema-up/lib/lanes.py +1 -1
- package/deploy/sema-up/lib/node-addrs.sh +42 -0
- package/deploy/sema-up/lib/parse-machines.py +2 -2
- package/deploy/sema-up/lib/shell-access.sh +1 -1
- package/deploy/sema-up/preflight.sh +4 -4
- package/deploy/sema-up/sema-up.sh +33 -33
- package/deploy/sema-up/smoke.sh +3 -3
- package/deploy/sema-up/stack/compose.yaml +1 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +26 -3
- package/dist/approval-card.d.ts +20 -4
- package/dist/approval-content-kind.d.ts +38 -22
- package/dist/approval-content-kind.js +20 -4
- package/dist/audit.js +3 -0
- package/dist/bench/s1/arms.d.ts +9 -37
- package/dist/bench/s1/arms.js +4 -61
- package/dist/bench/s1/live-deps.d.ts +4 -10
- package/dist/bench/s1/live-deps.js +1 -222
- package/dist/bench/s1/oracle.d.ts +1 -1
- package/dist/bench/s1/reviewer.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +5 -7
- package/dist/bench/s1/row.js +0 -2
- package/dist/bench/s1/run-firm.d.ts +2 -2
- package/dist/bench/s1/run-firm.js +1 -4
- package/dist/bench/s1/runner-ctx.d.ts +17 -29
- package/dist/bench/s1/runner-ctx.js +3 -7
- package/dist/bench/s1/tasks.d.ts +9 -46
- package/dist/bench/s1/tasks.js +4 -63
- package/dist/boot/execution-env.d.ts +38 -26
- package/dist/boot/execution-env.js +87 -41
- package/dist/boot/leader.d.ts +2 -1
- package/dist/boot/memory-boundary.d.ts +1 -1
- package/dist/boot/memory-consolidation.d.ts +37 -3
- package/dist/boot/memory-consolidation.js +18 -2
- package/dist/boot/parked-revive-gate.d.ts +0 -3
- package/dist/boot/parked-revive-gate.js +2 -2
- package/dist/boot/resolve-spec.d.ts +0 -2
- package/dist/boot/resolve-spec.js +12 -17
- package/dist/boot/retention-lane.d.ts +12 -1
- package/dist/boot/retention-lane.js +2 -0
- package/dist/boot/runner-deps.d.ts +7 -6
- package/dist/boot/runner-deps.js +5 -16
- package/dist/boot/session-faces.d.ts +7 -2
- package/dist/boot/session-faces.js +37 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +2 -2
- package/dist/boot/stage-05-execution-env.js +7 -4
- package/dist/boot/stage-06-runners.d.ts +2 -3
- package/dist/boot/stage-06-runners.js +13 -9
- package/dist/boot/stage-07-capability-layer.d.ts +2 -3
- package/dist/boot/stage-07-capability-layer.js +3 -4
- package/dist/boot/stage-08-reapers.d.ts +2 -3
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -3
- package/dist/boot/stage-09-leader.js +2 -1
- package/dist/boot/stage-10-http-server.d.ts +2 -3
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/boot/stores.d.ts +1 -0
- package/dist/boot/stores.js +4 -3
- package/dist/boot/web-admin.d.ts +5 -0
- package/dist/boot/web-admin.js +28 -14
- package/dist/brain.d.ts +2 -2
- package/dist/brain.js +1 -1
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/hands-lane.d.ts +9 -6
- package/dist/capabilities/hands-lane.js +2 -2
- package/dist/capabilities/memory-notice.d.ts +27 -22
- package/dist/capabilities/memory-notice.js +15 -17
- package/dist/capabilities/scenarios.d.ts +9 -14
- package/dist/capabilities/scenarios.js +5 -50
- package/dist/capability-facts.d.ts +22 -11
- package/dist/capability-facts.js +13 -6
- package/dist/config-catalog.js +14 -5
- package/dist/config-provider.d.ts +5 -1
- package/dist/config-provider.js +23 -4
- package/dist/config-types.d.ts +19 -2
- package/dist/config.js +41 -6
- package/dist/deployment-governance.d.ts +19 -21
- package/dist/deployment-governance.js +7 -8
- package/dist/env-name-allowlist-knobs.d.ts +5 -5
- package/dist/env-name-allowlist-knobs.js +1 -0
- package/dist/execution-lane-caps.d.ts +12 -0
- package/dist/execution-lane-caps.js +18 -4
- package/dist/fleet/subagent-tail-bus.js +15 -5
- package/dist/hooks/hook-runner.d.ts +84 -30
- package/dist/hooks/hook-runner.js +74 -41
- package/dist/http/admission.js +17 -10
- package/dist/http/durable-run-leg.d.ts +5 -4
- package/dist/http/durable-run-leg.js +2 -4
- package/dist/http/idempotency.d.ts +28 -6
- package/dist/http/idempotency.js +10 -2
- package/dist/http/principal-gate.d.ts +14 -0
- package/dist/http/principal-gate.js +7 -0
- package/dist/http/request-guards.d.ts +2 -1
- package/dist/http/request-guards.js +14 -14
- package/dist/http/resume-legs.d.ts +2 -2
- package/dist/http/resume-legs.js +20 -10
- package/dist/http/route-ctx.d.ts +15 -7
- package/dist/http/routes/a2a-serve.js +11 -7
- package/dist/http/routes/approvals-assistant.js +18 -3
- package/dist/http/routes/background.d.ts +1 -1
- package/dist/http/routes/background.js +1 -1
- package/dist/http/routes/capabilities.js +10 -2
- package/dist/http/routes/mcp-reconnect.js +1 -1
- package/dist/http/routes/runs.d.ts +4 -3
- package/dist/http/routes/runs.js +35 -14
- package/dist/http/routes/session-sync.js +14 -11
- package/dist/http/routes/sessions.js +9 -9
- package/dist/http/routes/side-query.js +6 -19
- package/dist/http/routes/tasks.js +29 -19
- package/dist/http/routes/workflows.js +8 -0
- package/dist/http/server.d.ts +4 -0
- package/dist/http/server.js +3 -5
- package/dist/http/submit-replay.d.ts +15 -8
- package/dist/http/submit-replay.js +6 -0
- package/dist/http/wire-types.d.ts +7 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal-run-env.d.ts +30 -0
- package/dist/internal-run-env.js +11 -0
- package/dist/leader/wire.js +3 -2
- package/dist/lsp/manager.js +1 -1
- package/dist/memory-scope.d.ts +19 -7
- package/dist/memory-scope.js +25 -8
- package/dist/observability/fail-open.d.ts +31 -3
- package/dist/observability/fail-open.js +31 -3
- package/dist/observability/metrics.d.ts +0 -1
- package/dist/observability/metrics.js +1 -4
- package/dist/observability/run-terminal.js +72 -4
- package/dist/permission-rule-vocab.d.ts +3 -2
- package/dist/permission-rule-vocab.js +1 -1
- package/dist/plan-cache-probe.d.ts +3 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
- package/dist/plugins/caching-session-store.d.ts +42 -22
- package/dist/plugins/caching-session-store.js +19 -9
- package/dist/plugins/checkpoint-store-sql.d.ts +42 -28
- package/dist/plugins/checkpoint-store-sql.js +57 -11
- package/dist/plugins/file-run-store.d.ts +25 -21
- package/dist/plugins/file-run-store.js +70 -34
- package/dist/plugins/k8s-exec-protocol.js +3 -0
- package/dist/plugins/local-checkpoint-store.d.ts +8 -5
- package/dist/plugins/local-checkpoint-store.js +5 -15
- package/dist/plugins/local-session-store.d.ts +66 -7
- package/dist/plugins/local-session-store.js +168 -101
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +1 -1
- package/dist/plugins/memory-run-store.d.ts +19 -3
- package/dist/plugins/memory-run-store.js +38 -3
- package/dist/plugins/one-time-migrations.d.ts +165 -39
- package/dist/plugins/one-time-migrations.js +51 -144
- package/dist/plugins/pg-pool.js +11 -1
- package/dist/plugins/pg-session-storage.d.ts +2 -0
- package/dist/plugins/pg-session-storage.js +9 -5
- package/dist/plugins/remote-env-adb.d.ts +3 -0
- package/dist/plugins/remote-env-adb.js +1 -0
- package/dist/plugins/remote-env-device.d.ts +3 -0
- package/dist/plugins/remote-env-device.js +1 -0
- package/dist/plugins/remote-env-e2b.d.ts +4 -0
- package/dist/plugins/remote-env-e2b.js +2 -1
- package/dist/plugins/remote-env-host.d.ts +23 -1
- package/dist/plugins/remote-env-host.js +20 -2
- package/dist/plugins/remote-env-k8s.d.ts +264 -41
- package/dist/plugins/remote-env-k8s.js +551 -82
- package/dist/plugins/remote-env-local-docker.d.ts +4 -0
- package/dist/plugins/remote-env-local-docker.js +2 -1
- package/dist/plugins/remote-env-ssh.d.ts +3 -0
- package/dist/plugins/remote-env-ssh.js +1 -0
- package/dist/plugins/retention-store-sql.d.ts +4 -1
- package/dist/plugins/retention-store-sql.js +11 -9
- package/dist/plugins/run-store-sql.d.ts +44 -6
- package/dist/plugins/run-store-sql.js +92 -27
- package/dist/plugins/session-capture-record-store-sql.d.ts +2 -3
- package/dist/plugins/session-store.d.ts +4 -3
- package/dist/plugins/session-store.js +1 -1
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/store-backend.d.ts +12 -5
- package/dist/plugins/store-backend.js +13 -4
- package/dist/plugins/store-contracts.d.ts +20 -3
- package/dist/plugins/store-open-wait.js +3 -0
- package/dist/plugins/tidb-pool.js +15 -3
- package/dist/plugins/tidb-session-storage.js +3 -2
- package/dist/plugins/tidb-session-store.d.ts +2 -0
- package/dist/plugins/tidb-session-store.js +6 -2
- package/dist/request-key-closure.d.ts +32 -7
- package/dist/request-key-closure.js +25 -9
- package/dist/router/route-orchestration.d.ts +3 -11
- package/dist/router/route-orchestration.js +0 -4
- package/dist/rule-entry-list.js +0 -4
- package/dist/rules-consent.js +3 -0
- package/dist/run-acceptance.d.ts +51 -0
- package/dist/run-acceptance.js +27 -0
- package/dist/run-local.d.ts +5 -4
- package/dist/run-local.js +23 -17
- package/dist/runs.d.ts +7 -11
- package/dist/runs.js +6 -16
- package/dist/sandbox-egress-policy.d.ts +61 -0
- package/dist/sandbox-egress-policy.js +235 -0
- package/dist/security.d.ts +7 -0
- package/dist/security.js +5 -0
- package/dist/server-secret-env.d.ts +10 -4
- package/dist/server-secret-env.js +4 -1
- package/dist/session-error-wire.d.ts +2 -2
- package/dist/session-incarnation.d.ts +46 -2
- package/dist/session-incarnation.js +14 -3
- package/dist/session-sync-kernel.d.ts +10 -3
- package/dist/session-titler.d.ts +5 -3
- package/dist/spec-fields.d.ts +24 -8
- package/dist/spec-fields.js +21 -2
- package/dist/task-workflow.d.ts +6 -4
- package/dist/task-workflow.js +3 -2
- package/dist/tool-approval.d.ts +78 -6
- package/dist/tool-approval.js +7 -3
- package/dist/trace/core-keyset-guard.d.ts +6 -5
- package/dist/trace/engine-notice-wire.d.ts +26 -1
- package/dist/trace/engine-notice-wire.js +7 -2
- package/dist/trace/ledger-events.d.ts +9 -3
- package/dist/trace/ledger-sink.d.ts +7 -0
- package/dist/trace/ledger-sink.js +14 -4
- package/dist/trace/project.d.ts +57 -11
- package/dist/trace/project.js +54 -8
- package/dist/trace/self-minted-wire.d.ts +94 -2
- package/dist/trace/self-minted-wire.js +28 -0
- package/dist/trace/tool-output-media.d.ts +26 -0
- package/dist/trace/tool-output-media.js +57 -0
- package/dist/trace/wire-projection-faces.d.ts +7 -1
- package/dist/trace/wire-projection-faces.js +2 -1
- package/dist/web-admin-client/apply-effective.d.ts +13 -7
- package/dist/web-admin-client/apply-effective.js +11 -26
- package/dist/web-admin-client/apply-ledger.d.ts +2 -2
- package/dist/web-admin-client/candidate-gate.d.ts +39 -4
- package/dist/web-admin-client/candidate-gate.js +9 -2
- package/dist/web-admin-client/facade.d.ts +2 -2
- package/dist/web-admin-client/http-client.d.ts +3 -1
- package/dist/web-admin-client/http-client.js +4 -3
- package/dist/web-admin-client/read-warnings.d.ts +33 -5
- package/dist/web-admin-client/read-warnings.js +41 -6
- package/dist/web-admin-client/types.d.ts +11 -5
- package/dist/workspace-cache.d.ts +45 -0
- package/dist/workspace-cache.js +30 -0
- package/dist/workspace-space-commit.d.ts +116 -0
- package/dist/workspace-space-commit.js +117 -0
- package/dist/workspace-space.d.ts +75 -9
- package/dist/workspace-space.js +52 -1
- package/package.json +4 -4
- package/dist/boot/session-incarnation-seat.d.ts +0 -41
- package/dist/boot/session-incarnation-seat.js +0 -69
- package/dist/capabilities/code-review-council.d.ts +0 -49
- package/dist/capabilities/code-review-council.js +0 -111
- package/dist/capabilities/collab-wire.d.ts +0 -36
- package/dist/capabilities/collab-wire.js +0 -2
- package/dist/capabilities/collab-workflows.d.ts +0 -47
- package/dist/capabilities/collab-workflows.js +0 -90
- package/dist/capabilities/prompts/code-review.d.ts +0 -25
- package/dist/capabilities/prompts/code-review.js +0 -39
- package/dist/capabilities/prompts/team.d.ts +0 -10
- package/dist/capabilities/prompts/team.js +0 -6
- package/dist/capabilities/team.d.ts +0 -113
- package/dist/capabilities/team.js +0 -70
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** The row's `state` closed set. `pending` = the run is over, its env has not begun committing; `committing` = its upload
|
|
3
|
+
* is running; `publishing` = its upload is done and it is moving `latest` (re-claimed just before the move). */
|
|
4
|
+
export declare const SPACE_COMMIT_STATES: readonly ["pending", "committing", "publishing"];
|
|
5
|
+
export type SpaceCommitState = (typeof SPACE_COMMIT_STATES)[number];
|
|
6
|
+
/** One space's row as read — `remainingMs` = its writer's deadline − now, on the store's own clock (`<= 0` = dead). */
|
|
7
|
+
export interface SpaceCommitReading {
|
|
8
|
+
readonly taskId: string;
|
|
9
|
+
readonly state: SpaceCommitState;
|
|
10
|
+
readonly remainingMs: number;
|
|
11
|
+
}
|
|
12
|
+
/** One write of this run's row: the deadline it sets, and whether only this run's own (live) row may be moved. */
|
|
13
|
+
export interface SpaceCommitClaim {
|
|
14
|
+
/** THIS run's bound: the write sets the row's deadline to now + `boundMs`. Never an operand of judging a row. */
|
|
15
|
+
readonly boundMs: number;
|
|
16
|
+
/** `true` = this run already wrote its row (its terminal fenced it): only that row, still alive, may move. */
|
|
17
|
+
readonly requireOwn: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** The row face a run store gives the fence (its table, its clock). Every write goes through {@link decideSpaceCommitClaim}. */
|
|
20
|
+
export interface SpaceCommitRows {
|
|
21
|
+
/** The space's row, or `undefined` (no commit in flight). A read that fails throws. */
|
|
22
|
+
readSpaceCommit(spaceKey: string): Promise<SpaceCommitReading | undefined>;
|
|
23
|
+
/** Make the space's row this run's, in `state`, its deadline := now + `claim.boundMs` — per {@link decideSpaceCommitClaim}.
|
|
24
|
+
* `true` ⇒ the row is now this run's. */
|
|
25
|
+
claimSpaceCommit(spaceKey: string, taskId: string, state: SpaceCommitState, claim: SpaceCommitClaim): Promise<boolean>;
|
|
26
|
+
/** Delete this run's row (never another run's). */
|
|
27
|
+
endSpaceCommit(spaceKey: string, taskId: string): Promise<void>;
|
|
28
|
+
/** Abandon run `taskId`'s commit: in ONE transaction / write section, delete the space's row iff it is still that run's
|
|
29
|
+
* and dead on the clock read under the row's lock ({@link decideSpaceCommitAbandon}). `true` ⇒ deleted. */
|
|
30
|
+
abandonSpaceCommit(spaceKey: string, taskId: string): Promise<boolean>;
|
|
31
|
+
}
|
|
32
|
+
/** Narrow a stored `state` cell to the closed set — an unknown word is a loud read failure, never a guess. */
|
|
33
|
+
export declare function spaceCommitStateOf(v: unknown): SpaceCommitState;
|
|
34
|
+
/** The ONE liveness predicate, shared by every backend and the reader: a row is alive while its writer's deadline is still
|
|
35
|
+
* ahead (`remainingMs > 0`) — the deadline in the row, never the caller's own bound. */
|
|
36
|
+
export declare function spaceCommitAlive(row: SpaceCommitReading): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The ONE claim rule, shared by every backend: what writing this run's row does to the row that is there.
|
|
39
|
+
* - none ⇒ insert (unless this run's own row is required — it is gone: refuse);
|
|
40
|
+
* - this run's row ⇒ move it while alive; past its deadline ⇒ refuse (a next run may have abandoned it);
|
|
41
|
+
* - another run's ⇒ replace it only when it is dead and this run's own row is not required; else refuse.
|
|
42
|
+
*/
|
|
43
|
+
export declare function decideSpaceCommitClaim(row: SpaceCommitReading | undefined, taskId: string, claim: {
|
|
44
|
+
readonly requireOwn: boolean;
|
|
45
|
+
}): "insert" | "update" | "refuse";
|
|
46
|
+
/** The ONE abandon rule, shared by every backend: the row read under its lock may be deleted iff it is still run
|
|
47
|
+
* `taskId`'s (the run whose row the reader saw dead) and still dead — renewed, taken by another run, or gone ⇒ keep. */
|
|
48
|
+
export declare function decideSpaceCommitAbandon(row: SpaceCommitReading | undefined, taskId: string): boolean;
|
|
49
|
+
/** The pending row a terminal write is asked to write (same transaction as the slot release). */
|
|
50
|
+
export interface PendingSpaceCommit {
|
|
51
|
+
readonly spaceKey: string;
|
|
52
|
+
readonly claim: SpaceCommitClaim;
|
|
53
|
+
}
|
|
54
|
+
/** One env's fence (the adapter's face). */
|
|
55
|
+
export interface SpaceCommitFence {
|
|
56
|
+
/** The space's current row (any run's) — what `connect()` waits on. Throws when the read fails. */
|
|
57
|
+
read(): Promise<SpaceCommitReading | undefined>;
|
|
58
|
+
/** Abandon the commit of run `deadTaskId` (whose row `read()` answered dead): `true` ⇒ its row is deleted under the
|
|
59
|
+
* row's lock; `false` ⇒ it was renewed, taken or already gone — re-read. Throws when the write fails. */
|
|
60
|
+
abandon(deadTaskId: string): Promise<boolean>;
|
|
61
|
+
/** This env now holds a workspace its `destroy()` will commit (call after the previous commit was waited out and the
|
|
62
|
+
* pod is up). `boundMs` = the upload's wall-clock bound — each write of this run's row sets its deadline to now + it. */
|
|
63
|
+
arm(boundMs: number): void;
|
|
64
|
+
/** The commit starts: the row becomes this run's `committing` (a fresh deadline). `false` ⇒ the fence is lost (this
|
|
65
|
+
* run's row is past its deadline, or another run's live row is there) — the commit must not publish. Throws when the
|
|
66
|
+
* write fails. */
|
|
67
|
+
begin(): Promise<boolean>;
|
|
68
|
+
/** The upload is done, `latest` is next: this run's row — only if it is still this run's and alive — becomes
|
|
69
|
+
* `publishing` (a fresh deadline). Answers the end of that deadline on this process's clock (epoch ms, counted from
|
|
70
|
+
* before the write, so never later than the row's own), or `undefined` = the fence is no longer this run's (its row is
|
|
71
|
+
* past its deadline or another run's, or no commit began) — `latest` must not be published. Throws when the write fails. */
|
|
72
|
+
publish(): Promise<number | undefined>;
|
|
73
|
+
/** The commit (or the workspace) is over: this run's row, if it wrote one, is deleted; the seat disarms. Throws when
|
|
74
|
+
* the delete fails (the seat is disarmed regardless). */
|
|
75
|
+
end(): Promise<void>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Open the fence of one env with an open space lane (the factory binding, per run). `taskId` = the run row's id
|
|
79
|
+
* (`ExecutionEnvFactoryContext.taskId`); absent ⇒ no terminal write can name this env — its commit is fenced from its
|
|
80
|
+
* start only. Returns a live object ⇒ `create*`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function createSpaceCommitFence(rows: SpaceCommitRows, spaceKey: string, taskId: string | undefined): SpaceCommitFence;
|
|
83
|
+
/**
|
|
84
|
+
* The terminal write's hook (every run store's `setTerminal`): `write` runs under the run's seat; it is offered the
|
|
85
|
+
* pending row iff the run's env is armed and has not begun committing, and returns whether that row is now this run's
|
|
86
|
+
* (written in the SAME transaction / write lock as the terminal row and the active-run slot release). No seat ⇒
|
|
87
|
+
* `write(undefined)`, nothing else.
|
|
88
|
+
*/
|
|
89
|
+
export declare function fenceSpaceCommitAtTerminal(taskId: string, write: (pending: PendingSpaceCommit | undefined) => Promise<boolean>): Promise<void>;
|
|
90
|
+
/** A row as an in-process twin keeps it (local File / memory run stores). `expiresAt` = its writer's deadline, epoch ms on
|
|
91
|
+
* this process's clock. The schema is the one reading of a persisted record (the File twin's `space-commits/<key>.json`). */
|
|
92
|
+
export declare const SPACE_COMMIT_RECORD_SCHEMA: z.ZodObject<{
|
|
93
|
+
spaceKey: z.ZodString;
|
|
94
|
+
taskId: z.ZodString;
|
|
95
|
+
state: z.ZodEnum<{
|
|
96
|
+
pending: "pending";
|
|
97
|
+
committing: "committing";
|
|
98
|
+
publishing: "publishing";
|
|
99
|
+
}>;
|
|
100
|
+
expiresAt: z.ZodNumber;
|
|
101
|
+
}, z.core.$strip>;
|
|
102
|
+
export type SpaceCommitRecord = Readonly<z.infer<typeof SPACE_COMMIT_RECORD_SCHEMA>>;
|
|
103
|
+
/**
|
|
104
|
+
* The in-process twins' table (local File / memory run stores): the SAME rule as the SQL twins over a record store the
|
|
105
|
+
* caller supplies (`load` / `save` / `remove`; the File twin persists each record, the memory twin keeps a map).
|
|
106
|
+
* Synchronous on purpose — the twins' terminal write calls `claimSync` inside its own synchronous write section.
|
|
107
|
+
* Returns a live object ⇒ `create*`.
|
|
108
|
+
*/
|
|
109
|
+
export declare function createInProcessSpaceCommitTable(records: {
|
|
110
|
+
load(spaceKey: string): SpaceCommitRecord | undefined;
|
|
111
|
+
save(record: SpaceCommitRecord): void;
|
|
112
|
+
remove(spaceKey: string): void;
|
|
113
|
+
}): SpaceCommitRows & {
|
|
114
|
+
claimSync(spaceKey: string, taskId: string, state: SpaceCommitState, claim: SpaceCommitClaim): boolean;
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=workspace-space-commit.d.ts.map
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const SPACE_COMMIT_STATES = ["pending", "committing", "publishing"];
|
|
4
|
+
export function spaceCommitStateOf(v) {
|
|
5
|
+
const word = String(v);
|
|
6
|
+
const known = SPACE_COMMIT_STATES.find((w) => w === word);
|
|
7
|
+
if (known !== undefined)
|
|
8
|
+
return known;
|
|
9
|
+
throw new Error(`workspace_space_commit: unknown state ${JSON.stringify(word)} (closed set: ${SPACE_COMMIT_STATES.join(" | ")})`);
|
|
10
|
+
}
|
|
11
|
+
export function spaceCommitAlive(row) {
|
|
12
|
+
return row.remainingMs > 0;
|
|
13
|
+
}
|
|
14
|
+
export function decideSpaceCommitClaim(row, taskId, claim) {
|
|
15
|
+
if (row === undefined)
|
|
16
|
+
return claim.requireOwn ? "refuse" : "insert";
|
|
17
|
+
if (row.taskId === taskId)
|
|
18
|
+
return spaceCommitAlive(row) ? "update" : "refuse";
|
|
19
|
+
return !claim.requireOwn && !spaceCommitAlive(row) ? "update" : "refuse";
|
|
20
|
+
}
|
|
21
|
+
export function decideSpaceCommitAbandon(row, taskId) {
|
|
22
|
+
return row !== undefined && row.taskId === taskId && !spaceCommitAlive(row);
|
|
23
|
+
}
|
|
24
|
+
const armed = new Map();
|
|
25
|
+
function serialize(seat, step) {
|
|
26
|
+
const run = seat.tail.then(step);
|
|
27
|
+
seat.tail = run.then(() => undefined, () => undefined);
|
|
28
|
+
return run;
|
|
29
|
+
}
|
|
30
|
+
export function createSpaceCommitFence(rows, spaceKey, taskId) {
|
|
31
|
+
const seat = { spaceKey, rowTaskId: taskId ?? `env-${randomUUID()}`, state: "idle", boundMs: 0, tail: Promise.resolve() };
|
|
32
|
+
return {
|
|
33
|
+
read: () => rows.readSpaceCommit(spaceKey),
|
|
34
|
+
abandon: (deadTaskId) => rows.abandonSpaceCommit(spaceKey, deadTaskId),
|
|
35
|
+
arm(boundMs) {
|
|
36
|
+
if (seat.state !== "idle")
|
|
37
|
+
return;
|
|
38
|
+
seat.state = "armed";
|
|
39
|
+
seat.boundMs = boundMs;
|
|
40
|
+
if (taskId !== undefined)
|
|
41
|
+
armed.set(taskId, seat);
|
|
42
|
+
},
|
|
43
|
+
begin: () => serialize(seat, async () => {
|
|
44
|
+
if (seat.state !== "armed" && seat.state !== "fenced")
|
|
45
|
+
return false;
|
|
46
|
+
const ok = await rows.claimSpaceCommit(spaceKey, seat.rowTaskId, "committing", { boundMs: seat.boundMs, requireOwn: seat.state === "fenced" });
|
|
47
|
+
if (ok)
|
|
48
|
+
seat.state = "committing";
|
|
49
|
+
return ok;
|
|
50
|
+
}),
|
|
51
|
+
publish: () => serialize(seat, async () => {
|
|
52
|
+
if (seat.state !== "committing")
|
|
53
|
+
return undefined;
|
|
54
|
+
const from = Date.now();
|
|
55
|
+
const ok = await rows.claimSpaceCommit(spaceKey, seat.rowTaskId, "publishing", { boundMs: seat.boundMs, requireOwn: true });
|
|
56
|
+
if (!ok)
|
|
57
|
+
return undefined;
|
|
58
|
+
seat.state = "publishing";
|
|
59
|
+
return from + seat.boundMs;
|
|
60
|
+
}),
|
|
61
|
+
end: () => serialize(seat, async () => {
|
|
62
|
+
const wrote = seat.state === "fenced" || seat.state === "committing" || seat.state === "publishing";
|
|
63
|
+
seat.state = "idle";
|
|
64
|
+
if (taskId !== undefined && armed.get(taskId) === seat)
|
|
65
|
+
armed.delete(taskId);
|
|
66
|
+
if (wrote)
|
|
67
|
+
await rows.endSpaceCommit(spaceKey, seat.rowTaskId);
|
|
68
|
+
}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export async function fenceSpaceCommitAtTerminal(taskId, write) {
|
|
72
|
+
const seat = armed.get(taskId);
|
|
73
|
+
if (seat === undefined) {
|
|
74
|
+
await write(undefined);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
await serialize(seat, async () => {
|
|
78
|
+
const offer = seat.state === "armed" ? { spaceKey: seat.spaceKey, claim: { boundMs: seat.boundMs, requireOwn: false } } : undefined;
|
|
79
|
+
const wrote = await write(offer);
|
|
80
|
+
if (offer !== undefined && wrote)
|
|
81
|
+
seat.state = "fenced";
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
export const SPACE_COMMIT_RECORD_SCHEMA = z.object({
|
|
85
|
+
spaceKey: z.string().min(1),
|
|
86
|
+
taskId: z.string().min(1),
|
|
87
|
+
state: z.enum(SPACE_COMMIT_STATES),
|
|
88
|
+
expiresAt: z.number().finite(),
|
|
89
|
+
});
|
|
90
|
+
export function createInProcessSpaceCommitTable(records) {
|
|
91
|
+
const reading = (spaceKey) => {
|
|
92
|
+
const r = records.load(spaceKey);
|
|
93
|
+
return r === undefined ? undefined : { taskId: r.taskId, state: r.state, remainingMs: r.expiresAt - Date.now() };
|
|
94
|
+
};
|
|
95
|
+
const claimSync = (spaceKey, taskId, state, claim) => {
|
|
96
|
+
if (decideSpaceCommitClaim(reading(spaceKey), taskId, claim) === "refuse")
|
|
97
|
+
return false;
|
|
98
|
+
records.save({ spaceKey, taskId, state, expiresAt: Date.now() + claim.boundMs });
|
|
99
|
+
return true;
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
readSpaceCommit: async (spaceKey) => reading(spaceKey),
|
|
103
|
+
claimSpaceCommit: async (spaceKey, taskId, state, claim) => claimSync(spaceKey, taskId, state, claim),
|
|
104
|
+
endSpaceCommit: async (spaceKey, taskId) => {
|
|
105
|
+
if (records.load(spaceKey)?.taskId === taskId)
|
|
106
|
+
records.remove(spaceKey);
|
|
107
|
+
},
|
|
108
|
+
abandonSpaceCommit: async (spaceKey, taskId) => {
|
|
109
|
+
if (!decideSpaceCommitAbandon(reading(spaceKey), taskId))
|
|
110
|
+
return false;
|
|
111
|
+
records.remove(spaceKey);
|
|
112
|
+
return true;
|
|
113
|
+
},
|
|
114
|
+
claimSync,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=workspace-space-commit.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Workspace persistence by **space** (k8s lane) — the closed word set, the defaults, the retention domain and
|
|
3
|
-
* the policy shape (pure leaf: no value imports
|
|
4
|
-
* all import it without a load cycle). The effective policy has ONE reading: the capability fact `workspaceSpace`
|
|
3
|
+
* the policy shape (pure leaf: no value imports from this repo — only a node builtin — so `config.ts`, the capability fact and the adapter
|
|
4
|
+
* in `plugins/` can all import it without a load cycle). The effective policy has ONE reading: the capability fact `workspaceSpace`
|
|
5
5
|
* (`src/capability-facts.ts`).
|
|
6
6
|
*
|
|
7
7
|
* The law (one fact, one seat): a k8s pod's `/workspace` is durable across runs as an object-store "space" owned by the
|
|
@@ -15,16 +15,17 @@
|
|
|
15
15
|
* Facility dependence: without a snapshot store (`s3Snapshot`) there is nothing to persist into — the fact is
|
|
16
16
|
* unavailable and the lane behaves exactly as before (fresh pod, empty `/workspace` every run).
|
|
17
17
|
*/
|
|
18
|
+
/** The k8s lane's workspace mount when `K8S_MOUNT_PATH` is unset (the adapter's default; the cache mount is checked against it). */
|
|
19
|
+
export declare const K8S_WORKSPACE_MOUNT_DEFAULT = "/workspace";
|
|
18
20
|
/** `WORKSPACE_PERSIST` closed set. `space` = the k8s workspace persists per space (the session occupant); `off` = a fresh
|
|
19
21
|
* workspace every run. */
|
|
20
22
|
export declare const WORKSPACE_PERSIST_WORDS: readonly ["space", "off"];
|
|
21
23
|
export type WorkspacePersist = (typeof WORKSPACE_PERSIST_WORDS)[number];
|
|
22
24
|
/**
|
|
23
|
-
* Default `
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* is released; until then a deployment turns persistence on knowing the window (USAGE §9.3b).
|
|
25
|
+
* Default `space`: a k8s lane with a snapshot store persists `/workspace` across runs. The run-end commit's ordering against
|
|
26
|
+
* the NEXT run is a commit fence held in server-side durable state — the run store's `workspace_space_commit` row, written
|
|
27
|
+
* by the run's terminal write before the session's active-run slot is released (`workspace-space-commit.ts`) — so the next
|
|
28
|
+
* run waits for the previous run's commit instead of restoring an older snapshot. `off` = a fresh workspace every run.
|
|
28
29
|
*/
|
|
29
30
|
export declare const WORKSPACE_PERSIST_DEFAULT: WorkspacePersist;
|
|
30
31
|
/** `WORKSPACE_SNAPSHOT_KEEP` — snapshots kept per space key (closed integer domain; out of domain refuses boot). */
|
|
@@ -33,9 +34,74 @@ export declare const WORKSPACE_SNAPSHOT_KEEP_RANGE: {
|
|
|
33
34
|
readonly min: 1;
|
|
34
35
|
readonly max: 50;
|
|
35
36
|
};
|
|
36
|
-
/**
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
|
+
* `WORKSPACE_SNAPSHOT_TIMEOUT_MS` — the k8s lane's ONE data bound (closed integer domain; out of domain refuses boot): the
|
|
39
|
+
* snapshot upload's and the restore's wall-clock, the reclaim seat's one absolute deadline per call (the cache volume and the objects of every space in that call), and the deadline a run's commit writes into its fence row (now + this
|
|
40
|
+
* number at each write — a next run waits for that run's commit until the deadline IN THE ROW, whatever its own replica's
|
|
41
|
+
* number) are all this one number (the adapter's `dataTimeoutMs`); it also bounds a large file transfer's wall-clock (a
|
|
42
|
+
* stalled one is cut earlier by the command liveness bound).
|
|
43
|
+
*/
|
|
44
|
+
export declare const WORKSPACE_SNAPSHOT_TIMEOUT_MS_DEFAULT = 300000;
|
|
45
|
+
export declare const WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE: {
|
|
46
|
+
readonly min: 30000;
|
|
47
|
+
readonly max: 3600000;
|
|
48
|
+
};
|
|
49
|
+
/** The lane's data bound as configured — the ONE reading of `WORKSPACE_SNAPSHOT_TIMEOUT_MS` (the loader always mints it; a
|
|
50
|
+
* hand-built config may omit it ⇒ the default): the boot assembly hands it to the adapter (`dataTimeoutMs`) and the capability
|
|
51
|
+
* fact reports it (`workspaceSync.timeoutMs`) — the same call, so the two never disagree. */
|
|
52
|
+
export declare function workspaceSnapshotTimeoutOf(lane: {
|
|
53
|
+
readonly workspaceSnapshotTimeoutMs?: number;
|
|
54
|
+
}): number;
|
|
55
|
+
/** The space policy the k8s adapter acts on (persistence word + retention). */
|
|
56
|
+
export interface WorkspaceSpacePolicy {
|
|
38
57
|
persist: WorkspacePersist;
|
|
39
58
|
keep: number;
|
|
40
59
|
}
|
|
60
|
+
/** The effective space policy as reported — the `workspaceSpace` fact's witness and the value of `GET /v1/capabilities.workspaceSync`:
|
|
61
|
+
* the policy plus the lane's data bound (`timeoutMs`, the snapshot upload / restore wall-clock and the longest a next run waits
|
|
62
|
+
* for the previous run's commit). The adapter gets the bound as `dataTimeoutMs`, never through this object. */
|
|
63
|
+
export interface WorkspaceSyncCapability extends WorkspaceSpacePolicy {
|
|
64
|
+
timeoutMs: number;
|
|
65
|
+
}
|
|
66
|
+
/** The refusal code of a `WORKSPACE_SNAPSHOT_EXCLUDE` item outside the closed form (the `config.*` family; fatal-exit prints it). */
|
|
67
|
+
export declare const WORKSPACE_SNAPSHOT_EXCLUDE_INVALID = "config.workspace_snapshot_exclude_invalid";
|
|
68
|
+
/**
|
|
69
|
+
* `WORKSPACE_SNAPSHOT_EXCLUDE` — the snapshot's exclusion table: a CSV of tar exclusion patterns relative to the workspace
|
|
70
|
+
* root (`build,.gradle,node_modules/.cache`), applied by the adapter's ONE tar upload as `--exclude=./<item>` (so the run-end
|
|
71
|
+
* space snapshot and the park suspend share it). Unset / empty ⇒ no table (the upload command is what it always was).
|
|
72
|
+
*
|
|
73
|
+
* The item form is CLOSED: plain relative path segments — no leading `/`, no `.` / `..` / empty segment (`./x`, `a//b`, a
|
|
74
|
+
* trailing `/`), no whitespace, no quote characters, no control characters. Tar wildcards inside a segment (`*.log`) are items
|
|
75
|
+
* like any other. A project's `.gitignore` is NOT read (a second grammar, per project, not equivalent to tar's). Items are
|
|
76
|
+
* trimmed (the CSV separator's spacing is not part of an item); a bad item refuses boot naming its position — the value is a
|
|
77
|
+
* path pattern, never a secret, so it is echoed.
|
|
78
|
+
*/
|
|
79
|
+
export declare function parseWorkspaceSnapshotExclude(raw: string | undefined): readonly string[];
|
|
80
|
+
/** Mint one snapshot id: `kata-<owner>-<ts36>-<rand>` (see {@link SNAPSHOT_OWNER_NONE}). The time and random parts only keep ids unique; nothing reads them back. */
|
|
81
|
+
export declare function mintSnapshotId(incarnation: string | undefined): string;
|
|
82
|
+
/** Whether an object name in the park partition (`<snapshotId>.tar.gz`, or any single-segment name) carries the mark of THIS occupant incarnation.
|
|
83
|
+
* An empty incarnation owns nothing; `none` and unmarked names are never owned (fail closed). */
|
|
84
|
+
export declare function snapshotNameOwnedBy(name: string, incarnation: string): boolean;
|
|
85
|
+
/** One ended space, as the reclaim seat is told of it: the session whose space ended (its park lane's partition) and the space key
|
|
86
|
+
* (the occupant's incarnation — the `space/` partition, the cache volume's label and, through {@link snapshotNameOwnedBy}, the owner mark of
|
|
87
|
+
* the park objects that are this occupant's). An empty `spaceKey` is not a space (the occupant could not be read) — the seat skips it. */
|
|
88
|
+
export interface EndedSpace {
|
|
89
|
+
readonly sessionId: string;
|
|
90
|
+
readonly spaceKey: string;
|
|
91
|
+
}
|
|
92
|
+
/** The closed word set of `workspace_cache_reclaim_failed.reason` — ONE owner for both legs of the reclaim (the seat in
|
|
93
|
+
* `plugins/remote-env-k8s.ts` says `delete_failed` / `budget`; the session-delete coordinator says `occupant_unreadable`). */
|
|
94
|
+
export type CacheReclaimReason = "delete_failed" | "budget" | "occupant_unreadable";
|
|
95
|
+
/**
|
|
96
|
+
* The ONE reclaim seat for an ended space — called where a space ENDS: the session-delete coordinator (`boot/session-faces.ts` `purgeSession`)
|
|
97
|
+
* and the managed-retention sweep after it deletes session trees (`boot/retention-lane.ts`); neither writes a reclaim of its own. It reclaims
|
|
98
|
+
* everything the space left behind: the cache volume (when configured), the `space/` snapshot partition and the session's park snapshots whose names carry the ended occupant's ownership mark (when a
|
|
99
|
+
* snapshot store is configured; old-form / `none` park objects are left to the bucket's lifecycle rule). ONE call runs under ONE
|
|
100
|
+
* absolute deadline (`dataTimeoutMs`) built at its entry — the cache volume and the objects of every space in the call; a space the deadline passed
|
|
101
|
+
* before reaching sends nothing and says so. Callers may fire-and-forget it (the session-delete coordinator does). A part that cannot be reclaimed = one operator line + `recordFailOpen`; NEVER throws: a space's leftovers never
|
|
102
|
+
* block a deletion (the bucket's lifecycle rule is the fallback for objects).
|
|
103
|
+
*/
|
|
104
|
+
export interface SpaceReclaimer {
|
|
105
|
+
reclaim(spaces: readonly EndedSpace[]): Promise<void>;
|
|
106
|
+
}
|
|
41
107
|
//# sourceMappingURL=workspace-space.d.ts.map
|
package/dist/workspace-space.js
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export const K8S_WORKSPACE_MOUNT_DEFAULT = "/workspace";
|
|
1
3
|
export const WORKSPACE_PERSIST_WORDS = ["space", "off"];
|
|
2
|
-
export const WORKSPACE_PERSIST_DEFAULT = "
|
|
4
|
+
export const WORKSPACE_PERSIST_DEFAULT = "space";
|
|
3
5
|
export const WORKSPACE_SNAPSHOT_KEEP_DEFAULT = 3;
|
|
4
6
|
export const WORKSPACE_SNAPSHOT_KEEP_RANGE = { min: 1, max: 50 };
|
|
7
|
+
export const WORKSPACE_SNAPSHOT_TIMEOUT_MS_DEFAULT = 300_000;
|
|
8
|
+
export const WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE = { min: 30_000, max: 3_600_000 };
|
|
9
|
+
export function workspaceSnapshotTimeoutOf(lane) {
|
|
10
|
+
return lane.workspaceSnapshotTimeoutMs ?? WORKSPACE_SNAPSHOT_TIMEOUT_MS_DEFAULT;
|
|
11
|
+
}
|
|
12
|
+
export const WORKSPACE_SNAPSHOT_EXCLUDE_INVALID = "config.workspace_snapshot_exclude_invalid";
|
|
13
|
+
export function parseWorkspaceSnapshotExclude(raw) {
|
|
14
|
+
if (raw === undefined || raw.trim() === "")
|
|
15
|
+
return [];
|
|
16
|
+
const items = raw.split(",").map((s) => s.trim());
|
|
17
|
+
items.forEach((item, i) => {
|
|
18
|
+
const problem = snapshotExcludeItemProblem(item);
|
|
19
|
+
if (problem === undefined)
|
|
20
|
+
return;
|
|
21
|
+
throw Object.assign(new Error(`env WORKSPACE_SNAPSHOT_EXCLUDE: item #${i + 1} of ${items.length} (${JSON.stringify(item)}) is ${problem} — each item is a tar exclusion pattern ` +
|
|
22
|
+
"relative to the workspace root, in plain path segments (e.g. WORKSPACE_SNAPSHOT_EXCLUDE=build,.gradle,node_modules/.cache); refusing to start rather than snapshot with a table that does not say what it means"), { code: WORKSPACE_SNAPSHOT_EXCLUDE_INVALID });
|
|
23
|
+
});
|
|
24
|
+
return items;
|
|
25
|
+
}
|
|
26
|
+
function snapshotExcludeItemProblem(item) {
|
|
27
|
+
if (item === "")
|
|
28
|
+
return "empty";
|
|
29
|
+
if (/[\s'"`\u0000-\u001f\u007f]/.test(item))
|
|
30
|
+
return "not a plain path (it holds whitespace, a quote or a control character)";
|
|
31
|
+
if (item.startsWith("/"))
|
|
32
|
+
return "absolute (a leading /) — items are relative to the workspace root";
|
|
33
|
+
const segments = item.split("/");
|
|
34
|
+
if (segments.includes(".."))
|
|
35
|
+
return "escaping the workspace (a .. segment)";
|
|
36
|
+
if (segments.some((s) => s === "" || s === "."))
|
|
37
|
+
return "not in plain segments (an empty or . segment: ./x, a//b, a trailing /)";
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const SNAPSHOT_OWNER_NONE = "none";
|
|
41
|
+
const SNAPSHOT_OWNER_HEX_LENGTH = 16;
|
|
42
|
+
const SNAPSHOT_ID_FAMILY = "kata";
|
|
43
|
+
function snapshotOwnerOf(incarnation) {
|
|
44
|
+
if (incarnation === undefined || incarnation === "")
|
|
45
|
+
return SNAPSHOT_OWNER_NONE;
|
|
46
|
+
return createHash("sha256").update(incarnation).digest("hex").slice(0, SNAPSHOT_OWNER_HEX_LENGTH);
|
|
47
|
+
}
|
|
48
|
+
export function mintSnapshotId(incarnation) {
|
|
49
|
+
return `${SNAPSHOT_ID_FAMILY}-${snapshotOwnerOf(incarnation)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
50
|
+
}
|
|
51
|
+
export function snapshotNameOwnedBy(name, incarnation) {
|
|
52
|
+
if (incarnation === "")
|
|
53
|
+
return false;
|
|
54
|
+
return name.startsWith(`${SNAPSHOT_ID_FAMILY}-${snapshotOwnerOf(incarnation)}-`);
|
|
55
|
+
}
|
|
5
56
|
//# sourceMappingURL=workspace-space.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.127.0",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@sema-agent/core": "7.
|
|
68
|
-
"@sema-agent/settings-schema": "
|
|
67
|
+
"@sema-agent/core": "7.50.2",
|
|
68
|
+
"@sema-agent/settings-schema": "12.2.1",
|
|
69
69
|
"e2b": "^2.28.0",
|
|
70
70
|
"libsodium-wrappers": "^0.8.4",
|
|
71
71
|
"mysql2": "^3.22.4",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"sharp": "^0.35.3"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@sema-agent/sdk": "
|
|
83
|
+
"@sema-agent/sdk": "21.1.0",
|
|
84
84
|
"@types/libsodium-wrappers": "^0.7.14",
|
|
85
85
|
"@types/node": "22.10.2",
|
|
86
86
|
"@types/pg": "^8.20.0",
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S-506([ref] §5)—— 记忆引擎的会话化身座 `RunnerDeps.memorySessionIncarnation` 的装配件。
|
|
3
|
-
*
|
|
4
|
-
* core 的座是**同步**签名(`({ sessionId }) => string | undefined`),而会话化身住在会话元数据里、读它是异步的 ⇒ 两段:
|
|
5
|
-
* · **写**(装配期):resolve-spec 每次提交(fresh 与 resume 腿同经)经 {@link createAssemblyIncarnationRead} 造的读口异步读一次会话面,
|
|
6
|
-
* 记进本副本的 per-session 登记簿(`boot/execution-env.ts` 的 `noteSessionIncarnation`,与 cwd / shellEnv 同一只 LRU、同一条围栏、
|
|
7
|
-
* 同一条删除);
|
|
8
|
-
* · **读**(运行期):{@link createMemorySessionIncarnationSeat} 从登记簿同步取。
|
|
9
|
-
*
|
|
10
|
-
* ## 读口缺席是装配期事实(合并复审 F2)
|
|
11
|
-
* 「会话店有没有 `sessionFaceOf`」由 {@link sessionFaceReaderOf} 判,resolve-spec 与 runner-deps 读同一只:缺席(内存会话店 /
|
|
12
|
-
* 多租户裸 boot / 降级到内存的副本)⇒ resolve-spec **构造时** warn 一次、请求路径上不再判不再打;记忆座不装(恒答 undefined 的座与不装
|
|
13
|
-
* 同义,core 按 id 绑定 = 修前行为)。修前是每一次提交打一行。
|
|
14
|
-
*
|
|
15
|
-
* ## 读不到的臂([ref]:响亮,不静默)
|
|
16
|
-
* 会话不在 / 读口抛(含空化身的响亮拒)⇒ 这一轮没有化身 ⇒ 座答 `undefined`(core 口径:按 id 绑定 —— 今天的行为,且是**保守**方向:
|
|
17
|
-
* 上一位住客的 opt-out / 污染标记仍会约束这一位,不会让任何一条被放过)+ warn,**按会话去重**(同一只会话连着读不到只说一次,读到了再
|
|
18
|
-
* 读不到重新说)。没有「读不到就沿用上次」的臂:装配期读失败会把登记簿那一格**清掉**,座随之答 undefined。
|
|
19
|
-
*
|
|
20
|
-
* ## 令牌不出本进程的内存
|
|
21
|
-
* 不上 wire、不进模型上下文;warn 行只带会话 id —— 缺席的那一臂根本没有令牌可打。
|
|
22
|
-
*/
|
|
23
|
-
import type { RunnerDeps } from "@sema-agent/core";
|
|
24
|
-
import type { SessionFaceReader } from "../session-incarnation.js";
|
|
25
|
-
/** warn 口(logger 的子集)。 */
|
|
26
|
-
type Warn = (event: string, fields: Record<string, unknown>) => void;
|
|
27
|
-
/** 会话店的「属主 + 化身」读口 —— 装配期判一次(resolve-spec 与 runner-deps 读同一只,判据不各写一份)。缺席 = 这只会话店没有它。 */
|
|
28
|
-
export declare function sessionFaceReaderOf(store: unknown): SessionFaceReader | undefined;
|
|
29
|
-
/**
|
|
30
|
-
* 装配期化身读口(resolve-spec **构造时**建一次)。读口缺席 ⇒ 当场 warn 一次、返回 `undefined`(请求路径上不再判不再打);
|
|
31
|
-
* 在场 ⇒ 返回一只读:读到 ⇒ 化身;会话不在 / 读抛 ⇒ `undefined` + 按会话去重的 warn。不抛:这是记忆座的输入,不是提交的准入门
|
|
32
|
-
* (提交的属主门在 authorizer;读失败的那一格由座答 undefined 兜成保守绑定)。
|
|
33
|
-
*/
|
|
34
|
-
export declare function createAssemblyIncarnationRead(read: SessionFaceReader | undefined, warn: Warn): ((sessionId: string) => Promise<string | undefined>) | undefined;
|
|
35
|
-
/**
|
|
36
|
-
* `RunnerDeps.memorySessionIncarnation` 的同步座:从本副本的 per-session 登记簿取装配期读数。缺席 ⇒ `undefined` + 每个会话一行 warn。
|
|
37
|
-
* 命名照工厂律:返回的是带行为的闭包 ⇒ `create*`。
|
|
38
|
-
*/
|
|
39
|
-
export declare function createMemorySessionIncarnationSeat(incarnationOf: (sessionId: string) => string | undefined, warn: Warn): NonNullable<RunnerDeps["memorySessionIncarnation"]>;
|
|
40
|
-
export {};
|
|
41
|
-
//# sourceMappingURL=session-incarnation-seat.d.ts.map
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const MISS_WARNED_MAX = 4096;
|
|
2
|
-
export function sessionFaceReaderOf(store) {
|
|
3
|
-
const s = store;
|
|
4
|
-
return typeof s?.sessionFaceOf === "function" ? s.sessionFaceOf.bind(s) : undefined;
|
|
5
|
-
}
|
|
6
|
-
function createPerSessionWarn(warn) {
|
|
7
|
-
const warned = new Set();
|
|
8
|
-
return {
|
|
9
|
-
once(sessionId, fields) {
|
|
10
|
-
if (warned.has(sessionId))
|
|
11
|
-
return;
|
|
12
|
-
if (warned.size >= MISS_WARNED_MAX)
|
|
13
|
-
warned.clear();
|
|
14
|
-
warned.add(sessionId);
|
|
15
|
-
warn("session_incarnation_unavailable", { sessionId, ...fields });
|
|
16
|
-
},
|
|
17
|
-
clear(sessionId) {
|
|
18
|
-
warned.delete(sessionId);
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
export function createAssemblyIncarnationRead(read, warn) {
|
|
23
|
-
if (read === undefined) {
|
|
24
|
-
warn("session_incarnation_unavailable", {
|
|
25
|
-
reason: "no_session_face_read",
|
|
26
|
-
note: "this deployment's session store has no sessionFaceOf read (an in-memory session store) — session incarnations are not read and memory records bind by id alone; stated once at assembly",
|
|
27
|
-
});
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
const perSession = createPerSessionWarn(warn);
|
|
31
|
-
return async (sessionId) => {
|
|
32
|
-
try {
|
|
33
|
-
const face = await read(sessionId);
|
|
34
|
-
if (face === undefined) {
|
|
35
|
-
perSession.once(sessionId, { reason: "session_absent", note: "no session row at assembly — memory records for this session bind by id alone this run" });
|
|
36
|
-
return undefined;
|
|
37
|
-
}
|
|
38
|
-
perSession.clear(sessionId);
|
|
39
|
-
return face.incarnation;
|
|
40
|
-
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
const code = e?.code;
|
|
43
|
-
perSession.once(sessionId, {
|
|
44
|
-
reason: typeof code === "string" ? code : "read_failed",
|
|
45
|
-
note: "the session face could not be read at assembly — memory records for this session bind by id alone this run",
|
|
46
|
-
});
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
export function createMemorySessionIncarnationSeat(incarnationOf, warn) {
|
|
52
|
-
const warned = new Set();
|
|
53
|
-
return ({ sessionId }) => {
|
|
54
|
-
const incarnation = incarnationOf(sessionId);
|
|
55
|
-
if (incarnation !== undefined)
|
|
56
|
-
return incarnation;
|
|
57
|
-
if (!warned.has(sessionId)) {
|
|
58
|
-
if (warned.size >= MISS_WARNED_MAX)
|
|
59
|
-
warned.clear();
|
|
60
|
-
warned.add(sessionId);
|
|
61
|
-
warn("memory_session_incarnation_unknown", {
|
|
62
|
-
sessionId,
|
|
63
|
-
note: "no incarnation was read for this session on this replica (not assembled here, or its read failed) — the memory engine binds this session's records by id alone",
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
return undefined;
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
//# sourceMappingURL=session-incarnation-seat.js.map
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { runTeamDiscussion, type Runner, type ToolSpec } from "@sema-agent/core";
|
|
2
|
-
import type { Metrics } from "../observability/metrics.js";
|
|
3
|
-
import type { Logger } from "../observability/logger.js";
|
|
4
|
-
type TeamFn = typeof runTeamDiscussion;
|
|
5
|
-
/**
|
|
6
|
-
* Code-review council (Option C+, layers L1 + L3) packaged as ONE tool, so the run model is unchanged
|
|
7
|
-
* and the orchestration is **code-driven** (deterministic — we don't rely on the model to follow a
|
|
8
|
-
* multi-step orchestration prompt, which live runs showed it doesn't do reliably).
|
|
9
|
-
*
|
|
10
|
-
* - L1 (gather): one isolated, read-only-repo-tooled subagent PER differential lens, run in PARALLEL.
|
|
11
|
-
* - L3 (arbitrate): a neutral arbiter grounds/dedups/buckets/ranks. It does not add findings.
|
|
12
|
-
* - L2 (peer debate over findings + dispute verification with member tools) is the next layer.
|
|
13
|
-
*
|
|
14
|
-
* Research basis (core's design): tooled differential exploration is the main source of real bugs;
|
|
15
|
-
* grounding + bucketing kill "imagined requirements" and stop a design preference being filed as a bug.
|
|
16
|
-
*/
|
|
17
|
-
interface Lens {
|
|
18
|
-
name: string;
|
|
19
|
-
brief: string;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Caller-tunable lens COUNT (OA request) — a structured cost/coverage dial, sibling of `@model` / `council` /
|
|
23
|
-
* `debate`. The deployment owns WHICH lenses (the `LENSES` order = the priority: security/correctness first =
|
|
24
|
-
* the bug-finders); the caller only picks HOW MANY. Clamp to [1, LENSES.length]; absent / non-numeric = ALL
|
|
25
|
-
* (the current default → zero regression). A named subset is deliberately NOT supported (it would force a
|
|
26
|
-
* published, maintained lens vocabulary contract; the count is the verifiable knob a "light/standard" UI needs).
|
|
27
|
-
*/
|
|
28
|
-
export declare function pickLenses(count?: number): readonly Lens[];
|
|
29
|
-
/** Caller-settable debate rounds: a FINITE integer clamped to [1,3]; non-number / NaN / ±Infinity = undefined
|
|
30
|
-
* (→ the council's default of 1). Mirrors `pickLenses`'s `Number.isFinite` guard — the previous inline clamp let
|
|
31
|
-
* `NaN` through (`typeof NaN === "number"`, `Math.min(3, NaN) === NaN`), corrupting the cost metric (council). */
|
|
32
|
-
export declare function clampRounds(rounds: unknown): number | undefined;
|
|
33
|
-
export interface CouncilToolOptions {
|
|
34
|
-
/** Aggregate the council's (otherwise invisible) sub-task cost into metrics. */
|
|
35
|
-
metrics?: Metrics;
|
|
36
|
-
logger?: Logger;
|
|
37
|
-
/** L1+L2+L3: add a peer-team debate (tool-grounded) before arbitration. Default L1+L3 only. */
|
|
38
|
-
debate?: boolean;
|
|
39
|
-
/** Debate rounds (when `debate`). Default 1. */
|
|
40
|
-
rounds?: number;
|
|
41
|
-
/** Caller-chosen lens COUNT (cost/coverage dial). Clamped to [1, LENSES.length]; absent = all lenses. */
|
|
42
|
-
lensCount?: number;
|
|
43
|
-
/** Injectable for tests; defaults to core's runTeamDiscussion. */
|
|
44
|
-
teamFn?: TeamFn;
|
|
45
|
-
}
|
|
46
|
-
/** Build the `run_council` tool. The lead calls it once; it returns the final arbitrated review. */
|
|
47
|
-
export declare function createCouncilTool(subRunner: Runner, repoTools: ToolSpec[], objective: string, opts?: CouncilToolOptions): ToolSpec;
|
|
48
|
-
export {};
|
|
49
|
-
//# sourceMappingURL=code-review-council.d.ts.map
|