@takboo/dsh-session-bin 0.2.0 → 0.2.1

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/dist/index.js CHANGED
@@ -1799,22 +1799,90 @@ import { readFile } from "node:fs/promises";
1799
1799
  import { dirname, join as join2 } from "node:path";
1800
1800
  import { createHash as createHash3 } from "node:crypto";
1801
1801
  var nativeRetirementSdkSources = {
1802
- cordis: { version: "4.0.4", files: { "lib/index.js": "6a9394c0877ff45218818c6e815edd038f8057e1a1deb390a8d43ec81c57691e" } },
1803
- "dsh-session": { version: "0.2.0-rc.2", files: { "lib/index.js": "87ea85e2fb5318bf1f826db9a1c88c1b26d3ea328027a7f32b211880c4d62b9d", "lib/types/index.js": "71b3a3578b85704f026b590462e7d5e8bceb6dededd4e8782a83696138ec7da7" } },
1804
- "dsh-session-persistence": { version: "0.2.0-rc.2", files: { "lib/index.js": "cc0b6d3a224133af611b428d5a49020e300f86c3b4ba28037aeb219029bde3eb" } },
1805
- "dsh-session-persistence-jsonl": { version: "0.2.0-rc.2", files: { "lib/index.js": "0845707017acc2b4a8a75eab2244fa3fd88587b8094ab32014321dce7ca1e31b" } },
1806
- "dsh-session-format-catalog": { version: "0.2.0-rc.2", files: { "lib/index.js": "836bbb772ab505c299f1a4a246164c50c7c08b67ab0d17f1251d7ea2cd8c1818", "lib/types/index.js": "c7d797760bf2b9bc654751f2f8cb0b8a6b98998c8d9c1e41323c71a4d5f316f2" } },
1807
- "dsh-storage-domain": { version: "0.2.0-rc.2", files: { "lib/index.js": "e536ba09b7ccc0f10bb54818dfe44454374e5cbf7aeba140b216ba1ca2e87517" } },
1808
- "dsh-storage-json": { version: "0.2.0-rc.2", files: { "lib/index.js": "0a6b75d5569db3379edd93e863570170e1f4121b6c9fabd856f5b476cffe8df4" } },
1809
- "dsh-workspace": { version: "0.2.0-rc.2", files: { "lib/index.js": "a33af459cfc7af29dd17412443a63655fd5037dd348b0dec20a413ce60c6c8bc", "lib/types/index.js": "dbc8cc80e2b33c6bce07c73bd4e43be08af02051077ea9e032c2db2b9a154104" } },
1810
- "dsh-session-query": { version: "0.2.0-rc.2", files: { "lib/index.js": "dd8056fad008063c7e85169d4306720abe8efa6b32eac98f1b3053c6f89894aa" } },
1811
- "dsh-session-query-sqlite": { version: "0.2.0-rc.2", files: { "lib/index.js": "dbecf83320e10d93d735b3d01384ab817a0b90102ccecb0a22c013c71dfe70a0" } },
1812
- "dsh-session-projection-cache": { version: "0.2.0-rc.2", files: { "lib/index.js": "797282e86a23ece3a6a6246765277ec00360813bc0bac0450caff8c56278db0b" } },
1813
- "dsh-api-session-controller": { version: "0.2.0-rc.2", files: { "lib/index.js": "fb0f7b96130f595db20809eeb77a195b05f4a039f931d1e67692f1f74a4dd269", "lib/types/index.js": "764de9dca8a029a3c874f8fe15b864de59b222666853319f0e5f16fe29909e9f" } }
1802
+ "cordis": {
1803
+ "version": "4.0.5",
1804
+ "files": {
1805
+ "lib/index.js": "6a9394c0877ff45218818c6e815edd038f8057e1a1deb390a8d43ec81c57691e"
1806
+ }
1807
+ },
1808
+ "dsh-session": {
1809
+ "version": "0.2.1-rc.1",
1810
+ "files": {
1811
+ "lib/index.js": "2f5dd07cb5c744a29abbb8003a8a4cefd9e582c6e2538074ca299a0ddd02a3bf",
1812
+ "lib/types/index.js": "59cced30c7ee65813c62f4858c2fc15c8c636df96507b60c15543468178b72f2"
1813
+ }
1814
+ },
1815
+ "dsh-session-persistence": {
1816
+ "version": "0.2.1-rc.1",
1817
+ "files": {
1818
+ "lib/index.js": "cc0b6d3a224133af611b428d5a49020e300f86c3b4ba28037aeb219029bde3eb"
1819
+ }
1820
+ },
1821
+ "dsh-session-persistence-jsonl": {
1822
+ "version": "0.2.1-rc.1",
1823
+ "files": {
1824
+ "lib/index.js": "973dd78679b2661d6f492343bc22b124ae958aa597d3b36c698a2c650f909984"
1825
+ }
1826
+ },
1827
+ "dsh-session-format-catalog": {
1828
+ "version": "0.2.1-rc.1",
1829
+ "files": {
1830
+ "lib/index.js": "836bbb772ab505c299f1a4a246164c50c7c08b67ab0d17f1251d7ea2cd8c1818",
1831
+ "lib/types/index.js": "c7d797760bf2b9bc654751f2f8cb0b8a6b98998c8d9c1e41323c71a4d5f316f2"
1832
+ }
1833
+ },
1834
+ "dsh-storage-domain": {
1835
+ "version": "0.2.1-rc.1",
1836
+ "files": {
1837
+ "lib/index.js": "a54f7664d2f64fe04a08c7058ca5bff4fc69ed6a0d30c2bc11561b620698ef16"
1838
+ }
1839
+ },
1840
+ "dsh-storage-json": {
1841
+ "version": "0.2.1-rc.1",
1842
+ "files": {
1843
+ "lib/index.js": "0a6b75d5569db3379edd93e863570170e1f4121b6c9fabd856f5b476cffe8df4"
1844
+ }
1845
+ },
1846
+ "dsh-workspace": {
1847
+ "version": "0.2.1-rc.1",
1848
+ "files": {
1849
+ "lib/index.js": "931ca0cb10c5102066c7723690a887f0e6e8e7ab0ffdee1a782686745b0b934f",
1850
+ "lib/types/index.js": "ed69989d8286598fddb3a40030723810a1238968e91ccfec05fc84657bb5ec74"
1851
+ }
1852
+ },
1853
+ "dsh-session-query": {
1854
+ "version": "0.2.1-rc.1",
1855
+ "files": {
1856
+ "lib/index.js": "76ce2944e561c12f48b5e240d68cafe54ce6d667b1d20722e6939ed834489939"
1857
+ }
1858
+ },
1859
+ "dsh-session-query-sqlite": {
1860
+ "version": "0.2.1-rc.1",
1861
+ "files": {
1862
+ "lib/index.js": "dbecf83320e10d93d735b3d01384ab817a0b90102ccecb0a22c013c71dfe70a0"
1863
+ }
1864
+ },
1865
+ "dsh-session-projection-cache": {
1866
+ "version": "0.2.1-rc.1",
1867
+ "files": {
1868
+ "lib/index.js": "faf307dce5db2fb7ff58b4c7d9e544fc7cad5de2f270a89326a8d7bb2bda9c80"
1869
+ }
1870
+ },
1871
+ "dsh-api-session-controller": {
1872
+ "version": "0.2.1-rc.1",
1873
+ "files": {
1874
+ "lib/index.js": "a9801acb577b03053c5d5a3191ff555c5f1d791d0acddec113bea4511e33b386",
1875
+ "lib/types/index.js": "616ced16623b7448afa908ff65093eb6ef2a478d32e5ef9bc22634bfa9f80472"
1876
+ }
1877
+ }
1814
1878
  };
1879
+ var legacyDurableHostContract = "0.2.0-rc.2";
1880
+ var legacyDurableContractFingerprint = "2618a33decce99fe8ae893245236273d10ac5536bb9dd582dddd115ef27069f3";
1815
1881
  async function nativeRetirementSdkFingerprint() {
1816
1882
  const root = createRequire(import.meta.url);
1817
- const base = createRequire(root.resolve("@deepseek-ai/dsh/package.json"));
1883
+ const hostPath = root.resolve("@deepseek-ai/dsh/package.json");
1884
+ if (JSON.parse(await readFile(hostPath, "utf8")).version !== "0.2.1-rc.1") return null;
1885
+ const base = createRequire(hostPath);
1818
1886
  for (const [name2, expected] of Object.entries(nativeRetirementSdkSources)) {
1819
1887
  let path;
1820
1888
  try {
@@ -1836,8 +1904,8 @@ async function nativeRetirementSdkFingerprint() {
1836
1904
  }
1837
1905
  const runtime = createRequire(base.resolve("@deepseek-ai/dsh-base/package.json"));
1838
1906
  for (const [name2, expected] of Object.entries({
1839
- "dsh-agent": "7b9aa39474de83115cf890dd7f8904cf0d59df0811cb335ab85565a04f1aac93",
1840
- "dsh-agent-loop": "00c4814d63f3d1e2754eb09144832d19b30499d6ea444730473f740b587948c2"
1907
+ "dsh-agent": "7b59cf82c2784c25bdce4e3e24e5e5303b02b9f1003efacf50255492d17baf8b",
1908
+ "dsh-agent-loop": "cf57e3ecd487ac5c2553455aaa5cef2c6fb41e6bd61be5aa455675d1d7193033"
1841
1909
  })) {
1842
1910
  let path;
1843
1911
  try {
@@ -1846,9 +1914,9 @@ async function nativeRetirementSdkFingerprint() {
1846
1914
  if (error.code === "MODULE_NOT_FOUND") return null;
1847
1915
  throw error;
1848
1916
  }
1849
- if (JSON.parse(await readFile(path, "utf8")).version !== "0.2.0-rc.2" || createHash3("sha256").update(await readFile(join2(dirname(path), "lib/index.js"))).digest("hex") !== expected) return null;
1917
+ if (JSON.parse(await readFile(path, "utf8")).version !== "0.2.1-rc.1" || createHash3("sha256").update(await readFile(join2(dirname(path), "lib/index.js"))).digest("hex") !== expected) return null;
1850
1918
  }
1851
- return createHash3("sha256").update(JSON.stringify(nativeRetirementSdkSources)).digest("hex");
1919
+ return legacyDurableContractFingerprint;
1852
1920
  }
1853
1921
 
1854
1922
  // src/host/native-jsonl-files.ts
@@ -1857,1511 +1925,1518 @@ import { isAbsolute as isAbsolute2, join as join3, relative, resolve as resolve2
1857
1925
  import { createHash as createHash4 } from "node:crypto";
1858
1926
  import { createRequire as createRequire2 } from "node:module";
1859
1927
  import { zstdDecompressSync } from "node:zlib";
1860
- import Jsonl from "@deepseek-ai/dsh-session-persistence-jsonl";
1928
+ import { SessionPersistence } from "@deepseek-ai/dsh-session-persistence";
1861
1929
  import { SESSION_FORMAT_VERSION } from "@deepseek-ai/dsh-session";
1862
1930
  import { sessionFormatCatalog } from "@deepseek-ai/dsh-session-format-catalog";
1863
1931
  import { tryLockExclusive as tryLockExclusive2 } from "@deepseek-ai/node-addon-system/flock";
1864
1932
  import { z as z4 } from "zod";
1865
- var integer = z4.string().regex(/^\d+$/);
1866
- var hash = z4.string().regex(/^[a-f0-9]{64}$/);
1867
- var positiveInteger = z4.string().regex(/^[1-9]\d*$/);
1868
- var nodeIdentitySchema = z4.object({ dev: integer, ino: positiveInteger, birthtimeNs: positiveInteger }).strict();
1869
- var fileIdentitySchema = nodeIdentitySchema.extend({ size: integer, mtimeNs: integer, ctimeNs: integer, nlink: z4.literal("1") }).strict();
1870
- var lockIdentitySchema = nodeIdentitySchema.extend({ size: z4.literal("0"), nlink: z4.literal("1") }).strict();
1871
- var windowsLockSchema = z4.object({ kind: z4.literal("win32-semaphore"), name: z4.string().min(1) }).strict();
1872
- var nativeLockSchema = z4.union([lockIdentitySchema, windowsLockSchema]);
1873
- var headerIdentitySchema = z4.object({
1874
- id: z4.string().min(1),
1875
- createdAt: z4.number().int().nonnegative(),
1876
- cwd: z4.string().nullable(),
1877
- parentSession: z4.string().nullable(),
1878
- origin: z4.literal("subagent").nullable(),
1879
- isSeeded: z4.boolean(),
1880
- delegationDepth: z4.number().int().nonnegative(),
1881
- agentPreset: z4.string().nullable()
1882
- }).strict();
1883
- var fileRowSchema = z4.object({
1884
- resourceId: z4.string().min(1),
1885
- kind: z4.enum(["generation", "staging"]),
1886
- formatVersion: z4.number().int().min(0).max(4),
1887
- compression: z4.enum(["none", "zstd"]),
1888
- identity: fileIdentitySchema,
1889
- digest: hash,
1890
- header: headerIdentitySchema,
1891
- revision: hash
1892
- }).strict().superRefine((value, ctx) => {
1893
- try {
1894
- const kind = classify(value.resourceId);
1895
- if (kind.kind !== value.kind || kind.version !== value.formatVersion || kind.compression !== value.compression || value.revision !== sha(JSON.stringify({ identity: value.identity, digest: value.digest, header: value.header }))) {
1896
- ctx.addIssue({ code: "custom", message: "Resource classification and identity digest must agree." });
1897
- }
1898
- } catch {
1899
- ctx.addIssue({ code: "custom", message: "Unknown physical resource name." });
1933
+
1934
+ // src/host/native-retirement-persistence.ts
1935
+ import { SessionId as SessionId2 } from "@deepseek-ai/dsh-session";
1936
+
1937
+ // src/host/native-retirement-admission.ts
1938
+ import { AsyncLocalStorage } from "node:async_hooks";
1939
+ var NativeAdmissionError = class extends Error {
1940
+ code = "native/session-busy";
1941
+ };
1942
+ var NativeAdmission = class {
1943
+ maintenance = new AsyncLocalStorage();
1944
+ acceptedFrames = new AsyncLocalStorage();
1945
+ activeAcceptedFrames = /* @__PURE__ */ new Set();
1946
+ held = /* @__PURE__ */ new Set();
1947
+ released = /* @__PURE__ */ new Map();
1948
+ pending = /* @__PURE__ */ new Map();
1949
+ globalReads = /* @__PURE__ */ new Set();
1950
+ retired = /* @__PURE__ */ new Set();
1951
+ candidates = /* @__PURE__ */ new Set();
1952
+ closing = false;
1953
+ failed = false;
1954
+ ready = false;
1955
+ requiresRecovery() {
1956
+ return this.failed;
1900
1957
  }
1901
- });
1902
- var nativeJsonlFileSchema = fileRowSchema;
1903
- var nativeJsonlInventorySchema = z4.object({
1904
- schemaVersion: z4.literal(1),
1905
- root: z4.string(),
1906
- rootIdentity: nodeIdentitySchema,
1907
- directory: z4.string(),
1908
- directoryIdentity: nodeIdentitySchema,
1909
- sessionId: z4.string().min(1),
1910
- compression: z4.enum(["none", "zstd"]),
1911
- header: headerIdentitySchema,
1912
- anchor: z4.object({ resourceId: z4.string(), identity: nodeIdentitySchema, header: headerIdentitySchema }).strict(),
1913
- lock: nativeLockSchema,
1914
- files: z4.array(fileRowSchema).max(4096),
1915
- revision: hash
1916
- }).strict().superRefine((value, ctx) => {
1917
- try {
1918
- const anchor = generation(value.anchor.resourceId);
1919
- if (!isAbsolute2(value.root) || value.directory !== join3(project(value.header.cwd), segment(value.sessionId)) || value.header.id !== value.sessionId || !same(value.anchor.header, value.header) || !anchor || anchor.compression !== value.compression || new Set(value.files.map((row) => row.resourceId)).size !== value.files.length || value.files.some((row) => row.compression !== value.compression || !same(row.header, value.header)) || value.revision !== sha(JSON.stringify(value.files))) {
1920
- ctx.addIssue({ code: "custom", message: "Frozen directory, header identities, file scope and digest must agree." });
1921
- }
1922
- } catch {
1923
- ctx.addIssue({ code: "custom", message: "Invalid frozen directory or anchor." });
1958
+ activate() {
1959
+ this.ready = true;
1924
1960
  }
1925
- });
1926
- var NativeJsonlRefusal = class extends Error {
1927
- constructor(code, message) {
1928
- super(message);
1929
- this.code = code;
1930
- this.name = "NativeJsonlRefusal";
1961
+ suspend() {
1962
+ this.failed = true;
1931
1963
  }
1932
- };
1933
- function refuse(code, message) {
1934
- throw new NativeJsonlRefusal(code, message);
1935
- }
1936
- function sha(value) {
1937
- return createHash4("sha256").update(value).digest("hex");
1938
- }
1939
- function same(a, b) {
1940
- return JSON.stringify(a) === JSON.stringify(b);
1941
- }
1942
- function nodeIdentity(stat) {
1943
- if (stat.ino <= 0n || stat.birthtimeNs <= 0n) refuse("jsonl/identity-unavailable", "The filesystem does not provide a stable inode and creation identity.");
1944
- return { dev: String(stat.dev), ino: String(stat.ino), birthtimeNs: String(stat.birthtimeNs) };
1945
- }
1946
- function nodeIdentityFromRow(row) {
1947
- return { dev: row.identity.dev, ino: row.identity.ino, birthtimeNs: row.identity.birthtimeNs };
1948
- }
1949
- function fileIdentity(stat) {
1950
- if (!stat.isFile() || stat.nlink !== 1n) refuse("jsonl/unsafe-file", "Resources must be exclusive regular files without additional hard links.");
1951
- return fileIdentitySchema.parse({ ...nodeIdentity(stat), size: String(stat.size), mtimeNs: String(stat.mtimeNs), ctimeNs: String(stat.ctimeNs), nlink: "1" });
1952
- }
1953
- function lockIdentity(stat) {
1954
- const identity3 = fileIdentity(stat);
1955
- if (identity3.size !== "0") refuse("jsonl/lock-invalid", "The existing stable lock must contain no session content.");
1956
- return lockIdentitySchema.parse({ ...nodeIdentity(stat), size: "0", nlink: "1" });
1957
- }
1958
- function headerIdentity(header) {
1959
- return headerIdentitySchema.parse({
1960
- id: header.id,
1961
- createdAt: header.createdAt,
1962
- cwd: header.cwd ?? null,
1963
- parentSession: header.parentSession ?? null,
1964
- origin: header.origin ?? null,
1965
- isSeeded: header.isSeeded,
1966
- delegationDepth: header.delegationDepth ?? 0,
1967
- agentPreset: header.agentPreset ?? null
1968
- });
1969
- }
1970
- function segment(value) {
1971
- if (!value) refuse("jsonl/identity-invalid", "A path identity cannot be empty.");
1972
- if (value === "." || value === "..") return value.replace(/\./g, "~002E");
1973
- return value.replace(/[^A-Za-z0-9._-]/g, (unit) => `~${unit.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0")}`);
1974
- }
1975
- function project(cwd) {
1976
- if (cwd === null) return "_no-cwd";
1977
- if (!isAbsolute2(cwd)) refuse("jsonl/identity-invalid", "The stored cwd must be absolute.");
1978
- const readable = segment(cwd.replace(/[/\\:]+/g, "-")).replace(/^-+/, "") || "root";
1979
- return `--${readable.slice(0, 251)}--`;
1980
- }
1981
- function generation(name2) {
1982
- const match = /^session(?:\.v([1-9]\d*))?\.jsonl(\.zstd)?$/.exec(name2);
1983
- if (!match) return;
1984
- const version = match[1] === void 0 ? 0 : Number(match[1]);
1985
- if (!Number.isSafeInteger(version) || version > SESSION_FORMAT_VERSION) refuse("jsonl/unsupported-generation", "Unknown future physical generations cannot be retired.");
1986
- return { version, compression: match[2] ? "zstd" : "none" };
1987
- }
1988
- function classify(name2) {
1989
- const committed = generation(name2);
1990
- if (committed) return { ...committed, kind: "generation" };
1991
- const materializing = /^(session(?:\.v[1-9]\d*)?\.jsonl(?:\.zstd)?)\.[a-f0-9]{12}\.tmp$/.exec(name2);
1992
- if (materializing) return { ...generation(materializing[1]), kind: "staging" };
1993
- const migrating = /^session\.migration\.[a-f0-9]{16}\.jsonl(\.zstd)?\.tmp$/.exec(name2);
1994
- if (migrating) return { version: SESSION_FORMAT_VERSION, compression: migrating[1] ? "zstd" : "none", kind: "staging" };
1995
- refuse("jsonl/unknown-resource", `Unclassified session resource: ${name2}`);
1996
- }
1997
- var HEADER_LIMIT = 1024 * 1024;
1998
- function firstFrameEnd(bytes) {
1999
- if (bytes.length < 5) return;
2000
- if (bytes.readUInt32LE(0) !== 4247762216) refuse("jsonl/header-invalid", "The first Zstandard frame is not a standard frame.");
2001
- const descriptor2 = bytes[4];
2002
- if (descriptor2 & 24) refuse("jsonl/header-invalid", "Reserved Zstandard frame flags are unsupported.");
2003
- const single = Boolean(descriptor2 & 32);
2004
- const sizeFlag = descriptor2 >>> 6;
2005
- const dictionaryBytes = [0, 1, 2, 4][descriptor2 & 3];
2006
- const sizeBytes = sizeFlag === 0 ? single ? 1 : 0 : [0, 2, 4, 8][sizeFlag];
2007
- let cursor = 5 + (single ? 0 : 1) + dictionaryBytes + sizeBytes;
2008
- if (cursor > bytes.length) return;
2009
- for (; ; ) {
2010
- if (cursor + 3 > bytes.length) return;
2011
- const block = bytes.readUIntLE(cursor, 3);
2012
- const type = block >>> 1 & 3;
2013
- if (type === 3) refuse("jsonl/header-invalid", "Reserved Zstandard block type.");
2014
- cursor += 3 + (type === 1 ? 1 : block >>> 3);
2015
- if (cursor > bytes.length) return;
2016
- if (block & 1) {
2017
- cursor += descriptor2 & 4 ? 4 : 0;
2018
- return cursor <= bytes.length ? cursor : void 0;
1964
+ beginClose() {
1965
+ this.closing = true;
1966
+ }
1967
+ isRetired(id) {
1968
+ return this.retired.has(id) || this.failed && this.candidates.has(id);
1969
+ }
1970
+ hasTombstones() {
1971
+ return this.retired.size > 0 || this.failed && this.candidates.size > 0;
1972
+ }
1973
+ markRetired(id) {
1974
+ this.retired.add(id);
1975
+ }
1976
+ isAcceptedFrame() {
1977
+ const frame = this.acceptedFrames.getStore();
1978
+ return frame !== void 0 && this.activeAcceptedFrames.has(frame);
1979
+ }
1980
+ assertAllowed(id) {
1981
+ const maintenance = this.maintenance.getStore();
1982
+ if (maintenance?.active && maintenance.id === id && !(this.failed && this.candidates.has(id))) return;
1983
+ if (!this.ready || this.closing && !this.isAcceptedFrame() || this.failed && this.candidates.has(id) || this.retired.has(id) || this.held.has(id) && !this.isAcceptedFrame()) {
1984
+ throw new NativeAdmissionError("The session is reserved for retirement or awaiting recovery.");
2019
1985
  }
2020
1986
  }
2021
- }
2022
- function decodeHeader(bytes, compression, version) {
2023
- let line;
2024
- if (compression === "none") {
2025
- const newline = bytes.indexOf(10);
2026
- if (newline < 0) refuse("jsonl/header-invalid", "A complete physical header is required, including for staging.");
2027
- line = bytes.subarray(0, newline);
2028
- } else {
2029
- const end = firstFrameEnd(bytes);
2030
- if (end === void 0) refuse("jsonl/header-invalid", "A complete Zstandard header frame is required.");
2031
- let decoded;
1987
+ bypass(id, work) {
1988
+ const token = { id, active: true };
2032
1989
  try {
2033
- decoded = zstdDecompressSync(bytes.subarray(0, end), { maxOutputLength: HEADER_LIMIT });
2034
- } catch {
2035
- refuse("jsonl/header-invalid", "The bounded first Zstandard frame cannot be decoded.");
1990
+ const value = this.maintenance.run(token, work);
1991
+ if (value && typeof value.then === "function") {
1992
+ return Promise.resolve(value).finally(() => {
1993
+ token.active = false;
1994
+ });
1995
+ }
1996
+ token.active = false;
1997
+ return value;
1998
+ } catch (error) {
1999
+ token.active = false;
2000
+ throw error;
2036
2001
  }
2037
- if (!decoded.length || decoded.indexOf(10) !== decoded.length - 1) refuse("jsonl/header-invalid", "The header frame must contain exactly one newline-terminated record.");
2038
- line = decoded.subarray(0, -1);
2039
2002
  }
2040
- try {
2041
- const raw = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(line));
2042
- const result = sessionFormatCatalog.readHeader(raw);
2043
- if (result.status !== "current" && result.status !== "migration-required") refuse("jsonl/header-invalid", "Malformed or unsupported physical Session header.");
2044
- if (result.storedVersion !== version) refuse("jsonl/header-invalid", "Physical filename and header versions differ.");
2045
- return headerIdentity(result.header);
2046
- } catch (error) {
2047
- if (error instanceof NativeJsonlRefusal) throw error;
2048
- refuse("jsonl/header-invalid", "The physical Session header cannot be decoded and identified.");
2003
+ withoutBypass(work) {
2004
+ return this.maintenance.run(void 0, work);
2049
2005
  }
2050
- }
2051
- function missing(error) {
2052
- return error?.code === "ENOENT";
2053
- }
2054
- function leaseStamp(inventory) {
2055
- return JSON.stringify({
2056
- root: inventory.root,
2057
- rootIdentity: inventory.rootIdentity,
2058
- directory: inventory.directory,
2059
- directoryIdentity: inventory.directoryIdentity,
2060
- sessionId: inventory.sessionId,
2061
- compression: inventory.compression,
2062
- header: inventory.header,
2063
- anchor: inventory.anchor,
2064
- lock: inventory.lock
2065
- });
2066
- }
2067
- var NativeJsonlFiles = class _NativeJsonlFiles {
2068
- constructor(provider, root, compression, rootIdentity) {
2069
- this.provider = provider;
2070
- this.root = root;
2071
- this.compression = compression;
2072
- this.rootIdentity = rootIdentity;
2006
+ track(id, work) {
2007
+ this.assertAllowed(id);
2008
+ const tasks = this.pending.get(id) ?? /* @__PURE__ */ new Set();
2009
+ this.pending.set(id, tasks);
2010
+ const frame = Symbol("native-accepted-operation");
2011
+ this.activeAcceptedFrames.add(frame);
2012
+ const task = this.acceptedFrames.run(frame, () => Promise.resolve().then(work));
2013
+ tasks.add(task);
2014
+ void task.finally(() => {
2015
+ this.activeAcceptedFrames.delete(frame);
2016
+ tasks.delete(task);
2017
+ if (!tasks.size) this.pending.delete(id);
2018
+ }).catch(() => {
2019
+ });
2020
+ return task;
2073
2021
  }
2074
- leases = /* @__PURE__ */ new Map();
2075
- static async open(provider) {
2076
- if (!nativePlatformCandidate()) return;
2077
- if (!(provider instanceof Jsonl) || provider.name !== "session-persistence-jsonl" || SESSION_FORMAT_VERSION !== 4) return;
2078
- const internals = provider;
2079
- if (typeof internals.root !== "string" || !isAbsolute2(internals.root) || internals.compression !== "none" && internals.compression !== "zstd" || typeof provider.config.root !== "string" || resolve2(provider.config.root) !== internals.root || (provider.config.compression ?? "zstd") !== internals.compression) return;
2080
- const require2 = createRequire2(import.meta.url);
2081
- const metadata = require2("@deepseek-ai/dsh-session-persistence-jsonl/package.json");
2082
- if (metadata.version !== "0.2.0-rc.2") return;
2083
- let root;
2084
- try {
2085
- root = await realpath2(internals.root);
2086
- } catch (error) {
2087
- if (missing(error)) return;
2088
- throw error;
2022
+ async trackGlobal(work) {
2023
+ if (this.closing && !this.isAcceptedFrame() && !this.maintenance.getStore()?.active) {
2024
+ throw new NativeAdmissionError("Native admission is closing.");
2089
2025
  }
2090
- if (process.platform === "win32" && resolve2(internals.root).toLowerCase() !== root.toLowerCase()) return;
2091
- const identity3 = await lstat3(root, { bigint: true });
2092
- if (!identity3.isDirectory()) refuse("jsonl/root-invalid", "The configured root must be an existing directory.");
2093
- if (identity3.ino <= 0n || identity3.birthtimeNs <= 0n) return;
2094
- return new _NativeJsonlFiles(provider, root, internals.compression, nodeIdentity(identity3));
2095
- }
2096
- async inspect(sessionId, header) {
2097
- if (header.version !== SESSION_FORMAT_VERSION) refuse("jsonl/identity-invalid", "Inspection requires the current logical Session header.");
2098
- const identity3 = headerIdentity(header);
2099
- if (sessionId !== identity3.id) refuse("jsonl/identity-invalid", "Requested session and header identities differ.");
2100
- const directory = join3(project(identity3.cwd), segment(sessionId));
2101
- const base = await this.directory(directory, sessionId, identity3);
2102
- const files = await this.rows(base.path, identity3);
2103
- const canonical3 = files.filter((row) => row.kind === "generation").sort((a, b) => a.formatVersion - b.formatVersion)[0];
2104
- if (!canonical3) refuse("jsonl/session-not-found", "No identified committed generation exists.");
2105
- const inventory = {
2106
- schemaVersion: 1,
2107
- root: this.root,
2108
- rootIdentity: this.rootIdentity,
2109
- directory,
2110
- directoryIdentity: base.identity,
2111
- sessionId,
2112
- compression: this.compression,
2113
- header: identity3,
2114
- anchor: {
2115
- resourceId: canonical3.resourceId,
2116
- identity: { dev: canonical3.identity.dev, ino: canonical3.identity.ino, birthtimeNs: canonical3.identity.birthtimeNs },
2117
- header: identity3
2118
- },
2119
- lock: await this.lockIdentity(base.path),
2120
- files,
2121
- revision: sha(JSON.stringify(files))
2122
- };
2123
- await this.directory(directory, sessionId, identity3);
2124
- return nativeJsonlInventorySchema.parse(inventory);
2125
- }
2126
- /** Re-enumerate the entire scope without changing its original durable anchor. */
2127
- async current(input) {
2128
- const inventory = this.validate(input);
2129
- const base = await this.assertDirectory(inventory);
2130
- const files = await this.rows(base.path, inventory.header, inventory);
2131
- const lock = await this.lockIdentity(base.path);
2132
- if (!same(lock, inventory.lock)) refuse("jsonl/lock-changed", "The stable coordination file changed.");
2133
- return nativeJsonlInventorySchema.parse({ ...inventory, files, revision: sha(JSON.stringify(files)) });
2134
- }
2135
- async acquire(input, options = {}) {
2136
- const inventory = this.validate(input);
2137
- const base = await this.assertDirectory(inventory);
2138
- let fd;
2139
- let unlock;
2140
- const record = {
2141
- stamp: leaseStamp(inventory),
2142
- closing: false,
2143
- tail: Promise.resolve(),
2144
- pending: /* @__PURE__ */ new Set(),
2145
- recovering: options.recovering === true
2146
- };
2147
- let held = false;
2026
+ while (this.held.size && !this.maintenance.getStore()?.active && !this.isAcceptedFrame()) {
2027
+ await Promise.all([...this.released.values()].map((signal) => signal.promise));
2028
+ }
2029
+ if (!this.ready || this.closing && !this.isAcceptedFrame() && !this.maintenance.getStore()?.active) {
2030
+ throw new NativeAdmissionError("Native admission is not accepting another request.");
2031
+ }
2032
+ const frame = Symbol("native-header-read");
2033
+ this.activeAcceptedFrames.add(frame);
2034
+ const task = this.acceptedFrames.run(frame, () => Promise.resolve().then(work));
2035
+ this.globalReads.add(task);
2148
2036
  try {
2149
- if (process.platform === "win32") {
2150
- try {
2151
- unlock = await acquireWindowsSemaphore(join3(base.path, "session.lock"), "session");
2152
- } catch (error) {
2153
- if (error.code === "EBUSY") refuse("jsonl/writer-active", "Another writer holds the session kernel lease.");
2154
- throw error;
2155
- }
2156
- } else {
2157
- fd = await this.openFile(join3(base.path, "session.lock"), "write");
2158
- if (!same(lockIdentity(await fd.stat({ bigint: true })), inventory.lock)) refuse("jsonl/lock-changed", "The frozen stable lock changed.");
2159
- try {
2160
- await tryLockExclusive2(fd.fd);
2161
- } catch (error) {
2162
- if (["EAGAIN", "EWOULDBLOCK"].includes(error.code ?? "")) refuse("jsonl/writer-active", "Another writer holds the session lock.");
2163
- throw error;
2164
- }
2165
- }
2166
- await this.assertDirectory(inventory);
2167
- if (!same(await this.lockIdentity(base.path), inventory.lock)) refuse("jsonl/lock-changed", "The held lock no longer has its frozen namespace identity.");
2168
- this.leases.set(inventory.directory, record);
2169
- held = true;
2037
+ return await task;
2170
2038
  } finally {
2171
- if (!held) {
2172
- try {
2173
- await unlock?.();
2174
- } finally {
2175
- await fd?.close();
2176
- }
2177
- }
2039
+ this.activeAcceptedFrames.delete(frame);
2040
+ this.globalReads.delete(task);
2178
2041
  }
2179
- let releasing;
2180
- return { release: () => releasing ??= (async () => {
2181
- record.closing = true;
2182
- await Promise.allSettled([...record.pending]);
2183
- try {
2184
- try {
2185
- await unlock?.();
2186
- } finally {
2187
- await fd?.close();
2188
- }
2189
- } finally {
2190
- if (this.leases.get(inventory.directory) === record) this.leases.delete(inventory.directory);
2191
- }
2192
- })() };
2193
2042
  }
2194
- /** Caller must have persisted the exact retirement intent before this method. */
2195
- async erase(input, inputRow) {
2196
- const inventory = this.validate(input);
2197
- const row = fileRowSchema.parse(inputRow);
2198
- const lease = this.leases.get(inventory.directory);
2199
- if (!lease || lease.closing || lease.stamp !== leaseStamp(inventory)) refuse("jsonl/lease-required", "Erasure requires the same stable namespace kernel lease.");
2200
- if (!inventory.files.some((saved) => same(saved, row))) refuse("jsonl/scope-changed", "The resource is outside the frozen inventory.");
2201
- const operation = lease.tail.then(() => this.eraseInner(inventory, row));
2202
- lease.tail = operation.then(() => void 0, () => void 0);
2203
- lease.pending.add(operation);
2204
- try {
2205
- await operation;
2206
- } finally {
2207
- lease.pending.delete(operation);
2043
+ async drain(id) {
2044
+ for (; ; ) {
2045
+ const tasks = id === void 0 ? [...this.pending.values()].flatMap((set) => [...set]) : [...this.pending.get(id) ?? []];
2046
+ tasks.push(...this.globalReads);
2047
+ if (!tasks.length) return;
2048
+ await Promise.allSettled(tasks);
2208
2049
  }
2209
2050
  }
2210
- async eraseInner(inventory, row) {
2211
- const base = await this.assertDirectory(inventory);
2212
- const names = await readdir(base.path);
2213
- if (names.some((name2) => name2 !== "session.lock" && !inventory.files.some((saved) => saved.resourceId === name2))) refuse("jsonl/scope-changed", "A new or unknown file entered the frozen scope.");
2214
- if (!same(await this.lockIdentity(base.path), inventory.lock)) refuse("jsonl/lock-changed", "The held lock changed.");
2215
- const absolute = join3(base.path, row.resourceId);
2216
- const target = resolve2(absolute);
2217
- if (target !== absolute || relative(base.path, target) !== row.resourceId) refuse("jsonl/path-invalid", "The exact resource must be a direct child of its bound directory.");
2218
- const remainder = await this.isWindowsErasureRemainder(inventory, row);
2051
+ async acquire(id, recovery = false) {
2052
+ while (this.held.has(id)) await this.released.get(id).promise;
2053
+ if (this.failed || this.closing || !this.ready || !recovery && this.retired.has(id)) {
2054
+ throw new NativeAdmissionError("The session cannot enter another retirement scope.");
2055
+ }
2056
+ let resolve4;
2057
+ const signal = { promise: new Promise((done2) => {
2058
+ resolve4 = done2;
2059
+ }), resolve: () => resolve4() };
2060
+ this.held.add(id);
2061
+ this.released.set(id, signal);
2062
+ this.candidates.add(id);
2063
+ const release = () => {
2064
+ this.held.delete(id);
2065
+ this.released.delete(id);
2066
+ signal.resolve();
2067
+ };
2219
2068
  try {
2220
- if (!remainder) {
2221
- const observed = await this.readRow(base.path, row.resourceId, inventory.header);
2222
- if (!same(row, observed)) refuse("jsonl/resource-changed", "The physical resource identity or bytes changed after confirmation.");
2223
- }
2069
+ await this.drain(id);
2224
2070
  } catch (error) {
2225
- if (missing(error)) {
2226
- await this.syncDirectory(base.path);
2227
- return;
2228
- }
2071
+ release();
2229
2072
  throw error;
2230
2073
  }
2231
- await this.assertDirectory(inventory);
2232
- const latest = fileIdentity(await lstat3(absolute, { bigint: true }));
2233
- if (remainder ? latest.size !== "0" || !same(nodeIdentity(await lstat3(absolute, { bigint: true })), nodeIdentityFromRow(row)) : !same(latest, row.identity)) refuse("jsonl/resource-changed", "The exact resource changed before erasure.");
2234
- if (process.platform === "win32") {
2235
- const handle = await this.openFile(absolute, "write");
2236
- try {
2237
- const opened = fileIdentity(await handle.stat({ bigint: true }));
2238
- if (remainder ? opened.size !== "0" || !same(nodeIdentity(await handle.stat({ bigint: true })), nodeIdentityFromRow(row)) : !same(opened, row.identity)) refuse("jsonl/resource-changed", "The opened erasure object differs from the frozen file.");
2239
- await handle.truncate(0);
2240
- await handle.sync();
2241
- } finally {
2242
- await handle.close();
2074
+ let done = false;
2075
+ return () => {
2076
+ if (!done) {
2077
+ done = true;
2078
+ release();
2243
2079
  }
2244
- const cleared = await lstat3(absolute, { bigint: true });
2245
- if (!cleared.isFile() || cleared.nlink !== 1n || cleared.size !== 0n || !same(nodeIdentity(cleared), nodeIdentityFromRow(row))) refuse("jsonl/resource-changed", "The cleared erasure object changed before unlink.");
2246
- }
2247
- await unlink(absolute);
2248
- await this.syncDirectory(base.path);
2080
+ };
2249
2081
  }
2250
- validate(input) {
2251
- const value = nativeJsonlInventorySchema.parse(input);
2252
- if (value.root !== this.root || value.compression !== this.compression || !same(value.rootIdentity, this.rootIdentity) || value.sessionId !== value.header.id || value.directory !== join3(project(value.header.cwd), segment(value.sessionId)) || value.files.some((row) => row.resourceId.includes(sep) || row.resourceId.includes("/") || row.resourceId.includes("\\") || row.resourceId === "session.lock" || !same(row.header, value.header))) refuse("jsonl/binding-invalid", "The inventory is not bound to this adapter and exact directory.");
2253
- const windowsLock = "kind" in value.lock;
2254
- if (process.platform === "win32" !== windowsLock || "kind" in value.lock && value.lock.name !== windowsSemaphoreName(join3(this.root, value.directory, "session.lock"), "session")) {
2255
- refuse("jsonl/binding-invalid", "The inventory kernel lease belongs to another platform or namespace.");
2256
- }
2257
- if (new Set(value.files.map((row) => row.resourceId)).size !== value.files.length || value.revision !== sha(JSON.stringify(value.files))) refuse("jsonl/binding-invalid", "The frozen resource inventory digest is invalid.");
2258
- for (const row of value.files) {
2259
- const classified = classify(row.resourceId);
2260
- if (classified.kind !== row.kind || classified.version !== row.formatVersion || classified.compression !== row.compression || row.revision !== sha(JSON.stringify({ identity: row.identity, digest: row.digest, header: row.header }))) refuse("jsonl/binding-invalid", "Frozen resource classification or digest changed.");
2261
- }
2262
- return value;
2263
- }
2264
- async directory(directory, sessionId, header) {
2265
- const internals = this.provider;
2266
- if (await realpath2(internals.root) !== this.root || internals.compression !== this.compression || process.platform === "win32" && resolve2(internals.root).toLowerCase() !== this.root.toLowerCase() || resolve2(this.provider.config.root) !== internals.root || (this.provider.config.compression ?? "zstd") !== this.compression) refuse("jsonl/provider-changed", "The provider root or encoding changed.");
2267
- const root = await lstat3(this.root, { bigint: true });
2268
- if (!root.isDirectory() || !same(nodeIdentity(root), this.rootIdentity)) refuse("jsonl/root-changed", "The configured root identity changed.");
2269
- if (directory !== join3(project(header.cwd), segment(sessionId))) refuse("jsonl/path-invalid", "Directory does not match the stored identity.");
2270
- const matches = [];
2271
- for (const entry of await readdir(this.root, { withFileTypes: true })) {
2272
- const projectPath = join3(this.root, entry.name);
2273
- if ([`${segment(sessionId)}.jsonl`, `${segment(sessionId)}.jsonl.zstd`].includes(entry.name)) refuse("jsonl/legacy-layout", "Root-level flat session artifacts are not admitted.");
2274
- if (entry.isSymbolicLink()) refuse("jsonl/unsafe-directory", "Symlink project directories cannot certify a unique target.");
2275
- if (!entry.isDirectory()) continue;
2276
- for (const suffix of [".jsonl", ".jsonl.zstd"]) {
2277
- try {
2278
- await lstat3(join3(projectPath, segment(sessionId) + suffix));
2279
- refuse("jsonl/legacy-layout", "Flat session artifacts are not admitted.");
2280
- } catch (error) {
2281
- if (!missing(error)) throw error;
2282
- }
2283
- }
2284
- const candidate = join3(projectPath, segment(sessionId));
2285
- try {
2286
- const stat = await lstat3(candidate, { bigint: true });
2287
- if (!stat.isDirectory()) refuse("jsonl/unsafe-directory", "Session directories must be direct regular directories.");
2288
- matches.push(candidate);
2289
- } catch (error) {
2290
- if (!missing(error)) throw error;
2291
- }
2292
- }
2293
- const path = join3(this.root, directory);
2294
- if (matches.length !== 1 || matches[0] !== path) refuse("jsonl/identity-ambiguous", "The session directory is missing, misplaced, or duplicated across projects.");
2295
- const actual = await realpath2(path);
2296
- const rel = relative(this.root, actual);
2297
- if (actual !== path || rel !== directory || rel.startsWith(`..${sep}`) || isAbsolute2(rel)) refuse("jsonl/unsafe-directory", "The session directory leaves the configured root.");
2298
- return { path, identity: nodeIdentity(await lstat3(path, { bigint: true })) };
2082
+ };
2083
+
2084
+ // src/host/native-retirement-persistence.ts
2085
+ function nativeServiceInstance(value) {
2086
+ return Reflect.get(value, Symbol.for("cordis.original")) ?? value;
2087
+ }
2088
+ var NativePersistenceAdapter = class {
2089
+ constructor(provider, admission) {
2090
+ this.provider = provider;
2091
+ this.admission = admission;
2092
+ const raw = nativeServiceInstance(provider);
2093
+ if (!(raw.tracker?.openHandles instanceof Set) || !(raw.tracker.writers instanceof Map) || !(raw.tracker.pending instanceof Map) || !(raw.migrationPreparations instanceof Map) || !(raw.coldLogMemo instanceof Map)) throw new Error("JSONL retirement runtime shape does not match the pinned provider.");
2094
+ this.raw = raw;
2095
+ this.originalStat = provider.stat.bind(provider);
2096
+ this.originalList = provider.list.bind(provider);
2299
2097
  }
2300
- async assertDirectory(inventory) {
2301
- const base = await this.directory(inventory.directory, inventory.sessionId, inventory.header);
2302
- if (!same(base.identity, inventory.directoryIdentity)) refuse("jsonl/directory-changed", "The bound directory incarnation changed.");
2303
- return base;
2098
+ raw;
2099
+ originalStat;
2100
+ originalList;
2101
+ restore = [];
2102
+ detached = false;
2103
+ active = true;
2104
+ managedHandles = /* @__PURE__ */ new WeakSet();
2105
+ stat(id) {
2106
+ return this.originalStat(SessionId2(id));
2304
2107
  }
2305
- async lockIdentity(directory) {
2306
- if (process.platform === "win32") return { kind: "win32-semaphore", name: windowsSemaphoreName(join3(directory, "session.lock"), "session") };
2307
- return lockIdentity(await lstat3(join3(directory, "session.lock"), { bigint: true }));
2108
+ list() {
2109
+ return this.originalList();
2308
2110
  }
2309
- async isWindowsErasureRemainder(inventory, row) {
2310
- const lease = this.leases.get(inventory.directory);
2311
- if (process.platform !== "win32" || !lease?.recovering || lease.stamp !== leaseStamp(inventory)) return false;
2312
- try {
2313
- const handle = await this.openFile(join3(this.root, inventory.directory, row.resourceId), "read");
2314
- try {
2315
- const stat = await handle.stat({ bigint: true });
2316
- return stat.size === 0n && same(nodeIdentity(stat), nodeIdentityFromRow(row));
2317
- } finally {
2318
- await handle.close();
2319
- }
2320
- } catch (error) {
2321
- if (missing(error)) return false;
2322
- throw error;
2323
- }
2111
+ busy(id) {
2112
+ return this.raw.tracker.pending.has(id) || this.raw.tracker.writers.has(id) || [...this.raw.tracker.openHandles].some((handle) => handle.id === id) || this.raw.migrationPreparations.size !== 0;
2324
2113
  }
2325
- async rows(directory, header, frozen) {
2326
- const names = (await readdir(directory)).sort();
2327
- if (names.length > 4097) refuse("jsonl/scope-too-large", "Session scope exceeds the bounded inventory.");
2328
- const posix = process.platform !== "win32";
2329
- if (posix && !names.includes("session.lock")) refuse("jsonl/lock-missing", "The existing stable writer lock is required.");
2330
- const rows = [];
2331
- for (const name2 of names) {
2332
- if (posix && name2 === "session.lock") continue;
2333
- const original = frozen?.files.find((row) => row.resourceId === name2);
2334
- if (frozen && original && await this.isWindowsErasureRemainder(frozen, original)) rows.push(original);
2335
- else rows.push(await this.readRow(directory, name2, header));
2336
- }
2337
- if (!same(names, (await readdir(directory)).sort())) refuse("jsonl/scope-changed", "The directory changed while enumerating resources.");
2338
- return rows;
2114
+ forget(id) {
2115
+ if (this.busy(id)) throw new NativeAdmissionError("A persistence reference still owns this session.");
2116
+ this.raw.coldLogMemo.delete(id);
2339
2117
  }
2340
- async readRow(directory, name2, expected) {
2341
- const classified = classify(name2);
2342
- if (classified.compression !== this.compression) refuse("jsonl/encoding-mismatch", "Mixed raw and Zstandard session generations are not admitted.");
2343
- const path = join3(directory, name2);
2344
- const before = fileIdentity(await lstat3(path, { bigint: true }));
2345
- const fd = await this.openFile(path, "read");
2346
- try {
2347
- if (!same(before, fileIdentity(await fd.stat({ bigint: true })))) refuse("jsonl/resource-changed", "Resource was replaced before reading.");
2348
- const digest2 = createHash4("sha256");
2349
- const chunks = [];
2350
- let headerBytes = 0;
2351
- const buffer = Buffer.alloc(64 * 1024);
2352
- let total = 0n;
2353
- for (; ; ) {
2354
- const { bytesRead } = await fd.read(buffer, 0, buffer.length, null);
2355
- if (!bytesRead) break;
2356
- total += BigInt(bytesRead);
2357
- digest2.update(buffer.subarray(0, bytesRead));
2358
- if (headerBytes < HEADER_LIMIT) {
2359
- const chunk = Buffer.from(buffer.subarray(0, Math.min(bytesRead, HEADER_LIMIT - headerBytes)));
2360
- chunks.push(chunk);
2361
- headerBytes += chunk.length;
2118
+ install() {
2119
+ this.originalStat = this.provider.stat.bind(this.provider);
2120
+ this.originalList = this.provider.list.bind(this.provider);
2121
+ const route = (target, name2, idFor, transform, globalRead = false) => {
2122
+ target = nativeServiceInstance(target);
2123
+ const record = target;
2124
+ const original = record[name2];
2125
+ if (typeof original !== "function") throw new Error(`Missing pinned JSONL route ${name2}.`);
2126
+ const own = Object.getOwnPropertyDescriptor(target, name2);
2127
+ const adapter2 = this;
2128
+ const wrapper = function(...args) {
2129
+ const receiver = this;
2130
+ if (adapter2.detached) return Promise.reject(new NativeAdmissionError("This native guard belongs to a replaced retirement owner."));
2131
+ const id = idFor(args);
2132
+ if (!adapter2.active) {
2133
+ if (adapter2.admission.isRetired(id)) return Promise.reject(new NativeAdmissionError("This session has a retirement tombstone."));
2134
+ return Reflect.apply(original, receiver, args);
2362
2135
  }
2363
- }
2364
- if (String(total) !== before.size || !same(before, fileIdentity(await fd.stat({ bigint: true }))) || !same(before, fileIdentity(await lstat3(path, { bigint: true })))) refuse("jsonl/resource-changed", "The resource changed while hashing its exact bytes.");
2365
- const header = decodeHeader(Buffer.concat(chunks), classified.compression, classified.version);
2366
- if (!same(header, expected)) refuse("jsonl/identity-changed", "A physical generation or staging header belongs to another lifecycle.");
2367
- const value = {
2368
- resourceId: name2,
2369
- kind: classified.kind,
2370
- formatVersion: classified.version,
2371
- compression: classified.compression,
2372
- identity: before,
2373
- digest: digest2.digest("hex"),
2374
- header
2136
+ const run = () => adapter2.admission.track(id, async () => {
2137
+ const value = await Reflect.apply(original, receiver, args);
2138
+ return transform ? transform(value) : value;
2139
+ });
2140
+ return globalRead ? adapter2.admission.trackGlobal(run) : run();
2375
2141
  };
2376
- return fileRowSchema.parse({ ...value, revision: sha(JSON.stringify({ identity: value.identity, digest: value.digest, header })) });
2377
- } finally {
2378
- await fd.close();
2142
+ Object.defineProperty(target, name2, { configurable: true, writable: true, value: wrapper });
2143
+ this.restore.push(() => {
2144
+ if (record[name2] !== wrapper) throw new Error(`JSONL route ${name2} changed while retirement was installed.`);
2145
+ if (own) Object.defineProperty(target, name2, own);
2146
+ else delete record[name2];
2147
+ });
2148
+ };
2149
+ const headerId = (args) => String(args[0].id);
2150
+ route(this.provider, "create", headerId, (value) => this.manage(value));
2151
+ route(this.provider, "open", (args) => String(args[0]), (value) => this.manage(value), true);
2152
+ for (const method of ["persistBatch", "persistHeader", "truncateTornTail", "acquireWriteLease"]) {
2153
+ route(this.provider, method, headerId);
2379
2154
  }
2155
+ route(this.provider, "readStoredLog", (args) => String(args[1]), void 0, true);
2156
+ route(this.provider, "resolveCurrentLog", (args) => String(args[0]));
2157
+ const instance = nativeServiceInstance(this.provider);
2158
+ const rawStat = instance.stat;
2159
+ const rawList = instance.list;
2160
+ const adapter = this;
2161
+ instance.stat = async function(id, options) {
2162
+ if (adapter.detached) throw new NativeAdmissionError("This native observer belongs to a replaced retirement owner.");
2163
+ if (adapter.admission.isRetired(id)) return void 0;
2164
+ const value = await adapter.admission.trackGlobal(() => adapter.admission.track(id, () => rawStat.call(this, id, options)));
2165
+ return adapter.admission.isRetired(id) ? void 0 : value;
2166
+ };
2167
+ instance.list = async function(options) {
2168
+ if (adapter.detached) throw new NativeAdmissionError("This native observer belongs to a replaced retirement owner.");
2169
+ return (await adapter.admission.trackGlobal(() => rawList.call(this, options))).filter((item) => !adapter.admission.isRetired(item.header.id));
2170
+ };
2171
+ this.restore.push(() => {
2172
+ instance.stat = rawStat;
2173
+ instance.list = rawList;
2174
+ });
2175
+ return async () => {
2176
+ await this.admission.drain();
2177
+ this.active = false;
2178
+ if (this.originalRetired()) return;
2179
+ for (const undo of [...this.restore].reverse()) undo();
2180
+ this.restore.length = 0;
2181
+ };
2380
2182
  }
2381
- async openFile(path, access) {
2382
- try {
2383
- return await openRegularFile(path, access);
2384
- } catch (error) {
2385
- if (error instanceof RegularFileRefusal) refuse(error.code === "platform/unsafe-file" ? "jsonl/unsafe-file" : error.code === "platform/identity-unavailable" ? "jsonl/identity-unavailable" : "jsonl/resource-changed", error.message);
2386
- throw error;
2387
- }
2183
+ forceRestore() {
2184
+ this.detached = true;
2185
+ this.active = false;
2186
+ for (const undo of [...this.restore].reverse()) undo();
2187
+ this.restore.length = 0;
2388
2188
  }
2389
- async syncDirectory(directory) {
2390
- await syncDirectory(directory);
2189
+ originalRetired() {
2190
+ return this.admission.hasTombstones();
2391
2191
  }
2392
- };
2393
-
2394
- // src/host/native-retirement-metadata.ts
2395
- import { AsyncLocalStorage } from "node:async_hooks";
2396
- import { createHash as createHash5 } from "node:crypto";
2397
- import { readdir as readdir2, realpath as realpath3, lstat as lstat4, unlink as unlink2 } from "node:fs/promises";
2398
- import { dirname as dirname2, join as join4, resolve as resolve3 } from "node:path";
2399
- import { workspaceDomainState as workspaceDomainState2, workspaceRecord } from "@deepseek-ai/dsh-workspace";
2400
- import { z as z5 } from "zod";
2401
- var NativeMetadataRefusal = class extends Error {
2402
- constructor(code, message) {
2403
- super(message);
2404
- this.code = code;
2405
- this.name = "NativeMetadataRefusal";
2192
+ manage(handle) {
2193
+ if (this.managedHandles.has(handle)) return handle;
2194
+ this.managedHandles.add(handle);
2195
+ const methods2 = ["read", "append", "flush"];
2196
+ for (const name2 of methods2) {
2197
+ const original = handle[name2];
2198
+ Object.defineProperty(handle, name2, {
2199
+ configurable: true,
2200
+ writable: true,
2201
+ value: (...args) => !this.active && !this.admission.isRetired(handle.id) ? Reflect.apply(original, handle, args) : this.admission.track(handle.id, async () => Reflect.apply(original, handle, args))
2202
+ });
2203
+ }
2204
+ return handle;
2406
2205
  }
2407
2206
  };
2408
- var cachePhysicalIdentitySchema = z5.object({
2409
- dev: z5.string().regex(/^\d+$/),
2410
- ino: z5.string().regex(/^[1-9]\d*$/),
2411
- birthtimeNs: z5.string().regex(/^[1-9]\d*$/)
2412
- }).strict();
2413
- var nativeMetadataSnapshotSchema = z5.object({
2414
- schemaVersion: z5.literal(1),
2415
- sessionId: z5.string().min(1),
2416
- global: z5.object({ archived: z5.boolean(), pinned: z5.boolean() }).strict(),
2417
- workspaces: z5.array(z5.object({ workspaceId: z5.string(), record: workspaceRecord }).strict()),
2418
- cache: z5.object({
2419
- present: z5.boolean(),
2420
- digest: z5.string().nullable(),
2421
- location: z5.string().nullable(),
2422
- documentDigest: z5.string().nullable(),
2423
- memoryDigest: z5.string().nullable(),
2424
- physicalIdentity: cachePhysicalIdentitySchema.optional()
2425
- }).strict(),
2426
- queryProvider: z5.enum(["none", "sqlite-0.2.0-rc.2", "sqlite-memory-disabled-0.2.0-rc.2"]),
2427
- queryPath: z5.string().nullable()
2207
+
2208
+ // src/host/native-jsonl-files.ts
2209
+ var integer = z4.string().regex(/^\d+$/);
2210
+ var hash = z4.string().regex(/^[a-f0-9]{64}$/);
2211
+ var positiveInteger = z4.string().regex(/^[1-9]\d*$/);
2212
+ var nodeIdentitySchema = z4.object({ dev: integer, ino: positiveInteger, birthtimeNs: positiveInteger }).strict();
2213
+ var fileIdentitySchema = nodeIdentitySchema.extend({ size: integer, mtimeNs: integer, ctimeNs: integer, nlink: z4.literal("1") }).strict();
2214
+ var lockIdentitySchema = nodeIdentitySchema.extend({ size: z4.literal("0"), nlink: z4.literal("1") }).strict();
2215
+ var windowsLockSchema = z4.object({ kind: z4.literal("win32-semaphore"), name: z4.string().min(1) }).strict();
2216
+ var nativeLockSchema = z4.union([lockIdentitySchema, windowsLockSchema]);
2217
+ var headerIdentitySchema = z4.object({
2218
+ id: z4.string().min(1),
2219
+ createdAt: z4.number().int().nonnegative(),
2220
+ cwd: z4.string().nullable(),
2221
+ parentSession: z4.string().nullable(),
2222
+ origin: z4.literal("subagent").nullable(),
2223
+ isSeeded: z4.boolean(),
2224
+ delegationDepth: z4.number().int().nonnegative(),
2225
+ agentPreset: z4.string().nullable()
2428
2226
  }).strict();
2429
- function object(value) {
2430
- return value !== null && typeof value === "object" ? value : void 0;
2227
+ var fileRowSchema = z4.object({
2228
+ resourceId: z4.string().min(1),
2229
+ kind: z4.enum(["generation", "staging"]),
2230
+ formatVersion: z4.number().int().min(0).max(4),
2231
+ compression: z4.enum(["none", "zstd"]),
2232
+ identity: fileIdentitySchema,
2233
+ digest: hash,
2234
+ header: headerIdentitySchema,
2235
+ revision: hash
2236
+ }).strict().superRefine((value, ctx) => {
2237
+ try {
2238
+ const kind = classify(value.resourceId);
2239
+ if (kind.kind !== value.kind || kind.version !== value.formatVersion || kind.compression !== value.compression || value.revision !== sha(JSON.stringify({ identity: value.identity, digest: value.digest, header: value.header }))) {
2240
+ ctx.addIssue({ code: "custom", message: "Resource classification and identity digest must agree." });
2241
+ }
2242
+ } catch {
2243
+ ctx.addIssue({ code: "custom", message: "Unknown physical resource name." });
2244
+ }
2245
+ });
2246
+ var nativeJsonlFileSchema = fileRowSchema;
2247
+ var nativeJsonlInventorySchema = z4.object({
2248
+ schemaVersion: z4.literal(1),
2249
+ root: z4.string(),
2250
+ rootIdentity: nodeIdentitySchema,
2251
+ directory: z4.string(),
2252
+ directoryIdentity: nodeIdentitySchema,
2253
+ sessionId: z4.string().min(1),
2254
+ compression: z4.enum(["none", "zstd"]),
2255
+ header: headerIdentitySchema,
2256
+ anchor: z4.object({ resourceId: z4.string(), identity: nodeIdentitySchema, header: headerIdentitySchema }).strict(),
2257
+ lock: nativeLockSchema,
2258
+ files: z4.array(fileRowSchema).max(4096),
2259
+ revision: hash
2260
+ }).strict().superRefine((value, ctx) => {
2261
+ try {
2262
+ const anchor = generation(value.anchor.resourceId);
2263
+ if (!isAbsolute2(value.root) || value.directory !== join3(project(value.header.cwd), segment(value.sessionId)) || value.header.id !== value.sessionId || !same(value.anchor.header, value.header) || !anchor || anchor.compression !== value.compression || new Set(value.files.map((row) => row.resourceId)).size !== value.files.length || value.files.some((row) => row.compression !== value.compression || !same(row.header, value.header)) || value.revision !== sha(JSON.stringify(value.files))) {
2264
+ ctx.addIssue({ code: "custom", message: "Frozen directory, header identities, file scope and digest must agree." });
2265
+ }
2266
+ } catch {
2267
+ ctx.addIssue({ code: "custom", message: "Invalid frozen directory or anchor." });
2268
+ }
2269
+ });
2270
+ var NativeJsonlRefusal = class extends Error {
2271
+ constructor(code, message) {
2272
+ super(message);
2273
+ this.code = code;
2274
+ this.name = "NativeJsonlRefusal";
2275
+ }
2276
+ };
2277
+ function refuse(code, message) {
2278
+ throw new NativeJsonlRefusal(code, message);
2431
2279
  }
2432
- function canonical2(value) {
2433
- if (Array.isArray(value)) return `[${value.map(canonical2).join(",")}]`;
2434
- if (value !== null && typeof value === "object") return `{${Object.keys(value).sort().map((key2) => `${JSON.stringify(key2)}:${canonical2(value[key2])}`).join(",")}}`;
2435
- return JSON.stringify(value);
2280
+ function sha(value) {
2281
+ return createHash4("sha256").update(value).digest("hex");
2436
2282
  }
2437
- function digest(value) {
2438
- return createHash5("sha256").update(canonical2(value)).digest("hex");
2283
+ function same(a, b) {
2284
+ return JSON.stringify(a) === JSON.stringify(b);
2439
2285
  }
2440
- var methods = (port, names) => names.every((name2) => typeof port[name2] === "function");
2441
- var windowsCacheStagePrefix = ".dsh-session-bin-cache-";
2442
- function physicalIdentity(stat) {
2286
+ function nodeIdentity(stat) {
2287
+ if (stat.ino <= 0n || stat.birthtimeNs <= 0n) refuse("jsonl/identity-unavailable", "The filesystem does not provide a stable inode and creation identity.");
2443
2288
  return { dev: String(stat.dev), ino: String(stat.ino), birthtimeNs: String(stat.birthtimeNs) };
2444
2289
  }
2445
- function samePhysicalIdentity(left, right) {
2446
- return left !== void 0 && right !== void 0 && left.dev === right.dev && left.ino === right.ino && left.birthtimeNs === right.birthtimeNs;
2290
+ function nodeIdentityFromRow(row) {
2291
+ return { dev: row.identity.dev, ino: row.identity.ino, birthtimeNs: row.identity.birthtimeNs };
2447
2292
  }
2448
- function cacheStageBasename(snapshot, expected, request) {
2449
- const value = digest({ schemaVersion: 1, expected, request, cache: snapshot });
2450
- return `${windowsCacheStagePrefix}${value}.stage`;
2293
+ function fileIdentity(stat) {
2294
+ if (!stat.isFile() || stat.nlink !== 1n) refuse("jsonl/unsafe-file", "Resources must be exclusive regular files without additional hard links.");
2295
+ return fileIdentitySchema.parse({ ...nodeIdentity(stat), size: String(stat.size), mtimeNs: String(stat.mtimeNs), ctimeNs: String(stat.ctimeNs), nlink: "1" });
2451
2296
  }
2452
- var NativeMetadataAdapter = class _NativeMetadataAdapter {
2453
- constructor(ctx, admission, workspace, sessions, cache, query, controller) {
2454
- this.ctx = ctx;
2455
- this.admission = admission;
2456
- this.workspace = workspace;
2457
- this.sessions = sessions;
2458
- this.cache = cache;
2459
- this.query = query;
2460
- this.controller = controller;
2461
- this.queryConfiguration = query ? { path: query.config.path, openAt: query.config.openAt } : void 0;
2462
- this.queryProvider = !query ? "none" : query.config.openAt === "never" ? "sqlite-memory-disabled-0.2.0-rc.2" : "sqlite-0.2.0-rc.2";
2463
- this.cacheTable = cache?.requireTable();
2464
- this.cacheDirectory = this.cacheTable?.host.unit.dir;
2465
- this.agents = controller ? _NativeMetadataAdapter.get(ctx, "agents") : void 0;
2466
- }
2467
- targets = /* @__PURE__ */ new Set();
2468
- retained = /* @__PURE__ */ new Map();
2469
- followers = /* @__PURE__ */ new Map();
2470
- followerStops = /* @__PURE__ */ new Map();
2471
- activationTarget = new AsyncLocalStorage();
2472
- apiHandles = /* @__PURE__ */ new Map();
2473
- operations = /* @__PURE__ */ new Map();
2474
- queueTarget = new AsyncLocalStorage();
2475
- receivers = new AsyncLocalStorage();
2476
- restores = [];
2477
- guardedMethods = [];
2478
- guardedEntities = /* @__PURE__ */ new WeakSet();
2479
- installed = false;
2480
- disposed = false;
2481
- detached = false;
2482
- fallbackRetired = /* @__PURE__ */ new Set();
2483
- queryConfiguration;
2484
- queryProvider;
2485
- cacheTable;
2486
- cacheDirectory;
2487
- agents;
2488
- moveCacheDocument = renameWindowsWriteThrough;
2489
- clearCacheStage = async (handle) => {
2490
- await handle.truncate(0);
2491
- await handle.sync();
2492
- };
2493
- removeCacheStage = unlink2;
2494
- static get(ctx, name2) {
2495
- const value = object(ctx.get(name2));
2496
- return object(value?.[Symbol.for("cordis.original")] ?? value);
2497
- }
2498
- static async open(ctx, admission) {
2499
- const workspace = this.get(ctx, "workspaceRegistry");
2500
- const sessions = this.get(ctx, "sessions");
2501
- const cache = this.get(ctx, "sessionProjectionCache");
2502
- const query = this.get(ctx, "sessionQuery");
2503
- const controller = this.get(ctx, "sessionController");
2504
- if (!workspace || !sessions || workspace.constructor.name !== "WorkspaceRegistry" || sessions.constructor.name !== "SessionStore" || !methods(workspace, ["list", "requireTable", "requireState", "setState", "enqueueOperation", "indexHeader", "readSessionHeader"]) || ![workspace.headers, workspace.sessionPaths, workspace.invalidSessionPaths].every((map) => map instanceof Map) || !methods(sessions, ["get", "prepare", "enter", "announce"])) return void 0;
2505
- if (cache && (cache.constructor.name !== "SessionProjectionCache" || !(cache.dirty instanceof Map) || !methods(cache, ["put", "requireTable", "write", "coldSnapshot", "hydratePrepared", "cachedSnapshot", "cachedPredecessorTitle"]))) return void 0;
2506
- if (cache) {
2507
- const table = cache.requireTable();
2508
- const domain = ctx.storageDomain.get("session_projcache");
2509
- if (table?.constructor.name !== "KvTableImpl" || table.tableName !== "sessions" || !(table.records instanceof Map) || table.host?.domainName !== "session_projcache" || table.host.unit?.constructor.name !== "PerRecordJsonUnit" || table.host.unit.descriptor?.name !== "session_projcache" || table.host.unit.descriptor.version !== 7 || table.host.unit.descriptor.layout !== "per-record" || typeof table.host.unit.dir !== "string" || !methods(table.host, ["enqueue", "emitChanged", "assertReadable"]) || !methods(table.host.unit, ["loadAll", "deleteRecord", "tableDir"]) || domain?.unit !== table.host.unit) return void 0;
2510
- }
2511
- if (query) {
2512
- const enabled = ["startup", "first-search"].includes(query.config?.openAt);
2513
- const disabledMemory = query.config?.openAt === "never" && query.config.path === ":memory:" && query._db === void 0 && query._ready === void 0;
2514
- if (query.constructor.name !== "SqliteSessionQueryEngine" || !enabled && !disabledMemory || typeof query.config?.path !== "string" || !methods(query, ["searchSessions", "listSessions", "observeSession", "_serialized"]) || !(query._observations?.cache instanceof Map) || !methods(query._observations, ["read", "store"])) return void 0;
2515
- }
2516
- if (controller && (controller.constructor.name !== "SessionController" || !(controller.history?.closeFollowers instanceof Set) || !methods(controller.history, ["page", "follow", "sourceFor"]) || controller.agents?.constructor.name !== "ApiSessionAgentController" || !methods(controller.agents, ["resumeObserved", "createOrAdopt"]) || !methods(controller.listState ?? {}, ["summarizeCold"]) || !methods(this.get(ctx, "agents") ?? {}, ["create", "resume", "get"]))) return void 0;
2517
- return new _NativeMetadataAdapter(ctx, admission, workspace, sessions, cache, query, controller);
2518
- }
2519
- assert(id) {
2520
- this.targets.add(id);
2521
- if (this.disposed) {
2522
- if (this.fallbackRetired.has(id)) throw new NativeMetadataRefusal("native/retired", "This retired session remains fenced after adapter withdrawal.");
2523
- return;
2297
+ function lockIdentity(stat) {
2298
+ const identity3 = fileIdentity(stat);
2299
+ if (identity3.size !== "0") refuse("jsonl/lock-invalid", "The existing stable lock must contain no session content.");
2300
+ return lockIdentitySchema.parse({ ...nodeIdentity(stat), size: "0", nlink: "1" });
2301
+ }
2302
+ function headerIdentity(header) {
2303
+ return headerIdentitySchema.parse({
2304
+ id: header.id,
2305
+ createdAt: header.createdAt,
2306
+ cwd: header.cwd ?? null,
2307
+ parentSession: header.parentSession ?? null,
2308
+ origin: header.origin ?? null,
2309
+ isSeeded: header.isSeeded,
2310
+ delegationDepth: header.delegationDepth ?? 0,
2311
+ agentPreset: header.agentPreset ?? null
2312
+ });
2313
+ }
2314
+ function segment(value) {
2315
+ if (!value) refuse("jsonl/identity-invalid", "A path identity cannot be empty.");
2316
+ if (value === "." || value === "..") return value.replace(/\./g, "~002E");
2317
+ return value.replace(/[^A-Za-z0-9._-]/g, (unit) => `~${unit.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0")}`);
2318
+ }
2319
+ function project(cwd) {
2320
+ if (cwd === null) return "_no-cwd";
2321
+ if (!isAbsolute2(cwd)) refuse("jsonl/identity-invalid", "The stored cwd must be absolute.");
2322
+ const readable = segment(cwd.replace(/[/\\:]+/g, "-")).replace(/^-+/, "") || "root";
2323
+ return `--${readable.slice(0, 251)}--`;
2324
+ }
2325
+ function generation(name2) {
2326
+ const match = /^session(?:\.v([1-9]\d*))?\.jsonl(\.zstd)?$/.exec(name2);
2327
+ if (!match) return;
2328
+ const version = match[1] === void 0 ? 0 : Number(match[1]);
2329
+ if (!Number.isSafeInteger(version) || version > SESSION_FORMAT_VERSION) refuse("jsonl/unsupported-generation", "Unknown future physical generations cannot be retired.");
2330
+ return { version, compression: match[2] ? "zstd" : "none" };
2331
+ }
2332
+ function classify(name2) {
2333
+ const committed = generation(name2);
2334
+ if (committed) return { ...committed, kind: "generation" };
2335
+ const materializing = /^(session(?:\.v[1-9]\d*)?\.jsonl(?:\.zstd)?)\.[a-f0-9]{12}\.tmp$/.exec(name2);
2336
+ if (materializing) return { ...generation(materializing[1]), kind: "staging" };
2337
+ const migrating = /^session\.migration\.[a-f0-9]{16}\.jsonl(\.zstd)?\.tmp$/.exec(name2);
2338
+ if (migrating) return { version: SESSION_FORMAT_VERSION, compression: migrating[1] ? "zstd" : "none", kind: "staging" };
2339
+ refuse("jsonl/unknown-resource", `Unclassified session resource: ${name2}`);
2340
+ }
2341
+ var HEADER_LIMIT = 1024 * 1024;
2342
+ function firstFrameEnd(bytes) {
2343
+ if (bytes.length < 5) return;
2344
+ if (bytes.readUInt32LE(0) !== 4247762216) refuse("jsonl/header-invalid", "The first Zstandard frame is not a standard frame.");
2345
+ const descriptor2 = bytes[4];
2346
+ if (descriptor2 & 24) refuse("jsonl/header-invalid", "Reserved Zstandard frame flags are unsupported.");
2347
+ const single = Boolean(descriptor2 & 32);
2348
+ const sizeFlag = descriptor2 >>> 6;
2349
+ const dictionaryBytes = [0, 1, 2, 4][descriptor2 & 3];
2350
+ const sizeBytes = sizeFlag === 0 ? single ? 1 : 0 : [0, 2, 4, 8][sizeFlag];
2351
+ let cursor = 5 + (single ? 0 : 1) + dictionaryBytes + sizeBytes;
2352
+ if (cursor > bytes.length) return;
2353
+ for (; ; ) {
2354
+ if (cursor + 3 > bytes.length) return;
2355
+ const block = bytes.readUIntLE(cursor, 3);
2356
+ const type = block >>> 1 & 3;
2357
+ if (type === 3) refuse("jsonl/header-invalid", "Reserved Zstandard block type.");
2358
+ cursor += 3 + (type === 1 ? 1 : block >>> 3);
2359
+ if (cursor > bytes.length) return;
2360
+ if (block & 1) {
2361
+ cursor += descriptor2 & 4 ? 4 : 0;
2362
+ return cursor <= bytes.length ? cursor : void 0;
2524
2363
  }
2525
- this.admission.assertAllowed(id);
2526
2364
  }
2527
- tracked(id, work) {
2528
- this.targets.add(id);
2529
- if (this.disposed) {
2530
- this.assert(id);
2531
- return work();
2532
- }
2533
- return this.admission.trackGlobal(() => this.admission.track(id, async () => {
2534
- this.assert(id);
2535
- this.increment(this.operations, id, 1);
2536
- try {
2537
- return await work();
2538
- } finally {
2539
- this.increment(this.operations, id, -1);
2540
- }
2541
- }));
2542
- }
2543
- increment(map, id, delta) {
2544
- const next = (map.get(id) ?? 0) + delta;
2545
- if (next === 0) map.delete(id);
2546
- else map.set(id, next);
2547
- }
2548
- refuse(code, message) {
2549
- throw new NativeMetadataRefusal(code, message);
2550
- }
2551
- assertInstances() {
2552
- if (this.guardedMethods.some(({ port, name: name2, replacement }) => port[name2] !== replacement)) {
2553
- this.refuse("native/guard-replaced", "A native metadata admission guard was replaced.");
2554
- }
2555
- if (_NativeMetadataAdapter.get(this.ctx, "workspaceRegistry") !== this.workspace || _NativeMetadataAdapter.get(this.ctx, "sessions") !== this.sessions || _NativeMetadataAdapter.get(this.ctx, "sessionProjectionCache") !== this.cache || _NativeMetadataAdapter.get(this.ctx, "sessionQuery") !== this.query || _NativeMetadataAdapter.get(this.ctx, "sessionController") !== this.controller || this.controller && _NativeMetadataAdapter.get(this.ctx, "agents") !== this.agents || this.cache && (this.cache.requireTable() !== this.cacheTable || this.cacheTable.host.unit.dir !== this.cacheDirectory) || this.query && (this.query.config.path !== this.queryConfiguration.path || this.query.config.openAt !== this.queryConfiguration.openAt) || this.queryProvider === "sqlite-memory-disabled-0.2.0-rc.2" && (this.query._db !== void 0 || this.query._ready !== void 0)) {
2556
- this.refuse("native/composition-changed", "Native metadata service composition changed.");
2365
+ }
2366
+ function decodeHeader(bytes, compression, version) {
2367
+ let line;
2368
+ if (compression === "none") {
2369
+ const newline = bytes.indexOf(10);
2370
+ if (newline < 0) refuse("jsonl/header-invalid", "A complete physical header is required, including for staging.");
2371
+ line = bytes.subarray(0, newline);
2372
+ } else {
2373
+ const end = firstFrameEnd(bytes);
2374
+ if (end === void 0) refuse("jsonl/header-invalid", "A complete Zstandard header frame is required.");
2375
+ let decoded;
2376
+ try {
2377
+ decoded = zstdDecompressSync(bytes.subarray(0, end), { maxOutputLength: HEADER_LIMIT });
2378
+ } catch {
2379
+ refuse("jsonl/header-invalid", "The bounded first Zstandard frame cannot be decoded.");
2557
2380
  }
2381
+ if (!decoded.length || decoded.indexOf(10) !== decoded.length - 1) refuse("jsonl/header-invalid", "The header frame must contain exactly one newline-terminated record.");
2382
+ line = decoded.subarray(0, -1);
2558
2383
  }
2559
- assertCold(id) {
2560
- if (this.sessions.get(id) !== void 0 || _NativeMetadataAdapter.get(this.ctx, "agents")?.get(id) !== void 0) {
2561
- this.refuse("native/session-live", "Native deletion currently accepts only cold sessions.");
2562
- }
2563
- const cached = this.query?._observations.cache.get(id);
2564
- if (cached?.refs > 0 || (this.retained.get(id) ?? 0) > 0) this.refuse("native/query-retained", "A retained query observation still owns this session.");
2565
- if ((this.followers.get(id) ?? 0) > 0) this.refuse("native/follow-retained", "A history follower still owns this session.");
2566
- const knownFollowers = [...this.followers.values()].reduce((sum, count) => sum + count, 0);
2567
- if ((this.controller?.history.closeFollowers.size ?? 0) > knownFollowers) this.refuse("native/unknown-follow", "A history follower predates native admission tracking.");
2568
- if (this.cache && [...this.cache.dirty.keys()].some((session) => session.id === id)) this.refuse("native/cache-dirty", "Target cache write-behind is not quiescent.");
2384
+ try {
2385
+ const raw = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(line));
2386
+ const result = sessionFormatCatalog.readHeader(raw);
2387
+ if (result.status !== "current" && result.status !== "migration-required") refuse("jsonl/header-invalid", "Malformed or unsupported physical Session header.");
2388
+ if (result.storedVersion !== version) refuse("jsonl/header-invalid", "Physical filename and header versions differ.");
2389
+ return headerIdentity(result.header);
2390
+ } catch (error) {
2391
+ if (error instanceof NativeJsonlRefusal) throw error;
2392
+ refuse("jsonl/header-invalid", "The physical Session header cannot be decoded and identified.");
2569
2393
  }
2570
- /** Explicit deletion preparation may unload an idle API-owned lifecycle.
2571
- * No bare registry Agent, foreign handle, or unknown reader is disposed. */
2572
- async releaseIdle(id) {
2573
- this.assertInstances();
2574
- const handle = this.apiHandles.get(id);
2575
- if (!handle) return;
2576
- const agent = handle.agent;
2577
- const registry = this.agents;
2578
- if (registry.get(id) !== agent || this.sessions.get(id) !== agent.session) return;
2579
- const activity = await this.admission.withoutBypass(() => this.ctx.waterfall(
2580
- "workspace/session-activity",
2581
- { sessionId: id },
2582
- async () => []
2583
- ));
2584
- if (activity.length || agent.constructor.name !== "ReactLoopAgent" || agent.phase?.kind !== "idle" || agent.status !== "idle" || !Array.isArray(agent.inbox?.nextTurn) || !Array.isArray(agent.inbox?.nextStep) || agent.inbox.nextTurn.length || agent.inbox.nextStep.length) {
2585
- this.refuse("native/session-active", "Native deletion refuses active or queued work.");
2586
- }
2587
- if (!this.workspace.archivedSessionIds.includes(id)) this.refuse("native/not-archived", "Only an archived target may be unloaded.");
2588
- if (registry.get(id) !== agent || this.sessions.get(id) !== agent.session) this.refuse("native/session-live", "The API lifecycle changed.");
2589
- await this.admission.bypass(id, async () => {
2590
- await handle.dispose();
2591
- for (const stop of [...this.followerStops.get(id) ?? []]) await stop();
2592
- if (this.cache) await this.cache.requireTable().host.enqueue(async () => void 0);
2593
- const summary = this.controller.listState.summarizeCold(agent.session.header);
2594
- this.admission.withoutBypass(() => this.ctx.emit("api-session/added", summary));
2595
- });
2596
- this.apiHandles.delete(id);
2394
+ }
2395
+ function missing(error) {
2396
+ return error?.code === "ENOENT";
2397
+ }
2398
+ function leaseStamp(inventory) {
2399
+ return JSON.stringify({
2400
+ root: inventory.root,
2401
+ rootIdentity: inventory.rootIdentity,
2402
+ directory: inventory.directory,
2403
+ directoryIdentity: inventory.directoryIdentity,
2404
+ sessionId: inventory.sessionId,
2405
+ compression: inventory.compression,
2406
+ header: inventory.header,
2407
+ anchor: inventory.anchor,
2408
+ lock: inventory.lock
2409
+ });
2410
+ }
2411
+ var NativeJsonlFiles = class _NativeJsonlFiles {
2412
+ constructor(provider, root, compression, rootIdentity) {
2413
+ this.provider = provider;
2414
+ this.root = root;
2415
+ this.compression = compression;
2416
+ this.rootIdentity = rootIdentity;
2597
2417
  }
2598
- async cacheView(table, id, acceptedStage) {
2599
- table.host.assertReadable();
2600
- if (!/^[a-zA-Z0-9_-]+$/.test(id)) this.refuse("native/cache-key-unsupported", "The pinned cache backend cannot own this record key.");
2601
- const directory = resolve3(table.host.unit.dir);
2602
- const legacyPath = join4(dirname2(directory), `${table.host.unit.descriptor.name}.json`);
2603
- try {
2604
- await lstat4(legacyPath);
2605
- this.refuse("native/cache-unclassified-resource", "A legacy whole-unit cache could republish the retired target document.");
2606
- } catch (error) {
2607
- if (error.code !== "ENOENT") throw error;
2608
- }
2609
- let location;
2610
- try {
2611
- location = await realpath3(directory);
2612
- } catch (error) {
2613
- if (error.code !== "ENOENT") throw error;
2614
- location = join4(await realpath3(dirname2(directory)), "session_projcache");
2615
- }
2616
- const tableDirectory = table.host.unit.tableDir("sessions");
2617
- let names;
2418
+ leases = /* @__PURE__ */ new Map();
2419
+ static async open(provider) {
2420
+ if (!nativePlatformCandidate()) return;
2421
+ if (!(provider instanceof SessionPersistence) || provider.constructor.name !== "JsonlSessionPersistence" || provider.name !== "session-persistence-jsonl" || SESSION_FORMAT_VERSION !== 4) return;
2422
+ if (createHash4("sha256").update(Function.prototype.toString.call(nativeServiceInstance(provider).constructor)).digest("hex") !== "bb0e12b14bd21adec58c51934f00014e482380102f09aa5e935536c57c0d6e1e") return;
2423
+ const internals = provider;
2424
+ const config = internals.config;
2425
+ if (typeof internals.root !== "string" || !isAbsolute2(internals.root) || internals.compression !== "none" && internals.compression !== "zstd" || typeof config?.root !== "string" || resolve2(config.root) !== internals.root || (config.compression ?? "zstd") !== internals.compression) return;
2426
+ const require2 = createRequire2(import.meta.url);
2427
+ const metadata = require2("@deepseek-ai/dsh-session-persistence-jsonl/package.json");
2428
+ if (metadata.version !== "0.2.1-rc.1") return;
2429
+ let root;
2618
2430
  try {
2619
- names = await readdir2(tableDirectory);
2431
+ root = await realpath2(internals.root);
2620
2432
  } catch (error) {
2621
- if (error.code !== "ENOENT") throw error;
2622
- names = [];
2623
- }
2624
- if (names.some((name2) => name2.startsWith(`${id}.json.bak.`) || /^\.[a-f0-9-]+\.tmp$/.test(name2) || name2.startsWith(windowsCacheStagePrefix) && name2 !== acceptedStage)) {
2625
- this.refuse("native/cache-unclassified-resource", "A cache backup or unclassified staging document prevents complete target erasure.");
2433
+ if (missing(error)) return;
2434
+ throw error;
2626
2435
  }
2627
- let documentDigest = null;
2628
- let documentIdentity;
2629
- const path = join4(tableDirectory, `${id}.json`);
2436
+ if (process.platform === "win32" && resolve2(internals.root).toLowerCase() !== root.toLowerCase()) return;
2437
+ const identity3 = await lstat3(root, { bigint: true });
2438
+ if (!identity3.isDirectory()) refuse("jsonl/root-invalid", "The configured root must be an existing directory.");
2439
+ if (identity3.ino <= 0n || identity3.birthtimeNs <= 0n) return;
2440
+ return new _NativeJsonlFiles(provider, root, internals.compression, nodeIdentity(identity3));
2441
+ }
2442
+ async inspect(sessionId, header) {
2443
+ if (header.version !== SESSION_FORMAT_VERSION) refuse("jsonl/identity-invalid", "Inspection requires the current logical Session header.");
2444
+ const identity3 = headerIdentity(header);
2445
+ if (sessionId !== identity3.id) refuse("jsonl/identity-invalid", "Requested session and header identities differ.");
2446
+ const directory = join3(project(identity3.cwd), segment(sessionId));
2447
+ const base = await this.directory(directory, sessionId, identity3);
2448
+ const files = await this.rows(base.path, identity3);
2449
+ const canonical3 = files.filter((row) => row.kind === "generation").sort((a, b) => a.formatVersion - b.formatVersion)[0];
2450
+ if (!canonical3) refuse("jsonl/session-not-found", "No identified committed generation exists.");
2451
+ const inventory = {
2452
+ schemaVersion: 1,
2453
+ root: this.root,
2454
+ rootIdentity: this.rootIdentity,
2455
+ directory,
2456
+ directoryIdentity: base.identity,
2457
+ sessionId,
2458
+ compression: this.compression,
2459
+ header: identity3,
2460
+ anchor: {
2461
+ resourceId: canonical3.resourceId,
2462
+ identity: { dev: canonical3.identity.dev, ino: canonical3.identity.ino, birthtimeNs: canonical3.identity.birthtimeNs },
2463
+ header: identity3
2464
+ },
2465
+ lock: await this.lockIdentity(base.path),
2466
+ files,
2467
+ revision: sha(JSON.stringify(files))
2468
+ };
2469
+ await this.directory(directory, sessionId, identity3);
2470
+ return nativeJsonlInventorySchema.parse(inventory);
2471
+ }
2472
+ /** Re-enumerate the entire scope without changing its original durable anchor. */
2473
+ async current(input) {
2474
+ const inventory = this.validate(input);
2475
+ const base = await this.assertDirectory(inventory);
2476
+ const files = await this.rows(base.path, inventory.header, inventory);
2477
+ const lock = await this.lockIdentity(base.path);
2478
+ if (!same(lock, inventory.lock)) refuse("jsonl/lock-changed", "The stable coordination file changed.");
2479
+ return nativeJsonlInventorySchema.parse({ ...inventory, files, revision: sha(JSON.stringify(files)) });
2480
+ }
2481
+ async acquire(input, options = {}) {
2482
+ const inventory = this.validate(input);
2483
+ const base = await this.assertDirectory(inventory);
2484
+ let fd;
2485
+ let unlock;
2486
+ const record = {
2487
+ stamp: leaseStamp(inventory),
2488
+ closing: false,
2489
+ tail: Promise.resolve(),
2490
+ pending: /* @__PURE__ */ new Set(),
2491
+ recovering: options.recovering === true
2492
+ };
2493
+ let held = false;
2630
2494
  try {
2631
- let handle;
2632
- try {
2633
- handle = await openRegularFile(path, "read");
2634
- } catch (error) {
2635
- if (error instanceof RegularFileRefusal) this.refuse(error.code === "platform/unsafe-file" ? "native/cache-unsafe-document" : "native/cache-document-changed", error.message);
2636
- throw error;
2495
+ if (process.platform === "win32") {
2496
+ try {
2497
+ unlock = await acquireWindowsSemaphore(join3(base.path, "session.lock"), "session");
2498
+ } catch (error) {
2499
+ if (error.code === "EBUSY") refuse("jsonl/writer-active", "Another writer holds the session kernel lease.");
2500
+ throw error;
2501
+ }
2502
+ } else {
2503
+ fd = await this.openFile(join3(base.path, "session.lock"), "write");
2504
+ if (!same(lockIdentity(await fd.stat({ bigint: true })), inventory.lock)) refuse("jsonl/lock-changed", "The frozen stable lock changed.");
2505
+ try {
2506
+ await tryLockExclusive2(fd.fd);
2507
+ } catch (error) {
2508
+ if (["EAGAIN", "EWOULDBLOCK"].includes(error.code ?? "")) refuse("jsonl/writer-active", "Another writer holds the session lock.");
2509
+ throw error;
2510
+ }
2637
2511
  }
2638
- try {
2639
- const before = await handle.stat({ bigint: true });
2640
- const bytes = await handle.readFile();
2641
- const after = await handle.stat({ bigint: true });
2642
- const current = await lstat4(path, { bigint: true });
2643
- if (!current.isFile() || before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.birthtimeNs !== after.birthtimeNs || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs || after.nlink !== 1n || after.dev !== current.dev || after.ino !== current.ino || after.birthtimeNs !== current.birthtimeNs || after.size !== current.size || after.mtimeNs !== current.mtimeNs || after.ctimeNs !== current.ctimeNs) {
2644
- this.refuse("native/cache-document-changed", "The physical cache document changed while observing its bytes.");
2512
+ await this.assertDirectory(inventory);
2513
+ if (!same(await this.lockIdentity(base.path), inventory.lock)) refuse("jsonl/lock-changed", "The held lock no longer has its frozen namespace identity.");
2514
+ this.leases.set(inventory.directory, record);
2515
+ held = true;
2516
+ } finally {
2517
+ if (!held) {
2518
+ try {
2519
+ await unlock?.();
2520
+ } finally {
2521
+ await fd?.close();
2645
2522
  }
2646
- documentDigest = createHash5("sha256").update(bytes).digest("hex");
2647
- if (process.platform === "win32") documentIdentity = physicalIdentity(after);
2648
- } finally {
2649
- await handle.close();
2650
2523
  }
2651
- } catch (error) {
2652
- if (error.code !== "ENOENT") throw error;
2653
2524
  }
2654
- const memory = table.records.get(id);
2655
- const memoryDigest = memory === void 0 ? null : digest(memory);
2656
- const present = documentDigest !== null || memoryDigest !== null;
2657
- return {
2658
- present,
2659
- digest: present ? digest({ documentDigest, memoryDigest }) : null,
2660
- location,
2661
- documentDigest,
2662
- memoryDigest,
2663
- ...documentIdentity ? { physicalIdentity: documentIdentity } : {}
2664
- };
2525
+ let releasing;
2526
+ return { release: () => releasing ??= (async () => {
2527
+ record.closing = true;
2528
+ await Promise.allSettled([...record.pending]);
2529
+ try {
2530
+ try {
2531
+ await unlock?.();
2532
+ } finally {
2533
+ await fd?.close();
2534
+ }
2535
+ } finally {
2536
+ if (this.leases.get(inventory.directory) === record) this.leases.delete(inventory.directory);
2537
+ }
2538
+ })() };
2665
2539
  }
2666
- async openCacheDocument(path, access) {
2540
+ /** Caller must have persisted the exact retirement intent before this method. */
2541
+ async erase(input, inputRow) {
2542
+ const inventory = this.validate(input);
2543
+ const row = fileRowSchema.parse(inputRow);
2544
+ const lease = this.leases.get(inventory.directory);
2545
+ if (!lease || lease.closing || lease.stamp !== leaseStamp(inventory)) refuse("jsonl/lease-required", "Erasure requires the same stable namespace kernel lease.");
2546
+ if (!inventory.files.some((saved) => same(saved, row))) refuse("jsonl/scope-changed", "The resource is outside the frozen inventory.");
2547
+ const operation = lease.tail.then(() => this.eraseInner(inventory, row));
2548
+ lease.tail = operation.then(() => void 0, () => void 0);
2549
+ lease.pending.add(operation);
2667
2550
  try {
2668
- return await openRegularFile(path, access);
2669
- } catch (error) {
2670
- if (error instanceof RegularFileRefusal) this.refuse(error.code === "platform/unsafe-file" ? "native/cache-unsafe-document" : "native/cache-document-changed", error.message);
2671
- throw error;
2551
+ await operation;
2552
+ } finally {
2553
+ lease.pending.delete(operation);
2672
2554
  }
2673
2555
  }
2674
- async pathAbsent(path) {
2556
+ async eraseInner(inventory, row) {
2557
+ const base = await this.assertDirectory(inventory);
2558
+ const names = await readdir(base.path);
2559
+ if (names.some((name2) => name2 !== "session.lock" && !inventory.files.some((saved) => saved.resourceId === name2))) refuse("jsonl/scope-changed", "A new or unknown file entered the frozen scope.");
2560
+ if (!same(await this.lockIdentity(base.path), inventory.lock)) refuse("jsonl/lock-changed", "The held lock changed.");
2561
+ const absolute = join3(base.path, row.resourceId);
2562
+ const target = resolve2(absolute);
2563
+ if (target !== absolute || relative(base.path, target) !== row.resourceId) refuse("jsonl/path-invalid", "The exact resource must be a direct child of its bound directory.");
2564
+ const remainder = await this.isWindowsErasureRemainder(inventory, row);
2675
2565
  try {
2676
- await lstat4(path);
2677
- return false;
2566
+ if (!remainder) {
2567
+ const observed = await this.readRow(base.path, row.resourceId, inventory.header);
2568
+ if (!same(row, observed)) refuse("jsonl/resource-changed", "The physical resource identity or bytes changed after confirmation.");
2569
+ }
2678
2570
  } catch (error) {
2679
- if (error.code === "ENOENT") return true;
2571
+ if (missing(error)) {
2572
+ await this.syncDirectory(base.path);
2573
+ return;
2574
+ }
2680
2575
  throw error;
2681
2576
  }
2682
- }
2683
- async frozenCacheBytes(handle, snapshot, allowCleared) {
2684
- const before = await handle.stat({ bigint: true });
2685
- if (!before.isFile() || before.nlink !== 1n || !samePhysicalIdentity(physicalIdentity(before), snapshot.physicalIdentity)) return false;
2686
- const bytes = await handle.readFile();
2687
- const after = await handle.stat({ bigint: true });
2688
- if (before.dev !== after.dev || before.ino !== after.ino || before.birthtimeNs !== after.birthtimeNs || before.size !== after.size || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs || after.nlink !== 1n) return false;
2689
- return allowCleared && bytes.length === 0 || snapshot.documentDigest !== null && createHash5("sha256").update(bytes).digest("hex") === snapshot.documentDigest;
2690
- }
2691
- async eraseWindowsCache(snapshot, id, expected, request, table) {
2692
- if (snapshot.documentDigest !== null && snapshot.physicalIdentity === void 0) return false;
2693
- if (snapshot.documentDigest === null && snapshot.physicalIdentity !== void 0) return false;
2694
- const tableDirectory = table.host.unit.tableDir("sessions");
2695
- const originalPath = join4(tableDirectory, `${id}.json`);
2696
- const stageName = cacheStageBasename(snapshot, expected, request);
2697
- const stagePath = join4(tableDirectory, stageName);
2698
- const current = await this.cacheView(table, id, stageName);
2699
- if (current.location !== snapshot.location || current.documentDigest !== null && current.documentDigest !== snapshot.documentDigest || current.memoryDigest !== null && current.memoryDigest !== snapshot.memoryDigest || !snapshot.present && current.present) return false;
2700
- let originalAbsent = await this.pathAbsent(originalPath);
2701
- let stageAbsent = await this.pathAbsent(stagePath);
2702
- if (!originalAbsent && !stageAbsent) return false;
2703
- if (!originalAbsent) {
2704
- if (snapshot.physicalIdentity === void 0 || current.documentDigest !== snapshot.documentDigest || !samePhysicalIdentity(current.physicalIdentity, snapshot.physicalIdentity)) return false;
2705
- let handle;
2577
+ await this.assertDirectory(inventory);
2578
+ const latest = fileIdentity(await lstat3(absolute, { bigint: true }));
2579
+ if (remainder ? latest.size !== "0" || !same(nodeIdentity(await lstat3(absolute, { bigint: true })), nodeIdentityFromRow(row)) : !same(latest, row.identity)) refuse("jsonl/resource-changed", "The exact resource changed before erasure.");
2580
+ if (process.platform === "win32") {
2581
+ const handle = await this.openFile(absolute, "write");
2706
2582
  try {
2707
- handle = await this.openCacheDocument(originalPath, "write");
2708
- } catch (error) {
2709
- if (error.code === "ENOENT") return false;
2710
- throw error;
2583
+ const opened = fileIdentity(await handle.stat({ bigint: true }));
2584
+ if (remainder ? opened.size !== "0" || !same(nodeIdentity(await handle.stat({ bigint: true })), nodeIdentityFromRow(row)) : !same(opened, row.identity)) refuse("jsonl/resource-changed", "The opened erasure object differs from the frozen file.");
2585
+ await handle.truncate(0);
2586
+ await handle.sync();
2587
+ } finally {
2588
+ await handle.close();
2711
2589
  }
2712
- try {
2713
- if (!await this.frozenCacheBytes(handle, snapshot, false)) return false;
2590
+ const cleared = await lstat3(absolute, { bigint: true });
2591
+ if (!cleared.isFile() || cleared.nlink !== 1n || cleared.size !== 0n || !same(nodeIdentity(cleared), nodeIdentityFromRow(row))) refuse("jsonl/resource-changed", "The cleared erasure object changed before unlink.");
2592
+ }
2593
+ await unlink(absolute);
2594
+ await this.syncDirectory(base.path);
2595
+ }
2596
+ validate(input) {
2597
+ const value = nativeJsonlInventorySchema.parse(input);
2598
+ if (value.root !== this.root || value.compression !== this.compression || !same(value.rootIdentity, this.rootIdentity) || value.sessionId !== value.header.id || value.directory !== join3(project(value.header.cwd), segment(value.sessionId)) || value.files.some((row) => row.resourceId.includes(sep) || row.resourceId.includes("/") || row.resourceId.includes("\\") || row.resourceId === "session.lock" || !same(row.header, value.header))) refuse("jsonl/binding-invalid", "The inventory is not bound to this adapter and exact directory.");
2599
+ const windowsLock = "kind" in value.lock;
2600
+ if (process.platform === "win32" !== windowsLock || "kind" in value.lock && value.lock.name !== windowsSemaphoreName(join3(this.root, value.directory, "session.lock"), "session")) {
2601
+ refuse("jsonl/binding-invalid", "The inventory kernel lease belongs to another platform or namespace.");
2602
+ }
2603
+ if (new Set(value.files.map((row) => row.resourceId)).size !== value.files.length || value.revision !== sha(JSON.stringify(value.files))) refuse("jsonl/binding-invalid", "The frozen resource inventory digest is invalid.");
2604
+ for (const row of value.files) {
2605
+ const classified = classify(row.resourceId);
2606
+ if (classified.kind !== row.kind || classified.version !== row.formatVersion || classified.compression !== row.compression || row.revision !== sha(JSON.stringify({ identity: row.identity, digest: row.digest, header: row.header }))) refuse("jsonl/binding-invalid", "Frozen resource classification or digest changed.");
2607
+ }
2608
+ return value;
2609
+ }
2610
+ async directory(directory, sessionId, header) {
2611
+ const internals = this.provider;
2612
+ if (await realpath2(internals.root) !== this.root || internals.compression !== this.compression || process.platform === "win32" && resolve2(internals.root).toLowerCase() !== this.root.toLowerCase() || resolve2(this.provider.config.root) !== internals.root || (this.provider.config.compression ?? "zstd") !== this.compression) refuse("jsonl/provider-changed", "The provider root or encoding changed.");
2613
+ const root = await lstat3(this.root, { bigint: true });
2614
+ if (!root.isDirectory() || !same(nodeIdentity(root), this.rootIdentity)) refuse("jsonl/root-changed", "The configured root identity changed.");
2615
+ if (directory !== join3(project(header.cwd), segment(sessionId))) refuse("jsonl/path-invalid", "Directory does not match the stored identity.");
2616
+ const matches = [];
2617
+ for (const entry of await readdir(this.root, { withFileTypes: true })) {
2618
+ const projectPath = join3(this.root, entry.name);
2619
+ if ([`${segment(sessionId)}.jsonl`, `${segment(sessionId)}.jsonl.zstd`].includes(entry.name)) refuse("jsonl/legacy-layout", "Root-level flat session artifacts are not admitted.");
2620
+ if (entry.isSymbolicLink()) refuse("jsonl/unsafe-directory", "Symlink project directories cannot certify a unique target.");
2621
+ if (!entry.isDirectory()) continue;
2622
+ for (const suffix of [".jsonl", ".jsonl.zstd"]) {
2714
2623
  try {
2715
- await this.moveCacheDocument(originalPath, stagePath);
2624
+ await lstat3(join3(projectPath, segment(sessionId) + suffix));
2625
+ refuse("jsonl/legacy-layout", "Flat session artifacts are not admitted.");
2716
2626
  } catch (error) {
2717
- if (["EEXIST", "EXDEV", "ENOENT"].includes(error.code ?? "")) return false;
2718
- throw error;
2627
+ if (!missing(error)) throw error;
2719
2628
  }
2720
- } finally {
2721
- await handle.close();
2722
2629
  }
2723
- originalAbsent = await this.pathAbsent(originalPath);
2724
- stageAbsent = await this.pathAbsent(stagePath);
2725
- if (!originalAbsent || stageAbsent) return false;
2726
- }
2727
- if (!stageAbsent) {
2728
- let handle;
2630
+ const candidate = join3(projectPath, segment(sessionId));
2729
2631
  try {
2730
- handle = await this.openCacheDocument(stagePath, "write");
2632
+ const stat = await lstat3(candidate, { bigint: true });
2633
+ if (!stat.isDirectory()) refuse("jsonl/unsafe-directory", "Session directories must be direct regular directories.");
2634
+ matches.push(candidate);
2731
2635
  } catch (error) {
2732
- if (error.code === "ENOENT") return false;
2733
- throw error;
2734
- }
2735
- try {
2736
- if (!await this.frozenCacheBytes(handle, snapshot, true)) return false;
2737
- await this.clearCacheStage(handle);
2738
- } finally {
2739
- await handle.close();
2636
+ if (!missing(error)) throw error;
2740
2637
  }
2741
- await this.removeCacheStage(stagePath);
2742
- if (!await this.pathAbsent(stagePath)) return false;
2743
2638
  }
2744
- if (!await this.pathAbsent(originalPath) || !await this.pathAbsent(stagePath)) return false;
2745
- table.records.delete(id);
2746
- this.admission.withoutBypass(() => table.host.emitChanged({ domain: table.host.domainName, table: "sessions", key: id, operation: "deleted" }));
2747
- const final = await this.cacheView(table, id, stageName);
2748
- return final.location === snapshot.location && !final.present && await this.pathAbsent(stagePath);
2639
+ const path = join3(this.root, directory);
2640
+ if (matches.length !== 1 || matches[0] !== path) refuse("jsonl/identity-ambiguous", "The session directory is missing, misplaced, or duplicated across projects.");
2641
+ const actual = await realpath2(path);
2642
+ const rel = relative(this.root, actual);
2643
+ if (actual !== path || rel !== directory || rel.startsWith(`..${sep}`) || isAbsolute2(rel)) refuse("jsonl/unsafe-directory", "The session directory leaves the configured root.");
2644
+ return { path, identity: nodeIdentity(await lstat3(path, { bigint: true })) };
2749
2645
  }
2750
- async eraseCache(snapshot, id, expected, request) {
2751
- const table = this.cacheTable;
2752
- if (!table) return !snapshot.present && snapshot.location === null;
2753
- return table.host.enqueue(async () => {
2754
- if (process.platform === "win32") return this.eraseWindowsCache(snapshot, id, expected, request, table);
2755
- const current = await this.cacheView(table, id);
2756
- if (current.location !== snapshot.location || current.documentDigest !== null && current.documentDigest !== snapshot.documentDigest || current.memoryDigest !== null && current.memoryDigest !== snapshot.memoryDigest || !snapshot.present && current.present) return false;
2757
- await table.host.unit.deleteRecord("sessions", id);
2758
- const tableDirectory = table.host.unit.tableDir("sessions");
2759
- try {
2760
- await syncDirectory(tableDirectory);
2761
- } catch (error) {
2762
- if (error.code !== "ENOENT") throw error;
2763
- }
2764
- table.records.delete(id);
2765
- this.admission.withoutBypass(() => table.host.emitChanged({ domain: table.host.domainName, table: "sessions", key: id, operation: "deleted" }));
2766
- const final = await this.cacheView(table, id);
2767
- return final.location === snapshot.location && !final.present;
2768
- });
2646
+ async assertDirectory(inventory) {
2647
+ const base = await this.directory(inventory.directory, inventory.sessionId, inventory.header);
2648
+ if (!same(base.identity, inventory.directoryIdentity)) refuse("jsonl/directory-changed", "The bound directory incarnation changed.");
2649
+ return base;
2769
2650
  }
2770
- async capture(sessionId) {
2771
- return this.admission.bypass(sessionId, () => this.captureInner(sessionId));
2651
+ async lockIdentity(directory) {
2652
+ if (process.platform === "win32") return { kind: "win32-semaphore", name: windowsSemaphoreName(join3(directory, "session.lock"), "session") };
2653
+ return lockIdentity(await lstat3(join3(directory, "session.lock"), { bigint: true }));
2772
2654
  }
2773
- async captureInner(sessionId) {
2774
- this.targets.add(sessionId);
2775
- this.assertInstances();
2776
- this.assertCold(sessionId);
2777
- const activity = await this.admission.withoutBypass(() => this.ctx.waterfall(
2778
- "workspace/session-activity",
2779
- { sessionId },
2780
- async () => []
2781
- ));
2782
- if (activity.length !== 0) this.refuse("native/session-active", "Native deletion refuses active work.");
2783
- this.assertCold(sessionId);
2784
- const domain = this.ctx.storageDomain.get("workspace");
2785
- if (!domain) throw new Error("Native workspace domain is unavailable.");
2786
- const global = workspaceDomainState2.parse(domain.global.get());
2787
- if (!global.archivedSessionIds.some((id) => id === sessionId)) this.refuse("native/not-archived", "Native metadata preparation requires an archived session.");
2788
- const workspaces = [];
2789
- for (const [workspaceId, raw] of this.workspace.requireTable().entries()) {
2790
- const record = workspaceRecord.parse(raw);
2791
- if (!record.sessionIds.some((id) => id === sessionId)) continue;
2792
- if (record.sessionIds.some((id) => id !== sessionId && this.workspace.sessionPaths.get(id) !== record.path)) {
2793
- this.refuse("native/workspace-pruning-required", "Target removal would prune an unrelated Workspace candidate.");
2655
+ async isWindowsErasureRemainder(inventory, row) {
2656
+ const lease = this.leases.get(inventory.directory);
2657
+ if (process.platform !== "win32" || !lease?.recovering || lease.stamp !== leaseStamp(inventory)) return false;
2658
+ try {
2659
+ const handle = await this.openFile(join3(this.root, inventory.directory, row.resourceId), "read");
2660
+ try {
2661
+ const stat = await handle.stat({ bigint: true });
2662
+ return stat.size === 0n && same(nodeIdentity(stat), nodeIdentityFromRow(row));
2663
+ } finally {
2664
+ await handle.close();
2794
2665
  }
2795
- workspaces.push({ workspaceId, record });
2666
+ } catch (error) {
2667
+ if (missing(error)) return false;
2668
+ throw error;
2796
2669
  }
2797
- const cache = this.cacheTable ? await this.cacheTable.host.enqueue(() => this.cacheView(this.cacheTable, sessionId)) : { present: false, digest: null, location: null, documentDigest: null, memoryDigest: null };
2798
- return nativeMetadataSnapshotSchema.parse({
2799
- schemaVersion: 1,
2800
- sessionId,
2801
- global: { archived: global.archivedSessionIds.includes(sessionId), pinned: global.pinnedSessionIds.includes(sessionId) },
2802
- workspaces,
2803
- cache,
2804
- queryProvider: this.queryProvider,
2805
- queryPath: this.queryConfiguration?.path ?? null
2806
- });
2807
2670
  }
2808
- wrap(port, name2, replace) {
2809
- const descriptor2 = Object.getOwnPropertyDescriptor(port, name2);
2810
- const original = port[name2];
2811
- const adapter = this;
2812
- const guarded = replace((...args) => Reflect.apply(original, adapter.receivers.getStore() ?? port, args));
2813
- const replacement = function(...args) {
2814
- if (adapter.detached) throw new NativeMetadataRefusal("native/stale-reference", "Reacquire native methods after retirement adapter takeover.");
2815
- return adapter.receivers.run(this, () => guarded(...args));
2816
- };
2817
- Object.defineProperty(port, name2, { configurable: true, writable: true, value: replacement });
2818
- this.guardedMethods.push({ port, name: name2, replacement });
2819
- this.restores.push(() => {
2820
- if (port[name2] !== replacement) throw new Error(`Native metadata guard ${name2} was replaced before withdrawal.`);
2821
- if (descriptor2) Object.defineProperty(port, name2, descriptor2);
2822
- else delete port[name2];
2823
- });
2671
+ async rows(directory, header, frozen) {
2672
+ const names = (await readdir(directory)).sort();
2673
+ if (names.length > 4097) refuse("jsonl/scope-too-large", "Session scope exceeds the bounded inventory.");
2674
+ const posix = process.platform !== "win32";
2675
+ if (posix && !names.includes("session.lock")) refuse("jsonl/lock-missing", "The existing stable writer lock is required.");
2676
+ const rows = [];
2677
+ for (const name2 of names) {
2678
+ if (posix && name2 === "session.lock") continue;
2679
+ const original = frozen?.files.find((row) => row.resourceId === name2);
2680
+ if (frozen && original && await this.isWindowsErasureRemainder(frozen, original)) rows.push(original);
2681
+ else rows.push(await this.readRow(directory, name2, header));
2682
+ }
2683
+ if (!same(names, (await readdir(directory)).sort())) refuse("jsonl/scope-changed", "The directory changed while enumerating resources.");
2684
+ return rows;
2824
2685
  }
2825
- guardEntity(entity) {
2826
- if (this.guardedEntities.has(entity)) return;
2827
- this.guardedEntities.add(entity);
2828
- this.wrap(entity, "attachSession", (original) => (id) => this.tracked(id, async () => {
2829
- const result = await original(id);
2686
+ async readRow(directory, name2, expected) {
2687
+ const classified = classify(name2);
2688
+ if (classified.compression !== this.compression) refuse("jsonl/encoding-mismatch", "Mixed raw and Zstandard session generations are not admitted.");
2689
+ const path = join3(directory, name2);
2690
+ const before = fileIdentity(await lstat3(path, { bigint: true }));
2691
+ const fd = await this.openFile(path, "read");
2692
+ try {
2693
+ if (!same(before, fileIdentity(await fd.stat({ bigint: true })))) refuse("jsonl/resource-changed", "Resource was replaced before reading.");
2694
+ const digest2 = createHash4("sha256");
2695
+ const chunks = [];
2696
+ let headerBytes = 0;
2697
+ const buffer = Buffer.alloc(64 * 1024);
2698
+ let total = 0n;
2699
+ for (; ; ) {
2700
+ const { bytesRead } = await fd.read(buffer, 0, buffer.length, null);
2701
+ if (!bytesRead) break;
2702
+ total += BigInt(bytesRead);
2703
+ digest2.update(buffer.subarray(0, bytesRead));
2704
+ if (headerBytes < HEADER_LIMIT) {
2705
+ const chunk = Buffer.from(buffer.subarray(0, Math.min(bytesRead, HEADER_LIMIT - headerBytes)));
2706
+ chunks.push(chunk);
2707
+ headerBytes += chunk.length;
2708
+ }
2709
+ }
2710
+ if (String(total) !== before.size || !same(before, fileIdentity(await fd.stat({ bigint: true }))) || !same(before, fileIdentity(await lstat3(path, { bigint: true })))) refuse("jsonl/resource-changed", "The resource changed while hashing its exact bytes.");
2711
+ const header = decodeHeader(Buffer.concat(chunks), classified.compression, classified.version);
2712
+ if (!same(header, expected)) refuse("jsonl/identity-changed", "A physical generation or staging header belongs to another lifecycle.");
2713
+ const value = {
2714
+ resourceId: name2,
2715
+ kind: classified.kind,
2716
+ formatVersion: classified.version,
2717
+ compression: classified.compression,
2718
+ identity: before,
2719
+ digest: digest2.digest("hex"),
2720
+ header
2721
+ };
2722
+ return fileRowSchema.parse({ ...value, revision: sha(JSON.stringify({ identity: value.identity, digest: value.digest, header })) });
2723
+ } finally {
2724
+ await fd.close();
2725
+ }
2726
+ }
2727
+ async openFile(path, access) {
2728
+ try {
2729
+ return await openRegularFile(path, access);
2730
+ } catch (error) {
2731
+ if (error instanceof RegularFileRefusal) refuse(error.code === "platform/unsafe-file" ? "jsonl/unsafe-file" : error.code === "platform/identity-unavailable" ? "jsonl/identity-unavailable" : "jsonl/resource-changed", error.message);
2732
+ throw error;
2733
+ }
2734
+ }
2735
+ async syncDirectory(directory) {
2736
+ await syncDirectory(directory);
2737
+ }
2738
+ };
2739
+
2740
+ // src/host/native-retirement-metadata.ts
2741
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
2742
+ import { createHash as createHash5 } from "node:crypto";
2743
+ import { readdir as readdir2, realpath as realpath3, lstat as lstat4, unlink as unlink2 } from "node:fs/promises";
2744
+ import { dirname as dirname2, join as join4, resolve as resolve3 } from "node:path";
2745
+ import { workspaceDomainState as workspaceDomainState2, workspaceRecord } from "@deepseek-ai/dsh-workspace";
2746
+ import { z as z5 } from "zod";
2747
+ var NativeMetadataRefusal = class extends Error {
2748
+ constructor(code, message) {
2749
+ super(message);
2750
+ this.code = code;
2751
+ this.name = "NativeMetadataRefusal";
2752
+ }
2753
+ };
2754
+ var cachePhysicalIdentitySchema = z5.object({
2755
+ dev: z5.string().regex(/^\d+$/),
2756
+ ino: z5.string().regex(/^[1-9]\d*$/),
2757
+ birthtimeNs: z5.string().regex(/^[1-9]\d*$/)
2758
+ }).strict();
2759
+ var nativeMetadataSnapshotSchema = z5.object({
2760
+ schemaVersion: z5.literal(1),
2761
+ sessionId: z5.string().min(1),
2762
+ global: z5.object({ archived: z5.boolean(), pinned: z5.boolean() }).strict(),
2763
+ workspaces: z5.array(z5.object({ workspaceId: z5.string(), record: workspaceRecord }).strict()),
2764
+ cache: z5.object({
2765
+ present: z5.boolean(),
2766
+ digest: z5.string().nullable(),
2767
+ location: z5.string().nullable(),
2768
+ documentDigest: z5.string().nullable(),
2769
+ memoryDigest: z5.string().nullable(),
2770
+ physicalIdentity: cachePhysicalIdentitySchema.optional()
2771
+ }).strict(),
2772
+ queryProvider: z5.enum(["none", "sqlite-0.2.0-rc.2", "sqlite-memory-disabled-0.2.0-rc.2"]),
2773
+ queryPath: z5.string().nullable()
2774
+ }).strict();
2775
+ function object(value) {
2776
+ return value !== null && typeof value === "object" ? value : void 0;
2777
+ }
2778
+ function canonical2(value) {
2779
+ if (Array.isArray(value)) return `[${value.map(canonical2).join(",")}]`;
2780
+ if (value !== null && typeof value === "object") return `{${Object.keys(value).sort().map((key2) => `${JSON.stringify(key2)}:${canonical2(value[key2])}`).join(",")}}`;
2781
+ return JSON.stringify(value);
2782
+ }
2783
+ function digest(value) {
2784
+ return createHash5("sha256").update(canonical2(value)).digest("hex");
2785
+ }
2786
+ var methods = (port, names) => names.every((name2) => typeof port[name2] === "function");
2787
+ var windowsCacheStagePrefix = ".dsh-session-bin-cache-";
2788
+ function physicalIdentity(stat) {
2789
+ return { dev: String(stat.dev), ino: String(stat.ino), birthtimeNs: String(stat.birthtimeNs) };
2790
+ }
2791
+ function samePhysicalIdentity(left, right) {
2792
+ return left !== void 0 && right !== void 0 && left.dev === right.dev && left.ino === right.ino && left.birthtimeNs === right.birthtimeNs;
2793
+ }
2794
+ function cacheStageBasename(snapshot, expected, request) {
2795
+ const value = digest({ schemaVersion: 1, expected, request, cache: snapshot });
2796
+ return `${windowsCacheStagePrefix}${value}.stage`;
2797
+ }
2798
+ var NativeMetadataAdapter = class _NativeMetadataAdapter {
2799
+ constructor(ctx, admission, workspace, sessions, cache, query, controller) {
2800
+ this.ctx = ctx;
2801
+ this.admission = admission;
2802
+ this.workspace = workspace;
2803
+ this.sessions = sessions;
2804
+ this.cache = cache;
2805
+ this.query = query;
2806
+ this.controller = controller;
2807
+ this.queryConfiguration = query ? { path: query.config.path, openAt: query.config.openAt } : void 0;
2808
+ this.queryProvider = !query ? "none" : query.config.openAt === "never" ? "sqlite-memory-disabled-0.2.0-rc.2" : "sqlite-0.2.0-rc.2";
2809
+ this.cacheTable = cache?.requireTable();
2810
+ this.cacheDirectory = this.cacheTable?.host.unit.dir;
2811
+ this.agents = controller ? _NativeMetadataAdapter.get(ctx, "agents") : void 0;
2812
+ }
2813
+ targets = /* @__PURE__ */ new Set();
2814
+ retained = /* @__PURE__ */ new Map();
2815
+ followers = /* @__PURE__ */ new Map();
2816
+ followerStops = /* @__PURE__ */ new Map();
2817
+ activationTarget = new AsyncLocalStorage2();
2818
+ apiHandles = /* @__PURE__ */ new Map();
2819
+ operations = /* @__PURE__ */ new Map();
2820
+ queueTarget = new AsyncLocalStorage2();
2821
+ receivers = new AsyncLocalStorage2();
2822
+ restores = [];
2823
+ guardedMethods = [];
2824
+ guardedEntities = /* @__PURE__ */ new WeakSet();
2825
+ installed = false;
2826
+ disposed = false;
2827
+ detached = false;
2828
+ fallbackRetired = /* @__PURE__ */ new Set();
2829
+ queryConfiguration;
2830
+ queryProvider;
2831
+ cacheTable;
2832
+ cacheDirectory;
2833
+ agents;
2834
+ moveCacheDocument = renameWindowsWriteThrough;
2835
+ clearCacheStage = async (handle) => {
2836
+ await handle.truncate(0);
2837
+ await handle.sync();
2838
+ };
2839
+ removeCacheStage = unlink2;
2840
+ static get(ctx, name2) {
2841
+ const value = object(ctx.get(name2));
2842
+ return object(value?.[Symbol.for("cordis.original")] ?? value);
2843
+ }
2844
+ static async open(ctx, admission) {
2845
+ const workspace = this.get(ctx, "workspaceRegistry");
2846
+ const sessions = this.get(ctx, "sessions");
2847
+ const cache = this.get(ctx, "sessionProjectionCache");
2848
+ const query = this.get(ctx, "sessionQuery");
2849
+ const controller = this.get(ctx, "sessionController");
2850
+ if (!workspace || !sessions || workspace.constructor.name !== "WorkspaceRegistry" || sessions.constructor.name !== "SessionStore" || !methods(workspace, ["list", "requireTable", "requireState", "setState", "enqueueOperation", "indexHeader", "readSessionHeader"]) || ![workspace.headers, workspace.sessionPaths, workspace.invalidSessionPaths].every((map) => map instanceof Map) || !(workspace.missingSessionPaths instanceof Set) || !methods(sessions, ["get", "prepare", "enter", "announce"])) return void 0;
2851
+ if (cache && (cache.constructor.name !== "SessionProjectionCache" || !(cache.dirty instanceof Map) || !methods(cache, ["put", "requireTable", "write", "coldSnapshot", "hydratePrepared", "cachedSnapshot", "cachedPredecessorTitle"]))) return void 0;
2852
+ if (cache) {
2853
+ const table = cache.requireTable();
2854
+ const domain = ctx.storageDomain.get("session_projcache");
2855
+ if (table?.constructor.name !== "KvTableImpl" || table.tableName !== "sessions" || !(table.records instanceof Map) || table.host?.domainName !== "session_projcache" || table.host.unit?.constructor.name !== "PerRecordJsonUnit" || table.host.unit.descriptor?.name !== "session_projcache" || table.host.unit.descriptor.version !== 7 || table.host.unit.descriptor.layout !== "per-record" || typeof table.host.unit.dir !== "string" || !methods(table.host, ["enqueue", "emitChanged", "assertReadable"]) || !methods(table.host.unit, ["loadAll", "deleteRecord", "tableDir"]) || domain?.unit !== table.host.unit) return void 0;
2856
+ }
2857
+ if (query) {
2858
+ const enabled = ["startup", "first-search"].includes(query.config?.openAt);
2859
+ const disabledMemory = query.config?.openAt === "never" && query.config.path === ":memory:" && query._db === void 0 && query._ready === void 0;
2860
+ if (query.constructor.name !== "SqliteSessionQueryEngine" || !enabled && !disabledMemory || typeof query.config?.path !== "string" || !methods(query, ["searchSessions", "listSessions", "observeSession", "_serialized"]) || !(query._observations?.cache instanceof Map) || !methods(query._observations, ["read", "store"])) return void 0;
2861
+ }
2862
+ if (controller && (controller.constructor.name !== "SessionController" || !(controller.history?.closeFollowers instanceof Set) || !methods(controller.history, ["page", "follow", "sourceFor"]) || controller.agents?.constructor.name !== "ApiSessionAgentController" || !methods(controller.agents, ["resumeObserved", "claim", "createAgent"]) || !methods(controller.listState ?? {}, ["summarizeCold"]) || !methods(this.get(ctx, "agents") ?? {}, ["create", "resume", "get"]))) return void 0;
2863
+ return new _NativeMetadataAdapter(ctx, admission, workspace, sessions, cache, query, controller);
2864
+ }
2865
+ assert(id) {
2866
+ this.targets.add(id);
2867
+ if (this.disposed) {
2868
+ if (this.fallbackRetired.has(id)) throw new NativeMetadataRefusal("native/retired", "This retired session remains fenced after adapter withdrawal.");
2869
+ return;
2870
+ }
2871
+ this.admission.assertAllowed(id);
2872
+ }
2873
+ tracked(id, work) {
2874
+ this.targets.add(id);
2875
+ if (this.disposed) {
2830
2876
  this.assert(id);
2831
- return result;
2877
+ return work();
2878
+ }
2879
+ return this.admission.trackGlobal(() => this.admission.track(id, async () => {
2880
+ this.assert(id);
2881
+ this.increment(this.operations, id, 1);
2882
+ try {
2883
+ return await work();
2884
+ } finally {
2885
+ this.increment(this.operations, id, -1);
2886
+ }
2832
2887
  }));
2833
2888
  }
2834
- guardedObservation(id, observation) {
2835
- this.increment(this.retained, id, 1);
2836
- let disposed = false;
2837
- return new Proxy(observation, { get: (target, property) => {
2838
- if (property === Symbol.dispose) return () => {
2839
- if (disposed) return;
2840
- disposed = true;
2841
- try {
2842
- target[Symbol.dispose]();
2843
- } finally {
2844
- this.increment(this.retained, id, -1);
2845
- }
2846
- };
2847
- if (property === "retain") return () => {
2848
- this.assert(id);
2849
- return this.guardedObservation(id, target.retain());
2850
- };
2851
- if (property === "events" || property === "projections") this.assert(id);
2852
- return Reflect.get(target, property, target);
2853
- } });
2889
+ increment(map, id, delta) {
2890
+ const next = (map.get(id) ?? 0) + delta;
2891
+ if (next === 0) map.delete(id);
2892
+ else map.set(id, next);
2854
2893
  }
2855
- async install() {
2856
- if (this.installed) throw new Error("Native metadata adapter is already installed.");
2894
+ refuse(code, message) {
2895
+ throw new NativeMetadataRefusal(code, message);
2896
+ }
2897
+ assertInstances() {
2898
+ if (this.guardedMethods.some(({ port, name: name2, replacement }) => port[name2] !== replacement)) {
2899
+ this.refuse("native/guard-replaced", "A native metadata admission guard was replaced.");
2900
+ }
2901
+ if (_NativeMetadataAdapter.get(this.ctx, "workspaceRegistry") !== this.workspace || _NativeMetadataAdapter.get(this.ctx, "sessions") !== this.sessions || _NativeMetadataAdapter.get(this.ctx, "sessionProjectionCache") !== this.cache || _NativeMetadataAdapter.get(this.ctx, "sessionQuery") !== this.query || _NativeMetadataAdapter.get(this.ctx, "sessionController") !== this.controller || this.controller && _NativeMetadataAdapter.get(this.ctx, "agents") !== this.agents || this.cache && (this.cache.requireTable() !== this.cacheTable || this.cacheTable.host.unit.dir !== this.cacheDirectory) || this.query && (this.query.config.path !== this.queryConfiguration.path || this.query.config.openAt !== this.queryConfiguration.openAt) || this.queryProvider === "sqlite-memory-disabled-0.2.0-rc.2" && (this.query._db !== void 0 || this.query._ready !== void 0)) {
2902
+ this.refuse("native/composition-changed", "Native metadata service composition changed.");
2903
+ }
2904
+ }
2905
+ assertCold(id) {
2906
+ if (this.sessions.get(id) !== void 0 || _NativeMetadataAdapter.get(this.ctx, "agents")?.get(id) !== void 0) {
2907
+ this.refuse("native/session-live", "Native deletion currently accepts only cold sessions.");
2908
+ }
2909
+ const cached = this.query?._observations.cache.get(id);
2910
+ if (cached?.refs > 0 || (this.retained.get(id) ?? 0) > 0) this.refuse("native/query-retained", "A retained query observation still owns this session.");
2911
+ if ((this.followers.get(id) ?? 0) > 0) this.refuse("native/follow-retained", "A history follower still owns this session.");
2912
+ const knownFollowers = [...this.followers.values()].reduce((sum, count) => sum + count, 0);
2913
+ if ((this.controller?.history.closeFollowers.size ?? 0) > knownFollowers) this.refuse("native/unknown-follow", "A history follower predates native admission tracking.");
2914
+ if (this.cache && [...this.cache.dirty.keys()].some((session) => session.id === id)) this.refuse("native/cache-dirty", "Target cache write-behind is not quiescent.");
2915
+ }
2916
+ /** Explicit deletion preparation may unload an idle API-owned lifecycle.
2917
+ * No bare registry Agent, foreign handle, or unknown reader is disposed. */
2918
+ async releaseIdle(id) {
2857
2919
  this.assertInstances();
2858
- this.installed = true;
2920
+ const handle = this.apiHandles.get(id);
2921
+ if (!handle) return;
2922
+ const agent = handle.agent;
2923
+ const registry = this.agents;
2924
+ if (registry.get(id) !== agent || this.sessions.get(id) !== agent.session) return;
2925
+ const activity = await this.admission.withoutBypass(() => this.ctx.waterfall(
2926
+ "workspace/session-activity",
2927
+ { sessionId: id },
2928
+ async () => []
2929
+ ));
2930
+ if (activity.length || agent.constructor.name !== "ReactLoopAgent" || agent.phase?.kind !== "idle" || agent.status !== "idle" || !Array.isArray(agent.inbox?.nextTurn) || !Array.isArray(agent.inbox?.nextStep) || agent.inbox.nextTurn.length || agent.inbox.nextStep.length) {
2931
+ this.refuse("native/session-active", "Native deletion refuses active or queued work.");
2932
+ }
2933
+ if (!this.workspace.archivedSessionIds.includes(id)) this.refuse("native/not-archived", "Only an archived target may be unloaded.");
2934
+ if (registry.get(id) !== agent || this.sessions.get(id) !== agent.session) this.refuse("native/session-live", "The API lifecycle changed.");
2935
+ await this.admission.bypass(id, async () => {
2936
+ await handle.dispose();
2937
+ for (const stop of [...this.followerStops.get(id) ?? []]) await stop();
2938
+ if (this.cache) await this.cache.requireTable().host.enqueue(async () => void 0);
2939
+ const summary = this.controller.listState.summarizeCold({ header: agent.session.header });
2940
+ this.admission.withoutBypass(() => this.ctx.emit("api-session/added", summary));
2941
+ });
2942
+ this.apiHandles.delete(id);
2943
+ }
2944
+ async cacheView(table, id, acceptedStage) {
2945
+ table.host.assertReadable();
2946
+ if (!/^[a-zA-Z0-9_-]+$/.test(id)) this.refuse("native/cache-key-unsupported", "The pinned cache backend cannot own this record key.");
2947
+ const directory = resolve3(table.host.unit.dir);
2948
+ const legacyPath = join4(dirname2(directory), `${table.host.unit.descriptor.name}.json`);
2859
2949
  try {
2860
- for (const name2 of ["workspace", ...this.cache ? ["session_projcache"] : []]) {
2861
- const domain = this.ctx.storageDomain.get(name2);
2862
- if (!domain || domain.constructor.name !== "DomainImpl" || !methods(domain, ["emitChanged"])) {
2863
- throw new Error("Native metadata domain publication shape changed.");
2864
- }
2865
- this.wrap(domain, "emitChanged", (original) => (change) => this.admission.withoutBypass(() => original(change)));
2866
- }
2867
- for (const name2 of ["archiveSession", "unarchiveSession", "pinSession", "unpinSession"]) {
2868
- this.wrap(this.workspace, name2, (original) => (id, ...args) => this.tracked(
2869
- id,
2870
- () => this.queueTarget.run(id, async () => original(id, ...args))
2871
- ));
2872
- }
2873
- this.wrap(this.workspace, "enqueueOperation", (original) => (operation) => {
2874
- const id = this.queueTarget.getStore();
2875
- return original(async () => {
2876
- if (id !== void 0) this.assert(id);
2877
- return operation();
2878
- });
2879
- });
2880
- this.wrap(this.workspace, "setState", (original) => async (next) => {
2881
- const id = this.queueTarget.getStore();
2882
- if (id !== void 0) this.assert(id);
2883
- return original(next);
2884
- });
2885
- this.wrap(this.workspace, "indexHeader", (original) => (header) => this.tracked(header.id, async () => {
2886
- const result = await original(header);
2887
- this.assert(header.id);
2888
- return result;
2889
- }));
2890
- this.wrap(this.workspace, "readSessionHeader", (original) => (id) => this.tracked(id, async () => {
2891
- const result = await original(id);
2892
- this.assert(id);
2893
- return result;
2894
- }));
2895
- for (const entity of this.workspace.list()) this.guardEntity(entity);
2896
- for (const name2 of ["create", "initializeDefault"]) this.wrap(this.workspace, name2, (original) => async (...args) => {
2897
- const entity = await original(...args);
2898
- if (entity) this.guardEntity(entity);
2899
- return entity;
2900
- });
2901
- this.wrap(this.sessions, "prepare", (original) => (id, ...args) => {
2902
- if (id !== void 0) this.assert(id);
2903
- const session = original(id, ...args);
2904
- this.assert(session.id);
2905
- return session;
2906
- });
2907
- for (const name2 of ["enter", "announce"]) this.wrap(this.sessions, name2, (original) => (session) => {
2908
- this.assert(session.id);
2909
- return original(session);
2910
- });
2911
- if (this.cache) {
2912
- this.wrap(this.cache, "put", (original) => (id, ...args) => this.tracked(id, async () => original(id, ...args)));
2913
- for (const name2 of ["cachedSnapshot", "cachedPredecessorTitle", "coldSnapshot"]) this.wrap(
2914
- this.cache,
2915
- name2,
2916
- (original) => (header, ...args) => {
2917
- this.assert(header.id);
2918
- return original(header, ...args);
2919
- }
2920
- );
2921
- this.wrap(this.cache, "hydratePrepared", (original) => (session, ...args) => {
2922
- this.assert(session.id);
2923
- return original(session, ...args);
2924
- });
2925
- }
2926
- if (this.query) {
2927
- this.wrap(this.query, "_serialized", (original) => (signal, operation) => this.admission.trackGlobal(async () => original(signal, operation)));
2928
- this.wrap(this.query._observations, "read", (original) => (id, ...args) => this.tracked(id, async () => {
2929
- const observation = await original(id, ...args);
2930
- try {
2931
- this.assert(id);
2932
- return this.guardedObservation(id, observation);
2933
- } catch (error) {
2934
- observation[Symbol.dispose]();
2935
- throw error;
2936
- }
2937
- }));
2938
- this.wrap(this.query._observations, "store", (original) => (id, ...args) => {
2939
- this.assert(id);
2940
- return original(id, ...args);
2941
- });
2942
- for (const name2 of ["readSession", "readTitle", "readTitleSnapshot", "listEvents", "filterEvents", "readSurface", "traceSession"]) {
2943
- if (typeof this.query[name2] === "function") this.wrap(this.query, name2, (original) => (id, ...args) => this.tracked(id, async () => {
2944
- const result = await original(id, ...args);
2945
- this.assert(id);
2946
- return result;
2947
- }));
2948
- }
2949
- for (const name2 of ["searchEvents", "readEvent", "traceEvent"]) if (typeof this.query[name2] === "function") {
2950
- this.wrap(this.query, name2, (original) => (request, ...args) => this.tracked(
2951
- request.sessionId,
2952
- async () => {
2953
- const result = await original(request, ...args);
2954
- this.assert(request.sessionId);
2955
- return result;
2956
- }
2957
- ));
2958
- }
2959
- }
2960
- if (this.controller) {
2961
- const adapter = this;
2962
- for (const name2 of ["resumeObserved", "createOrAdopt"]) {
2963
- this.wrap(this.controller.agents, name2, (original) => (id, ...args) => this.tracked(id, () => this.activationTarget.run(id, async () => original(id, ...args))));
2964
- }
2965
- const agents = this.agents;
2966
- for (const name2 of ["create", "resume"]) {
2967
- this.wrap(agents, name2, (original) => (options, ...args) => {
2968
- const id = String(name2 === "create" ? options.sessionId : options.resumeSessionId);
2969
- return this.tracked(id, async () => {
2970
- const handle = await original(options, ...args);
2971
- if (this.activationTarget.getStore() === id && options.parentAgent === void 0 && handle.agent.id === id && handle.agent.session.header.origin !== "subagent" && typeof handle.dispose === "function") this.apiHandles.set(id, handle);
2972
- return handle;
2973
- });
2974
- });
2975
- }
2976
- this.restores.push(this.ctx.on("agent/disposed", ({ agent }) => {
2977
- if (this.apiHandles.get(agent.id)?.agent === agent) this.apiHandles.delete(agent.id);
2978
- }, { global: true }));
2979
- this.wrap(this.controller.history, "follow", (original) => function(request, signal) {
2980
- const id = String(request.address.sessionId);
2981
- adapter.assert(id);
2982
- return (async function* () {
2983
- adapter.assert(id);
2984
- adapter.increment(adapter.followers, id, 1);
2985
- const cancellation = new AbortController();
2986
- const iterator = original(request, AbortSignal.any([signal, cancellation.signal]));
2987
- const stops = adapter.followerStops.get(id) ?? /* @__PURE__ */ new Set();
2988
- adapter.followerStops.set(id, stops);
2989
- let finished = false;
2990
- const finish = () => {
2991
- if (finished) return;
2992
- finished = true;
2993
- adapter.increment(adapter.followers, id, -1);
2994
- stops.delete(stop);
2995
- if (!stops.size) adapter.followerStops.delete(id);
2996
- };
2997
- const stop = async () => {
2998
- cancellation.abort();
2999
- await iterator.return();
3000
- finish();
3001
- };
3002
- stops.add(stop);
3003
- try {
3004
- for await (const frame of iterator) {
3005
- adapter.assert(id);
3006
- yield frame;
3007
- }
3008
- } finally {
3009
- finish();
3010
- }
3011
- })();
3012
- });
3013
- }
2950
+ await lstat4(legacyPath);
2951
+ this.refuse("native/cache-unclassified-resource", "A legacy whole-unit cache could republish the retired target document.");
2952
+ } catch (error) {
2953
+ if (error.code !== "ENOENT") throw error;
2954
+ }
2955
+ let location;
2956
+ try {
2957
+ location = await realpath3(directory);
3014
2958
  } catch (error) {
3015
- for (const restore of [...this.restores].reverse()) restore();
3016
- this.restores.length = 0;
3017
- this.installed = false;
3018
- throw error;
2959
+ if (error.code !== "ENOENT") throw error;
2960
+ location = join4(await realpath3(dirname2(directory)), "session_projcache");
3019
2961
  }
3020
- let closing;
3021
- return () => closing ??= (async () => {
3022
- this.fallbackRetired = new Set([...this.targets].filter((id) => this.admission.isRetired(id)));
3023
- this.disposed = true;
3024
- this.apiHandles.clear();
3025
- if (this.fallbackRetired.size === 0) {
3026
- for (const restore of [...this.restores].reverse()) restore();
3027
- this.restores.length = 0;
3028
- }
3029
- })();
3030
- }
3031
- /** The verified owner completes all asynchronous takeover work before this
3032
- * synchronous restoration and installs its successor guards without yielding. */
3033
- forceRestore() {
3034
- if (this.restores.length && this.guardedMethods.some(({ port, name: name2, replacement }) => port[name2] !== replacement)) {
3035
- throw new Error("Native metadata guards changed before trusted takeover.");
2962
+ const tableDirectory = table.host.unit.tableDir("sessions");
2963
+ let names;
2964
+ try {
2965
+ names = await readdir2(tableDirectory);
2966
+ } catch (error) {
2967
+ if (error.code !== "ENOENT") throw error;
2968
+ names = [];
3036
2969
  }
3037
- this.detached = true;
3038
- this.disposed = true;
3039
- for (const restore of [...this.restores].reverse()) restore();
3040
- this.restores.length = 0;
3041
- this.guardedMethods.length = 0;
3042
- this.fallbackRetired.clear();
3043
- this.apiHandles.clear();
3044
- }
3045
- async converge(input, expected, request) {
3046
- const snapshot = nativeMetadataSnapshotSchema.parse(input);
3047
- const id = snapshot.sessionId;
3048
- this.targets.add(id);
3049
- this.assertInstances();
3050
- if (snapshot.queryProvider !== this.queryProvider || snapshot.queryPath !== (this.queryConfiguration?.path ?? null)) return false;
3051
- if (id !== expected.sessionId || id !== request.expected.sessionId || expected.storeId !== request.expected.storeId || expected.lifecycleId !== request.expected.lifecycleId || !this.admission.isRetired(id)) {
3052
- this.refuse("native/maintenance-binding-changed", "Native convergence requires the exact durable retirement binding.");
2970
+ if (names.some((name2) => name2.startsWith(`${id}.json.bak.`) || /^\.[a-f0-9-]+\.tmp$/.test(name2) || name2.startsWith(windowsCacheStagePrefix) && name2 !== acceptedStage)) {
2971
+ this.refuse("native/cache-unclassified-resource", "A cache backup or unclassified staging document prevents complete target erasure.");
3053
2972
  }
3054
- if ((this.operations.get(id) ?? 0) > 0 || (this.retained.get(id) ?? 0) > 0 || (this.followers.get(id) ?? 0) > 0) return false;
3055
- this.assertCold(id);
3056
- return this.admission.bypass(id, async () => {
3057
- if (!await this.eraseCache(snapshot.cache, id, expected, request)) return false;
3058
- this.query?._observations.cache.delete(id);
3059
- const frozenIds = new Set(snapshot.workspaces.map((item) => item.workspaceId));
3060
- const convergeWorkspace = async () => {
3061
- for (const [workspaceId, raw] of this.workspace.requireTable().entries()) {
3062
- const record = workspaceRecord.parse(raw);
3063
- if (!record.sessionIds.some((sessionId) => sessionId === id)) continue;
3064
- if (!frozenIds.has(workspaceId) || record.sessionIds.some((other) => other !== id && this.workspace.sessionPaths.get(other) !== record.path)) return false;
3065
- const entity = this.workspace.get(workspaceId);
3066
- if (!entity) throw new Error("Native Workspace account lost its runtime entity.");
3067
- await entity.detachSession(id);
3068
- }
3069
- const state = workspaceDomainState2.parse(this.workspace.requireState());
3070
- if (state.archivedSessionIds.includes(id) || state.pinnedSessionIds.includes(id)) {
3071
- await this.workspace.setState({
3072
- ...state,
3073
- archivedSessionIds: state.archivedSessionIds.filter((other) => other !== id),
3074
- pinnedSessionIds: state.pinnedSessionIds.filter((other) => other !== id)
3075
- });
3076
- }
3077
- this.workspace.headers.delete(id);
3078
- this.workspace.sessionPaths.delete(id);
3079
- this.workspace.invalidSessionPaths.delete(id);
3080
- return true;
3081
- };
3082
- if (!await this.workspace.enqueueOperation(convergeWorkspace)) return false;
3083
- if (this.query) {
3084
- if (this.queryProvider === "sqlite-0.2.0-rc.2") {
3085
- await this.query.searchSessions({ query: "native-retirement-reconciliation", limit: 1 });
2973
+ let documentDigest = null;
2974
+ let documentIdentity;
2975
+ const path = join4(tableDirectory, `${id}.json`);
2976
+ try {
2977
+ let handle;
2978
+ try {
2979
+ handle = await openRegularFile(path, "read");
2980
+ } catch (error) {
2981
+ if (error instanceof RegularFileRefusal) this.refuse(error.code === "platform/unsafe-file" ? "native/cache-unsafe-document" : "native/cache-document-changed", error.message);
2982
+ throw error;
2983
+ }
2984
+ try {
2985
+ const before = await handle.stat({ bigint: true });
2986
+ const bytes = await handle.readFile();
2987
+ const after = await handle.stat({ bigint: true });
2988
+ const current = await lstat4(path, { bigint: true });
2989
+ if (!current.isFile() || before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.birthtimeNs !== after.birthtimeNs || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs || after.nlink !== 1n || after.dev !== current.dev || after.ino !== current.ino || after.birthtimeNs !== current.birthtimeNs || after.size !== current.size || after.mtimeNs !== current.mtimeNs || after.ctimeNs !== current.ctimeNs) {
2990
+ this.refuse("native/cache-document-changed", "The physical cache document changed while observing its bytes.");
3086
2991
  }
3087
- if ((await this.query.listSessions()).some((record) => record.header.id === id)) return false;
3088
- this.assertInstances();
2992
+ documentDigest = createHash5("sha256").update(bytes).digest("hex");
2993
+ if (process.platform === "win32") documentIdentity = physicalIdentity(after);
2994
+ } finally {
2995
+ await handle.close();
3089
2996
  }
3090
- this.admission.withoutBypass(() => this.ctx.emit("api-session/removed", id));
3091
- return true;
3092
- });
3093
- }
3094
- };
3095
-
3096
- // src/host/native-retirement-admission.ts
3097
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
3098
- var NativeAdmissionError = class extends Error {
3099
- code = "native/session-busy";
3100
- };
3101
- var NativeAdmission = class {
3102
- maintenance = new AsyncLocalStorage2();
3103
- acceptedFrames = new AsyncLocalStorage2();
3104
- activeAcceptedFrames = /* @__PURE__ */ new Set();
3105
- held = /* @__PURE__ */ new Set();
3106
- released = /* @__PURE__ */ new Map();
3107
- pending = /* @__PURE__ */ new Map();
3108
- globalReads = /* @__PURE__ */ new Set();
3109
- retired = /* @__PURE__ */ new Set();
3110
- candidates = /* @__PURE__ */ new Set();
3111
- closing = false;
3112
- failed = false;
3113
- ready = false;
3114
- requiresRecovery() {
3115
- return this.failed;
3116
- }
3117
- activate() {
3118
- this.ready = true;
3119
- }
3120
- suspend() {
3121
- this.failed = true;
2997
+ } catch (error) {
2998
+ if (error.code !== "ENOENT") throw error;
2999
+ }
3000
+ const memory = table.records.get(id);
3001
+ const memoryDigest = memory === void 0 ? null : digest(memory);
3002
+ const present = documentDigest !== null || memoryDigest !== null;
3003
+ return {
3004
+ present,
3005
+ digest: present ? digest({ documentDigest, memoryDigest }) : null,
3006
+ location,
3007
+ documentDigest,
3008
+ memoryDigest,
3009
+ ...documentIdentity ? { physicalIdentity: documentIdentity } : {}
3010
+ };
3122
3011
  }
3123
- beginClose() {
3124
- this.closing = true;
3012
+ async openCacheDocument(path, access) {
3013
+ try {
3014
+ return await openRegularFile(path, access);
3015
+ } catch (error) {
3016
+ if (error instanceof RegularFileRefusal) this.refuse(error.code === "platform/unsafe-file" ? "native/cache-unsafe-document" : "native/cache-document-changed", error.message);
3017
+ throw error;
3018
+ }
3125
3019
  }
3126
- isRetired(id) {
3127
- return this.retired.has(id) || this.failed && this.candidates.has(id);
3020
+ async pathAbsent(path) {
3021
+ try {
3022
+ await lstat4(path);
3023
+ return false;
3024
+ } catch (error) {
3025
+ if (error.code === "ENOENT") return true;
3026
+ throw error;
3027
+ }
3128
3028
  }
3129
- hasTombstones() {
3130
- return this.retired.size > 0 || this.failed && this.candidates.size > 0;
3029
+ async frozenCacheBytes(handle, snapshot, allowCleared) {
3030
+ const before = await handle.stat({ bigint: true });
3031
+ if (!before.isFile() || before.nlink !== 1n || !samePhysicalIdentity(physicalIdentity(before), snapshot.physicalIdentity)) return false;
3032
+ const bytes = await handle.readFile();
3033
+ const after = await handle.stat({ bigint: true });
3034
+ if (before.dev !== after.dev || before.ino !== after.ino || before.birthtimeNs !== after.birthtimeNs || before.size !== after.size || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs || after.nlink !== 1n) return false;
3035
+ return allowCleared && bytes.length === 0 || snapshot.documentDigest !== null && createHash5("sha256").update(bytes).digest("hex") === snapshot.documentDigest;
3131
3036
  }
3132
- markRetired(id) {
3133
- this.retired.add(id);
3037
+ async eraseWindowsCache(snapshot, id, expected, request, table) {
3038
+ if (snapshot.documentDigest !== null && snapshot.physicalIdentity === void 0) return false;
3039
+ if (snapshot.documentDigest === null && snapshot.physicalIdentity !== void 0) return false;
3040
+ const tableDirectory = table.host.unit.tableDir("sessions");
3041
+ const originalPath = join4(tableDirectory, `${id}.json`);
3042
+ const stageName = cacheStageBasename(snapshot, expected, request);
3043
+ const stagePath = join4(tableDirectory, stageName);
3044
+ const current = await this.cacheView(table, id, stageName);
3045
+ if (current.location !== snapshot.location || current.documentDigest !== null && current.documentDigest !== snapshot.documentDigest || current.memoryDigest !== null && current.memoryDigest !== snapshot.memoryDigest || !snapshot.present && current.present) return false;
3046
+ let originalAbsent = await this.pathAbsent(originalPath);
3047
+ let stageAbsent = await this.pathAbsent(stagePath);
3048
+ if (!originalAbsent && !stageAbsent) return false;
3049
+ if (!originalAbsent) {
3050
+ if (snapshot.physicalIdentity === void 0 || current.documentDigest !== snapshot.documentDigest || !samePhysicalIdentity(current.physicalIdentity, snapshot.physicalIdentity)) return false;
3051
+ let handle;
3052
+ try {
3053
+ handle = await this.openCacheDocument(originalPath, "write");
3054
+ } catch (error) {
3055
+ if (error.code === "ENOENT") return false;
3056
+ throw error;
3057
+ }
3058
+ try {
3059
+ if (!await this.frozenCacheBytes(handle, snapshot, false)) return false;
3060
+ try {
3061
+ await this.moveCacheDocument(originalPath, stagePath);
3062
+ } catch (error) {
3063
+ if (["EEXIST", "EXDEV", "ENOENT"].includes(error.code ?? "")) return false;
3064
+ throw error;
3065
+ }
3066
+ } finally {
3067
+ await handle.close();
3068
+ }
3069
+ originalAbsent = await this.pathAbsent(originalPath);
3070
+ stageAbsent = await this.pathAbsent(stagePath);
3071
+ if (!originalAbsent || stageAbsent) return false;
3072
+ }
3073
+ if (!stageAbsent) {
3074
+ let handle;
3075
+ try {
3076
+ handle = await this.openCacheDocument(stagePath, "write");
3077
+ } catch (error) {
3078
+ if (error.code === "ENOENT") return false;
3079
+ throw error;
3080
+ }
3081
+ try {
3082
+ if (!await this.frozenCacheBytes(handle, snapshot, true)) return false;
3083
+ await this.clearCacheStage(handle);
3084
+ } finally {
3085
+ await handle.close();
3086
+ }
3087
+ await this.removeCacheStage(stagePath);
3088
+ if (!await this.pathAbsent(stagePath)) return false;
3089
+ }
3090
+ if (!await this.pathAbsent(originalPath) || !await this.pathAbsent(stagePath)) return false;
3091
+ table.records.delete(id);
3092
+ this.admission.withoutBypass(() => table.host.emitChanged({ domain: table.host.domainName, table: "sessions", key: id, operation: "deleted" }));
3093
+ const final = await this.cacheView(table, id, stageName);
3094
+ return final.location === snapshot.location && !final.present && await this.pathAbsent(stagePath);
3134
3095
  }
3135
- isAcceptedFrame() {
3136
- const frame = this.acceptedFrames.getStore();
3137
- return frame !== void 0 && this.activeAcceptedFrames.has(frame);
3096
+ async eraseCache(snapshot, id, expected, request) {
3097
+ const table = this.cacheTable;
3098
+ if (!table) return !snapshot.present && snapshot.location === null;
3099
+ return table.host.enqueue(async () => {
3100
+ if (process.platform === "win32") return this.eraseWindowsCache(snapshot, id, expected, request, table);
3101
+ const current = await this.cacheView(table, id);
3102
+ if (current.location !== snapshot.location || current.documentDigest !== null && current.documentDigest !== snapshot.documentDigest || current.memoryDigest !== null && current.memoryDigest !== snapshot.memoryDigest || !snapshot.present && current.present) return false;
3103
+ await table.host.unit.deleteRecord("sessions", id);
3104
+ const tableDirectory = table.host.unit.tableDir("sessions");
3105
+ try {
3106
+ await syncDirectory(tableDirectory);
3107
+ } catch (error) {
3108
+ if (error.code !== "ENOENT") throw error;
3109
+ }
3110
+ table.records.delete(id);
3111
+ this.admission.withoutBypass(() => table.host.emitChanged({ domain: table.host.domainName, table: "sessions", key: id, operation: "deleted" }));
3112
+ const final = await this.cacheView(table, id);
3113
+ return final.location === snapshot.location && !final.present;
3114
+ });
3138
3115
  }
3139
- assertAllowed(id) {
3140
- const maintenance = this.maintenance.getStore();
3141
- if (maintenance?.active && maintenance.id === id && !(this.failed && this.candidates.has(id))) return;
3142
- if (!this.ready || this.closing && !this.isAcceptedFrame() || this.failed && this.candidates.has(id) || this.retired.has(id) || this.held.has(id) && !this.isAcceptedFrame()) {
3143
- throw new NativeAdmissionError("The session is reserved for retirement or awaiting recovery.");
3144
- }
3116
+ async capture(sessionId) {
3117
+ return this.admission.bypass(sessionId, () => this.captureInner(sessionId));
3145
3118
  }
3146
- bypass(id, work) {
3147
- const token = { id, active: true };
3148
- try {
3149
- const value = this.maintenance.run(token, work);
3150
- if (value && typeof value.then === "function") {
3151
- return Promise.resolve(value).finally(() => {
3152
- token.active = false;
3153
- });
3119
+ async captureInner(sessionId) {
3120
+ this.targets.add(sessionId);
3121
+ this.assertInstances();
3122
+ this.assertCold(sessionId);
3123
+ const activity = await this.admission.withoutBypass(() => this.ctx.waterfall(
3124
+ "workspace/session-activity",
3125
+ { sessionId },
3126
+ async () => []
3127
+ ));
3128
+ if (activity.length !== 0) this.refuse("native/session-active", "Native deletion refuses active work.");
3129
+ this.assertCold(sessionId);
3130
+ const domain = this.ctx.storageDomain.get("workspace");
3131
+ if (!domain) throw new Error("Native workspace domain is unavailable.");
3132
+ const global = workspaceDomainState2.parse(domain.global.get());
3133
+ if (!global.archivedSessionIds.some((id) => id === sessionId)) this.refuse("native/not-archived", "Native metadata preparation requires an archived session.");
3134
+ const workspaces = [];
3135
+ for (const [workspaceId, raw] of this.workspace.requireTable().entries()) {
3136
+ const record = workspaceRecord.parse(raw);
3137
+ if (!record.sessionIds.some((id) => id === sessionId)) continue;
3138
+ if (record.sessionIds.some((id) => id !== sessionId && this.workspace.sessionPaths.get(id) !== record.path && !this.workspace.missingSessionPaths.has(id))) {
3139
+ this.refuse("native/workspace-pruning-required", "Target removal would prune an unrelated Workspace candidate.");
3154
3140
  }
3155
- token.active = false;
3156
- return value;
3157
- } catch (error) {
3158
- token.active = false;
3159
- throw error;
3141
+ workspaces.push({ workspaceId, record });
3160
3142
  }
3143
+ const cache = this.cacheTable ? await this.cacheTable.host.enqueue(() => this.cacheView(this.cacheTable, sessionId)) : { present: false, digest: null, location: null, documentDigest: null, memoryDigest: null };
3144
+ return nativeMetadataSnapshotSchema.parse({
3145
+ schemaVersion: 1,
3146
+ sessionId,
3147
+ global: { archived: global.archivedSessionIds.includes(sessionId), pinned: global.pinnedSessionIds.includes(sessionId) },
3148
+ workspaces,
3149
+ cache,
3150
+ queryProvider: this.queryProvider,
3151
+ queryPath: this.queryConfiguration?.path ?? null
3152
+ });
3161
3153
  }
3162
- withoutBypass(work) {
3163
- return this.maintenance.run(void 0, work);
3164
- }
3165
- track(id, work) {
3166
- this.assertAllowed(id);
3167
- const tasks = this.pending.get(id) ?? /* @__PURE__ */ new Set();
3168
- this.pending.set(id, tasks);
3169
- const frame = Symbol("native-accepted-operation");
3170
- this.activeAcceptedFrames.add(frame);
3171
- const task = this.acceptedFrames.run(frame, () => Promise.resolve().then(work));
3172
- tasks.add(task);
3173
- void task.finally(() => {
3174
- this.activeAcceptedFrames.delete(frame);
3175
- tasks.delete(task);
3176
- if (!tasks.size) this.pending.delete(id);
3177
- }).catch(() => {
3154
+ wrap(port, name2, replace) {
3155
+ const descriptor2 = Object.getOwnPropertyDescriptor(port, name2);
3156
+ const original = port[name2];
3157
+ const adapter = this;
3158
+ const guarded = replace((...args) => Reflect.apply(original, adapter.receivers.getStore() ?? port, args));
3159
+ const replacement = function(...args) {
3160
+ if (adapter.detached) throw new NativeMetadataRefusal("native/stale-reference", "Reacquire native methods after retirement adapter takeover.");
3161
+ return adapter.receivers.run(this, () => guarded(...args));
3162
+ };
3163
+ Object.defineProperty(port, name2, { configurable: true, writable: true, value: replacement });
3164
+ this.guardedMethods.push({ port, name: name2, replacement });
3165
+ this.restores.push(() => {
3166
+ if (port[name2] !== replacement) throw new Error(`Native metadata guard ${name2} was replaced before withdrawal.`);
3167
+ if (descriptor2) Object.defineProperty(port, name2, descriptor2);
3168
+ else delete port[name2];
3178
3169
  });
3179
- return task;
3180
3170
  }
3181
- async trackGlobal(work) {
3182
- if (this.closing && !this.isAcceptedFrame() && !this.maintenance.getStore()?.active) {
3183
- throw new NativeAdmissionError("Native admission is closing.");
3184
- }
3185
- while (this.held.size && !this.maintenance.getStore()?.active && !this.isAcceptedFrame()) {
3186
- await Promise.all([...this.released.values()].map((signal) => signal.promise));
3187
- }
3188
- if (!this.ready || this.closing && !this.isAcceptedFrame() && !this.maintenance.getStore()?.active) {
3189
- throw new NativeAdmissionError("Native admission is not accepting another request.");
3190
- }
3191
- const frame = Symbol("native-header-read");
3192
- this.activeAcceptedFrames.add(frame);
3193
- const task = this.acceptedFrames.run(frame, () => Promise.resolve().then(work));
3194
- this.globalReads.add(task);
3195
- try {
3196
- return await task;
3197
- } finally {
3198
- this.activeAcceptedFrames.delete(frame);
3199
- this.globalReads.delete(task);
3200
- }
3171
+ guardEntity(entity) {
3172
+ if (this.guardedEntities.has(entity)) return;
3173
+ this.guardedEntities.add(entity);
3174
+ this.wrap(entity, "attachSession", (original) => (id) => this.tracked(id, async () => {
3175
+ const result = await original(id);
3176
+ this.assert(id);
3177
+ return result;
3178
+ }));
3201
3179
  }
3202
- async drain(id) {
3203
- for (; ; ) {
3204
- const tasks = id === void 0 ? [...this.pending.values()].flatMap((set) => [...set]) : [...this.pending.get(id) ?? []];
3205
- tasks.push(...this.globalReads);
3206
- if (!tasks.length) return;
3207
- await Promise.allSettled(tasks);
3208
- }
3180
+ guardedObservation(id, observation) {
3181
+ this.increment(this.retained, id, 1);
3182
+ let disposed = false;
3183
+ return new Proxy(observation, { get: (target, property) => {
3184
+ if (property === Symbol.dispose) return () => {
3185
+ if (disposed) return;
3186
+ disposed = true;
3187
+ try {
3188
+ target[Symbol.dispose]();
3189
+ } finally {
3190
+ this.increment(this.retained, id, -1);
3191
+ }
3192
+ };
3193
+ if (property === "retain") return () => {
3194
+ this.assert(id);
3195
+ return this.guardedObservation(id, target.retain());
3196
+ };
3197
+ if (property === "events" || property === "projections") this.assert(id);
3198
+ return Reflect.get(target, property, target);
3199
+ } });
3209
3200
  }
3210
- async acquire(id, recovery = false) {
3211
- while (this.held.has(id)) await this.released.get(id).promise;
3212
- if (this.failed || this.closing || !this.ready || !recovery && this.retired.has(id)) {
3213
- throw new NativeAdmissionError("The session cannot enter another retirement scope.");
3214
- }
3215
- let resolve4;
3216
- const signal = { promise: new Promise((done2) => {
3217
- resolve4 = done2;
3218
- }), resolve: () => resolve4() };
3219
- this.held.add(id);
3220
- this.released.set(id, signal);
3221
- this.candidates.add(id);
3222
- const release = () => {
3223
- this.held.delete(id);
3224
- this.released.delete(id);
3225
- signal.resolve();
3226
- };
3201
+ async install() {
3202
+ if (this.installed) throw new Error("Native metadata adapter is already installed.");
3203
+ this.assertInstances();
3204
+ this.installed = true;
3227
3205
  try {
3228
- await this.drain(id);
3229
- } catch (error) {
3230
- release();
3231
- throw error;
3232
- }
3233
- let done = false;
3234
- return () => {
3235
- if (!done) {
3236
- done = true;
3237
- release();
3206
+ for (const name2 of ["workspace", ...this.cache ? ["session_projcache"] : []]) {
3207
+ const domain = this.ctx.storageDomain.get(name2);
3208
+ if (!domain || domain.constructor.name !== "DomainImpl" || !methods(domain, ["emitChanged"])) {
3209
+ throw new Error("Native metadata domain publication shape changed.");
3210
+ }
3211
+ this.wrap(domain, "emitChanged", (original) => (change) => this.admission.withoutBypass(() => original(change)));
3212
+ }
3213
+ for (const name2 of ["archiveSession", "unarchiveSession", "pinSession", "unpinSession"]) {
3214
+ this.wrap(this.workspace, name2, (original) => (id, ...args) => this.tracked(
3215
+ id,
3216
+ () => this.queueTarget.run(id, async () => original(id, ...args))
3217
+ ));
3218
+ }
3219
+ this.wrap(this.workspace, "enqueueOperation", (original) => (operation) => {
3220
+ const id = this.queueTarget.getStore();
3221
+ return original(async () => {
3222
+ if (id !== void 0) this.assert(id);
3223
+ return operation();
3224
+ });
3225
+ });
3226
+ this.wrap(this.workspace, "setState", (original) => async (next) => {
3227
+ const id = this.queueTarget.getStore();
3228
+ if (id !== void 0) this.assert(id);
3229
+ return original(next);
3230
+ });
3231
+ this.wrap(this.workspace, "indexHeader", (original) => (header) => this.tracked(header.id, async () => {
3232
+ const result = await original(header);
3233
+ this.assert(header.id);
3234
+ return result;
3235
+ }));
3236
+ this.wrap(this.workspace, "readSessionHeader", (original) => (id) => this.tracked(id, async () => {
3237
+ const result = await original(id);
3238
+ this.assert(id);
3239
+ return result;
3240
+ }));
3241
+ for (const entity of this.workspace.list()) this.guardEntity(entity);
3242
+ for (const name2 of ["create", "initializeDefault"]) this.wrap(this.workspace, name2, (original) => async (...args) => {
3243
+ const entity = await original(...args);
3244
+ if (entity) this.guardEntity(entity);
3245
+ return entity;
3246
+ });
3247
+ this.wrap(this.sessions, "prepare", (original) => (id, ...args) => {
3248
+ if (id !== void 0) this.assert(id);
3249
+ const session = original(id, ...args);
3250
+ this.assert(session.id);
3251
+ return session;
3252
+ });
3253
+ for (const name2 of ["enter", "announce"]) this.wrap(this.sessions, name2, (original) => (session) => {
3254
+ this.assert(session.id);
3255
+ return original(session);
3256
+ });
3257
+ if (this.cache) {
3258
+ this.wrap(this.cache, "put", (original) => (id, ...args) => this.tracked(id, async () => original(id, ...args)));
3259
+ for (const name2 of ["cachedSnapshot", "cachedPredecessorTitle", "coldSnapshot"]) this.wrap(
3260
+ this.cache,
3261
+ name2,
3262
+ (original) => (header, ...args) => {
3263
+ this.assert(header.id);
3264
+ return original(header, ...args);
3265
+ }
3266
+ );
3267
+ this.wrap(this.cache, "hydratePrepared", (original) => (session, ...args) => {
3268
+ this.assert(session.id);
3269
+ return original(session, ...args);
3270
+ });
3271
+ }
3272
+ if (this.query) {
3273
+ this.wrap(this.query, "_serialized", (original) => (signal, operation) => this.admission.trackGlobal(async () => original(signal, operation)));
3274
+ this.wrap(this.query._observations, "read", (original) => (id, ...args) => this.tracked(id, async () => {
3275
+ const observation = await original(id, ...args);
3276
+ try {
3277
+ this.assert(id);
3278
+ return this.guardedObservation(id, observation);
3279
+ } catch (error) {
3280
+ observation[Symbol.dispose]();
3281
+ throw error;
3282
+ }
3283
+ }));
3284
+ this.wrap(this.query._observations, "store", (original) => (id, ...args) => {
3285
+ this.assert(id);
3286
+ return original(id, ...args);
3287
+ });
3288
+ for (const name2 of ["readSession", "readTitle", "readTitleSnapshot", "listEvents", "filterEvents", "readSurface", "traceSession"]) {
3289
+ if (typeof this.query[name2] === "function") this.wrap(this.query, name2, (original) => (id, ...args) => this.tracked(id, async () => {
3290
+ const result = await original(id, ...args);
3291
+ this.assert(id);
3292
+ return result;
3293
+ }));
3294
+ }
3295
+ for (const name2 of ["searchEvents", "readEvent", "traceEvent"]) if (typeof this.query[name2] === "function") {
3296
+ this.wrap(this.query, name2, (original) => (request, ...args) => this.tracked(
3297
+ request.sessionId,
3298
+ async () => {
3299
+ const result = await original(request, ...args);
3300
+ this.assert(request.sessionId);
3301
+ return result;
3302
+ }
3303
+ ));
3304
+ }
3238
3305
  }
3239
- };
3240
- }
3241
- };
3242
-
3243
- // src/host/native-retirement-persistence.ts
3244
- import { SessionId as SessionId2 } from "@deepseek-ai/dsh-session";
3245
- function nativeServiceInstance(value) {
3246
- return Reflect.get(value, Symbol.for("cordis.original")) ?? value;
3247
- }
3248
- var NativePersistenceAdapter = class {
3249
- constructor(provider, admission) {
3250
- this.provider = provider;
3251
- this.admission = admission;
3252
- const raw = nativeServiceInstance(provider);
3253
- if (!(raw.tracker?.openHandles instanceof Set) || !(raw.tracker.writers instanceof Map) || !(raw.tracker.pending instanceof Map) || !(raw.migrationPreparations instanceof Map) || !(raw.coldLogMemo instanceof Map)) throw new Error("JSONL retirement runtime shape does not match the pinned provider.");
3254
- this.raw = raw;
3255
- this.originalStat = provider.stat.bind(provider);
3256
- this.originalList = provider.list.bind(provider);
3257
- }
3258
- raw;
3259
- originalStat;
3260
- originalList;
3261
- restore = [];
3262
- detached = false;
3263
- active = true;
3264
- managedHandles = /* @__PURE__ */ new WeakSet();
3265
- stat(id) {
3266
- return this.originalStat(SessionId2(id));
3267
- }
3268
- list() {
3269
- return this.originalList();
3270
- }
3271
- busy(id) {
3272
- return this.raw.tracker.pending.has(id) || this.raw.tracker.writers.has(id) || [...this.raw.tracker.openHandles].some((handle) => handle.id === id) || this.raw.migrationPreparations.size !== 0;
3273
- }
3274
- forget(id) {
3275
- if (this.busy(id)) throw new NativeAdmissionError("A persistence reference still owns this session.");
3276
- this.raw.coldLogMemo.delete(id);
3277
- }
3278
- install() {
3279
- this.originalStat = this.provider.stat.bind(this.provider);
3280
- this.originalList = this.provider.list.bind(this.provider);
3281
- const route = (target, name2, idFor, transform, globalRead = false) => {
3282
- target = nativeServiceInstance(target);
3283
- const record = target;
3284
- const original = record[name2];
3285
- if (typeof original !== "function") throw new Error(`Missing pinned JSONL route ${name2}.`);
3286
- const own = Object.getOwnPropertyDescriptor(target, name2);
3287
- const adapter2 = this;
3288
- const wrapper = function(...args) {
3289
- const receiver = this;
3290
- if (adapter2.detached) return Promise.reject(new NativeAdmissionError("This native guard belongs to a replaced retirement owner."));
3291
- const id = idFor(args);
3292
- if (!adapter2.active) {
3293
- if (adapter2.admission.isRetired(id)) return Promise.reject(new NativeAdmissionError("This session has a retirement tombstone."));
3294
- return Reflect.apply(original, receiver, args);
3306
+ if (this.controller) {
3307
+ const adapter = this;
3308
+ for (const name2 of ["resumeObserved", "claim", "createAgent"]) {
3309
+ this.wrap(this.controller.agents, name2, (original) => (id, ...args) => this.tracked(id, () => this.activationTarget.run(id, async () => original(id, ...args))));
3295
3310
  }
3296
- const run = () => adapter2.admission.track(id, async () => {
3297
- const value = await Reflect.apply(original, receiver, args);
3298
- return transform ? transform(value) : value;
3311
+ const agents = this.agents;
3312
+ for (const name2 of ["create", "resume"]) {
3313
+ this.wrap(agents, name2, (original) => (options, ...args) => {
3314
+ const id = String(name2 === "create" ? options.sessionId : options.resumeSessionId);
3315
+ return this.tracked(id, async () => {
3316
+ const handle = await original(options, ...args);
3317
+ if (this.activationTarget.getStore() === id && options.parentAgent === void 0 && handle.agent.id === id && handle.agent.session.header.origin !== "subagent" && typeof handle.dispose === "function") this.apiHandles.set(id, handle);
3318
+ return handle;
3319
+ });
3320
+ });
3321
+ }
3322
+ this.restores.push(this.ctx.on("agent/disposed", ({ agent }) => {
3323
+ if (this.apiHandles.get(agent.id)?.agent === agent) this.apiHandles.delete(agent.id);
3324
+ }, { global: true }));
3325
+ this.wrap(this.controller.history, "follow", (original) => function(request, signal) {
3326
+ const id = String(request.address.sessionId);
3327
+ adapter.assert(id);
3328
+ return (async function* () {
3329
+ adapter.assert(id);
3330
+ adapter.increment(adapter.followers, id, 1);
3331
+ const cancellation = new AbortController();
3332
+ const iterator = original(request, AbortSignal.any([signal, cancellation.signal]));
3333
+ const stops = adapter.followerStops.get(id) ?? /* @__PURE__ */ new Set();
3334
+ adapter.followerStops.set(id, stops);
3335
+ let finished = false;
3336
+ const finish = () => {
3337
+ if (finished) return;
3338
+ finished = true;
3339
+ adapter.increment(adapter.followers, id, -1);
3340
+ stops.delete(stop);
3341
+ if (!stops.size) adapter.followerStops.delete(id);
3342
+ };
3343
+ const stop = async () => {
3344
+ cancellation.abort();
3345
+ await iterator.return();
3346
+ finish();
3347
+ };
3348
+ stops.add(stop);
3349
+ try {
3350
+ for await (const frame of iterator) {
3351
+ adapter.assert(id);
3352
+ yield frame;
3353
+ }
3354
+ } finally {
3355
+ finish();
3356
+ }
3357
+ })();
3299
3358
  });
3300
- return globalRead ? adapter2.admission.trackGlobal(run) : run();
3301
- };
3302
- Object.defineProperty(target, name2, { configurable: true, writable: true, value: wrapper });
3303
- this.restore.push(() => {
3304
- if (record[name2] !== wrapper) throw new Error(`JSONL route ${name2} changed while retirement was installed.`);
3305
- if (own) Object.defineProperty(target, name2, own);
3306
- else delete record[name2];
3307
- });
3308
- };
3309
- const headerId = (args) => String(args[0].id);
3310
- route(this.provider, "create", headerId, (value) => this.manage(value));
3311
- route(this.provider, "open", (args) => String(args[0]), (value) => this.manage(value), true);
3312
- for (const method of ["persistBatch", "persistHeader", "truncateTornTail", "acquireWriteLease"]) {
3313
- route(this.provider, method, headerId);
3359
+ }
3360
+ } catch (error) {
3361
+ for (const restore of [...this.restores].reverse()) restore();
3362
+ this.restores.length = 0;
3363
+ this.installed = false;
3364
+ throw error;
3314
3365
  }
3315
- route(this.provider, "readStoredLog", (args) => String(args[1]), void 0, true);
3316
- route(this.provider, "resolveCurrentLog", (args) => String(args[0]));
3317
- const instance = nativeServiceInstance(this.provider);
3318
- const rawStat = instance.stat;
3319
- const rawList = instance.list;
3320
- const adapter = this;
3321
- instance.stat = async function(id, options) {
3322
- if (adapter.detached) throw new NativeAdmissionError("This native observer belongs to a replaced retirement owner.");
3323
- if (adapter.admission.isRetired(id)) return void 0;
3324
- const value = await adapter.admission.trackGlobal(() => adapter.admission.track(id, () => rawStat.call(this, id, options)));
3325
- return adapter.admission.isRetired(id) ? void 0 : value;
3326
- };
3327
- instance.list = async function(options) {
3328
- if (adapter.detached) throw new NativeAdmissionError("This native observer belongs to a replaced retirement owner.");
3329
- return (await adapter.admission.trackGlobal(() => rawList.call(this, options))).filter((item) => !adapter.admission.isRetired(item.header.id));
3330
- };
3331
- this.restore.push(() => {
3332
- instance.stat = rawStat;
3333
- instance.list = rawList;
3334
- });
3335
- return async () => {
3336
- await this.admission.drain();
3337
- this.active = false;
3338
- if (this.originalRetired()) return;
3339
- for (const undo of [...this.restore].reverse()) undo();
3340
- this.restore.length = 0;
3341
- };
3366
+ let closing;
3367
+ return () => closing ??= (async () => {
3368
+ this.fallbackRetired = new Set([...this.targets].filter((id) => this.admission.isRetired(id)));
3369
+ this.disposed = true;
3370
+ this.apiHandles.clear();
3371
+ if (this.fallbackRetired.size === 0) {
3372
+ for (const restore of [...this.restores].reverse()) restore();
3373
+ this.restores.length = 0;
3374
+ }
3375
+ })();
3342
3376
  }
3377
+ /** The verified owner completes all asynchronous takeover work before this
3378
+ * synchronous restoration and installs its successor guards without yielding. */
3343
3379
  forceRestore() {
3380
+ if (this.restores.length && this.guardedMethods.some(({ port, name: name2, replacement }) => port[name2] !== replacement)) {
3381
+ throw new Error("Native metadata guards changed before trusted takeover.");
3382
+ }
3344
3383
  this.detached = true;
3345
- this.active = false;
3346
- for (const undo of [...this.restore].reverse()) undo();
3347
- this.restore.length = 0;
3348
- }
3349
- originalRetired() {
3350
- return this.admission.hasTombstones();
3384
+ this.disposed = true;
3385
+ for (const restore of [...this.restores].reverse()) restore();
3386
+ this.restores.length = 0;
3387
+ this.guardedMethods.length = 0;
3388
+ this.fallbackRetired.clear();
3389
+ this.apiHandles.clear();
3351
3390
  }
3352
- manage(handle) {
3353
- if (this.managedHandles.has(handle)) return handle;
3354
- this.managedHandles.add(handle);
3355
- const methods2 = ["read", "append", "flush"];
3356
- for (const name2 of methods2) {
3357
- const original = handle[name2];
3358
- Object.defineProperty(handle, name2, {
3359
- configurable: true,
3360
- writable: true,
3361
- value: (...args) => !this.active && !this.admission.isRetired(handle.id) ? Reflect.apply(original, handle, args) : this.admission.track(handle.id, async () => Reflect.apply(original, handle, args))
3362
- });
3391
+ async converge(input, expected, request) {
3392
+ const snapshot = nativeMetadataSnapshotSchema.parse(input);
3393
+ const id = snapshot.sessionId;
3394
+ this.targets.add(id);
3395
+ this.assertInstances();
3396
+ if (snapshot.queryProvider !== this.queryProvider || snapshot.queryPath !== (this.queryConfiguration?.path ?? null)) return false;
3397
+ if (id !== expected.sessionId || id !== request.expected.sessionId || expected.storeId !== request.expected.storeId || expected.lifecycleId !== request.expected.lifecycleId || !this.admission.isRetired(id)) {
3398
+ this.refuse("native/maintenance-binding-changed", "Native convergence requires the exact durable retirement binding.");
3363
3399
  }
3364
- return handle;
3400
+ if ((this.operations.get(id) ?? 0) > 0 || (this.retained.get(id) ?? 0) > 0 || (this.followers.get(id) ?? 0) > 0) return false;
3401
+ this.assertCold(id);
3402
+ return this.admission.bypass(id, async () => {
3403
+ if (!await this.eraseCache(snapshot.cache, id, expected, request)) return false;
3404
+ this.query?._observations.cache.delete(id);
3405
+ const frozenIds = new Set(snapshot.workspaces.map((item) => item.workspaceId));
3406
+ const convergeWorkspace = async () => {
3407
+ for (const [workspaceId, raw] of this.workspace.requireTable().entries()) {
3408
+ const record = workspaceRecord.parse(raw);
3409
+ if (!record.sessionIds.some((sessionId) => sessionId === id)) continue;
3410
+ if (!frozenIds.has(workspaceId) || record.sessionIds.some((other) => other !== id && this.workspace.sessionPaths.get(other) !== record.path && !this.workspace.missingSessionPaths.has(other))) return false;
3411
+ const entity = this.workspace.get(workspaceId);
3412
+ if (!entity) throw new Error("Native Workspace account lost its runtime entity.");
3413
+ await entity.detachSession(id);
3414
+ }
3415
+ const state = workspaceDomainState2.parse(this.workspace.requireState());
3416
+ if (state.archivedSessionIds.includes(id) || state.pinnedSessionIds.includes(id)) {
3417
+ await this.workspace.setState({
3418
+ ...state,
3419
+ archivedSessionIds: state.archivedSessionIds.filter((other) => other !== id),
3420
+ pinnedSessionIds: state.pinnedSessionIds.filter((other) => other !== id)
3421
+ });
3422
+ }
3423
+ this.workspace.headers.delete(id);
3424
+ this.workspace.sessionPaths.delete(id);
3425
+ this.workspace.invalidSessionPaths.delete(id);
3426
+ this.workspace.missingSessionPaths.delete(id);
3427
+ return true;
3428
+ };
3429
+ if (!await this.workspace.enqueueOperation(convergeWorkspace)) return false;
3430
+ if (this.query) {
3431
+ if (this.queryProvider === "sqlite-0.2.0-rc.2") {
3432
+ await this.query.searchSessions({ query: "native-retirement-reconciliation", limit: 1 });
3433
+ }
3434
+ if ((await this.query.listSessions()).some((record) => record.header.id === id)) return false;
3435
+ this.assertInstances();
3436
+ }
3437
+ this.admission.withoutBypass(() => this.ctx.emit("api-session/removed", id));
3438
+ return true;
3439
+ });
3365
3440
  }
3366
3441
  };
3367
3442
 
@@ -4059,7 +4134,7 @@ var NativeRetirementOwner = class _NativeRetirementOwner {
4059
4134
  this.descriptor = retirementCapabilitiesSchema.parse({
4060
4135
  protocolVersion: 1,
4061
4136
  ownerId: "session-bin-native-jsonl-owner",
4062
- hostVersion: "0.2.0-rc.2",
4137
+ hostVersion: legacyDurableHostContract,
4063
4138
  providerId: "jsonl-session-records-v1",
4064
4139
  storeId: domain.global.get().storeId,
4065
4140
  participants: [{ id: "native-jsonl-files", version: fingerprint }, { id: "native-metadata", version: fingerprint }]