@cairnkeep/cli 2.13.0 → 2.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@ All notable user-facing changes are documented here. This project follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [2.13.1] - 2026-08-17
9
+
10
+ ### Fixed
11
+
12
+ - Generate release SBOMs directly as reproducible, schema-validated CycloneDX
13
+ 1.6 documents with the pinned official npm generator. This replaces npm's
14
+ invalid CycloneDX 1.5 output and fails publication before attaching a broken
15
+ SBOM.
16
+
8
17
  ## [2.13.0] - 2026-08-17
9
18
 
10
19
  ### Added
@@ -347,7 +356,8 @@ stored memories.
347
356
  - Preserve executable permissions and Bash 3.2 portability on macOS.
348
357
  - Add backup-first uninstall and SQLite-safe memory export/import guidance.
349
358
 
350
- [Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.13.0...HEAD
359
+ [Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.13.1...HEAD
360
+ [2.13.1]: https://github.com/cairnkeep/cairnkeep/compare/v2.13.0...v2.13.1
351
361
  [2.13.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.12.0...v2.13.0
352
362
  [2.12.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.11.0...v2.12.0
353
363
  [2.11.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.9.0...v2.11.0
@@ -1,6 +1,6 @@
1
1
  # Curriculum Coverage Map
2
2
 
3
- **Baseline:** Cairnkeep 2.13.0
3
+ **Baseline:** Cairnkeep 2.13.1
4
4
  **Last reviewed:** 2026-08-13
5
5
 
6
6
  This map prevents the course from drifting behind the product. It assigns each
@@ -1,6 +1,6 @@
1
1
  # Cairnkeep feature guide
2
2
 
3
- **Baseline:** Cairnkeep 2.13.0
3
+ **Baseline:** Cairnkeep 2.13.1
4
4
 
5
5
  This is the step-back map for choosing and operating Cairnkeep features. The
6
6
  [course labs](https://github.com/cairnkeep/cairnkeep-course-labs) provide one
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 10 minutes
6
- **Tested with:** Cairnkeep 2.13.0
6
+ **Tested with:** Cairnkeep 2.13.1
7
7
 
8
8
  ## Outcome
9
9
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 15 minutes
6
- **Tested with:** Cairnkeep 2.13.0
6
+ **Tested with:** Cairnkeep 2.13.1
7
7
 
8
8
  ## Outcome
9
9
 
@@ -26,7 +26,7 @@ ephemeral; the named course volume is persistent.
26
26
  1. Pull the public image:
27
27
 
28
28
  ```bash
29
- podman pull ghcr.io/cairnkeep/cairnkeep:2.13.0
29
+ podman pull ghcr.io/cairnkeep/cairnkeep:2.13.1
30
30
  ```
31
31
 
32
32
  2. Start the stdio server with a read-only root filesystem and no Linux
@@ -38,7 +38,7 @@ ephemeral; the named course volume is persistent.
38
38
  --read-only --cap-drop=all --security-opt=no-new-privileges \
39
39
  --tmpfs=/tmp:rw,noexec,nosuid,size=64m,mode=1777 \
40
40
  --volume cairnkeep-course-data:/data:Z,U \
41
- ghcr.io/cairnkeep/cairnkeep:2.13.0 stdio
41
+ ghcr.io/cairnkeep/cairnkeep:2.13.1 stdio
42
42
  ```
43
43
 
44
44
  3. The process waits quietly for MCP input. Press `Ctrl-C` after confirming it
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 25 minutes
6
- **Tested with:** Cairnkeep 2.13.0 and Node.js 22 or newer
6
+ **Tested with:** Cairnkeep 2.13.1 and Node.js 22 or newer
7
7
 
8
8
  ## Outcome
9
9
 
@@ -47,7 +47,7 @@ sync. Codex project trust remains an explicit operator decision.
47
47
  2. Install Cairnkeep:
48
48
 
49
49
  ```bash
50
- npm install --global @cairnkeep/cli@2.13.0
50
+ npm install --global @cairnkeep/cli@2.13.1
51
51
  cairn --version
52
52
  ```
53
53
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 25 minutes
6
- **Tested with:** Cairnkeep 2.13.0
6
+ **Tested with:** Cairnkeep 2.13.1
7
7
 
8
8
  ## Outcome
9
9
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Evidence and Evaluation
5
5
  **Time:** 50 minutes
6
- **Tested with:** Cairnkeep 2.13.0
6
+ **Tested with:** Cairnkeep 2.13.1
7
7
 
8
8
  ## Outcome
9
9
 
@@ -1,7 +1,7 @@
1
1
  # L20 - Least-authority MCP tool profiles
2
2
 
3
3
  **Status:** Ready
4
- **Tested with:** Cairnkeep 2.13.0 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.13.1 and Node.js 22 or newer
5
5
  **Time:** 25 minutes
6
6
 
7
7
  ## Outcome
@@ -1,7 +1,7 @@
1
1
  # L21 - Immutable context packs and skill approval
2
2
 
3
3
  **Status:** Ready
4
- **Tested with:** Cairnkeep 2.13.0 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.13.1 and Node.js 22 or newer
5
5
  **Time:** 40 minutes
6
6
 
7
7
  ## Outcome
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Operator
5
5
  **Time:** 30 minutes
6
- **Tested with:** Cairnkeep 2.13.0, Windows x64, and Node.js 22 or newer
6
+ **Tested with:** Cairnkeep 2.13.1, Windows x64, and Node.js 22 or newer
7
7
 
8
8
  ## Outcome
9
9
 
@@ -16,7 +16,7 @@ perform a reversible uninstall without relying on WSL or Git Bash.
16
16
  From PowerShell:
17
17
 
18
18
  ```powershell
19
- npm install --global @cairnkeep/cli@2.13.0
19
+ npm install --global @cairnkeep/cli@2.13.1
20
20
  cairn version
21
21
 
22
22
  $Lab = Join-Path $env:TEMP 'Cairnkeep Windows Lab'
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart and Operator
5
5
  **Time:** 35 minutes
6
- **Tested with:** Cairnkeep 2.13.0; Pi 0.84.1; Node.js 22, 24, and 26
6
+ **Tested with:** Cairnkeep 2.13.1; Pi 0.84.1; Node.js 22, 24, and 26
7
7
 
8
8
  ## Outcome
9
9
 
@@ -134,7 +134,7 @@ prompts, approve skills, create an autonomous loop, or add remote access.
134
134
 
135
135
  ## Release boundary
136
136
 
137
- Ready means this lesson and its deterministic contracts pass against v2.13.0.
137
+ Ready means this lesson and its deterministic contracts pass against v2.13.1.
138
138
  Release readiness requires a non-skipping acceptance run
139
139
  against separate Pi 0.84.1 minimum and explicitly versioned registry-current
140
140
  installations, plus the documented Node.js, Bash 3.2, and native Windows matrix.
package/docs/releasing.md CHANGED
@@ -12,8 +12,12 @@ from a workstation.
12
12
  4. Publish a GitHub Release whose tag is exactly `v<package.json version>`.
13
13
  5. The `Publish release` workflow checks out that immutable tag, repeats the
14
14
  tests, and publishes `@cairnkeep/cli` with npm provenance.
15
- 6. The workflow attaches the npm tarball, a CycloneDX SBOM, and SHA-256 checksums
16
- to the GitHub Release.
15
+ 6. The workflow uses the exact locked `@cyclonedx/cyclonedx-npm` development
16
+ dependency to generate a reproducible CycloneDX 1.6 SBOM from
17
+ `package-lock.json`. Generation includes schema validation and runs before
18
+ npm publication, so an invalid document blocks both publication and
19
+ attachment. The workflow attaches that SBOM, the npm tarball, and SHA-256
20
+ checksums to the GitHub Release.
17
21
  7. The workflow publishes versioned `linux/amd64` and `linux/arm64`
18
22
  memory-server and workspace images to GHCR. It also updates `latest` for a
19
23
  stable release or `next` for a prerelease.
@@ -1 +1 @@
1
- {"identifier":"cairn-offline-fake-v1","package_version":"2.13.0","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
1
+ {"identifier":"cairn-offline-fake-v1","package_version":"2.13.1","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cairnkeep/cli",
3
- "version": "2.13.0",
3
+ "version": "2.13.1",
4
4
  "description": "A durable, harness-agnostic memory + context layer for coding agents and MCP clients.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -70,5 +70,8 @@
70
70
  "pi-coding-agent",
71
71
  "context",
72
72
  "rag"
73
- ]
73
+ ],
74
+ "devDependencies": {
75
+ "@cyclonedx/cyclonedx-npm": "6.0.0"
76
+ }
74
77
  }
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
5
+ WORKFLOW="$ROOT/.github/workflows/publish.yml"
6
+ TEMP_DIR=$(mktemp -d)
7
+ trap 'rm -f "$TEMP_DIR/cairnkeep.cdx.json"; rmdir "$TEMP_DIR"' EXIT
8
+
9
+ fail() {
10
+ echo "FAIL: $*" >&2
11
+ exit 1
12
+ }
13
+
14
+ node - "$ROOT/package.json" "$ROOT/package-lock.json" "$WORKFLOW" <<'NODE'
15
+ const fs = require("node:fs");
16
+
17
+ const manifest = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
18
+ const lock = JSON.parse(fs.readFileSync(process.argv[3], "utf8"));
19
+ const workflow = fs.readFileSync(process.argv[4], "utf8");
20
+ const expected = "6.0.0";
21
+
22
+ if (manifest.devDependencies?.["@cyclonedx/cyclonedx-npm"] !== expected) {
23
+ throw new Error(`package.json must pin @cyclonedx/cyclonedx-npm exactly to ${expected}`);
24
+ }
25
+ if (lock.packages?.[""]?.devDependencies?.["@cyclonedx/cyclonedx-npm"] !== expected) {
26
+ throw new Error(`package-lock.json root must pin @cyclonedx/cyclonedx-npm exactly to ${expected}`);
27
+ }
28
+ if (lock.packages?.["node_modules/@cyclonedx/cyclonedx-npm"]?.version !== expected) {
29
+ throw new Error(`package-lock.json must resolve @cyclonedx/cyclonedx-npm ${expected}`);
30
+ }
31
+
32
+ const artifactStep = workflow.indexOf("- name: Build and validate release artifacts");
33
+ const publishStep = workflow.indexOf("- name: Publish to npm with provenance");
34
+ const attachStep = workflow.indexOf("- name: Attach package and SBOM to GitHub release");
35
+ if (artifactStep < 0 || publishStep < 0 || attachStep < 0 || !(artifactStep < publishStep && publishStep < attachStep)) {
36
+ throw new Error("release artifacts must validate before npm publication and attach only after publication");
37
+ }
38
+ NODE
39
+
40
+ grep -Fq './node_modules/.bin/cyclonedx-npm' "$WORKFLOW" || fail "release workflow does not use the locked CycloneDX generator"
41
+ grep -Fq -- '--package-lock-only' "$WORKFLOW" || fail "release workflow does not use the package lock"
42
+ grep -Fq -- '--omit dev' "$WORKFLOW" || fail "release workflow does not omit development dependencies"
43
+ grep -Fq -- '--output-reproducible' "$WORKFLOW" || fail "release workflow does not request reproducible output"
44
+ grep -Fq -- '--spec-version 1.6' "$WORKFLOW" || fail "release workflow does not emit CycloneDX 1.6"
45
+ grep -Fq -- '--validate' "$WORKFLOW" || fail "release workflow does not validate the generated SBOM"
46
+ if grep -Fq 'npm sbom' "$WORKFLOW"; then
47
+ fail "release workflow still uses npm sbom"
48
+ fi
49
+ if grep -Fqi 'sbomsmith' "$WORKFLOW"; then
50
+ fail "release workflow must not depend on an external converter"
51
+ fi
52
+
53
+ "$ROOT/node_modules/.bin/cyclonedx-npm" \
54
+ --package-lock-only \
55
+ --omit dev \
56
+ --output-reproducible \
57
+ --spec-version 1.6 \
58
+ --output-format JSON \
59
+ --output-file "$TEMP_DIR/cairnkeep.cdx.json" \
60
+ --validate \
61
+ "$ROOT/package.json"
62
+
63
+ node - "$TEMP_DIR/cairnkeep.cdx.json" <<'NODE'
64
+ const fs = require("node:fs");
65
+
66
+ const bom = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
67
+ if (bom.bomFormat !== "CycloneDX") throw new Error("release SBOM format is not CycloneDX");
68
+ if (bom.specVersion !== "1.6") throw new Error("release SBOM version is not CycloneDX 1.6");
69
+ if (!Array.isArray(bom.components) || bom.components.length === 0) throw new Error("release SBOM has no components");
70
+ if (!Array.isArray(bom.dependencies) || bom.dependencies.length === 0) throw new Error("release SBOM has no dependency graph");
71
+
72
+ const scpLike = /^[^/@\s:]+@[^/\s:]+:.+$/;
73
+ function inspect(value) {
74
+ if (Array.isArray(value)) {
75
+ for (const item of value) inspect(item);
76
+ return;
77
+ }
78
+ if (!value || typeof value !== "object") return;
79
+ if (Array.isArray(value.externalReferences)) {
80
+ for (const reference of value.externalReferences) {
81
+ if (typeof reference?.url === "string" && scpLike.test(reference.url)) {
82
+ throw new Error(`release SBOM contains an invalid SCP-style external reference: ${reference.url}`);
83
+ }
84
+ }
85
+ }
86
+ for (const child of Object.values(value)) inspect(child);
87
+ }
88
+ inspect(bom);
89
+ NODE
90
+
91
+ echo "PASS: release SBOM is reproducible, schema-validated CycloneDX 1.6"