memax-cli 0.1.0-alpha.11 → 0.1.0-alpha.13
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/assets/memax-memory-skill.md +154 -0
- package/dist/commands/auth.d.ts +1 -0
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +9 -2
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/capture.d.ts +1 -1
- package/dist/commands/capture.d.ts.map +1 -1
- package/dist/commands/capture.js +3 -3
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/delete.js +5 -5
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/hub.d.ts +4 -0
- package/dist/commands/hub.d.ts.map +1 -0
- package/dist/commands/hub.js +52 -0
- package/dist/commands/hub.js.map +1 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +14 -14
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +22 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +37 -35
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/push.d.ts +1 -0
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +69 -6
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/recall.d.ts +1 -0
- package/dist/commands/recall.d.ts.map +1 -1
- package/dist/commands/recall.js +62 -24
- package/dist/commands/recall.js.map +1 -1
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +76 -4
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/show.js +9 -9
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/sync.js +3 -3
- package/dist/commands/sync.js.map +1 -1
- package/dist/index.js +23 -19
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +4 -3
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +83 -40
- package/dist/lib/api.js.map +1 -1
- package/package.json +6 -1
- package/.vscode/mcp.json +0 -8
- package/src/commands/auth.ts +0 -92
- package/src/commands/capture.ts +0 -86
- package/src/commands/config.ts +0 -27
- package/src/commands/delete.ts +0 -58
- package/src/commands/hook.ts +0 -243
- package/src/commands/list.ts +0 -92
- package/src/commands/login.ts +0 -164
- package/src/commands/mcp.ts +0 -528
- package/src/commands/push.ts +0 -137
- package/src/commands/recall.ts +0 -163
- package/src/commands/setup.ts +0 -1129
- package/src/commands/show.ts +0 -35
- package/src/commands/sync.ts +0 -506
- package/src/index.ts +0 -224
- package/src/lib/api.ts +0 -110
- package/src/lib/config.ts +0 -61
- package/src/lib/credentials.ts +0 -42
- package/tsconfig.json +0 -9
package/src/commands/show.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import { apiGet } from "../lib/api.js";
|
|
3
|
-
import type { Note } from "@memaxlabs/shared";
|
|
4
|
-
|
|
5
|
-
export async function showCommand(id: string): Promise<void> {
|
|
6
|
-
if (!id) {
|
|
7
|
-
console.error(chalk.red("Provide a note ID: memax show <id>"));
|
|
8
|
-
process.exit(1);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
const note = await apiGet<Note>(`/v1/notes/${id}`);
|
|
13
|
-
|
|
14
|
-
console.log(chalk.bold(note.title));
|
|
15
|
-
console.log(
|
|
16
|
-
chalk.gray(
|
|
17
|
-
`${note.category} · ${note.source} · v${note.version} · ${note.state}`,
|
|
18
|
-
),
|
|
19
|
-
);
|
|
20
|
-
if (note.tags?.length) {
|
|
21
|
-
console.log(chalk.gray(`tags: ${note.tags.join(", ")}`));
|
|
22
|
-
}
|
|
23
|
-
console.log(chalk.gray(`id: ${note.id}`));
|
|
24
|
-
console.log();
|
|
25
|
-
// API returns content inline; the shared Note type doesn't include it
|
|
26
|
-
// because production stores content in R2. Cast to access it.
|
|
27
|
-
const content = (note as Note & { content?: string }).content;
|
|
28
|
-
if (content) {
|
|
29
|
-
console.log(content);
|
|
30
|
-
}
|
|
31
|
-
} catch (err) {
|
|
32
|
-
console.error(chalk.red(`Show failed: ${(err as Error).message}`));
|
|
33
|
-
process.exit(1);
|
|
34
|
-
}
|
|
35
|
-
}
|
package/src/commands/sync.ts
DELETED
|
@@ -1,506 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import {
|
|
3
|
-
readFileSync,
|
|
4
|
-
readdirSync,
|
|
5
|
-
statSync,
|
|
6
|
-
watch,
|
|
7
|
-
existsSync,
|
|
8
|
-
} from "node:fs";
|
|
9
|
-
import { createInterface } from "node:readline";
|
|
10
|
-
import { join, relative, extname, resolve, basename } from "node:path";
|
|
11
|
-
import { homedir } from "node:os";
|
|
12
|
-
import { apiPost } from "../lib/api.js";
|
|
13
|
-
import type { Note } from "@memaxlabs/shared";
|
|
14
|
-
|
|
15
|
-
interface SyncOptions {
|
|
16
|
-
boundary?: string;
|
|
17
|
-
category?: string;
|
|
18
|
-
watch?: boolean;
|
|
19
|
-
ignore?: string;
|
|
20
|
-
agentMemory?: boolean;
|
|
21
|
-
yes?: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const DEFAULT_IGNORE = new Set([
|
|
25
|
-
"node_modules",
|
|
26
|
-
".git",
|
|
27
|
-
".next",
|
|
28
|
-
"dist",
|
|
29
|
-
"__pycache__",
|
|
30
|
-
".env",
|
|
31
|
-
".env.local",
|
|
32
|
-
".DS_Store",
|
|
33
|
-
]);
|
|
34
|
-
|
|
35
|
-
const SUPPORTED_EXTENSIONS = new Set([
|
|
36
|
-
".md",
|
|
37
|
-
".txt",
|
|
38
|
-
".ts",
|
|
39
|
-
".tsx",
|
|
40
|
-
".js",
|
|
41
|
-
".jsx",
|
|
42
|
-
".go",
|
|
43
|
-
".py",
|
|
44
|
-
".rs",
|
|
45
|
-
".yaml",
|
|
46
|
-
".yml",
|
|
47
|
-
".json",
|
|
48
|
-
".toml",
|
|
49
|
-
".sh",
|
|
50
|
-
".bash",
|
|
51
|
-
".zsh",
|
|
52
|
-
".css",
|
|
53
|
-
".html",
|
|
54
|
-
".sql",
|
|
55
|
-
".graphql",
|
|
56
|
-
".proto",
|
|
57
|
-
".dockerfile",
|
|
58
|
-
]);
|
|
59
|
-
|
|
60
|
-
export async function syncAgentMemoryCommand(): Promise<void> {
|
|
61
|
-
await syncAgentMemory();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export async function syncCommand(
|
|
65
|
-
directory: string | undefined,
|
|
66
|
-
options: SyncOptions,
|
|
67
|
-
): Promise<void> {
|
|
68
|
-
if (options.agentMemory || directory === "agents") {
|
|
69
|
-
await syncAgentMemory();
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const dir = directory ?? ".";
|
|
74
|
-
|
|
75
|
-
const customIgnore = options.ignore
|
|
76
|
-
? new Set(options.ignore.split(",").map((s) => s.trim()))
|
|
77
|
-
: new Set<string>();
|
|
78
|
-
const ignoreSet = new Set([...DEFAULT_IGNORE, ...customIgnore]);
|
|
79
|
-
|
|
80
|
-
console.log(chalk.blue("Scanning"), dir);
|
|
81
|
-
|
|
82
|
-
const files = walkDir(dir, ignoreSet);
|
|
83
|
-
|
|
84
|
-
if (files.length === 0) {
|
|
85
|
-
console.log(chalk.yellow("No supported files found."));
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
console.log(chalk.gray(`Found ${files.length} files to sync`));
|
|
90
|
-
|
|
91
|
-
// Confirm if many files (>10) unless -y is passed
|
|
92
|
-
if (files.length > 10 && !options.yes) {
|
|
93
|
-
console.log(
|
|
94
|
-
chalk.yellow(
|
|
95
|
-
`\n This will push ${files.length} files. Continue? (y/N) `,
|
|
96
|
-
),
|
|
97
|
-
);
|
|
98
|
-
const confirmed = await confirmSync();
|
|
99
|
-
if (!confirmed) {
|
|
100
|
-
console.log(chalk.gray(" Cancelled.\n"));
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
console.log();
|
|
106
|
-
|
|
107
|
-
let pushed = 0;
|
|
108
|
-
let errors = 0;
|
|
109
|
-
|
|
110
|
-
for (const file of files) {
|
|
111
|
-
const result = await pushFile(file, options);
|
|
112
|
-
if (result === "pushed") pushed++;
|
|
113
|
-
else if (result === "error") errors++;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
console.log();
|
|
117
|
-
console.log(
|
|
118
|
-
chalk.blue(`Synced ${pushed} files`),
|
|
119
|
-
errors > 0 ? chalk.red(`(${errors} errors)`) : "",
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
if (options.watch) {
|
|
123
|
-
const resolvedDir = resolve(dir);
|
|
124
|
-
console.log(
|
|
125
|
-
chalk.cyan(`\nWatching ${dir} for changes... (Ctrl+C to stop)`),
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
let debounceTimer: NodeJS.Timeout | null = null;
|
|
129
|
-
const pendingChanges = new Set<string>();
|
|
130
|
-
|
|
131
|
-
watch(resolvedDir, { recursive: true }, (_eventType, filename) => {
|
|
132
|
-
if (!filename) return;
|
|
133
|
-
const fullPath = join(resolvedDir, filename);
|
|
134
|
-
|
|
135
|
-
if (!isSupportedFile(filename) || isIgnored(filename, ignoreSet)) return;
|
|
136
|
-
|
|
137
|
-
pendingChanges.add(fullPath);
|
|
138
|
-
if (debounceTimer) clearTimeout(debounceTimer);
|
|
139
|
-
debounceTimer = setTimeout(async () => {
|
|
140
|
-
for (const file of pendingChanges) {
|
|
141
|
-
if (!existsSync(file)) {
|
|
142
|
-
console.log(
|
|
143
|
-
chalk.gray(" ~"),
|
|
144
|
-
relative(process.cwd(), file),
|
|
145
|
-
chalk.gray("[deleted, skipped]"),
|
|
146
|
-
);
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
await pushFile(file, options);
|
|
150
|
-
}
|
|
151
|
-
pendingChanges.clear();
|
|
152
|
-
}, 500);
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async function pushFile(
|
|
158
|
-
file: string,
|
|
159
|
-
options: SyncOptions,
|
|
160
|
-
): Promise<"pushed" | "skipped" | "error"> {
|
|
161
|
-
try {
|
|
162
|
-
const content = readFileSync(file, "utf-8");
|
|
163
|
-
if (!content.trim()) return "skipped";
|
|
164
|
-
|
|
165
|
-
const relPath = relative(process.cwd(), file);
|
|
166
|
-
const ext = extname(file);
|
|
167
|
-
const contentType =
|
|
168
|
-
ext === ".md"
|
|
169
|
-
? "markdown"
|
|
170
|
-
: ext === ".json" || ext === ".yaml" || ext === ".yml"
|
|
171
|
-
? "structured"
|
|
172
|
-
: "code";
|
|
173
|
-
|
|
174
|
-
const note = await apiPost<Note>("/v1/notes", {
|
|
175
|
-
content,
|
|
176
|
-
title: relPath,
|
|
177
|
-
category: options.category ?? guessCategory(relPath),
|
|
178
|
-
source: "sync",
|
|
179
|
-
source_path: relPath,
|
|
180
|
-
content_type: contentType,
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
console.log(chalk.green(" +"), relPath, chalk.gray(`[${note.category}]`));
|
|
184
|
-
return "pushed";
|
|
185
|
-
} catch (err) {
|
|
186
|
-
console.log(chalk.red(" x"), file, chalk.gray((err as Error).message));
|
|
187
|
-
return "error";
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function isSupportedFile(filename: string): boolean {
|
|
192
|
-
return SUPPORTED_EXTENSIONS.has(extname(filename));
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function isIgnored(filename: string, ignoreSet: Set<string>): boolean {
|
|
196
|
-
const parts = filename.split(/[/\\]/);
|
|
197
|
-
return parts.some((part) => ignoreSet.has(part) || part.startsWith("."));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function walkDir(dir: string, ignore: Set<string>): string[] {
|
|
201
|
-
const files: string[] = [];
|
|
202
|
-
|
|
203
|
-
function walk(currentDir: string): void {
|
|
204
|
-
let entries: string[];
|
|
205
|
-
try {
|
|
206
|
-
entries = readdirSync(currentDir);
|
|
207
|
-
} catch {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
for (const entry of entries) {
|
|
212
|
-
if (ignore.has(entry) || entry.startsWith(".")) continue;
|
|
213
|
-
|
|
214
|
-
const fullPath = join(currentDir, entry);
|
|
215
|
-
let stat;
|
|
216
|
-
try {
|
|
217
|
-
stat = statSync(fullPath);
|
|
218
|
-
} catch {
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (stat.isDirectory()) {
|
|
223
|
-
walk(fullPath);
|
|
224
|
-
} else if (stat.isFile() && SUPPORTED_EXTENSIONS.has(extname(entry))) {
|
|
225
|
-
files.push(fullPath);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
walk(dir);
|
|
231
|
-
return files;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function guessCategory(path: string): string {
|
|
235
|
-
const lower = path.toLowerCase();
|
|
236
|
-
if (lower.includes("adr") || lower.includes("decision"))
|
|
237
|
-
return "decisions/adr";
|
|
238
|
-
if (lower.includes("deploy") || lower.includes("ci")) return "process/deploy";
|
|
239
|
-
if (lower.includes("architecture") || lower.includes("design"))
|
|
240
|
-
return "core/architecture";
|
|
241
|
-
if (lower.includes("readme") || lower.includes("docs"))
|
|
242
|
-
return "reference/api";
|
|
243
|
-
if (lower.includes("test")) return "reference/api";
|
|
244
|
-
if (lower.includes("config") || lower.includes(".env"))
|
|
245
|
-
return "reference/config";
|
|
246
|
-
return "daily/note";
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// --- Agent memory sync ---
|
|
250
|
-
|
|
251
|
-
interface AgentMemoryLocation {
|
|
252
|
-
label: string;
|
|
253
|
-
path: string;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function discoverAgentMemoryFiles(): AgentMemoryLocation[] {
|
|
257
|
-
const home = homedir();
|
|
258
|
-
const cwd = process.cwd();
|
|
259
|
-
const locations: AgentMemoryLocation[] = [];
|
|
260
|
-
|
|
261
|
-
// Claude Code global memory
|
|
262
|
-
const claudeMemory = join(home, ".claude", "MEMORY.md");
|
|
263
|
-
locations.push({ label: "~/.claude/MEMORY.md", path: claudeMemory });
|
|
264
|
-
|
|
265
|
-
// Claude Code per-project memories: ~/.claude/projects/*/memory/*.md
|
|
266
|
-
const claudeProjectsDir = join(home, ".claude", "projects");
|
|
267
|
-
if (existsSync(claudeProjectsDir)) {
|
|
268
|
-
try {
|
|
269
|
-
for (const project of readdirSync(claudeProjectsDir)) {
|
|
270
|
-
const memoryDir = join(claudeProjectsDir, project, "memory");
|
|
271
|
-
if (existsSync(memoryDir)) {
|
|
272
|
-
try {
|
|
273
|
-
for (const file of readdirSync(memoryDir)) {
|
|
274
|
-
if (file.endsWith(".md")) {
|
|
275
|
-
locations.push({
|
|
276
|
-
label: `~/.claude/projects/${project}/memory/${file}`,
|
|
277
|
-
path: join(memoryDir, file),
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
} catch {
|
|
282
|
-
// Permission denied or other read error — skip
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
} catch {
|
|
287
|
-
// Permission denied or other read error — skip
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Cursor rules (project-level)
|
|
292
|
-
locations.push({ label: "./.cursorrules", path: join(cwd, ".cursorrules") });
|
|
293
|
-
|
|
294
|
-
// Cursor scoped rules: .cursor/rules/*.mdc
|
|
295
|
-
const cursorRulesDir = join(cwd, ".cursor", "rules");
|
|
296
|
-
if (existsSync(cursorRulesDir)) {
|
|
297
|
-
try {
|
|
298
|
-
for (const file of readdirSync(cursorRulesDir)) {
|
|
299
|
-
if (file.endsWith(".mdc")) {
|
|
300
|
-
locations.push({
|
|
301
|
-
label: `./.cursor/rules/${file}`,
|
|
302
|
-
path: join(cursorRulesDir, file),
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
} catch {
|
|
307
|
-
// Skip on error
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Codex instructions
|
|
312
|
-
locations.push({
|
|
313
|
-
label: "./.codex/instructions.md",
|
|
314
|
-
path: join(cwd, ".codex", "instructions.md"),
|
|
315
|
-
});
|
|
316
|
-
locations.push({
|
|
317
|
-
label: "~/.codex/AGENTS.md",
|
|
318
|
-
path: join(home, ".codex", "AGENTS.md"),
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
// Gemini CLI
|
|
322
|
-
locations.push({
|
|
323
|
-
label: "~/.gemini/GEMINI.md",
|
|
324
|
-
path: join(home, ".gemini", "GEMINI.md"),
|
|
325
|
-
});
|
|
326
|
-
locations.push({ label: "./GEMINI.md", path: join(cwd, "GEMINI.md") });
|
|
327
|
-
|
|
328
|
-
// GitHub Copilot
|
|
329
|
-
locations.push({
|
|
330
|
-
label: "./.github/copilot-instructions.md",
|
|
331
|
-
path: join(cwd, ".github", "copilot-instructions.md"),
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
// Windsurf
|
|
335
|
-
locations.push({
|
|
336
|
-
label: "./.windsurfrules",
|
|
337
|
-
path: join(cwd, ".windsurfrules"),
|
|
338
|
-
});
|
|
339
|
-
const windsurfRulesDir = join(cwd, ".windsurf", "rules");
|
|
340
|
-
if (existsSync(windsurfRulesDir)) {
|
|
341
|
-
try {
|
|
342
|
-
for (const file of readdirSync(windsurfRulesDir)) {
|
|
343
|
-
if (file.endsWith(".md")) {
|
|
344
|
-
locations.push({
|
|
345
|
-
label: `./.windsurf/rules/${file}`,
|
|
346
|
-
path: join(windsurfRulesDir, file),
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
} catch {
|
|
351
|
-
// Skip on error
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// OpenClaw memory
|
|
356
|
-
const openclawMemoryDir = join(home, ".openclaw", "memory");
|
|
357
|
-
if (existsSync(openclawMemoryDir)) {
|
|
358
|
-
try {
|
|
359
|
-
for (const file of readdirSync(openclawMemoryDir)) {
|
|
360
|
-
if (file.endsWith(".md") || file.endsWith(".json")) {
|
|
361
|
-
locations.push({
|
|
362
|
-
label: `~/.openclaw/memory/${file}`,
|
|
363
|
-
path: join(openclawMemoryDir, file),
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
} catch {
|
|
368
|
-
// Skip on error
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// OpenCode (anomalyco) context
|
|
373
|
-
const opencodePath = join(cwd, ".opencode");
|
|
374
|
-
if (existsSync(opencodePath)) {
|
|
375
|
-
// Check for any markdown context files in .opencode/
|
|
376
|
-
try {
|
|
377
|
-
for (const file of readdirSync(opencodePath)) {
|
|
378
|
-
if (file.endsWith(".md")) {
|
|
379
|
-
locations.push({
|
|
380
|
-
label: `./.opencode/${file}`,
|
|
381
|
-
path: join(opencodePath, file),
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
} catch {
|
|
386
|
-
// Skip on error
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Generic agent config files in current directory
|
|
391
|
-
locations.push({ label: "./AGENTS.md", path: join(cwd, "AGENTS.md") });
|
|
392
|
-
locations.push({ label: "./CLAUDE.md", path: join(cwd, "CLAUDE.md") });
|
|
393
|
-
|
|
394
|
-
return locations;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function formatFileSize(bytes: number): string {
|
|
398
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
399
|
-
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
async function syncAgentMemory(): Promise<void> {
|
|
403
|
-
console.log(chalk.blue("Scanning for agent memory files..."));
|
|
404
|
-
console.log();
|
|
405
|
-
|
|
406
|
-
const locations = discoverAgentMemoryFiles();
|
|
407
|
-
const found: { label: string; path: string; size: number }[] = [];
|
|
408
|
-
const notFound: string[] = [];
|
|
409
|
-
|
|
410
|
-
for (const loc of locations) {
|
|
411
|
-
if (existsSync(loc.path)) {
|
|
412
|
-
try {
|
|
413
|
-
const stat = statSync(loc.path);
|
|
414
|
-
if (stat.isFile() && stat.size > 0) {
|
|
415
|
-
found.push({ label: loc.label, path: loc.path, size: stat.size });
|
|
416
|
-
} else {
|
|
417
|
-
notFound.push(loc.label);
|
|
418
|
-
}
|
|
419
|
-
} catch {
|
|
420
|
-
notFound.push(loc.label);
|
|
421
|
-
}
|
|
422
|
-
} else {
|
|
423
|
-
notFound.push(loc.label);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (found.length === 0) {
|
|
428
|
-
console.log(chalk.yellow("No agent memory files found."));
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
console.log("Found:");
|
|
433
|
-
|
|
434
|
-
for (const f of found) {
|
|
435
|
-
console.log(
|
|
436
|
-
chalk.green(" \u2713"),
|
|
437
|
-
f.label,
|
|
438
|
-
chalk.gray(`(${formatFileSize(f.size)})`),
|
|
439
|
-
);
|
|
440
|
-
}
|
|
441
|
-
for (const label of notFound) {
|
|
442
|
-
console.log(
|
|
443
|
-
chalk.gray(" \u2717"),
|
|
444
|
-
chalk.gray(label),
|
|
445
|
-
chalk.gray("(not found)"),
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
console.log();
|
|
450
|
-
|
|
451
|
-
let synced = 0;
|
|
452
|
-
let unchanged = 0;
|
|
453
|
-
let errors = 0;
|
|
454
|
-
|
|
455
|
-
for (const f of found) {
|
|
456
|
-
try {
|
|
457
|
-
const content = readFileSync(f.path, "utf-8");
|
|
458
|
-
if (!content.trim()) continue;
|
|
459
|
-
|
|
460
|
-
const title = basename(f.path);
|
|
461
|
-
|
|
462
|
-
await apiPost<Note>("/v1/notes", {
|
|
463
|
-
content,
|
|
464
|
-
title,
|
|
465
|
-
source: "sync",
|
|
466
|
-
source_path: f.path,
|
|
467
|
-
content_type: "markdown",
|
|
468
|
-
category: "",
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
synced++;
|
|
472
|
-
} catch (err) {
|
|
473
|
-
const msg = (err as Error).message;
|
|
474
|
-
if (
|
|
475
|
-
msg.includes("unchanged") ||
|
|
476
|
-
msg.includes("duplicate") ||
|
|
477
|
-
msg.includes("exists")
|
|
478
|
-
) {
|
|
479
|
-
unchanged++;
|
|
480
|
-
} else {
|
|
481
|
-
errors++;
|
|
482
|
-
console.log(chalk.red(" Error syncing"), f.label, chalk.gray(msg));
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
console.log(
|
|
488
|
-
chalk.blue(`Synced ${found.length} files to Memax`),
|
|
489
|
-
chalk.gray(
|
|
490
|
-
`(${synced} new, ${unchanged} unchanged${errors > 0 ? `, ${errors} errors` : ""})`,
|
|
491
|
-
),
|
|
492
|
-
);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
function confirmSync(): Promise<boolean> {
|
|
496
|
-
return new Promise((resolve) => {
|
|
497
|
-
const rl = createInterface({
|
|
498
|
-
input: process.stdin,
|
|
499
|
-
output: process.stdout,
|
|
500
|
-
});
|
|
501
|
-
rl.question(" ", (answer) => {
|
|
502
|
-
rl.close();
|
|
503
|
-
resolve(answer.trim().toLowerCase() === "y");
|
|
504
|
-
});
|
|
505
|
-
});
|
|
506
|
-
}
|