toon-memory 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.
@@ -8,7 +8,7 @@ const args = process.argv.slice(2)
8
8
 
9
9
  const target = args[0] === "mcp"
10
10
  ? join(__dirname, "..", "mcp", "server.js")
11
- : join(__dirname, "setup.js")
11
+ : join(__dirname, "..", "dist", "cli", "setup.js")
12
12
 
13
13
  const extraArgs = args[0] === "mcp" ? [] : args
14
14
  const child = spawn("node", [target, ...extraArgs], { stdio: "inherit" })
@@ -0,0 +1,237 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, cpSync, unlinkSync } from "fs";
2
+ import { dirname, join } from "path";
3
+ import { fileURLToPath } from "url";
4
+ import { execSync } from "child_process";
5
+ import { createInterface } from "readline";
6
+ import { createRequire } from "module";
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const projectRoot = process.cwd();
9
+ const sourceDir = join(__dirname, "..", "..", "src");
10
+ const HOME = process.env.HOME || process.env.USERPROFILE || "~";
11
+ try {
12
+ createRequire(import.meta.url).resolve("@toon-format/toon");
13
+ } catch {
14
+ console.log("Installing @toon-format/toon...");
15
+ execSync("npm install @toon-format/toon", { cwd: projectRoot, stdio: "inherit" });
16
+ }
17
+ function detectAgents() {
18
+ const agents2 = [];
19
+ const opencodeGlobal = join(HOME, ".config", "opencode", "opencode.json");
20
+ const opencodeLocal = join(projectRoot, ".opencode", "opencode.json");
21
+ agents2.push({
22
+ name: "opencode",
23
+ global: opencodeGlobal,
24
+ local: opencodeLocal,
25
+ mcpKey: "mcp"
26
+ });
27
+ const vscodeLocal = join(projectRoot, ".vscode", "mcp.json");
28
+ agents2.push({
29
+ name: "vscode/copilot",
30
+ local: vscodeLocal,
31
+ mcpKey: "servers"
32
+ });
33
+ const claudeGlobal = join(HOME, ".claude", "settings.json");
34
+ const claudeLocal = join(projectRoot, ".claude", "settings.json");
35
+ agents2.push({
36
+ name: "claude",
37
+ global: claudeGlobal,
38
+ local: claudeLocal,
39
+ mcpKey: "mcpServers"
40
+ });
41
+ const cursorLocal = join(projectRoot, ".cursor", "mcp.json");
42
+ agents2.push({
43
+ name: "cursor",
44
+ local: cursorLocal,
45
+ mcpKey: "mcpServers"
46
+ });
47
+ const windsurfGlobal = join(HOME, ".codeium", "windsurf", "mcp_config.json");
48
+ agents2.push({
49
+ name: "windsurf",
50
+ global: windsurfGlobal,
51
+ mcpKey: "mcpServers"
52
+ });
53
+ const clineLocal = join(projectRoot, ".cline", "mcp.json");
54
+ agents2.push({
55
+ name: "cline",
56
+ local: clineLocal,
57
+ mcpKey: "mcpServers"
58
+ });
59
+ const continueLocal = join(projectRoot, ".continue", "config.json");
60
+ agents2.push({
61
+ name: "continue",
62
+ local: continueLocal,
63
+ mcpKey: "mcpServers"
64
+ });
65
+ return agents2;
66
+ }
67
+ function installOpenCodeTools() {
68
+ const toolsDir = join(projectRoot, ".opencode", "tools");
69
+ const memoryDir = join(projectRoot, ".opencode", "memory");
70
+ const memoryFile = join(memoryDir, "data.toon");
71
+ if (!existsSync(toolsDir)) mkdirSync(toolsDir, { recursive: true });
72
+ if (!existsSync(memoryDir)) mkdirSync(memoryDir, { recursive: true });
73
+ cpSync(join(sourceDir, "memory.ts"), join(toolsDir, "memory.ts"));
74
+ console.log(" Copied memory.ts to .opencode/tools/");
75
+ if (!existsSync(memoryFile)) {
76
+ writeFileSync(memoryFile, "version: 1\nentries[0|]{id|category|key|content|file|tags|date}:\n");
77
+ console.log(" Created .opencode/memory/data.toon");
78
+ }
79
+ }
80
+ function installMCPConfig(agent, scope) {
81
+ const configPath = scope === "global" ? agent.global : agent.local;
82
+ if (!configPath) {
83
+ console.log(` No ${scope} config path for ${agent.name}`);
84
+ return;
85
+ }
86
+ const configDir = dirname(configPath);
87
+ if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true });
88
+ let config = {};
89
+ if (existsSync(configPath)) {
90
+ try {
91
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
92
+ } catch {
93
+ config = {};
94
+ }
95
+ }
96
+ const mcpKey = agent.mcpKey || "mcpServers";
97
+ if (!config[mcpKey]) config[mcpKey] = {};
98
+ config[mcpKey]["toon-memory"] = {
99
+ command: "npx",
100
+ args: ["-y", "toon-memory", "mcp"]
101
+ };
102
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
103
+ console.log(` MCP server added to ${configPath}`);
104
+ }
105
+ function uninstall() {
106
+ console.log("\n\u{1F9E0} toon-memory uninstaller\n");
107
+ const agents2 = detectAgents();
108
+ for (const agent of agents2) {
109
+ const configs = [agent.global, agent.local].filter(Boolean);
110
+ for (const configPath of configs) {
111
+ if (!existsSync(configPath)) continue;
112
+ try {
113
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
114
+ const mcpKey = agent.mcpKey || "mcpServers";
115
+ if (config[mcpKey]?.["toon-memory"]) {
116
+ delete config[mcpKey]["toon-memory"];
117
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
118
+ console.log(` \u2705 Removed from ${agent.name} (${configPath})`);
119
+ }
120
+ } catch {
121
+ }
122
+ }
123
+ }
124
+ const toolsFile = join(projectRoot, ".opencode", "tools", "memory.ts");
125
+ if (existsSync(toolsFile)) {
126
+ unlinkSync(toolsFile);
127
+ console.log(" \u2705 Removed .opencode/tools/memory.ts");
128
+ }
129
+ console.log("\n\u2705 toon-memory uninstalled from all agents\n");
130
+ }
131
+ function init(scope = "local") {
132
+ console.log("\n\u{1F9E0} toon-memory init\n");
133
+ const agents2 = detectAgents();
134
+ for (const agent of agents2) {
135
+ console.log(`${agent.name}:`);
136
+ if (agent.name === "opencode") {
137
+ installOpenCodeTools();
138
+ }
139
+ installMCPConfig(agent, scope);
140
+ console.log("");
141
+ }
142
+ console.log("Done! Restart your agent to use memory tools.\n");
143
+ }
144
+ function status() {
145
+ console.log("\n\u{1F9E0} toon-memory status\n");
146
+ try {
147
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
148
+ console.log(`Version: ${pkg.version}`);
149
+ } catch {
150
+ console.log("Version: unknown");
151
+ }
152
+ const memoryFile = join(projectRoot, ".opencode", "memory", "data.toon");
153
+ if (existsSync(memoryFile)) {
154
+ const data = readFileSync(memoryFile, "utf-8");
155
+ const lines = data.split("\n").filter((l) => l.startsWith(" ") && l.includes("|"));
156
+ console.log(`Memory: ${lines.length} entries`);
157
+ } else {
158
+ console.log("Memory: not initialized");
159
+ }
160
+ const agents2 = detectAgents();
161
+ console.log("\nAgent configs:");
162
+ for (const agent of agents2) {
163
+ const configs = [agent.global, agent.local].filter(Boolean);
164
+ let found = false;
165
+ for (const configPath of configs) {
166
+ if (!existsSync(configPath)) continue;
167
+ try {
168
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
169
+ const mcpKey = agent.mcpKey || "mcpServers";
170
+ if (config[mcpKey]?.["toon-memory"]) {
171
+ console.log(` \u2705 ${agent.name} (${configPath})`);
172
+ found = true;
173
+ }
174
+ } catch {
175
+ }
176
+ }
177
+ if (!found) {
178
+ console.log(` \u274C ${agent.name} (not configured)`);
179
+ }
180
+ }
181
+ console.log("");
182
+ }
183
+ function upgrade() {
184
+ console.log("\n\u{1F9E0} toon-memory upgrade\n");
185
+ try {
186
+ console.log("Checking for updates...");
187
+ const latest = execSync("npm view toon-memory version", { encoding: "utf-8" }).trim();
188
+ console.log(`Latest version: ${latest}`);
189
+ console.log("Upgrading...");
190
+ execSync("npm install -g toon-memory@" + latest, { stdio: "inherit" });
191
+ console.log(`
192
+ \u2705 Upgraded to toon-memory@${latest}`);
193
+ console.log("Restart your agent to use the new version.\n");
194
+ } catch (error) {
195
+ console.error("Upgrade failed:", error.message);
196
+ }
197
+ }
198
+ const args = process.argv.slice(2);
199
+ if (args[0] === "uninstall") {
200
+ uninstall();
201
+ process.exit(0);
202
+ }
203
+ if (args[0] === "init") {
204
+ init(args[1] || "local");
205
+ process.exit(0);
206
+ }
207
+ if (args[0] === "status") {
208
+ status();
209
+ process.exit(0);
210
+ }
211
+ if (args[0] === "upgrade") {
212
+ upgrade();
213
+ process.exit(0);
214
+ }
215
+ const agents = detectAgents();
216
+ console.log("\n\u{1F9E0} toon-memory installer\n");
217
+ console.log("Supported agents:");
218
+ agents.forEach((a, i) => console.log(` ${i + 1}. ${a.name}`));
219
+ console.log("");
220
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
221
+ rl.question("Install (1) Local or (2) Global? [1/2]: ", (answer) => {
222
+ const scope = answer === "2" ? "global" : "local";
223
+ console.log(`
224
+ Installing ${scope}ly...
225
+ `);
226
+ for (const agent of agents) {
227
+ console.log(`${agent.name}:`);
228
+ if (agent.name === "opencode") {
229
+ installOpenCodeTools();
230
+ }
231
+ installMCPConfig(agent, scope);
232
+ console.log("");
233
+ }
234
+ console.log("Done! Restart your agent to use memory tools.");
235
+ console.log("Run 'npx toon-memory uninstall' to remove.\n");
236
+ rl.close();
237
+ });
@@ -0,0 +1,9 @@
1
+ import { dirname, join } from "path";
2
+ import { fileURLToPath } from "url";
3
+ import { spawn } from "child_process";
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ const args = process.argv.slice(2);
6
+ const target = args[0] === "mcp" ? join(__dirname, "..", "mcp", "server.js") : join(__dirname, "..", "dist", "cli", "setup.js");
7
+ const extraArgs = args[0] === "mcp" ? [] : args;
8
+ const child = spawn("node", [target, ...extraArgs], { stdio: "inherit" });
9
+ child.on("exit", (code) => process.exit(code ?? 0));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toon-memory",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Persistent memory system for AI coding agents using TOON format (40% fewer tokens than JSON)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,6 +9,7 @@
9
9
  "files": [
10
10
  "src/",
11
11
  "bin/",
12
+ "dist/",
12
13
  "mcp/",
13
14
  "skills/",
14
15
  "install.sh",
@@ -16,8 +17,12 @@
16
17
  "uninstall.sh"
17
18
  ],
18
19
  "scripts": {
19
- "build": "esbuild src/mcp/server.ts --bundle --platform=node --format=esm --outfile=mcp/server.js",
20
- "prepublishOnly": "npm run build"
20
+ "build": "npm run build:mcp && npm run build:cli",
21
+ "build:mcp": "esbuild src/mcp/server.ts --bundle --platform=node --format=esm --outfile=mcp/server.js",
22
+ "build:cli": "esbuild src/cli/setup.ts --platform=node --format=esm --outfile=dist/cli/setup.js && esbuild src/cli/toon-memory.ts --platform=node --format=esm --outfile=dist/cli/toon-memory.js",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "prepublishOnly": "npm run build && npm test"
21
26
  },
22
27
  "dependencies": {
23
28
  "@modelcontextprotocol/server": "^2.0.0-beta.3",
@@ -25,7 +30,10 @@
25
30
  "zod": "^4.4.3"
26
31
  },
27
32
  "devDependencies": {
28
- "esbuild": "^0.25.0"
33
+ "@types/node": "^26.1.1",
34
+ "esbuild": "^0.25.0",
35
+ "typescript": "^7.0.2",
36
+ "vitest": "^4.1.10"
29
37
  },
30
38
  "keywords": [
31
39
  "opencode",
@@ -47,10 +55,10 @@
47
55
  "license": "MIT",
48
56
  "repository": {
49
57
  "type": "git",
50
- "url": "https://github.com/luiggival/toon-memory.git"
58
+ "url": "https://github.com/LuiggiVal08/toon-memory.git"
51
59
  },
52
- "homepage": "https://github.com/luiggival/toon-memory#readme",
60
+ "homepage": "https://github.com/LuiggiVal08/toon-memory#readme",
53
61
  "bugs": {
54
- "url": "https://github.com/luiggival/toon-memory/issues"
62
+ "url": "https://github.com/LuiggiVal08/toon-memory/issues"
55
63
  }
56
64
  }
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync, cpSync, unlinkSync } from "fs"
3
2
  import { dirname, join } from "path"
4
3
  import { fileURLToPath } from "url"
@@ -8,9 +7,18 @@ import { createRequire } from "module"
8
7
 
9
8
  const __dirname = dirname(fileURLToPath(import.meta.url))
10
9
  const projectRoot = process.cwd()
11
- const sourceDir = join(__dirname, "..", "src")
10
+ // When compiled to dist/cli/, src is at ../../src
11
+ // When running directly from src/cli/, src is at ../src
12
+ const sourceDir = join(__dirname, "..", "..", "src")
12
13
  const HOME = process.env.HOME || process.env.USERPROFILE || "~"
13
14
 
15
+ interface Agent {
16
+ name: string
17
+ global?: string
18
+ local?: string
19
+ mcpKey: string
20
+ }
21
+
14
22
  // Auto-install @toon-format/toon if not present
15
23
  try {
16
24
  createRequire(import.meta.url).resolve("@toon-format/toon")
@@ -20,8 +28,8 @@ try {
20
28
  }
21
29
 
22
30
  // Detect all supported agents
23
- function detectAgents() {
24
- const agents = []
31
+ function detectAgents(): Agent[] {
32
+ const agents: Agent[] = []
25
33
 
26
34
  // OpenCode
27
35
  const opencodeGlobal = join(HOME, ".config", "opencode", "opencode.json")
@@ -87,7 +95,7 @@ function detectAgents() {
87
95
  }
88
96
 
89
97
  // Install custom tools for OpenCode
90
- function installOpenCodeTools() {
98
+ function installOpenCodeTools(): void {
91
99
  const toolsDir = join(projectRoot, ".opencode", "tools")
92
100
  const memoryDir = join(projectRoot, ".opencode", "memory")
93
101
  const memoryFile = join(memoryDir, "data.toon")
@@ -105,7 +113,7 @@ function installOpenCodeTools() {
105
113
  }
106
114
 
107
115
  // Install MCP server config for different agents
108
- function installMCPConfig(agent, scope) {
116
+ function installMCPConfig(agent: Agent, scope: string): void {
109
117
  const configPath = scope === "global" ? agent.global : agent.local
110
118
 
111
119
  if (!configPath) {
@@ -116,7 +124,7 @@ function installMCPConfig(agent, scope) {
116
124
  const configDir = dirname(configPath)
117
125
  if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true })
118
126
 
119
- let config = {}
127
+ let config: Record<string, any> = {}
120
128
  if (existsSync(configPath)) {
121
129
  try {
122
130
  config = JSON.parse(readFileSync(configPath, "utf-8"))
@@ -138,13 +146,13 @@ function installMCPConfig(agent, scope) {
138
146
  }
139
147
 
140
148
  // Uninstall from all agents
141
- function uninstall() {
149
+ function uninstall(): void {
142
150
  console.log("\n🧠 toon-memory uninstaller\n")
143
151
 
144
152
  const agents = detectAgents()
145
153
 
146
154
  for (const agent of agents) {
147
- const configs = [agent.global, agent.local].filter(Boolean)
155
+ const configs = [agent.global, agent.local].filter(Boolean) as string[]
148
156
 
149
157
  for (const configPath of configs) {
150
158
  if (!existsSync(configPath)) continue
@@ -173,7 +181,7 @@ function uninstall() {
173
181
  }
174
182
 
175
183
  // Quick init without interactive prompts
176
- function init(scope = "local") {
184
+ function init(scope: string = "local"): void {
177
185
  console.log("\n🧠 toon-memory init\n")
178
186
 
179
187
  const agents = detectAgents()
@@ -193,7 +201,7 @@ function init(scope = "local") {
193
201
  }
194
202
 
195
203
  // Show installation status
196
- function status() {
204
+ function status(): void {
197
205
  console.log("\n🧠 toon-memory status\n")
198
206
 
199
207
  // Check npm package
@@ -208,7 +216,7 @@ function status() {
208
216
  const memoryFile = join(projectRoot, ".opencode", "memory", "data.toon")
209
217
  if (existsSync(memoryFile)) {
210
218
  const data = readFileSync(memoryFile, "utf-8")
211
- const lines = data.split("\n").filter((l) => l.startsWith(" ") && l.includes("|"))
219
+ const lines = data.split("\n").filter((l: string) => l.startsWith(" ") && l.includes("|"))
212
220
  console.log(`Memory: ${lines.length} entries`)
213
221
  } else {
214
222
  console.log("Memory: not initialized")
@@ -219,7 +227,7 @@ function status() {
219
227
  console.log("\nAgent configs:")
220
228
 
221
229
  for (const agent of agents) {
222
- const configs = [agent.global, agent.local].filter(Boolean)
230
+ const configs = [agent.global, agent.local].filter(Boolean) as string[]
223
231
  let found = false
224
232
 
225
233
  for (const configPath of configs) {
@@ -245,7 +253,7 @@ function status() {
245
253
  }
246
254
 
247
255
  // Upgrade to latest version
248
- function upgrade() {
256
+ function upgrade(): void {
249
257
  console.log("\n🧠 toon-memory upgrade\n")
250
258
 
251
259
  try {
@@ -256,10 +264,10 @@ function upgrade() {
256
264
  console.log("Upgrading...")
257
265
  execSync("npm install -g toon-memory@" + latest, { stdio: "inherit" })
258
266
 
259
- console.log("\n✅ Upgraded to toon-memory@" + latest)
267
+ console.log(`\n✅ Upgraded to toon-memory@${latest}`)
260
268
  console.log("Restart your agent to use the new version.\n")
261
269
  } catch (error) {
262
- console.error("Upgrade failed:", error.message)
270
+ console.error("Upgrade failed:", (error as Error).message)
263
271
  }
264
272
  }
265
273
 
@@ -290,11 +298,11 @@ const agents = detectAgents()
290
298
  console.log("\n🧠 toon-memory installer\n")
291
299
 
292
300
  console.log("Supported agents:")
293
- agents.forEach((a, i) => console.log(` ${i + 1}. ${a.name}`))
301
+ agents.forEach((a: Agent, i: number) => console.log(` ${i + 1}. ${a.name}`))
294
302
  console.log("")
295
303
 
296
304
  const rl = createInterface({ input: process.stdin, output: process.stdout })
297
- rl.question("Install (1) Local or (2) Global? [1/2]: ", (answer) => {
305
+ rl.question("Install (1) Local or (2) Global? [1/2]: ", (answer: string) => {
298
306
  const scope = answer === "2" ? "global" : "local"
299
307
  console.log(`\nInstalling ${scope}ly...\n`)
300
308
 
@@ -0,0 +1,14 @@
1
+ import { dirname, join } from "path"
2
+ import { fileURLToPath } from "url"
3
+ import { spawn } from "child_process"
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url))
6
+ const args = process.argv.slice(2)
7
+
8
+ const target = args[0] === "mcp"
9
+ ? join(__dirname, "..", "mcp", "server.js")
10
+ : join(__dirname, "..", "dist", "cli", "setup.js")
11
+
12
+ const extraArgs = args[0] === "mcp" ? [] : args
13
+ const child = spawn("node", [target, ...extraArgs], { stdio: "inherit" })
14
+ child.on("exit", (code) => process.exit(code ?? 0))