@sema-agent/server 7.140.0 → 7.141.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 +290 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +75 -13
- package/dist/approval-batch-census.d.ts +27 -0
- package/dist/approval-batch-census.js +27 -0
- package/dist/approval-card.d.ts +31 -16
- package/dist/approval-card.js +6 -3
- package/dist/approval.d.ts +15 -0
- package/dist/approval.js +10 -0
- package/dist/audit.d.ts +4 -2
- package/dist/audit.js +2 -2
- package/dist/boot/device-lane.d.ts +11 -0
- package/dist/boot/device-lane.js +16 -0
- package/dist/boot/engine-lease.d.ts +24 -3
- package/dist/boot/engine-lease.js +9 -2
- package/dist/boot/execution-env.js +8 -4
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +1 -1
- package/dist/boot/memory-consolidation.js +1 -1
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/resolve-spec.js +7 -4
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.js +5 -0
- package/dist/boot/stage-05-execution-env.js +3 -1
- package/dist/boot/stage-06-runners.d.ts +0 -2
- package/dist/boot/stage-06-runners.js +1 -1
- package/dist/boot/stage-07-capability-layer.d.ts +0 -1
- package/dist/boot/stage-07-capability-layer.js +8 -10
- package/dist/boot/stage-08-reapers.d.ts +0 -1
- package/dist/boot/stage-09-leader.d.ts +0 -1
- package/dist/boot/stage-10-http-server.d.ts +0 -1
- package/dist/boot/stage-10-http-server.js +1 -0
- package/dist/boot/stores.js +10 -4
- package/dist/boot/web-admin.js +1 -0
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +9 -0
- package/dist/capability-facts.js +9 -0
- package/dist/card-void.d.ts +38 -0
- package/dist/card-void.js +23 -0
- package/dist/config-catalog.js +11 -8
- package/dist/config-provider.d.ts +13 -13
- package/dist/config-provider.js +19 -33
- package/dist/config-types.d.ts +26 -8
- package/dist/config.js +55 -46
- package/dist/delegated-session-owner.d.ts +21 -19
- package/dist/delegated-session-owner.js +1 -1
- package/dist/device-store.d.ts +7 -0
- package/dist/device-store.js +3 -0
- package/dist/execution-config-root.d.ts +22 -0
- package/dist/execution-config-root.js +35 -0
- package/dist/execution-lane-caps.d.ts +49 -2
- package/dist/execution-lane-caps.js +90 -13
- package/dist/execution-placement.d.ts +3 -0
- package/dist/execution-placement.js +7 -0
- package/dist/fleet/drain-entry.d.ts +3 -0
- package/dist/hosted-posture.d.ts +8 -0
- package/dist/hosted-posture.js +4 -0
- package/dist/http/admission.js +3 -3
- package/dist/http/caller-trust.d.ts +3 -2
- package/dist/http/caller-trust.js +2 -1
- package/dist/http/dispatch.js +4 -0
- package/dist/http/live-frame.d.ts +24 -0
- package/dist/http/live-frame.js +16 -0
- package/dist/http/resume-legs.js +37 -20
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/capabilities.js +5 -4
- package/dist/http/routes/diagnostics.d.ts +0 -19
- package/dist/http/routes/diagnostics.js +16 -2
- package/dist/http/routes/memory-bundle.d.ts +2 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-policy.js +2 -2
- package/dist/http/routes/run-permission-mode.d.ts +75 -0
- package/dist/http/routes/run-permission-mode.js +170 -0
- package/dist/http/routes/session-sync.d.ts +3 -6
- package/dist/http/routes/session-sync.js +7 -2
- package/dist/http/routes/sessions.js +5 -4
- package/dist/http/routes/tasks.js +63 -66
- package/dist/http/run-read-face.js +3 -3
- package/dist/http/send.d.ts +1 -1
- package/dist/http/send.js +2 -2
- package/dist/http/server.d.ts +9 -2
- package/dist/http/sse-log.d.ts +3 -8
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +3 -1
- package/dist/instruction-source-notice.d.ts +7 -0
- package/dist/instruction-source-notice.js +6 -6
- package/dist/mcp-assertion-header.d.ts +4 -0
- package/dist/mcp-assertion-header.js +5 -0
- package/dist/memory-posture.d.ts +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +1 -1
- package/dist/memory-sync-client.d.ts +14 -2
- package/dist/memory-sync-client.js +80 -18
- package/dist/observability/fail-open.d.ts +30 -2
- package/dist/observability/fail-open.js +30 -2
- package/dist/observability/metrics.js +0 -1
- package/dist/observability/run-terminal.d.ts +6 -2
- package/dist/observability/run-terminal.js +25 -26
- package/dist/observability/secret-env-scrub.d.ts +20 -1
- package/dist/observability/secret-env-scrub.js +14 -0
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
- package/dist/orchestration/workflow-completion-inbox.js +13 -5
- package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
- package/dist/orchestration/workflow-notify-journal.js +2 -1
- package/dist/permission-mode-admission.d.ts +68 -0
- package/dist/permission-mode-admission.js +23 -0
- package/dist/permission-rule-list.d.ts +55 -6
- package/dist/permission-rule-list.js +52 -5
- package/dist/plugins/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
- package/dist/plugins/checkpoint-store-sql.js +74 -3
- package/dist/plugins/device-store-sql.d.ts +5 -2
- package/dist/plugins/device-store-sql.js +4 -1
- package/dist/plugins/execution-placement-sql.d.ts +11 -1
- package/dist/plugins/execution-placement-sql.js +12 -1
- package/dist/plugins/file-run-store.d.ts +2 -2
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/fork-routing-session-store.d.ts +10 -32
- package/dist/plugins/fork-routing-session-store.js +2 -61
- package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
- package/dist/plugins/k8s-exec-protocol.js +6 -1
- package/dist/plugins/local-checkpoint-store.d.ts +10 -1
- package/dist/plugins/local-checkpoint-store.js +22 -0
- package/dist/plugins/local-session-store.d.ts +227 -35
- package/dist/plugins/local-session-store.js +518 -37
- package/dist/plugins/local-session-window.d.ts +17 -3
- package/dist/plugins/local-session-window.js +7 -13
- package/dist/plugins/memory-run-store.d.ts +2 -2
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/one-time-migrations.d.ts +42 -2
- package/dist/plugins/one-time-migrations.js +65 -3
- package/dist/plugins/pg-pool.js +3 -2
- package/dist/plugins/pg-session-storage.d.ts +2 -0
- package/dist/plugins/pg-session-storage.js +3 -2
- package/dist/plugins/remote-env-e2b.d.ts +24 -3
- package/dist/plugins/remote-env-e2b.js +131 -18
- package/dist/plugins/remote-env-k8s.d.ts +20 -1
- package/dist/plugins/remote-env-k8s.js +148 -25
- package/dist/plugins/remote-env-local-docker.d.ts +25 -11
- package/dist/plugins/remote-env-local-docker.js +87 -21
- package/dist/plugins/run-store-sql.d.ts +3 -3
- package/dist/plugins/run-store-sql.js +4 -3
- package/dist/plugins/sandbox-read-floor.d.ts +273 -0
- package/dist/plugins/sandbox-read-floor.js +608 -0
- package/dist/plugins/session-ownership.d.ts +2 -1
- package/dist/plugins/session-placement.d.ts +17 -4
- package/dist/plugins/session-placement.js +2 -1
- package/dist/plugins/session-store.d.ts +18 -20
- package/dist/plugins/session-store.js +4 -12
- package/dist/plugins/store-backend.d.ts +31 -0
- package/dist/plugins/store-backend.js +21 -4
- package/dist/plugins/store-contracts.d.ts +9 -2
- package/dist/plugins/tidb-pool.js +2 -1
- package/dist/plugins/tidb-session-store.d.ts +4 -1
- package/dist/plugins/tidb-session-store.js +3 -2
- package/dist/run-cancel-context.d.ts +34 -0
- package/dist/run-cancel-context.js +7 -0
- package/dist/runs.d.ts +39 -12
- package/dist/runs.js +68 -53
- package/dist/security.d.ts +2 -2
- package/dist/server-secret-env.d.ts +2 -1
- package/dist/server-secret-env.js +2 -4
- package/dist/session-error-wire.d.ts +22 -4
- package/dist/session-error-wire.js +16 -0
- package/dist/session-incarnation.d.ts +9 -3
- package/dist/session-sync-kernel.d.ts +42 -1
- package/dist/session-sync-kernel.js +17 -0
- package/dist/session-sync.js +16 -4
- package/dist/sql-engine-coordinates.d.ts +49 -0
- package/dist/sql-engine-coordinates.js +27 -0
- package/dist/standing-answer-grant.d.ts +31 -2
- package/dist/standing-answer-grant.js +14 -2
- package/dist/store-posture.d.ts +1 -1
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +52 -25
- package/dist/task-settings.js +91 -28
- package/dist/terminal.d.ts +77 -20
- package/dist/terminal.js +66 -20
- package/dist/trace/core-keyset-guard.d.ts +79 -2
- package/dist/trace/exit-seat.d.ts +7 -0
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/model-segment.d.ts +2 -2
- package/dist/trace/redact.js +323 -90
- package/dist/trace/self-minted-wire.d.ts +168 -2
- package/dist/trace/self-minted-wire.js +63 -0
- package/dist/verifier-pause-card.d.ts +8 -0
- package/dist/verifier-pause-card.js +19 -0
- package/dist/web-admin-client/apply-effective.d.ts +5 -7
- package/dist/web-admin-client/apply-effective.js +2 -2
- package/dist/web-admin-client/candidate-gate.d.ts +1 -1
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
- package/package.json +2 -2
- package/wire-changes/server@7.141.0.json +367 -0
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
* branch below the floor — so the record the engine reads is the one the run's walk reaches.
|
|
17
17
|
* Read-only: the log is read once (`exportEntries`, pure), no append log is opened, and the window refuses writes.
|
|
18
18
|
*
|
|
19
|
+
* ## The metadata is the store's, not the archive's
|
|
20
|
+
* Both halves come from the local session store ({@link LocalSessionRows}) — this module opens no repo of its own. The metadata is the
|
|
21
|
+
* store's one projection of the session's row (`LocalSessionStore.sessionMetadataOf`: owner, creation time and fork lineage read from the
|
|
22
|
+
* session-meta cell, the same projection the store hands the engine), never the archive header's copy — an archive rebuilt by a log swap
|
|
23
|
+
* keeps the row's creation time. The log is the store's export of the archive.
|
|
24
|
+
*
|
|
19
25
|
* ## Cost: one linear walk, the engine's
|
|
20
26
|
* The branch is core's own `getPathToRoot` over the whole log (the walk every engine read of a local session makes, with its stop
|
|
21
27
|
* rules: an entry without a parent ends it, a parent the log does not hold is `invalid_session`, an unknown leaf is `not_found`).
|
|
@@ -29,7 +35,15 @@
|
|
|
29
35
|
* by `getPathToRoot` and the run's resume ancestor scan (the two walks core 7.54.1 guards; this module has no walker of its own left).
|
|
30
36
|
* Pinned in `test/session-log-parent-cycle.test.ts`.
|
|
31
37
|
*/
|
|
32
|
-
import { BaseSessionStorage } from "@sema-agent/core";
|
|
38
|
+
import { BaseSessionStorage, type SessionMetadata, type SessionTreeEntry } from "@sema-agent/core";
|
|
39
|
+
/**
|
|
40
|
+
* What the window reads, and from whom: the local session store's row projection and its export of the log (`LocalSessionStore` is the one
|
|
41
|
+
* implementation; `store-backend.ts#localSessionRowsOf` hands it out). `undefined` / `null` = no such session.
|
|
42
|
+
*/
|
|
43
|
+
export interface LocalSessionRows {
|
|
44
|
+
sessionMetadataOf(sessionId: string): Promise<SessionMetadata | undefined>;
|
|
45
|
+
exportEntries(sessionId: string): Promise<SessionTreeEntry[] | null>;
|
|
46
|
+
}
|
|
33
47
|
export declare class LocalSessionWindow extends BaseSessionStorage {
|
|
34
48
|
/** The branch below the floor, root first (empty when the window is the whole branch). */
|
|
35
49
|
private readonly below;
|
|
@@ -39,7 +53,7 @@ export declare class LocalSessionWindow extends BaseSessionStorage {
|
|
|
39
53
|
/** `SessionStorage.getEpochAnchor?()` — the nearest carrier on the branch below the floor, as stored ({@link scanEpochAnchor}).
|
|
40
54
|
* A row's `seq` is its position on the branch; the whole branch is in memory, so one page holds every row. */
|
|
41
55
|
getEpochAnchor(): Promise<unknown>;
|
|
42
|
-
/** Wake the window of `sessionId`
|
|
43
|
-
static wake(
|
|
56
|
+
/** Wake the window of `sessionId` from the local session store's rows; `null` if there is no such session. */
|
|
57
|
+
static wake(rows: LocalSessionRows, sessionId: string): Promise<LocalSessionWindow | null>;
|
|
44
58
|
}
|
|
45
59
|
//# sourceMappingURL=local-session-window.d.ts.map
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { BaseSessionStorage, InMemorySessionStorage, SessionError, boundedTail } from "@sema-agent/core";
|
|
2
|
-
import { createLocalSessionRepo } from "./local-session-store.js";
|
|
3
2
|
import { scanEpochAnchor } from "./session-epoch-anchor.js";
|
|
4
3
|
export class LocalSessionWindow extends BaseSessionStorage {
|
|
5
4
|
below;
|
|
@@ -16,18 +15,13 @@ export class LocalSessionWindow extends BaseSessionStorage {
|
|
|
16
15
|
async getEpochAnchor() {
|
|
17
16
|
return scanEpochAnchor(this.below.length, async (beforeSeq) => this.below.slice(0, beforeSeq).map((entry, seq) => ({ seq, entry })).reverse(), (row) => row.entry);
|
|
18
17
|
}
|
|
19
|
-
static async wake(
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (e.code === "not_found")
|
|
27
|
-
return null;
|
|
28
|
-
throw e;
|
|
29
|
-
}
|
|
30
|
-
const metadata = (await repo.list()).find((m) => m.id === sessionId) ?? { id: sessionId, createdAt: new Date().toISOString() };
|
|
18
|
+
static async wake(rows, sessionId) {
|
|
19
|
+
const log = await rows.exportEntries(sessionId);
|
|
20
|
+
if (log === null)
|
|
21
|
+
return null;
|
|
22
|
+
const metadata = await rows.sessionMetadataOf(sessionId);
|
|
23
|
+
if (metadata === undefined)
|
|
24
|
+
return null;
|
|
31
25
|
const whole = new InMemorySessionStorage({ entries: log });
|
|
32
26
|
const leafId = await whole.getLeafId();
|
|
33
27
|
const branch = await whole.getPathToRoot(leafId);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type UsageRow } from "../usage-analytics.js";
|
|
2
2
|
import type { TaskStatus } from "@sema-agent/core";
|
|
3
|
-
import { type FenceLanded, type InProcessClaimFence, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
3
|
+
import { type FenceLanded, type FencedRun, type InProcessClaimFence, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
4
4
|
import type { LedgerEventType } from "../trace/ledger-events.js";
|
|
5
5
|
import { type SpaceCommitClaim, type SpaceCommitReading, type SpaceCommitState } from "../workspace-space-commit.js";
|
|
6
6
|
/**
|
|
@@ -83,7 +83,7 @@ export declare class MemoryRunStore implements InProcessClaimFence {
|
|
|
83
83
|
markResuming(taskId: string, instanceId: string): Promise<boolean>;
|
|
84
84
|
getActiveTaskId(sessionId: string): Promise<string | undefined>;
|
|
85
85
|
/** 认领当写栅栏用(契约 = `store-contracts.ts` 的 `InProcessClaimFence`):判、刷新活性与 `write` 是同一个同步段。 */
|
|
86
|
-
whileHoldingClaim(sessionId: string, taskId: string, write: () => FenceLanded): boolean;
|
|
86
|
+
whileHoldingClaim(sessionId: string, taskId: string, write: (run: FencedRun) => FenceLanded): boolean;
|
|
87
87
|
getRun(taskId: string): Promise<RunRecord | undefined>;
|
|
88
88
|
/** Runs newest-first, keyset on (createdAt, taskId) DESC; optional exact-match filters (owner is exact, like the SQL). */
|
|
89
89
|
listRuns(opts: RunListQuery): Promise<RunRecord[]>;
|
|
@@ -238,7 +238,7 @@ export class MemoryRunStore {
|
|
|
238
238
|
if (this.active.get(sessionId) !== taskId || r === undefined || r.status !== "running")
|
|
239
239
|
return false;
|
|
240
240
|
r.updatedAt = new Date();
|
|
241
|
-
write();
|
|
241
|
+
write({ instanceId: r.instanceId });
|
|
242
242
|
return true;
|
|
243
243
|
}
|
|
244
244
|
async getRun(taskId) {
|
|
@@ -316,6 +316,18 @@
|
|
|
316
316
|
* 或 `storage` 时权限 / 磁盘修好)后的下一次起服照常补放置;存档移走则它不再是本服务的会话(不补放置、不再点名;fork 创建的会话例外 —— 它的格还在,读作 fork 未落定,出路是同键重试那次 fork 或删除该会话)。
|
|
317
317
|
* · **旧版在已切换库上**:≤7.137.x 起服建回空 `device_session`,随后列册对账见执行列为幽灵列拒启、零行写;再起本版 ⇒ ⓪ 删掉那张空表。回滚的唯一支持形 = 恢复切换前的备份。
|
|
318
318
|
* 读数:`executionPlacementColumnsAdded` / `deviceBindingsMoved` / `deviceBindingsOrphaned`(非零 ⇒ 另一行 warn)/ `deviceBindingTablesDropped` / `executionPlacementsBackfilled` / `executionPlacementSessionsUnreadable`(点名数组 `{ sessionId, fault, errno? }`,只 local;一行一条 warn),收据只记起服日志行。
|
|
319
|
+
* · **M33 local 存档的行事实搬进行、带戳存档改写成匿名**(7.141.0;local 独有 —— SQL 孪生的行事实本来就只在 `session_meta` 行上)—— local 店的行事实(属主 / 化身 / 执行放置 /
|
|
320
|
+
* 建档时刻 / fork 谱系)只住在会话元数据边档的那一格,引擎仓是匿名内容仓(`local-session-store.ts` 头注「规则一」):本店交给引擎仓的写一律不交属主,交出的会话元数据是那一格的一只投影。
|
|
321
|
+
* ≤7.140.x 写下的存量 ① 格里没有建档时刻 / 谱系(那两样只在存档头上)② 换装 / 导入写下的存档头带着导入者的属主戳(及其 fork 后代 —— fork 抄戳)⇒ **一次性**:
|
|
322
|
+
* 步 0 恢复先行(上一次被打断留下的快照逐份消化,`LocalSessionStore.settleArchiveSnapshots`;起服 `ensureSchema` 先调,迁移开头再调)· 步 1 枚举(引擎仓列表 ∪ 边档全部键;
|
|
323
|
+
* 只在边档里、头读不出的 ⇒ 点名 unreadable)· 步 2 行回填(列表里每只存档:格缺 ⇒ 建一格、属主「从没被记下」;格缺建档时刻 / 谱系 ⇒ 从存档头补;一次边档提交 + 文件与目录各 fsync,
|
|
324
|
+
* 在这之前不碰任何存档)· 步 3 存档归一(每只带戳存档,在它的会话写锁里):整档一次读 → 读时跳过了记录 ⇒ 留着(`records_skipped`)→ 引擎导入闸先验(带发言者归属)不过 ⇒ 留着
|
|
325
|
+
* (`invalid`)→ 验后与原日志不逐条相等 ⇒ 留着(`normalizes`;迁移从不改内容)→ 快照记录(core `atomicWriteFile`)→ 以这一代为条件删存档 → 匿名导入 → 删快照。
|
|
326
|
+
* 留着的存档字节不动、点名(一行一条 warn);它们之后被 fork 拒、改日志的推送答 `conflict`(读、续跑、拉取照常),出路 = 删掉会话后重推。
|
|
327
|
+
* **快照目录的常设拒启臂**(`assertNoArchiveSnapshots`,无窗;删码后仍在):起服时数据根下的快照目录非空 ⇒ 拒启(`config.local_archive_snapshot_present`,`StoreBootRefusalError` 族)。
|
|
328
|
+
* **回滚**:边档对象形一格是严格形,上一版不认 `createdAt` / `forkedFrom` 两键 ⇒ 读本版写过的边档严格拒启 —— 回滚的唯一支持形 = 恢复升级前的数据根备份(MIGRATION 写了:升级前备份、先停光旧副本)。
|
|
329
|
+
* 读数:`localArchiveRowFactsBackfilled` / `localArchivesAnonymized` / `localArchivesKeptStamped`(点名数组 `{ sessionId, reason }`)/ `localArchivesUnreadable`(点名数组 `{ sessionId }`)/
|
|
330
|
+
* `localArchiveSnapshotsRecovered`;只 local(SQL 恒零 / 空)。
|
|
319
331
|
*
|
|
320
332
|
* ## 收据账(一次起服一只,每一条迁移同一只)
|
|
321
333
|
* 每一步把它**已提交**的改写 / 删除与点名读数当场记进同一只收据账({@link MigrationReceipts}):计数随每次提交累加、行随每次提交追加、形读数在那一步落定时写。走完 ⇒
|
|
@@ -424,6 +436,16 @@ export interface OneTimeMigrationReport {
|
|
|
424
436
|
/** M32 local 腿:该回填放置、却读不出的会话 —— 有 run、存档读不出(会话头读不出 / 结构走不通 / 读存档文件时抛了别的故障:权限 / 磁盘 I/O / 超大)。一个字节没写,起服不挡:
|
|
425
437
|
* 该会话的请求照旧答存档的故障;存档修好(从留存副本恢复,或权限 / 磁盘修好)后的下一次起服照常补放置。点名行数组(会话 id + 故障词,`storage` 再带 errno),一行一条 warn,每次起服都报直到处置。SQL 独有的反面:SQL 没有这一形(行就是会话);SQL 恒空。 */
|
|
426
438
|
readonly executionPlacementSessionsUnreadable: readonly ExecutionPlacementSessionUnreadable[];
|
|
439
|
+
/** M33:本次补了行事实(建档时刻 / fork 谱系)的会话元数据格数(含为「有存档、没有格」的会话新建的格)。local 独有;SQL 恒 0。非零 = 真写了存量行。 */
|
|
440
|
+
readonly localArchiveRowFactsBackfilled: number;
|
|
441
|
+
/** M33:本次由带属主戳改写成匿名的存档数(条目逐条相等,内容不改)。local 独有;SQL 恒 0。非零 = 真写了存量存档。 */
|
|
442
|
+
readonly localArchivesAnonymized: number;
|
|
443
|
+
/** M33:留着带戳的存档(点名 + 原因,一行一条 warn,每次起服都报直到处置)。local 独有;SQL 恒空。 */
|
|
444
|
+
readonly localArchivesKeptStamped: readonly LocalArchiveKeptStamped[];
|
|
445
|
+
/** M33:存档读不出的会话(边档里有格而存档头读不出,或整档读抛;点名,一行一条 warn,每次起服都报直到处置)。local 独有;SQL 恒空。 */
|
|
446
|
+
readonly localArchivesUnreadable: readonly LocalArchiveUnreadable[];
|
|
447
|
+
/** M33:本次起服消化掉的快照记录数(上一次被打断的改写留下的;补回 / 丢弃)。local 独有;SQL 恒 0。 */
|
|
448
|
+
readonly localArchiveSnapshotsRecovered: number;
|
|
427
449
|
}
|
|
428
450
|
/** 退役的两只命令桶(引擎 7.51.0 起不是桶;只给 M17 点名认)。 */
|
|
429
451
|
export type RetiredSessionRuleBucket = "commandAllow" | "commandDeny";
|
|
@@ -474,6 +496,24 @@ export interface ExecutionPlacementSessionUnreadable {
|
|
|
474
496
|
/** 仅 `fault === "storage"` 且那只故障带字符串 `code` 时在场(`EACCES` / `EIO` / `ERR_STRING_TOO_LONG` ……)。 */
|
|
475
497
|
readonly errno?: string;
|
|
476
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* M33 留着带戳的一只存档的原因(闭集):`invalid` = 引擎导入闸不收这份日志(重导会被拒);`normalizes` = 引擎导入会改写它的内容(重导不再逐条相等);
|
|
501
|
+
* `records_skipped` = 读这只存档时跳过了读不出的记录(重写会把盘上那几行字节抹掉)。三种都一个字节不动。
|
|
502
|
+
*/
|
|
503
|
+
export type LocalArchiveKeptReason = "invalid" | "normalizes" | "records_skipped";
|
|
504
|
+
/** M33 留着带戳的一只存档:会话 id 是点名坐标 + 原因。日志内容与盘上路径不出店。 */
|
|
505
|
+
export interface LocalArchiveKeptStamped {
|
|
506
|
+
readonly sessionId: string;
|
|
507
|
+
readonly reason: LocalArchiveKeptReason;
|
|
508
|
+
/** `reason: "invalid"` 时在场:引擎导入闸拒的那一句(条目 id + 结构毛病,不含条目内容)—— 运维据它找到挡住改写的那一条。 */
|
|
509
|
+
readonly detail?: string;
|
|
510
|
+
}
|
|
511
|
+
/** M33 读不出的一只:会话元数据边档里有它的格而存档头读不出(会话头坏),或列表读得出头、整档读抛。一个字节没写;会话的请求照旧答存档的故障。 */
|
|
512
|
+
export interface LocalArchiveUnreadable {
|
|
513
|
+
readonly sessionId: string;
|
|
514
|
+
/** 读的时候抛的那只故障带串型 `code` 时在场(`EACCES` / `EIO` / `corrupt_session` …);盘上路径与故障句不出店。 */
|
|
515
|
+
readonly errno?: string;
|
|
516
|
+
}
|
|
477
517
|
/** 三个形读数(M9 主键 / M17 列名 / M24 scope 列)—— 那一步**落定**之前收据账里缺席(读数行要它们齐;被打断的那一行只带已落定的)。 */
|
|
478
518
|
type ShapeReadingKey = "workflowParkIndexKey" | "sessionRuleColumn" | "workflowJournalScopeColumn";
|
|
479
519
|
/**
|
|
@@ -544,8 +584,8 @@ export declare function migrationWindowOpen(window: Pick<OneTimeMigrationWindow,
|
|
|
544
584
|
* 还没有日期可写)⇒ 响亮抛,不铸一句带空日期的句子。
|
|
545
585
|
*/
|
|
546
586
|
export declare function migrationWindowEnd(id: string): string;
|
|
547
|
-
/** local 车道上 SQL 独有的几条(M8 / M9 / M11 / M17 / M18 / M21 / M23 / M24 / M26 / M27 / M29)的读数(M6 与 M32
|
|
548
|
-
export declare const NO_SQL_MIGRATIONS: Omit<OneTimeMigrationReport, "holderDeathCodeRowsBackfilled" | "executionPlacementsBackfilled" | "askExecutionLanesBackfilled" | "executionPlacementSessionsUnreadable">;
|
|
587
|
+
/** local 车道上 SQL 独有的几条(M8 / M9 / M11 / M17 / M18 / M21 / M23 / M24 / M26 / M27 / M29)的读数(M6 与 M32 的回填两车道都有、M33 只在 local,local 腿的读数由 `LocalBackend.runOneTimeMigrations` 现算):那几张表 / 列在文件底座上从来不存在 ⇒ 如实答 absent / 0。 */
|
|
588
|
+
export declare const NO_SQL_MIGRATIONS: Omit<OneTimeMigrationReport, "holderDeathCodeRowsBackfilled" | "executionPlacementsBackfilled" | "askExecutionLanesBackfilled" | "executionPlacementSessionsUnreadable" | "localArchiveRowFactsBackfilled" | "localArchivesAnonymized" | "localArchivesKeptStamped" | "localArchivesUnreadable" | "localArchiveSnapshotsRecovered">;
|
|
549
589
|
/** 启动期的日志口(logger 的子集)。两级各有其用,见 {@link logOneTimeMigrations}。 */
|
|
550
590
|
export interface MigrationLogSink {
|
|
551
591
|
warn(msg: string, meta?: Record<string, unknown>): void;
|
|
@@ -55,6 +55,11 @@ export function buildMigrationReceipts() {
|
|
|
55
55
|
executionPlacementsBackfilled: 0,
|
|
56
56
|
askExecutionLanesBackfilled: 0,
|
|
57
57
|
executionPlacementSessionsUnreadable: [],
|
|
58
|
+
localArchiveRowFactsBackfilled: 0,
|
|
59
|
+
localArchivesAnonymized: 0,
|
|
60
|
+
localArchivesKeptStamped: [],
|
|
61
|
+
localArchivesUnreadable: [],
|
|
62
|
+
localArchiveSnapshotsRecovered: 0,
|
|
58
63
|
};
|
|
59
64
|
}
|
|
60
65
|
function completedReport(r) {
|
|
@@ -100,7 +105,12 @@ function changedAnything(r) {
|
|
|
100
105
|
r.deviceBindingTablesDropped > 0 ||
|
|
101
106
|
r.executionPlacementsBackfilled > 0 ||
|
|
102
107
|
r.askExecutionLanesBackfilled > 0 ||
|
|
103
|
-
r.executionPlacementSessionsUnreadable.length > 0
|
|
108
|
+
r.executionPlacementSessionsUnreadable.length > 0 ||
|
|
109
|
+
r.localArchiveRowFactsBackfilled > 0 ||
|
|
110
|
+
r.localArchivesAnonymized > 0 ||
|
|
111
|
+
r.localArchivesKeptStamped.length > 0 ||
|
|
112
|
+
r.localArchivesUnreadable.length > 0 ||
|
|
113
|
+
r.localArchiveSnapshotsRecovered > 0);
|
|
104
114
|
}
|
|
105
115
|
function readingsSnapshot(r) {
|
|
106
116
|
return {
|
|
@@ -113,6 +123,8 @@ function readingsSnapshot(r) {
|
|
|
113
123
|
parkedApprovalCardRowsUnreadable: [...r.parkedApprovalCardRowsUnreadable],
|
|
114
124
|
parkedApprovalCardRowsTooLong: [...r.parkedApprovalCardRowsTooLong],
|
|
115
125
|
executionPlacementSessionsUnreadable: [...r.executionPlacementSessionsUnreadable],
|
|
126
|
+
localArchivesKeptStamped: [...r.localArchivesKeptStamped],
|
|
127
|
+
localArchivesUnreadable: [...r.localArchivesUnreadable],
|
|
116
128
|
};
|
|
117
129
|
}
|
|
118
130
|
function receiptSentence(r) {
|
|
@@ -381,7 +393,7 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
381
393
|
removal: "删 migrateOn 的 M23 步(`inheritPlacedSessionOwners`:placed ∧ 属主 NULL 的行按 session_id 键集分页单趟扫描 + 同一条语句连读根 / 父两行 + 按认领句回写属主)与 `PLACED_OWNER_SCAN_PAGE` / `placedOwnerScanSql` / `scannedPlacement` / `scannedFaces` / `scannedPlacedSources`(`isOrphanSessionOwner` 若再无别的读者一并删);" +
|
|
382
394
|
"**同窗同删的另一半**(认领:按律给升级前写下的无主子代行写属主 —— 停驻挂点对宿主无主行做的就是本条对那一行的单行步):`delegated-session-owner.ts` 的 `CLAIM_OWNERLESS_PLACED_SQL` / `claimOwnerlessParams` / `OwnerlessClaim` / " +
|
|
383
395
|
"`settleDelegatedOwner` 的认领一步(删后它只剩树比对与属主比对)/ `DelegationTreeStore.claimOwnerless`," +
|
|
384
|
-
"两只 SQL 店(`tidb-session-store.ts` / `pg-session-storage.ts`)的 `claimOwnerless`、`CachingSessionStore` 的转发、`OwnerAwareSessionStore.claimOwnerless`、`delegatedOwnerHostOf` 对它的「与 `placementOf` 同在或同缺」;" +
|
|
396
|
+
"两只 SQL 店(`tidb-session-store.ts` / `pg-session-storage.ts`)与 local 店(`local-session-store.ts` 的 `claimOwnerless` 字段与 `claimOwnerlessPlaced`)的 `claimOwnerless`、`CachingSessionStore` 的转发、`OwnerAwareSessionStore.claimOwnerless`、`delegatedOwnerHostOf` 对它的「与 `placementOf` 同在或同缺」;" +
|
|
385
397
|
"报告、日志行与 `NO_SQL_MIGRATIONS` 的 `placedSessionOwnersInherited` / `placedSessionOwnersOrphaned` / `placedSessionOwnersRemaining` 与 `placed_session_owners_orphaned` 那一行 warn;" +
|
|
386
398
|
"`test/one-time-migrations.test.ts` 的 M23 组与 `test/one-time-migrations-db-integration.test.ts` 的 M23 格。" +
|
|
387
399
|
"**不随本条删**:属主为 NULL 的 placed 行只对 fleet 调用方放行(`security.ts` 的 `ownerlessRowOpen` / `sessionOwnerCellOf` 与各门读 `placementOf` 的那一次)—— 那是常设的读面律",
|
|
@@ -531,6 +543,24 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
531
543
|
"跳过了带本条的版本直接升的库响亮拒启,出路 = 先在带本条的版本起服一次让切换走完,再升;缺执行放置列的库由列集对账缺列拒启(`config.schema_mismatch`,拒句给 ALTER),同一出路",
|
|
532
544
|
reportKeys: ["executionPlacementColumnsAdded", "deviceBindingsMoved", "deviceBindingsOrphaned", "deviceBindingTablesDropped", "executionPlacementsBackfilled", "askExecutionLanesBackfilled", "executionPlacementSessionsUnreadable"],
|
|
533
545
|
},
|
|
546
|
+
{
|
|
547
|
+
id: "M33",
|
|
548
|
+
introducedIn: "7.141.0",
|
|
549
|
+
releasedOn: "2026-10-30",
|
|
550
|
+
removableAfter: "2026-11-29",
|
|
551
|
+
removal: "删 `LocalSessionStore.migrateLocalArchives` 与它的私有助手 `anonymizeArchiveHeld` / `fillRowFacts`、`settleArchiveSnapshots` 里除最后一句常设臂 `assertNoArchiveSnapshots(dir)` 以外的一切(逐份消化的循环与 `settleArchiveSnapshot`)、" +
|
|
552
|
+
"`archiveSnapshotsSettled` 字段、`syncArchiveDirectory`、`rowFactsFilled` / `ArchivedRowFacts` / `archivedRowFactsOf` / `ARCHIVE_SNAPSHOT_RECORD` / `ArchiveSnapshotRecord` / `readArchiveSnapshotRecord` / `sameLog` / " +
|
|
553
|
+
"`ArchiveRewriteStep` / `LocalArchiveMigrationReading` / `errnoOf`、" +
|
|
554
|
+
"`archiveRewriteReadScope` / `noteReplayInArchiveRewriteRead` 与 `createLocalSessionRepo` 座里调它的那一腿、`SidecarMap.syncToDisk`(若再无别的调用方)与 `fsyncPaths`(同);" +
|
|
555
|
+
"`store-backend.ts` 的 `LocalBackend.runOneTimeMigrations` 里对 `migrateLocalArchives` 的调用与报告五键的那五行;本文件的 `LocalArchiveKeptReason` / `LocalArchiveKeptStamped` / `LocalArchiveUnreadable`、" +
|
|
556
|
+
"报告 / 收据 / `changedAnything` / `readingsSnapshot` / `readingFields` 里的 `localArchiveRowFactsBackfilled` / `localArchivesAnonymized` / `localArchivesKeptStamped` / `localArchivesUnreadable` / `localArchiveSnapshotsRecovered`、" +
|
|
557
|
+
"`local_archive_kept_stamped` / `local_archive_unreadable` 两行 warn、读数行 note 里的 M33 句与头注 M33 段;`test/local-archive-owner.test.ts` 里标题含 `P3` / `P4` / `P5` / `P6` / `F1` / `F2` / `F3` 的格与 `legacyRoot` / `writeArchive` / `boot` / `M33_ZERO` / `m33Of` 助手。" +
|
|
558
|
+
"**不随本条删**:行格的 `createdAt` / `forkedFrom` 两键(常设的数据形)、`LocalArchiveSnapshotsPresentError` / `assertNoArchiveSnapshots` / `LOCAL_ARCHIVE_SNAPSHOT_DIR` 与 `LocalBackend.ensureSchema` 里调它的那一句、" +
|
|
559
|
+
"`session-error-wire.ts` 的 `StampedSessionArchiveError` / `STAMPED_SESSION_ARCHIVE_SENTENCE` / `sessionErrorWireOf` 与本店两处带戳判(fork 的源、改日志推送的落点)、行上缺建档时刻的 F 类读法(`server.local-session-row.created-at-absent`)",
|
|
560
|
+
afterRemoval: "三只常设臂接住:① 数据根下的快照目录非空 ⇒ 拒启(`config.local_archive_snapshot_present`,点名文件与两条出路);② 跳过了带本条的版本直接升的数据根(或本条留着的存档),带属主戳的存档被 fork 与改日志的推送同一只具名拒(409 `conflict` + 固定句,零写 / 行格净零写)," +
|
|
561
|
+
"读 / 续跑 / 拉取照常 —— 出路 = 删掉会话后重推,或升级时先过一次带本条的版本并在窗内起服;③ 行上没有建档时刻的格(同一类数据根)⇒ 列表 / 会话视图 / 交出的元数据读纪元(F 类 tag 计数)",
|
|
562
|
+
reportKeys: ["localArchiveRowFactsBackfilled", "localArchivesAnonymized", "localArchivesKeptStamped", "localArchivesUnreadable", "localArchiveSnapshotsRecovered"],
|
|
563
|
+
},
|
|
534
564
|
];
|
|
535
565
|
export function migrationWindowOpen(window, today) {
|
|
536
566
|
return window.removableAfter === null || today <= window.removableAfter;
|
|
@@ -1602,6 +1632,11 @@ function readingFields(r) {
|
|
|
1602
1632
|
executionPlacementsBackfilled: r.executionPlacementsBackfilled,
|
|
1603
1633
|
askExecutionLanesBackfilled: r.askExecutionLanesBackfilled,
|
|
1604
1634
|
executionPlacementSessionsUnreadable: r.executionPlacementSessionsUnreadable.length,
|
|
1635
|
+
localArchiveRowFactsBackfilled: r.localArchiveRowFactsBackfilled,
|
|
1636
|
+
localArchivesAnonymized: r.localArchivesAnonymized,
|
|
1637
|
+
localArchivesKeptStamped: r.localArchivesKeptStamped.length,
|
|
1638
|
+
localArchivesUnreadable: r.localArchivesUnreadable.length,
|
|
1639
|
+
localArchiveSnapshotsRecovered: r.localArchiveSnapshotsRecovered,
|
|
1605
1640
|
};
|
|
1606
1641
|
}
|
|
1607
1642
|
export function logOneTimeMigrations(log, backend, report) {
|
|
@@ -1650,7 +1685,12 @@ export function logOneTimeMigrations(log, backend, report) {
|
|
|
1650
1685
|
"M32: session↔device bindings moved from the retired table device_session onto the root session rows (the table is first renamed device_session_retired, " +
|
|
1651
1686
|
"the eight execution placement columns are added to session_meta, every binding overwrites the device placement of its root session row — a binding whose " +
|
|
1652
1687
|
"root session row is gone is dropped and counted, named by a device_bindings_orphaned line — and the renamed table is dropped), and session rows that have " +
|
|
1653
|
-
"runs but no execution placement placed on the only declared lane; once the switch is complete this step does nothing
|
|
1688
|
+
"runs but no execution placement placed on the only declared lane; once the switch is complete this step does nothing; " +
|
|
1689
|
+
"M33 (local backend only): each local session's creation time and fork lineage were copied from its stored archive into its session-metadata cell, and archives " +
|
|
1690
|
+
"that still carried an importer's owner stamp were rewritten as anonymous with every entry kept as it was (a snapshot of the log is written before each rewrite " +
|
|
1691
|
+
"and removed after it; an interrupted rewrite is finished from the snapshot on the next boot); an archive whose log the import check refuses, whose re-import would " +
|
|
1692
|
+
"change its content, or whose read skipped unreadable records is left byte for byte as it was and named by a local_archive_kept_stamped line, and a session whose " +
|
|
1693
|
+
"archive header cannot be read is named by a local_archive_unreadable line). Each step " +
|
|
1654
1694
|
"runs on every boot until its window closes (the release that introduced it + 30 days; the per-step date is in " +
|
|
1655
1695
|
"removableAfter, null while that release is not published yet) and is deleted in the first minor after that — start a " +
|
|
1656
1696
|
"version that still carries a step at least once before upgrading past its deletion.",
|
|
@@ -1658,6 +1698,28 @@ export function logOneTimeMigrations(log, backend, report) {
|
|
|
1658
1698
|
logReceiptRows(log, backend, report);
|
|
1659
1699
|
}
|
|
1660
1700
|
function logReceiptRows(log, backend, r) {
|
|
1701
|
+
for (const row of r.localArchivesKeptStamped) {
|
|
1702
|
+
log.warn("local_archive_kept_stamped", {
|
|
1703
|
+
backend,
|
|
1704
|
+
sessionId: row.sessionId,
|
|
1705
|
+
reason: row.reason,
|
|
1706
|
+
...(row.detail !== undefined ? { detail: row.detail } : {}),
|
|
1707
|
+
note: "this local session's stored archive still carries the owner stamp an earlier version wrote, and the one-time migration that rewrites such archives as anonymous left it byte for byte as it was " +
|
|
1708
|
+
"(reason invalid = the import check refuses its log; normalizes = re-importing would change its content; records_skipped = reading it skipped unreadable records, which a rewrite would erase). " +
|
|
1709
|
+
"Reading, resuming and pulling the session work as before; forking it is refused and a push that changes its log answers 409 conflict. Way out: delete the session and push it again " +
|
|
1710
|
+
"(a push onto an absent session creates it anew), or repair the archive under the data root's sessions directory. Named on every boot until then",
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
for (const row of r.localArchivesUnreadable) {
|
|
1714
|
+
log.warn("local_archive_unreadable", {
|
|
1715
|
+
backend,
|
|
1716
|
+
sessionId: row.sessionId,
|
|
1717
|
+
...(row.errno !== undefined ? { errno: row.errno } : {}),
|
|
1718
|
+
note: "this local session's stored archive cannot be read (its header, or the whole archive), so the one-time migration could neither copy its creation time into its session-metadata cell nor rewrite it; " +
|
|
1719
|
+
"nothing was written. Every request that needs the session keeps answering the archive's own fault until the archive under the data root's sessions directory is restored from a kept copy " +
|
|
1720
|
+
"(the next boot then migrates it) or the session is deleted. Named on every boot until then",
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1661
1723
|
if (r.deviceBindingsOrphaned > 0) {
|
|
1662
1724
|
log.warn("device_bindings_orphaned", {
|
|
1663
1725
|
backend,
|
package/dist/plugins/pg-pool.js
CHANGED
|
@@ -347,8 +347,9 @@ export const PG_SCHEMA_STATEMENTS = [
|
|
|
347
347
|
enqueued_at_ms BIGINT NOT NULL,
|
|
348
348
|
-- 1.109 delivery envelope. kind NULL = a LEGACY \`workflow_complete\` row (the shape that predates the
|
|
349
349
|
-- envelope); readers must keep treating NULL as that kind, it is not "unknown". payload = the kind's JSON
|
|
350
|
-
-- extras: task_notification: task_type / result / …; workflow_complete: at most {"completionId": …}
|
|
351
|
-
-- engine's own correlation id, verbatim;
|
|
350
|
+
-- extras: task_notification: task_type / result / …; workflow_complete: at most {"completionId": …, "diagnostics": …}
|
|
351
|
+
-- (the engine's own correlation id, verbatim; the engine's diagnostic teaching text, redacted + bounded at enqueue;
|
|
352
|
+
-- each key absent when the engine minted none, NULL when neither).
|
|
352
353
|
kind VARCHAR(24) COLLATE "C",
|
|
353
354
|
payload TEXT COLLATE "C",
|
|
354
355
|
PRIMARY KEY (session_id, run_id),
|
|
@@ -67,6 +67,8 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
67
67
|
readonly durability: "durable";
|
|
68
68
|
};
|
|
69
69
|
};
|
|
70
|
+
/** 会话耐久声明(TiDB 孪生同格,同一只常量 {@link SESSION_DURABILITY};理由见 `session-placement.ts` 的常量注)。 */
|
|
71
|
+
readonly durability: "durable";
|
|
70
72
|
/** In-flight acquisitions keyed by id, so concurrent acquire(sameId) in one process share one. */
|
|
71
73
|
private readonly pending;
|
|
72
74
|
/** 委派子代孤行那一行 warn 的去处(TiDB 孪生同格)。 */
|
|
@@ -8,7 +8,7 @@ import { scanEpochAnchor } from "./session-epoch-anchor.js";
|
|
|
8
8
|
import { jsonColumnText } from "./sql-json-column.js";
|
|
9
9
|
import { pgSafeJsonStringify } from "./pg-safe-json.js";
|
|
10
10
|
import { toIso } from "./sql-row-helpers.js";
|
|
11
|
-
import { placementCapabilityOf, LIST_PLACED_BATCH, PLACEMENT_SELECT_COLUMNS, placedRowFromRow, placementFromRow, placementInsertValues,
|
|
11
|
+
import { placementCapabilityOf, LIST_PLACED_BATCH, PLACEMENT_SELECT_COLUMNS, placedRowFromRow, placementFromRow, placementInsertValues, SESSION_DURABILITY, SESSION_PLACEMENTS, } from "./session-placement.js";
|
|
12
12
|
import { contentForkRelation, fastForwardSharedContentDiverged } from "../session-sync-content.js";
|
|
13
13
|
import { CLAIM_OWNERLESS_PLACED_SQL, claimOwnerlessParams, createPlacedSessionRow } from "../delegated-session-owner.js";
|
|
14
14
|
import { createLogger } from "../observability/logger.js";
|
|
@@ -188,7 +188,8 @@ export class PgSessionStorage extends BaseSessionStorage {
|
|
|
188
188
|
export class PgSessionStore {
|
|
189
189
|
pool;
|
|
190
190
|
retention;
|
|
191
|
-
placements =
|
|
191
|
+
placements = SESSION_PLACEMENTS;
|
|
192
|
+
durability = SESSION_DURABILITY;
|
|
192
193
|
pending = new Map();
|
|
193
194
|
log;
|
|
194
195
|
executionPlacement;
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
* iterator MAY throw `RemoteExecutionError` mid-stream before an `exit` chunk (seam contract, OutputChunk).
|
|
21
21
|
*/
|
|
22
22
|
import { Sandbox, type SandboxOpts, type SandboxConnectOpts } from "e2b";
|
|
23
|
-
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type ExecutionEnvFactory, type VmLifecycleOptions, type BackgroundShellCapability, type BackgroundShellId, type BackgroundShellError, type BackgroundSpawnOptions, type BackgroundPoll } from "@sema-agent/core";
|
|
23
|
+
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type ExecutionEnvFactory, type VmLifecycleOptions, type BackgroundShellCapability, type BackgroundShellId, type BackgroundShellError, type BackgroundSpawnOptions, type BackgroundPoll, type ExecutionEnvCapabilities } from "@sema-agent/core";
|
|
24
|
+
import { type SandboxReadFloorKnob } from "../execution-lane-caps.js";
|
|
25
|
+
import { type SandboxReadFloor } from "./sandbox-read-floor.js";
|
|
24
26
|
import { type LaneHomeConfig } from "../lane-home-probe.js";
|
|
25
27
|
/** Options accepted by `ExecutionEnv.exec` (core does not re-export the type; derive it from the seam). */
|
|
26
28
|
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
@@ -71,6 +73,8 @@ export interface RemoteContainerEnvConfig extends RemoteEnvObservers, LaneHomeCo
|
|
|
71
73
|
* create/connect) — wider than {@link rpcTimeoutMs} so a legit multi-minute transfer is not killed. Default
|
|
72
74
|
* {@link DEFAULT_DATA_TIMEOUT_MS}. */
|
|
73
75
|
dataTimeoutMs?: number;
|
|
76
|
+
/** `SANDBOX_READ_FLOOR`(keep | off;缺席 ⇒ keep):本沙箱守不守读拒表的字节地板 = 读地板模块服务本车道 ∧ 本键不是 off(`sandbox-read-floor.ts`)。 */
|
|
77
|
+
sandboxReadFloor?: SandboxReadFloorKnob;
|
|
74
78
|
}
|
|
75
79
|
/** Minimal slice of the E2B `Sandbox` static API the adapter uses — injectable so tests pass a fake. */
|
|
76
80
|
export interface SandboxApi {
|
|
@@ -80,6 +84,8 @@ export interface SandboxApi {
|
|
|
80
84
|
/** Inject the E2B SDK for tests (a fake `Sandbox`). Defaults to the real SDK. */
|
|
81
85
|
export interface RemoteContainerEnvDeps {
|
|
82
86
|
sandboxApi?: SandboxApi;
|
|
87
|
+
/** 这只环境手里的读地板模块(缺席 ⇒ `createSandboxReadFloor` 按旋钮选;钉注入守地板的模块)。能力块的 `keepsReadFloor` 读它的状态。 */
|
|
88
|
+
readFloor?: SandboxReadFloor;
|
|
83
89
|
}
|
|
84
90
|
/**
|
|
85
91
|
* E2B-backed remote `ExecutionEnv`. **Lazy by default (v1b):** the VM is provisioned on the
|
|
@@ -130,8 +136,20 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
130
136
|
* SAME env instance skips the reconnect and every later fs/exec runs against the dead VM. */
|
|
131
137
|
private paused;
|
|
132
138
|
constructor(config: RemoteContainerEnvConfig, deps?: RemoteContainerEnvDeps);
|
|
133
|
-
/** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)
|
|
134
|
-
readonly capabilities:
|
|
139
|
+
/** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)。读地板旋钮是它的输入,{@link floor} 由同一只判据、同一个旋钮值选出。 */
|
|
140
|
+
readonly capabilities: ExecutionEnvCapabilities;
|
|
141
|
+
/** 读拒表字节地板模块:沙箱里每一次 `commands.run` 起动都先经它的 `wrap`({@link startIn} → {@link runIn},唯一接缝)。 */
|
|
142
|
+
private readonly floor;
|
|
143
|
+
/**
|
|
144
|
+
* **唯一起动接缝(上半)**:一次起动 → 地板模块 `wrap` → e2b 编码(身份 + 命令行;不守地板 ⇒ 命令与每命令 env 原样,与改前逐字同)。
|
|
145
|
+
* 本适配器对地板零判断;模块拒 ⇒ `spawn_error`,命令从未起。
|
|
146
|
+
*/
|
|
147
|
+
private startIn;
|
|
148
|
+
/** **唯一起动接缝(下半)**:本文件里每一次 `commands.run`(中继除外:那是地板模块自己的进程)都经这里,身份与 env 只取起动编码。 */
|
|
149
|
+
private runIn;
|
|
150
|
+
/** 地板模块的三件原语。引导命令经 {@link startIn}(起动形 `bootstrap`:只在附着中合法);放置 = root 建目录 → `files.write`(root)写暂存件 →
|
|
151
|
+
* root `chmod 0755 && mv -f`;中继 = 以模块给的身份起一只长连后台命令(stdin 开着:`sendStdin` 写答,stdout 回调读问)。 */
|
|
152
|
+
private floorTransport;
|
|
135
153
|
workspaceHandle(): WorkspaceHandle;
|
|
136
154
|
/**
|
|
137
155
|
* Public host for a port inside the sandbox (E2B reverse proxy → `<port>-<id>.e2b.app`). The LSP sidecar
|
|
@@ -224,6 +242,9 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
224
242
|
shellId: string;
|
|
225
243
|
};
|
|
226
244
|
}, ExecutionError>>;
|
|
245
|
+
/** 适配器自己的固定命令(文件面助手:readlink / realpath / rm / mktemp / 暂存写的提交)—— 与 {@link exec} 同一条路,起动形 `adapter`。 */
|
|
246
|
+
private execInternal;
|
|
247
|
+
private execAs;
|
|
227
248
|
execStream(command: string, options?: ExecStreamOptions): AsyncIterable<OutputChunk>;
|
|
228
249
|
readonly backgroundCapabilities: {
|
|
229
250
|
readonly supported: true;
|