owlrunkit 0.25.0 → 0.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.25.2
4
+
5
+ - Supports managed Linux worker recovery with system Bubblewrap when Landlock
6
+ is unavailable. RunKit verifies the writable attempt, read-only sandbox
7
+ root, hidden host files, and seccomp process and network restrictions before
8
+ selecting the backend.
9
+ - Keeps Landlock as the first Linux backend. If neither backend passes its
10
+ runtime probe, managed peer commands refuse to start.
11
+
12
+ ## 0.25.1
13
+
14
+ - Adds enforced Linux peer isolation for x86-64 and ARM64 with Landlock and
15
+ seccomp. The helper verifies kernel support before managed tasks start.
16
+ - A cooperating agent can attach its worker command to `peer recover`.
17
+ A confirmed wake preserves the current owner. After takeover, exactly one
18
+ invocation starts the successor from the last accepted checkpoint.
19
+ - On Linux, control transactions use an OS lock that is released on process
20
+ exit. The next transaction verifies interrupted state before proceeding.
21
+ Partial multi-file changes and ownerless directory locks still require
22
+ reconciliation. Legacy shared-directory worker leases remain explicit.
23
+
3
24
  ## 0.25.0
4
25
 
5
26
  - Adds opt-in same-host peer recovery for macOS-contained workers. A cooperating
package/NOTICE.md CHANGED
@@ -1,137 +1,22 @@
1
- # NOTICE
1
+ # OwlRunKit Notice
2
2
 
3
- ## OwlCoda Positioning
3
+ OwlRunKit is an independent package in the OwlCoda product family. It is not
4
+ affiliated with any model vendor, coding-agent vendor, or hosted agent service.
4
5
 
5
- OwlCoda is an independent local AI coding platform. It is not affiliated with
6
- any external coding assistant vendor.
6
+ The OwlRunKit CLI, Core, contracts, and attestation package are distributed
7
+ under `GPL-3.0-or-later`; see [`LICENSE`](LICENSE). The published package uses
8
+ Node.js built-in modules and currently declares no runtime npm dependencies.
9
+ Files carrying their own license or provenance notice retain those terms.
7
10
 
8
- Third-party product names may appear where they are needed for protocol
9
- interoperability, optional user-provided provider integrations, migration
10
- history, or competitive analysis. The default npm release package contains the
11
- OwlCoda runtime, bundled skill resources, branding assets, configuration
12
- examples, and public release documents. Bundled skills and third-party-derived
13
- resources keep their own license files and provenance records where applicable.
11
+ Product and provider names may appear only where needed for interoperability,
12
+ portable integration guidance, compatibility history, or evidence captured by
13
+ the user. Such references do not imply endorsement, sponsorship, or
14
+ affiliation.
14
15
 
15
- Starting with the `0.15.0` license boundary, the OwlCoda core package is
16
- released under `GPL-3.0-or-later`. Third-party dependencies and in-tree
17
- attributions keep their own licenses as listed below; this notice records
18
- those dependencies and does not override the OwlCoda project license.
16
+ OwlRunKit records delivery continuity and verification evidence. It does not
17
+ grant Git, release, deployment, production, automation, money, or business
18
+ authority, and it does not become the Business Truth of a domain product.
19
19
 
20
- ### What OwlCoda Provides
21
-
22
- OwlCoda provides:
23
- - Protocol translation layer (messages API ↔ OpenAI Chat Completions)
24
- - Local model platform integration (Ollama, LM Studio, vLLM)
25
- - Native REPL, tool orchestration, and session workflows
26
- - Production infrastructure (health monitoring, rate limiting, circuit breakers)
27
- - Extended REPL commands and observability
28
-
29
- ### What OwlCoda Does NOT Provide
30
-
31
- OwlCoda does not claim to be any third-party coding assistant, does not ship a
32
- third-party branded UI, and does not rely on an external vendor CLI as its
33
- primary product surface.
34
-
35
- ### Protocol Interoperability vs Affiliation
36
-
37
- OwlCoda implements two widely-deployed wire formats so that users can
38
- plug their existing local runtime into it without rewriting the
39
- runtime:
40
-
41
- 1. The Messages-shaped API (originated by Anthropic and now implemented
42
- by many independent open-source servers) — incoming `/v1/messages`
43
- requests are accepted in this shape and translated as needed.
44
- 2. The OpenAI Chat Completions wire format — outgoing requests to
45
- user-configured backends use this shape because most local
46
- inference runtimes (Ollama, LM Studio, vLLM, etc.) expose it.
47
-
48
- Implementing these wire formats is a technical interoperability
49
- choice, not a brand affiliation. Where the codebase contains the
50
- literal strings `Anthropic`, `Anthropic-compatible`,
51
- `anthropic-version`, `/v1/messages`, or imports the public
52
- `@anthropic-ai/sdk` package, those references are protocol-level,
53
- exist solely to maintain over-the-wire compatibility, and do not
54
- constitute or imply:
55
-
56
- - endorsement by, or sponsorship from, Anthropic, OpenAI, or any
57
- other third party;
58
- - any affiliation, partnership, or contractual relationship with
59
- those parties; or
60
- - a claim that OwlCoda is a substitute for, or a derivative of,
61
- any third-party product.
62
-
63
- The `@anthropic-ai/sdk` package is listed as a `devDependency` only
64
- and is used by `tests/sdk-verify.ts` as an interoperability sanity
65
- check against OwlCoda's own server implementation. It is not loaded
66
- by the OwlCoda runtime.
67
-
68
- ## Third-Party Source Attributions
69
-
70
- OwlCoda incorporates source code derived from the following third-party
71
- projects. Their original copyright notices and MIT permission text are
72
- reproduced below as required by their licenses.
73
-
74
- ### Ink (https://github.com/vadimdemedes/ink)
75
-
76
- The `src/ink/` directory contains a fork of the Ink terminal-UI library
77
- originally authored by Vadim Demedes. OwlCoda's fork extends Ink with
78
- ScrollBox / viewport-culling / sticky-scroll primitives needed by the
79
- native REPL, but the underlying reconciler, layout, renderer, DOM, event,
80
- and component code remain derivative of upstream Ink.
81
-
82
- ```
83
- MIT License
84
-
85
- Copyright (c) Vadim Demedes <vadimdemedes@hey.com> (vadimdemedes.com)
86
-
87
- Permission is hereby granted, free of charge, to any person obtaining a
88
- copy of this software and associated documentation files (the "Software"),
89
- to deal in the Software without restriction, including without limitation
90
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
91
- and/or sell copies of the Software, and to permit persons to whom the
92
- Software is furnished to do so, subject to the following conditions:
93
-
94
- The above copyright notice and this permission notice shall be included
95
- in all copies or substantial portions of the Software.
96
-
97
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
98
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
99
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
100
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
101
- OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
102
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
103
- OTHER DEALINGS IN THE SOFTWARE.
104
- ```
105
-
106
- A copy of this attribution also lives at `src/ink/ATTRIBUTION.md` so it
107
- travels with the fork in any redistribution.
108
-
109
- ### Direct Runtime Dependencies
110
-
111
- OwlCoda's published tarball ships only `dist/`; runtime dependencies are
112
- resolved by `npm install` and their full license texts are available
113
- under `node_modules/<pkg>/LICENSE` after install. The list below is
114
- provided for transparency; it does not replace the per-package license
115
- files that npm fetches automatically.
116
-
117
- For GPL-covered npm packages, corresponding source availability is documented
118
- in `SOURCE.md`. Dependency-license review for GPLv3 compatibility is a release
119
- gate distinct from the older "does this project depend on GPL code?" check.
120
-
121
- | Package | License |
122
- |---|---|
123
- | `@anthropic-ai/sdk` (devDependency, type-only import + verify script) | MIT |
124
- | `@commander-js/extra-typings` | MIT |
125
- | `@growthbook/growthbook` | MIT |
126
- | `@modelcontextprotocol/sdk` | MIT |
127
- | `@opentelemetry/*` (api, core, sdk-logs, sdk-metrics, sdk-trace-base, resources, api-logs, semantic-conventions) | Apache-2.0 |
128
- | `axios`, `chalk`, `chokidar`, `marked`, `react`, `react-reconciler`, `ws`, `zod`, `undici`, `execa`, `turndown`, `xss`, `yaml`, others | MIT |
129
- | `cacache`, `cli-highlight`, `semver`, `signal-exit`, `yaml` | ISC |
130
- | `diff` | BSD-3-Clause |
131
- | `lru-cache` | BlueOak-1.0.0 |
132
- | `ink` (npm — co-installed alongside the in-tree fork in `src/ink/`) | MIT (Vadim Demedes) |
133
-
134
- No GPL / AGPL / SSPL / Business Source / Commons Clause / Elastic License
135
- dependencies are present in the current transitive graph (verified via
136
- `npm ls --all`). That is a dependency fact, not a statement about OwlCoda's own
137
- project license.
20
+ The Linux helper binaries statically link musl. See
21
+ [`peer-linux.MUSL-COPYRIGHT`](scripts/runkit-contract/peer-linux.MUSL-COPYRIGHT)
22
+ for its copyright and license notices.
package/README.md CHANGED
@@ -136,7 +136,7 @@ separate authority boundaries.
136
136
 
137
137
  ## Install
138
138
 
139
- This package is the lifecycle-stable, registry-gated `owlrunkit@0.25.0`
139
+ This package is the lifecycle-stable, registry-gated `owlrunkit@0.25.2`
140
140
  artifact. Registry adoption remains fail-closed until its exact official npm
141
141
  version, shasum, integrity, and tarball URL are independently verified. Local
142
142
  tarballs remain candidate-test inputs and are never adoption provenance. Until
@@ -144,7 +144,7 @@ that registry evidence exists, use the package only for isolated candidate
144
144
  verification; do not treat the command below as available release truth.
145
145
 
146
146
  ```bash
147
- npm install --save-exact owlrunkit@0.25.0
147
+ npm install --save-exact owlrunkit@0.25.2
148
148
  ```
149
149
 
150
150
  Use `npx --no-install owlrunkit` for project commands. The package bootstrap
@@ -160,9 +160,9 @@ the project Config must independently bind the same Core.
160
160
  ```bash
161
161
  npx --no-install owlrunkit --version
162
162
  npx --no-install owlrunkit bootstrap --workspace /absolute/path/to/project \
163
- --exact owlrunkit@0.25.0 --dry-run
163
+ --exact owlrunkit@0.25.2 --dry-run
164
164
  npx --no-install owlrunkit bootstrap --workspace /absolute/path/to/project \
165
- --exact owlrunkit@0.25.0 --apply
165
+ --exact owlrunkit@0.25.2 --apply
166
166
  npx --no-install owlrunkit init --workspace /absolute/path/to/project
167
167
  npx --no-install owlrunkit doctor --workspace /absolute/path/to/project
168
168
  npx --no-install owlrunkit inspect --workspace /absolute/path/to/project --json --compact
@@ -997,9 +997,9 @@ continuation; fully idle Desktop wake requires a separate supported ingress.
997
997
 
998
998
  ## Managed local peer recovery
999
999
 
1000
- On macOS, opt a new task into peer recovery before starting its writer. The
1001
- project controller names the current agent, successor, and exact checkpoint
1002
- paths in `peer.json`, for example:
1000
+ Opt a new task into peer recovery before starting its writer. The project
1001
+ controller names the current agent, successor, and exact checkpoint paths in
1002
+ `peer.json`, for example:
1003
1003
 
1004
1004
  ```json
1005
1005
  {"owner":"alpha","successor":"bravo","paths":["result.txt"]}
@@ -1009,18 +1009,21 @@ paths in `peer.json`, for example:
1009
1009
  npx --no-install owlrunkit peer create --workspace . --task repair --request peer.json
1010
1010
  npx --no-install owlrunkit peer run --workspace . --task repair --agent alpha --generation 1 -- /absolute/worker
1011
1011
  npx --no-install owlrunkit peer inspect --workspace . --task repair
1012
- npx --no-install owlrunkit peer recover --workspace . --task repair --agent bravo --generation 1 --revision 2
1012
+ npx --no-install owlrunkit peer recover --workspace . --task repair --agent bravo --generation 1 --revision 2 -- /absolute/successor-worker
1013
1013
  ```
1014
1014
 
1015
- Run the last two commands from the cooperating agent while it is investigating
1016
- an interruption. Use the actual generation and revision returned by `inspect`.
1015
+ The cooperating agent uses the last two commands when it observes an
1016
+ interruption and has authority to run the successor worker. Use the generation
1017
+ and revision returned by `inspect`.
1017
1018
  Recovery requests a wake from the current worker. A matching, changed checkpoint
1018
1019
  keeps that worker in charge. If wake remains unconfirmed after the bounded wait,
1019
1020
  recovery can move ownership to the designated successor because the current
1020
1021
  attempt already runs in an isolated directory. One durable revision binds the
1021
- successor generation to the last accepted checkpoint. The successor explicitly
1022
- runs its own worker using that generation. An ACK or timeout is not a proof of
1023
- worker death. Retry the same observed revision to read back a race or recovery.
1022
+ successor generation to the last accepted checkpoint. With a worker command
1023
+ after `--`, recovery starts that worker after takeover and reports its result.
1024
+ A concurrent retry may report the already-started attempt. Without a command,
1025
+ the successor starts its own worker with `peer run`. An ACK or timeout does
1026
+ not prove worker death. Retry the observed revision to read back the handoff.
1024
1027
 
1025
1028
  Use a local worker that speaks newline-delimited JSON. RunKit seeds the attempt
1026
1029
  directory from the previous checkpoint and sets `OWLRUNKIT_PEER_PATHS` to the
@@ -1035,14 +1038,25 @@ go to stderr. `inspect` returns the checkpoint path and hash for handoff and
1035
1038
  review. Only accepted checkpoints seed the next attempt, and the previous
1036
1039
  scratch directory is reported for inspection while it remains on disk.
1037
1040
 
1038
- The macOS backend confines each worker's writes to its own attempt and denies
1039
- network and additional processes. The host caller explicitly authorizes the
1040
- worker command, and supplies the peer identity. This is a supported boundary
1041
- for contained workers and their checkpoints. An unmanaged file lease, a raw
1042
- shared-directory writer, or an existing Desktop session needs its own recovery
1043
- procedure. Legacy lease records and `control.lock` are untouched. The result
1044
- is task evidence for the existing acceptance process. Canonical source
1045
- integration remains a separate authorized step.
1041
+ The macOS and Linux backends confine writes to the attempt and deny network
1042
+ connections and new worker processes. Linux supports x86-64 and ARM64 with
1043
+ seccomp filtering and `close_range`. RunKit tries Landlock ABI 3 or later
1044
+ first. If Landlock is unavailable, it can use a trusted system Bubblewrap
1045
+ executable with user and mount namespaces. The Bubblewrap probe verifies
1046
+ that the attempt is writable, host files are hidden, and new processes and
1047
+ network sockets are denied. If the probe fails, the task stays blocked.
1048
+ On Linux, the worker is terminated if its supervisor is killed. The host
1049
+ caller supplies the worker command and peer identity. Existing Desktop sessions and writers using
1050
+ legacy shared-directory leases follow their own recovery procedure. An
1051
+ existing managed task remains pinned to the core that created it.
1052
+
1053
+ Linux control transactions use a kernel lock and a marker in the runtime
1054
+ directory. If the process exits during an atomic lease operation, the next
1055
+ transaction reads the lease state from the committed artifact. For other
1056
+ transactions, automatic recovery requires unchanged control state. A partial
1057
+ transaction returns `runkit_control_reconciliation_required` and preserves its
1058
+ state. An older `control.lock` directory has no kernel ownership record and
1059
+ requires the existing explicit recovery procedure.
1046
1060
 
1047
1061
  ## Shared Skill upgrades
1048
1062
 
package/SOURCE.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # Source
2
2
 
3
3
  OwlRunKit is maintained in the private OwlCoda source repository. The npm
4
- tarball contains the complete JavaScript source for the published runtime and
5
- read-only verifier; it does not contain generated minified binaries.
4
+ tarball contains the JavaScript runtime, the read-only verifier and the C
5
+ source for the two Linux helper binaries. The distributed binaries link musl
6
+ statically and include its copyright notice. Build the helper on each supported
7
+ Linux architecture with `sh packages/runkit/build-linux-helper.sh <output>`
8
+ in Alpine Linux with `build-base` and `linux-headers`, then pass their output directory to
9
+ `packages/runkit/build-package.mjs --linux-helpers`.
6
10
 
7
11
  The authoritative release is identified by the npm registry version, shasum,
8
12
  integrity, and tarball URL. Local directories, `file:` dependencies, local
@@ -6,7 +6,7 @@
6
6
  ## 已验证现场事实
7
7
 
8
8
  以下结论来自对
9
- `/Users/yeemio/AI/project/sieracMes-AI/.owlcoda/runkit/` 的只读检查,
9
+ 一个真实 MES 项目的 `.owlcoda/runkit/` 只读检查,
10
10
  不是体验推测:
11
11
 
12
12
  - W1.6 留下四份 Quick Receipt V1。按回执生成时的 `exitResult` 与
@@ -7,14 +7,14 @@ description: Run receipt-backed, project-owned work with OwlCoda RunKit. Use whe
7
7
 
8
8
  Use the bundled deterministic Core to coordinate work through project artifacts rather than chat memory. Require Node.js 20 or later.
9
9
 
10
- Bundled registry-gated artifact: standalone `owlrunkit@0.25.0`, bundling Contract
11
- `0.2` and Core `0.25.0` with manifest
12
- `sha256:20e75c386f1408f11e908a6d3ee1a39316d9728d5719fa06f8d6a5aa45abd83e`.
10
+ Bundled registry-gated artifact: standalone `owlrunkit@0.25.2`, bundling Contract
11
+ `0.2` and Core `0.25.2` with manifest
12
+ `sha256:da816d343597b91c30e4f96c0a3d765bf5c00d6013d6bee430f58bc701399acc`.
13
13
  Registry adoption remains fail-closed until exact official npm registry
14
- provenance for `owlrunkit@0.25.0` is independently verified. The
15
- published rollback baseline for this artifact is `owlrunkit@0.24.1`, with SHA-1
16
- `b70b857c128f67d19d401acaa096a6cf9f1f348e` and canonical npm tarball URL
17
- `https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.24.1.tgz`.
14
+ provenance for `owlrunkit@0.25.2` is independently verified. The
15
+ published rollback baseline for this artifact is `owlrunkit@0.25.1`, with SHA-1
16
+ `755bdcef5f6df55977ee64d2d4391d1098c00168` and canonical npm tarball URL
17
+ `https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.25.1.tgz`.
18
18
  The root `owlcoda` package has a separate version lifecycle.
19
19
 
20
20
  The session is an execution interface. Project artifacts are the system of record.
@@ -25,10 +25,12 @@ For a task already enrolled in `owlrunkit peer` with an isolated worker, inspect
25
25
  the task when your cooperating agent stops progressing. As the designated
26
26
  successor, run `peer recover` with the observed generation and revision. A
27
27
  new checkpoint tied to the wake challenge keeps the original agent active.
28
- When recovery grants a successor generation, explicitly run the authorized
29
- worker in that generation and resume from its seeded checkpoint. Treat an ACK
30
- without progress as unconfirmed. Keep legacy shared-workspace leases on the
31
- manual recovery path. Use the package README and `peer --help` for setup.
28
+ Append `-- /absolute/worker` when you already have authority to run the
29
+ successor worker. The command only launches it if ownership transfers and
30
+ seeds it from the last accepted checkpoint. Read the returned attempt status
31
+ before treating the work as finished. Treat an ACK without progress as
32
+ unconfirmed. Keep legacy shared-workspace leases on the manual recovery path.
33
+ Use the package README and `peer --help` for setup.
32
34
 
33
35
  ## Optional file-event continuation
34
36
 
@@ -368,9 +370,9 @@ below has no CLI entry.
368
370
 
369
371
  ```bash
370
372
  npx --no-install owlrunkit bootstrap --workspace "$PROJECT_ROOT" \
371
- --exact owlrunkit@0.25.0 --dry-run
373
+ --exact owlrunkit@0.25.2 --dry-run
372
374
  npx --no-install owlrunkit bootstrap --workspace "$PROJECT_ROOT" \
373
- --exact owlrunkit@0.25.0 --apply
375
+ --exact owlrunkit@0.25.2 --apply
374
376
  npx --no-install owlrunkit init --workspace "$PROJECT_ROOT"
375
377
  npx --no-install owlrunkit inspect --json --workspace "$PROJECT_ROOT"
376
378
  npx --no-install owlrunkit inspect --json --compact --workspace "$PROJECT_ROOT"
@@ -2,9 +2,9 @@
2
2
  "schemaVersion": "OwlCodaRunKitConfigV2",
3
3
  "core": {
4
4
  "contractVersion": "0.2",
5
- "coreVersion": "0.25.0",
6
- "coreManifestSha256": "sha256:20e75c386f1408f11e908a6d3ee1a39316d9728d5719fa06f8d6a5aa45abd83e",
7
- "coreSourceRef": "artifact:sha256:20e75c386f1408f11e908a6d3ee1a39316d9728d5719fa06f8d6a5aa45abd83e"
5
+ "coreVersion": "0.25.2",
6
+ "coreManifestSha256": "sha256:da816d343597b91c30e4f96c0a3d765bf5c00d6013d6bee430f58bc701399acc",
7
+ "coreSourceRef": "artifact:sha256:da816d343597b91c30e4f96c0a3d765bf5c00d6013d6bee430f58bc701399acc"
8
8
  },
9
9
  "authorizationPolicy": "external_explicit_authority_required"
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "owlrunkit",
3
- "version": "0.25.0",
3
+ "version": "0.25.2",
4
4
  "description": "Project Driver for cross-Agent project continuity and progression; execution, evidence, verification, and recovery are the underlying trust substrate.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "yeemio <owlclaw@163.com>",
@@ -42,6 +42,16 @@
42
42
  "sha256": "sha256:3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986"
43
43
  },
44
44
  "supportedProducerCoreIdentities": [
45
+ {
46
+ "contractVersion": "0.2",
47
+ "coreVersion": "0.25.2",
48
+ "coreManifestSha256": "sha256:da816d343597b91c30e4f96c0a3d765bf5c00d6013d6bee430f58bc701399acc"
49
+ },
50
+ {
51
+ "contractVersion": "0.2",
52
+ "coreVersion": "0.25.1",
53
+ "coreManifestSha256": "sha256:0934a076b147847a4623bc89263b677c88088b493495fc74f11485985b7903b5"
54
+ },
45
55
  {
46
56
  "contractVersion": "0.2",
47
57
  "coreVersion": "0.25.0",
@@ -23,6 +23,16 @@ import {
23
23
  export { validQuickReceiptShape } from "./quick-receipt-contract.mjs";
24
24
 
25
25
  export const SUPPORTED_QUICK_CORE_IDENTITIES = Object.freeze([
26
+ {
27
+ contractVersion: "0.2",
28
+ coreVersion: "0.25.2",
29
+ coreManifestSha256: "sha256:da816d343597b91c30e4f96c0a3d765bf5c00d6013d6bee430f58bc701399acc",
30
+ },
31
+ {
32
+ contractVersion: "0.2",
33
+ coreVersion: "0.25.1",
34
+ coreManifestSha256: "sha256:0934a076b147847a4623bc89263b677c88088b493495fc74f11485985b7903b5",
35
+ },
26
36
  {
27
37
  contractVersion: "0.2",
28
38
  coreVersion: "0.25.0",
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": "OwlCodaRunKitRegistryReleasePolicyV2",
3
3
  "status": "release_artifact_registry_gated",
4
4
  "packageName": "owlrunkit",
5
- "artifactVersion": "0.25.0",
5
+ "artifactVersion": "0.25.2",
6
6
  "registry": "https://registry.npmjs.org",
7
7
  "registryRequiredBeforeAdoption": true,
8
8
  "exactVersionRequired": true,
@@ -23,10 +23,10 @@
23
23
  ],
24
24
  "rollbackRelease": {
25
25
  "packageName": "owlrunkit",
26
- "version": "0.24.1",
27
- "shasum": "b70b857c128f67d19d401acaa096a6cf9f1f348e",
28
- "integrity": "sha512-8Fr5XTAbtRlxyYboDSB8C257sxSWWiAFqGU6yexF99NXgilJ3pbxtMwq4FcbrlHN5V6yJLME04vTceI2s9F4bA==",
29
- "tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.24.1.tgz"
26
+ "version": "0.25.1",
27
+ "shasum": "755bdcef5f6df55977ee64d2d4391d1098c00168",
28
+ "integrity": "sha512-+s+PHZXemJIgBo8ScT65+OngqniojRFMxpoUOTjp/Xkq/szB8FqEUOH1BFlokMz6dx64FSOKb30rDPZWC2lS4w==",
29
+ "tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.25.1.tgz"
30
30
  },
31
31
  "registryEvidenceMustBeExternal": true,
32
32
  "registryEvidenceSchemaVersion": "OwlCodaRunKitRegistryReleaseEvidenceV1",
package/sbom.spdx.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "owlrunkit-0.25.0",
6
- "documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.25.0",
5
+ "name": "owlrunkit-0.25.2",
6
+ "documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.25.2",
7
7
  "creationInfo": {
8
8
  "created": "2026-11-11T00:00:00Z",
9
9
  "creators": [
@@ -14,7 +14,7 @@
14
14
  {
15
15
  "name": "owlrunkit",
16
16
  "SPDXID": "SPDXRef-Package-OwlRunKit",
17
- "versionInfo": "0.25.0",
17
+ "versionInfo": "0.25.2",
18
18
  "downloadLocation": "NOASSERTION",
19
19
  "filesAnalyzed": false,
20
20
  "licenseConcluded": "GPL-3.0-or-later",
@@ -24,7 +24,7 @@
24
24
  {
25
25
  "referenceCategory": "PACKAGE-MANAGER",
26
26
  "referenceType": "purl",
27
- "referenceLocator": "pkg:npm/owlrunkit@0.25.0"
27
+ "referenceLocator": "pkg:npm/owlrunkit@0.25.2"
28
28
  }
29
29
  ]
30
30
  }
@@ -0,0 +1,108 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import {
4
+ closeSync, constants, fstatSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync,
5
+ readFileSync, readdirSync, rmdirSync, unlinkSync, writeFileSync,
6
+ } from "node:fs";
7
+ import path from "node:path";
8
+
9
+ import { linuxRuntimeHelper } from "./linux-runtime.mjs";
10
+
11
+ const LOCK = "control.lock";
12
+ const GUARD = "control.lock.guard";
13
+ const TEMP_PREFIX = ".control-lock-";
14
+ const SCHEMA = "OwlRunKitControlLockV1";
15
+ const ACTIVE = "Another RunKit control transaction is already active.";
16
+
17
+ function fileIdentity(stat) {
18
+ return `${stat.dev}:${stat.ino}`;
19
+ }
20
+
21
+ function controlStateDigest(root) {
22
+ const hash = createHash("sha256");
23
+ function visit(directory, prefix) {
24
+ for (const name of readdirSync(directory).sort()) {
25
+ if (!prefix && (name === LOCK || name === GUARD || name === "peer-recovery"
26
+ || name.startsWith(TEMP_PREFIX))) continue;
27
+ const absolute = path.join(directory, name);
28
+ const relative = `${prefix}${name}`;
29
+ const stat = lstatSync(absolute, { bigint: true });
30
+ hash.update(JSON.stringify([
31
+ relative, fileIdentity(stat), String(stat.mode), String(stat.size),
32
+ String(stat.mtimeNs), String(stat.ctimeNs),
33
+ ]) + "\n");
34
+ if (stat.isDirectory()) visit(absolute, `${relative}/`);
35
+ }
36
+ }
37
+ visit(root, "");
38
+ return hash.digest("hex");
39
+ }
40
+
41
+ function recoverInterruptedLock(root, lockPath, guard) {
42
+ let stat;
43
+ try { stat = lstatSync(lockPath); }
44
+ catch (error) { if (error.code === "ENOENT") return; throw error; }
45
+ // Releases without an ownership record still use a directory at this
46
+ // path. Its presence alone cannot establish who owns it or if it is stale.
47
+ if (!stat.isFile() || stat.size > 1024) throw new Error(ACTIVE);
48
+ const fd = openSync(lockPath, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
49
+ let previous;
50
+ try { previous = JSON.parse(readFileSync(fd, "utf8")); }
51
+ finally { closeSync(fd); }
52
+ if (previous?.schemaVersion !== SCHEMA || previous.guard !== guard
53
+ || !["atomic-lease", "control-state"].includes(previous.kind)) throw new Error(ACTIVE);
54
+ if (previous.kind === "control-state" && previous.before !== controlStateDigest(root)) {
55
+ throw new Error("runkit_control_reconciliation_required: interrupted transaction changed control state.");
56
+ }
57
+ unlinkSync(lockPath);
58
+ }
59
+
60
+ function acquireLinuxLock(root, lockPath, helper, kind) {
61
+ const guardPath = path.join(root, GUARD);
62
+ const fd = openSync(guardPath,
63
+ constants.O_RDWR | constants.O_CREAT | constants.O_NOFOLLOW | constants.O_NONBLOCK, 0o600);
64
+ try {
65
+ const guardStat = fstatSync(fd, { bigint: true });
66
+ if (!guardStat.isFile() || guardStat.nlink !== 1n) throw new Error("Invalid RunKit control lock guard.");
67
+ const result = spawnSync(helper, ["lock"], {
68
+ env: {}, timeout: 3000, stdio: ["ignore", "ignore", "pipe", fd], encoding: "utf8",
69
+ });
70
+ if (result.status === 73) throw new Error(ACTIVE);
71
+ if (result.status !== 0) {
72
+ throw new Error(`RunKit control lock unavailable: ${result.stderr?.trim() || result.error?.code}`);
73
+ }
74
+ // The helper locks the open description shared with this process. Keep
75
+ // the descriptor open until the transaction ends or the kernel reaps it.
76
+ const guard = fileIdentity(guardStat);
77
+ if (fileIdentity(lstatSync(guardPath, { bigint: true })) !== guard) {
78
+ throw new Error("RunKit control lock guard was replaced.");
79
+ }
80
+ recoverInterruptedLock(root, lockPath, guard);
81
+ const record = { schemaVersion: SCHEMA, guard, kind,
82
+ before: kind === "control-state" ? controlStateDigest(root) : null };
83
+ const scratch = path.join(root, `${TEMP_PREFIX}${randomUUID()}`);
84
+ const marker = openSync(scratch, "wx", 0o600);
85
+ try {
86
+ writeFileSync(marker, JSON.stringify(record));
87
+ fsyncSync(marker);
88
+ try { linkSync(scratch, lockPath); }
89
+ catch (error) { if (error.code === "EEXIST") throw new Error(ACTIVE); throw error; }
90
+ } finally { closeSync(marker); unlinkSync(scratch); }
91
+ return () => {
92
+ try { unlinkSync(lockPath); }
93
+ finally { closeSync(fd); }
94
+ };
95
+ } catch (error) {
96
+ closeSync(fd);
97
+ throw error;
98
+ }
99
+ }
100
+
101
+ export function acquireRunKitControlLock(root, { atomicLease = false } = {}) {
102
+ const lockPath = path.join(root, LOCK);
103
+ const helper = linuxRuntimeHelper();
104
+ if (helper) return acquireLinuxLock(root, lockPath, helper, atomicLease ? "atomic-lease" : "control-state");
105
+ try { mkdirSync(lockPath); }
106
+ catch (error) { if (error.code === "EEXIST") throw new Error(ACTIVE); throw error; }
107
+ return () => rmdirSync(lockPath);
108
+ }
@@ -14,7 +14,7 @@ import { fileURLToPath } from "node:url";
14
14
  import { parseProjectControlState } from "./project-control-parser.mjs";
15
15
 
16
16
  export const CONTRACT_VERSION = "0.2";
17
- export const CORE_VERSION = "0.25.0";
17
+ export const CORE_VERSION = "0.25.2";
18
18
  export const RUNTIME_ROOT = ".owlcoda/runkit";
19
19
 
20
20
  const CORE_FILES = [
@@ -23,6 +23,7 @@ const CORE_FILES = [
23
23
  "core-successor.mjs",
24
24
  "coverage-adoption.mjs",
25
25
  "core-contract.mjs",
26
+ "control-transaction-lock.mjs",
26
27
  "delivery-create.mjs",
27
28
  "delivery-selection.mjs",
28
29
  "deployment-workflow.mjs",
@@ -40,8 +41,11 @@ const CORE_FILES = [
40
41
  "install-codex-skill.mjs",
41
42
  "lease-lifecycle.mjs",
42
43
  "lifecycle-orchestration.mjs",
44
+ "linux-runtime.mjs",
43
45
  "offline-store.mjs",
44
46
  "outcome-presentation.mjs",
47
+ "peer-linux-bwrap.mjs",
48
+ "peer-linux.c",
45
49
  "peer-recovery.mjs",
46
50
  "onboarding-doctor.mjs",
47
51
  "onboarding-bootstrap.mjs",