@cairnkeep/cli 2.9.0 → 2.11.0

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.
Files changed (78) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/README.md +54 -25
  3. package/bin/cairn +6 -165
  4. package/bin/cairn-container +8 -0
  5. package/docs/building-an-overlay.md +41 -4
  6. package/docs/containers.md +10 -0
  7. package/docs/harness-compatibility.md +30 -2
  8. package/docs/learning/CURRICULUM-MAP.md +9 -3
  9. package/docs/learning/FEATURE-GUIDE.md +9 -3
  10. package/docs/learning/README.md +2 -0
  11. package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
  12. package/docs/learning/lessons/L01-safe-trial.md +3 -3
  13. package/docs/learning/lessons/L02-installation.md +11 -2
  14. package/docs/learning/lessons/L03-first-project.md +1 -1
  15. package/docs/learning/lessons/L19-validated-skill-improvement.md +1 -1
  16. package/docs/learning/lessons/L20-mcp-tool-profiles.md +1 -1
  17. package/docs/learning/lessons/L21-context-packs.md +1 -1
  18. package/docs/learning/lessons/L22-native-windows.md +83 -0
  19. package/docs/learning/lessons/L23-guided-setup.md +138 -0
  20. package/docs/learning/tracks/operator.md +8 -3
  21. package/docs/learning/tracks/quickstart.md +7 -3
  22. package/docs/native-windows.md +122 -0
  23. package/docs/operating.md +119 -18
  24. package/docs/privacy-and-data-flow.md +34 -1
  25. package/docs/storage.md +14 -2
  26. package/examples/eval/bundled-fake.json +1 -1
  27. package/mcp-memory-server/dist/artifact-store-windows-worker.js +74 -0
  28. package/mcp-memory-server/dist/artifact-store.js +196 -55
  29. package/mcp-memory-server/dist/capability-cli.js +2 -1
  30. package/mcp-memory-server/dist/capability-config.js +4 -3
  31. package/mcp-memory-server/dist/capability-harness.js +34 -7
  32. package/mcp-memory-server/dist/context-pack.js +84 -25
  33. package/mcp-memory-server/dist/eval-cli.js +6 -5
  34. package/mcp-memory-server/dist/eval-plan.js +35 -13
  35. package/mcp-memory-server/dist/eval-process.js +11 -4
  36. package/mcp-memory-server/dist/eval-report.js +7 -5
  37. package/mcp-memory-server/dist/graph-cli.js +7 -1
  38. package/mcp-memory-server/dist/index.js +19 -20
  39. package/mcp-memory-server/dist/mcp-tool-profile.js +6 -4
  40. package/mcp-memory-server/dist/note-store.js +12 -3
  41. package/mcp-memory-server/dist/pi-mcp-bridge.js +185 -0
  42. package/mcp-memory-server/dist/platform-security.js +102 -0
  43. package/mcp-memory-server/dist/skill-store.js +27 -12
  44. package/mcp-memory-server/package.json +2 -1
  45. package/package.json +5 -4
  46. package/pi/extensions/cairnkeep-memory.ts +61 -0
  47. package/schemas/cairnkeep-setup-policy.schema.json +55 -0
  48. package/schemas/cairnkeep-setup.schema.json +36 -0
  49. package/scripts/cairn-cli.mjs +119 -0
  50. package/scripts/cairn-container-cli.mjs +121 -0
  51. package/scripts/cairn-hook.mjs +199 -0
  52. package/scripts/completion.sh +12 -3
  53. package/scripts/doctor.sh +57 -0
  54. package/scripts/fix-permissions.mjs +12 -0
  55. package/scripts/memory-wiki-audit.mjs +95 -0
  56. package/scripts/phase26-test-manifest.mjs +26 -0
  57. package/scripts/run-repository-tests.mjs +76 -0
  58. package/scripts/setup-core.mjs +310 -0
  59. package/scripts/setup-reconcile.mjs +331 -0
  60. package/scripts/setup.mjs +306 -0
  61. package/scripts/sync-pi-assets.sh +19 -4
  62. package/scripts/test-completion.sh +39 -0
  63. package/scripts/test-doctor.sh +66 -0
  64. package/scripts/test-learning-docs.sh +52 -3
  65. package/scripts/test-package-install.sh +64 -0
  66. package/scripts/test-phase17-artifact-lifecycle.sh +1 -1
  67. package/scripts/test-phase18-capability-lifecycle.sh +1 -1
  68. package/scripts/test-pi-lifecycle.mjs +190 -0
  69. package/scripts/test-setup-compatibility.mjs +186 -0
  70. package/scripts/test-setup-output.sh +131 -0
  71. package/scripts/test-setup-overlay.sh +113 -0
  72. package/scripts/test-setup-preflight.mjs +281 -0
  73. package/scripts/test-setup-reconcile.mjs +257 -0
  74. package/scripts/test-uninstall.sh +50 -0
  75. package/scripts/test-windows-native.mjs +136 -0
  76. package/scripts/uninstall.sh +69 -6
  77. package/scripts/verify-pi-mcp-bridge.mjs +588 -0
  78. package/scripts/windows-platform.mjs +725 -0
package/docs/operating.md CHANGED
@@ -7,20 +7,23 @@ Cairnkeep has three moving parts:
7
7
 
8
8
  1. **The memory server** (`cairn-memory`) — an MCP server your harness talks to.
9
9
  2. **The project scaffold** — `.ai/` launchers and the `.planning/` knowledge
10
- layer, written by `cairn bootstrap`.
10
+ layer, written by `cairn setup` or the compatibility-oriented
11
+ `cairn bootstrap` primitive.
11
12
  3. **The operating layer** — the commands, agents, and hooks that live in your
12
13
  harness config and drive the workflow.
13
14
 
14
- `cairn bootstrap` only does step 2. Steps 1 and 3 are one-time-per-machine
15
- installs. This guide covers all three in order.
15
+ `cairn setup` is the recommended project entry point. `cairn bootstrap`
16
+ retains its established deterministic behavior for existing automation. Steps
17
+ 1 and 3 are one-time-per-machine installs; project setup reports the explicit
18
+ sync command but never runs it automatically. This guide covers all three.
16
19
 
17
20
  ## Prerequisites
18
21
 
19
22
  - Node.js 22 or newer (for the memory server) and a supported harness. Claude
20
23
  Code and OpenCode receive the full operating layer. Kimi Code receives the
21
24
  memory MCP, launcher, and opt-in graph Skill; Qwen Code receives the memory
22
- MCP and launcher. Pi receives its native trajectory adapter, graph prompt,
23
- and launcher.
25
+ MCP and launcher. Pi receives a maintained local stdio MCP extension, native
26
+ trajectory adapter, graph prompt, and launcher after explicit machine sync.
24
27
  - Optional: the `sqlite3` CLI for `cairn memory export`. Runtime memory and
25
28
  `cairn memory import` do not require it.
26
29
  - Optional: an OpenAI-compatible LLM endpoint for memory extraction and
@@ -29,6 +32,12 @@ installs. This guide covers all three in order.
29
32
  - Optional: rootless Podman for the containerized memory server and isolated
30
33
  workspace base described in [Containers](containers.md).
31
34
 
35
+ Native Windows x64 is supported directly from PowerShell or Command Prompt;
36
+ WSL and Git Bash are not required. The npm package installs a Node entry point,
37
+ and bootstrap emits `.cmd` plus PowerShell launchers. See
38
+ [Native Windows operation](native-windows.md) for the exact setup and recovery
39
+ contract. Windows ARM64 currently uses x64 emulation.
40
+
32
41
  ## Shell completion
33
42
 
34
43
  Generate completion definitions directly from the CLI:
@@ -37,12 +46,65 @@ Generate completion definitions directly from the CLI:
37
46
  cairn completion bash
38
47
  cairn completion zsh
39
48
  cairn completion fish
49
+ cairn completion powershell
40
50
  ```
41
51
 
42
52
  Distributions can install these outputs into the platform's normal completion
43
53
  directories. They can also be loaded for the current shell, for example with
44
54
  `source <(cairn completion bash)`.
45
55
 
56
+ In PowerShell, load completion for the current session with:
57
+
58
+ ```powershell
59
+ Invoke-Expression (& cairn completion powershell | Out-String)
60
+ ```
61
+
62
+ ## Guided project setup
63
+
64
+ Interactive terminals may run `cairn setup` and answer the target, Git,
65
+ harness, memory, and confirmation questions. Automation must make every choice
66
+ explicit:
67
+
68
+ ```bash
69
+ cairn setup /path/to/project --git init --harness claude,pi --memory local --yes
70
+ ```
71
+
72
+ The deterministic form accepts `--git init|existing|none`, a comma-separated
73
+ subset of `claude,opencode,pi,kimi,qwen`, and `--memory local|none`. `--git
74
+ existing` requires the target to be in an existing work tree. `--git init`
75
+ requires Git and is the only non-interactive authorization to initialize a
76
+ repository. `--git none` is an explicit limited mode: repository-aware features
77
+ remain unavailable, and both setup output and `cairn doctor` say so. A missing
78
+ or empty interactive target recommends initialization and asks before writing;
79
+ an existing non-Git tree is never initialized silently.
80
+
81
+ Setup first classifies the target and Git state without writing, then creates or
82
+ reconciles only the selected project launchers and common scaffold assets.
83
+ Identical managed files remain unchanged, changed managed files are updated,
84
+ and unrelated files are preserved. The result reports created, updated,
85
+ unchanged, and skipped counts; `cairn doctor`; an exact launcher per selected
86
+ harness; and the deterministic setup command to use for recovery. `--json`
87
+ returns the same schema-v1 result. The private mode-`0600`
88
+ `.ai/cairnkeep.json` record stores the package version, Git and memory modes,
89
+ selected harnesses, and digests/modes/template identifiers for setup-owned
90
+ assets. It contains no credentials, endpoints, or absolute paths.
91
+
92
+ Setup never installs or refreshes machine-level harness assets. Its
93
+ `machine_sync.automatic` field is always false, and the human output labels the
94
+ reported command as not run automatically. Apply the relevant machine command
95
+ explicitly, check it, then diagnose and launch:
96
+
97
+ ```bash
98
+ cairn sync --apply # Claude Code operating assets
99
+ cairn sync-pi --apply # Pi extension and prompt
100
+ cairn sync-pi --check
101
+ cd /path/to/project && cairn doctor
102
+ ./.ai/start-pi.sh
103
+ ```
104
+
105
+ `cairn bootstrap [--untracked] PATH` remains available for scripts that depend
106
+ on its original scaffold and Git-exclusion contract.
107
+
46
108
  ## Setup order (Claude Code)
47
109
 
48
110
  The commands below install the default local topology: `cairn-memory` runs as a
@@ -206,8 +268,9 @@ cairn graph diff
206
268
  ```
207
269
 
208
270
  The same direct CLI works with Qwen Code, Codex, and other shell-capable
209
- clients. This does not add a Pi MCP bridge or imply that those harnesses receive
210
- the rest of Cairnkeep's operating layer.
271
+ clients. Pi sync separately installs Cairnkeep's maintained local stdio MCP
272
+ extension; the graph prompt remains a thin adapter and does not expand the rest
273
+ of Pi's operating surface.
211
274
 
212
275
  All six modes delegate to `cairn graph`. Managed builds run Graphify's local
213
276
  code-only `update` path with provider credentials removed from the subprocess
@@ -217,6 +280,9 @@ so Graphify cannot re-index its own generated HTML/report/JSON. Managed builds
217
280
  do not perform Graphify's optional semantic document extraction. Prefer exact
218
281
  function, class, or file names; broad natural-language graph queries are less
219
282
  precise. Cairnkeep does not install or update Graphify automatically.
283
+ Set `CAIRN_GRAPHIFY_BINARY` to override the `graphify` command when Graphify is
284
+ installed at a specific path. Native executables run directly; `.js`, `.mjs`,
285
+ and `.cjs` helpers run through the active Node runtime on every platform.
220
286
 
221
287
  Graphify also maintains an incremental `graphify-out/` work directory at the
222
288
  repository root. It is separate from Cairnkeep's published
@@ -299,26 +365,52 @@ configuration, approval behavior, and overlay guidance.
299
365
 
300
366
  ## Setup order (Pi)
301
367
 
302
- Pi trajectory capture uses the same project scaffold and store. Its sync also
303
- installs a thin `/graphify` prompt into Pi's agent root:
368
+ Pi uses the same project scaffold and local memory store. Its explicit sync
369
+ installs the maintained memory extension, native trajectory extension, and thin
370
+ `/graphify` prompt into Pi's agent root:
304
371
 
305
372
  ```bash
306
373
  npm install -g @cairnkeep/cli
307
374
  cairn sync-pi --apply # default: ~/.pi/agent
308
- cairn bootstrap /path/to/project
375
+ cairn setup /path/to/project --git init --harness pi --memory local --yes
309
376
  cp /path/to/project/.ai/env.example /path/to/project/.ai/.env
310
377
  cd /path/to/project && cairn doctor && ./.ai/start-pi.sh
311
378
  ```
312
379
 
313
- This command does not install an MCP bridge. Cairnkeep does not own or select a
314
- Pi bridge; if you want `cairn memory-server` tools inside Pi as well, configure
315
- a user-chosen Pi extension/bridge separately.
380
+ The memory extension starts `cairn memory-server` as a local stdio child from
381
+ the project root. It dynamically discovers the effective server catalog, so
382
+ feature gates, capability state, and the current MCP tool profile remain
383
+ authoritative. It does not contain a second hard-coded catalog. Startup is
384
+ bounded to 10 seconds, calls to 30 seconds, results to 4 MiB, and retained child
385
+ stderr to the newest 16 KiB. Cancellation is propagated, child or protocol
386
+ failure is surfaced, and session shutdown closes the child.
387
+
388
+ Tool names, descriptions, input and output schemas, content,
389
+ `structuredContent`, `_meta`, and failure behavior cross the bridge without
390
+ semantic rewriting. The exact MCP annotations are preserved in the trusted Pi
391
+ result `details`, together with the discovered tool metadata and original
392
+ content. Pi 0.84.1 has no native annotations field in its public tool API, so
393
+ Cairnkeep does not claim native model-facing annotation propagation or invent a
394
+ substitute field.
395
+
396
+ The bridge is tools-only: it does not run prompts, activate context-pack skills,
397
+ create an autonomous loop, add remote access, or bypass server-side tool
398
+ restrictions. Removing `MCP_HTTP_PORT` from the child environment deliberately
399
+ keeps this integration on local stdio.
316
400
 
317
401
  Use `cairn sync-pi --check` to report drift without writing, or
318
402
  `--live-root DIR` to target an isolated Pi agent root. The command owns exactly
319
- `extensions/cairnkeep-trajectory.ts` and `prompts/graphify.md`; `cairn
320
- uninstall --pi-live-root DIR` removes those files backup-first and leaves every
321
- other Pi asset untouched.
403
+ `extensions/cairnkeep-memory.ts`, `extensions/cairnkeep-trajectory.ts`, and
404
+ `prompts/graphify.md`; `cairn doctor` reports a selected Pi extension that is
405
+ missing or drifted and points to `cairn sync-pi --apply`. `cairn uninstall
406
+ --pi-live-root DIR` removes those files backup-first and leaves every other Pi
407
+ asset untouched.
408
+
409
+ Pi 0.84.1 is the validated minimum supported version for this extension. The
410
+ v2.11 release passed the complete setup and bridge matrix on separate Pi 0.84.1
411
+ minimum and registry-current installations, Node.js 22, 24, and 26, Bash 3.2,
412
+ and native Windows. The two Pi executable paths differed, while both reported
413
+ 0.84.1 because that was also the registry-current release.
322
414
 
323
415
  The extension listens for Pi's native `session_shutdown` event and reads only
324
416
  the active branch from the read-only session manager. It returns before doing
@@ -381,6 +473,7 @@ vendor or host.
381
473
  | `CAIRN_HARNESS_STATE_DIR` | Optional absolute local root for recoverable native capability leases (default `${XDG_STATE_HOME:-~/.local/state}/cairn/harness`) |
382
474
  | `CAIRN_GIT_PROVIDER` | Git host for collaboration commands: `github`\|`gitlab`\|`codeberg`\|`forgejo`\|`none`. See [git-providers.md](git-providers.md) |
383
475
  | `CAIRN_ROUTE_ENDPOINT` | Base URL of an already-running token-miser routing/tiering proxy (unset → the `route_check` tool is inert) |
476
+ | `CAIRN_GRAPHIFY_BINARY` | Optional Graphify command/path override; JavaScript helpers run through the active Node runtime (default `graphify` from `PATH`) |
384
477
  | `CAIRN_EXPLORE_BINARY` | Absolute path to the `token_miser` binary used by `context_explore` (unset → the tool throws at call time) |
385
478
  | `CAIRN_EXPLORE_REPO_ROOT` | Default repo root for `context_explore` when no per-call `repo_root` is given (unset + no param → the tool throws) |
386
479
  | `CAIRN_EXPLORE_CACHE` | Caches `context_explore` results keyed on query + repo HEAD + dirty-state; default ON, set to `0` to disable |
@@ -809,6 +902,13 @@ rebuild only derived indexes/dedupe/pointers from valid authoritative records.
809
902
  Unsupported schema, SQLite failure, invalid full records, or digest corruption
810
903
  fails untouched with guidance to preserve the database before manual recovery.
811
904
 
905
+ When `.ai/cairnkeep.json` exists, doctor also validates its private state,
906
+ selected assets, digests, and modes. It reports `limited` for explicit
907
+ `--git none`, fails an incomplete or drifted setup with the recorded
908
+ deterministic `cairn setup` recovery command, and checks the Pi machine
909
+ extension when Pi was selected. `cairn sync-pi --apply` repairs that
910
+ machine-level drift; setup itself never performs the sync.
911
+
812
912
  ### Evaluation harness (opt-in)
813
913
 
814
914
  `cairn eval` is a local, serial experiment coordinator. It is disabled unless
@@ -897,8 +997,9 @@ claims.
897
997
  SIGINT or SIGTERM stops schedule admission, terminates the active adapter,
898
998
  checkpoints a `cancelled` observation, waits for bounded cleanup, and retains
899
999
  an inspectable partial report. On POSIX systems the runner targets the child
900
- process group with TERM then bounded KILL escalation. Windows descendant-tree
901
- termination is not guaranteed and is not a supported evaluation claim.
1000
+ process group with TERM then bounded KILL escalation. Native Windows targets
1001
+ the adapter and its descendant tree with `taskkill.exe /T`, escalating to `/F`
1002
+ after the bounded grace period.
902
1003
 
903
1004
  See [storage](storage.md#evaluation-report-and-note-snapshot-storage) for local
904
1005
  retention/removal and [privacy](privacy-and-data-flow.md#evaluation-adapter-and-report-flow)
@@ -36,6 +36,8 @@ request unless the corresponding endpoint and credential are configured.
36
36
  | Automatic compaction recovery | None | Structured categories are injected locally; raw summary and other bodies are excluded |
37
37
  | Explicit artifact read/show | The redacted body only when HTTP is separately enabled and the operator/client explicitly reads it | Local terminal/stdio, or the explicitly registered authenticated server |
38
38
  | Opt-in evaluation coordinator | Adapter-defined inference may leave the machine only according to the explicit operator-owned adapter and inherited environment | Local adapter subprocess; Cairnkeep supplies no provider, endpoint, credential, model, or network default |
39
+ | Guided project setup | None | Selected scaffold assets and private `.ai/cairnkeep.json` state in the target; machine sync is never automatic |
40
+ | Pi memory extension | None | Local `cairn memory-server` stdio child; no HTTP transport is inherited |
39
41
 
40
42
  Model endpoints may be local or remote. Cairnkeep cannot determine a provider's
41
43
  retention, training, or logging policy; verify it before sending confidential
@@ -91,6 +93,35 @@ and its generated `revert.sh` restores exact bytes, modes, and layout. Explicit
91
93
  `cairn eval delete` and `prune` remove selected contained experiment trees with
92
94
  no hidden tombstone.
93
95
 
96
+ ## Guided setup and Pi bridge
97
+
98
+ Guided setup performs a read-only target and Git preflight before project
99
+ writes. Its schema-v1 `.ai/cairnkeep.json` record contains the package version,
100
+ Git and memory choices, selected harness names, and setup-owned asset paths,
101
+ digests, modes, and template identifiers. It does not contain credentials,
102
+ endpoints, absolute paths, prompts, or memory values. The file is mode `0600`
103
+ on POSIX and receives the private managed-file ACL on native Windows. Setup
104
+ never invokes machine sync, and it does not start a harness or server child.
105
+
106
+ When the explicitly installed Pi memory extension starts a session, it spawns
107
+ `cairn memory-server` as a child in the project directory over local stdio. The
108
+ bridge removes `MCP_HTTP_PORT` from the child environment, retains only the
109
+ newest 16 KiB of child stderr for bounded failure diagnostics, caps startup,
110
+ calls, catalogs, and results, and closes the child at shutdown. The child still
111
+ inherits the remaining operator environment needed by the normal local server,
112
+ so those environment values and the project directory are a child-process trust
113
+ boundary even though they are not persisted by the bridge.
114
+
115
+ Catalog and call replay is allow-listed to MCP tool metadata and result fields.
116
+ Names, schemas, annotations, content, `structuredContent`, `_meta`, and error
117
+ state are preserved without sanitizing away protocol meaning; Pi receives the
118
+ annotations in trusted result `details` because Pi 0.84.1 has no native
119
+ annotations field. The bridge does not log requests or results, create a second
120
+ catalog, activate prompts or skills, add remote access, or persist a transcript.
121
+ Sanitized test replay uses synthetic tool arguments, results, stderr, and
122
+ project paths only; release evidence must not include credentials, private
123
+ endpoints, memory values, or identifying local paths.
124
+
94
125
  ## Evaluation adapter and report flow
95
126
 
96
127
  `CAIRN_EVAL` is unset/off by default. With it off, `cairn eval` returns a fixed
@@ -169,7 +200,9 @@ network-free, and permanently scoped as framework-only evidence.
169
200
  SIGINT/SIGTERM stops new schedule admission, terminates the active adapter,
170
201
  checkpoints cancellation, performs bounded cleanup, and retains a partial
171
202
  report. POSIX process groups receive TERM followed by bounded KILL escalation.
172
- There is no Windows descendant-process-tree termination guarantee.
203
+ Native Windows uses `taskkill.exe /T` for the exact child tree and `/F` for
204
+ bounded force escalation; it does not enumerate or terminate unrelated
205
+ processes.
173
206
 
174
207
  Turns aggregate only under exact matching compatibility IDs. Missing token
175
208
  components/totals, unknown verifier outcomes, incompatible turn semantics, and
package/docs/storage.md CHANGED
@@ -31,6 +31,17 @@ For the local launchers, the server working directory is normally the project
31
31
  root. Bootstrap installs `.agentfs/.gitignore` so private project memory is not
32
32
  accidentally committed. SQLite may also create `-wal` and `-shm` sidecar files.
33
33
 
34
+ Private-file protection is platform-equivalent rather than mode-identical.
35
+ Linux and macOS use `0600` files and `0700` directories. Native Windows removes
36
+ inherited ACLs and grants access only to the current SID, Local System, and the
37
+ built-in Administrators group. `cairn doctor` fails closed when a managed MCP
38
+ profile or context-pack pointer has broader access. Context-pack objects also
39
+ receive a read-only attribute after their content digest is verified.
40
+
41
+ Where this document names a generated `revert.sh`, native Windows produces the
42
+ equivalent backup manifest and `revert.ps1`; it restores exact bytes and the
43
+ Windows ACL contract rather than emulating POSIX mode bits.
44
+
34
45
  `CAIRN_LLM_API_URL` and `CAIRN_MEMORY_EMBEDDING_URL` select optional model
35
46
  services used to process/search memory. They do not change where the SQLite
36
47
  databases are stored. Git-provider and routing configuration do not change
@@ -502,8 +513,9 @@ bearer_token_env_var = "CAIRN_MEMORY_HTTP_TOKEN"
502
513
  Context-pack objects are content-addressed, immutable directories. Installation
503
514
  copies verified content through a temporary directory and atomically publishes
504
515
  the digest; a failed or concurrent install never changes project enablement.
505
- Project pointers are separate atomic mode-`0600` files keyed by canonical local
506
- project identity or a validated remote project ID. Updates retain old objects
516
+ Project pointers are separate atomic private files (`0600` on POSIX, restricted
517
+ ACLs on Windows) keyed by canonical local project identity or a validated
518
+ remote project ID. Updates retain old objects
507
519
  and switch only the named project after exact-digest confirmation.
508
520
 
509
521
  `cairn doctor` verifies objects, pointers, and interrupted-install remnants.
@@ -1 +1 @@
1
- {"identifier":"cairn-offline-fake-v1","package_version":"2.9.0","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
1
+ {"identifier":"cairn-offline-fake-v1","package_version":"2.11.0","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
@@ -0,0 +1,74 @@
1
+ import { AgentFS } from "agentfs-sdk";
2
+ import { deleteArtifactForWindowsWorker, doctorArtifactStore, getArtifactDbPath, listArtifacts, pruneArtifactsForWindowsWorker, putArtifact, readArtifact, readLatestCompaction, recordUnsupportedCompactionAdapter, } from "./artifact-store.js";
3
+ async function readRequest() {
4
+ const chunks = [];
5
+ for await (const chunk of process.stdin)
6
+ chunks.push(Buffer.from(chunk));
7
+ const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
8
+ if (!parsed || typeof parsed.operation !== "string" || typeof parsed.projectRoot !== "string") {
9
+ throw new Error("Invalid Windows artifact worker request.");
10
+ }
11
+ return parsed;
12
+ }
13
+ function resolvedOptions(options = {}) {
14
+ const { now, ...rest } = options;
15
+ return { ...rest, ...(now ? { now: new Date(now) } : {}) };
16
+ }
17
+ async function rawOperation(request) {
18
+ const agent = await AgentFS.open({ id: "artifacts", path: getArtifactDbPath(request.projectRoot) });
19
+ try {
20
+ if (request.action === "list")
21
+ return await agent.kv.list(request.prefix ?? "");
22
+ if (request.action === "get")
23
+ return await agent.kv.get(request.key ?? "");
24
+ if (request.action === "set") {
25
+ await agent.kv.set(request.key ?? "", request.value);
26
+ return null;
27
+ }
28
+ if (request.action === "delete") {
29
+ await agent.kv.delete(request.key ?? "");
30
+ return null;
31
+ }
32
+ throw new Error("Unsupported raw Windows artifact operation.");
33
+ }
34
+ finally {
35
+ await agent.close();
36
+ }
37
+ }
38
+ async function dispatch(request) {
39
+ const limits = request.limits;
40
+ if (request.operation === "put" && limits) {
41
+ return { result: await putArtifact(request.projectRoot, request.candidate, limits, resolvedOptions(request.options)) };
42
+ }
43
+ if (request.operation === "read" && request.identifier) {
44
+ return { result: await readArtifact(request.identifier, request.projectRoot) };
45
+ }
46
+ if (request.operation === "list") {
47
+ return { result: await listArtifacts(request.projectRoot, request.filters) };
48
+ }
49
+ if (request.operation === "latest") {
50
+ return { result: await readLatestCompaction(request.projectRoot, request.sessionRef) };
51
+ }
52
+ if (request.operation === "delete" && request.identifier) {
53
+ return deleteArtifactForWindowsWorker(request.identifier, request.projectRoot, request.options);
54
+ }
55
+ if (request.operation === "prune" && limits) {
56
+ return pruneArtifactsForWindowsWorker(request.projectRoot, limits, resolvedOptions(request.options));
57
+ }
58
+ if (request.operation === "record-unsupported") {
59
+ await recordUnsupportedCompactionAdapter(request.projectRoot, request.diagnostic);
60
+ return { result: null };
61
+ }
62
+ if (request.operation === "doctor" && limits) {
63
+ return { result: await doctorArtifactStore(request.projectRoot, request.repair, limits) };
64
+ }
65
+ if (request.operation === "raw")
66
+ return { result: await rawOperation(request) };
67
+ throw new Error("Unsupported Windows artifact worker operation.");
68
+ }
69
+ dispatch(await readRequest())
70
+ .then((response) => process.stdout.write(JSON.stringify(response)))
71
+ .catch((error) => {
72
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
73
+ process.exitCode = 1;
74
+ });