Bläddra i källkod

Merge master into session-log-v3 release

Merge 3ea52fc3e475a3e7c430812bde4209258416e57b into a0a61a8237f61344a01448a97954df603d8fff73. Retain the V2-to-V3 migration dependency alongside native system flock support, removing the replaced fs-ext dependency. Union the lockfile workspace importer entries; frozen installation validates the result without regeneration.

Preserve release publint async lane-signal cancellation, close ownership, and spawn-error regressions, satisfying the incoming CI budget intent. Keep canonical, prompt, preset, and latest migration regression behavior. Rename an arbitrary preset fixture value to custom-agent to avoid the inherited vendor-rescope false positive without changing test semantics.

Validation: frozen install; full build including Darwin addon; focused V3/persistence/prompt/publint and runtime tests; built migration, two-process lease, and loader smokes; native flock and package-matrix tests; touched dependency and CI owner tests; all hygiene leaves (vendor residue repaired and rechecked); doc-sync 34/34.
Tianyi Cui 1 månad sedan
förälder
incheckning
bb407e309d
100 ändrade filer med 1229 tillägg och 899 borttagningar
  1. 6 0
      .agents/notes/implemented/architecture/2026-09-07-prebuilt-system-primitives.i18n.yaml
  2. 33 0
      .agents/notes/implemented/architecture/2026-09-07-prebuilt-system-primitives.md
  3. 33 0
      .agents/notes/implemented/architecture/2026-09-07-prebuilt-system-primitives.zh.md
  4. 2 2
      .agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml
  5. 1 1
      .agents/notes/implemented/feature/2026-07-06-sandbox.md
  6. 1 1
      .agents/notes/implemented/feature/2026-07-06-sandbox.zh.md
  7. 2 2
      .agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.i18n.yaml
  8. 6 6
      .agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md
  9. 6 6
      .agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.zh.md
  10. 2 2
      .agents/notes/implemented/feature/2026-08-15-product-subagent-noninteractive-permissions.i18n.yaml
  11. 2 2
      .agents/notes/implemented/feature/2026-08-15-product-subagent-noninteractive-permissions.md
  12. 2 2
      .agents/notes/implemented/feature/2026-08-15-product-subagent-noninteractive-permissions.zh.md
  13. 2 2
      .agents/notes/implemented/feature/2026-08-31-cross-process-session-write-lease.i18n.yaml
  14. 3 3
      .agents/notes/implemented/feature/2026-08-31-cross-process-session-write-lease.md
  15. 3 3
      .agents/notes/implemented/feature/2026-08-31-cross-process-session-write-lease.zh.md
  16. 2 2
      .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml
  17. 1 1
      .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md
  18. 1 1
      .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md
  19. 2 2
      .agents/notes/implemented/process/2026-08-10-npm-release-sequences.i18n.yaml
  20. 2 2
      .agents/notes/implemented/process/2026-08-10-npm-release-sequences.md
  21. 2 2
      .agents/notes/implemented/process/2026-08-10-npm-release-sequences.zh.md
  22. 6 0
      .agents/notes/implemented/testing/2026-09-08-ci-readiness-and-completion.i18n.yaml
  23. 33 0
      .agents/notes/implemented/testing/2026-09-08-ci-readiness-and-completion.md
  24. 33 0
      .agents/notes/implemented/testing/2026-09-08-ci-readiness-and-completion.zh.md
  25. 0 144
      .github/workflows/landlock-run.yml
  26. 18 10
      .github/workflows/node-addon-system-release.yml
  27. 179 0
      .github/workflows/node-addon-system.yml
  28. 2 2
      .github/workflows/release-publish.yml
  29. 2 2
      .github/workflows/release.yml
  30. 3 3
      .github/workflows/sandbox.yml
  31. 1 0
      .gitignore
  32. 1 1
      AGENTS.md
  33. 10 12
      THIRD_PARTY_NOTICES.md
  34. 2 2
      apps/desktop/scripts/package-target.ts
  35. 22 4
      apps/desktop/tests/project-manager.spec.ts
  36. 1 1
      apps/web/tests/preview-boot.e2e.ts
  37. 26 6
      apps/web/tests/settings-chrome.e2e.ts
  38. 4 2
      apps/web/tests/workflow-run.e2e.ts
  39. 2 2
      native/README.i18n.yaml
  40. 3 3
      native/README.md
  41. 3 3
      native/README.zh.md
  42. 0 50
      native/landlock-run/AGENTS.md
  43. 0 60
      native/landlock-run/README.md
  44. 0 60
      native/landlock-run/README.zh.md
  45. 0 34
      native/landlock-run/docs/architecture.md
  46. 0 45
      native/landlock-run/docs/packaging.md
  47. 0 60
      native/landlock-run/docs/release.md
  48. 0 18
      native/landlock-run/docs/support-matrix.md
  49. 0 18
      native/landlock-run/packages/entry/README.md
  50. 0 18
      native/landlock-run/packages/entry/README.zh.md
  51. 0 41
      native/landlock-run/packages/entry/package.json
  52. 0 9
      native/landlock-run/packages/linux-arm64/README.md
  53. 0 9
      native/landlock-run/packages/linux-arm64/README.zh.md
  54. 0 10
      native/landlock-run/packages/linux-arm64/prebuilds.json
  55. 0 9
      native/landlock-run/packages/linux-x64/README.md
  56. 0 9
      native/landlock-run/packages/linux-x64/README.zh.md
  57. 0 10
      native/landlock-run/packages/linux-x64/prebuilds.json
  58. 0 86
      native/landlock-run/scripts/build.ts
  59. 0 88
      native/landlock-run/scripts/repo.mjs
  60. 0 0
      native/system/.gitignore
  61. 28 0
      native/system/AGENTS.md
  62. 0 0
      native/system/LICENSE
  63. 3 3
      native/system/README.i18n.yaml
  64. 41 0
      native/system/README.md
  65. 41 0
      native/system/README.zh.md
  66. 25 0
      native/system/docs/architecture.md
  67. 0 0
      native/system/docs/cli-contract.md
  68. 36 0
      native/system/docs/flock-contract.md
  69. 5 5
      native/system/docs/naming.md
  70. 24 0
      native/system/docs/packaging.md
  71. 63 0
      native/system/docs/release.md
  72. 14 0
      native/system/docs/support-matrix.md
  73. 6 3
      native/system/package.json
  74. 0 0
      native/system/packages/darwin-arm64/LICENSE
  75. 3 3
      native/system/packages/darwin-arm64/README.i18n.yaml
  76. 9 0
      native/system/packages/darwin-arm64/README.md
  77. 9 0
      native/system/packages/darwin-arm64/README.zh.md
  78. 19 0
      native/system/packages/darwin-arm64/package.json
  79. 6 0
      native/system/packages/darwin-arm64/prebuilds.json
  80. 0 0
      native/system/packages/darwin-x64/LICENSE
  81. 3 3
      native/system/packages/darwin-x64/README.i18n.yaml
  82. 9 0
      native/system/packages/darwin-x64/README.md
  83. 9 0
      native/system/packages/darwin-x64/README.zh.md
  84. 19 0
      native/system/packages/darwin-x64/package.json
  85. 6 0
      native/system/packages/darwin-x64/prebuilds.json
  86. 3 3
      native/system/packages/entry/README.i18n.yaml
  87. 15 0
      native/system/packages/entry/README.md
  88. 15 0
      native/system/packages/entry/README.zh.md
  89. 46 0
      native/system/packages/entry/package.json
  90. 164 0
      native/system/packages/entry/src/flock.c
  91. 57 0
      native/system/packages/entry/src/flock.ts
  92. 2 2
      native/system/packages/entry/src/index.ts
  93. 1 1
      native/system/packages/entry/src/main.c
  94. 0 0
      native/system/packages/entry/tsconfig.json
  95. 28 0
      native/system/packages/linux-arm64/LICENSE
  96. 6 0
      native/system/packages/linux-arm64/README.i18n.yaml
  97. 11 0
      native/system/packages/linux-arm64/README.md
  98. 11 0
      native/system/packages/linux-arm64/README.zh.md
  99. 3 3
      native/system/packages/linux-arm64/package.json
  100. 24 0
      native/system/packages/linux-arm64/prebuilds.json

+ 6 - 0
.agents/notes/implemented/architecture/2026-09-07-prebuilt-system-primitives.i18n.yaml

@@ -0,0 +1,6 @@
+# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
+# side as of the last confirmed-consistent state. Both languages carry equal authority;
+# after editing either side, bring the other along and re-record with:
+#   pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-09-07-prebuilt-system-primitives.md
+2026-09-07-prebuilt-system-primitives.md: 183cd3ea984cd779417493f0de17a770f38fc001
+2026-09-07-prebuilt-system-primitives.zh.md: f051bba92910086601aa48a877f360e276df524d

+ 33 - 0
.agents/notes/implemented/architecture/2026-09-07-prebuilt-system-primitives.md

@@ -0,0 +1,33 @@
+# Agent Note: Prebuilt system primitives
+
+Status: implemented
+
+English | [中文](2026-09-07-prebuilt-system-primitives.zh.md)
+
+## Problem
+
+The JSONL writer's `fs-ext` dependency compiled a NAN addon during consumer installation. Native compiler availability and Node module ABI changes therefore affected ordinary installs, including Node 26. The repository already maintained the Landlock launcher and its per-platform publication workflow.
+
+## Decision
+
+The independently versioned `@deepseek-ai/node-addon-system` family in [native/system](../../../../native/system/README.md) distributes the existing `landlock-run` executable and a stable Node-API v8 `system.node` addon. Platform packages select OS and CPU; Linux carries distinct glibc and musl addon files. macOS carries the addon without a Landlock executable. Neither the entry nor platform packages compile during installation.
+
+The package has no root export. The `./landlock-run` JavaScript entry retains Landlock's API and [CLI protocol](../../../../native/system/docs/cli-contract.md). The `./flock` entry loads its addon only when `tryLockExclusive(fd)` is called. It runs `flock(fd, LOCK_EX | LOCK_NB)` in asynchronous native work and captures errno on that worker. The caller owns the descriptor through completion and releases its lock by closing it. Missing bindings reject acquisition rather than granting an unprotected lock.
+
+The [Session write-lease decision](../feature/2026-08-31-cross-process-session-write-lease.md) continues to own acquisition timing, inode checks, close ownership, and crash semantics. Windows retains its existing koffi semaphore. The browser worker substitutes only the flock subpath; it uses the unchanged `./landlock-run` JavaScript API.
+
+Source builds explicitly compile the host addon before repository tests and builds that need it. Native CI builds the complete platform payload and tests the same addon bytes across Node releases; Linux also exercises the musl payload in Alpine. Platform prepack rejects malformed or incomplete binaries, and an offline npm install rehearsal checks installed bytes and real lock behavior. Native [tests](../../../../native/system/test/flock.test.js) cover descriptor/process contention, close and crash release, independent errno values, and worker teardown.
+
+## Alternatives considered
+
+**Keep NAN and publish one build per Node ABI.** This retains a Node-major build matrix for a binding that needs only stable Node-API operations. The evaluated `fs-ext-extra-prebuilt@2.2.14` selected a Node 25 ABI 141 binary under Node 26 ABI 147; its default-install fallback also exited without building when NAN was hoisted.
+
+**Bundle fs-ext into the parent tarball.** npm normally still runs bundled dependency installation hooks. Bundling alone neither suppresses compilation nor makes one binary portable across operating systems, CPUs, libc implementations, or Node ABIs.
+
+**Replace flock with OFD/fcntl locks.** On ordinary Linux filesystems these locks do not necessarily exclude existing flock holders. A tmpfs probe admitted an OFD lock while fs-ext held flock, so this is not a behavior-preserving replacement.
+
+**Use koffi for the POSIX call.** A synchronous call changes event-loop blocking behavior; reading errno after its asynchronous callback reads the wrong thread's value. A native async-work adapter keeps the syscall result and errno together without another FFI coordination layer.
+
+## Consequences
+
+The family owns a small C binding, platform builds, and installed-artifact verification rather than an entire filesystem-extension API. Node-API removes the per-Node-major binary requirement, not OS/CPU/libc requirements. The shared native release includes both capabilities, but importing or using one does not load the other. Landlock binary semantics, Windows locking, and released Session data formats remain unchanged.

+ 33 - 0
.agents/notes/implemented/architecture/2026-09-07-prebuilt-system-primitives.zh.md

@@ -0,0 +1,33 @@
+# Agent Note: 预编译系统原语
+
+Status: implemented
+
+[English](2026-09-07-prebuilt-system-primitives.md) | 中文
+
+## Problem
+
+JSONL 写入方依赖的 `fs-ext` 在用户安装时编译 NAN addon。因此,原生编译器是否可用以及 Node 模块 ABI 的变化会影响普通安装,包括 Node 26。仓库已经维护了 Landlock 启动器及其按平台发布的工作流。
+
+## Decision
+
+[native/system](../../../../native/system/README.zh.md) 中独立版本的 `@deepseek-ai/node-addon-system` 包族分发既有 `landlock-run` 可执行文件和使用稳定 Node-API v8 的 `system.node` addon。平台包按操作系统和 CPU 选择;Linux 分别携带 glibc 与 musl addon 文件。macOS 携带 addon,但不包含 Landlock 可执行文件。入口包和平台包都不在安装期间编译。
+
+包不提供根导出。`./landlock-run` JavaScript 入口保留 Landlock API 和 [CLI 协议](../../../../native/system/docs/cli-contract.md)。`./flock` 入口仅在调用 `tryLockExclusive(fd)` 时加载 addon。它在异步原生工作中执行 `flock(fd, LOCK_EX | LOCK_NB)`,并在该工作线程保存 errno。调用方在完成前持有描述符,并通过关闭它释放锁。绑定缺失时拒绝获取锁,不授予没有保护的锁。
+
+[Session 写租约决策](../feature/2026-08-31-cross-process-session-write-lease.zh.md) 继续负责获取时机、inode 校验、关闭所有权和崩溃语义。Windows 保留既有 koffi 信号量。浏览器 worker 仅替换 flock 子路径,使用未经修改的 `./landlock-run` JavaScript API。
+
+源码构建在需要 addon 的仓库测试与构建之前显式编译当前宿主 addon。Native CI 构建完整平台产物,并让相同 addon 字节跨 Node 版本测试;Linux 还在 Alpine 中执行 musl 产物。平台 prepack 拒绝格式错误或不完整的二进制,离线 npm 安装演练检查安装字节与真实锁行为。Native [测试](../../../../native/system/test/flock.test.js) 覆盖描述符与进程竞争、关闭和崩溃释放、独立 errno 值及 worker 清理。
+
+## Alternatives considered
+
+**保留 NAN,为每个 Node ABI 发布构建。** 这会为仅需稳定 Node-API 操作的绑定保留 Node 主版本构建矩阵。已评估的 `fs-ext-extra-prebuilt@2.2.14` 在 Node 26 ABI147 下选中 Node 25 ABI141 二进制;默认安装回退还会在 NAN 被提升安装时提前退出而不编译。
+
+**将 fs-ext 打入父包 tarball。** npm 默认仍执行 bundled 依赖的安装钩子。仅打包既不能禁止编译,也不能让一个二进制跨操作系统、CPU、libc 实现或 Node ABI 通用。
+
+**将 flock 换成 OFD/fcntl 锁。** 在普通 Linux 文件系统上,这些锁不一定排斥既有 flock 持有者。tmpfs 探针在 fs-ext 持有 flock 时仍取得 OFD 锁,因此这不是保持行为的替换。
+
+**通过 koffi 执行 POSIX 调用。** 同步调用改变事件循环的阻塞行为;在异步回调后读取 errno 会读到错误线程的值。原生 async-work 适配器把系统调用结果和 errno 保存在一起,无须另加 FFI 协调层。
+
+## Consequences
+
+包族维护小型 C 绑定、平台构建和安装产物验证,而不是整套文件系统扩展 API。Node-API 消除按 Node 主版本分发二进制的要求,但不消除操作系统、CPU 和 libc 要求。统一原生发布包含两项能力,但导入或使用其中一项不会加载另一项。Landlock 二进制语义、Windows 锁和已发布 Session 数据格式保持不变。

+ 2 - 2
.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-06-sandbox.md
-2026-07-06-sandbox.md: a6e5639e21ca7140cb0314c9918319e99b1495f6
-2026-07-06-sandbox.zh.md: 5144b3fa719465707d7fb2870d45094b8c07661a
+2026-07-06-sandbox.md: 31d96836ad2f932f2abf7d1d76242a711f0de2f6
+2026-07-06-sandbox.zh.md: fdf5f4b1691b4a55fffbd206847c99307e12c9da

+ 1 - 1
.agents/notes/implemented/feature/2026-07-06-sandbox.md

@@ -64,7 +64,7 @@ Left open, for the phase that needs them: whether network restriction arrives as
 
 The launcher is a ~300-line C program (plain C11 over the raw Landlock UAPI — no libraries beyond a statically linked musl, so the audit surface is that one file plus the kernel's stable syscall contract): `--ro <path>` / `--rw <path>` grants, `--`, the wrapped argv; it installs the ruleset on itself and `exec`s (rulesets are inherited across `execve`, and it sets `no_new_privs` before restricting); `--probe` enforces a maximal ruleset in a short-lived child and exits 0 only when the kernel actually enforces; every launcher failure exits 125 without running the child and prints a fatal `landlock-run:` line. A successfully exec'd child may also return 125, so status alone is not launcher evidence. An older ABI prints the exact `landlock-run: partial enforcement (older Landlock ABI)` notice before it executes the child, so that line is not fatal evidence.
 
-The Landlock launcher source and package family live at `native/landlock-run`, next to the harness consumers and inside the root pnpm workspace. The [`native/` README](../../../../native/README.md) owns the shared lockfile, native build, pack rehearsal, and npm publication boundary. Platform binaries are selected by npm, and the entry package owns path resolution, probing, CLI flags, the fatal prefix, and the partial-enforcement notice while the harness maps sandbox modes to grants. Versioning the entry point with its binaries keeps probe parsing and launch syntax aligned.
+The Landlock launcher source and package family live at `native/system`, next to the harness consumers and inside the root pnpm workspace. The [`native/` README](../../../../native/README.md) owns the shared lockfile, native build, pack rehearsal, and npm publication boundary. Platform binaries are selected by npm, and the entry package owns path resolution, probing, CLI flags, the fatal prefix, and the partial-enforcement notice while the harness maps sandbox modes to grants. Versioning the entry point with its binaries keeps probe parsing and launch syntax aligned.
 
 Backend profiles share the mode contract but differ in necessary host grants. Landlock and Seatbelt allow only `/dev/null` in read-only mode; workspace-write also permits their required host temp roots. Each wrap carries backend-specific denial signatures. Landlock reports partial enforcement on older ABIs that cannot govern every operation, while successful bwrap and Seatbelt profiles report full enforcement.
 

+ 1 - 1
.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md

@@ -64,7 +64,7 @@ OS 子进程约束适用于 bash 执行器(包括钩子命令),后续还
 
 launcher 是一个约 300 行的 C 程序(纯 C11,直接使用 Landlock UAPI——除静态链接的 musl 外无其他库,因此审计面仅为该文件加内核的稳定 syscall 约定):`--ro <path>` / `--rw <path>` 授权,`--`,被包装的 argv;它为自身安装规则集并执行 `exec`(规则集跨 `execve` 继承,且它在限制前设置 `no_new_privs`);`--probe` 在一个短生命周期子进程中强制最大规则集,仅当内核确实强制时才以 0 退出;所有 launcher 失败都会以 125 退出且不运行子进程,并打印一行致命的 `landlock-run:` 诊断。成功完成 exec 的子进程也可能返回 125,因此仅凭退出状态不能作为 launcher 失败的证据。较旧的 ABI 会在执行子进程之前打印精确的 `landlock-run: partial enforcement (older Landlock ABI)` 通知,因此该行不是致命证据。
 
-Landlock launcher 源码和包家族位于 `native/landlock-run`,与 harness 消费方同仓,并属于根 pnpm workspace。[`native/` README](../../../../native/README.zh.md)负责共享锁文件、原生构建、打包演练和 npm 发布边界。平台二进制由 npm 选择,入口包拥有路径解析、探测、CLI(命令行界面)参数、致命前缀和部分强制执行通知,而 harness 将沙箱模式映射为授权。将入口点与其二进制一起版本化,使探测解析和启动语法保持对齐。
+Landlock launcher 源码和包家族位于 `native/system`,与 harness 消费方同仓,并属于根 pnpm workspace。[`native/` README](../../../../native/README.zh.md)负责共享锁文件、原生构建、打包演练和 npm 发布边界。平台二进制由 npm 选择,入口包拥有路径解析、探测、CLI(命令行界面)参数、致命前缀和部分强制执行通知,而 harness 将沙箱模式映射为授权。将入口点与其二进制一起版本化,使探测解析和启动语法保持对齐。
 
 后端 profile 共享模式约定但在必要的主机授权上有所不同。Landlock 和 Seatbelt 在 read-only 模式下仅允许 `/dev/null`;workspace-write 还允许各自所需的主机临时目录根。每次包装携带后端特定的拒绝签名。Landlock 在较旧的 ABI 无法管控所有操作时报告 partial enforcement,而成功的 bwrap 和 Seatbelt profile 报告 full enforcement。
 

+ 2 - 2
.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md
-2026-08-04-claude-code-and-codex-subagent-backends.md: 52665a44b654a50b8dc28f4bbd530a0606f8e2d9
-2026-08-04-claude-code-and-codex-subagent-backends.zh.md: f16d2412826db5d0fd3dcaad1281ccd92acdd26e
+2026-08-04-claude-code-and-codex-subagent-backends.md: d11b200e95cbb0769ad30ae88cb976c7921c80f8
+2026-08-04-claude-code-and-codex-subagent-backends.zh.md: 5899a27bb8ad592d9b83b7d19e681bef375525fb

+ 6 - 6
.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md

@@ -34,21 +34,21 @@ configured tool -> dsh-tool-subagent -> ctx.subagents -> product provider -> pro
 
 ## Codex provider
 
-`@deepseek-ai/dsh-subagent-codex` registers a Profile-selected provider name that defaults to `codex`, resolves the `codex` bin declared by its pinned `@openai/codex@0.149.1` package, and starts that wrapper through the current Node executable with `app-server --stdio`. The wrapper selects the private native platform payload; the provider neither resolves nor falls back to a host `codex`. Its public configuration contains a non-empty `providerName`, an optional non-empty `model`, an explicit `env` overlay, a positive finite `disposeGraceMs` no greater than the repository's shared `MAX_TIMER_DELAY_MS`, and a three-value native `permissionMode` that defaults to `never`. Each named instance retains those resolved values for its own runs. An explicit model is passed unchanged on every ephemeral `thread/start`; omission leaves native Codex settings authoritative. Installation, login, `CODEX_HOME`, model discovery or fallback, base URL, and product-session settings remain native Codex or deployment responsibilities; the selected mode owns only the thread approval/reviewer/sandbox fields described by the non-interactive permissions decision.
+`@deepseek-ai/dsh-subagent-codex` registers a Profile-selected provider name that defaults to `codex`, resolves the `codex` bin declared by its pinned `@openai/codex@0.153.4` package, and starts that wrapper through the current Node executable with `app-server --stdio`. The wrapper selects the private native platform payload; the provider neither resolves nor falls back to a host `codex`. Its public configuration contains a non-empty `providerName`, an optional non-empty `model`, an explicit `env` overlay, a positive finite `disposeGraceMs` no greater than the repository's shared `MAX_TIMER_DELAY_MS`, and a three-value native `permissionMode` that defaults to `never`. Each named instance retains those resolved values for its own runs. An explicit model is passed unchanged on every ephemeral `thread/start`; omission leaves native Codex settings authoritative. Installation, login, `CODEX_HOME`, model discovery or fallback, base URL, and product-session settings remain native Codex or deployment responsibilities; the selected mode owns only the thread approval/reviewer/sandbox fields described by the non-interactive permissions decision.
 
 Before publication, the provider validates a non-empty text-only task, starts the managed app-server in the parent workspace, completes `initialize` → `initialized`, maps the optional model and resolved mode into official `thread/start` fields, and creates an `ephemeral: true` thread. The fixed app-server argv contains no model, mode, or task text. The published run owns exactly one `turn/start`; its thread and turn ids remain private and are never persisted in the parent Session.
 
 `turn/completed` is the authoritative remote terminal fact. The latest `agentMessage` with `phase: "final_answer"` wins, and that selected message must contain nonblank text. When the product emits no explicit final phase, the latest message with `phase: null` is the compatibility fallback and must likewise be nonblank; commentary never replaces either answer. The [minimal-diagnostics decision](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md) owns Codex action categories, HTTP status, lifecycle stages, process outcomes, and stop-reason preservation. Local cancellation remains `aborted` without a failure diagnostic.
 
-For command and file approvals, the unattended wire selects a non-approval decision offered by the request, preferring `cancel`; the stable 0.149.1 request shape without an offered-decision list falls back to `decline`. It grants no requested permissions for the turn, answers user-input requests with no answers, and declines MCP elicitation. It records safe categories for those requests, declined command/file items, and structured `sandboxError` terminals. Product stderr is forwarded unchanged to the Host but is neither classified nor copied into the diagnostic. A request with no legal unattended response, or any unknown server request, fails the run instead of waiting for a user interface the provider does not supply.
+For command and file approvals, the unattended wire selects a non-approval decision offered by the request, preferring `cancel`; a request without an offered-decision list falls back to `decline`. It grants no requested permissions for the turn, answers user-input requests with no answers, and declines MCP elicitation. It records safe categories for those requests, declined command/file items, and structured `sandboxError` terminals. Product stderr is forwarded unchanged to the Host but is neither classified nor copied into the diagnostic. A request with no legal unattended response, or any unknown server request, fails the run instead of waiting for a user interface the provider does not supply.
 
 An unpublished startup failure closes the wire, terminates the acquired process tree, waits for exit, detaches the stderr observer, and then rejects `start()` with its fixed operation stage. Published disposal best-effort interrupts a known turn, closes the wire, ends stdin, invokes the shared termination escalation, waits for whole-tree exit, and detaches the observer. Independent cleanup failure reports `teardown`; when startup and rollback both fail, the aggregate's top message retains both safe stage lines while the underlying causes remain internal.
 
-Codex 0.149.1 speaks the Responses protocol, while DeepSeek's public OpenAI-compatible endpoint speaks Chat Completions. The credentialed Codex e2e therefore uses a loopback-only, test-private bridge for one no-tool nonce request: real Codex sends Responses to the bridge, the bridge forwards the received bearer credential and extracted task to the fixed official DeepSeek endpoint, and it wraps the real text in the minimal Responses SSE lifecycle. The bridge is neither a production proxy nor evidence that Codex connects to DeepSeek Chat Completions natively.
+Codex 0.153.4 speaks the Responses protocol, while DeepSeek's public OpenAI-compatible endpoint speaks Chat Completions. The credentialed Codex e2e therefore uses a loopback-only, test-private bridge for one no-tool nonce request: real Codex sends Responses to the bridge, the bridge forwards the received bearer credential and extracted task to the fixed official DeepSeek endpoint, and it wraps the real text in the minimal Responses SSE lifecycle. The bridge is neither a production proxy nor evidence that Codex connects to DeepSeek Chat Completions natively.
 
 ## Claude Code provider
 
-`@deepseek-ai/dsh-subagent-claude-code` registers a Profile-selected provider name that defaults to `claude-code` and invokes `@anthropic-ai/claude-agent-sdk@0.3.241`. The provider omits `pathToClaudeCodeExecutable`, so the SDK selects Claude Code 2.1.241 from the matching OS, CPU, and Linux-libc platform package in its own optional dependency closure. The provider does not resolve or fall back to a host `claude`; an omitted, unsupported, missing, or damaged platform payload fails the first delegation at the SDK startup boundary. The provider uses the official `query()` entrypoint and passes the SDK's native `claude` or `claude.exe` command, arguments, cwd, environment, and forwarded signal from `spawnClaudeCodeProcess` to `dsh-subprocess`; its private `SpawnedProcess` adapter exposes only the stream, event, kill, and exit facts the SDK requires.
+`@deepseek-ai/dsh-subagent-claude-code` registers a Profile-selected provider name that defaults to `claude-code` and invokes `@anthropic-ai/claude-agent-sdk@0.3.263`. The provider omits `pathToClaudeCodeExecutable`, so the SDK selects Claude Code 2.1.263 from the matching OS, CPU, and Linux-libc platform package in its own optional dependency closure. The provider does not resolve or fall back to a host `claude`; an omitted, unsupported, missing, or damaged platform payload fails the first delegation at the SDK startup boundary. The provider uses the official `query()` entrypoint and passes the SDK's native `claude` or `claude.exe` command, arguments, cwd, environment, and forwarded signal from `spawnClaudeCodeProcess` to `dsh-subprocess`; its private `SpawnedProcess` adapter exposes only the stream, event, kill, and exit facts the SDK requires.
 
 The public configuration contains a non-empty `providerName`, an optional non-empty `model`, an explicit `env` overlay, a positive finite `disposeGraceMs` no greater than the repository's shared `MAX_TIMER_DELAY_MS`, and a five-value native `permissionMode` that defaults to `dontAsk`. Each named instance retains those resolved values for its own runs. An explicit model is passed unchanged through `Options.model`; omission leaves that field absent so native settings choose the model. Each run creates its own `AbortController`, sets `persistSession: false`, disables `AskUserQuestion`, and passes the resolved mode to the SDK; only `bypassPermissions` receives the SDK's explicit dangerous confirmation. The provider deliberately omits `settingSources`, so the SDK reads the host's normal user, project, and local Claude settings relative to the parent Session cwd. It neither copies nor filters those settings and does not create or modify login state. Remaining permission prompts are denied, MCP elicitation is declined, and blocking dialogs fail closed instead of waiting for a user interface the provider does not own.
 
@@ -62,11 +62,11 @@ The credentialed Claude Code e2e uses the official DeepSeek Claude Code contract
 
 Each product owns branch-complete package tests, a required keyless real-product spec, a Loader composition e2e, and a credentialed DeepSeek e2e. The keyless product tier uses the exact official distribution under test, a non-empty fake product key, an isolated temporary workspace and product home, and a loopback fixed-answer model. Missing product requests, wrong authentication, altered task text, a non-exact answer, a skipped real product, or a surviving managed handle fails the required test. The Codex Loader fixture exposes two named Codex instances and tools; the Claude Code Loader fixture exposes the default Codex tool plus two named Claude Code instances and tools. Both fixtures include generic Job controls and start neither product process. The credentialed tier starts the same production provider and real product with a runtime-only key, requires a unique nonce from the fixed official DeepSeek service, and proves quiescence again; it self-skips only when a local operator supplied no key, while trusted CI preflights the secret.
 
-The Codex evidence pins `@openai/codex@0.149.1`, `codex-cli 0.149.1`, and all six optional platform aliases. Its generated schema proves optional `ThreadStartParams.model`; the real-product spec observes omitted-model inheritance, two explicit instance models, the package-local wrapper argv, exact Bearer key, original task, byte-exact final answer, native permission modes, explicit dangerous-bypass writing in suite-owned temporary storage, and wrapper/native whole-tree exit. An isolated wrapper fixture proves missing-payload failure without host fallback, named instances retain separate models, environments, and modes, and production never resolves a host `codex` from `PATH`. The [minimal-diagnostics decision](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md) owns failure, process-outcome, and final presentation evidence.
+The Codex evidence pins `@openai/codex@0.153.4`, `codex-cli 0.153.4`, and all six optional platform aliases. Its generated schema proves optional `ThreadStartParams.model`; the real-product spec observes omitted-model inheritance, two explicit instance models, the package-local wrapper argv, exact Bearer key, original task, byte-exact final answer, native permission modes, explicit dangerous-bypass writing in suite-owned temporary storage, and wrapper/native whole-tree exit. An isolated wrapper fixture proves missing-payload failure without host fallback, named instances retain separate models, environments, and modes, and production never resolves a host `codex` from `PATH`. The [minimal-diagnostics decision](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md) owns failure, process-outcome, and final presentation evidence.
 
 The Codex credentialed e2e registers the production provider, starts the same real app-server, and requests one random nonce through the test-private bridge described above. It fixes the external endpoint and model, stores no credential or request payload, requires exactly one completed upstream response, compares the trimmed product answer byte-for-byte with the nonce, and waits for every managed handle to exit.
 
-The Claude Code evidence pins Agent SDK 0.3.241, Claude Code 2.1.241, and all eight SDK platform packages. Its real-product spec lets the SDK select the installed payload, asserts that the shared subprocess argv begins with that package's native CLI, and observes omitted-model inheritance, two explicit instance models, the exact `x-api-key`, original task, byte-exact final answer, native permission modes, suite-owned denied and bypassed writes, and whole-tree exit. Package tests prove that production never resolves host `PATH`, omits the executable override, and forwards the SDK-selected Windows `claude.exe` without a batch shim. This evidence proves the pinned official SDK/CLI integration rather than compatibility with independently installed Claude versions; the [minimal-diagnostics decision](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md) owns failure and process-outcome evidence. Loader coverage resolves both products through their optional Bundle patches while starting neither product.
+The Claude Code evidence pins Agent SDK 0.3.263, Claude Code 2.1.263, and all eight SDK platform packages. Its real-product spec lets the SDK select the installed payload, asserts that the shared subprocess argv begins with that package's native CLI, and observes omitted-model inheritance, two explicit instance models, the exact `x-api-key`, original task, byte-exact final answer, native permission modes, suite-owned denied and bypassed writes, and whole-tree exit. Package tests prove that production never resolves host `PATH`, omits the executable override, and forwards the SDK-selected Windows `claude.exe` without a batch shim. This evidence proves the pinned official SDK/CLI integration rather than compatibility with independently installed Claude versions; the [minimal-diagnostics decision](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md) owns failure and process-outcome evidence. Loader coverage resolves both products through their optional Bundle patches while starting neither product.
 
 The Claude Code credentialed e2e maps the key and fixed official endpoint only in the provider's in-memory environment, uses the documented `deepseek-v4-pro[1m]` and `deepseek-v4-flash` model variables, and traverses the production provider, official SDK, and real CLI. It compares the trimmed result with a random nonce and proves whole-tree exit without calling the Messages API directly from the test.
 

+ 6 - 6
.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.zh.md

@@ -34,21 +34,21 @@ configured tool -> dsh-tool-subagent -> ctx.subagents -> product provider -> pro
 
 ## Codex 提供方
 
-`@deepseek-ai/dsh-subagent-codex` 注册由 Profile 选择、默认值为 `codex` 的提供方名称,解析锁定的 `@openai/codex@0.149.1` 包所声明的 `codex` bin,并使用当前 Node 可执行文件加 `app-server --stdio` 启动该 wrapper。Wrapper 会选择私有原生平台载荷;提供方既不解析也不回退宿主 `codex`。其公开配置包含非空的 `providerName`、可选的非空 `model`、显式的 `env` 覆盖项、须为正有限值且不得大于仓库共享 `MAX_TIMER_DELAY_MS` 的 `disposeGraceMs`,以及默认使用 `never` 的三值原生 `permissionMode`。每个命名实例会为自己的运行保留这些已解析值。显式模型会原样传给每个临时 `thread/start`;省略时仍以 Codex 原生设置为权威。安装、登录、`CODEX_HOME`、模型发现或 fallback、基础 URL 和产品会话设置仍由 Codex 原生机制或部署环境负责;所选模式只拥有非交互权限决策中描述的线程 approval/reviewer/sandbox 字段。
+`@deepseek-ai/dsh-subagent-codex` 注册由 Profile 选择、默认值为 `codex` 的提供方名称,解析锁定的 `@openai/codex@0.153.4` 包所声明的 `codex` bin,并使用当前 Node 可执行文件加 `app-server --stdio` 启动该 wrapper。Wrapper 会选择私有原生平台载荷;提供方既不解析也不回退宿主 `codex`。其公开配置包含非空的 `providerName`、可选的非空 `model`、显式的 `env` 覆盖项、须为正有限值且不得大于仓库共享 `MAX_TIMER_DELAY_MS` 的 `disposeGraceMs`,以及默认使用 `never` 的三值原生 `permissionMode`。每个命名实例会为自己的运行保留这些已解析值。显式模型会原样传给每个临时 `thread/start`;省略时仍以 Codex 原生设置为权威。安装、登录、`CODEX_HOME`、模型发现或 fallback、基础 URL 和产品会话设置仍由 Codex 原生机制或部署环境负责;所选模式只拥有非交互权限决策中描述的线程 approval/reviewer/sandbox 字段。
 
 发布前,提供方会验证非空的纯文本任务,在父级工作区中启动受管的 app-server,完成 `initialize` → `initialized` 握手,把可选模型与已解析模式映射为官方 `thread/start` 字段,并创建一个 `ephemeral: true` 线程。固定 app-server argv 不包含模型、模式或任务文本。已发布的运行只拥有一次 `turn/start`;其线程 ID 与轮次 ID 保持私有,绝不会持久化到父会话。
 
 `turn/completed` 是权威的远端终止事实。以最后一条带有 `phase: "final_answer"` 的 `agentMessage` 为准,且选中的消息必须包含非空白文本。若产品没有发出明确的最终阶段,则以最后一条 `phase: null` 的消息作为兼容性回退,该消息也必须包含非空白文本;过程说明绝不会取代上述任一答案。[最小诊断决策](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md)负责 Codex 行动类别、HTTP status、生命周期阶段、进程结果与终止原因保持。本地取消仍是 `aborted` 且不附带失败诊断。
 
-对于命令与文件审批,无人值守的协议连接会从请求给出的决策选项中选择一项不予批准的决策,并优先选择 `cancel`;稳定的 0.149.1 请求形态没有决策选项列表,因此回退到 `decline`。它不授予该轮次请求的任何权限,不向用户输入请求提供任何答案,并拒绝 MCP elicitation。它会记录这些请求、被拒绝的命令/文件 item 与结构化 `sandboxError` 终态的安全类别。产品 stderr 会原样转发给 Host,但既不会被分类,也不会复制进诊断。若请求在无人值守模式下没有合法响应,或是未知服务器请求,此次运行就会失败,而不会等待本提供方没有提供的用户界面。
+对于命令与文件审批,无人值守的协议连接会从请求给出的决策选项中选择一项不予批准的决策,并优先选择 `cancel`;若请求没有决策选项列表,则回退到 `decline`。它不授予该轮次请求的任何权限,不向用户输入请求提供任何答案,并拒绝 MCP elicitation。它会记录这些请求、被拒绝的命令/文件 item 与结构化 `sandboxError` 终态的安全类别。产品 stderr 会原样转发给 Host,但既不会被分类,也不会复制进诊断。若请求在无人值守模式下没有合法响应,或是未知服务器请求,此次运行就会失败,而不会等待本提供方没有提供的用户界面。
 
 若启动在发布前失败,提供方会关闭协议连接、终止已获取的进程树、等待其退出、移除 stderr observer,然后用固定操作阶段拒绝 `start()`。对已发布的运行执行资源释放时,提供方会尽力中断已知轮次、关闭协议连接、结束标准输入、调用共享的逐级终止机制,等待整棵进程树退出,并移除 observer。独立清理失败会报告 `teardown`;启动与回滚同时失败时,聚合的顶层消息会保留两条安全阶段说明,而底层 cause 仍只在内部可见。
 
-Codex 0.149.1 使用 Responses 协议,而 DeepSeek 的公开 OpenAI 兼容端点使用 Chat Completions。因此,带密钥 Codex e2e 会采用一个仅限回环、仅供测试内部使用的桥接层来处理一次不使用工具的随机数请求:真实 Codex 将 Responses 发送到桥接层,桥接层把收到的 Bearer 凭据与提取出的任务转发到固定的 DeepSeek 官方端点,再将真实文本包装进最小化的 Responses SSE(Server-Sent Events)生命周期。该桥接层既不是生产代理,也不能作为 Codex 原生连接 DeepSeek Chat Completions 的证据。
+Codex 0.153.4 使用 Responses 协议,而 DeepSeek 的公开 OpenAI 兼容端点使用 Chat Completions。因此,带密钥 Codex e2e 会采用一个仅限回环、仅供测试内部使用的桥接层来处理一次不使用工具的随机数请求:真实 Codex 将 Responses 发送到桥接层,桥接层把收到的 Bearer 凭据与提取出的任务转发到固定的 DeepSeek 官方端点,再将真实文本包装进最小化的 Responses SSE(Server-Sent Events)生命周期。该桥接层既不是生产代理,也不能作为 Codex 原生连接 DeepSeek Chat Completions 的证据。
 
 ## Claude Code 提供方
 
-`@deepseek-ai/dsh-subagent-claude-code` 注册由 Profile 选择、默认值为 `claude-code` 的提供方名称,并调用 `@anthropic-ai/claude-agent-sdk@0.3.241`。提供方会省略 `pathToClaudeCodeExecutable`,因此 SDK 会从自己的 optional dependency 闭包中,按操作系统、CPU 与 Linux libc 选择携带 Claude Code 2.1.241 的匹配平台包。提供方既不会解析也不会回退宿主 `claude`;省略 optional dependency、不受支持的平台,以及缺失或损坏的平台载荷,都会在第一次委派的 SDK 启动边界失败。提供方使用官方 `query()` 入口点,并把 SDK 的 `spawnClaudeCodeProcess` 给出的原生 `claude` 或 `claude.exe` 命令、参数、cwd、环境和转发的信号交给 `dsh-subprocess`;其私有 `SpawnedProcess` 适配器只公开 SDK 所需的流、事件、终止和退出事实。
+`@deepseek-ai/dsh-subagent-claude-code` 注册由 Profile 选择、默认值为 `claude-code` 的提供方名称,并调用 `@anthropic-ai/claude-agent-sdk@0.3.263`。提供方会省略 `pathToClaudeCodeExecutable`,因此 SDK 会从自己的 optional dependency 闭包中,按操作系统、CPU 与 Linux libc 选择携带 Claude Code 2.1.263 的匹配平台包。提供方既不会解析也不会回退宿主 `claude`;省略 optional dependency、不受支持的平台,以及缺失或损坏的平台载荷,都会在第一次委派的 SDK 启动边界失败。提供方使用官方 `query()` 入口点,并把 SDK 的 `spawnClaudeCodeProcess` 给出的原生 `claude` 或 `claude.exe` 命令、参数、cwd、环境和转发的信号交给 `dsh-subprocess`;其私有 `SpawnedProcess` 适配器只公开 SDK 所需的流、事件、终止和退出事实。
 
 公开配置包含非空的 `providerName`、可选的非空 `model`、显式的 `env` 覆盖项、须为正有限值且不得大于仓库共享 `MAX_TIMER_DELAY_MS` 的 `disposeGraceMs`,以及默认使用 `dontAsk` 的五值原生 `permissionMode`。每个命名实例会为自己的运行保留这些已解析值。显式模型会原样传入 `Options.model`;省略时不设置该字段,由原生设置选择模型。每次运行都会创建自己的 `AbortController`,设置 `persistSession: false`、禁用 `AskUserQuestion`,并把已解析模式传给 SDK;只有 `bypassPermissions` 会取得 SDK 的显式危险确认。提供方故意省略 `settingSources`,因此 SDK 会相对于父会话 cwd 读取宿主机常规的用户、项目和本地 Claude 设置。它既不复制也不过滤这些设置,也不会创建或修改登录状态。其余权限提示会被拒绝,MCP elicitation 会被拒绝,阻塞对话会快速失败,而不会等待本提供方不负责的用户界面。
 
@@ -62,11 +62,11 @@ Codex 0.149.1 使用 Responses 协议,而 DeepSeek 的公开 OpenAI 兼容端
 
 每个产品都负责覆盖所有分支的包测试、一项必跑的无密钥真实产品测试、一项 Loader 组合 e2e 和一项带密钥 DeepSeek e2e。无密钥产品层级使用被测的确切官方发行版、非空的伪产品密钥、隔离的临时工作区与产品主目录,以及能返回固定答案的回环模型。产品请求缺失、身份验证错误、任务文本被改动、答案不完全一致、真实产品被跳过或受管句柄仍存活,都会使这项必跑测试失败。Codex Loader fixture 会公开两个命名 Codex 实例与工具;Claude Code Loader fixture 会公开默认 Codex 工具以及两个命名 Claude Code 实例与工具。两个 fixture 都包含通用 Job 控制工具,而且不会启动任何产品进程。带密钥层级会使用仅在运行时提供的密钥启动同一生产提供方与真实产品,要求从固定的 DeepSeek 官方服务取得唯一随机数,并再次证明完全停稳;仅当本地操作者未提供密钥时才会自行跳过,而受信任的 CI 会预检该 secret。
 
-Codex 证据会锁定 `@openai/codex@0.149.1`、`codex-cli 0.149.1` 与六个平台 alias。生成 schema 会证明可选的 `ThreadStartParams.model`;真实产品测试会观测省略模型继承、两个显式实例模型、包内 wrapper argv、确切的 Bearer 密钥、原始任务、逐字节完全一致的最终回答、原生权限模式、测试拥有临时存储中的显式危险绕过写入,以及 wrapper/原生整棵进程树退出。独立 wrapper fixture 会证明载荷缺失时不回退宿主命令,命名实例会保留彼此独立的模型、环境与模式,生产环境也不会从 `PATH` 解析宿主 `codex`。[最小诊断决策](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md)负责失败、进程结果与最终呈现证据。
+Codex 证据会锁定 `@openai/codex@0.153.4`、`codex-cli 0.153.4` 与六个平台 alias。生成 schema 会证明可选的 `ThreadStartParams.model`;真实产品测试会观测省略模型继承、两个显式实例模型、包内 wrapper argv、确切的 Bearer 密钥、原始任务、逐字节完全一致的最终回答、原生权限模式、测试拥有临时存储中的显式危险绕过写入,以及 wrapper/原生整棵进程树退出。独立 wrapper fixture 会证明载荷缺失时不回退宿主命令,命名实例会保留彼此独立的模型、环境与模式,生产环境也不会从 `PATH` 解析宿主 `codex`。[最小诊断决策](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md)负责失败、进程结果与最终呈现证据。
 
 带密钥 Codex e2e 会注册生产提供方,启动同样的真实 app-server,并通过上述测试专用桥接层请求一个随机数。该测试固定外部端点与模型,不存储任何凭据或请求载荷,要求上游恰好完成一次响应,将去除首尾空白后的产品答案与该随机数逐字节比较,并等待所有受管句柄退出。
 
-Claude Code 证据会锁定 Agent SDK 0.3.241、Claude Code 2.1.241 与八个 SDK 平台包。真实产品测试会让 SDK 选择已安装载荷,断言共享子进程 argv 以该包的原生 CLI 开头,并观测省略模型继承、两个显式实例模型、确切的 `x-api-key`、原始任务、逐字节完全一致的最终回答、原生权限模式、测试拥有范围内的拒绝写入与 bypass 写入,以及整棵进程树退出。包测试还会证明生产运行从不解析宿主 `PATH`、省略可执行文件覆盖,并直接转发 SDK 所选的 Windows `claude.exe` 而不经过 batch shim。这项证据证明锁定的官方 SDK/CLI 集成,而不证明与独立安装的 Claude 版本兼容;[最小诊断决策](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md)负责失败与进程结果证据。Loader 覆盖会通过各自的可选 Bundle patch 解析两个产品,且不会启动任一产品。
+Claude Code 证据会锁定 Agent SDK 0.3.263、Claude Code 2.1.263 与八个 SDK 平台包。真实产品测试会让 SDK 选择已安装载荷,断言共享子进程 argv 以该包的原生 CLI 开头,并观测省略模型继承、两个显式实例模型、确切的 `x-api-key`、原始任务、逐字节完全一致的最终回答、原生权限模式、测试拥有范围内的拒绝写入与 bypass 写入,以及整棵进程树退出。包测试还会证明生产运行从不解析宿主 `PATH`、省略可执行文件覆盖,并直接转发 SDK 所选的 Windows `claude.exe` 而不经过 batch shim。这项证据证明锁定的官方 SDK/CLI 集成,而不证明与独立安装的 Claude 版本兼容;[最小诊断决策](../../archived/simplification/2026-08-21-product-subagent-minimal-diagnostics.md)负责失败与进程结果证据。Loader 覆盖会通过各自的可选 Bundle patch 解析两个产品,且不会启动任一产品。
 
 带密钥 Claude Code e2e 仅在提供方的内存环境中映射密钥与固定的官方端点,把模型变量设为文档所示的 `deepseek-v4-pro[1m]` 与 `deepseek-v4-flash`,并实际经过生产提供方、官方 SDK 与真实 CLI。它将去除首尾空白后的结果与一个随机数比较,并证明整棵进程树退出,且测试不会直接调用 Messages API。
 

+ 2 - 2
.agents/notes/implemented/feature/2026-08-15-product-subagent-noninteractive-permissions.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-15-product-subagent-noninteractive-permissions.md
-2026-08-15-product-subagent-noninteractive-permissions.md: 1bdca6214bf730386e27e922361bb45a3c120ecf
-2026-08-15-product-subagent-noninteractive-permissions.zh.md: 9377da8d5f3622f5faafce631ed2c6095d22560c
+2026-08-15-product-subagent-noninteractive-permissions.md: 1ec45f9adafa2364f9d0f37f3914d97054942226
+2026-08-15-product-subagent-noninteractive-permissions.zh.md: 80e99d9ee47da859456faf66560d42e73c88cf3d

+ 2 - 2
.agents/notes/implemented/feature/2026-08-15-product-subagent-noninteractive-permissions.md

@@ -32,7 +32,7 @@ Every query disables `AskUserQuestion`. Non-bypass permission callbacks deny ins
 
 ### Codex
 
-Codex defaults to `never` and accepts the three native non-interactive modes exposed by Codex 0.149.1. The Provider starts the fixed app-server command, then maps the selected mode into official `thread/start` fields because CLI-global permission flags do not configure threads created later by an app-server client:
+Codex defaults to `never` and accepts the three native non-interactive modes exposed by Codex 0.153.4. The Provider starts the fixed app-server command, then maps the selected mode into official `thread/start` fields because CLI-global permission flags do not configure threads created later by an app-server client:
 
 | Value | `thread/start` fields | Native behavior |
 | --- | --- | --- |
@@ -63,7 +63,7 @@ The foreground consumer presents the stop-reason headline, then the optional dia
 
 ## Verification
 
-Package tests pin every allowed and rejected Config value, the exact SDK and app-server field mappings, dangerous confirmations, unattended terminal responses, diagnostic sanitization and UTF-8 bound, successful-result omission, concurrent-run isolation, foreground ordering, Job detail, stderr observer disposal, and process cleanup. The real Claude Agent SDK 0.3.241 and Claude Code 2.1.241 fixture proves its safe default, restricted denial, explicit bypass, and whole-tree quiescence. The real Codex 0.149.1 app-server fixture proves that thread-level `never` overrides ambient `on-request`, automatic review starts, dangerous bypass writes only inside suite-owned temporary storage, a rejected escalation leaves no side effect or raw command or path in the diagnostic, stderr remains Host-only, and the wrapper/native tree exits. Loader composition proves non-default modes can be published without starting either product, and the keyless ACP snapshot records each product's failure diagnostic through foreground and Job presentation while the model-facing product tool schemas contain no permission parameter.
+Package tests pin every allowed and rejected Config value, the exact SDK and app-server field mappings, dangerous confirmations, unattended terminal responses, diagnostic sanitization and UTF-8 bound, successful-result omission, concurrent-run isolation, foreground ordering, Job detail, stderr observer disposal, and process cleanup. The real Claude Agent SDK 0.3.263 and Claude Code 2.1.263 fixture proves its safe default, restricted denial, explicit bypass, and whole-tree quiescence. The real Codex 0.153.4 app-server fixture proves that thread-level `never` overrides ambient `on-request`, automatic review starts, dangerous bypass writes only inside suite-owned temporary storage, a rejected escalation leaves no side effect or raw command or path in the diagnostic, stderr remains Host-only, and the wrapper/native tree exits. Loader composition proves non-default modes can be published without starting either product, and the keyless ACP snapshot records each product's failure diagnostic through foreground and Job presentation while the model-facing product tool schemas contain no permission parameter.
 
 ## Alternatives considered
 

+ 2 - 2
.agents/notes/implemented/feature/2026-08-15-product-subagent-noninteractive-permissions.zh.md

@@ -32,7 +32,7 @@ Claude Code 默认使用 `dontAsk`,而且只接受锁定版本 Agent SDK 支
 
 ### Codex
 
-Codex 默认使用 `never`,并接受 Codex 0.149.1 公开的三种原生非交互模式。提供方启动固定的 app-server 命令,再把所选模式映射为官方 `thread/start` 字段,因为 CLI 全局权限 flag 不会配置之后由 app-server 客户端创建的线程:
+Codex 默认使用 `never`,并接受 Codex 0.153.4 公开的三种原生非交互模式。提供方启动固定的 app-server 命令,再把所选模式映射为官方 `thread/start` 字段,因为 CLI 全局权限 flag 不会配置之后由 app-server 客户端创建的线程:
 
 | 值 | `thread/start` 字段 | 原生行为 |
 | --- | --- | --- |
@@ -63,7 +63,7 @@ Codex 默认使用 `never`,并接受 Codex 0.149.1 公开的三种原生非交
 
 ## Verification
 
-包测试固定所有允许与拒绝的 Config 值、准确的 SDK 与 app-server 字段映射、危险确认、无人值守终态、诊断脱敏与 UTF-8 上限、成功结果不携带诊断、并发运行隔离、前台顺序、Job detail、stderr observer 释放和进程清理。真实 Claude Agent SDK 0.3.241 与 Claude Code 2.1.241 fixture 证明其安全默认、受限拒绝、显式 bypass 与整棵进程树完全停稳。真实 Codex 0.149.1 app-server fixture 证明线程级 `never` 覆盖环境中的 `on-request`、自动评审可以启动、危险绕过只在测试拥有的临时存储中写入、被拒绝的提权不会留下副作用且诊断不含原始命令或路径、stderr 只供 Host 观测,而且 wrapper/native 进程树会退出。Loader 组装证明非默认模式可以在不启动任一产品的情况下发布;无密钥 ACP snapshot 则记录每个产品的失败诊断如何经过前台与 Job 呈现,同时面向模型的产品工具 schema 不包含权限参数。
+包测试固定所有允许与拒绝的 Config 值、准确的 SDK 与 app-server 字段映射、危险确认、无人值守终态、诊断脱敏与 UTF-8 上限、成功结果不携带诊断、并发运行隔离、前台顺序、Job detail、stderr observer 释放和进程清理。真实 Claude Agent SDK 0.3.263 与 Claude Code 2.1.263 fixture 证明其安全默认、受限拒绝、显式 bypass 与整棵进程树完全停稳。真实 Codex 0.153.4 app-server fixture 证明线程级 `never` 覆盖环境中的 `on-request`、自动评审可以启动、危险绕过只在测试拥有的临时存储中写入、被拒绝的提权不会留下副作用且诊断不含原始命令或路径、stderr 只供 Host 观测,而且 wrapper/native 进程树会退出。Loader 组装证明非默认模式可以在不启动任一产品的情况下发布;无密钥 ACP snapshot 则记录每个产品的失败诊断如何经过前台与 Job 呈现,同时面向模型的产品工具 schema 不包含权限参数。
 
 ## Alternatives considered
 

+ 2 - 2
.agents/notes/implemented/feature/2026-08-31-cross-process-session-write-lease.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-31-cross-process-session-write-lease.md
-2026-08-31-cross-process-session-write-lease.md: 174c5152ea62e01e30ade9a68b6786638acb8ada
-2026-08-31-cross-process-session-write-lease.zh.md: e4246f12f7ed8d8b304ca7f7514117f03f32267b
+2026-08-31-cross-process-session-write-lease.md: ef8ebe2de6b231075dee31a9184bcc0a5b323011
+2026-08-31-cross-process-session-write-lease.zh.md: 8a79b6d5327c7bd5d0ca12ac435140bc0951e993

+ 3 - 3
.agents/notes/implemented/feature/2026-08-31-cross-process-session-write-lease.md

@@ -10,7 +10,7 @@ The JSONL backend's write-handle claim excluded a second writer only inside one
 
 ## Decision
 
-`SessionWriteLease` (packages/session/session-persistence-jsonl/src/lease.ts) holds a kernel lock on `session.lock` beside the log for the whole life of a write handle: POSIX takes a non-blocking `flock(2)` through the pinned native dependency `fs-ext`, and Windows holds a named kernel semaphore (count 1) derived from the canonical lock path (`CreateSemaphoreW` in src/win32.ts beside the existing koffi bindings) — a kernel object with no filesystem footprint, destroyed with its last handle. Contention maps to `SessionAlreadyOwnedError`; the kernel releases the lock when the holder's descriptor or handle closes, including on any process death, so a crashed holder never blocks a successor and no expiry bookkeeping exists. A live but wedged holder keeps the lock until its process exits: expropriating a stalled writer was rejected because its resumed appends would tear the log, and on POSIX removing the lock file remains the explicit forfeit for that case. Because a POSIX lock names an inode rather than a path, acquisition verifies the locked inode is still the file at the lock path and retries otherwise. The lock is taken at write-open of an existing artifact and, for a created session, only right before its first materializing write — an unmaterialized session leaves no filesystem footprint, and a handle that acquired the lock keeps it through close even when materialization fails; release never removes the lock file, preserving the stable inode later lockers verify against. The browser worker deployment stubs fs-ext to immediate success: it is single-process, so the in-process write claim already excludes every writer.
+`SessionWriteLease` (packages/session/session-persistence-jsonl/src/lease.ts) holds a kernel lock on `session.lock` beside the log for the whole life of a write handle: POSIX takes a non-blocking `flock(2)` through the prebuilt `@deepseek-ai/node-addon-system/flock` binding, and Windows holds a named kernel semaphore (count 1) derived from the canonical lock path (`CreateSemaphoreW` in src/win32.ts beside the existing koffi bindings) — a kernel object with no filesystem footprint, destroyed with its last handle. Contention maps to `SessionAlreadyOwnedError`; the kernel releases the lock when the holder's descriptor or handle closes, including on any process death, so a crashed holder never blocks a successor and no expiry bookkeeping exists. A live but wedged holder keeps the lock until its process exits: expropriating a stalled writer was rejected because its resumed appends would tear the log, and on POSIX removing the lock file remains the explicit forfeit for that case. Because a POSIX lock names an inode rather than a path, acquisition verifies the locked inode is still the file at the lock path and retries otherwise. The lock is taken at write-open of an existing artifact and, for a created session, only right before its first materializing write — an unmaterialized session leaves no filesystem footprint, and a handle that acquired the lock keeps it through close even when materialization fails; release never removes the lock file, preserving the stable inode later lockers verify against. The browser worker deployment stubs the flock entry to immediate success: it is single-process, so the in-process write claim already excludes every writer.
 
 ## Alternatives considered
 
@@ -22,8 +22,8 @@ The JSONL backend's write-handle claim excluded a second writer only inside one
 
 **Windows exclusive-open sharing mode (`CreateFileW` denying `FILE_SHARE_WRITE`)** — leaves readers untouched but pins the lock file's name and directory while held: CI showed dozens of suites failing their temp-root cleanup with EBUSY because a still-open handle blocks recursive removal, and users deleting a session directory would hit the same wall. The named semaphore keeps kernel arbitration with zero filesystem footprint.
 
-**Hand-rolled ffi for POSIX too (`flock(2)` via koffi)** — avoids the node-gyp install-time build, but means owning both platform lock implementations plus their error mapping; `fs-ext` ships the POSIX code maintained and pinned, and the Windows side reuses the koffi bindings `win32.ts` already owns.
+**Hand-rolled ffi for POSIX too (`flock(2)` via koffi)** — binding selection and asynchronous errno handling are governed by the [prebuilt system primitives decision](../architecture/2026-09-07-prebuilt-system-primitives.md). The Windows side retains the koffi bindings `win32.ts` already owns.
 
 ## Consequences
 
-Cross-process exclusion costs a node-gyp-compiled native dependency (`fs-ext`, allow-listed in `pnpm-workspace.yaml` `allowBuilds`), one lock file per materialized session that release deliberately leaves in place, and the wedged-holder rule: a stuck process blocks that session's writers until it exits. It buys immediate crash recovery (no waiting period), no renewal traffic, and the removal of every takeover race the TTL design managed rather than prevented. Advisory `flock` is unreliable on some network filesystems (NFSv3); a root on such a mount degrades toward in-process-only exclusion. Deleting a live session's lock file forfeits exclusion on POSIX by design — the harness never does so; the agent-loop resume test uses it deliberately to simulate a wedged first lifecycle, and skips on Windows, where the lock is a kernel object no file operation can forfeit.
+Cross-process exclusion requires the platform's prebuilt system binding, one lock file per materialized session that release deliberately leaves in place, and the wedged-holder rule: a stuck process blocks that session's writers until it exits. It buys immediate crash recovery (no waiting period), no renewal traffic, and the removal of every takeover race the TTL design managed rather than prevented. Advisory `flock` is unreliable on some network filesystems (NFSv3); a root on such a mount degrades toward in-process-only exclusion. Deleting a live session's lock file forfeits exclusion on POSIX by design — the harness never does so; the agent-loop resume test uses it deliberately to simulate a wedged first lifecycle, and skips on Windows, where the lock is a kernel object no file operation can forfeit.

+ 3 - 3
.agents/notes/implemented/feature/2026-08-31-cross-process-session-write-lease.zh.md

@@ -10,7 +10,7 @@ JSONL 后端的写句柄认领只在单个后端实例内部排除第二个写
 
 ## Decision
 
-`SessionWriteLease`(packages/session/session-persistence-jsonl/src/lease.ts)在日志旁的 `session.lock` 上持有内核锁,贯穿写句柄的整个生命期:POSIX 经由固定版本的原生依赖 `fs-ext` 以非阻塞 `flock(2)` 加锁,Windows 持有由规范锁路径派生的命名内核信号量(计数 1,`CreateSemaphoreW`,实现在 src/win32.ts 既有 koffi 绑定旁)——零文件系统足迹的内核对象,随最后一个句柄关闭而销毁。竞争映射为 `SessionAlreadyOwnedError`;持有者的描述符或句柄关闭时内核释放锁,包括任何形式的进程死亡,因此崩溃的持有者从不阻塞后继者,也不存在任何过期簿记。活着但卡死的持有者保有锁直到其进程退出:剥夺停顿写入方的所有权被否决,因为其复活后的追加会撕坏日志;POSIX 上删除锁文件仍是该场景的显式放弃手段。由于 POSIX 锁指向 inode 而非路径,获取后会校验所锁 inode 仍是锁路径上的文件,否则重试。锁在写打开既有工件时立即获取,新建会话则仅在首次物化写入之前获取——未物化的会话不留任何文件系统足迹,已取得锁的句柄即使物化失败也保有锁直到关闭;释放从不删除锁文件,保住后续加锁者用于校验的稳定 inode。浏览器 worker 部署将 fs-ext 存根为立即成功:它是单进程部署,进程内写认领已排除所有写入方。
+`SessionWriteLease`(packages/session/session-persistence-jsonl/src/lease.ts)在日志旁的 `session.lock` 上持有内核锁,贯穿写句柄的整个生命期:POSIX 经由预编译 `@deepseek-ai/node-addon-system/flock` 绑定 以非阻塞 `flock(2)` 加锁,Windows 持有由规范锁路径派生的命名内核信号量(计数 1,`CreateSemaphoreW`,实现在 src/win32.ts 既有 koffi 绑定旁)——零文件系统足迹的内核对象,随最后一个句柄关闭而销毁。竞争映射为 `SessionAlreadyOwnedError`;持有者的描述符或句柄关闭时内核释放锁,包括任何形式的进程死亡,因此崩溃的持有者从不阻塞后继者,也不存在任何过期簿记。活着但卡死的持有者保有锁直到其进程退出:剥夺停顿写入方的所有权被否决,因为其复活后的追加会撕坏日志;POSIX 上删除锁文件仍是该场景的显式放弃手段。由于 POSIX 锁指向 inode 而非路径,获取后会校验所锁 inode 仍是锁路径上的文件,否则重试。锁在写打开既有工件时立即获取,新建会话则仅在首次物化写入之前获取——未物化的会话不留任何文件系统足迹,已取得锁的句柄即使物化失败也保有锁直到关闭;释放从不删除锁文件,保住后续加锁者用于校验的稳定 inode。浏览器 worker 部署将 flock 入口存根为立即成功:它是单进程部署,进程内写认领已排除所有写入方。
 
 ## Alternatives considered
 
@@ -22,8 +22,8 @@ JSONL 后端的写句柄认领只在单个后端实例内部排除第二个写
 
 **Windows 共享模式独占打开(`CreateFileW` 拒绝 `FILE_SHARE_WRITE`)** —— 读者不受影响,但持有期间钉住锁文件的名字与目录:CI 显示数十个套件的临时根清理因仍打开的句柄阻塞递归删除而报 EBUSY,用户删除会话目录也会撞上同一堵墙。命名信号量保住内核仲裁,且文件系统足迹为零。
 
-**POSIX 也手写 ffi(经 koffi 调 `flock(2)`)** —— 免去 node-gyp 安装期编译,但意味着自有两个平台的锁实现及其错误映射;`fs-ext` 交付了有维护、可固定版本的 POSIX 侧,Windows 侧复用 `win32.ts` 已自有的 koffi 绑定。
+**POSIX 也手写 ffi(经 koffi 调 `flock(2)`)** —— 绑定选择与异步 errno 处理由[预编译系统原语决策](../architecture/2026-09-07-prebuilt-system-primitives.zh.md)规定。Windows 侧保留 `win32.ts` 已有的 koffi 绑定。
 
 ## Consequences
 
-跨进程排他的代价是一个 node-gyp 编译的原生依赖(`fs-ext`,已在 `pnpm-workspace.yaml` 的 `allowBuilds` 列入允许)、每个物化会话一个由释放刻意留下的锁文件,以及卡死持有者规则:卡住的进程阻塞该会话的写入方直到其退出。它换来的是即时崩溃恢复(无等待期)、零续约流量,以及删除了 TTL 设计只能"管理"而非"消除"的全部接管竞态。咨询式 `flock` 在部分网络文件系统(NFSv3)上不可靠;位于此类挂载上的根目录会退化为仅进程内排他。POSIX 上删除活跃会话的锁文件按设计即放弃排他——harness 自身从不这样做;agent-loop 的 resume 测试刻意用它模拟卡死的第一个生命周期,并在 Windows 上跳过:那里的锁是任何文件操作都无法放弃的内核对象。
+跨进程排他需要对应平台的预编译系统绑定、每个物化会话一个由释放刻意留下的锁文件,以及卡死持有者规则:卡住的进程阻塞该会话的写入方直到其退出。它换来的是即时崩溃恢复(无等待期)、零续约流量,以及删除了 TTL 设计只能"管理"而非"消除"的全部接管竞态。咨询式 `flock` 在部分网络文件系统(NFSv3)上不可靠;位于此类挂载上的根目录会退化为仅进程内排他。POSIX 上删除活跃会话的锁文件按设计即放弃排他——harness 自身从不这样做;agent-loop 的 resume 测试刻意用它模拟卡死的第一个生命周期,并在 Windows 上跳过:那里的锁是任何文件操作都无法放弃的内核对象。

+ 2 - 2
.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md
-2026-08-08-native-windows-pull-request-ci.md: ba63af5a8f1d32035e116b3900eb9d5905f326d0
-2026-08-08-native-windows-pull-request-ci.zh.md: 3a0c8f510f2f8881833633f69d8ac5d7330d5195
+2026-08-08-native-windows-pull-request-ci.md: 690f8e6f9b13fa7e72240a42ff482bd83f9088b0
+2026-08-08-native-windows-pull-request-ci.zh.md: 9efa3cbcf33b6c12e4eed253b6a0546c79b768fe

+ 1 - 1
.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md

@@ -32,7 +32,7 @@ Windows durable JSONL paths keep drive roots in native spelling and apply the ex
 
 Post-boot profile watcher setup proceeds only while the root fiber and Loader are both live. A concurrent setup error is contained only when the same invocation's recorded signal already owns shutdown; unrelated HMR failures remain loud. The [process-shutdown controller](../bug-fix/2026-08-03-cli-signal-shutdown-escalation.md) lets a successful one-shot completion drain Node's remaining handles after root disposal, while teardown failure, deadline, and signal escalation retain forced exit. The vendored Include serializes debounced writes, retries only transient access or busy failures with bounded backoff, and observes every timer rejection. A terminal persistence failure remains on the queue and is rethrown to the teardown owner, while successful teardown drains the latest write.
 
-Shiki disables lazy TextMate-regex compilation and warms each boot grammar before user content enters the unchanged per-line tokenization budget, so scheduler contention cannot publish a partial highlighted stream. The Codex real-product fixture is pinned to stable 0.149.1 schemas and selects an actually advertised command tool and argument shape, preserving the provider-owned protocol while proving unattended rejection and whole-tree exit on each host.
+Shiki disables lazy TextMate-regex compilation and warms each boot grammar before user content enters the unchanged per-line tokenization budget, so scheduler contention cannot publish a partial highlighted stream. The Codex real-product fixture is pinned to stable 0.153.4 schemas and selects an actually advertised command tool and argument shape, preserving the provider-owned protocol while proving unattended rejection and whole-tree exit on each host.
 
 ## Alternatives considered
 

+ 1 - 1
.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md

@@ -32,7 +32,7 @@ Windows 的持久 JSONL 路径会保留驱动器根目录的原生写法,并
 
 启动后,只有根 fiber 与 Loader 均处于活跃状态时,系统才会继续设置 profile watcher。只有当同一次调用所记录的信号已取得关闭流程所有权时,系统才会隔离并发设置错误;无关 HMR 故障仍会响亮失败。[进程关闭控制器](../bug-fix/2026-08-03-cli-signal-shutdown-escalation.zh.md)会在根级 dispose 成功后让单次任务的正常完成流程排空 Node 剩余句柄,同时让拆卸失败、截止时间到期和信号升级继续强制退出。vendored Include 会串行化防抖写入,只对瞬时访问或忙碌故障执行有界退避重试,并确保每个由计时器触发的拒绝都得到观察。持久化最终失败后,该故障会保留在队列中,并重新抛给拆卸责任方;成功拆卸则会排空最新写入。
 
-Shiki 会禁用 TextMate 正则的延迟编译,并在用户内容进入保持不变的逐行 tokenization(词元化)预算前预热每种启动语法,从而避免调度器争用发布不完整的高亮流。Codex 真实产品 fixture 固定使用稳定版 0.149.1 schema,并选择实际提供的命令工具与对应参数形态;这样既保留由提供方负责的协议,也能在每种宿主上证明无人值守拒绝和整棵进程树退出。
+Shiki 会禁用 TextMate 正则的延迟编译,并在用户内容进入保持不变的逐行 tokenization(词元化)预算前预热每种启动语法,从而避免调度器争用发布不完整的高亮流。Codex 真实产品 fixture 固定使用稳定版 0.153.4 schema,并选择实际提供的命令工具与对应参数形态;这样既保留由提供方负责的协议,也能在每种宿主上证明无人值守拒绝和整棵进程树退出。
 
 ## 曾考虑的替代方案
 

+ 2 - 2
.agents/notes/implemented/process/2026-08-10-npm-release-sequences.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-10-npm-release-sequences.md
-2026-08-10-npm-release-sequences.md: 6729b506a9cfe7f6d4410dbf0750621901e07293
-2026-08-10-npm-release-sequences.zh.md: 18a30d6dd57c17b8e13cc3a1f71bc91242a391ff
+2026-08-10-npm-release-sequences.md: c403964d8de1c158e5949b5e112a038832709874
+2026-08-10-npm-release-sequences.zh.md: d03da4c4485c4807497dfb28b61ab342bb4c8d12

+ 2 - 2
.agents/notes/implemented/process/2026-08-10-npm-release-sequences.md

@@ -8,7 +8,7 @@ English | [中文](2026-08-10-npm-release-sequences.zh.md)
 
 This repository held three unrelated groups of publishable packages and no channel that sent any of them to a registry.
 
-`packages/*/*` and `apps/*` form the runtime surface of `@deepseek-ai/dsh`; `vendor/*` holds nine rescoped Cordis framework packages, each carrying its upstream version; `native/landlock-run/packages/*` holds Linux platform packages with their own workflow. The three differ in version baseline, change rate, and build requirements: dsh moves with the product, vendor moves only when upstream is re-synced or a local modification changes, and native needs a musl toolchain and one build per architecture. Forcing them through one pipeline means every product release republishes the framework and the native binaries.
+`packages/*/*` and `apps/*` form the runtime surface of `@deepseek-ai/dsh`; `vendor/*` holds nine rescoped Cordis framework packages, each carrying its upstream version; `native/system/packages/*` holds Linux platform packages with their own workflow. The three differ in version baseline, change rate, and build requirements: dsh moves with the product, vendor moves only when upstream is re-synced or a local modification changes, and native needs a musl toolchain and one build per architecture. Forcing them through one pipeline means every product release republishes the framework and the native binaries.
 
 Two hard blockers sat in the way. All 217 workspace manifests set `private: true`, which npm refuses to publish. The subtler one was 933 hand-written `peerDependencies: "^0.0.1"` entries between sibling dsh packages: `pnpm pack` substitutes the `workspace:` protocol but leaves semver ranges alone, and `^0.0.1` means `>=0.0.1 <0.0.2` — it excludes `0.0.2`, and semver excludes prereleases from a range without a prerelease of its own, so it excluded `0.0.1-rc.1` too. Those entries never failed only because the version never left `0.0.1`.
 
@@ -24,7 +24,7 @@ Two hard blockers sat in the way. All 217 workspace manifests set `private: true
 |---|---|---|---|---|
 | dsh | Publish set: non-experimental `packages/*/*` + `apps/*`; private experimental packages join only the shared version bump | one version for the publish set, private dsh packages, and workspace root, `0.0.x` | `dsh-v<version>` | `release.yml` (pack) / `release-publish.yml` (publish) |
 | vendored framework | the nine `vendor/*` packages | each package on its own version line | `vendor-<package>-v<version>` (one per package) | `release-vendor.yml` (pack) / `release-vendor-publish.yml` (publish) |
-| native | `native/landlock-run/packages/*` | its own `0.0.x` | `landlock-run-v<version>` | `landlock-run-release.yml` |
+| native | `native/system/packages/*` | its own `0.0.x` | `node-addon-system-v<version>` | `node-addon-system-release.yml` |
 
 All three publish to the `@deepseek-ai` scope on npmjs.com, and access is per sequence rather than per scope: the vendored framework and the native packages are `public`, and the dsh family has been `public` since its own sequence went public on 2026-08-13 ([rationale](../../archived/process/2026-08-13-public-vendor-and-native-sequences.md)). No publish path passes `--access`, because one flag cannot serve sequences that disagree and would override the manifest that owns the level.
 

+ 2 - 2
.agents/notes/implemented/process/2026-08-10-npm-release-sequences.zh.md

@@ -8,7 +8,7 @@ Status: implemented
 
 这个仓库有三组互不相干的可发布包,却没有任何发布通道把它们送上 registry。
 
-`packages/*/*` 与 `apps/*` 组成 `@deepseek-ai/dsh` 的运行面;`vendor/*` 是九个 rescope 过的 Cordis 框架包,各自带着上游的版本号;`native/landlock-run/packages/*` 是 Linux 平台包,有自己的 workflow。三组的版本基线、变更节奏和构建要求都不同:dsh 随产品迭代,vendor 只在同步上游或改动本地修改时才动,native 需要 musl 工具链和逐架构构建。把它们塞进一条发布流水线,等于每次产品发版都要重发框架和原生二进制。
+`packages/*/*` 与 `apps/*` 组成 `@deepseek-ai/dsh` 的运行面;`vendor/*` 是九个 rescope 过的 Cordis 框架包,各自带着上游的版本号;`native/system/packages/*` 是 Linux 平台包,有自己的 workflow。三组的版本基线、变更节奏和构建要求都不同:dsh 随产品迭代,vendor 只在同步上游或改动本地修改时才动,native 需要 musl 工具链和逐架构构建。把它们塞进一条发布流水线,等于每次产品发版都要重发框架和原生二进制。
 
 挡路的还有两处硬门。全部 217 个 workspace manifest 都是 `private: true`,`npm publish` 直接拒绝。更隐蔽的是 933 条 dsh 兄弟包之间硬写的 `peerDependencies: "^0.0.1"`:`pnpm pack` 只替换 `workspace:` 协议,不动语义范围,而 `^0.0.1` 等于 `>=0.0.1 <0.0.2`——发 `0.0.2` 落不进去,发 `0.0.1-rc.1` 也落不进去(semver 规定不带预发布段的范围排除预发布版本)。这些条目至今没出事,只因为版本一直停在 `0.0.1`。
 
@@ -24,7 +24,7 @@ Status: implemented
 |---|---|---|---|---|
 | dsh | 发布集:非 experimental 的 `packages/*/*` + `apps/*`;私有实验性包仅加入共享版本 bump | 发布集、私有 dsh 包与 workspace 根共用一个 `0.0.x` | `dsh-v<版本>` | `release.yml`(pack)/ `release-publish.yml`(发布) |
 | vendored framework | `vendor/*` 九个包 | 每包各自一条版本线 | `vendor-<包名>-v<版本>`(每包一个) | `release-vendor.yml`(pack)/ `release-vendor-publish.yml`(发布) |
-| native | `native/landlock-run/packages/*` | 自己的 `0.0.x` | `landlock-run-v<版本>` | `landlock-run-release.yml` |
+| native | `native/system/packages/*` | 自己的 `0.0.x` | `node-addon-system-v<版本>` | `node-addon-system-release.yml` |
 
 三组一律发到 npmjs.com 的 `@deepseek-ai` scope,且 access 按序列而非按 scope 区分:vendored 框架与 native 包是 `public`,dsh 族自 2026-08-13 其自身序列公开发布起即为 `public`([理由](../../archived/process/2026-08-13-public-vendor-and-native-sequences.md))。没有任何发布路径传 `--access`——一个选项无法服务级别互不相同的序列,且会覆盖真正拥有该级别的 manifest。
 

+ 6 - 0
.agents/notes/implemented/testing/2026-09-08-ci-readiness-and-completion.i18n.yaml

@@ -0,0 +1,6 @@
+# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
+# side as of the last confirmed-consistent state. Both languages carry equal authority;
+# after editing either side, bring the other along and re-record with:
+#   pnpm run verify-translation-pairing --write .agents/notes/implemented/testing/2026-09-08-ci-readiness-and-completion.md
+2026-09-08-ci-readiness-and-completion.md: 8ea0a5892d78eda16e657334dba2af58b6648d09
+2026-09-08-ci-readiness-and-completion.zh.md: 62a4c64081369a20a576805fb8a465bffff2922d

+ 33 - 0
.agents/notes/implemented/testing/2026-09-08-ci-readiness-and-completion.md

@@ -0,0 +1,33 @@
+# Agent Note: CI assertions wait for owned completion
+
+Status: implemented
+
+English | [中文](2026-09-08-ci-readiness-and-completion.zh.md)
+
+## Problem
+
+The [empty master PR run](https://github.com/deepseek-harness/deepseek-harness/actions/runs/34206953049) fails while waiting one second for webhook Session creation and five seconds for PowerShell output. Neither test measures a startup latency guarantee. A [separate run](https://github.com/deepseek-harness/deepseek-harness/actions/runs/34207864157) shows the same short-budget problem in a desktop worker readiness test and captures a feedback acknowledgement while the composer still holds the submitted command.
+
+Another [Windows coverage run](https://github.com/deepseek-harness/deepseek-harness/actions/runs/34224004885/job/102053583437) reports a null publint child status and an LSP initialization-marker timeout. Their helpers impose five- and three-second limits inside the lane's 90-second test budget. These cases verify publication contents and cancellation behavior rather than cold-start latency.
+
+## Decision
+
+The [webhook browser test](../../../../apps/web/tests/github-ready-review.e2e.ts) observes the model request caused by delivery before checking Session registration. The [feedback test](../../../../apps/web/tests/feedback-command.e2e.ts) waits for the empty composer and enabled attachment control before comparing ARIA output. Matching consecutive snapshots cannot prove that the command RPC has settled: its event stream can publish the acknowledgement first.
+
+The [desktop transaction test](../../../../apps/desktop/tests/project-manager.spec.ts) gives the worker readiness marker the active test's execution budget. Its independent `afterEach` releases and awaits workers before deleting private roots, including when the runner abandons a timed-out test body. The poll observes runner cancellation, and teardown reports transaction failures independently from assertion failures. The [PowerShell tests](../../../../packages/shell/pwsh-local/tests/executor.spec.ts) register each helper-created Context before plugin initialization and dispose those Contexts before deleting temporary directories. The background-input case awaits process completion before checking complete output, completed status, and exit code. Consuming reads remain covered by their separate streaming tests.
+
+The [publint runner tests](../../../../scripts/publint-all.spec.ts) pass the active test budget to their child and check launch errors and termination signals before interpreting its exit code. The [LSP instance test](../../../../packages/lsp/lsp-stdio/tests/instance.spec.ts) uses the same budget for its fixture marker, observes the actual pending `didOpen` write before aborting, and captures the query's rejection before waiting for readiness. Its [server fixture](../../../../packages/lsp/lsp-stdio/tests/fixture-server.ts) publishes the marker after pausing stdin. Teardown captures the instance list, Context, and directory before its first await.
+
+The [subagent teardown decision](2026-09-07-subagent-teardown-test-budgets.md) owns lifecycle cleanup budgets. The [persistent PowerShell decision](2026-09-07-pwsh-ci-observable-completion.md) owns exact versus inferred terminal readiness; a one-shot process's completion promise has different semantics.
+
+## Alternatives considered
+
+**Larger independent waits.** Rejected where a completion promise already exists. A separate polling deadline continues to compete with the execution lane's budget.
+
+**Refresh the feedback golden.** Rejected: the populated composer and disabled attachment control describe an in-flight submission. The settled expected UI remains the intended behavior.
+
+**Serialize CI or retry these tests.** Rejected: neither establishes the missing completion condition or releases a blocked child after assertion failure.
+
+## Consequences
+
+Readiness and output assertions preserve their original content and ownership checks. Controlled desktop readiness, webhook preflight, command-response, PowerShell output, publint startup, and LSP initialization delays reproduce the original failures and pass with the completion waits. A stalled desktop-worker control still reports a test timeout while proving that teardown drains the child before removing its directory. The execution lane bounds test bodies and cleanup hooks separately; native Windows execution remains necessary to verify PowerShell and process cleanup there.

+ 33 - 0
.agents/notes/implemented/testing/2026-09-08-ci-readiness-and-completion.zh.md

@@ -0,0 +1,33 @@
+# Agent Note: CI 断言等待所属操作完成
+
+Status: implemented
+
+[English](2026-09-08-ci-readiness-and-completion.md) | 中文
+
+## 问题
+
+[master 空 PR 的运行](https://github.com/deepseek-harness/deepseek-harness/actions/runs/34206953049)在等待 Webhook Session 创建一秒、等待 PowerShell 输出五秒时失败。两个测试都不衡量启动延迟保证。[另一次运行](https://github.com/deepseek-harness/deepseek-harness/actions/runs/34207864157)在 Desktop worker 就绪测试中暴露了相同的局部短时限问题,并在输入框仍保留已提交命令时截取了反馈确认。
+
+另一次 [Windows coverage 运行](https://github.com/deepseek-harness/deepseek-harness/actions/runs/34224004885/job/102053583437)报告了 publint 子进程退出状态为 null,以及 LSP 初始化标记等待超时。对应 helper 在通道的 90 秒测试预算内另设五秒和三秒限制。这些用例验证发布内容与取消行为,不衡量冷启动延迟。
+
+## 决策
+
+[Webhook 浏览器测试](../../../../apps/web/tests/github-ready-review.e2e.ts)观察投递触发的模型请求后再检查 Session 注册。[反馈测试](../../../../apps/web/tests/feedback-command.e2e.ts)在比较 ARIA 输出前等待输入框清空且附件按钮启用。连续两次快照相同不能证明命令 RPC 已完成:事件流可能先发布确认消息。
+
+[Desktop 事务测试](../../../../apps/desktop/tests/project-manager.spec.ts)为 worker 就绪标记使用当前测试的执行预算。独立的 `afterEach` 在删除私有目录前释放并等待 worker,包括运行器放弃超时测试体的情况。轮询观察运行器的取消信号,teardown 独立报告事务失败,不覆盖断言失败。[PowerShell 测试](../../../../packages/shell/pwsh-local/tests/executor.spec.ts)在初始化插件前登记每个 helper 创建的 Context,并在删除临时目录前处置这些 Context。后台输入用例等待进程完成后检查完整输出、完成状态与退出码。消费式读取仍由独立的流式测试覆盖。
+
+[publint runner 测试](../../../../scripts/publint-all.spec.ts)将当前测试预算传给子进程,并在解释退出码前检查启动错误和终止信号。[LSP 实例测试](../../../../packages/lsp/lsp-stdio/tests/instance.spec.ts)用同一预算等待 fixture 标记,在取消前观察实际尚未完成的 `didOpen` 写入,并在等待就绪前接住查询的 rejection。[服务器 fixture](../../../../packages/lsp/lsp-stdio/tests/fixture-server.ts)在暂停 stdin 后发布标记。Teardown 在首次 await 前捕获实例列表、Context 和目录。
+
+[子 Agent 拆卸决策](2026-09-07-subagent-teardown-test-budgets.zh.md)负责生命周期清理预算。[持久 PowerShell 决策](2026-09-07-pwsh-ci-observable-completion.zh.md)负责精确与推断的终端就绪状态;一次性进程的完成 Promise 具有不同语义。
+
+## 考虑过的替代方案
+
+**增大独立等待时限。** 已有完成 Promise 时不采用。独立轮询期限仍会与执行通道的预算竞争。
+
+**刷新反馈 golden。** 不采用:保留内容的输入框与禁用的附件按钮描述了尚未完成的提交。已稳定的预期 UI 仍是目标行为。
+
+**串行化 CI 或重试这些测试。** 不采用:两者都不能建立缺失的完成条件,也不能在断言失败后释放阻塞的子进程。
+
+## 后果
+
+就绪与输出断言保留原有的内容和所有权检查。受控的 Desktop 就绪、Webhook 预检、命令响应、PowerShell 输出、publint 启动及 LSP 初始化延迟可复现原始失败,并在采用完成等待后通过。阻塞 Desktop worker 的控制用例仍报告测试超时,同时证明 teardown 在删除目录前等待子进程退出。执行通道分别限制测试体和清理 hook;PowerShell 和进程清理仍需在原生 Windows 上验证。

+ 0 - 144
.github/workflows/landlock-run.yml

@@ -1,144 +0,0 @@
-# CI for the landlock-run packages under native/landlock-run. A separate
-# workflow from ci.yml keeps the native OS/architecture matrix independent of
-# the harness Node matrix. Release assembly and publication use the companion
-# Landlock Run Release workflow.
-name: Landlock Run
-
-on:
-  pull_request:
-    paths:
-      - '.github/workflows/landlock-run.yml'
-      - '.github/workflows/landlock-run-release.yml'
-      - 'native/landlock-run/**'
-      - 'package.json'
-      - 'pnpm-lock.yaml'
-      - 'pnpm-workspace.yaml'
-  push:
-    branches: [master]
-    paths:
-      - '.github/workflows/landlock-run.yml'
-      - '.github/workflows/landlock-run-release.yml'
-      - 'native/landlock-run/**'
-      - 'package.json'
-      - 'pnpm-lock.yaml'
-      - 'pnpm-workspace.yaml'
-  workflow_dispatch:
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.ref }}
-  cancel-in-progress: true
-
-permissions:
-  contents: read
-
-env:
-  # CI runs must never report to the production telemetry endpoint baked
-  # into apps/cli/cordis.yml (AppCLIEntry disables the row when set).
-  DSH_TELEMETRY_DISABLED: '1'
-
-defaults:
-  run:
-    working-directory: native/landlock-run
-
-jobs:
-  matrix:
-    name: Matrix
-    runs-on: ubuntu-24.04
-    outputs:
-      ci: ${{ steps.matrix.outputs.ci }}
-    steps:
-      - uses: actions/checkout@v4
-
-      - id: matrix
-        run: echo "ci=$(node ./scripts/github-matrix.mjs ci)" >> "$GITHUB_OUTPUT"
-
-  native:
-    name: ${{ matrix.platform }}
-    needs: matrix
-    runs-on: ${{ matrix.runner }}
-    strategy:
-      fail-fast: false
-      matrix: ${{ fromJson(needs.matrix.outputs.ci) }}
-    steps:
-      - uses: actions/checkout@v4
-
-      - uses: pnpm/action-setup@v4
-        with:
-          package_json_file: package.json
-
-      - uses: actions/setup-node@v4
-        with:
-          node-version: 24
-          cache: pnpm
-          cache-dependency-path: pnpm-lock.yaml
-
-      - name: Install dependencies
-        run: pnpm install --filter @deepseek-ai/node-addon-landlock-run-workspace... --frozen-lockfile
-
-      - name: Install musl toolchain
-        run: |
-          sudo apt-get update -q
-          sudo apt-get install -yq musl-tools
-
-      - name: Build TypeScript
-        run: pnpm build:ts
-
-      - name: Typecheck
-        run: pnpm typecheck
-
-      - name: Build native binaries (this architecture is the builder of record)
-        run: pnpm build:native
-
-      - name: Entry tests (keyless)
-        run: node ./test/entry.test.js
-
-      # NALR_REQUIRE_LANDLOCK: a self-skip on the very platform that exists to
-      # prove enforcement would be a false green, so an unenforcing kernel
-      # fails the leg instead of skipping.
-      - name: Launcher tests (real kernel enforcement)
-        run: node ./test/launcher.test.js
-        env:
-          NALR_REQUIRE_LANDLOCK: 1
-
-      - name: Pack rehearsal (pack → install → confine, this platform only)
-        run: |
-          node ./scripts/pack-release.mjs .release/npm --current-platform-only
-          node ./scripts/verify-packed-install.mjs .release/npm --current-platform-only
-        env:
-          NALR_REQUIRE_LANDLOCK: 1
-
-  darwin:
-    name: darwin (no platform package — degradation proof)
-    runs-on: macos-latest
-    steps:
-      - uses: actions/checkout@v4
-
-      - uses: pnpm/action-setup@v4
-        with:
-          package_json_file: package.json
-
-      - uses: actions/setup-node@v4
-        with:
-          node-version: 24
-          cache: pnpm
-          cache-dependency-path: pnpm-lock.yaml
-
-      - name: Install dependencies
-        run: pnpm install --filter @deepseek-ai/node-addon-landlock-run-workspace... --frozen-lockfile
-
-      - name: Build TypeScript
-        run: pnpm build:ts
-
-      - name: Typecheck
-        run: pnpm typecheck
-
-      - name: Entry tests (keyless)
-        run: node ./test/entry.test.js
-
-      - name: Launcher tests (must self-skip cleanly)
-        run: node ./test/launcher.test.js
-
-      - name: Pack rehearsal (entry only — fallback resolution + unusable probe)
-        run: |
-          node ./scripts/pack-release.mjs .release/npm --current-platform-only
-          node ./scripts/verify-packed-install.mjs .release/npm --current-platform-only

+ 18 - 10
.github/workflows/landlock-run-release.yml → .github/workflows/node-addon-system-release.yml

@@ -1,13 +1,13 @@
-# Build and publish the @deepseek-ai/node-addon-landlock-run package family from the
+# Build and publish the @deepseek-ai/node-addon-system package family from the
 # harness source of record. Rehearsal and publication consume the same packed
 # tarballs; each native binary is built on its matching architecture.
-name: Landlock Run Release
+name: Node Addon System Release
 
 on:
   workflow_dispatch:
     inputs:
       publish:
-        description: Publish packed tarballs to npm. Must run from a landlock-run-v* tag.
+        description: Publish packed tarballs to npm. Must run from a node-addon-system-v* tag.
         required: true
         type: boolean
         default: false
@@ -23,7 +23,7 @@ concurrency:
 
 defaults:
   run:
-    working-directory: native/landlock-run
+    working-directory: native/system
 
 jobs:
   matrix:
@@ -58,9 +58,10 @@ jobs:
           cache-dependency-path: pnpm-lock.yaml
 
       - name: Install dependencies
-        run: pnpm install --filter @deepseek-ai/node-addon-landlock-run-workspace... --frozen-lockfile
+        run: pnpm install --filter @deepseek-ai/node-addon-system-workspace... --frozen-lockfile
 
       - name: Install musl toolchain
+        if: runner.os == 'Linux'
         run: |
           sudo apt-get update -q
           sudo apt-get install -yq musl-tools
@@ -71,11 +72,18 @@ jobs:
       - name: Verify binary metadata
         run: node ./scripts/verify-launcher-binary.mjs ${{ matrix.dir }}
 
+      - name: Verify the built entry and flock
+        run: |
+          pnpm build:ts
+          pnpm build:test-oracle
+          pnpm test:flock
+          pnpm test:packaging
+
       - name: Upload prebuild artifact
         uses: actions/upload-artifact@v4
         with:
           name: ${{ matrix.artifact }}
-          path: native/landlock-run/${{ matrix.dir }}/bin/*
+          path: native/system/${{ matrix.dir }}/bin/**
           if-no-files-found: error
           retention-days: 7
 
@@ -97,7 +105,7 @@ jobs:
           cache-dependency-path: pnpm-lock.yaml
 
       - name: Install dependencies
-        run: pnpm install --filter @deepseek-ai/node-addon-landlock-run-workspace... --frozen-lockfile
+        run: pnpm install --filter @deepseek-ai/node-addon-system-workspace... --frozen-lockfile
 
       - name: Build TypeScript
         run: pnpm build:ts
@@ -111,7 +119,7 @@ jobs:
         uses: actions/download-artifact@v4
         with:
           pattern: prebuild-*
-          path: native/landlock-run/.release/prebuild-artifacts
+          path: native/system/.release/prebuild-artifacts
 
       - name: Assemble and verify prebuilds
         run: node ./scripts/assemble-prebuilds.mjs .release/prebuild-artifacts
@@ -133,7 +141,7 @@ jobs:
         uses: actions/upload-artifact@v4
         with:
           name: npm-tarballs
-          path: native/landlock-run/dist/npm/*
+          path: native/system/dist/npm/*
           if-no-files-found: error
           retention-days: 7
 
@@ -162,7 +170,7 @@ jobs:
         uses: actions/download-artifact@v4
         with:
           name: npm-tarballs
-          path: native/landlock-run/dist/npm
+          path: native/system/dist/npm
 
       - name: Configure npm token fallback
         env:

+ 179 - 0
.github/workflows/node-addon-system.yml

@@ -0,0 +1,179 @@
+# CI for the node-addon-system packages under native/system. A separate
+# workflow from ci.yml keeps the native OS/architecture matrix independent of
+# the harness Node matrix. Release assembly and publication use the companion
+# Node Addon System Release workflow.
+name: Node Addon System
+
+on:
+  pull_request:
+    paths:
+      - '.github/workflows/node-addon-system.yml'
+      - '.github/workflows/node-addon-system-release.yml'
+      - 'native/system/**'
+      - 'package.json'
+      - 'pnpm-lock.yaml'
+      - 'pnpm-workspace.yaml'
+  push:
+    branches: [master]
+    paths:
+      - '.github/workflows/node-addon-system.yml'
+      - '.github/workflows/node-addon-system-release.yml'
+      - 'native/system/**'
+      - 'package.json'
+      - 'pnpm-lock.yaml'
+      - 'pnpm-workspace.yaml'
+  workflow_dispatch:
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+permissions:
+  contents: read
+
+env:
+  # CI runs must never report to the production telemetry endpoint baked
+  # into apps/cli/cordis.yml (AppCLIEntry disables the row when set).
+  DSH_TELEMETRY_DISABLED: '1'
+
+defaults:
+  run:
+    working-directory: native/system
+
+jobs:
+  matrix:
+    name: Matrix
+    runs-on: ubuntu-24.04
+    outputs:
+      ci: ${{ steps.matrix.outputs.ci }}
+      compatibility: ${{ steps.matrix.outputs.compatibility }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - id: matrix
+        run: |
+          echo "ci=$(node ./scripts/github-matrix.mjs ci)" >> "$GITHUB_OUTPUT"
+          echo "compatibility=$(node ./scripts/github-matrix.mjs compatibility)" >> "$GITHUB_OUTPUT"
+
+  native:
+    name: ${{ matrix.platform }}
+    needs: matrix
+    runs-on: ${{ matrix.runner }}
+    strategy:
+      fail-fast: false
+      matrix: ${{ fromJson(needs.matrix.outputs.ci) }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - uses: pnpm/action-setup@v4
+        with:
+          package_json_file: package.json
+
+      - uses: actions/setup-node@v4
+        with:
+          node-version: 24
+          cache: pnpm
+          cache-dependency-path: pnpm-lock.yaml
+
+      - name: Install dependencies
+        run: pnpm install --filter @deepseek-ai/node-addon-system-workspace... --frozen-lockfile
+
+      - name: Install musl toolchain
+        if: runner.os == 'Linux'
+        run: |
+          sudo apt-get update -q
+          sudo apt-get install -yq musl-tools
+
+      - name: Build TypeScript
+        run: pnpm build:ts
+
+      - name: Typecheck
+        run: pnpm typecheck
+
+      - name: Build native binaries (this architecture is the builder of record)
+        run: pnpm build:native
+
+      - name: Entry tests (keyless)
+        run: node ./test/entry.test.js
+
+      # NALR_REQUIRE_LANDLOCK: a self-skip on the very platform that exists to
+      # prove enforcement would be a false green, so an unenforcing kernel
+      # fails the leg instead of skipping.
+      - name: Launcher tests (real kernel enforcement)
+        if: runner.os == 'Linux'
+        run: node ./test/launcher.test.js
+        env:
+          NALR_REQUIRE_LANDLOCK: 1
+
+      - name: Pack rehearsal (pack → install → confine, this platform only)
+        run: |
+          node ./scripts/pack-release.mjs .release/npm --current-platform-only
+          node ./scripts/verify-packed-install.mjs .release/npm --current-platform-only
+        env:
+          NALR_REQUIRE_LANDLOCK: ${{ runner.os == 'Linux' && '1' || '0' }}
+
+      - name: Verify platform payload rules
+        run: pnpm test:packaging
+
+      - name: Flock behavior (built addon)
+        run: |
+          pnpm build:test-oracle
+          pnpm test:flock
+
+      - name: Upload this platform's built addon and entry
+        uses: actions/upload-artifact@v4
+        with:
+          name: system-compat-${{ matrix.platform }}
+          path: |
+            native/system/packages/*/bin/**
+            native/system/packages/entry/lib/**
+          if-no-files-found: error
+
+      - name: Upload independent syscall test oracle
+        uses: actions/upload-artifact@v4
+        with:
+          name: system-oracle-${{ matrix.platform }}
+          path: native/system/test/bin/**
+          if-no-files-found: error
+
+  compatibility:
+    name: ${{ matrix.platform }} / Node ${{ matrix.node }} (same binary)
+    needs: [matrix, native]
+    strategy:
+      fail-fast: false
+      matrix:
+        include: ${{ fromJson(needs.matrix.outputs.compatibility) }}
+    runs-on: ${{ matrix.runner }}
+    steps:
+      - uses: actions/checkout@v4
+
+      - uses: actions/setup-node@v4
+        with:
+          node-version: ${{ matrix.node }}
+
+      - name: Download the original platform build
+        uses: actions/download-artifact@v4
+        with:
+          name: system-compat-${{ matrix.platform }}
+          path: native/system/packages
+
+      - name: Download independent syscall test oracle
+        uses: actions/download-artifact@v4
+        with:
+          name: system-oracle-${{ matrix.platform }}
+          path: native/system/test/bin
+
+      - name: Restore oracle executable permissions
+        run: find ./test/bin -type f -name flock-oracle -exec chmod +x {} +
+
+      - name: Test without rebuilding or installing dependencies
+        run: |
+          node ./test/link-platform.mjs
+          node --test ./test/flock.test.js ./test/package-matrix.test.js
+
+      - name: Test the same musl addon without a compiler
+        if: runner.os == 'Linux'
+        run: >-
+          docker run --rm -v "$PWD:$PWD" -w "$PWD"
+          node:${{ matrix.node }}-alpine
+          node --test ./test/flock.test.js ./test/package-matrix.test.js

+ 2 - 2
.github/workflows/release-publish.yml

@@ -76,8 +76,8 @@ jobs:
       # are optional, and building them needs a musl toolchain per architecture.
       - name: Pack the Landlock entry for verification
         run: |
-          pnpm --dir native/landlock-run run build:ts
-          pnpm --dir native/landlock-run/packages/entry pack --pack-destination "$PWD/dist/npm-landlock"
+          pnpm --dir native/system run build:ts
+          pnpm --dir native/system/packages/entry pack --pack-destination "$PWD/dist/npm-landlock"
 
       - name: Verify packed install
         run: pnpm run release:verify-packed-install --family dsh --from dist/npm --from dist/npm-vendor --from dist/npm-landlock

+ 2 - 2
.github/workflows/release.yml

@@ -166,8 +166,8 @@ jobs:
       # are optional, and building them needs a musl toolchain per architecture.
       - name: Pack the Landlock entry for verification
         run: |
-          pnpm --dir native/landlock-run run build:ts
-          pnpm --dir native/landlock-run/packages/entry pack --pack-destination "$PWD/dist/npm-landlock"
+          pnpm --dir native/system run build:ts
+          pnpm --dir native/system/packages/entry pack --pack-destination "$PWD/dist/npm-landlock"
 
       - name: Verify packed install
         run: pnpm run release:verify-packed-install --family dsh --from dist/npm --from dist/npm-vendor --from dist/npm-landlock

+ 3 - 3
.github/workflows/sandbox.yml

@@ -3,7 +3,7 @@
 # .agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.md.
 # A separate workflow from ci.yml because the axis is different — these jobs
 # fan out over OS×runner (kernel capabilities), not node versions. The Landlock
-# launcher is built from native/landlock-run on each Landlock leg and installed
+# launcher is built from native/system on each Landlock leg and installed
 # from the same tarballs the main-repository release workflow publishes.
 name: Sandbox
 
@@ -84,8 +84,8 @@ jobs:
         run: |
           sudo apt-get update -q
           sudo apt-get install -yq musl-tools
-          pnpm --dir native/landlock-run run build:ts
-          pnpm --dir native/landlock-run run build:native
+          pnpm --dir native/system run build:ts
+          pnpm --dir native/system run build:native
 
       # The unit suite runs on ubuntu in `checks`; this is the one darwin leg
       # in the workflow, so run it here too — the platform-dependent unit

+ 1 - 0
.gitignore

@@ -43,3 +43,4 @@ apps/web/dist/
 worktrees/
 .agents/worktrees/
 .typert-*/
+native/system/test/bin/

+ 1 - 1
AGENTS.md

@@ -49,7 +49,7 @@ packages/    @deepseek-ai/dsh-<pkg> workspaces at packages/<group>/<pkg>/
   support/     dev/test infrastructure
   util/        zero-dependency utilities
 python/      Python SDK/runtime (see python/README.md)
-native/      @deepseek-ai/node-addon-landlock-run source of record (see native/README.md)
+native/      @deepseek-ai/node-addon-system source of record (see native/README.md)
 benchmarks/  performance gates
 .agents/     Agent workflows and Agent Notes (`notes/`)
 docs/        architecture, generated catalogs, postmortems, cookbook (see docs/AGENTS.md)

+ 10 - 12
THIRD_PARTY_NOTICES.md

@@ -71,7 +71,6 @@ External packages that a workspace package resolves at runtime. The tier covers
 | [`electron-updater`](https://github.com/electron-userland/electron-builder) | MIT |
 | [`eventsource-parser`](https://github.com/rexxars/eventsource-parser) | MIT |
 | [`fflate`](https://github.com/101arrowz/fflate) | MIT |
-| [`fs-ext`](https://github.com/baudehlo/node-fs-ext) | MIT |
 | [`immer`](https://github.com/immerjs/immer) | MIT |
 | [`ipaddr.js`](https://github.com/whitequark/ipaddr.js) | MIT |
 | [`js-yaml`](https://github.com/nodeca/js-yaml) | MIT |
@@ -123,18 +122,18 @@ pnpm applies local patches to the following packages at install time, so shipped
 
 The project owner authorizes distribution of every version of the official `@anthropic-ai/claude-agent-sdk` package and the official Claude Code CLI/platform payloads that each version declares through `optionalDependencies`. This identity-scoped authorization does not classify their declared terms as permissive and does not cover any unrelated runtime package; version, declared-license, and payload-set changes still require the ordinary dependency, lockfile, compatibility, terms, and notices review.
 
-The installed SDK 0.3.241 declares the following optional platform packages. Each carries the official Claude Code 2.1.241 executable; the package identities and versions come from the SDK manifest, while the declared license field is verified against the platform payload installed for the current host.
+The installed SDK 0.3.263 declares the following optional platform packages. Each carries the official Claude Code 2.1.263 executable; the package identities and versions come from the SDK manifest, while the declared license field is verified against the platform payload installed for the current host.
 
 | Optional platform package | Version | Declared license |
 | --- | --- | --- |
-| [`@anthropic-ai/claude-agent-sdk-darwin-arm64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-darwin-arm64) | 0.3.241 | SEE LICENSE IN LICENSE.md |
-| [`@anthropic-ai/claude-agent-sdk-darwin-x64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-darwin-x64) | 0.3.241 | SEE LICENSE IN LICENSE.md |
-| [`@anthropic-ai/claude-agent-sdk-linux-arm64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-linux-arm64) | 0.3.241 | SEE LICENSE IN LICENSE.md |
-| [`@anthropic-ai/claude-agent-sdk-linux-arm64-musl`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-linux-arm64-musl) | 0.3.241 | SEE LICENSE IN LICENSE.md |
-| [`@anthropic-ai/claude-agent-sdk-linux-x64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-linux-x64) | 0.3.241 | SEE LICENSE IN LICENSE.md |
-| [`@anthropic-ai/claude-agent-sdk-linux-x64-musl`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-linux-x64-musl) | 0.3.241 | SEE LICENSE IN LICENSE.md |
-| [`@anthropic-ai/claude-agent-sdk-win32-arm64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-win32-arm64) | 0.3.241 | SEE LICENSE IN LICENSE.md |
-| [`@anthropic-ai/claude-agent-sdk-win32-x64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-win32-x64) | 0.3.241 | SEE LICENSE IN LICENSE.md |
+| [`@anthropic-ai/claude-agent-sdk-darwin-arm64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-darwin-arm64) | 0.3.263 | SEE LICENSE IN LICENSE.md |
+| [`@anthropic-ai/claude-agent-sdk-darwin-x64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-darwin-x64) | 0.3.263 | SEE LICENSE IN LICENSE.md |
+| [`@anthropic-ai/claude-agent-sdk-linux-arm64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-linux-arm64) | 0.3.263 | SEE LICENSE IN LICENSE.md |
+| [`@anthropic-ai/claude-agent-sdk-linux-arm64-musl`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-linux-arm64-musl) | 0.3.263 | SEE LICENSE IN LICENSE.md |
+| [`@anthropic-ai/claude-agent-sdk-linux-x64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-linux-x64) | 0.3.263 | SEE LICENSE IN LICENSE.md |
+| [`@anthropic-ai/claude-agent-sdk-linux-x64-musl`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-linux-x64-musl) | 0.3.263 | SEE LICENSE IN LICENSE.md |
+| [`@anthropic-ai/claude-agent-sdk-win32-arm64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-win32-arm64) | 0.3.263 | SEE LICENSE IN LICENSE.md |
+| [`@anthropic-ai/claude-agent-sdk-win32-x64`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk-win32-x64) | 0.3.263 | SEE LICENSE IN LICENSE.md |
 
 
 ## Development-only npm dependencies
@@ -154,7 +153,6 @@ External packages **directly declared** only by repository tooling, test infrast
 | [`@testing-library/react`](https://github.com/testing-library/react-testing-library) | MIT |
 | [`@types/babel__code-frame`](https://github.com/DefinitelyTyped/DefinitelyTyped) | MIT |
 | [`@types/compression`](https://github.com/DefinitelyTyped/DefinitelyTyped) | MIT |
-| [`@types/fs-ext`](https://github.com/DefinitelyTyped/DefinitelyTyped) | MIT |
 | [`@types/js-yaml`](https://github.com/DefinitelyTyped/DefinitelyTyped) | MIT |
 | [`@types/jsdom`](https://github.com/DefinitelyTyped/DefinitelyTyped) | MIT |
 | [`@types/mime-types`](https://github.com/DefinitelyTyped/DefinitelyTyped) | MIT |
@@ -224,4 +222,4 @@ Direct dependencies of the `pyproject.toml` manifests, plus `uv` as the developm
 
 ## First-party native packages
 
-`@deepseek-ai/node-addon-landlock-run` (and its platform packages) is built and released from this repository under BSD 3-Clause. It is listed here for completeness; it is first-party, not third-party.
+`@deepseek-ai/node-addon-system` (and its platform packages) is built and released from this repository under BSD 3-Clause. It is listed here for completeness; it is first-party, not third-party.

+ 2 - 2
apps/desktop/scripts/package-target.ts

@@ -266,10 +266,10 @@ async function main(): Promise<void> {
   await runPnpm(['run', 'release:pack', '--family', 'vendor', '--out', buildPaths.packedVendor], buildEnv, REPOSITORY_ROOT)
   rmSync(buildPaths.packedLandlock, { recursive: true, force: true })
   mkdirSync(buildPaths.packedLandlock, { recursive: true })
-  await runPnpm(['--dir', 'native/landlock-run', 'run', 'build:ts'], buildEnv, REPOSITORY_ROOT)
+  await runPnpm(['--dir', 'native/system', 'run', 'build:ts'], buildEnv, REPOSITORY_ROOT)
   await runPnpm([
     '--dir',
-    'native/landlock-run/packages/entry',
+    'native/system/packages/entry',
     'pack',
     '--pack-destination',
     buildPaths.packedLandlock,

+ 22 - 4
apps/desktop/tests/project-manager.spec.ts

@@ -18,6 +18,7 @@ import type { DesktopRelease } from '../src/release.ts'
 import { archivePnpmStore } from '../src/seed-store.ts'
 
 const roots: string[] = []
+const releaseWorkers: Array<() => Promise<void>> = []
 
 function temporaryRoot(): string {
   const root = mkdtempSync(join(tmpdir(), 'dsh-desktop-test-'))
@@ -162,8 +163,13 @@ function release(version = '1.0.0'): DesktopRelease {
   }
 }
 
-afterEach(() => {
-  for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true })
+afterEach(async () => {
+  const cleanups = releaseWorkers.splice(0)
+  const directories = roots.splice(0)
+  const results = await Promise.allSettled(cleanups.map(cleanup => cleanup()))
+  for (const root of directories) rmSync(root, { recursive: true, force: true })
+  const failures: unknown[] = results.flatMap((result): unknown[] => result.status === 'rejected' ? [result.reason] : [])
+  if (failures.length > 0) throw new AggregateError(failures, 'desktop worker cleanup failed')
 })
 
 describe('desktop package policy', () => {
@@ -293,7 +299,7 @@ describe('desktop project transactions', () => {
     expect(existsSync(paths.pending)).toBe(false)
   })
 
-  it('records the live pnpm worker as transaction owner until it exits', async () => {
+  it('records the live pnpm worker as transaction owner until it exits', async ({ task, signal }) => {
     const root = temporaryRoot()
     const seed = join(root, 'seed')
     const ready = join(root, 'pnpm-ready')
@@ -306,7 +312,19 @@ describe('desktop project transactions', () => {
     const runtime = { node: process.execPath, pnpm: writeBlockingFakePnpm(root, ready, releaseWorker) }
     const manager = new DesktopProjectManager(paths, runtime)
     const installing = manager.applyRelease(seed, '1.0.0', hooks())
-    await expect.poll(() => existsSync(ready)).toBe(true)
+    // Teardown observes failures even if the runner has abandoned the test body.
+    const completed = installing.then(value => ({ value }), (error: unknown) => ({ error }))
+    releaseWorkers.push(async () => {
+      writeFileSync(releaseWorker, 'continue')
+      const outcome = await completed
+      if ('error' in outcome) throw outcome.error
+    })
+    // Child startup shares the test budget; an aborted poll must not resume ownership assertions.
+    await expect.poll(() => {
+      signal.throwIfAborted()
+      return existsSync(ready)
+    }, { timeout: task.timeout }).toBe(true)
+    signal.throwIfAborted()
     const workerPid = Number.parseInt(readFileSync(ready, 'utf8'), 10)
     expect(readFileSync(paths.lock, 'utf8')).toBe(`${String(workerPid)}\n`)
     const competing = new DesktopProjectManager(paths, runtime)

+ 1 - 1
apps/web/tests/preview-boot.e2e.ts

@@ -415,7 +415,7 @@ async function bootPreview(origin: string, browser: Browser): Promise<void> {
     await page.getByText(SHOWCASE_OLDEST, { exact: true }).waitFor({ timeout: 15_000 })
     expect(pageErrors.map(error => error.message)).toEqual([])
     expect(consoleErrors.filter(line =>
-      /watchFile|failed to watch|node-addon-landlock-run\.probe|sandbox backend is usable|SANDBOX_UNAVAILABLE/i.test(line))).toEqual([])
+      /watchFile|failed to watch|node-addon-system\.probe|sandbox backend is usable|SANDBOX_UNAVAILABLE/i.test(line))).toEqual([])
   } catch (error) {
     await saveFailureShot(page, 'preview-boot')
     throw pageErrors.length === 0

+ 26 - 6
apps/web/tests/settings-chrome.e2e.ts

@@ -10,7 +10,7 @@
 // open llm seam.
 import { readFile } from 'node:fs/promises'
 import { fileURLToPath } from 'node:url'
-import type { Browser, Page } from 'playwright'
+import type { Browser, Locator, Page } from 'playwright'
 import { chromium } from 'playwright'
 import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest'
 import { join } from 'node:path'
@@ -190,13 +190,33 @@ describe('web e2e: settings modal and General preferences', () => {
     expect(tripwire.pageErrors).toEqual([])
   }, 60_000)
 
+  async function selectTheme(cube: Locator, preference: 'light' | 'dark' | 'system'): Promise<void> {
+    // Optimistic UI and a file value from an earlier gesture do not prove this write finished.
+    const [response] = await Promise.all([
+      page.waitForResponse((candidate) => {
+        if (candidate.request().method() !== 'POST'
+          || new URL(candidate.url()).pathname !== '/api/settings/mutate') return false
+        const { payload: { args } } = candidate.request().postDataJSON() as {
+          payload: { args: { ns: string; ops: { op: string; path: string[]; value?: unknown }[] } }
+        }
+        return args.ns === 'ui-theme' && args.ops.some(op => op.op === 'set'
+          && op.path.length === 1 && op.path[0] === 'preference' && op.value === preference)
+      }, { timeout: 5_000 }),
+      cube.click(),
+    ])
+    expect(response.ok()).toBe(true)
+    expect(await response.json()).toMatchObject({
+      result: { ok: true, value: { ns: 'ui-theme', value: { preference } } },
+    })
+  }
+
   it('uses the persisted dark preference while plugins are still loading', async () => {
     onTestFailed(() => saveFailureShot(page, 'web-e2e-settings-boot-theme'))
     await page.emulateMedia({ colorScheme: 'light' })
     await page.getByRole('button', { name: '设置', exact: true }).click()
     const initialDialog = page.getByRole('dialog', { name: '设置' })
     const darkCube = initialDialog.getByRole('button', { name: '深色' })
-    await darkCube.click()
+    await selectTheme(darkCube, 'dark')
     await expect.poll(() => darkCube.getAttribute('aria-pressed'), { timeout: 5_000 }).toBe('true')
     await expect.poll(async () => readFile(join(scaffold.harnessHome, 'settings.yaml'), 'utf8'), { timeout: 5_000 })
       .toMatch(/ui-theme:\n\s+preference: dark/)
@@ -242,7 +262,7 @@ describe('web e2e: settings modal and General preferences', () => {
     await page.getByRole('button', { name: '设置', exact: true }).click()
     const restoredDialog = page.getByRole('dialog', { name: '设置' })
     const systemCube = restoredDialog.getByRole('button', { name: '跟随系统' })
-    await systemCube.click()
+    await selectTheme(systemCube, 'system')
     await expect.poll(() => systemCube.getAttribute('aria-pressed'), { timeout: 5_000 }).toBe('true')
     await expect.poll(() => page.evaluate(() => document.body.hasAttribute('data-ds-dark-theme')), {
       timeout: 5_000,
@@ -291,7 +311,7 @@ describe('web e2e: settings modal and General preferences', () => {
     await dialog.waitFor({ timeout: 10_000 })
     const darkCube = dialog.getByRole('button', { name: '深色' })
     expect(await darkCube.getAttribute('aria-pressed')).toBe('false')
-    await darkCube.click()
+    await selectTheme(darkCube, 'dark')
     // The full cascade: pressed state, Host-backed preference, body attribute,
     // alias token flip — all from one real user gesture.
     await expect.poll(() => darkCube.getAttribute('aria-pressed'), { timeout: 5_000 }).toBe('true')
@@ -340,7 +360,7 @@ describe('web e2e: settings modal and General preferences', () => {
     // `system` follows the emulated OS scheme (dark stays dark, light clears).
     await page.getByRole('button', { name: '设置', exact: true }).click()
     const systemCube = page.getByRole('dialog', { name: '设置' }).getByRole('button', { name: '跟随系统' })
-    await systemCube.click()
+    await selectTheme(systemCube, 'system')
     await expect.poll(() => systemCube.getAttribute('aria-pressed'), { timeout: 5_000 }).toBe('true')
     await expect.poll(async () => (await readState()).attr, { timeout: 5_000 }).toBe(false)
     expectThemeColorSynchronized(await readState())
@@ -349,7 +369,7 @@ describe('web e2e: settings modal and General preferences', () => {
     expectThemeColorSynchronized(await readState())
     // Restore for the specs that follow: light preference beats the emulated
     // dark OS scheme, leaving the shared page in the light default.
-    await page.getByRole('dialog', { name: '设置' }).getByRole('button', { name: '浅色' }).click()
+    await selectTheme(page.getByRole('dialog', { name: '设置' }).getByRole('button', { name: '浅色' }), 'light')
     await expect.poll(async () => (await readState()).attr, { timeout: 5_000 }).toBe(false)
     expectThemeColorSynchronized(await readState())
     await page.keyboard.press('Escape')

+ 4 - 2
apps/web/tests/workflow-run.e2e.ts

@@ -114,11 +114,13 @@ describe.skipIf(MODE === 'record')('web e2e: durable workflow run in Chat', () =
     await runDisclosure.press('Space')
     expect(await disclosures.count()).toBe(2)
     expect(await phaseDisclosure.getAttribute('aria-expanded')).toBe('true')
-    await member.focus()
-
     const lightColor = await member.locator('[data-member-label]').evaluate(element => getComputedStyle(element).color)
     await page.setViewportSize({ width: 560, height: 800 })
     await page.evaluate(() => { document.body.setAttribute('data-ds-dark-theme', '') })
+    // Exercise keyboard focus after the responsive layout has changed.
+    await phaseDisclosure.focus()
+    await phaseDisclosure.press('Tab')
+    await expect.poll(() => member.evaluate(element => element.matches(':focus-visible'))).toBe(true)
     const darkNarrow = await page.locator('[data-workflow-run]').evaluate((element) => {
       const panel = element as HTMLElement
       panel.style.width = '356px'

+ 2 - 2
native/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write native/README.md
-README.md: 51c8da7b57df15e65b8e431ee18ce6cebb89d54b
-README.zh.md: 6d07c6afb43e2763795a71639707454b9cfbe280
+README.md: 100e25dbfa9f472cb6a5a93a719eb7e1be02d10e
+README.zh.md: b1a66ac678334fd535951a7a0e4a921622b8ba51

+ 3 - 3
native/README.md

@@ -2,10 +2,10 @@
 
 English | [中文](README.zh.md)
 
-Native source and public packages maintained with DeepSeek Harness. The [`landlock-run/` workspace](landlock-run/README.md) owns the Landlock self-restrict-then-exec launcher consumed by the harness, including its architecture, three-package npm family, platform support, development workflow, and [release procedure](landlock-run/docs/release.md).
+Native source and public packages maintained with DeepSeek Harness. The [`system/` workspace](system/README.md) owns the Landlock launcher and POSIX flock binding, their platform packages, and the [release procedure](system/docs/release.md).
 
 ## Workspace and release boundary
 
-`landlock-run/` and its packages belong to the repository's root pnpm workspace and lockfile. Harness consumers use the current workspace entry package during development and CI, so a launcher contract change and its consumer update can land and be tested together.
+`system/` and its packages belong to the repository's root pnpm workspace and lockfile. Harness consumers use the current workspace entry package during development and CI, so a launcher contract change and its consumer update can land and be tested together.
 
-The main repository's `Landlock Run` workflow builds and tests each supported architecture. `Landlock Run Release` assembles those native artifacts, packs and verifies the three npm tarballs, then optionally publishes them under one launcher version. The entry package retains platform packages as npm optional dependencies, so npm still installs only the package matching the user's operating system and CPU.
+The main repository's `Node Addon System` workflow builds and tests each supported architecture. `Node Addon System Release` assembles those native artifacts, packs and verifies the npm tarballs, then optionally publishes them under one native version. The entry package retains platform packages as npm optional dependencies, so npm still installs only the package matching the user's operating system and CPU.

+ 3 - 3
native/README.zh.md

@@ -2,10 +2,10 @@
 
 [English](README.md) | 中文
 
-与 DeepSeek Harness 一同维护的原生源码和公开包。[`landlock-run/` workspace](landlock-run/README.zh.md) 负责 harness 使用的 Landlock 自限后执行启动器,包括其架构、由三个包组成的 npm 包家族、平台支持、开发工作流和[发布流程](landlock-run/docs/release.md)。
+与 DeepSeek Harness 一同维护的原生源码和公开包。[`system/` workspace](system/README.zh.md) 负责 Landlock 启动器、POSIX flock 绑定、平台包和[发布流程](system/docs/release.md)。
 
 ## Workspace 与发布边界
 
-`landlock-run/` 及其包属于仓库根 pnpm workspace,并共用根锁文件。开发和 CI 中的 harness 消费方直接使用当前 workspace 的入口包,因此启动器约定变更与消费方更新可以在同一个改动中落地并一起测试。
+`system/` 及其包属于仓库根 pnpm workspace,并共用根锁文件。开发和 CI 中的 harness 消费方直接使用当前 workspace 的入口包,因此启动器约定变更与消费方更新可以在同一个改动中落地并一起测试。
 
-主仓库的 `Landlock Run` 工作流为每个受支持架构构建并测试。`Landlock Run Release` 汇集这些原生产物,打包并验证三个 npm tarball,随后可选择以同一个启动器版本发布。入口包继续将平台包声明为 npm 可选依赖,因此 npm 仍然只会安装与用户操作系统和 CPU 匹配的包。
+主仓库的 `Node Addon System` 工作流为每个受支持架构构建并测试。`Node Addon System Release` 汇集这些原生产物,打包并验证 npm tarball,随后可选择以同一个原生包版本发布。入口包继续将平台包声明为 npm 可选依赖,因此 npm 仍然只会安装与用户操作系统和 CPU 匹配的包。

+ 0 - 50
native/landlock-run/AGENTS.md

@@ -1,50 +0,0 @@
-# AGENTS.md
-
-This directory builds `landlock-run`, a Landlock self-restrict-then-exec launcher: a small, auditable confinement binary distributed as prebuilt per-platform npm packages, plus the thin JS entry package that resolves it and implements its CLI contract. It belongs to the repository's root pnpm workspace and lockfile. The main repository owns native CI, tarball assembly, verification, and npm publication; keep package-family changes coordinated with harness consumers in the same repository.
-
-## Pre-release stance
-
-The project is pre-1.0. Prefer the correct public API over compatibility shims: if a package name, exported field, layout, or contract detail is wrong, rename it and update all references in the same change. Do not add deprecated aliases unless a stable release already needs them.
-
-## Runtime safety rules
-
-- Every tool must fail closed. If a ruleset cannot be created or the kernel does not enforce it, exit non-zero WITHOUT exec'ing the wrapped command. Never run unconfined as a fallback.
-- Runtime binaries and the entry packages take NO environment-variable overrides: which binary confines a process must never be decidable by the ambient environment. Test injection is by function parameter; the `NALR_*` prefix is for build/test orchestration only.
-- Kernel UAPI is self-defined in the C source (verbatim from the kernel headers), keeping builds independent of toolchain header vintage and making the definitions part of the audit record.
-- No libraries beyond libc, linked statically against musl. The audit surface of a tool is its C source plus the kernel's stable syscall contract.
-- The CLI contract of each tool ([docs/cli-contract.md](docs/cli-contract.md)) is the cross-repo compatibility contract: argv grammar, exit codes, and report lines change only with a version bump and a changelog entry, and consumers parse them only through the entry package.
-- There is deliberately NO install-time build fallback: a host without a matching platform package gets a nonexistent launcher path, the consumer's probe fails, and the consumer falls closed — that degradation is part of the design, not a gap to fill with node-gyp.
-
-## Repository layout
-
-```text
-packages/entry/     Published entry package: JavaScript API (resolve/probe/grants) + the C source.
-packages/linux-*/   Published per-platform packages: one prebuilt static binary, no JavaScript.
-scripts/            Build, matrix derivation, prepack gates, and release orchestration.
-test/               Plain-node behavioral tests (entry API + real-kernel launcher proofs).
-docs/               Architecture, packaging, CLI contract, release, support matrix, naming.
-```
-
-## Commands
-
-```sh
-pnpm install
-pnpm build:ts        # entry packages → lib/
-pnpm build:native    # this Linux architecture's binaries (needs musl-tools); fails fast elsewhere
-pnpm typecheck
-pnpm test            # entry tests everywhere; launcher tests need linux + built binary
-```
-
-## Packaging invariants
-
-- The package matrix is explicit, checked-in metadata: `packages/<name>/package.json` (`os`, `cpu`), `packages/<name>/prebuilds.json` (the binaries that may exist there), and [docs/support-matrix.md](docs/support-matrix.md) stay synchronized when the matrix changes. `scripts/github-matrix.mjs` derives CI and release matrices from it; nothing else enumerates platforms.
-- Platform package names contain platform only (`-linux-x64`), never tool variants — those stay inside `prebuilds.json`. Static musl linking is why there is no libc suffix: one binary serves glibc and musl distros.
-- Platform packages ship no JavaScript; the entry package resolves them to file paths. Backends prove themselves at runtime through the functional probe, never through metadata trust.
-- Builds are native-only: each architecture compiles its own binary on its own runner (CI is the builder of record); no cross toolchain enters the repo.
-- Every tarball is gated at pack time: platform packages refuse to pack without their declared binaries present, executable, and in the right ELF architecture (`verify-launcher-binary.mjs`), entry packages without built `lib/` (`verify-entry-lib.mjs`), and the release pipeline byte-pins installed binaries against the workspace builds (`verify-packed-install.mjs`).
-- Platform tarballs are packed with `npm pack`, never `pnpm pack`: pnpm's pack path strips the executable bit (observed on 11.7.0), shipping a launcher no consumer can spawn. `pack-release.mjs` encodes the split; the rehearsal asserts executability of the installed copy so a regression fails loudly instead of masquerading as a non-enforcing kernel.
-- Generated artifacts stay out of git: `packages/*/bin/`, `packages/*/lib/`, `dist/`, `.release/`, `*.tsbuildinfo`. Ignore rules live in the ROOT `.gitignore` only — a package-nested ignore file can silently drop payload from tarballs.
-
-## Documentation
-
-User-facing docs are English. Keep the README focused on install, usage, and support status; durable design decisions belong in docs/ alongside the code, and the current implementation belongs in [docs/architecture.md](docs/architecture.md).

+ 0 - 60
native/landlock-run/README.md

@@ -1,60 +0,0 @@
-# @deepseek-ai/node-addon-landlock-run
-
-English | [中文](README.zh.md)
-
-A [Landlock](https://landlock.io/) self-restrict-then-exec launcher for confining subprocesses on Linux, distributed as prebuilt per-platform npm packages plus a thin JS entry package that resolves the binary and speaks its CLI contract. Built for agent harnesses and other hosts that need to run untrusted commands under a filesystem allow-list without confining themselves.
-
-The tool is **`landlock-run`** — a self-restrict-then-exec [Landlock](https://landlock.io/) launcher (~300 lines of C11 over the raw kernel UAPI, statically linked against musl). It installs a Landlock ruleset on itself and `exec`s the wrapped command; the ruleset is inherited across `execve`, so the command and every process it spawns run confined while the invoking process stays unrestricted. Fail-closed: if the kernel cannot enforce, it exits without running the command.
-
-## Install
-
-```sh
-npm install @deepseek-ai/node-addon-landlock-run
-```
-
-Published packages use an entry package plus platform optional packages:
-
-```text
-@deepseek-ai/node-addon-landlock-run
-@deepseek-ai/node-addon-landlock-run-linux-x64
-@deepseek-ai/node-addon-landlock-run-linux-arm64
-```
-
-npm's `os`/`cpu` fields make installers fetch only the matching platform package. There is no install-time build fallback on purpose: on a host without a platform package the resolved path never exists, the probe reports `unusable`, and the consumer falls closed.
-
-## Usage
-
-```js
-import { grantArgs, launcherPath, probe } from '@deepseek-ai/node-addon-landlock-run';
-
-const launcher = launcherPath();
-if (probe(launcher) !== 'unusable') {
-  const argv = [launcher, ...grantArgs({ readOnly: ['/'], readWrite: ['/tmp/work'] }), '--', 'bash', '-c', command];
-  // spawn argv with your process runner of choice
-}
-```
-
-The public API is intentionally small:
-
-- `launcherPath()`: absolute path of this host's launcher (existence deliberately unchecked — the probe is the availability signal).
-- `probe(launcher?, { timeoutMs? })`: functional enforcement probe — `'full' | 'partial' | 'unusable'`.
-- `grantArgs({ readOnly?, readWrite? })`: the launcher's grant argv; everything not granted is denied.
-- `LAUNCHER_BIN` and `LAUNCHER_FAILURE_EXIT` (125): contract constants. A successfully exec'd child may also return 125, so consumers need the fatal diagnostic as well as the status to attribute launcher failure.
-
-The full binary contract (argv grammar, exit codes, report lines) is pinned in [docs/cli-contract.md](docs/cli-contract.md).
-
-## Support
-
-linux-x64 and linux-arm64, kernel with Landlock enabled (5.13+; ABI level determines `full` vs `partial` enforcement — see [docs/support-matrix.md](docs/support-matrix.md)). Other platforms deliberately have no package: consumers run different confinement backends there.
-
-## Development
-
-```sh
-corepack enable
-pnpm install
-pnpm build:ts        # entry packages → lib/
-pnpm build:native    # this Linux architecture's binaries (apt-get install musl-tools)
-pnpm test
-```
-
-Binaries are git-ignored and built natively per architecture — locally for your own machine, by CI's per-arch runners as the builders of record. Release flow: [docs/release.md](docs/release.md).

+ 0 - 60
native/landlock-run/README.zh.md

@@ -1,60 +0,0 @@
-# @deepseek-ai/node-addon-landlock-run
-
-[English](README.md) | 中文
-
-一个 [Landlock](https://landlock.io/)「先限制自身、再执行」启动器,用于在 Linux 上限制子进程。它以按平台预构建的 npm 包以及一个轻量 JS 入口包的形式发布;入口包负责解析二进制文件并遵循其 CLI(命令行界面)约定。该启动器面向需要让不可信命令在文件系统允许清单约束下运行、同时保持自身不受限制的 agent harness(智能体框架)和其他宿主。
-
-该工具是 **`landlock-run`**:一个「先限制自身、再执行」的 [Landlock](https://landlock.io/) 启动器(基于原始内核 UAPI 编写,约 300 行 C11,并与 musl 静态链接)。它在自身上安装 Landlock 规则集,再 `exec` 被包装的命令;该规则集会跨 `execve` 继承,因此命令及其产生的每个进程都在限制下运行,调用进程仍不受限制。它采用失败闭合:如果内核无法强制执行,则不运行命令并直接退出。
-
-## 安装
-
-```sh
-npm install @deepseek-ai/node-addon-landlock-run
-```
-
-已发布包由一个入口包和可选平台包组成:
-
-```text
-@deepseek-ai/node-addon-landlock-run
-@deepseek-ai/node-addon-landlock-run-linux-x64
-@deepseek-ai/node-addon-landlock-run-linux-arm64
-```
-
-npm 的 `os`/`cpu` 字段使安装器只拉取匹配的平台包。系统有意不提供安装时构建回退:在没有对应平台包的宿主上,解析后的路径绝不存在,探测会报告 `unusable`,消费方以失败闭合方式处理。
-
-## 用法
-
-```js
-import { grantArgs, launcherPath, probe } from '@deepseek-ai/node-addon-landlock-run';
-
-const launcher = launcherPath();
-if (probe(launcher) !== 'unusable') {
-  const argv = [launcher, ...grantArgs({ readOnly: ['/'], readWrite: ['/tmp/work'] }), '--', 'bash', '-c', command];
-  // spawn argv with your process runner of choice
-}
-```
-
-公开 API 有意保持精简:
-
-- `launcherPath()`:当前宿主启动器的绝对路径(有意不检查是否存在;探测结果才是可用性信号)。
-- `probe(launcher?, { timeoutMs? })`:功能性强制执行探测,返回 `'full' | 'partial' | 'unusable'`。
-- `grantArgs({ readOnly?, readWrite? })`:启动器的授权 argv;未授予的一切都被拒绝。
-- `LAUNCHER_BIN` 和 `LAUNCHER_FAILURE_EXIT`(125):约定常量。成功完成 exec 的子进程也可能返回 125,因此消费方必须同时看到致命诊断和该状态,才能将结果归因为启动器失败。
-
-完整的二进制约定(argv 语法、退出码、报告行)锁定在 [docs/cli-contract.md](docs/cli-contract.md) 中。
-
-## 支持范围
-
-支持 linux-x64 和 linux-arm64,且内核已启用 Landlock(5.13+;ABI 级别决定强制执行为 `full` 还是 `partial`,详见 [docs/support-matrix.md](docs/support-matrix.md))。其他平台有意不提供对应包:消费方会在这些平台上运行其他限制后端。
-
-## 开发
-
-```sh
-corepack enable
-pnpm install
-pnpm build:ts        # entry packages → lib/
-pnpm build:native    # this Linux architecture's binaries (apt-get install musl-tools)
-pnpm test
-```
-
-二进制文件被 git 忽略,并且按架构原生构建:本地只构建当前机器的版本,CI 各架构 runner 产出的构建则作为正式发布依据。发布流程详见 [docs/release.md](docs/release.md)。

+ 0 - 34
native/landlock-run/docs/architecture.md

@@ -1,34 +0,0 @@
-# Architecture
-
-This repository owns confinement *mechanism*, not policy: consumers (agent harnesses and sandbox capabilities) decide which paths a run may read or write; this package family provides the launcher that enforces those grants and the JavaScript API that resolves and speaks to it. The packaging follows the per-platform-package model of [`node-addon-require-builtin`](https://www.npmjs.com/package/@esplus/node-addon-require-builtin) (and esbuild), adapted from Node addons to standalone static executables.
-
-## Two-layer package family
-
-The family is one entry package plus per-platform binary packages:
-
-- **Entry package** (`@deepseek-ai/node-addon-landlock-run`): ESM JavaScript. Owns the tool's CLI contract — path resolution (`launcherPath`), the functional probe (`probe`), grant-argv construction (`grantArgs`), and the contract constants. Ships the C source in its tarball for auditability. Lists every platform package as an `optionalDependency`.
-- **Platform packages** (`@deepseek-ai/node-addon-landlock-run-linux-{x64,arm64}`): one prebuilt static binary under `bin/`, a `prebuilds.json` declaring it, and no JavaScript at all. npm's `os`/`cpu` fields select the matching one at install time; the entry package resolves it to a file path — there is nothing to import.
-
-Because the CLI parser and binary are versioned together in one package family, the parser cannot fall behind that binary version. Preventing that mismatch is why the package split exists.
-
-There is no shared loader package: platform packages have nothing to load. If a second tool ever needs shared JS, extract it then, not preemptively.
-
-## Resolution and availability
-
-`launcherPath()` resolves `@deepseek-ai/node-addon-landlock-run-<platform>-<arch>` and returns `<package>/bin/landlock-run`. When the package is not resolvable it returns a deterministic fallback path inside the entry package's own `node_modules` that simply never exists. Existence is deliberately unchecked either way: `probe()` is the single availability signal, and a missing binary probes `unusable` exactly like an unenforcing kernel. Consumers get one degradation path, not two.
-
-The probe is functional — the launcher builds and enforces a real maximal ruleset in a short-lived child — because version checks would miss a kernel that has the syscalls but refuses enforcement.
-
-## Fail-closed everywhere
-
-The launcher exits `125` without exec'ing the command on any launcher-level failure: usage error, unenforcing kernel, unopenable grant root, failed exec. Partial enforcement (an older Landlock ABI governing only a subset of accesses) is accepted, reported on stderr, and surfaced by the probe as `partial` — the consumer decides what its mode vocabulary promises at each level. Neither the binary nor the entry package reads environment variables: which binary confines a process is never decidable by the ambient environment.
-
-## Build and release model
-
-Builds are native-only. `scripts/build.ts` compiles the running architecture's binaries with the distro `musl-gcc` (static: no loader or libc expectations on consumers, one binary for glibc and musl distros); CI's per-architecture runners are the builders of record, and no cross toolchain exists in the repo. Review covers the C source and the CI job that built each binary, enforced by three gates: platform prepack refuses missing/wrong-ELF binaries, entry prepack refuses unbuilt `lib/`, and the release pipeline byte-pins installed binaries against the workspace builds they were packed from.
-
-The package matrix is checked-in metadata (`prebuilds.json` + `os`/`cpu` fields); `scripts/github-matrix.mjs` derives the CI and Release matrices from it, so adding a platform extends automation without editing workflows.
-
-## Adding a platform
-
-A new platform adds one `packages/<platform>/` package (`package.json` with `os`/`cpu`, `prebuilds.json`, README, LICENSE), a runner entry in `scripts/github-matrix.mjs`, and a row in [support-matrix.md](support-matrix.md) — added only together with a native GitHub runner that builds and proves it (the no-cross-toolchain rule). Sibling launchers for other confinement mechanisms belong in their own repositories on this same template, not as second tools here.

+ 0 - 45
native/landlock-run/docs/packaging.md

@@ -1,45 +0,0 @@
-# Packaging
-
-The package family uses the same layout as native packages such as esbuild: one JS entry package plus platform optional packages. Unlike Node addons there is no ABI or backend division — each platform package carries exactly the static executables its `prebuilds.json` declares.
-
-## Published packages
-
-```text
-@deepseek-ai/node-addon-landlock-run
-@deepseek-ai/node-addon-landlock-run-linux-x64
-@deepseek-ai/node-addon-landlock-run-linux-arm64
-```
-
-Unsupported platforms are intentionally absent from `optionalDependencies` — see [support-matrix.md](support-matrix.md).
-
-## Package matrix
-
-The matrix is explicit in checked-in metadata:
-
-- `packages/entry/package.json` lists the platform packages as `optionalDependencies`.
-- `packages/<name>/package.json` declares `os` and `cpu`. There is no `libc` field on purpose: the binaries are statically linked against musl and run on glibc and musl distros alike.
-- `packages/<name>/prebuilds.json` declares the binaries that may exist in that package (`tool`, `kind`, `path`).
-- [support-matrix.md](support-matrix.md) explains why unsupported platform packages are not published.
-
-`scripts/github-matrix.mjs` derives the CI and Release matrices from these files. `scripts/build.ts` builds only the current host's targets, into `packages/<name>/bin/`; it is not a matrix generator. When changing the matrix, update package metadata, `prebuilds.json`, the lockfile, and the support/release docs in the same change.
-
-## Runtime selection
-
-1. npm's `os`/`cpu` fields make installers fetch only the matching platform package.
-2. The entry package's `launcherPath()` resolves it to `<package>/bin/landlock-run`; unresolvable packages yield a deterministic, never-existing fallback path.
-3. `probe()` is the single availability signal: missing binary and unenforcing kernel are deliberately indistinguishable (`unusable`), so consumers have one fail-closed path.
-
-## No install fallback
-
-The entry package has NO install script and never compiles on the consumer host. A compile fallback would require a musl toolchain everywhere and turn a clean fail-closed degradation into an environment-dependent maybe. The packed-manifest check in `verify-packed-install.mjs` enforces the absence of install lifecycle scripts.
-
-## Pack gates
-
-Platform tarballs are produced by `npm pack`, entry tarballs by `pnpm pack` — deliberately split: `pnpm pack` (observed on 11.7.0) normalizes file modes and strips the executable bit, which would ship a launcher no consumer can spawn, while platform packages have no dependencies and so need none of pnpm's workspace-protocol conversion; entry packages need that conversion and carry no executables. `scripts/pack-release.mjs` encodes the split — never hand-pack a platform package with pnpm.
-
-Both pack paths produce the exact publish bytes behind a `prepack` gate:
-
-- Platform packages: `scripts/verify-launcher-binary.mjs` — every declared binary present, executable, ELF `e_machine` matching the declared `cpu`, nothing undeclared in `bin/`.
-- Entry packages: `scripts/verify-entry-lib.mjs` — built `lib/` present.
-
-`scripts/verify-packed-install.mjs` then rehearses the consumer path from the packed tarballs: payload checks, a throwaway install, a byte-pin of the installed binary against the workspace build, an executability check on the installed copy, and a real confinement world-proof through the installed launcher. A non-executable or missing binary fails loudly here instead of masquerading as a non-enforcing kernel.

+ 0 - 60
native/landlock-run/docs/release.md

@@ -1,60 +0,0 @@
-# Release
-
-Pre-1.0: treat this as a release checklist, not a stability policy.
-
-## Versioning
-
-The launcher workspace root and its three public packages share one version. Run the bump helper from the repository root:
-
-```sh
-pnpm --dir native/landlock-run release:bump patch          # or minor / major / x.y.z
-```
-
-It updates `native/landlock-run/package.json` and every `native/landlock-run/packages/*` manifest, refreshes the repository root lockfile (`--ignore-scripts --lockfile-only`), and runs `release:verify`. Explicit versions accept full semver including prereleases (`pnpm --dir native/landlock-run release:bump 0.0.0-test.0`); the publish workflow puts prerelease versions under the `next` dist-tag, so `latest` never points at a test build. Keep `workspace:*` dependencies in source; pnpm converts them to concrete versions during pack.
-
-Version bumps are normal source changes: open a release PR (or commit) with the launcher manifests and root lockfile, merge it, then create the matching `landlock-run-vX.Y.Z` tag from that commit. The namespace avoids colliding with release tags for other package families in the repository. The publish workflow validates that the tag matches every launcher package version.
-
-```sh
-pnpm --dir native/landlock-run release:commit patch        # bump + stage + commit in one command
-git tag landlock-run-v0.0.2
-```
-
-## Preflight
-
-```sh
-pnpm install --frozen-lockfile
-pnpm --dir native/landlock-run build:ts
-pnpm --dir native/landlock-run typecheck
-pnpm --dir native/landlock-run test:entry
-```
-
-On a Linux host, also rehearse the pack path locally:
-
-```sh
-pnpm --dir native/landlock-run build:native
-pnpm --dir native/landlock-run test:launcher
-node native/landlock-run/scripts/pack-release.mjs native/landlock-run/.release/npm --current-platform-only
-node native/landlock-run/scripts/verify-packed-install.mjs native/landlock-run/.release/npm --current-platform-only
-```
-
-## Publish
-
-Use the main repository's `Landlock Run Release` workflow so every binary is built on its matching native runner:
-
-1. Run it with `publish=false` (from the release commit) to build all platform binaries, assemble and verify the payloads, pack the tarballs in publish order, rehearse the packed install, and upload the `npm-tarballs` artifact for inspection.
-2. Create and push the `landlock-run-vX.Y.Z` tag matching the package versions.
-3. Run the same workflow from that tag with `publish=true`.
-
-The workflow publishes only from the final packed tarballs, in `publish-order.txt` order (platform packages before the entry that optionally depends on them). A current-platform rehearsal can still query npm for metadata about an incompatible optional platform package; that package cannot supply the host launcher, which comes from the matching local tarball. Publishing every platform package before the entry ensures a public entry version never points ahead of its platform packages. The workflow supports npm trusted publishing through GitHub OIDC; without it, provide an `NPM_TOKEN` secret in the `npm-publish` environment. Packages publish with `--access public`.
-
-The three scoped package names must be bootstrapped with an `@deepseek-ai` organization token through the `NPM_TOKEN` fallback: npm [requires a package to exist before a trusted publisher can be configured](https://docs.npmjs.com/cli/v11/commands/npm-trust/). After the first release creates all three packages, configure each package to trust `landlock-run-release.yml` in this repository with the `npm-publish` environment, then remove the fallback token when organization policy permits it.
-
-Manual local fallback (current platform's packages only) — always through `pack-release.mjs`, never `pnpm publish` directly (pnpm's pack path strips the launcher's executable bit; see [packaging.md](packaging.md)):
-
-```sh
-node native/landlock-run/scripts/pack-release.mjs native/landlock-run/dist/npm --current-platform-only
-node native/landlock-run/scripts/verify-packed-install.mjs native/landlock-run/dist/npm --current-platform-only
-while IFS= read -r tarball; do npm publish "native/landlock-run/dist/npm/${tarball}" --access public; done < native/landlock-run/dist/npm/publish-order.txt
-```
-
-Do not commit `.npmrc` files with tokens or registry overrides.

+ 0 - 18
native/landlock-run/docs/support-matrix.md

@@ -1,18 +0,0 @@
-# Support matrix
-
-## Supported
-
-| Platform package | GitHub runner (builder of record) | Notes |
-|---|---|---|
-| `@deepseek-ai/node-addon-landlock-run-linux-x64` | `ubuntu-24.04` | static musl — glibc and musl distros alike |
-| `@deepseek-ai/node-addon-landlock-run-linux-arm64` | `ubuntu-24.04-arm` | static musl — glibc and musl distros alike |
-
-Enforcement additionally requires a kernel with Landlock enabled (5.13+). The negotiated ABI level decides the probe verdict: every access this build knows governed → `full`; an older ABI governing a subset → `partial` (still confined for everything it supports); Landlock absent or disabled → `unusable`, and the launcher refuses to run commands at all. The probe — not the kernel version — is the authority: a kernel built without Landlock, or with the LSM disabled, probes `unusable` regardless of its version.
-
-## Deliberately unsupported
-
-- **darwin**: macOS consumers typically confine through `sandbox-exec`/Seatbelt, which ships with the OS — there is no binary to distribute.
-- **win32**: a Windows confinement launcher would be a different mechanism in its own repository, not a port of this one.
-- **Other Linux architectures** (riscv64, s390x, …): no native CI builder of record yet. The no-cross-toolchain rule means a platform package is added only together with a native runner that builds and proves it.
-
-A consumer on an unsupported platform resolves a nonexistent launcher path, probes `unusable`, and falls closed — the documented degradation, exercised by CI's darwin leg.

+ 0 - 18
native/landlock-run/packages/entry/README.md

@@ -1,18 +0,0 @@
-# @deepseek-ai/node-addon-landlock-run
-
-English | [中文](README.zh.md)
-
-Landlock self-restrict-then-exec launcher for confining subprocesses on Linux: this entry package resolves the per-platform prebuilt binary, runs its functional enforcement probe, and builds its grant argv — consumers never spell launcher flags or parse launcher output themselves.
-
-```js
-import { grantArgs, launcherPath, probe } from '@deepseek-ai/node-addon-landlock-run';
-
-const launcher = launcherPath();
-if (probe(launcher) !== 'unusable') {
-  const argv = [launcher, ...grantArgs({ readOnly: ['/'], readWrite: ['/tmp/work'] }), '--', 'bash', '-c', command];
-}
-```
-
-The launcher installs a Landlock ruleset on itself and `exec`s the wrapped command; the ruleset is inherited across `execve`, so the whole process tree runs confined. Everything not granted is denied, and launcher failures exit `125` without running the command — fail-closed, never fail-open. The binary contract is pinned in the repo's `docs/cli-contract.md`; the C source rides this tarball (`src/main.c`) for audit.
-
-Platform packages (`os`/`cpu`-selected optional dependencies, no JavaScript inside): `@deepseek-ai/node-addon-landlock-run-linux-x64`, `@deepseek-ai/node-addon-landlock-run-linux-arm64`. On hosts without one, `launcherPath()` returns a deterministic nonexistent path and `probe()` reports `'unusable'` — there is deliberately no install-time compile fallback.

+ 0 - 18
native/landlock-run/packages/entry/README.zh.md

@@ -1,18 +0,0 @@
-# @deepseek-ai/node-addon-landlock-run
-
-[English](README.md) | 中文
-
-用于在 Linux 上限制子进程的 Landlock「先限制自身、再执行」启动器:此入口包定位对应平台的预构建二进制文件,运行功能性强制执行探测,并构建其授权 argv。消费方无需自行拼写启动器标志或解析启动器输出。
-
-```js
-import { grantArgs, launcherPath, probe } from '@deepseek-ai/node-addon-landlock-run';
-
-const launcher = launcherPath();
-if (probe(launcher) !== 'unusable') {
-  const argv = [launcher, ...grantArgs({ readOnly: ['/'], readWrite: ['/tmp/work'] }), '--', 'bash', '-c', command];
-}
-```
-
-启动器在自身上安装 Landlock 规则集,再 `exec` 被包装的命令;该规则集会跨 `execve` 继承,因此整个进程树都在限制下运行。未授予的一切都被拒绝;启动器失败时以 `125` 退出且不运行命令:采用失败闭合策略,绝不在失败时放行。二进制约定锁定在仓库的 `docs/cli-contract.md` 中;C 源码作为 `src/main.c` 随该 tarball 分发,便于审计。
-
-平台包(由 `os`/`cpu` 选择的可选依赖,内部不含 JavaScript):`@deepseek-ai/node-addon-landlock-run-linux-x64`、`@deepseek-ai/node-addon-landlock-run-linux-arm64`。在缺少对应包的宿主上,`launcherPath()` 返回一个固定但不存在的路径,`probe()` 报告 `'unusable'`;系统有意不提供安装时编译回退。

+ 0 - 41
native/landlock-run/packages/entry/package.json

@@ -1,41 +0,0 @@
-{
-  "name": "@deepseek-ai/node-addon-landlock-run",
-  "version": "0.1.1",
-  "type": "module",
-  "description": "Landlock self-restrict-then-exec launcher for sandboxing subprocesses on Linux: per-platform prebuilt static binaries plus the JS seam that resolves, probes, and speaks their CLI contract",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/deepseek-harness/deepseek-harness.git",
-    "directory": "native/landlock-run/packages/entry"
-  },
-  "main": "lib/index.js",
-  "types": "lib/index.d.ts",
-  "exports": {
-    ".": {
-      "types": "./lib/index.d.ts",
-      "default": "./lib/index.js"
-    },
-    "./package.json": "./package.json"
-  },
-  "files": [
-    "README.md",
-    "lib/",
-    "!lib/*.tsbuildinfo",
-    "src/main.c"
-  ],
-  "scripts": {
-    "build:js": "tsc -b",
-    "prepack": "node ../../scripts/verify-entry-lib.mjs"
-  },
-  "engines": {
-    "node": ">=20"
-  },
-  "license": "BSD-3-Clause",
-  "publishConfig": {
-    "access": "public"
-  },
-  "optionalDependencies": {
-    "@deepseek-ai/node-addon-landlock-run-linux-arm64": "workspace:*",
-    "@deepseek-ai/node-addon-landlock-run-linux-x64": "workspace:*"
-  }
-}

+ 0 - 9
native/landlock-run/packages/linux-arm64/README.md

@@ -1,9 +0,0 @@
-# @deepseek-ai/node-addon-landlock-run-linux-arm64
-
-English | [中文](README.zh.md)
-
-Prebuilt `bin/landlock-run` Landlock launcher for linux-arm64 — a static musl binary compiled natively (no cross toolchain) from the C source shipped in [`@deepseek-ai/node-addon-landlock-run`](https://www.npmjs.com/package/@deepseek-ai/node-addon-landlock-run). npm's `os`/`cpu` fields select this package at install time; the entry package resolves it to a file path — it ships no JavaScript and is never imported.
-
-The binary is git-ignored and rides the npm tarball via the `files` list; the `prepack` gate refuses to pack when it is missing or has the wrong ELF architecture, and the release pipeline byte-pins the packed binary against the CI build it came from. Static musl linking means one binary for glibc and musl distros alike — hence no libc suffix in the name.
-
-Sibling: `@deepseek-ai/node-addon-landlock-run-linux-x64`.

+ 0 - 9
native/landlock-run/packages/linux-arm64/README.zh.md

@@ -1,9 +0,0 @@
-# @deepseek-ai/node-addon-landlock-run-linux-arm64
-
-[English](README.md) | 中文
-
-面向 linux-arm64 的预构建 `bin/landlock-run` Landlock 启动器:一个由 [`@deepseek-ai/node-addon-landlock-run`](https://www.npmjs.com/package/@deepseek-ai/node-addon-landlock-run) 包所附的 C 源码原生编译而成的静态 musl 二进制文件(不使用交叉工具链)。npm 的 `os`/`cpu` 字段在安装时选择此包;入口包将其定位到文件路径。该包不包含 JavaScript,也绝不会被导入。
-
-该二进制文件被 git 忽略,并通过 `files` 列表进入 npm tarball;如果文件缺失或 ELF 架构错误,`prepack` 门禁会拒绝打包,发布流水线则会按字节核验打包的二进制文件与其来源 CI 构建产物一致。静态 musl 链接使同一个二进制文件同时适用于 glibc 和 musl 发行版,因此名称中没有 libc 后缀。
-
-同级包:`@deepseek-ai/node-addon-landlock-run-linux-x64`。

+ 0 - 10
native/landlock-run/packages/linux-arm64/prebuilds.json

@@ -1,10 +0,0 @@
-{
-  "platform": "linux-arm64",
-  "binaries": [
-    {
-      "tool": "landlock-run",
-      "kind": "static-musl",
-      "path": "bin/landlock-run"
-    }
-  ]
-}

+ 0 - 9
native/landlock-run/packages/linux-x64/README.md

@@ -1,9 +0,0 @@
-# @deepseek-ai/node-addon-landlock-run-linux-x64
-
-English | [中文](README.zh.md)
-
-Prebuilt `bin/landlock-run` Landlock launcher for linux-x64 — a static musl binary compiled natively (no cross toolchain) from the C source shipped in [`@deepseek-ai/node-addon-landlock-run`](https://www.npmjs.com/package/@deepseek-ai/node-addon-landlock-run). npm's `os`/`cpu` fields select this package at install time; the entry package resolves it to a file path — it ships no JavaScript and is never imported.
-
-The binary is git-ignored and rides the npm tarball via the `files` list; the `prepack` gate refuses to pack when it is missing or has the wrong ELF architecture, and the release pipeline byte-pins the packed binary against the CI build it came from. Static musl linking means one binary for glibc and musl distros alike — hence no libc suffix in the name.
-
-Sibling: `@deepseek-ai/node-addon-landlock-run-linux-arm64`.

+ 0 - 9
native/landlock-run/packages/linux-x64/README.zh.md

@@ -1,9 +0,0 @@
-# @deepseek-ai/node-addon-landlock-run-linux-x64
-
-[English](README.md) | 中文
-
-面向 linux-x64 的预构建 `bin/landlock-run` Landlock 启动器:一个由 [`@deepseek-ai/node-addon-landlock-run`](https://www.npmjs.com/package/@deepseek-ai/node-addon-landlock-run) 包所附的 C 源码原生编译而成的静态 musl 二进制文件(不使用交叉工具链)。npm 的 `os`/`cpu` 字段在安装时选择此包;入口包将其定位到文件路径。该包不包含 JavaScript,也绝不会被导入。
-
-该二进制文件被 git 忽略,并通过 `files` 列表进入 npm tarball;如果文件缺失或 ELF 架构错误,`prepack` 门禁会拒绝打包,发布流水线则会按字节核验打包的二进制文件与其来源 CI 构建产物一致。静态 musl 链接使同一个二进制文件同时适用于 glibc 和 musl 发行版,因此名称中没有 libc 后缀。
-
-同级包:`@deepseek-ai/node-addon-landlock-run-linux-arm64`。

+ 0 - 10
native/landlock-run/packages/linux-x64/prebuilds.json

@@ -1,10 +0,0 @@
-{
-  "platform": "linux-x64",
-  "binaries": [
-    {
-      "tool": "landlock-run",
-      "kind": "static-musl",
-      "path": "bin/landlock-run"
-    }
-  ]
-}

+ 0 - 86
native/landlock-run/scripts/build.ts

@@ -1,86 +0,0 @@
-/**
- * Build every native tool this host can build, into its per-platform
- * package.
- *
- * Targets are derived from the checked-in matrix: each
- * `packages/<name>/prebuilds.json` whose `platform` matches this host names
- * the binaries to produce; the TOOLS table below maps each `tool` to its C
- * source. Builds are NATIVE-ONLY — each Linux architecture compiles its own
- * binary with the distro's `musl-gcc` (static musl: runs on glibc and musl
- * distros alike, no loader or libc expectations on the consumer host), and
- * CI's per-arch runners are the builders of record. No cross toolchain
- * exists here on purpose: native runners replace it, and the audit surface
- * is the reviewed C source plus the CI job that built the binary.
- *
- * Binaries land in `packages/<name>/bin/` — git-ignored (root
- * `.gitignore`), packed into the platform package's npm tarball behind its
- * `prepack` gate (`scripts/verify-launcher-binary.mjs`).
- *
- * Run: `pnpm run build:native` (Linux with musl-gcc on PATH:
- * `apt-get install musl-tools`). Non-Linux hosts fail fast — no platform
- * package exists for them to build.
- */
-import { spawnSync } from 'node:child_process'
-import { existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs'
-import { basename, dirname, join, resolve } from 'node:path'
-
-/** Each native tool's C source, keyed by the `tool` field in prebuilds.json. */
-const TOOLS: Record<string, { source: string }> = {
-  'landlock-run': { source: 'packages/entry/src/main.c' },
-}
-
-const repoRoot = resolve(import.meta.dirname, '..')
-
-if (process.platform !== 'linux') {
-  console.error(`build: native tools are built natively per Linux architecture (no cross toolchain) — nothing to build on ${process.platform}. CI's per-arch runners build and rehearse every platform package.`)
-  process.exit(1)
-}
-const hostPlatform = `linux-${process.arch}`
-
-/** This host's platform packages, from the checked-in matrix. */
-const targets: { packageDir: string; tool: string; binaryPath: string; kind: string }[] = []
-const packagesRoot = join(repoRoot, 'packages')
-for (const name of readdirSync(packagesRoot).sort()) {
-  const prebuildsFile = join(packagesRoot, name, 'prebuilds.json')
-  if (!existsSync(prebuildsFile)) continue
-  const prebuilds = JSON.parse(readFileSync(prebuildsFile, 'utf8')) as {
-    platform: string
-    binaries: { tool: string; kind: string; path: string }[]
-  }
-  if (prebuilds.platform !== hostPlatform) continue
-  for (const binary of prebuilds.binaries) {
-    targets.push({ packageDir: join(packagesRoot, name), tool: binary.tool, binaryPath: binary.path, kind: binary.kind })
-  }
-}
-if (targets.length === 0) {
-  console.error(`build: no platform package declares binaries for ${hostPlatform} — supported platforms are the packages/*/prebuilds.json "platform" values.`)
-  process.exit(1)
-}
-
-for (const target of targets) {
-  const tool = TOOLS[target.tool]
-  if (tool === undefined) {
-    console.error(`build: prebuilds.json names unknown tool "${target.tool}" — add it to the TOOLS table in scripts/build.ts.`)
-    process.exit(1)
-  }
-  if (target.kind !== 'static-musl') {
-    console.error(`build: unknown binary kind "${target.kind}" — the only toolchain here is static musl.`)
-    process.exit(1)
-  }
-  const binary = join(target.packageDir, target.binaryPath)
-  mkdirSync(dirname(binary), { recursive: true })
-
-  // -static against musl: self-contained, no loader/libc expectations on the
-  // consumer host. -Werror is safe to keep hard: CI pins the builder images,
-  // and a new warning on a toolchain bump deserves a look, not a pass.
-  const result = spawnSync('musl-gcc', [
-    '-std=c11', '-Os', '-Wall', '-Wextra', '-Werror', '-static', '-s',
-    '-o', binary, join(repoRoot, tool.source),
-  ], { stdio: ['ignore', 'inherit', 'inherit'] })
-  if (result.error !== undefined || result.status !== 0) {
-    console.error('build: musl-gcc failed' +
-      (result.error ? ` (${result.error.message} — is musl-tools installed?)` : ''))
-    process.exit(1)
-  }
-  console.log(`build: built ${basename(target.packageDir)}/${target.binaryPath}`)
-}

+ 0 - 88
native/landlock-run/scripts/repo.mjs

@@ -1,88 +0,0 @@
-#!/usr/bin/env node
-/**
- * Shared helpers for the repo scripts: package discovery, the checked-in
- * prebuild matrix, and binary verification. The package matrix is explicit
- * metadata — `packages/<name>/prebuilds.json` marks a platform package and
- * declares its binaries; everything else under `packages/` is an entry
- * package. Scripts derive from these files and never guess.
- */
-
-import fs from 'node:fs';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-
-export const root = fileURLToPath(new URL('..', import.meta.url));
-const packagesRoot = path.join(root, 'packages');
-
-/** ELF `e_machine` (offset 18, little-endian) per platform-package `cpu` value. */
-const E_MACHINE = { x64: 62, arm64: 183 };
-
-export function readJson(file) {
-  return JSON.parse(fs.readFileSync(file, 'utf8'));
-}
-
-/** Platform packages: every `packages/<name>` carrying a `prebuilds.json`. */
-export function platformDirs() {
-  return fs.readdirSync(packagesRoot)
-    .filter((name) => fs.existsSync(path.join(packagesRoot, name, 'prebuilds.json')))
-    .sort()
-    .map((name) => path.join('packages', name));
-}
-
-/** Entry packages: every other `packages/<name>` with a `package.json`. */
-export function entryDirs() {
-  return fs.readdirSync(packagesRoot)
-    .filter((name) => !fs.existsSync(path.join(packagesRoot, name, 'prebuilds.json')))
-    .filter((name) => fs.existsSync(path.join(packagesRoot, name, 'package.json')))
-    .sort()
-    .map((name) => path.join('packages', name));
-}
-
-/** All published packages in publish order: platform packages before the entries that optionally depend on them. */
-export function packageDirs() {
-  return [...platformDirs(), ...entryDirs()];
-}
-
-/**
- * Verify one platform package's binaries against its `prebuilds.json`:
- * every declared binary exists, nothing undeclared sits in `bin/`, and each
- * file's ELF `e_machine` matches the package's declared `cpu`. Throws with
- * a remediation message on the first mismatch.
- */
-export function verifyPlatformBinaries(packageDir) {
-  const manifest = readJson(path.join(packageDir, 'package.json'));
-  const prebuilds = readJson(path.join(packageDir, 'prebuilds.json'));
-  const cpu = manifest.cpu?.[0];
-  if (cpu === undefined || !(cpu in E_MACHINE)) {
-    throw new Error(`${manifest.name}: unsupported or missing "cpu" in package.json (expected one of: ${Object.keys(E_MACHINE).join(', ')})`);
-  }
-
-  for (const binary of prebuilds.binaries) {
-    const file = path.join(packageDir, binary.path);
-    if (!fs.existsSync(file)) {
-      throw new Error(`${manifest.name}: missing ${binary.path} — run \`pnpm build:native\` on a ${prebuilds.platform} host (or assemble release artifacts) before packing.`);
-    }
-    try {
-      fs.accessSync(file, fs.constants.X_OK);
-    } catch {
-      // Only reachable when the mode was mangled somewhere between build and
-      // here (e.g. an archive step that normalized permissions) — the build
-      // itself always produces 755.
-      throw new Error(`${manifest.name}: ${binary.path} is not executable — a pack/extract step stripped the mode bit.`);
-    }
-    const machine = fs.readFileSync(file).readUInt16LE(18);
-    if (machine !== E_MACHINE[cpu]) {
-      throw new Error(`${manifest.name}: ${binary.path} has ELF e_machine ${machine}, expected ${E_MACHINE[cpu]} for ${cpu} — the binary was built for a different architecture.`);
-    }
-  }
-
-  const declared = prebuilds.binaries.map((binary) => path.basename(binary.path)).sort();
-  const binDir = path.join(packageDir, 'bin');
-  const actual = fs.existsSync(binDir) ? fs.readdirSync(binDir).sort() : [];
-  const extra = actual.filter((name) => !declared.includes(name));
-  if (extra.length) {
-    throw new Error(`${manifest.name}: bin/ contains files not declared in prebuilds.json: ${extra.join(', ')}`);
-  }
-
-  return { name: manifest.name, count: prebuilds.binaries.length };
-}

+ 0 - 0
native/landlock-run/.gitignore → native/system/.gitignore


+ 28 - 0
native/system/AGENTS.md

@@ -0,0 +1,28 @@
+# AGENTS.md
+
+This workspace owns `@deepseek-ai/node-addon-system`: the Linux `landlock-run` confinement executable and the POSIX `system.node` binding. It shares the root pnpm workspace and lockfile; native packages have one independent version and release workflow.
+
+## Runtime rules
+
+- Landlock's argv, exit codes, diagnostics, and fail-closed confinement are defined in [docs/cli-contract.md](docs/cli-contract.md). Do not change them when extending another system capability.
+- The launcher uses only libc, statically linked against musl. Its kernel UAPI definitions remain in the reviewed C source.
+- Node bindings use stable Node-API v8, never NAN, V8 C++ APIs, or experimental Node interfaces. Linux glibc and musl addons are distinct binaries; macOS has its own Mach-O bundle.
+- The flock binding attempts only `LOCK_EX | LOCK_NB` in asynchronous work and captures errno on that worker. The caller owns the fd through completion and releases its lock by closing it.
+- `./landlock-run` and `./flock` are independent capability exports; the package has no root export. Neither import loads the addon. `./flock` loads it only when called; Windows retains the Harness's existing semaphore implementation.
+- Runtime binary selection has no environment-variable overrides. `NALR_REQUIRE_LANDLOCK` is a test-only enforcement requirement.
+- There is no install-time compile fallback. Missing Landlock binaries probe unusable; missing flock bindings reject acquisition, never silently grant a lock.
+
+## Layout and commands
+
+`packages/entry/` owns JavaScript, types, and auditable C sources. Platform packages hold only binaries and metadata. `scripts/` owns native builds, packing, validation, and release; `test/` owns real process and lock behavior.
+
+Run `pnpm build:ts`, `pnpm build:native`, `pnpm build:test-oracle`, `pnpm typecheck`, and `pnpm test` in this directory. Linux full builds require musl-gcc; macOS uses cc. Repository tests build only their host addon through the root `build:native-system` script. The independent syscall fixture is test-only and never enters a published platform package.
+
+## Packaging and verification
+
+- `os`/`cpu` and `prebuilds.json` are the checked-in package matrix. CI derives runners from that matrix, builds natively on each architecture, and tests identical addon bytes under several Node releases.
+- Linux packages contain `bin/landlock-run`, `bin/glibc/system.node`, and `bin/musl/system.node`. macOS packages contain `bin/system.node`. No Windows platform package is needed by these capabilities.
+- Platform prepack rejects missing, undeclared, wrong-format, wrong-architecture, and non-Node-API addon payloads. Launcher executability is checked separately.
+- Platform tarballs use npm pack to preserve executable permissions. The entry uses pnpm pack for workspace version conversion.
+- Packed-install verification checks manifests, installs local tarballs without a registry, byte-pins payloads, and exercises both the installed flock binding and Landlock's functional probe.
+- Build outputs stay ignored. Source/consumer changes and their behavior tests land together; preserve bilingual READMEs and independent native publication.

+ 0 - 0
native/landlock-run/LICENSE → native/system/LICENSE


+ 3 - 3
native/landlock-run/README.i18n.yaml → native/system/README.i18n.yaml

@@ -1,6 +1,6 @@
 # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
-#   pnpm run verify-translation-pairing --write native/landlock-run/README.md
-README.md: bf9b163d42a9b7402dbf4c045d47e7b8d36e15ab
-README.zh.md: 7bd4765a73f0d5df2a4710ce06ff319f6c902db6
+#   pnpm run verify-translation-pairing --write native/system/README.md
+README.md: 5a01754cb96fabbdfd2dbf4f068f19addd7a2347
+README.zh.md: dabd00cecd05ded13a50d2efd000985afed713d4

+ 41 - 0
native/system/README.md

@@ -0,0 +1,41 @@
+---
+description: "Prebuilt system primitives for Linux confinement and POSIX Session write locks."
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system
+
+English | [中文](README.zh.md)
+
+## Summary
+
+Use the Linux `landlock-run` executable to confine subprocesses, or the `./flock` entry to acquire a POSIX write lock. Platform packages contain the precompiled binaries; consumer installation never builds native code. Landlock policy and Session lifecycle remain with callers.
+
+## Table of Contents
+
+- [Use](#use)
+- [Support](#support)
+- [Development](#development)
+
+## Use
+
+`@deepseek-ai/node-addon-system/landlock-run` exports `launcherPath`, `probe`, and `grantArgs` for Landlock. Its executable name, flags, and failure semantics are defined by the [CLI contract](docs/cli-contract.md).
+
+The [flock behavior contract](docs/flock-contract.md) maps descriptor, process, and advisory-lock semantics to independent native tests.
+
+`@deepseek-ai/node-addon-system/flock` exports `tryLockExclusive(fd): Promise<void>`. Keep the descriptor open until completion. Acquisition uses nonblocking exclusive flock; contention rejects with `EAGAIN` or `EWOULDBLOCK`, and closing the final descriptor for the open file description releases the lock. See the [entry README](packages/entry/README.md).
+
+Importing either entry does not load an addon. A missing Landlock executable probes unusable; a missing flock binding rejects acquisition. Neither path compiles or silently grants unsupported behavior.
+
+## Support
+
+Linux x64/arm64 packages contain the static Landlock executable and separate glibc/musl `system.node` files. macOS x64/arm64 packages contain `system.node` only. Landlock additionally needs an enforcing Linux kernel; Windows uses the Harness's existing locking implementation. The [support matrix](docs/support-matrix.md) names builders and verification owners.
+
+## Development
+
+From this directory, `pnpm build:ts` builds the entry, `pnpm build:native` builds the host's declared native payload, and `pnpm build:test-oracle` builds an independent flock syscall fixture. Then `pnpm test` exercises entry, lock, packaging, and available kernel behavior. Linux requires musl-gcc for a complete build; macOS uses cc. The root `pnpm run build:native-system` builds only the current host addon for source tests.
+
+The [architecture](docs/architecture.md), [packaging](docs/packaging.md), and [release procedure](docs/release.md) own implementation and publication details.
+
+### Dev Note
+
+None.

+ 41 - 0
native/system/README.zh.md

@@ -0,0 +1,41 @@
+---
+description: "为 Linux 进程隔离与 POSIX Session 写锁提供预编译系统原语。"
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system
+
+[English](README.md) | 中文
+
+## Summary
+
+使用 Linux `landlock-run` 可执行文件限制子进程,或通过 `./flock` 入口获取 POSIX 写锁。平台包包含预编译二进制;用户安装时不会构建原生代码。Landlock 策略与 Session 生命周期仍由调用方负责。
+
+## Table of Contents
+
+- [使用](#use)
+- [支持范围](#support)
+- [开发](#development)
+
+## Use
+
+`@deepseek-ai/node-addon-system/landlock-run` 为 Landlock 导出 `launcherPath`、`probe` 和 `grantArgs`。其可执行文件名、参数和失败语义由 [CLI 约定](docs/cli-contract.md) 定义。
+
+[flock 行为约定](docs/flock-contract.md) 将描述符、进程和咨询式锁语义对应到独立原生测试。
+
+`@deepseek-ai/node-addon-system/flock` 导出 `tryLockExclusive(fd): Promise<void>`。在调用完成前保持描述符打开。获取操作使用非阻塞独占 flock;竞争以 `EAGAIN` 或 `EWOULDBLOCK` 拒绝,关闭该打开文件描述的最后一个描述符即释放锁。参见[入口 README](packages/entry/README.zh.md)。
+
+导入任一入口都不会加载 addon。Landlock 可执行文件缺失时探测为不可用;flock 绑定缺失时拒绝获取。两条路径都不会编译或静默授予不受支持的行为。
+
+## Support
+
+Linux x64/arm64 包包含静态 Landlock 可执行文件,以及分别用于 glibc/musl 的 `system.node` 文件。macOS x64/arm64 包仅包含 `system.node`。Landlock 还需要支持强制执行的 Linux 内核;Windows 使用 Harness 既有锁实现。[支持矩阵](docs/support-matrix.md) 指定构建者与验证负责人。
+
+## Development
+
+在本目录运行 `pnpm build:ts` 构建入口、`pnpm build:native` 构建当前宿主声明的原生产物、`pnpm build:test-oracle` 构建独立的 flock 系统调用 fixture。随后用 `pnpm test` 验证入口、锁、打包及可用的内核行为。Linux 完整构建需要 musl-gcc;macOS 使用 cc。根目录 `pnpm run build:native-system` 只构建源码测试所需的当前宿主 addon。
+
+[架构](docs/architecture.md)、[打包](docs/packaging.md)和[发布流程](docs/release.md)分别负责实现与发布细节。
+
+### Dev Note
+
+无。

+ 25 - 0
native/system/docs/architecture.md

@@ -0,0 +1,25 @@
+# Architecture
+
+The system package family supplies native mechanisms to Node callers: a Linux confinement executable and a POSIX file-lock binding. Consumers own sandbox policy and Session lifecycle.
+
+## Package family
+
+The ESM package `@deepseek-ai/node-addon-system` and its optional platform packages share one version. Platform metadata chooses the operating system and CPU; each package's `prebuilds.json` declares the files it must contain.
+
+The `./landlock-run` entry owns Landlock path resolution, grant argv, and the functional probe. It does not load native addons. The `./flock` entry lazily loads `system.node` only when `tryLockExclusive(fd)` is called. Importing either JavaScript entry therefore works without a matching native payload. The package exposes these capability subpaths and its manifest, without a root export.
+
+## Separate mechanisms
+
+`landlock-run` remains a static musl executable with the [existing CLI contract](cli-contract.md). It installs confinement on itself before exec, and refuses to exec if enforcement is unavailable. A missing launcher or unsupported kernel produces an unusable probe.
+
+`system.node` uses stable Node-API v8. Its flock operation follows [fs-ext's asynchronous callback model](https://github.com/baudehlo/node-fs-ext/blob/v2.1.1/fs-ext.cc): it runs `flock(fd, LOCK_EX | LOCK_NB)` in asynchronous work and records errno on that worker. The native callback receives zero or positive errno; JavaScript owns the promise and syscall error construction. Setup errors throw into that promise. Callback exceptions are reported through Node's uncaught-exception handler; unexpected Node-API failures terminate the process. A terminating environment may suppress JavaScript completion, but its cleanup waits for queued or running native work before freeing storage.
+
+The descriptor belongs to the caller and must stay open through completion. The binding neither opens nor closes it; closing the final descriptor for its open file description releases the lock.
+
+The JSONL backend retains its inode check, materialization timing, and close lifecycle. Windows uses its existing koffi semaphore and never calls this POSIX binding. The browser worker supplies a single-process replacement for the flock entry, while running the Landlock JavaScript API unchanged.
+
+## Builds and release
+
+Repository builds and `build:bench` explicitly build the host addon before running consumers. Each platform builds natively on its CI runner. Landlock is static-musl; Linux addons are separately built for glibc and musl, and macOS uses a Mach-O bundle. Stable Node-API removes the Node-major build dimension, not OS, CPU, or libc differences. CI exercises identical addon bytes under Node 20, 22, 24, and 26; Linux also runs the musl addon in Alpine containers.
+
+Platform prepack validates file formats, architecture, payload completeness, and Node-API exports. The packed-install rehearsal installs local tarballs, checks their bytes, and exercises the installed mechanisms. Missing capabilities fail explicitly; no consumer install runs a compiler. [Packaging](packaging.md) and [release](release.md) own the operational details.

+ 0 - 0
native/landlock-run/docs/cli-contract.md → native/system/docs/cli-contract.md


+ 36 - 0
native/system/docs/flock-contract.md

@@ -0,0 +1,36 @@
+# POSIX flock behavior
+
+`tryLockExclusive(fd)` returns a promise for one `flock(fd, LOCK_EX | LOCK_NB)` attempt. The syscall runs off the JavaScript thread. The caller keeps the descriptor open through completion; the binding does not open, duplicate, or close it. It exposes neither a blocking-wait API nor a shared-lock API.
+
+## Behavior tests
+
+The [native tests](../test/flock.test.js) exercise real descriptors and independent processes. The [C oracle](../test/fixtures/flock-oracle.c) calls the operating system directly, independently of `system.node`.
+
+| Condition | Required observation |
+|---|---|
+| No conflicting lock | Acquisition resolves to void |
+| Same open file description acquires again | Acquisition succeeds without a second ownership record |
+| Separate opens of the same file | Exactly one exclusive holder; the contender rejects with EAGAIN/EWOULDBLOCK |
+| Different files | Both can be locked |
+| Independent C flock holder | The addon cannot acquire, and the C oracle cannot acquire while the addon holds the lock |
+| A shared flock holder | The addon's exclusive attempt conflicts |
+| Holder remains live | A nonblocking attempt reports contention before the holder unlocks |
+| Ordinary read/write by another process | Access is allowed: flock is advisory, not an I/O permission mechanism |
+| One unrelated descriptor closes | The actual holder keeps its lock |
+| A descriptor inherited by a child remains open | Closing the parent's descriptor does not release the shared open file description's lock |
+| Last owning descriptor closes | An already-open contender can acquire |
+| Holder process exits or is killed | Acquisition succeeds after process exit, without a stale-lock timeout |
+| Invalid descriptor | The promise rejects with EBADF and positive errno |
+| Native argument validation fails | The JavaScript entry returns a rejected promise without throwing synchronously |
+| Native completion callback | It receives zero or the request's positive errno asynchronously |
+| Native completion callback throws | The exception reaches Node's uncaught-exception handler |
+| Concurrent success/failure calls | Each completion receives its own syscall errno |
+| Worker environment terminates before or during its callback | Native work and cleanup reach completion without taking ownership of the caller's descriptor |
+
+Tests synchronize through IPC or flushed line protocols and await process exit before asserting crash recovery. They do not use fixed sleeps or a millisecond performance threshold to prove nonblocking behavior. The syscall oracle is built only for tests and never included in a published platform package.
+
+## Limits
+
+Locks belong to open file descriptions and follow the host filesystem's flock semantics. Removing or replacing a pathname does not transfer a lock to the replacement inode; the JSONL backend separately checks inode identity. Network filesystems can have different or unsupported lock semantics. Windows does not use this API and retains its existing semaphore implementation.
+
+Node-API compatibility tests reuse the same platform addon under different Node versions. They complement these syscall tests; loading a binary alone does not prove correct locking behavior.

+ 5 - 5
native/landlock-run/docs/naming.md → native/system/docs/naming.md

@@ -2,18 +2,18 @@
 
 ## npm packages
 
-The public package family belongs to the `@deepseek-ai` scope and uses the `node-addon-landlock-run` package prefix; platform packages append platform information only:
+The public package family belongs to the `@deepseek-ai` scope and uses the `node-addon-system` package prefix; platform packages append platform information only:
 
 ```text
-@deepseek-ai/node-addon-landlock-run
-@deepseek-ai/node-addon-landlock-run-<platform>
+@deepseek-ai/node-addon-system
+@deepseek-ai/node-addon-system-<platform>
 ```
 
-Platform suffixes carry no libc component (binaries are static musl) and no variant component — variants stay inside `prebuilds.json` and binary filenames.
+Platform suffixes carry OS and CPU. Linux libc variants live inside the same platform package and are declared in `prebuilds.json`.
 
 ## Binaries
 
-The launcher executable is `landlock-run`, shipped at `bin/landlock-run` inside each platform package.
+The Linux launcher remains `bin/landlock-run`. The Node-API addon is `system.node`: `bin/glibc/system.node` and `bin/musl/system.node` on Linux, `bin/system.node` on macOS.
 
 ## Environment variables
 

+ 24 - 0
native/system/docs/packaging.md

@@ -0,0 +1,24 @@
+# Packaging
+
+The family publishes one ESM entry package plus OS/CPU-selected optional platform packages. All share one version; platform packages publish before the entry.
+
+## Payloads
+
+The entry package exports the Landlock API at `./landlock-run` and the asynchronous lock API at `./flock`, with C sources included for auditability. There is no root export. Platform packages contain no JavaScript.
+
+- Linux: `bin/landlock-run`, `bin/glibc/system.node`, and `bin/musl/system.node`.
+- macOS: `bin/system.node`.
+
+`package.json` supplies OS/CPU metadata; `prebuilds.json` supplies tool, binary kind, path, and addon Node-API/libc metadata. CI matrices and release assembly derive from those files. Nested paths remain intact in uploaded artifacts and tarballs.
+
+## Installation and use
+
+Neither entry nor platform packages have installation lifecycle scripts. The entry resolves its matching optional package when a native operation needs it. Optional means that the package manager selects a platform, not that a requested lock can succeed without its binding.
+
+The `./landlock-run` API stays importable without native payloads and reports unavailable enforcement through its probe. The flock entry is also lazy at import; acquisition reports a missing or unloadable addon instead of compiling or granting an unprotected lock.
+
+## Pack verification
+
+Platform tarballs use npm pack to preserve the launcher's executable bit. The entry uses pnpm pack to convert workspace dependency versions. Prepack rejects missing or undeclared payloads, invalid ELF/Mach-O architecture or type, addons without Node-API exports, and launchers without executable permission.
+
+The installed-artifact rehearsal verifies concrete dependency versions and absence of installation hooks, performs an offline npm install from local tarballs, and compares installed bytes with build outputs. It then proves flock contention/close release and probes the installed Landlock launcher; real confinement remains required on enforcing CI kernels.

+ 63 - 0
native/system/docs/release.md

@@ -0,0 +1,63 @@
+# Release
+
+Pre-1.0: treat this as a release checklist, not a stability policy.
+
+## Versioning
+
+The native workspace root and every platform/entry package share one version. Run the bump helper from the repository root:
+
+```sh
+pnpm --dir native/system release:bump patch          # or minor / major / x.y.z
+```
+
+It updates `native/system/package.json` and every `native/system/packages/*` manifest, refreshes the repository root lockfile (`--ignore-scripts --lockfile-only`), and runs `release:verify`. Explicit versions accept full semver including prereleases (`pnpm --dir native/system release:bump 0.0.0-test.0`); the publish workflow puts prerelease versions under the `next` dist-tag, so `latest` never points at a test build. Keep `workspace:*` dependencies in source; pnpm converts them to concrete versions during pack.
+
+Version bumps are normal source changes: open a release PR (or commit) with the launcher manifests and root lockfile, merge it, then create the matching `node-addon-system-vX.Y.Z` tag from that commit. The namespace avoids colliding with release tags for other package families in the repository. The publish workflow validates that the tag matches every launcher package version.
+
+```sh
+pnpm --dir native/system release:commit patch        # bump + stage + commit in one command
+git tag node-addon-system-v0.0.2
+```
+
+## Preflight
+
+```sh
+pnpm install --frozen-lockfile
+pnpm --dir native/system build:ts
+pnpm --dir native/system typecheck
+pnpm --dir native/system test:entry
+```
+
+On a supported Linux or macOS host, also rehearse the pack path locally:
+
+```sh
+pnpm --dir native/system build:native
+pnpm --dir native/system build:test-oracle
+pnpm --dir native/system test:launcher
+pnpm --dir native/system test:flock
+pnpm --dir native/system test:packaging
+node native/system/scripts/pack-release.mjs native/system/.release/npm --current-platform-only
+node native/system/scripts/verify-packed-install.mjs native/system/.release/npm --current-platform-only
+```
+
+## Publish
+
+Use the main repository's `Node Addon System Release` workflow so every binary is built on its matching native runner:
+
+1. Run it with `publish=false` (from the release commit) to build all platform binaries, assemble and verify the payloads, pack the tarballs in publish order, rehearse the packed install, and upload the `npm-tarballs` artifact for inspection.
+2. Create and push the `node-addon-system-vX.Y.Z` tag matching the package versions.
+3. Run the same workflow from that tag with `publish=true`.
+
+The workflow publishes only from the final packed tarballs, in `publish-order.txt` order (platform packages before the entry that optionally depends on them). The current-platform rehearsal uses offline npm installation; the current entry and platform package come from local tarballs. Publishing every platform package before the entry ensures a public entry version never points ahead of its platform packages. The workflow supports npm trusted publishing through GitHub OIDC; without it, provide an `NPM_TOKEN` secret in the `npm-publish` environment. Packages publish with `--access public`.
+
+New scoped package names must be bootstrapped with an `@deepseek-ai` organization token through the `NPM_TOKEN` fallback: npm [requires a package to exist before a trusted publisher can be configured](https://docs.npmjs.com/cli/v11/commands/npm-trust/). After the first release creates the packages, configure each package to trust `node-addon-system-release.yml` in this repository with the `npm-publish` environment, then remove the fallback token when organization policy permits it.
+
+Manual local fallback (current platform's packages only) — always through `pack-release.mjs`, never `pnpm publish` directly (pnpm's pack path strips the launcher's executable bit; see [packaging.md](packaging.md)):
+
+```sh
+node native/system/scripts/pack-release.mjs native/system/dist/npm --current-platform-only
+node native/system/scripts/verify-packed-install.mjs native/system/dist/npm --current-platform-only
+while IFS= read -r tarball; do npm publish "native/system/dist/npm/${tarball}" --access public; done < native/system/dist/npm/publish-order.txt
+```
+
+Do not commit `.npmrc` files with tokens or registry overrides.

+ 14 - 0
native/system/docs/support-matrix.md

@@ -0,0 +1,14 @@
+# Support matrix
+
+| Platform package suffix | Builder | Payload |
+|---|---|---|
+| linux-x64 | ubuntu-24.04 | static Landlock executable; glibc and musl system.node |
+| linux-arm64 | ubuntu-24.04-arm | static Landlock executable; glibc and musl system.node |
+| darwin-x64 | macos-15-intel | system.node |
+| darwin-arm64 | macos-latest | system.node |
+
+The stable Node-API v8 addon is built once per platform/libc and exercised by CI under Node 20, 22, 24, and 26. macOS builds target 11.0 or later. Linux binding selection uses the running Node process's libc; the static launcher serves both libc variants.
+
+Landlock additionally requires an enforcing Linux kernel. The functional probe determines full, partial, or unusable enforcement; kernel version alone is not an availability guarantee.
+
+Windows has neither a Landlock launcher nor this POSIX addon. The Harness retains its existing Windows semaphore implementation. Other CPU/OS combinations have no published platform package: Landlock probes unusable, and flock acquisition rejects. New platform support requires a native builder and installed-artifact verification.

+ 6 - 3
native/landlock-run/package.json → native/system/package.json

@@ -1,5 +1,5 @@
 {
-  "name": "@deepseek-ai/node-addon-landlock-run-workspace",
+  "name": "@deepseek-ai/node-addon-system-workspace",
   "version": "0.1.1",
   "private": true,
   "type": "module",
@@ -9,10 +9,13 @@
     "build": "pnpm build:ts",
     "build:ts": "tsc -b",
     "build:native": "tsx ./scripts/build.ts",
+    "build:test-oracle": "node ./scripts/build-test-oracle.mjs",
     "typecheck": "tsc --noEmit && tsc -b --dry",
-    "test": "node ./test/entry.test.js && node ./test/launcher.test.js",
+    "test": "node ./test/entry.test.js && node ./test/launcher.test.js && node --test ./test/flock.test.js ./test/package-matrix.test.js",
     "test:entry": "node ./test/entry.test.js",
     "test:launcher": "node ./test/launcher.test.js",
+    "test:flock": "node --test ./test/flock.test.js",
+    "test:packaging": "node --test ./test/package-matrix.test.js",
     "gha:matrix": "node ./scripts/github-matrix.mjs",
     "release:bump": "node ./scripts/bump-release.mjs",
     "release:commit": "node ./scripts/commit-release.mjs",
@@ -23,7 +26,7 @@
     "release:verify-packed-install": "node ./scripts/verify-packed-install.mjs"
   },
   "devDependencies": {
-    "@deepseek-ai/node-addon-landlock-run": "workspace:*",
+    "@deepseek-ai/node-addon-system": "workspace:*",
     "@types/node": "^26.0.1",
     "tsx": "^4.20.6",
     "typescript": "^6.0.3"

+ 0 - 0
native/landlock-run/packages/linux-arm64/LICENSE → native/system/packages/darwin-arm64/LICENSE


+ 3 - 3
native/landlock-run/packages/linux-x64/README.i18n.yaml → native/system/packages/darwin-arm64/README.i18n.yaml

@@ -1,6 +1,6 @@
 # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
-#   pnpm run verify-translation-pairing --write native/landlock-run/packages/linux-x64/README.md
-README.md: d08cc0c4abbc74f64c5d1075dea796427211bd8f
-README.zh.md: ed6839aa6230b16b82c67a716fc0a4128e5a977c
+#   pnpm run verify-translation-pairing --write native/system/packages/darwin-arm64/README.md
+README.md: 71cfaacc9bc442341b3a9d57389c2cb1904fbb70
+README.zh.md: 5e54c8155009b98e3336ea612535ce08e56817ae

+ 9 - 0
native/system/packages/darwin-arm64/README.md

@@ -0,0 +1,9 @@
+---
+description: "Prebuilt system.node for macOS arm64 POSIX locks."
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system-darwin-arm64
+
+English | [中文](README.zh.md)
+
+This platform package supplies `bin/system.node`, a stable Node-API v8 addon used by `@deepseek-ai/node-addon-system/flock`. It contains no Landlock executable, JavaScript loader, or installation build script. The native workflow builds it on macOS arm64 and owns its installed-artifact validation.

+ 9 - 0
native/system/packages/darwin-arm64/README.zh.md

@@ -0,0 +1,9 @@
+---
+description: "为 macOS arm64 POSIX 锁提供预编译 system.node。"
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system-darwin-arm64
+
+[English](README.md) | 中文
+
+此平台包提供 `bin/system.node`,供 `@deepseek-ai/node-addon-system/flock` 使用的稳定 Node-API v8 addon。它不包含 Landlock 可执行文件、JavaScript 加载器或安装构建脚本。Native 工作流在 macOS arm64 上构建它,并负责验证安装后的产物。

+ 19 - 0
native/system/packages/darwin-arm64/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "@deepseek-ai/node-addon-system-darwin-arm64",
+  "version": "0.1.1",
+  "description": "Prebuilt POSIX flock Node-API binding for macOS arm64",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/deepseek-harness/deepseek-harness.git",
+    "directory": "native/system/packages/darwin-arm64"
+  },
+  "os": ["darwin"],
+  "cpu": ["arm64"],
+  "files": ["README.md", "bin/", "prebuilds.json"],
+  "scripts": {
+    "prepack": "node ../../scripts/verify-launcher-binary.mjs"
+  },
+  "engines": { "node": ">=20" },
+  "license": "BSD-3-Clause",
+  "publishConfig": { "access": "public" }
+}

+ 6 - 0
native/system/packages/darwin-arm64/prebuilds.json

@@ -0,0 +1,6 @@
+{
+  "platform": "darwin-arm64",
+  "binaries": [
+    { "tool": "flock", "kind": "node-api", "napi": 8, "path": "bin/system.node" }
+  ]
+}

+ 0 - 0
native/landlock-run/packages/linux-x64/LICENSE → native/system/packages/darwin-x64/LICENSE


+ 3 - 3
native/landlock-run/packages/entry/README.i18n.yaml → native/system/packages/darwin-x64/README.i18n.yaml

@@ -1,6 +1,6 @@
 # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
-#   pnpm run verify-translation-pairing --write native/landlock-run/packages/entry/README.md
-README.md: fff722428c5d213d9fcce0ee87a1d48cdc189884
-README.zh.md: cbf867d9dd3551a12b74b19a6ceaf2be3e1c53a6
+#   pnpm run verify-translation-pairing --write native/system/packages/darwin-x64/README.md
+README.md: 1740788eef943373591a895baeb7207635972a46
+README.zh.md: 644165743486a29e48bee7af33429ebf4f5d8fe2

+ 9 - 0
native/system/packages/darwin-x64/README.md

@@ -0,0 +1,9 @@
+---
+description: "Prebuilt system.node for macOS x64 POSIX locks."
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system-darwin-x64
+
+English | [中文](README.zh.md)
+
+This platform package supplies `bin/system.node`, a stable Node-API v8 addon used by `@deepseek-ai/node-addon-system/flock`. It contains no Landlock executable, JavaScript loader, or installation build script. The native workflow builds it on macOS x64 and owns its installed-artifact validation.

+ 9 - 0
native/system/packages/darwin-x64/README.zh.md

@@ -0,0 +1,9 @@
+---
+description: "为 macOS x64 POSIX 锁提供预编译 system.node。"
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system-darwin-x64
+
+[English](README.md) | 中文
+
+此平台包提供 `bin/system.node`,供 `@deepseek-ai/node-addon-system/flock` 使用的稳定 Node-API v8 addon。它不包含 Landlock 可执行文件、JavaScript 加载器或安装构建脚本。Native 工作流在 macOS x64 上构建它,并负责验证安装后的产物。

+ 19 - 0
native/system/packages/darwin-x64/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "@deepseek-ai/node-addon-system-darwin-x64",
+  "version": "0.1.1",
+  "description": "Prebuilt POSIX flock Node-API binding for macOS x64",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/deepseek-harness/deepseek-harness.git",
+    "directory": "native/system/packages/darwin-x64"
+  },
+  "os": ["darwin"],
+  "cpu": ["x64"],
+  "files": ["README.md", "bin/", "prebuilds.json"],
+  "scripts": {
+    "prepack": "node ../../scripts/verify-launcher-binary.mjs"
+  },
+  "engines": { "node": ">=20" },
+  "license": "BSD-3-Clause",
+  "publishConfig": { "access": "public" }
+}

+ 6 - 0
native/system/packages/darwin-x64/prebuilds.json

@@ -0,0 +1,6 @@
+{
+  "platform": "darwin-x64",
+  "binaries": [
+    { "tool": "flock", "kind": "node-api", "napi": 8, "path": "bin/system.node" }
+  ]
+}

+ 3 - 3
native/landlock-run/packages/linux-arm64/README.i18n.yaml → native/system/packages/entry/README.i18n.yaml

@@ -1,6 +1,6 @@
 # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
-#   pnpm run verify-translation-pairing --write native/landlock-run/packages/linux-arm64/README.md
-README.md: dfcc9e97dc1393a42ff4b89ac009cdfd31e1497b
-README.zh.md: 350044e92f1d0247222cc16c82f03588ed0154c9
+#   pnpm run verify-translation-pairing --write native/system/packages/entry/README.md
+README.md: 8f6a4d341c8f9e4c104e5706e08d9a7d45c065e1
+README.zh.md: 152257916df0cf40511b9743d389ae753ab6c85c

+ 15 - 0
native/system/packages/entry/README.md

@@ -0,0 +1,15 @@
+---
+description: "JavaScript entry for the prebuilt Landlock launcher and asynchronous POSIX flock."
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system
+
+English | [中文](README.zh.md)
+
+The `./landlock-run` entry exports the Landlock launcher path, enforcement probe, grant arguments, and protocol constants. The independent `./flock` entry exports `tryLockExclusive(fd): Promise<void>`; importing either entry does not load `system.node`. The package has no root export.
+
+The lock operation attempts `LOCK_EX | LOCK_NB` asynchronously. Keep the caller-owned descriptor open until completion; contention rejects with `EAGAIN`/`EWOULDBLOCK`, other syscall failures also reject, and errors carry their code, positive errno, and `syscall: 'flock'`. Native setup errors reject the same promise. Closing the last descriptor for the open file description releases the lock. The binding does not open, duplicate, close, or explicitly unlock descriptors.
+
+Optional OS/CPU platform packages carry the binaries. Linux has `bin/landlock-run` and separate `bin/glibc/system.node` / `bin/musl/system.node`; macOS has `bin/system.node`. Missing or unloadable flock bindings reject acquisition, without installation-time compilation. Landlock remains a separate executable with its existing fail-closed protocol; unsupported kernels/platforms probe unusable.
+
+The two C sources ship for auditability. See the workspace [architecture](../../docs/architecture.md), [support matrix](../../docs/support-matrix.md), and [CLI contract](../../docs/cli-contract.md).

+ 15 - 0
native/system/packages/entry/README.zh.md

@@ -0,0 +1,15 @@
+---
+description: "预编译 Landlock 启动器与异步 POSIX flock 的 JavaScript 入口。"
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system
+
+[English](README.md) | 中文
+
+`./landlock-run` 入口导出 Landlock 启动器路径、强制执行探测、授权参数和协议常量。独立的 `./flock` 入口导出 `tryLockExclusive(fd): Promise<void>`;导入任一入口都不会加载 `system.node`。包不提供根导出。
+
+锁操作异步尝试 `LOCK_EX | LOCK_NB`。在完成前保持调用方拥有的描述符打开;竞争以 `EAGAIN`/`EWOULDBLOCK` 拒绝,其他系统调用失败也会拒绝,错误携带 code、正 errno 和 `syscall: 'flock'`。原生调用准备阶段的错误也会拒绝同一个 promise。关闭该打开文件描述的最后一个描述符即释放锁。绑定不打开、复制、关闭或显式解锁描述符。
+
+可选操作系统/CPU 平台包携带二进制。Linux 包含 `bin/landlock-run` 和分别用于两种 libc 的 `bin/glibc/system.node` / `bin/musl/system.node`;macOS 包含 `bin/system.node`。flock 绑定缺失或无法加载时拒绝获取,不在安装时编译。Landlock 仍是遵循既有失败关闭协议的独立可执行文件;不支持的内核或平台探测为不可用。
+
+两个 C 源文件随包分发以供审计。参见工作区[架构](../../docs/architecture.md)、[支持矩阵](../../docs/support-matrix.md)和 [CLI 约定](../../docs/cli-contract.md)。

+ 46 - 0
native/system/packages/entry/package.json

@@ -0,0 +1,46 @@
+{
+  "name": "@deepseek-ai/node-addon-system",
+  "version": "0.1.1",
+  "type": "module",
+  "description": "Prebuilt system primitives: a Linux Landlock launcher and asynchronous POSIX flock through stable Node-API",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/deepseek-harness/deepseek-harness.git",
+    "directory": "native/system/packages/entry"
+  },
+  "exports": {
+    "./landlock-run": {
+      "types": "./lib/index.d.ts",
+      "default": "./lib/index.js"
+    },
+    "./flock": {
+      "types": "./lib/flock.d.ts",
+      "default": "./lib/flock.js"
+    },
+    "./package.json": "./package.json"
+  },
+  "files": [
+    "README.md",
+    "lib/",
+    "!lib/*.tsbuildinfo",
+    "src/main.c",
+    "src/flock.c"
+  ],
+  "scripts": {
+    "build:js": "tsc -b",
+    "prepack": "node ../../scripts/verify-entry-lib.mjs"
+  },
+  "engines": {
+    "node": ">=20"
+  },
+  "license": "BSD-3-Clause",
+  "publishConfig": {
+    "access": "public"
+  },
+  "optionalDependencies": {
+    "@deepseek-ai/node-addon-system-darwin-arm64": "workspace:*",
+    "@deepseek-ai/node-addon-system-darwin-x64": "workspace:*",
+    "@deepseek-ai/node-addon-system-linux-arm64": "workspace:*",
+    "@deepseek-ai/node-addon-system-linux-x64": "workspace:*"
+  }
+}

+ 164 - 0
native/system/packages/entry/src/flock.c

@@ -0,0 +1,164 @@
+/*
+ * Node-API v8 binding for asynchronous flock(LOCK_EX | LOCK_NB).
+ * The caller owns fd through completion; this module never opens, duplicates,
+ * closes, or explicitly unlocks it. The callback receives zero or a positive
+ * errno; JavaScript owns the promise and syscall error construction.
+ */
+
+#include <node_api.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/file.h>
+
+typedef struct {
+  napi_env env;
+  napi_ref callback;
+  napi_async_work work;
+  napi_async_cleanup_hook_handle cleanup;
+  int fd;
+  int error;
+  bool closing;
+} lock_request;
+
+static void check_status(napi_status status, const char *message) {
+  if (status != napi_ok) {
+    napi_fatal_error("flock", NAPI_AUTO_LENGTH, message, NAPI_AUTO_LENGTH);
+  }
+}
+
+static void release_request(lock_request *request) {
+  if (request->callback != NULL) {
+    (void)napi_delete_reference(request->env, request->callback);
+  }
+  if (request->work != NULL) {
+    (void)napi_delete_async_work(request->env, request->work);
+  }
+  if (request->cleanup != NULL) {
+    (void)napi_remove_async_cleanup_hook(request->cleanup);
+  }
+  free(request);
+}
+
+static napi_value throw_setup_error(napi_env env, napi_status status,
+                                   const char *message) {
+  if (status != napi_pending_exception) {
+    status = napi_throw_error(env, "ERR_FLOCK_ASYNC_WORK", message);
+    bool pending;
+    /* Error construction can fail with both generic_failure and a JS exception. */
+    check_status(napi_is_exception_pending(env, &pending), "Cannot inspect flock setup exception");
+    if (!pending && status != napi_pending_exception) check_status(status, message);
+  }
+  return NULL;
+}
+
+static void execute_lock(napi_env env, void *data) {
+  (void)env;
+  lock_request *request = data;
+  request->error = flock(request->fd, LOCK_EX | LOCK_NB) == 0 ? 0 : errno;
+}
+
+static void complete_lock(napi_env env, napi_status status, void *data) {
+  lock_request *request = data;
+  if (env != NULL && !request->closing) {
+    napi_value callback;
+    napi_value receiver;
+    napi_value result;
+    check_status(status, "flock async work did not complete");
+    check_status(napi_get_reference_value(env, request->callback, &callback),
+                 "Cannot retrieve flock callback");
+    check_status(napi_get_undefined(env, &receiver), "Cannot create flock receiver");
+    check_status(napi_create_int32(env, request->error, &result),
+                 "Cannot create flock result");
+    status = napi_call_function(env, receiver, callback, 1, &result, NULL);
+  } else {
+    status = napi_ok;
+  }
+  release_request(request);
+  /* Node's async-work dispatcher reports callback exceptions and handles termination. */
+  if (status != napi_pending_exception) {
+    check_status(status, "Cannot invoke flock callback");
+  }
+}
+
+static void cleanup_lock(napi_async_cleanup_hook_handle handle, void *data) {
+  (void)handle;
+  lock_request *request = data;
+  request->closing = true;
+  /*
+   * Running work cannot be cancelled. The hook keeps the environment alive
+   * until completion releases both the work and this hook; it never frees
+   * memory that the execution thread can still access.
+   */
+  (void)napi_cancel_async_work(request->env, request->work);
+}
+
+static napi_value try_lock(napi_env env, napi_callback_info info) {
+  size_t argc = 2;
+  napi_value argv[2];
+  double fd;
+  napi_status status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
+  if (status != napi_ok) {
+    return throw_setup_error(env, status, "Cannot read flock arguments");
+  }
+  if (argc < 1 || napi_get_value_double(env, argv[0], &fd) != napi_ok) {
+    (void)napi_throw_type_error(env, NULL, "fd must be a number");
+    return NULL;
+  }
+  if (!(fd >= INT_MIN && fd <= INT_MAX) || fd != (int)fd) {
+    (void)napi_throw_range_error(env, NULL, "fd must be a signed C int");
+    return NULL;
+  }
+  napi_valuetype callback_type;
+  if (argc < 2 || napi_typeof(env, argv[1], &callback_type) != napi_ok ||
+      callback_type != napi_function) {
+    (void)napi_throw_type_error(env, NULL, "callback must be a function");
+    return NULL;
+  }
+
+  lock_request *request = calloc(1, sizeof(*request));
+  if (request == NULL) {
+    (void)napi_throw_error(env, "ENOMEM", "Cannot allocate flock async work");
+    return NULL;
+  }
+  request->env = env;
+  request->fd = (int)fd;
+
+  status = napi_create_reference(env, argv[1], 1, &request->callback);
+  if (status != napi_ok) {
+    release_request(request);
+    return throw_setup_error(env, status, "Cannot retain flock callback");
+  }
+  napi_value name;
+  status = napi_create_string_utf8(env, "flock", NAPI_AUTO_LENGTH, &name);
+  if (status == napi_ok) {
+    status = napi_create_async_work(env, NULL, name, execute_lock, complete_lock,
+                                   request, &request->work);
+  }
+  if (status != napi_ok) {
+    release_request(request);
+    return throw_setup_error(env, status, "Cannot create flock async work");
+  }
+  status = napi_add_async_cleanup_hook(env, cleanup_lock, request, &request->cleanup);
+  if (status != napi_ok) {
+    release_request(request);
+    return throw_setup_error(env, status, "Cannot register flock environment cleanup");
+  }
+  status = napi_queue_async_work(env, request->work);
+  if (status != napi_ok) {
+    /* Queue failure schedules no completion callback. */
+    release_request(request);
+    return throw_setup_error(env, status, "Cannot queue flock async work");
+  }
+  return NULL;
+}
+
+NAPI_MODULE_INIT() {
+  napi_value function;
+  if (napi_create_function(env, "tryLock", NAPI_AUTO_LENGTH, try_lock,
+                           NULL, &function) != napi_ok ||
+      napi_set_named_property(env, exports, "tryLock", function) != napi_ok) {
+    return NULL;
+  }
+  return exports;
+}

+ 57 - 0
native/system/packages/entry/src/flock.ts

@@ -0,0 +1,57 @@
+/** Lazy POSIX flock entry; importing it does not load a native addon. */
+import { createRequire } from 'node:module'
+import { dirname, join } from 'node:path'
+import { getSystemErrorName } from 'node:util'
+
+interface FlockBinding {
+  tryLock(fd: number, callback: (errno: number) => void): void
+}
+
+let binding: FlockBinding | undefined
+
+function loadBinding(): FlockBinding {
+  if (binding) return binding
+  const { platform, arch } = process
+  if (platform !== 'linux' && platform !== 'darwin') {
+    throw Object.assign(new Error(`flock is not supported on ${platform}-${arch}`), {
+      code: 'ERR_FLOCK_UNSUPPORTED_PLATFORM',
+      syscall: 'flock',
+    })
+  }
+
+  let filename = 'system.node'
+  if (platform === 'linux') {
+    // Node's report types omit the libc field supplied by Linux reports.
+    const report = process.report.getReport() as { header: { glibcVersionRuntime?: string } }
+    filename = join(report.header.glibcVersionRuntime ? 'glibc' : 'musl', filename)
+  }
+  const require = createRequire(import.meta.url)
+  const manifest = require.resolve(`@deepseek-ai/node-addon-system-${platform}-${arch}/package.json`)
+  binding = require(join(dirname(manifest), 'bin', filename)) as FlockBinding
+  return binding
+}
+
+/**
+ * Attempt an exclusive, nonblocking POSIX flock on the caller's descriptor.
+ * The syscall runs in asynchronous work, so acquisition can occur after this
+ * call returns. Keep fd open until the promise settles; the binding never
+ * opens, duplicates, or closes it. Closing the locked descriptor releases the
+ * lock once all descriptors for its open file description are closed.
+ * @param fd - Open file descriptor to lock; ownership remains with the caller.
+ * @returns A promise resolving to void on acquisition. Contention rejects with
+ *   EAGAIN/EWOULDBLOCK; other syscall failures also reject. Syscall errors carry
+ *   code, positive errno, and syscall='flock'. Native setup errors, unsupported
+ *   platforms, and addon loading failures reject; importing alone does not load it.
+ */
+export async function tryLockExclusive(fd: number): Promise<void> {
+  const errno = await new Promise<number>((resolve) => {
+    loadBinding().tryLock(fd, resolve)
+  })
+  if (errno === 0) return
+  const code = getSystemErrorName(-errno)
+  throw Object.assign(new Error(`${code}: flock failed`), {
+    code,
+    errno,
+    syscall: 'flock',
+  })
+}

+ 2 - 2
native/landlock-run/packages/entry/src/index.ts → native/system/packages/entry/src/index.ts

@@ -53,7 +53,7 @@ export interface LauncherGrants {
 
 /**
  * Path of the launcher binary for this host: resolved from the per-platform
- * npm package `@deepseek-ai/node-addon-landlock-run-<platform>-<arch>` (npm's
+ * npm package `@deepseek-ai/node-addon-system-<platform>-<arch>` (npm's
  * `os`/`cpu` fields make installers fetch only the matching one). When the
  * package is not resolvable — a platform without one, or an install that
  * skipped the optional dependency — the returned fallback path points inside
@@ -69,7 +69,7 @@ export interface LauncherGrants {
 export function launcherPath(
   resolvePackageJson: (specifier: string) => string = createRequire(import.meta.url).resolve,
 ): string {
-  const platformPackage = `@deepseek-ai/node-addon-landlock-run-${process.platform}-${process.arch}`
+  const platformPackage = `@deepseek-ai/node-addon-system-${process.platform}-${process.arch}`
   try {
     return join(dirname(resolvePackageJson(`${platformPackage}/package.json`)), 'bin', LAUNCHER_BIN)
   } catch {

+ 1 - 1
native/landlock-run/packages/entry/src/main.c → native/system/packages/entry/src/main.c

@@ -31,7 +31,7 @@
  * linked statically), so the whole audit surface is this file plus the
  * kernel's stable syscall contract. Built natively per architecture by
  * `scripts/build.ts` into the per-platform npm packages
- * (`@deepseek-ai/node-addon-landlock-run-linux-{x64,arm64}`); the argv grammar,
+ * (`@deepseek-ai/node-addon-system-linux-{x64,arm64}`); the argv grammar,
  * exit codes, and report lines are pinned in `docs/cli-contract.md`.
  */
 

+ 0 - 0
native/landlock-run/packages/entry/tsconfig.json → native/system/packages/entry/tsconfig.json


+ 28 - 0
native/system/packages/linux-arm64/LICENSE

@@ -0,0 +1,28 @@
+BSD 3-Clause License
+
+Copyright (c) 2026, node-addon-landlock-run contributors
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 6 - 0
native/system/packages/linux-arm64/README.i18n.yaml

@@ -0,0 +1,6 @@
+# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
+# side as of the last confirmed-consistent state. Both languages carry equal authority;
+# after editing either side, bring the other along and re-record with:
+#   pnpm run verify-translation-pairing --write native/system/packages/linux-arm64/README.md
+README.md: b1e97481a3f59b5b7cf85e6565cd3d078e42cd7f
+README.zh.md: 79f3b75e16570c4dff8d7249bcd75481f11cc85c

+ 11 - 0
native/system/packages/linux-arm64/README.md

@@ -0,0 +1,11 @@
+---
+description: "Prebuilt Landlock launcher and POSIX flock addons for Linux arm64."
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system-linux-arm64
+
+English | [中文](README.zh.md)
+
+This platform package contains the static musl executable `bin/landlock-run` and Node-API v8 addons `bin/glibc/system.node` and `bin/musl/system.node`. The entry chooses the addon matching the running Node process's libc; the Landlock executable serves both libc systems.
+
+The package contains no JavaScript or installation build script. Platform prepack checks complete payloads, ELF architecture, Node-API exports, and launcher executability; the installed-artifact rehearsal checks bytes and executes native behavior. See the workspace [support matrix](../../docs/support-matrix.md).

+ 11 - 0
native/system/packages/linux-arm64/README.zh.md

@@ -0,0 +1,11 @@
+---
+description: "为 Linux arm64 提供预编译 Landlock 启动器和 POSIX flock addon。"
+kind: "package-library"
+---
+# @deepseek-ai/node-addon-system-linux-arm64
+
+[English](README.md) | 中文
+
+此平台包包含静态 musl 可执行文件 `bin/landlock-run`,以及 Node-API v8 addon `bin/glibc/system.node` 和 `bin/musl/system.node`。入口包按运行 Node 进程的 libc 选择 addon;Landlock 可执行文件在两种 libc 系统上共用。
+
+包中没有 JavaScript 或安装编译脚本。平台 prepack 检查完整产物、ELF 架构、Node-API 导出和启动器可执行权限;安装演练核对字节并执行原生行为。参见工作区[支持矩阵](../../docs/support-matrix.md)。

+ 3 - 3
native/landlock-run/packages/linux-arm64/package.json → native/system/packages/linux-arm64/package.json

@@ -1,11 +1,11 @@
 {
-  "name": "@deepseek-ai/node-addon-landlock-run-linux-arm64",
+  "name": "@deepseek-ai/node-addon-system-linux-arm64",
   "version": "0.1.1",
-  "description": "Prebuilt landlock-run Landlock launcher binary for linux-arm64 (static musl) — resolved as a file path by @deepseek-ai/node-addon-landlock-run, never imported",
+  "description": "Linux arm64 system binaries: static Landlock launcher and glibc/musl Node-API flock addons",
   "repository": {
     "type": "git",
     "url": "git+https://github.com/deepseek-harness/deepseek-harness.git",
-    "directory": "native/landlock-run/packages/linux-arm64"
+    "directory": "native/system/packages/linux-arm64"
   },
   "os": [
     "linux"

+ 24 - 0
native/system/packages/linux-arm64/prebuilds.json

@@ -0,0 +1,24 @@
+{
+  "platform": "linux-arm64",
+  "binaries": [
+    {
+      "tool": "landlock-run",
+      "kind": "static-musl",
+      "path": "bin/landlock-run"
+    },
+    {
+      "tool": "flock",
+      "kind": "node-api",
+      "napi": 8,
+      "libc": "glibc",
+      "path": "bin/glibc/system.node"
+    },
+    {
+      "tool": "flock",
+      "kind": "node-api",
+      "napi": 8,
+      "libc": "musl",
+      "path": "bin/musl/system.node"
+    }
+  ]
+}

Vissa filer visades inte eftersom för många filer har ändrats