@pleri/olam-cli 0.1.206 → 0.1.207

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.
@@ -1,4 +1,4 @@
1
1
  {
2
- "bundledAt": "2026-06-02T12:45:34.001Z",
2
+ "bundledAt": "2026-06-02T16:46:23.219Z",
3
3
  "kgFirstSha": "29a9ccce1b115d049e375c4a90eb5cf7c123e610e2d0590270a4db2cdbc64a28"
4
4
  }
@@ -118,7 +118,7 @@ spec:
118
118
  # k3d), started by `olam upgrade` Step 0.7 — not inside this Pod.
119
119
  containers:
120
120
  - name: olam-host-cp
121
- image: ghcr.io/pleri/olam-host-cp@sha256:f11d34247171fba77439e3877ba8b781b857d1eb3f1c983bac2621dd7a254fef
121
+ image: ghcr.io/pleri/olam-host-cp@sha256:0d1869ed3c823e6ea1b5d885d2f73d7418134c1b82c9dd70719044fd04d74027
122
122
  imagePullPolicy: IfNotPresent
123
123
  securityContext:
124
124
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  mountPath: /data
71
71
  containers:
72
72
  - name: olam-auth-service
73
- image: ghcr.io/pleri/olam-auth@sha256:10879610c8930d06e2201171ca98249da756461fbbca7540face7593de3f2516
73
+ image: ghcr.io/pleri/olam-auth@sha256:9f8195a20727ec844d7393696c298b42e3e83e841fe684787ee9c6d1e301b5e8
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true
@@ -61,7 +61,7 @@ spec:
61
61
  mountPath: /data
62
62
  containers:
63
63
  - name: olam-kg-service
64
- image: ghcr.io/pleri/olam-kg-service@sha256:4fc5f7257d2fa8e11c07e5436a68edd0353c0d503739b9e90f7736e5b336a8fa
64
+ image: ghcr.io/pleri/olam-kg-service@sha256:0b1f78a566675509f371e4e0636a76859f800c1bec787f06742e3a4f116d7c90
65
65
  imagePullPolicy: IfNotPresent
66
66
  securityContext:
67
67
  runAsNonRoot: true
@@ -68,7 +68,7 @@ spec:
68
68
  mountPath: /data
69
69
  containers:
70
70
  - name: olam-mcp-auth-service
71
- image: ghcr.io/pleri/olam-mcp-auth@sha256:0780d597d7eb7d124eb998cf8e56649e375a594e4181ddb181f8b1cb2d443701
71
+ image: ghcr.io/pleri/olam-mcp-auth@sha256:63ecc6bdd5c3def600a78046f0e7ab36938e88bc6fc7d31a446d7cec84a27a3a
72
72
  imagePullPolicy: IfNotPresent
73
73
  securityContext:
74
74
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  # bootstrap-placeholder comment + run `npm run refresh:manifest-digests`
71
71
  # once ghcr.io/pleri/olam-memory-service has a real published digest.
72
72
  # bootstrap-placeholder: pre-publish; refresh after first release
73
- image: ghcr.io/pleri/olam-memory-service@sha256:4b2742280eb0437e3865e603d1d148e28408a1ec8aa4a7dd2c726cd3d31ee8dd
73
+ image: ghcr.io/pleri/olam-memory-service@sha256:673156cc638fc9af096e73fc7cd7c666373f92e63e566a57f51271b691aa9d74
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * agentmemory-save.mjs — PostToolUse hook: persist agent-written memory notes.
4
+ *
5
+ * AM_SENTINEL=olam-agent-memory-hook-v2
6
+ *
7
+ * This is the FILE-BASED port of the legacy inline python SAVE blob that used
8
+ * to live directly in ~/.claude/settings.json under
9
+ * `AM_SENTINEL=olam-agent-memory-hook-v1; python3 -c '…'`. The installer
10
+ * (`olam hooks install-all`, invoked by `olam skills sync`) copies this file to
11
+ * ~/.claude/scripts/hooks/ and registers a settings.json entry pointing at it,
12
+ * REPLACING the inline blob. Keeping the logic in a real source file means it
13
+ * is version-controlled, testable, bundled into @pleri/olam-cli, and owned by
14
+ * sync — not stranded as a string in the operator's settings.
15
+ *
16
+ * Behaviour (byte-faithful port of the v1 blob):
17
+ * - Reads the PostToolUse JSON payload from stdin.
18
+ * - Acts ONLY when tool_name === "Write" AND the written file_path matches
19
+ * /\/\.claude\/projects\/.*\/memory\/.*\.md$/ ; otherwise bails (exit 0).
20
+ * - Requires OLAM_AGENT_MEMORY_BEARER (trimmed, non-empty); else bails.
21
+ * - Parses YAML-ish frontmatter delimited by leading "---":
22
+ * description: → title (default "memory") ← keyed on description, per v1
23
+ * type: → type (default "fact")
24
+ * remainder → body
25
+ * - POSTs {title, content: body, type} to
26
+ * <OLAM_AGENT_MEMORY_URL|default>/agentmemory/remember
27
+ * with Authorization: Bearer <bearer>, ~3s timeout.
28
+ * - On success prints to STDERR the green status line:
29
+ * [🧠⇡ Memory saved] "<title first 60 chars>"
30
+ * - Fail-open: ANY error → silent, exit 0. Never throws to the caller.
31
+ *
32
+ * Node built-ins only (global fetch + AbortController, available on Node ≥18).
33
+ */
34
+
35
+ import { readFileSync } from 'node:fs';
36
+
37
+ const DEFAULT_URL = 'https://atlas-agent-memory.atlas-kitchen.workers.dev';
38
+ const MEMORY_PATH_RE = /\/\.claude\/projects\/.*\/memory\/.*\.md$/;
39
+ const TIMEOUT_MS = 3000;
40
+
41
+ /** Read all of stdin as a UTF-8 string. */
42
+ function readStdin() {
43
+ try {
44
+ return readFileSync(0, 'utf8');
45
+ } catch {
46
+ return '';
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Parse leading "---"-delimited frontmatter. Returns {title, type, body}.
52
+ * Mirrors the v1 blob: title comes from `description:`, type from `type:`.
53
+ */
54
+ function parseNote(raw) {
55
+ let title = 'memory';
56
+ let type = 'fact';
57
+ let body = raw;
58
+ if (raw.startsWith('---')) {
59
+ // Split into [before-first-delim, frontmatter, …rest]. JS's limited split
60
+ // truncates the remainder, so slice manually to keep the full body.
61
+ const firstDelimEnd = 3; // length of leading "---"
62
+ const secondDelim = raw.indexOf('---', firstDelimEnd);
63
+ if (secondDelim !== -1) {
64
+ const fm = raw.slice(firstDelimEnd, secondDelim);
65
+ body = raw.slice(secondDelim + 3).trim();
66
+ for (const ln of fm.split('\n')) {
67
+ const s = ln.trim();
68
+ if (s.startsWith('description:')) {
69
+ title = stripQuotes(s.slice(s.indexOf(':') + 1).trim());
70
+ } else if (s.startsWith('type:')) {
71
+ type = stripQuotes(s.slice(s.indexOf(':') + 1).trim());
72
+ }
73
+ }
74
+ }
75
+ }
76
+ return { title, type, body };
77
+ }
78
+
79
+ function stripQuotes(v) {
80
+ return v.replace(/^["']/, '').replace(/["']$/, '');
81
+ }
82
+
83
+ async function main() {
84
+ const payloadRaw = readStdin();
85
+ let payload;
86
+ try {
87
+ payload = JSON.parse(payloadRaw);
88
+ } catch {
89
+ return; // not parseable → fail-open
90
+ }
91
+
92
+ const toolName = payload?.tool_name ?? '';
93
+ const filePath = payload?.tool_input?.file_path ?? '';
94
+ if (toolName !== 'Write' || !MEMORY_PATH_RE.test(filePath)) return;
95
+
96
+ const bearer = (process.env['OLAM_AGENT_MEMORY_BEARER'] ?? '').trim();
97
+ if (!bearer) return;
98
+
99
+ let raw;
100
+ try {
101
+ raw = readFileSync(filePath, 'utf8');
102
+ } catch {
103
+ return;
104
+ }
105
+
106
+ const { title, type, body } = parseNote(raw);
107
+ const base = (process.env['OLAM_AGENT_MEMORY_URL'] ?? DEFAULT_URL).replace(/\/$/, '');
108
+ const url = `${base}/agentmemory/remember`;
109
+
110
+ const controller = new AbortController();
111
+ const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
112
+ try {
113
+ const resp = await fetch(url, {
114
+ method: 'POST',
115
+ headers: {
116
+ 'Content-Type': 'application/json',
117
+ Authorization: `Bearer ${bearer}`,
118
+ 'User-Agent': 'olam-agent-memory-hook/2',
119
+ },
120
+ body: JSON.stringify({ title, content: body, type }),
121
+ signal: controller.signal,
122
+ });
123
+ // Treat any non-throwing response as delivered (the v1 blob did the same —
124
+ // it printed on a non-exception urlopen regardless of status code).
125
+ if (resp) {
126
+ const label = title.slice(0, 60);
127
+ process.stderr.write(`\x1b[32m[\u{1F9E0}\u{21E1} Memory saved]\x1b[0m "${label}"\n`);
128
+ }
129
+ } catch {
130
+ // Fail-open: network error / timeout / abort → silent.
131
+ } finally {
132
+ clearTimeout(timer);
133
+ }
134
+ }
135
+
136
+ main().catch(() => {
137
+ /* fail-open: never propagate to the caller */
138
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pleri/olam-cli",
3
- "version": "0.1.206",
3
+ "version": "0.1.207",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "olam": "./bin/olam.cjs"