@cairnkeep/cli 2.17.0 → 2.17.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 +10 -0
- package/docs/ecosystem.md +0 -1
- package/docs/learning/CURRICULUM-MAP.md +1 -1
- package/docs/learning/FEATURE-GUIDE.md +1 -1
- package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
- package/docs/learning/lessons/L01-safe-trial.md +3 -3
- package/docs/learning/lessons/L02-installation.md +2 -2
- package/docs/learning/lessons/L03-first-project.md +1 -1
- package/docs/learning/lessons/L19-validated-skill-improvement.md +1 -1
- package/docs/learning/lessons/L20-mcp-tool-profiles.md +1 -1
- package/docs/learning/lessons/L21-context-packs.md +1 -1
- package/docs/learning/lessons/L22-native-windows.md +2 -2
- package/docs/learning/lessons/L23-guided-setup.md +1 -1
- package/docs/learning/lessons/L24-okf-exchange.md +1 -1
- package/docs/learning/lessons/L25-playbooks.md +1 -1
- package/examples/eval/bundled-fake.json +1 -1
- package/package.json +2 -2
- package/scripts/terminal-prompts.mjs +5 -3
- package/scripts/test-release-sbom.sh +1 -1
- package/scripts/test-setup-preflight.mjs +13 -0
- package/templates/PROJECT-INSTRUCTIONS.md.template +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ All notable user-facing changes are documented here. This project follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [2.17.1] - 2026-08-31
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Release TTY stdin after every interactive `cairn setup` selector so setup
|
|
13
|
+
returns to the shell after completion, including through SSH terminals that
|
|
14
|
+
report stdin as already flowing.
|
|
15
|
+
- Keep the context-usage receipt smoke fixture relative to the test run so its
|
|
16
|
+
doctor assertion cannot fail merely because a hard-coded timestamp aged out.
|
|
17
|
+
|
|
8
18
|
## [2.17.0] - 2026-08-29
|
|
9
19
|
|
|
10
20
|
### Added
|
package/docs/ecosystem.md
CHANGED
|
@@ -14,7 +14,6 @@ graph workflows have their own explicit companion requirements.
|
|
|
14
14
|
|
|
15
15
|
| Tool | What it adds | Integration |
|
|
16
16
|
|---|---|---|
|
|
17
|
-
| [lean-ctx](https://github.com/yvgude/lean-ctx) | Compressed file reads, searches, shell output, and directory maps | Register it as an MCP server in the chosen harness |
|
|
18
17
|
| [token-miser](https://github.com/cairnkeep/token-miser) | Model routing and compact codebase exploration | Configure `CAIRN_ROUTE_ENDPOINT` and/or `CAIRN_EXPLORE_BINARY` |
|
|
19
18
|
| [rtk](https://github.com/rtk-ai/rtk) | Token-reduced output for common Git, npm, and Cargo commands | Install as a shell-level proxy; Cairnkeep wiring is not required |
|
|
20
19
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Quickstart
|
|
5
5
|
**Time:** 15 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.17.
|
|
6
|
+
**Tested with:** Cairnkeep 2.17.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.17.
|
|
29
|
+
podman pull ghcr.io/cairnkeep/cairnkeep:2.17.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.17.
|
|
41
|
+
ghcr.io/cairnkeep/cairnkeep:2.17.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.17.
|
|
6
|
+
**Tested with:** Cairnkeep 2.17.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.17.
|
|
50
|
+
npm install --global @cairnkeep/cli@2.17.1
|
|
51
51
|
cairn --version
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Operator
|
|
5
5
|
**Time:** 30 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.17.
|
|
6
|
+
**Tested with:** Cairnkeep 2.17.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.17.
|
|
19
|
+
npm install --global @cairnkeep/cli@2.17.1
|
|
20
20
|
cairn version
|
|
21
21
|
|
|
22
22
|
$Lab = Join-Path $env:TEMP 'Cairnkeep Windows Lab'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"identifier":"cairn-offline-fake-v1","package_version":"2.17.
|
|
1
|
+
{"identifier":"cairn-offline-fake-v1","package_version":"2.17.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.17.
|
|
3
|
+
"version": "2.17.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",
|
|
@@ -73,6 +73,6 @@
|
|
|
73
73
|
"rag"
|
|
74
74
|
],
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@cyclonedx/cyclonedx-npm": "6.0.
|
|
76
|
+
"@cyclonedx/cyclonedx-npm": "6.0.1"
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -37,7 +37,6 @@ async function runKeypressPrompt({ input, output, draw, accept }) {
|
|
|
37
37
|
let settled = false;
|
|
38
38
|
let keypressHandler = null;
|
|
39
39
|
let rawChanged = false;
|
|
40
|
-
let resumed = false;
|
|
41
40
|
let cursorHidden = false;
|
|
42
41
|
|
|
43
42
|
const render = () => {
|
|
@@ -59,7 +58,6 @@ async function runKeypressPrompt({ input, output, draw, accept }) {
|
|
|
59
58
|
}
|
|
60
59
|
if (wasPaused && typeof input.resume === "function") {
|
|
61
60
|
input.resume();
|
|
62
|
-
resumed = true;
|
|
63
61
|
}
|
|
64
62
|
output.write("\x1b[?25l");
|
|
65
63
|
cursorHidden = true;
|
|
@@ -92,7 +90,11 @@ async function runKeypressPrompt({ input, output, draw, accept }) {
|
|
|
92
90
|
clear();
|
|
93
91
|
if (cursorHidden) output.write("\x1b[?25h");
|
|
94
92
|
if (rawChanged) input.setRawMode(false);
|
|
95
|
-
|
|
93
|
+
// A TTY can report itself as already flowing before the first prompt (for
|
|
94
|
+
// example through an SSH pseudo-terminal). Leaving it flowing keeps Node's
|
|
95
|
+
// event loop alive after setup has printed its final result. Always pause
|
|
96
|
+
// prompt input after removing our listener; the next selector resumes it.
|
|
97
|
+
if (typeof input.pause === "function") input.pause();
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
|
|
@@ -19,7 +19,7 @@ const manifest = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
|
|
19
19
|
const lock = JSON.parse(fs.readFileSync(process.argv[3], "utf8"));
|
|
20
20
|
const candidateWorkflow = fs.readFileSync(process.argv[4], "utf8");
|
|
21
21
|
const publishWorkflow = fs.readFileSync(process.argv[5], "utf8");
|
|
22
|
-
const expected = "6.0.
|
|
22
|
+
const expected = "6.0.1";
|
|
23
23
|
|
|
24
24
|
if (manifest.devDependencies?.["@cyclonedx/cyclonedx-npm"] !== expected) {
|
|
25
25
|
throw new Error(`package.json must pin @cyclonedx/cyclonedx-npm exactly to ${expected}`);
|
|
@@ -300,6 +300,19 @@ async function testTerminalSelectors(prompts) {
|
|
|
300
300
|
await assert.rejects(cancelled, (error) => error?.status === 130 && /cancelled/i.test(error.message));
|
|
301
301
|
assert.equal(input.isRaw, false);
|
|
302
302
|
assert.equal(input.isPaused(), true);
|
|
303
|
+
|
|
304
|
+
const flowingInput = new FakeTTY();
|
|
305
|
+
flowingInput.paused = false;
|
|
306
|
+
const flowing = prompts.selectOnePrompt({
|
|
307
|
+
message: "Release flowing input",
|
|
308
|
+
choices: [{ value: "done", label: "Done" }],
|
|
309
|
+
input: flowingInput,
|
|
310
|
+
output: output.stream,
|
|
311
|
+
});
|
|
312
|
+
setImmediate(() => flowingInput.emit("keypress", "", { name: "return" }));
|
|
313
|
+
assert.equal(await flowing, "done");
|
|
314
|
+
assert.equal(flowingInput.isRaw, false);
|
|
315
|
+
assert.equal(flowingInput.isPaused(), true, "terminal prompt must release flowing stdin so the CLI can exit");
|
|
303
316
|
}
|
|
304
317
|
|
|
305
318
|
async function testStructuredSetupSelectors(setup, fixture) {
|
|
@@ -38,5 +38,4 @@ Scopes defined in `.opencode/memory.json`:
|
|
|
38
38
|
## Tool Roles
|
|
39
39
|
- AgentFS is the durable structured memory layer.
|
|
40
40
|
- AnythingLLM is the long-form document retrieval layer.
|
|
41
|
-
- `lean-ctx` is the default context layer (reads, search, exploration), not durable project memory.
|
|
42
41
|
- RTK is a recommended companion for shell-heavy sessions (git, listings, failing builds); Token Savior is not default.
|