@cairnkeep/cli 1.1.0 → 1.1.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.
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/cairnkeep/cairnkeep/main/schemas/cairnkeep-overlay.schema.json",
4
+ "title": "Cairnkeep distribution profile",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "id", "name", "version", "core", "policy", "bootstrap"],
8
+ "properties": {
9
+ "schemaVersion": {"const": 1},
10
+ "id": {"type": "string", "pattern": "^[a-z][a-z0-9-]{1,63}$"},
11
+ "name": {"type": "string", "minLength": 1, "maxLength": 120},
12
+ "version": {
13
+ "type": "string",
14
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:[-+][0-9A-Za-z.-]+)?$"
15
+ },
16
+ "core": {
17
+ "type": "object",
18
+ "additionalProperties": false,
19
+ "required": ["package", "version"],
20
+ "properties": {
21
+ "package": {"const": "@cairnkeep/cli"},
22
+ "version": {
23
+ "type": "string",
24
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:[-+][0-9A-Za-z.-]+)?$"
25
+ }
26
+ }
27
+ },
28
+ "policy": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["memory", "rag", "gitProvider"],
32
+ "properties": {
33
+ "memory": {
34
+ "type": "object",
35
+ "additionalProperties": false,
36
+ "required": ["transport", "storage"],
37
+ "properties": {
38
+ "transport": {"enum": ["stdio", "http"]},
39
+ "storage": {"enum": ["local", "remote"]},
40
+ "baseDir": {"type": "string", "minLength": 1},
41
+ "endpoint": {"type": "string", "format": "uri"}
42
+ },
43
+ "allOf": [
44
+ {
45
+ "if": {"properties": {"storage": {"const": "local"}}},
46
+ "then": {"required": ["baseDir"]}
47
+ },
48
+ {
49
+ "if": {"properties": {"storage": {"const": "remote"}}},
50
+ "then": {"required": ["endpoint"]}
51
+ }
52
+ ]
53
+ },
54
+ "rag": {
55
+ "type": "object",
56
+ "additionalProperties": false,
57
+ "required": ["mode"],
58
+ "properties": {
59
+ "mode": {"enum": ["disabled", "local", "remote"]},
60
+ "baseUrl": {"type": "string", "format": "uri"}
61
+ },
62
+ "if": {"properties": {"mode": {"enum": ["local", "remote"]}}},
63
+ "then": {"required": ["baseUrl"]}
64
+ },
65
+ "gitProvider": {"type": "string", "minLength": 1}
66
+ }
67
+ },
68
+ "bootstrap": {
69
+ "type": "object",
70
+ "additionalProperties": false,
71
+ "required": ["defaultMode", "launcher", "profileLock"],
72
+ "properties": {
73
+ "defaultMode": {"enum": ["tracked", "untracked"]},
74
+ "launcher": {"type": "string", "minLength": 1},
75
+ "profileLock": {"type": "string", "minLength": 1}
76
+ }
77
+ }
78
+ }
79
+ }
@@ -1,13 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from "node:child_process";
3
3
 
4
- const serverPath = process.argv[2];
5
- if (!serverPath) {
6
- console.error("usage: probe-memory-server.mjs PATH_TO_SERVER");
4
+ const probeArgs = process.argv.slice(2);
5
+ if (probeArgs.length === 0) {
6
+ console.error("usage: probe-memory-server.mjs PATH_TO_SERVER | --command COMMAND [ARGS...]");
7
7
  process.exit(2);
8
8
  }
9
9
 
10
- const child = spawn(process.execPath, [serverPath], {
10
+ const commandMode = probeArgs[0] === "--command";
11
+ const command = commandMode ? probeArgs[1] : process.execPath;
12
+ const commandArgs = commandMode ? probeArgs.slice(2) : [probeArgs[0]];
13
+ if (!command) {
14
+ console.error("probe-memory-server.mjs: --command requires a command");
15
+ process.exit(2);
16
+ }
17
+
18
+ const child = spawn(command, commandArgs, {
11
19
  env: process.env,
12
20
  stdio: ["pipe", "pipe", "pipe"],
13
21
  });
@@ -29,7 +37,11 @@ const response = new Promise((resolve, reject) => {
29
37
  if (!line.trim()) continue;
30
38
  try {
31
39
  const message = JSON.parse(line);
32
- if (message.id === 1 && message.result?.serverInfo?.name === "cairn-memory") {
40
+ if (
41
+ message.id === 1 &&
42
+ message.result?.serverInfo?.name === "cairn-memory" &&
43
+ message.result?.capabilities?.tools
44
+ ) {
33
45
  resolve();
34
46
  return;
35
47
  }
@@ -5,35 +5,28 @@
5
5
  # transport works. This is the core product path, and nothing else tests it
6
6
  # after packaging/installation.
7
7
  #
8
- # Prefers `cairn memory-server` (a global install), else falls back to node on
9
- # the repo's dist build — so it works both post-install and from a clone.
8
+ # Prefers `cairn memory-server` (a global install), else falls back to the
9
+ # repository build. The Node probe owns the timeout so this works on macOS,
10
+ # which does not ship GNU `timeout`.
10
11
  set -uo pipefail
11
12
 
12
13
  ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
13
14
 
14
15
  if command -v cairn >/dev/null 2>&1; then
15
- server=(cairn memory-server)
16
+ probe=(node "$ROOT_DIR/scripts/probe-memory-server.mjs" --command cairn memory-server)
16
17
  elif [[ -f "$ROOT_DIR/mcp-memory-server/dist/index.js" ]]; then
17
- server=(node "$ROOT_DIR/mcp-memory-server/dist/index.js")
18
+ probe=(node "$ROOT_DIR/scripts/probe-memory-server.mjs" "$ROOT_DIR/mcp-memory-server/dist/index.js")
18
19
  else
19
20
  echo "smoke-mcp-boot: FAIL (no cairn on PATH and no dist build to run)"
20
21
  exit 1
21
22
  fi
22
23
 
23
- req='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"ci","version":"0"}}}'
24
-
25
24
  tmp=$(mktemp -d)
26
25
  trap 'rm -rf "$tmp"' EXIT
27
26
 
28
- # HOME points at a throwaway dir so the server's default store (~/.cairnkeep)
29
- # lands there; `head -1` closes stdin after the first reply, so the server sees
30
- # EOF and exits cleanly.
31
- out=$(printf '%s\n' "$req" | HOME="$tmp" timeout 15 "${server[@]}" 2>/dev/null | head -1)
32
-
33
- if grep -q '"result"' <<<"$out" && grep -q '"tools"' <<<"$out"; then
27
+ if HOME="$tmp" "${probe[@]}"; then
34
28
  echo "smoke-mcp-boot: OK (server booted, initialize returned tools capability)"
35
29
  exit 0
36
30
  fi
37
31
  echo "smoke-mcp-boot: FAIL (no valid initialize response)"
38
- echo " got: ${out:0:200}"
39
32
  exit 1
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
5
+
6
+ node --input-type=module - "$ROOT" <<'NODE'
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+
10
+ const root = process.argv[2];
11
+ const schema = JSON.parse(fs.readFileSync(path.join(root, "schemas/cairnkeep-overlay.schema.json"), "utf8"));
12
+ const example = JSON.parse(fs.readFileSync(path.join(root, "examples/overlay-distribution/cairnkeep.overlay.json"), "utf8"));
13
+
14
+ if (schema.$schema !== "https://json-schema.org/draft/2020-12/schema") throw new Error("unexpected schema draft");
15
+ if (schema.properties.schemaVersion.const !== 1) throw new Error("unexpected schema version");
16
+ for (const field of schema.required) {
17
+ if (!(field in example)) throw new Error(`example missing required field: ${field}`);
18
+ }
19
+ if (example.core.package !== "@cairnkeep/cli") throw new Error("example must consume the public core");
20
+ if (example.policy.memory.storage !== "local") throw new Error("example must remain local-first");
21
+ if (example.policy.memory.transport !== "stdio") throw new Error("example must remain local-first");
22
+ NODE
23
+
24
+ pack_manifest=$(mktemp)
25
+ trap 'rm -f "$pack_manifest"' EXIT
26
+ npm --prefix "$ROOT" pack --dry-run --json --ignore-scripts > "$pack_manifest"
27
+ node --input-type=module - "$pack_manifest" <<'NODE'
28
+ import fs from "node:fs";
29
+
30
+ const manifest = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
31
+ const files = new Set(manifest[0].files.map((item) => item.path));
32
+ for (const required of [
33
+ "schemas/cairnkeep-overlay.schema.json",
34
+ "examples/overlay-distribution/cairnkeep.overlay.json",
35
+ "docs/overlay-distributions.md",
36
+ ]) {
37
+ if (!files.has(required)) throw new Error(`npm package missing ${required}`);
38
+ }
39
+ NODE
40
+
41
+ echo "overlay schema checks passed"
@@ -29,4 +29,8 @@ bootstrap_output=$(cairn bootstrap "$tmp/project")
29
29
 
30
30
  (cd "$tmp/project" && cairn doctor) >/dev/null || fail "installed package failed cairn doctor"
31
31
 
32
+ installed_root="$tmp/prefix/lib/node_modules/@cairnkeep/cli"
33
+ [[ -f "$installed_root/examples/anythingllm/sync_to_anythingllm.py" ]] || \
34
+ fail "npm tarball omitted the default AnythingLLM sync script"
35
+
32
36
  echo "PASS: npm tarball installs a self-contained CLI and MCP server"
@@ -27,3 +27,9 @@
27
27
  # Optional: comma-separated allowed Host headers for DNS-rebinding protection
28
28
  # (default: the bind host + localhost on the chosen port).
29
29
  # CAIRN_MEMORY_HTTP_ALLOWED_HOSTS=
30
+ #
31
+ # Optional document-RAG sync. API credentials and endpoint may be local or remote.
32
+ # ANYTHINGLLM_BASE_URL=http://localhost:3001
33
+ # ANYTHINGLLM_API_KEY=
34
+ # CAIRN_ANYTHINGLLM_PROJECTS_FILE=~/.config/cairnkeep/anythingllm-projects.json
35
+ # CAIRN_ANYTHINGLLM_STATE_FILE=~/.local/state/cairnkeep/anythingllm-sync.json