@memstack/cli 0.6.4 → 0.7.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @memstack/cli
2
2
 
3
- CLI for MemStack — shell-based agent memory. Use from bash scripts, Claude Code shell tool, CI pipelines, or any subprocess-capable agent.
3
+ CLI for MemStack — shell-based agent memory. Use from bash scripts, opencode/Claude Code shell tools, CI pipelines, or any subprocess-capable agent.
4
4
 
5
5
  ## Installation
6
6
 
@@ -106,6 +106,18 @@ memstack import --actor "agent-1" --file ./backup.json
106
106
  # {"imported":1500}
107
107
  ```
108
108
 
109
+ Each memory's original `createdAt` is preserved on import (round-trips exactly with `export`). Importing a snapshot with zero memories fails cleanly with a non-zero exit.
110
+
111
+ ## Input validation
112
+
113
+ The CLI normalizes and validates input before storing:
114
+
115
+ - **`--importance`** is clamped to the `0.0–1.0` range (e.g. `--importance 5` stores as `1`, `--importance=-1` stores as `0`).
116
+ - **`--actor`** is trimmed of leading/trailing whitespace (`--actor " a "` and `--actor a` are the same actor).
117
+ - **`--tags`** drops empty entries from trailing/double commas (`--tags "a,,b,"` → `["a","b"]`).
118
+ - **`prune --type`** rejects unknown strategies with a non-zero exit instead of silently doing nothing. Valid: `byAge`, `byImportance`, `byCount`, `byType`, `custom`, `compose`.
119
+ - **`prune --actor`** is scoped to that actor only — it never touches other actors' memories.
120
+
109
121
  ## Shell agent usage
110
122
 
111
123
  ```bash
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from 'util';
3
+ import { readFile, writeFile } from 'fs/promises';
4
+ import { MemStack } from '@memstack/core';
5
+ import { loadConfigFromEnv } from '@memstack/config-env';
6
+
7
+ async function loadConfig() {
8
+ const { config } = await loadConfigFromEnv();
9
+ return config;
10
+ }
11
+
12
+ // src/cli.ts
13
+ async function main() {
14
+ const { positionals, values } = parseArgs({
15
+ allowPositionals: true,
16
+ options: {
17
+ actor: { type: "string" },
18
+ content: { type: "string" },
19
+ type: { type: "string" },
20
+ importance: { type: "string" },
21
+ tags: { type: "string" },
22
+ query: { type: "string" },
23
+ strategy: { type: "string" },
24
+ limit: { type: "string" },
25
+ "max-tokens": { type: "string" },
26
+ "older-than": { type: "string" },
27
+ "max-age": { type: "string" },
28
+ "min-importance": { type: "string" },
29
+ "max-count": { type: "string" },
30
+ ids: { type: "string" },
31
+ id: { type: "string" },
32
+ "created-after": { type: "string" },
33
+ "created-before": { type: "string" },
34
+ "dry-run": { type: "boolean" },
35
+ out: { type: "string" },
36
+ file: { type: "string" }
37
+ }
38
+ });
39
+ const command = positionals[0];
40
+ if (!command) {
41
+ printUsage();
42
+ process.exit(1);
43
+ }
44
+ const config = await loadConfig();
45
+ const ms = new MemStack(config);
46
+ let result;
47
+ switch (command) {
48
+ case "store": {
49
+ if (!values.actor) fail("--actor is required");
50
+ if (!values.content) fail("--content is required");
51
+ const importance = values.importance ? Math.max(0, Math.min(1, Number(values.importance))) : void 0;
52
+ result = await ms.memory.store({
53
+ actorId: String(values.actor).trim(),
54
+ content: String(values.content),
55
+ memoryType: values.type,
56
+ importance,
57
+ tags: values.tags ? String(values.tags).split(",").map((t) => t.trim()).filter((t) => t.length > 0) : void 0
58
+ });
59
+ break;
60
+ }
61
+ case "retrieve": {
62
+ if (!values.actor) fail("--actor is required");
63
+ result = await ms.memory.retrieve({
64
+ actorId: values.actor,
65
+ query: values.query,
66
+ strategy: values.strategy,
67
+ limit: values.limit ? Number(values.limit) : void 0,
68
+ tags: values.tags ? String(values.tags).split(",") : void 0,
69
+ createdAfter: values["created-after"] ? new Date(String(values["created-after"])) : void 0,
70
+ createdBefore: values["created-before"] ? new Date(String(values["created-before"])) : void 0
71
+ });
72
+ break;
73
+ }
74
+ case "context": {
75
+ if (!values.actor) fail("--actor is required");
76
+ result = await ms.memory.compileContext({
77
+ actorId: String(values.actor),
78
+ maxTokens: values["max-tokens"] ? Number(values["max-tokens"]) : void 0
79
+ });
80
+ break;
81
+ }
82
+ case "summarize": {
83
+ if (!values.actor) fail("--actor is required");
84
+ const durationMs = values["older-than"] ? parseDuration(String(values["older-than"])) : void 0;
85
+ const olderThan = durationMs ? new Date(Date.now() - durationMs) : void 0;
86
+ result = await ms.memory.summarize({
87
+ actorId: values.actor,
88
+ olderThan
89
+ });
90
+ break;
91
+ }
92
+ case "prune": {
93
+ if (!values.actor) fail("--actor is required");
94
+ const VALID_TYPES = ["byAge", "byImportance", "byCount", "byType", "custom", "compose"];
95
+ const pruneType = values.type ?? "byAge";
96
+ if (!VALID_TYPES.includes(String(pruneType))) {
97
+ fail(`Invalid prune type: ${pruneType}. Valid: ${VALID_TYPES.join(", ")}`);
98
+ }
99
+ const strategy = {
100
+ type: pruneType,
101
+ actorId: String(values.actor).trim(),
102
+ maxAge: values["max-age"] ? parseDuration(String(values["max-age"])) : void 0,
103
+ minImportance: values["min-importance"] ? Number(values["min-importance"]) : void 0,
104
+ maxPerActor: values["max-count"] ? Number(values["max-count"]) : void 0
105
+ };
106
+ if (values["dry-run"]) {
107
+ result = await ms.memory.dryRunPrune(strategy);
108
+ } else {
109
+ result = await ms.memory.prune(strategy);
110
+ }
111
+ break;
112
+ }
113
+ case "purge": {
114
+ if (!values.actor) fail("--actor is required");
115
+ result = await ms.memory.purgeActor(String(values.actor));
116
+ break;
117
+ }
118
+ case "merge": {
119
+ if (!values.ids) fail("--ids is required");
120
+ result = await ms.memory.merge(
121
+ String(values.ids).split(",").map((s) => s.trim())
122
+ );
123
+ break;
124
+ }
125
+ case "stats": {
126
+ result = await ms.memory.stats(values.actor);
127
+ break;
128
+ }
129
+ case "delete": {
130
+ if (!values.id) fail("--id is required");
131
+ await ms.memory.delete(String(values.id));
132
+ result = { deleted: true };
133
+ break;
134
+ }
135
+ case "health": {
136
+ result = await ms.health();
137
+ break;
138
+ }
139
+ case "export": {
140
+ const snapshot = await ms.export(values.actor);
141
+ const outPath = values.out;
142
+ if (outPath) {
143
+ await writeFile(outPath, JSON.stringify(snapshot, null, 2), "utf-8");
144
+ }
145
+ result = outPath ? { saved: outPath, count: snapshot.memories.length } : snapshot;
146
+ break;
147
+ }
148
+ case "import": {
149
+ if (!values.actor) fail("--actor is required");
150
+ if (!values.file) fail("--file is required");
151
+ const raw = await readFile(String(values.file), "utf-8");
152
+ let snapshot = JSON.parse(raw);
153
+ if (Array.isArray(snapshot)) {
154
+ snapshot = { version: 1, memories: snapshot, exportedAt: (/* @__PURE__ */ new Date()).toISOString() };
155
+ }
156
+ if (!snapshot.memories || !Array.isArray(snapshot.memories) || snapshot.memories.length === 0) {
157
+ fail("Snapshot contains no memories to import");
158
+ }
159
+ await ms.import(snapshot);
160
+ result = { imported: snapshot.memories.length };
161
+ break;
162
+ }
163
+ default:
164
+ printUsage();
165
+ process.exit(1);
166
+ }
167
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
168
+ await ms.close();
169
+ }
170
+ function parseDuration(input) {
171
+ const match = input.match(/^(\d+)([smhd])$/);
172
+ if (!match) {
173
+ throw new Error(
174
+ `Invalid duration: ${input}. Use format like "7d", "24h", "30m".`
175
+ );
176
+ }
177
+ const value = Number(match[1]);
178
+ switch (match[2]) {
179
+ case "s":
180
+ return value * 1e3;
181
+ case "m":
182
+ return value * 60 * 1e3;
183
+ case "h":
184
+ return value * 3600 * 1e3;
185
+ case "d":
186
+ return value * 86400 * 1e3;
187
+ default:
188
+ return value;
189
+ }
190
+ }
191
+ function printUsage() {
192
+ process.stderr.write(`memstack <command> [flags]
193
+
194
+ Commands:
195
+ store Store a memory
196
+ retrieve Retrieve memories
197
+ context Compile LLM-ready context
198
+ summarize Compress old interactions
199
+ prune Remove stale memories
200
+ purge Delete all memories for an actor
201
+ merge Merge multiple memories
202
+ stats Memory diagnostics
203
+ delete Delete a single memory
204
+ health Check connectivity
205
+ export Export all memories
206
+ import Import memories from a JSON snapshot
207
+
208
+ Run memstack <command> --help for flags.
209
+ `);
210
+ }
211
+ function fail(message) {
212
+ process.stderr.write(`Error: ${message}
213
+ `);
214
+ process.exit(1);
215
+ }
216
+ main().catch((err) => {
217
+ process.stderr.write(
218
+ `Error: ${err instanceof Error ? err.message : String(err)}
219
+ `
220
+ );
221
+ process.exit(1);
222
+ });
223
+ //# sourceMappingURL=cli.js.map
224
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["import type { MemStackConfig } from \"@memstack/core\";\nimport { loadConfigFromEnv } from \"@memstack/config-env\";\n\nexport async function loadConfig(): Promise<MemStackConfig> {\n const { config } = await loadConfigFromEnv();\n return config;\n}\n","#!/usr/bin/env node\nimport { parseArgs } from \"node:util\";\nimport { writeFile, readFile } from \"node:fs/promises\";\nimport { MemStack } from \"@memstack/core\";\nimport type { MemStackConfig, MemoryType, PruneStrategy } from \"@memstack/core\";\nimport { loadConfig } from \"./config.js\";\n\nasync function main() {\n const { positionals, values } = parseArgs({\n allowPositionals: true,\n options: {\n actor: { type: \"string\" },\n content: { type: \"string\" },\n type: { type: \"string\" },\n importance: { type: \"string\" },\n tags: { type: \"string\" },\n query: { type: \"string\" },\n strategy: { type: \"string\" },\n limit: { type: \"string\" },\n \"max-tokens\": { type: \"string\" },\n \"older-than\": { type: \"string\" },\n \"max-age\": { type: \"string\" },\n \"min-importance\": { type: \"string\" },\n \"max-count\": { type: \"string\" },\n ids: { type: \"string\" },\n id: { type: \"string\" },\n \"created-after\": { type: \"string\" },\n \"created-before\": { type: \"string\" },\n \"dry-run\": { type: \"boolean\" },\n out: { type: \"string\" },\n file: { type: \"string\" },\n },\n });\n\n const command = positionals[0];\n if (!command) {\n printUsage();\n process.exit(1);\n }\n\n const config: MemStackConfig = await loadConfig();\n const ms = new MemStack(config);\n\n let result: unknown;\n switch (command) {\n case \"store\": {\n if (!values.actor) fail(\"--actor is required\");\n if (!values.content) fail(\"--content is required\");\n const importance = values.importance ? Math.max(0, Math.min(1, Number(values.importance))) : undefined;\n result = await ms.memory.store({\n actorId: String(values.actor).trim(),\n content: String(values.content),\n memoryType: values.type as MemoryType | undefined,\n importance,\n tags: values.tags\n ? String(values.tags)\n .split(\",\")\n .map((t) => t.trim())\n .filter((t) => t.length > 0)\n : undefined,\n });\n break;\n }\n\n case \"retrieve\": {\n if (!values.actor) fail(\"--actor is required\");\n result = await ms.memory.retrieve({\n actorId: values.actor as string | undefined,\n query: values.query as string | undefined,\n strategy: values.strategy as \"recent\" | \"important\" | \"semantic\" | \"hybrid\" | undefined,\n limit: values.limit ? Number(values.limit) : undefined,\n tags: values.tags ? String(values.tags).split(\",\") : undefined,\n createdAfter: values[\"created-after\"]\n ? new Date(String(values[\"created-after\"]))\n : undefined,\n createdBefore: values[\"created-before\"]\n ? new Date(String(values[\"created-before\"]))\n : undefined,\n });\n break;\n }\n\n case \"context\": {\n if (!values.actor) fail(\"--actor is required\");\n result = await ms.memory.compileContext({\n actorId: String(values.actor),\n maxTokens: values[\"max-tokens\"] ? Number(values[\"max-tokens\"]) : undefined,\n });\n break;\n }\n\n case \"summarize\": {\n if (!values.actor) fail(\"--actor is required\");\n const durationMs = values[\"older-than\"]\n ? parseDuration(String(values[\"older-than\"]))\n : undefined;\n const olderThan = durationMs ? new Date(Date.now() - durationMs) : undefined;\n result = await ms.memory.summarize({\n actorId: values.actor as string | undefined,\n olderThan,\n });\n break;\n }\n\n case \"prune\": {\n if (!values.actor) fail(\"--actor is required\");\n const VALID_TYPES = [\"byAge\", \"byImportance\", \"byCount\", \"byType\", \"custom\", \"compose\"];\n const pruneType = values.type ?? \"byAge\";\n if (!VALID_TYPES.includes(String(pruneType))) {\n fail(`Invalid prune type: ${pruneType}. Valid: ${VALID_TYPES.join(\", \")}`);\n }\n const strategy: PruneStrategy = {\n type: pruneType as PruneStrategy[\"type\"],\n actorId: String(values.actor).trim(),\n maxAge: values[\"max-age\"]\n ? parseDuration(String(values[\"max-age\"]))\n : undefined,\n minImportance: values[\"min-importance\"]\n ? Number(values[\"min-importance\"])\n : undefined,\n maxPerActor: values[\"max-count\"]\n ? Number(values[\"max-count\"])\n : undefined,\n };\n\n if (values[\"dry-run\"]) {\n result = await ms.memory.dryRunPrune(strategy);\n } else {\n result = await ms.memory.prune(strategy);\n }\n break;\n }\n\n case \"purge\": {\n if (!values.actor) fail(\"--actor is required\");\n result = await ms.memory.purgeActor(String(values.actor));\n break;\n }\n\n case \"merge\": {\n if (!values.ids) fail(\"--ids is required\");\n result = await ms.memory.merge(\n String(values.ids)\n .split(\",\")\n .map((s) => s.trim()),\n );\n break;\n }\n\n case \"stats\": {\n result = await ms.memory.stats(values.actor as string | undefined);\n break;\n }\n\n case \"delete\": {\n if (!values.id) fail(\"--id is required\");\n await ms.memory.delete(String(values.id));\n result = { deleted: true };\n break;\n }\n\n case \"health\": {\n result = await ms.health();\n break;\n }\n\n case \"export\": {\n const snapshot = await ms.export(values.actor as string | undefined);\n const outPath = values.out as string | undefined;\n if (outPath) {\n await writeFile(outPath, JSON.stringify(snapshot, null, 2), \"utf-8\");\n }\n result = outPath ? { saved: outPath, count: snapshot.memories.length } : snapshot;\n break;\n }\n\n case \"import\": {\n if (!values.actor) fail(\"--actor is required\");\n if (!values.file) fail(\"--file is required\");\n const raw = await readFile(String(values.file), \"utf-8\");\n let snapshot = JSON.parse(raw);\n if (Array.isArray(snapshot)) {\n snapshot = { version: 1 as const, memories: snapshot, exportedAt: new Date().toISOString() };\n }\n if (!snapshot.memories || !Array.isArray(snapshot.memories) || snapshot.memories.length === 0) {\n fail(\"Snapshot contains no memories to import\");\n }\n await ms.import(snapshot);\n result = { imported: snapshot.memories.length };\n break;\n }\n\n default:\n printUsage();\n process.exit(1);\n }\n\n process.stdout.write(JSON.stringify(result, null, 2) + \"\\n\");\n await ms.close();\n}\n\nfunction parseDuration(input: string): number {\n const match = input.match(/^(\\d+)([smhd])$/);\n if (!match) {\n throw new Error(\n `Invalid duration: ${input}. Use format like \"7d\", \"24h\", \"30m\".`,\n );\n }\n const value = Number(match[1]);\n switch (match[2]) {\n case \"s\":\n return value * 1000;\n case \"m\":\n return value * 60 * 1000;\n case \"h\":\n return value * 3600 * 1000;\n case \"d\":\n return value * 86400 * 1000;\n default:\n return value;\n }\n}\n\nfunction printUsage() {\n process.stderr.write(`memstack <command> [flags]\n\nCommands:\n store Store a memory\n retrieve Retrieve memories\n context Compile LLM-ready context\n summarize Compress old interactions\n prune Remove stale memories\n purge Delete all memories for an actor\n merge Merge multiple memories\n stats Memory diagnostics\n delete Delete a single memory\n health Check connectivity\n export Export all memories\n import Import memories from a JSON snapshot\n\nRun memstack <command> --help for flags.\n`);\n}\n\nfunction fail(message: string): never {\n process.stderr.write(`Error: ${message}\\n`);\n process.exit(1);\n}\n\nmain().catch((err) => {\n process.stderr.write(\n `Error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memstack/cli",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
4
4
  "description": "CLI for MemStack — shell-based agent memory",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
@@ -29,7 +29,8 @@
29
29
  },
30
30
  "homepage": "https://github.com/isiomaC/memstack",
31
31
  "dependencies": {
32
- "@memstack/core": "0.6.4"
32
+ "@memstack/config-env": "0.7.0",
33
+ "@memstack/core": "0.7.0"
33
34
  },
34
35
  "devDependencies": {
35
36
  "tsup": "^8.0.0",