claude-launchpad 0.16.0 → 1.0.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.
Files changed (45) hide show
  1. package/README.md +13 -4
  2. package/dist/{chunk-JQDMBE7W.js → chunk-3UJYOWGF.js} +18 -1
  3. package/dist/chunk-3UJYOWGF.js.map +1 -0
  4. package/dist/chunk-4JNFXVVC.js +1139 -0
  5. package/dist/chunk-4JNFXVVC.js.map +1 -0
  6. package/dist/{chunk-5MWCQLNL.js → chunk-AUV2JTXX.js} +3 -3
  7. package/dist/{chunk-Z6FBT44W.js → chunk-PGDSAUP4.js} +2 -2
  8. package/dist/{chunk-24VLPHJU.js → chunk-V4NXT4KB.js} +43 -16
  9. package/dist/chunk-V4NXT4KB.js.map +1 -0
  10. package/dist/{chunk-EDKY7JWY.js → chunk-ZXJK7CHB.js} +31 -4
  11. package/dist/chunk-ZXJK7CHB.js.map +1 -0
  12. package/dist/cli.js +156 -1065
  13. package/dist/cli.js.map +1 -1
  14. package/dist/commands/memory/server.js +9 -4
  15. package/dist/commands/memory/server.js.map +1 -1
  16. package/dist/{context-CWJUUTTU.js → context-Q5ZQBY7O.js} +6 -6
  17. package/dist/{install-MVATZUXZ.js → install-LS7DTMIE.js} +65 -63
  18. package/dist/install-LS7DTMIE.js.map +1 -0
  19. package/dist/{pull-YOESZ3UC.js → pull-4NRD4GQ4.js} +13 -9
  20. package/dist/pull-4NRD4GQ4.js.map +1 -0
  21. package/dist/{push-74XC5CUK.js → push-BHYEETGP.js} +9 -9
  22. package/dist/{require-deps-NKRCPVAO.js → require-deps-3GIE6TAG.js} +3 -3
  23. package/dist/{stats-QUBHHPV7.js → stats-NQ5NRUZC.js} +7 -7
  24. package/dist/sync-clean-QWEQVAYO.js +53 -0
  25. package/dist/sync-clean-QWEQVAYO.js.map +1 -0
  26. package/dist/sync-status-ZMXMEBGC.js +70 -0
  27. package/dist/sync-status-ZMXMEBGC.js.map +1 -0
  28. package/dist/{tui-XIYOOUP6.js → tui-YL5NWME5.js} +5 -5
  29. package/package.json +1 -1
  30. package/dist/chunk-24VLPHJU.js.map +0 -1
  31. package/dist/chunk-EDKY7JWY.js.map +0 -1
  32. package/dist/chunk-JQDMBE7W.js.map +0 -1
  33. package/dist/chunk-RJGXPH7P.js +0 -107
  34. package/dist/chunk-RJGXPH7P.js.map +0 -1
  35. package/dist/chunk-SBA5KYQU.js +0 -76
  36. package/dist/chunk-SBA5KYQU.js.map +0 -1
  37. package/dist/install-MVATZUXZ.js.map +0 -1
  38. package/dist/pull-YOESZ3UC.js.map +0 -1
  39. /package/dist/{chunk-5MWCQLNL.js.map → chunk-AUV2JTXX.js.map} +0 -0
  40. /package/dist/{chunk-Z6FBT44W.js.map → chunk-PGDSAUP4.js.map} +0 -0
  41. /package/dist/{context-CWJUUTTU.js.map → context-Q5ZQBY7O.js.map} +0 -0
  42. /package/dist/{push-74XC5CUK.js.map → push-BHYEETGP.js.map} +0 -0
  43. /package/dist/{require-deps-NKRCPVAO.js.map → require-deps-3GIE6TAG.js.map} +0 -0
  44. /package/dist/{stats-QUBHHPV7.js.map → stats-NQ5NRUZC.js.map} +0 -0
  45. /package/dist/{tui-XIYOOUP6.js.map → tui-YL5NWME5.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/subcommands/install.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { createDatabase, closeDatabase } from '../storage/database.js';\nimport { migrate } from '../storage/migrator.js';\nimport { loadConfig, resolveDataDir } from '../config.js';\nimport { readSettingsJson, writeSettingsJson, readSettingsLocalJson, writeSettingsLocalJson } from '../../../lib/settings.js';\nimport { getMemoryPlacement } from '../../../lib/memory-placement.js';\nimport { log } from '../../../lib/output.js';\nimport type { MemoryPlacement } from '../../../types/index.js';\n\nfunction isGhAuthenticated(): boolean {\n try {\n execSync('gh auth status', { stdio: 'pipe', timeout: 5000 });\n return true;\n } catch {\n return false;\n }\n}\n\ninterface InstallOpts {\n readonly dbPath?: string;\n}\n\nexport async function runInstall(opts: InstallOpts): Promise<void> {\n log.blank();\n log.step('Setting up your knowledge base');\n log.blank();\n\n // Step 0: Ensure native deps are installed globally\n await ensureNativeDeps();\n\n // Prompt for placement before any config writes\n const placement = await getMemoryPlacement(process.cwd());\n\n const config = loadConfig(opts.dbPath ? { dataDir: opts.dbPath } : undefined);\n const dataDir = resolveDataDir(config.dataDir);\n\n // Step 1: Database\n log.step('[1/5] Creating knowledge base...');\n if (!existsSync(dataDir)) {\n mkdirSync(dataDir, { recursive: true });\n }\n const db = createDatabase({ dataDir });\n migrate(db);\n closeDatabase(db);\n log.success(`Knowledge base created at ${dataDir}/memory.db`);\n\n // Step 2: Configure Claude Code settings\n log.step('[2/5] Connecting to Claude Code...');\n await configureSettings(process.cwd(), placement);\n\n // Step 3: Register MCP server (project scope for shared, local scope for local)\n log.step('[3/5] Enabling memory tools...');\n const mcpScope = placement === \"local\" ? \"local\" : \"project\";\n const registered = registerMcpServer(mcpScope);\n if (registered) {\n log.success('Memory tools available in Claude Code');\n } else {\n log.warn('Could not enable memory tools automatically.');\n log.info(`Run: claude mcp add --scope ${mcpScope} agentic-memory -- npx claude-launchpad memory serve`);\n }\n\n // Step 4: CLAUDE.md + skills\n log.step('[4/5] Adding instructions...');\n const guidanceAdded = injectClaudeMdGuidance(process.cwd(), placement);\n if (guidanceAdded) {\n const label = placement === \"local\" ? \".claude/CLAUDE.md\" : \"CLAUDE.md\";\n log.success(`${label} updated with memory instructions`);\n }\n if (placement === \"shared\") {\n const skillsInstalled = installSkills(process.cwd());\n if (skillsInstalled > 0) {\n log.success(`Installed ${skillsInstalled} skill(s) to .claude/skills/`);\n }\n }\n\n log.blank();\n log.success('Knowledge base is ready. Claude will now remember across sessions.');\n log.info('Restart your Claude Code session to activate.');\n\n // Sync guidance\n if (isGhAuthenticated()) {\n log.info('Cross-device sync available. Run `memory push` to back up, or it auto-syncs each session.');\n } else {\n log.blank();\n log.info('Recommended: install the GitHub CLI for cross-device memory sync:');\n log.step(' https://cli.github.com/');\n log.step(' gh auth login');\n }\n log.blank();\n}\n\nexport function detectExistingSetup(projectDir: string): MemoryPlacement | null {\n // Check local CLAUDE.md\n try {\n const localClaude = readFileSync(join(projectDir, '.claude', 'CLAUDE.md'), 'utf-8');\n if (localClaude.includes('## Memory') || localClaude.includes('agentic-memory')) return \"local\";\n } catch { /* not found */ }\n\n // Check root CLAUDE.md\n try {\n const rootClaude = readFileSync(join(projectDir, 'CLAUDE.md'), 'utf-8');\n if (rootClaude.includes('## Memory (agentic-memory)')) return \"shared\";\n } catch { /* not found */ }\n\n return null;\n}\n\nasync function configureSettings(projectDir: string, placement: MemoryPlacement): Promise<void> {\n const read = placement === \"local\" ? readSettingsLocalJson : readSettingsJson;\n const write = placement === \"local\" ? writeSettingsLocalJson : writeSettingsJson;\n const settings = await read(projectDir);\n\n // Disable built-in auto-memory\n log.info('Built-in auto-memory disabled (replaced by knowledge base)');\n\n // Build hooks immutably — always add sync hooks (they fail silently without gh)\n const baseHooks = (settings['hooks'] ?? {}) as Record<string, unknown[]>;\n const withPull = addSessionStartPullHook(baseHooks);\n const withContext = addSessionStartHook(withPull);\n const withPush = addSessionEndPushHook(withContext);\n\n // Build permissions immutably\n const withPermissions = addToolPermissions(settings);\n\n const updated = {\n ...withPermissions,\n autoMemoryEnabled: false,\n hooks: withPush,\n };\n\n await write(projectDir, updated);\n const target = placement === \"local\" ? \"settings.local.json\" : \"settings.json\";\n log.success(`Claude Code configured in ${target}`);\n}\n\nfunction addSessionStartPullHook(hooks: Record<string, unknown[]>): Record<string, unknown[]> {\n const sessionStartHooks = (hooks['SessionStart'] ?? []) as Record<string, unknown>[];\n const alreadyHooked = sessionStartHooks.some((h) => {\n const innerHooks = h['hooks'] as Record<string, unknown>[] | undefined;\n return innerHooks?.some(\n ih => typeof ih['command'] === 'string' && (ih['command'] as string).includes('memory pull'),\n );\n });\n\n if (alreadyHooked) return hooks;\n\n // Insert at the beginning so pull runs before context injection\n const entry = {\n matcher: 'startup',\n hooks: [{ type: 'command', command: 'claude-launchpad memory pull -y 2>/dev/null; exit 0' }],\n };\n log.info('Session start: memories will auto-pull from GitHub Gist');\n return { ...hooks, SessionStart: [entry, ...sessionStartHooks] };\n}\n\nfunction addSessionStartHook(hooks: Record<string, unknown[]>): Record<string, unknown[]> {\n const sessionStartHooks = (hooks['SessionStart'] ?? []) as Record<string, unknown>[];\n const hookCommand = 'npx claude-launchpad memory context --json 2>/dev/null; exit 0';\n\n const alreadyHooked = sessionStartHooks.some((h) => {\n const innerHooks = h['hooks'] as Record<string, unknown>[] | undefined;\n return innerHooks?.some(\n ih => typeof ih['command'] === 'string' && (ih['command'] as string).includes('claude-launchpad memory context'),\n );\n });\n\n if (alreadyHooked) return hooks;\n\n const entry = {\n matcher: 'startup|resume',\n hooks: [{ type: 'command', command: hookCommand }],\n };\n log.info('Session start: Claude will recall relevant context automatically');\n return { ...hooks, SessionStart: [...sessionStartHooks, entry] };\n}\n\nfunction addSessionEndPushHook(hooks: Record<string, unknown[]>): Record<string, unknown[]> {\n const sessionEndHooks = (hooks['SessionEnd'] ?? []) as Record<string, unknown>[];\n const alreadyHooked = sessionEndHooks.some((h) => {\n const innerHooks = h['hooks'] as Record<string, unknown>[] | undefined;\n return innerHooks?.some(\n ih => typeof ih['command'] === 'string' && (ih['command'] as string).includes('memory push'),\n );\n });\n\n if (alreadyHooked) return hooks;\n\n const entry = {\n hooks: [{ type: 'command', command: 'claude-launchpad memory push -y >/dev/null 2>&1 & exit 0' }],\n };\n log.info('Session end: memories will auto-push to GitHub Gist');\n return { ...hooks, SessionEnd: [...sessionEndHooks, entry] };\n}\n\nfunction addToolPermissions(settings: Record<string, unknown>): Record<string, unknown> {\n const permissions = (settings['permissions'] ?? {}) as Record<string, unknown>;\n const allowList = (permissions['allow'] ?? []) as readonly string[];\n\n const memoryTools = [\n 'mcp__agentic-memory__memory_store',\n 'mcp__agentic-memory__memory_search',\n 'mcp__agentic-memory__memory_recent',\n 'mcp__agentic-memory__memory_forget',\n 'mcp__agentic-memory__memory_relate',\n 'mcp__agentic-memory__memory_stats',\n 'mcp__agentic-memory__memory_update',\n ];\n\n const missing = memoryTools.filter((t) => !allowList.includes(t));\n if (missing.length === 0) return settings;\n\n log.info(`${missing.length} memory tools auto-approved`);\n return {\n ...settings,\n permissions: { ...permissions, allow: [...allowList, ...missing] },\n };\n}\n\nasync function ensureNativeDeps(): Promise<void> {\n const { cwdRequire } = await import('../utils/require-deps.js');\n try {\n cwdRequire('better-sqlite3');\n return;\n } catch {\n // Not installed — install globally\n }\n\n log.step('Installing required database libraries...');\n try {\n execSync('npm install -g better-sqlite3 sqlite-vec', { stdio: 'pipe', timeout: 120000 });\n log.success('Database libraries installed');\n } catch {\n log.error('Could not install database libraries automatically.');\n log.blank();\n log.info('Install manually:');\n log.step(' npm install -g better-sqlite3 sqlite-vec');\n log.blank();\n log.info('Requires a C++ compiler (Xcode on macOS, build-essential on Linux).');\n process.exit(1);\n }\n}\n\nfunction registerMcpServer(scope: \"project\" | \"local\"): boolean {\n try {\n const existing = execSync('claude mcp list', { stdio: 'pipe', timeout: 10000, encoding: 'utf-8' });\n if (existing.includes('agentic-memory')) {\n log.info('Memory tools already registered');\n return true;\n }\n execSync(\n `claude mcp add --scope ${scope} agentic-memory -- npx claude-launchpad memory serve`,\n { stdio: 'pipe', timeout: 10000 },\n );\n return true;\n } catch {\n return false;\n }\n}\n\nconst MEMORY_GUIDANCE = `\n## Memory (agentic-memory)\nThis project uses **agentic-memory** for persistent memory across sessions.\n- **DO NOT** use the built-in auto-memory system (~/.claude/projects/*/memory/)\n- Memory context is **automatically injected** at session start via SessionStart hook - no need to call memory_recent manually\n- Use \\`memory_search\\` to find specific memories by keyword\n- Use \\`memory_store\\` to save decisions, gotchas, and learnings worth remembering\n- Use \\`memory_stats\\` to check memory health\n- **STORE IMMEDIATELY** when: a dependency strategy changes, an architecture decision is made, a convention is established, a bug pattern is discovered, or a feature is killed/added\n`;\n\nfunction injectClaudeMdGuidance(projectDir: string, placement: MemoryPlacement): boolean {\n const claudeMdPath = placement === \"local\"\n ? join(projectDir, '.claude', 'CLAUDE.md')\n : join(projectDir, 'CLAUDE.md');\n\n let content = '';\n try {\n content = readFileSync(claudeMdPath, 'utf-8');\n } catch {\n if (placement !== \"local\") return false;\n // Create local .claude/CLAUDE.md\n mkdirSync(join(projectDir, '.claude'), { recursive: true });\n content = '# Local Claude Config\\n';\n }\n\n if (content.includes('## Memory (agentic-memory)')) {\n return false;\n }\n\n const updated = content.trimEnd() + '\\n' + MEMORY_GUIDANCE;\n writeFileSync(claudeMdPath, updated, 'utf-8');\n return true;\n}\n\nconst MIGRATE_MEMORY_SKILL = `---\nname: lp-migrate-memory\ndescription: Migrate legacy Claude Code auto-memory files (~/.claude/projects/*/memory/*.md) into agentic-memory. Use when setting up agentic-memory on a project that already has built-in memories.\nallowed-tools: Read, Glob, Grep, mcp__agentic-memory__memory_store, mcp__agentic-memory__memory_search\n---\n\n# Migrate Legacy Claude Code Memories\n\nMigrate memory files from Claude Code's built-in auto-memory system into agentic-memory.\n\n## Steps\n\n1. **Find legacy memory files** for this project:\n - Scan \\`~/.claude/projects/*/memory/*.md\\` for directories whose slug matches the current project path\n - The slug format is the absolute path with \\`/\\` replaced by \\`-\\` and leading \\`-\\` (e.g. \\`-Users-john-projects-myapp\\`)\n - Also check \\`~/.claude/projects/*/memory/team/*.md\\` for team memories\n\n2. **For each memory file found**, read it and parse:\n - YAML frontmatter: \\`name\\`, \\`description\\`, \\`type\\` (user/feedback/project/reference)\n - Body content (everything after the frontmatter closing \\`---\\`)\n - Skip \\`MEMORY.md\\` (it's just an index file, not a memory)\n\n3. **Before storing**, check for duplicates:\n - Call \\`memory_search\\` with the memory description or first 100 chars of content\n - If a close match exists (same topic), skip it and report\n\n4. **Map types and store** each memory via \\`memory_store\\`:\n - \\`user\\` -> type: \\`semantic\\`, tags: [\\`user\\`, \\`migrated\\`], importance: 0.7\n - \\`feedback\\` -> type: \\`semantic\\`, tags: [\\`feedback\\`, \\`migrated\\`], importance: 0.8\n - \\`project\\` -> type: \\`semantic\\`, tags: [\\`project\\`, \\`migrated\\`], importance: 0.6\n - \\`reference\\` -> type: \\`semantic\\`, tags: [\\`reference\\`, \\`migrated\\`], importance: 0.5\n - Use the frontmatter \\`name\\` as the title\n - Use the body content as the memory content\n - Set source: \\`import\\`\n - Adjust importance up/down based on the content (decisions and gotchas deserve higher importance)\n\n5. **Report results**: list what was migrated, what was skipped (duplicates), and what failed\n\n## Important\n\n- Do NOT delete the original files - the user can do that manually after verifying\n- Do NOT migrate content that is purely derived from code (architecture, file structure) - it belongs in CLAUDE.md, not memory\n- If unsure about a memory's value, migrate it anyway - the decay system will naturally prune low-value memories over time\n`;\n\nconst SKILLS: Readonly<Record<string, string>> = {\n 'lp-migrate-memory': MIGRATE_MEMORY_SKILL,\n};\n\nfunction installSkills(projectDir: string): number {\n const skillsDir = join(projectDir, '.claude', 'skills');\n let installed = 0;\n\n for (const [name, content] of Object.entries(SKILLS)) {\n const skillDir = join(skillsDir, name);\n const skillPath = join(skillDir, 'SKILL.md');\n\n if (existsSync(skillPath)) continue;\n\n mkdirSync(skillDir, { recursive: true });\n writeFileSync(skillPath, content.trimStart(), 'utf-8');\n installed++;\n }\n\n return installed;\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,6 @@ import {
3
3
  mergeFromRemote,
4
4
  parsePayload
5
5
  } from "./chunk-TSTTFR4B.js";
6
- import "./chunk-GRL3DOCP.js";
7
6
  import {
8
7
  assertGhAvailable,
9
8
  filenameToProject,
@@ -11,19 +10,20 @@ import {
11
10
  loadSyncConfig,
12
11
  projectToFilename,
13
12
  readGistFile
14
- } from "./chunk-JQDMBE7W.js";
13
+ } from "./chunk-3UJYOWGF.js";
14
+ import "./chunk-GRL3DOCP.js";
15
15
  import {
16
16
  detectProject
17
17
  } from "./chunk-NAW47BYA.js";
18
18
  import {
19
19
  initStorage
20
- } from "./chunk-5MWCQLNL.js";
21
- import "./chunk-24VLPHJU.js";
22
- import "./chunk-EDKY7JWY.js";
23
- import "./chunk-Z6FBT44W.js";
20
+ } from "./chunk-AUV2JTXX.js";
21
+ import "./chunk-V4NXT4KB.js";
22
+ import "./chunk-ZXJK7CHB.js";
23
+ import "./chunk-PGDSAUP4.js";
24
24
  import {
25
25
  log
26
- } from "./chunk-RJGXPH7P.js";
26
+ } from "./chunk-4JNFXVVC.js";
27
27
 
28
28
  // src/commands/memory/subcommands/pull.ts
29
29
  async function runPull(opts) {
@@ -33,7 +33,7 @@ async function runPull(opts) {
33
33
  log.error("No sync gist found. Run `memory push` first.");
34
34
  return;
35
35
  }
36
- const { requireMemoryDeps } = await import("./require-deps-NKRCPVAO.js");
36
+ const { requireMemoryDeps } = await import("./require-deps-3GIE6TAG.js");
37
37
  await requireMemoryDeps();
38
38
  const ctx = initStorage();
39
39
  try {
@@ -58,6 +58,10 @@ function pullProject(ctx, gistId) {
58
58
  log.error(`No memories found for project "${project}" in gist.`);
59
59
  return;
60
60
  }
61
+ const localCount = ctx.memoryRepo.count(project);
62
+ if (localCount === 0) {
63
+ log.warn(`No local memories for "${project}" \u2014 creating fresh database from remote.`);
64
+ }
61
65
  const result = mergeFromRemote(ctx.memoryRepo, ctx.relationRepo, payload);
62
66
  printResult(result, project);
63
67
  }
@@ -108,4 +112,4 @@ function printResult(result, project) {
108
112
  export {
109
113
  runPull
110
114
  };
111
- //# sourceMappingURL=pull-YOESZ3UC.js.map
115
+ //# sourceMappingURL=pull-4NRD4GQ4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/subcommands/pull.ts"],"sourcesContent":["import { log } from '../../../lib/output.js';\nimport { initStorage } from './init-storage.js';\nimport {\n assertGhAvailable,\n loadSyncConfig,\n readGistFile,\n listGistFiles,\n filenameToProject,\n projectToFilename,\n} from '../utils/gist-transport.js';\nimport { mergeFromRemote, parsePayload } from '../utils/sync-merge.js';\nimport type { SyncPayload, MergeResult } from '../types.js';\nimport { detectProject } from '../utils/project.js';\n\ninterface PullOpts {\n readonly all?: boolean;\n}\n\nexport async function runPull(opts: PullOpts): Promise<void> {\n assertGhAvailable();\n\n const syncConfig = loadSyncConfig();\n if (!syncConfig) {\n log.error('No sync gist found. Run `memory push` first.');\n return;\n }\n\n const { requireMemoryDeps } = await import('../utils/require-deps.js');\n await requireMemoryDeps();\n const ctx = initStorage();\n\n try {\n if (opts.all) {\n pullAll(ctx, syncConfig.gistId);\n } else {\n pullProject(ctx, syncConfig.gistId);\n }\n } finally {\n ctx.close();\n }\n}\n\nfunction pullProject(ctx: ReturnType<typeof initStorage>, gistId: string): void {\n const project = detectProject(process.cwd());\n if (!project) {\n log.error('Could not detect project. Run from a project directory or use --all.');\n return;\n }\n\n const filename = projectToFilename(project);\n const payload = parsePayload(readGistFile(gistId, filename));\n if (!payload) {\n log.error(`No memories found for project \"${project}\" in gist.`);\n return;\n }\n\n const localCount = ctx.memoryRepo.count(project);\n if (localCount === 0) {\n log.warn(`No local memories for \"${project}\" — creating fresh database from remote.`);\n }\n\n const result = mergeFromRemote(ctx.memoryRepo, ctx.relationRepo, payload);\n printResult(result, project);\n}\n\nfunction pullAll(ctx: ReturnType<typeof initStorage>, gistId: string): void {\n const files = listGistFiles(gistId);\n const projectFiles = files.filter((f) => filenameToProject(f) !== null);\n\n if (projectFiles.length === 0) {\n log.error('No memory files found in gist.');\n return;\n }\n\n let totalInserted = 0;\n let totalUpdated = 0;\n let totalRelations = 0;\n\n for (const filename of projectFiles) {\n const payload = parsePayload(readGistFile(gistId, filename));\n if (!payload) continue;\n const result = mergeFromRemote(ctx.memoryRepo, ctx.relationRepo, payload);\n totalInserted += result.inserted;\n totalUpdated += result.updated;\n totalRelations += result.relationsAdded;\n }\n\n log.blank();\n if (totalInserted === 0 && totalUpdated === 0 && totalRelations === 0) {\n log.step('Already in sync');\n } else {\n log.step('Pull complete');\n if (totalInserted > 0) log.info(`Inserted: ${totalInserted}`);\n if (totalUpdated > 0) log.info(`Updated: ${totalUpdated}`);\n if (totalRelations > 0) log.info(`Relations: ${totalRelations} added`);\n }\n log.info(`Projects: ${projectFiles.length}`);\n log.blank();\n}\n\nfunction printResult(result: MergeResult, project: string): void {\n log.blank();\n if (result.inserted === 0 && result.updated === 0 && result.relationsAdded === 0) {\n log.step('Already in sync');\n log.info(`Project: ${project}`);\n } else {\n log.step('Pull complete');\n log.info(`Project: ${project}`);\n if (result.inserted > 0) log.info(`Inserted: ${result.inserted}`);\n if (result.updated > 0) log.info(`Updated: ${result.updated}`);\n if (result.relationsAdded > 0) log.info(`Relations: ${result.relationsAdded} added`);\n }\n log.blank();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,eAAsB,QAAQ,MAA+B;AAC3D,oBAAkB;AAElB,QAAM,aAAa,eAAe;AAClC,MAAI,CAAC,YAAY;AACf,QAAI,MAAM,8CAA8C;AACxD;AAAA,EACF;AAEA,QAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,4BAA0B;AACrE,QAAM,kBAAkB;AACxB,QAAM,MAAM,YAAY;AAExB,MAAI;AACF,QAAI,KAAK,KAAK;AACZ,cAAQ,KAAK,WAAW,MAAM;AAAA,IAChC,OAAO;AACL,kBAAY,KAAK,WAAW,MAAM;AAAA,IACpC;AAAA,EACF,UAAE;AACA,QAAI,MAAM;AAAA,EACZ;AACF;AAEA,SAAS,YAAY,KAAqC,QAAsB;AAC9E,QAAM,UAAU,cAAc,QAAQ,IAAI,CAAC;AAC3C,MAAI,CAAC,SAAS;AACZ,QAAI,MAAM,sEAAsE;AAChF;AAAA,EACF;AAEA,QAAM,WAAW,kBAAkB,OAAO;AAC1C,QAAM,UAAU,aAAa,aAAa,QAAQ,QAAQ,CAAC;AAC3D,MAAI,CAAC,SAAS;AACZ,QAAI,MAAM,kCAAkC,OAAO,YAAY;AAC/D;AAAA,EACF;AAEA,QAAM,aAAa,IAAI,WAAW,MAAM,OAAO;AAC/C,MAAI,eAAe,GAAG;AACpB,QAAI,KAAK,0BAA0B,OAAO,+CAA0C;AAAA,EACtF;AAEA,QAAM,SAAS,gBAAgB,IAAI,YAAY,IAAI,cAAc,OAAO;AACxE,cAAY,QAAQ,OAAO;AAC7B;AAEA,SAAS,QAAQ,KAAqC,QAAsB;AAC1E,QAAM,QAAQ,cAAc,MAAM;AAClC,QAAM,eAAe,MAAM,OAAO,CAAC,MAAM,kBAAkB,CAAC,MAAM,IAAI;AAEtE,MAAI,aAAa,WAAW,GAAG;AAC7B,QAAI,MAAM,gCAAgC;AAC1C;AAAA,EACF;AAEA,MAAI,gBAAgB;AACpB,MAAI,eAAe;AACnB,MAAI,iBAAiB;AAErB,aAAW,YAAY,cAAc;AACnC,UAAM,UAAU,aAAa,aAAa,QAAQ,QAAQ,CAAC;AAC3D,QAAI,CAAC,QAAS;AACd,UAAM,SAAS,gBAAgB,IAAI,YAAY,IAAI,cAAc,OAAO;AACxE,qBAAiB,OAAO;AACxB,oBAAgB,OAAO;AACvB,sBAAkB,OAAO;AAAA,EAC3B;AAEA,MAAI,MAAM;AACV,MAAI,kBAAkB,KAAK,iBAAiB,KAAK,mBAAmB,GAAG;AACrE,QAAI,KAAK,iBAAiB;AAAA,EAC5B,OAAO;AACL,QAAI,KAAK,eAAe;AACxB,QAAI,gBAAgB,EAAG,KAAI,KAAK,cAAc,aAAa,EAAE;AAC7D,QAAI,eAAe,EAAG,KAAI,KAAK,cAAc,YAAY,EAAE;AAC3D,QAAI,iBAAiB,EAAG,KAAI,KAAK,cAAc,cAAc,QAAQ;AAAA,EACvE;AACA,MAAI,KAAK,cAAc,aAAa,MAAM,EAAE;AAC5C,MAAI,MAAM;AACZ;AAEA,SAAS,YAAY,QAAqB,SAAuB;AAC/D,MAAI,MAAM;AACV,MAAI,OAAO,aAAa,KAAK,OAAO,YAAY,KAAK,OAAO,mBAAmB,GAAG;AAChF,QAAI,KAAK,iBAAiB;AAC1B,QAAI,KAAK,YAAY,OAAO,EAAE;AAAA,EAChC,OAAO;AACL,QAAI,KAAK,eAAe;AACxB,QAAI,KAAK,cAAc,OAAO,EAAE;AAChC,QAAI,OAAO,WAAW,EAAG,KAAI,KAAK,cAAc,OAAO,QAAQ,EAAE;AACjE,QAAI,OAAO,UAAU,EAAG,KAAI,KAAK,cAAc,OAAO,OAAO,EAAE;AAC/D,QAAI,OAAO,iBAAiB,EAAG,KAAI,KAAK,cAAc,OAAO,cAAc,QAAQ;AAAA,EACrF;AACA,MAAI,MAAM;AACZ;","names":[]}
@@ -4,7 +4,6 @@ import {
4
4
  mergeFromRemote,
5
5
  parsePayload
6
6
  } from "./chunk-TSTTFR4B.js";
7
- import "./chunk-GRL3DOCP.js";
8
7
  import {
9
8
  assertGhAvailable,
10
9
  createGist,
@@ -12,19 +11,20 @@ import {
12
11
  projectToFilename,
13
12
  readGistFile,
14
13
  updateGistFiles
15
- } from "./chunk-JQDMBE7W.js";
14
+ } from "./chunk-3UJYOWGF.js";
15
+ import "./chunk-GRL3DOCP.js";
16
16
  import {
17
17
  detectProject
18
18
  } from "./chunk-NAW47BYA.js";
19
19
  import {
20
20
  initStorage
21
- } from "./chunk-5MWCQLNL.js";
22
- import "./chunk-24VLPHJU.js";
23
- import "./chunk-EDKY7JWY.js";
24
- import "./chunk-Z6FBT44W.js";
21
+ } from "./chunk-AUV2JTXX.js";
22
+ import "./chunk-V4NXT4KB.js";
23
+ import "./chunk-ZXJK7CHB.js";
24
+ import "./chunk-PGDSAUP4.js";
25
25
  import {
26
26
  log
27
- } from "./chunk-RJGXPH7P.js";
27
+ } from "./chunk-4JNFXVVC.js";
28
28
 
29
29
  // src/commands/memory/subcommands/push.ts
30
30
  import { hostname } from "os";
@@ -48,7 +48,7 @@ function filterRelations(allRelations, memoryIds) {
48
48
  }
49
49
  async function runPush(opts) {
50
50
  assertGhAvailable();
51
- const { requireMemoryDeps } = await import("./require-deps-NKRCPVAO.js");
51
+ const { requireMemoryDeps } = await import("./require-deps-3GIE6TAG.js");
52
52
  await requireMemoryDeps();
53
53
  const ctx = initStorage();
54
54
  try {
@@ -148,4 +148,4 @@ async function confirmCreate() {
148
148
  export {
149
149
  runPush
150
150
  };
151
- //# sourceMappingURL=push-74XC5CUK.js.map
151
+ //# sourceMappingURL=push-BHYEETGP.js.map
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  cwdRequire,
4
4
  requireMemoryDeps
5
- } from "./chunk-Z6FBT44W.js";
6
- import "./chunk-RJGXPH7P.js";
5
+ } from "./chunk-PGDSAUP4.js";
6
+ import "./chunk-4JNFXVVC.js";
7
7
  export {
8
8
  cwdRequire,
9
9
  requireMemoryDeps
10
10
  };
11
- //# sourceMappingURL=require-deps-NKRCPVAO.js.map
11
+ //# sourceMappingURL=require-deps-3GIE6TAG.js.map
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  initStorage
4
- } from "./chunk-5MWCQLNL.js";
5
- import "./chunk-24VLPHJU.js";
6
- import "./chunk-EDKY7JWY.js";
7
- import "./chunk-Z6FBT44W.js";
4
+ } from "./chunk-AUV2JTXX.js";
5
+ import "./chunk-V4NXT4KB.js";
6
+ import "./chunk-ZXJK7CHB.js";
7
+ import "./chunk-PGDSAUP4.js";
8
8
  import {
9
9
  log
10
- } from "./chunk-RJGXPH7P.js";
10
+ } from "./chunk-4JNFXVVC.js";
11
11
 
12
12
  // src/commands/memory/subcommands/stats.ts
13
13
  import { existsSync, statSync } from "fs";
@@ -18,7 +18,7 @@ function formatBytes(bytes) {
18
18
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
19
19
  }
20
20
  async function runStats(opts) {
21
- const { requireMemoryDeps } = await import("./require-deps-NKRCPVAO.js");
21
+ const { requireMemoryDeps } = await import("./require-deps-3GIE6TAG.js");
22
22
  await requireMemoryDeps();
23
23
  const ctx = initStorage(opts.dbPath);
24
24
  try {
@@ -72,4 +72,4 @@ async function runStats(opts) {
72
72
  export {
73
73
  runStats
74
74
  };
75
- //# sourceMappingURL=stats-QUBHHPV7.js.map
75
+ //# sourceMappingURL=stats-NQ5NRUZC.js.map
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ assertGhAvailable,
4
+ deleteGistFile,
5
+ filenameToProject,
6
+ listGistFiles,
7
+ loadSyncConfig,
8
+ projectToFilename
9
+ } from "./chunk-3UJYOWGF.js";
10
+ import {
11
+ log
12
+ } from "./chunk-4JNFXVVC.js";
13
+
14
+ // src/commands/memory/subcommands/sync-clean.ts
15
+ import { confirm } from "@inquirer/prompts";
16
+ async function runSyncClean(project, opts) {
17
+ assertGhAvailable();
18
+ const syncConfig = loadSyncConfig();
19
+ if (!syncConfig) {
20
+ log.error("No sync gist found. Run `memory push` first.");
21
+ return;
22
+ }
23
+ const filename = projectToFilename(project);
24
+ const files = listGistFiles(syncConfig.gistId);
25
+ const projectFiles = files.filter((f) => filenameToProject(f) !== null);
26
+ if (!projectFiles.includes(filename)) {
27
+ log.error(`Project "${project}" not found in gist.`);
28
+ if (projectFiles.length > 0) {
29
+ log.blank();
30
+ log.info("Available projects:");
31
+ for (const f of projectFiles) {
32
+ log.info(` ${filenameToProject(f)}`);
33
+ }
34
+ }
35
+ return;
36
+ }
37
+ if (!opts.yes) {
38
+ const proceed = await confirm({
39
+ message: `Remove "${project}" from sync gist? This only removes the remote copy.`,
40
+ default: false
41
+ });
42
+ if (!proceed) {
43
+ log.info("Skipped.");
44
+ return;
45
+ }
46
+ }
47
+ deleteGistFile(syncConfig.gistId, filename);
48
+ log.success(`Removed "${project}" from sync gist.`);
49
+ }
50
+ export {
51
+ runSyncClean
52
+ };
53
+ //# sourceMappingURL=sync-clean-QWEQVAYO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/subcommands/sync-clean.ts"],"sourcesContent":["import { confirm } from '@inquirer/prompts';\nimport { log } from '../../../lib/output.js';\nimport {\n assertGhAvailable,\n loadSyncConfig,\n listGistFiles,\n filenameToProject,\n projectToFilename,\n deleteGistFile,\n} from '../utils/gist-transport.js';\n\ninterface SyncCleanOpts {\n readonly yes?: boolean;\n}\n\nexport async function runSyncClean(project: string, opts: SyncCleanOpts): Promise<void> {\n assertGhAvailable();\n\n const syncConfig = loadSyncConfig();\n if (!syncConfig) {\n log.error('No sync gist found. Run `memory push` first.');\n return;\n }\n\n const filename = projectToFilename(project);\n const files = listGistFiles(syncConfig.gistId);\n const projectFiles = files.filter((f) => filenameToProject(f) !== null);\n\n if (!projectFiles.includes(filename)) {\n log.error(`Project \"${project}\" not found in gist.`);\n if (projectFiles.length > 0) {\n log.blank();\n log.info('Available projects:');\n for (const f of projectFiles) {\n log.info(` ${filenameToProject(f)}`);\n }\n }\n return;\n }\n\n if (!opts.yes) {\n const proceed = await confirm({\n message: `Remove \"${project}\" from sync gist? This only removes the remote copy.`,\n default: false,\n });\n if (!proceed) {\n log.info('Skipped.');\n return;\n }\n }\n\n deleteGistFile(syncConfig.gistId, filename);\n log.success(`Removed \"${project}\" from sync gist.`);\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,eAAe;AAexB,eAAsB,aAAa,SAAiB,MAAoC;AACtF,oBAAkB;AAElB,QAAM,aAAa,eAAe;AAClC,MAAI,CAAC,YAAY;AACf,QAAI,MAAM,8CAA8C;AACxD;AAAA,EACF;AAEA,QAAM,WAAW,kBAAkB,OAAO;AAC1C,QAAM,QAAQ,cAAc,WAAW,MAAM;AAC7C,QAAM,eAAe,MAAM,OAAO,CAAC,MAAM,kBAAkB,CAAC,MAAM,IAAI;AAEtE,MAAI,CAAC,aAAa,SAAS,QAAQ,GAAG;AACpC,QAAI,MAAM,YAAY,OAAO,sBAAsB;AACnD,QAAI,aAAa,SAAS,GAAG;AAC3B,UAAI,MAAM;AACV,UAAI,KAAK,qBAAqB;AAC9B,iBAAW,KAAK,cAAc;AAC5B,YAAI,KAAK,KAAK,kBAAkB,CAAC,CAAC,EAAE;AAAA,MACtC;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI,CAAC,KAAK,KAAK;AACb,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,SAAS,WAAW,OAAO;AAAA,MAC3B,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,UAAI,KAAK,UAAU;AACnB;AAAA,IACF;AAAA,EACF;AAEA,iBAAe,WAAW,QAAQ,QAAQ;AAC1C,MAAI,QAAQ,YAAY,OAAO,mBAAmB;AACpD;","names":[]}
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ parsePayload
4
+ } from "./chunk-TSTTFR4B.js";
5
+ import {
6
+ assertGhAvailable,
7
+ filenameToProject,
8
+ listGistFiles,
9
+ loadSyncConfig,
10
+ readGistFile
11
+ } from "./chunk-3UJYOWGF.js";
12
+ import "./chunk-GRL3DOCP.js";
13
+ import {
14
+ initStorage
15
+ } from "./chunk-AUV2JTXX.js";
16
+ import "./chunk-V4NXT4KB.js";
17
+ import "./chunk-ZXJK7CHB.js";
18
+ import "./chunk-PGDSAUP4.js";
19
+ import {
20
+ log
21
+ } from "./chunk-4JNFXVVC.js";
22
+
23
+ // src/commands/memory/subcommands/sync-status.ts
24
+ async function runSyncStatus() {
25
+ assertGhAvailable();
26
+ const syncConfig = loadSyncConfig();
27
+ if (!syncConfig) {
28
+ log.error("No sync gist found. Run `memory push` first.");
29
+ return;
30
+ }
31
+ const { requireMemoryDeps } = await import("./require-deps-3GIE6TAG.js");
32
+ await requireMemoryDeps();
33
+ const ctx = initStorage();
34
+ try {
35
+ const localCounts = ctx.memoryRepo.projectCounts();
36
+ const remoteFiles = listGistFiles(syncConfig.gistId);
37
+ const remoteProjects = remoteFiles.map((f) => filenameToProject(f)).filter((p) => p !== null);
38
+ const remoteCounts = /* @__PURE__ */ new Map();
39
+ for (const file of remoteFiles) {
40
+ const project = filenameToProject(file);
41
+ if (!project) continue;
42
+ const payload = parsePayload(readGistFile(syncConfig.gistId, file));
43
+ remoteCounts.set(project, payload?.memories.length ?? 0);
44
+ }
45
+ const allProjects = /* @__PURE__ */ new Set([...localCounts.keys(), ...remoteCounts.keys()]);
46
+ log.blank();
47
+ log.step("Sync status");
48
+ log.info(`Gist: ${syncConfig.gistId}`);
49
+ log.blank();
50
+ if (allProjects.size === 0) {
51
+ log.info("No projects found locally or remotely.");
52
+ } else {
53
+ log.info("Project Local Remote");
54
+ log.info("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500");
55
+ for (const project of [...allProjects].sort()) {
56
+ const local = localCounts.get(project) ?? 0;
57
+ const remote = remoteCounts.get(project) ?? 0;
58
+ const name = project.length > 33 ? project.slice(0, 30) + "..." : project;
59
+ log.info(`${name.padEnd(33)} ${String(local).padStart(5)} ${String(remote).padStart(6)}`);
60
+ }
61
+ }
62
+ log.blank();
63
+ } finally {
64
+ ctx.close();
65
+ }
66
+ }
67
+ export {
68
+ runSyncStatus
69
+ };
70
+ //# sourceMappingURL=sync-status-ZMXMEBGC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/subcommands/sync-status.ts"],"sourcesContent":["import { log } from '../../../lib/output.js';\nimport { initStorage } from './init-storage.js';\nimport {\n assertGhAvailable,\n loadSyncConfig,\n listGistFiles,\n filenameToProject,\n readGistFile,\n} from '../utils/gist-transport.js';\nimport { parsePayload } from '../utils/sync-merge.js';\n\nexport async function runSyncStatus(): Promise<void> {\n assertGhAvailable();\n\n const syncConfig = loadSyncConfig();\n if (!syncConfig) {\n log.error('No sync gist found. Run `memory push` first.');\n return;\n }\n\n const { requireMemoryDeps } = await import('../utils/require-deps.js');\n await requireMemoryDeps();\n const ctx = initStorage();\n\n try {\n const localCounts = ctx.memoryRepo.projectCounts();\n const remoteFiles = listGistFiles(syncConfig.gistId);\n const remoteProjects = remoteFiles\n .map((f) => filenameToProject(f))\n .filter((p): p is string => p !== null);\n\n const remoteCounts = new Map<string, number>();\n for (const file of remoteFiles) {\n const project = filenameToProject(file);\n if (!project) continue;\n const payload = parsePayload(readGistFile(syncConfig.gistId, file));\n remoteCounts.set(project, payload?.memories.length ?? 0);\n }\n\n const allProjects = new Set([...localCounts.keys(), ...remoteCounts.keys()]);\n\n log.blank();\n log.step('Sync status');\n log.info(`Gist: ${syncConfig.gistId}`);\n log.blank();\n\n if (allProjects.size === 0) {\n log.info('No projects found locally or remotely.');\n } else {\n log.info('Project Local Remote');\n log.info('─────────────────────────────── ───── ──────');\n for (const project of [...allProjects].sort()) {\n const local = localCounts.get(project) ?? 0;\n const remote = remoteCounts.get(project) ?? 0;\n const name = project.length > 33 ? project.slice(0, 30) + '...' : project;\n log.info(`${name.padEnd(33)} ${String(local).padStart(5)} ${String(remote).padStart(6)}`);\n }\n }\n log.blank();\n } finally {\n ctx.close();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAWA,eAAsB,gBAA+B;AACnD,oBAAkB;AAElB,QAAM,aAAa,eAAe;AAClC,MAAI,CAAC,YAAY;AACf,QAAI,MAAM,8CAA8C;AACxD;AAAA,EACF;AAEA,QAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,4BAA0B;AACrE,QAAM,kBAAkB;AACxB,QAAM,MAAM,YAAY;AAExB,MAAI;AACF,UAAM,cAAc,IAAI,WAAW,cAAc;AACjD,UAAM,cAAc,cAAc,WAAW,MAAM;AACnD,UAAM,iBAAiB,YACpB,IAAI,CAAC,MAAM,kBAAkB,CAAC,CAAC,EAC/B,OAAO,CAAC,MAAmB,MAAM,IAAI;AAExC,UAAM,eAAe,oBAAI,IAAoB;AAC7C,eAAW,QAAQ,aAAa;AAC9B,YAAM,UAAU,kBAAkB,IAAI;AACtC,UAAI,CAAC,QAAS;AACd,YAAM,UAAU,aAAa,aAAa,WAAW,QAAQ,IAAI,CAAC;AAClE,mBAAa,IAAI,SAAS,SAAS,SAAS,UAAU,CAAC;AAAA,IACzD;AAEA,UAAM,cAAc,oBAAI,IAAI,CAAC,GAAG,YAAY,KAAK,GAAG,GAAG,aAAa,KAAK,CAAC,CAAC;AAE3E,QAAI,MAAM;AACV,QAAI,KAAK,aAAa;AACtB,QAAI,KAAK,SAAS,WAAW,MAAM,EAAE;AACrC,QAAI,MAAM;AAEV,QAAI,YAAY,SAAS,GAAG;AAC1B,UAAI,KAAK,wCAAwC;AAAA,IACnD,OAAO;AACL,UAAI,KAAK,gDAAgD;AACzD,UAAI,KAAK,kQAAgD;AACzD,iBAAW,WAAW,CAAC,GAAG,WAAW,EAAE,KAAK,GAAG;AAC7C,cAAM,QAAQ,YAAY,IAAI,OAAO,KAAK;AAC1C,cAAM,SAAS,aAAa,IAAI,OAAO,KAAK;AAC5C,cAAM,OAAO,QAAQ,SAAS,KAAK,QAAQ,MAAM,GAAG,EAAE,IAAI,QAAQ;AAClE,YAAI,KAAK,GAAG,KAAK,OAAO,EAAE,CAAC,IAAI,OAAO,KAAK,EAAE,SAAS,CAAC,CAAC,KAAK,OAAO,MAAM,EAAE,SAAS,CAAC,CAAC,EAAE;AAAA,MAC3F;AAAA,IACF;AACA,QAAI,MAAM;AAAA,EACZ,UAAE;AACA,QAAI,MAAM;AAAA,EACZ;AACF;","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  MemoryRepo,
4
4
  RelationRepo,
5
5
  SearchRepo
6
- } from "./chunk-24VLPHJU.js";
6
+ } from "./chunk-V4NXT4KB.js";
7
7
  import {
8
8
  DEFAULT_DECAY_PARAMS,
9
9
  closeDatabase,
@@ -11,9 +11,9 @@ import {
11
11
  loadConfig,
12
12
  migrate,
13
13
  resolveDataDir
14
- } from "./chunk-EDKY7JWY.js";
15
- import "./chunk-Z6FBT44W.js";
16
- import "./chunk-RJGXPH7P.js";
14
+ } from "./chunk-ZXJK7CHB.js";
15
+ import "./chunk-PGDSAUP4.js";
16
+ import "./chunk-4JNFXVVC.js";
17
17
 
18
18
  // src/commands/memory/dashboard/tui.tsx
19
19
  import { render } from "ink";
@@ -1138,4 +1138,4 @@ async function startTui(options) {
1138
1138
  export {
1139
1139
  startTui
1140
1140
  };
1141
- //# sourceMappingURL=tui-XIYOOUP6.js.map
1141
+ //# sourceMappingURL=tui-YL5NWME5.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-launchpad",
3
- "version": "0.16.0",
3
+ "version": "1.0.0",
4
4
  "description": "CLI toolkit for Claude Code — scaffold CLAUDE.md, diagnose config, enforce hooks, test with eval, add persistent memory",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/storage/memory-repo.ts","../src/commands/memory/storage/relation-repo.ts","../src/commands/memory/storage/search-repo.ts"],"sourcesContent":["import type Database from 'better-sqlite3';\nimport type { Memory, MemoryType, MemorySource, StoreInput, SyncMemoryRow } from '../types.js';\nimport { randomUUID } from 'node:crypto';\n\nfunction safeParseTags(raw: string): string[] {\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed.filter(t => typeof t === 'string') : [];\n } catch {\n return [];\n }\n}\n\n// ── Row shape from SQLite ─────────────────────────────────────\n\ninterface MemoryRow {\n id: string;\n type: string;\n title: string | null;\n content: string;\n context: string | null;\n source: string | null;\n project: string | null;\n tags: string;\n importance: number;\n created_at: string;\n updated_at: string;\n access_count: number;\n last_accessed: string | null;\n injection_count: number;\n embedding: Buffer | null;\n}\n\nfunction rowToMemory(row: MemoryRow): Memory {\n return {\n id: row.id,\n type: row.type as MemoryType,\n title: row.title,\n content: row.content,\n context: row.context,\n source: row.source as MemorySource | null,\n project: row.project,\n tags: safeParseTags(row.tags),\n importance: row.importance,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n accessCount: row.access_count,\n lastAccessed: row.last_accessed,\n injectionCount: row.injection_count,\n };\n}\n\n// ── Repository ────────────────────────────────────────────────\n\nexport class MemoryRepo {\n readonly #stmts;\n readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.#stmts = {\n insert: db.prepare(`\n INSERT INTO memories (id, type, title, content, context, source, project, tags, importance, created_at, updated_at, embedding)\n VALUES (@id, @type, @title, @content, @context, @source, @project, @tags, @importance, @createdAt, @updatedAt, @embedding)\n `),\n getById: db.prepare('SELECT * FROM memories WHERE id = ?'),\n getAll: db.prepare('SELECT * FROM memories ORDER BY created_at DESC'),\n getAllByProject: db.prepare('SELECT * FROM memories WHERE project = ? OR project IS NULL ORDER BY created_at DESC'),\n getByType: db.prepare('SELECT * FROM memories WHERE type = ? ORDER BY created_at DESC'),\n getByTypeAndProject: db.prepare('SELECT * FROM memories WHERE type = ? AND (project = ? OR project IS NULL) ORDER BY created_at DESC'),\n getRecent: db.prepare('SELECT * FROM memories ORDER BY created_at DESC LIMIT ?'),\n getRecentByProject: db.prepare('SELECT * FROM memories WHERE project = ? OR project IS NULL ORDER BY created_at DESC LIMIT ?'),\n getRecentByTypeAndProject: db.prepare('SELECT * FROM memories WHERE type = ? AND (project = ? OR project IS NULL) ORDER BY created_at DESC LIMIT ?'),\n update: db.prepare(`\n UPDATE memories\n SET title = @title, content = @content, context = @context, tags = @tags,\n importance = @importance, updated_at = @updatedAt, embedding = @embedding\n WHERE id = @id\n `),\n updateImportance: db.prepare('UPDATE memories SET importance = ?, updated_at = ? WHERE id = ?'),\n updateImportanceOnly: db.prepare('UPDATE memories SET importance = ? WHERE id = ?'),\n incrementAccess: db.prepare(`\n UPDATE memories SET access_count = access_count + 1, last_accessed = ? WHERE id = ?\n `),\n incrementInjection: db.prepare(`\n UPDATE memories SET injection_count = injection_count + 1 WHERE id = ?\n `),\n softDelete: db.prepare('UPDATE memories SET importance = 0, updated_at = ? WHERE id = ?'),\n hardDelete: db.prepare('DELETE FROM memories WHERE id = ?'),\n deleteByType: db.prepare('DELETE FROM memories WHERE type = ?'),\n deleteByProject: db.prepare('DELETE FROM memories WHERE project = ?'),\n count: db.prepare('SELECT COUNT(*) as count FROM memories'),\n countByProject: db.prepare('SELECT COUNT(*) as count FROM memories WHERE project = ?'),\n countByType: db.prepare('SELECT type, COUNT(*) as count FROM memories GROUP BY type'),\n dateRange: db.prepare('SELECT MIN(created_at) as oldest, MAX(created_at) as newest FROM memories'),\n topInjected: db.prepare(`\n SELECT id, title, injection_count FROM memories\n WHERE injection_count > 0 ORDER BY injection_count DESC LIMIT ?\n `),\n upsertSync: db.prepare(`\n INSERT OR REPLACE INTO memories\n (id, type, title, content, context, source, project, tags, importance,\n access_count, injection_count, created_at, updated_at, last_accessed, embedding)\n VALUES (@id, @type, @title, @content, @context, @source, @project, @tags, @importance,\n @accessCount, @injectionCount, @createdAt, @updatedAt, @lastAccessed, NULL)\n `),\n getAllStrictProject: db.prepare(\n 'SELECT * FROM memories WHERE project = ? ORDER BY created_at DESC'\n ),\n };\n }\n\n create(input: StoreInput, _embedding: Buffer | null = null): Memory {\n const now = new Date().toISOString();\n const id = randomUUID();\n\n const params = {\n id,\n type: input.type,\n title: input.title ?? null,\n content: input.content,\n context: input.context ?? null,\n source: input.source,\n project: input.project ?? null,\n tags: JSON.stringify(input.tags),\n importance: input.importance,\n createdAt: now,\n updatedAt: now,\n embedding: null,\n };\n\n this.#stmts.insert.run(params);\n\n const row: MemoryRow = {\n id,\n type: input.type,\n title: input.title ?? null,\n content: input.content,\n context: input.context ?? null,\n source: input.source,\n project: input.project ?? null,\n tags: JSON.stringify(input.tags),\n importance: input.importance,\n created_at: now,\n updated_at: now,\n access_count: 0,\n last_accessed: null,\n injection_count: 0,\n embedding: null,\n };\n\n return rowToMemory(row);\n }\n\n getById(id: string): Memory | undefined {\n const row = this.#stmts.getById.get(id) as MemoryRow | undefined;\n return row ? rowToMemory(row) : undefined;\n }\n\n getAll(project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getAllByProject.all(project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getAll.all() as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n getRecent(limit: number, project?: string, type?: MemoryType): readonly Memory[] {\n if (type && project) {\n const rows = this.#stmts.getRecentByTypeAndProject.all(type, project, limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n if (project) {\n const rows = this.#stmts.getRecentByProject.all(project, limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getRecent.all(limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n getByType(type: MemoryType, project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getByTypeAndProject.all(type, project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getByType.all(type) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n updateContent(id: string, updates: {\n readonly title?: string | null;\n readonly content?: string;\n readonly context?: string | null;\n readonly tags?: readonly string[];\n readonly importance?: number;\n }): boolean {\n const existing = this.getById(id);\n if (!existing) return false;\n\n const now = new Date().toISOString();\n\n const params = {\n id,\n title: updates.title !== undefined ? updates.title : existing.title,\n content: updates.content ?? existing.content,\n context: updates.context !== undefined ? updates.context : existing.context,\n tags: JSON.stringify(updates.tags ?? existing.tags),\n importance: updates.importance ?? existing.importance,\n updatedAt: now,\n embedding: null,\n };\n\n this.#stmts.update.run(params);\n return true;\n }\n\n updateImportance(id: string, importance: number): boolean {\n const now = new Date().toISOString();\n const result = this.#stmts.updateImportance.run(importance, now, id);\n return result.changes > 0;\n }\n\n /** Update importance without touching updated_at - used by decay to avoid resetting the clock. */\n updateImportanceOnly(id: string, importance: number): boolean {\n const result = this.#stmts.updateImportanceOnly.run(importance, id);\n return result.changes > 0;\n }\n\n incrementAccess(id: string): void {\n this.#stmts.incrementAccess.run(new Date().toISOString(), id);\n }\n\n incrementInjection(id: string): void {\n this.#stmts.incrementInjection.run(id);\n }\n\n softDelete(id: string): boolean {\n const result = this.#stmts.softDelete.run(new Date().toISOString(), id);\n return result.changes > 0;\n }\n\n hardDelete(id: string): boolean {\n const result = this.#stmts.hardDelete.run(id);\n return result.changes > 0;\n }\n\n deleteByType(type: MemoryType): number {\n const result = this.#stmts.deleteByType.run(type);\n return result.changes;\n }\n\n deleteByProject(project: string): number {\n const result = this.#stmts.deleteByProject.run(project);\n return result.changes;\n }\n\n count(project?: string): number {\n if (project) {\n const row = this.#stmts.countByProject.get(project) as { count: number };\n return row.count;\n }\n const row = this.#stmts.count.get() as { count: number };\n return row.count;\n }\n\n countByType(): Record<string, number> {\n const rows = this.#stmts.countByType.all() as { type: string; count: number }[];\n return Object.fromEntries(rows.map(r => [r.type, r.count]));\n }\n\n dateRange(): { oldest: string | null; newest: string | null } {\n const row = this.#stmts.dateRange.get() as { oldest: string | null; newest: string | null };\n return { oldest: row.oldest, newest: row.newest };\n }\n\n topInjected(limit: number = 5): readonly { id: string; title: string | null; injectionCount: number }[] {\n const rows = this.#stmts.topInjected.all(limit) as { id: string; title: string | null; injection_count: number }[];\n return rows.map(r => ({ id: r.id, title: r.title, injectionCount: r.injection_count }));\n }\n\n upsertFromSync(row: SyncMemoryRow): void {\n this.#stmts.upsertSync.run({\n id: row.id,\n type: row.type,\n title: row.title,\n content: row.content,\n context: row.context,\n source: row.source,\n project: row.project,\n tags: JSON.stringify(row.tags),\n importance: row.importance,\n accessCount: row.access_count,\n injectionCount: row.injection_count,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n lastAccessed: row.last_accessed,\n });\n }\n\n getAllForSync(project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getAllStrictProject.all(project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n return this.getAll();\n }\n}\n","import type Database from 'better-sqlite3';\nimport type { Relation, RelationType } from '../types.js';\n\ninterface RelationRow {\n source_id: string;\n target_id: string;\n relation_type: string;\n created_at: string;\n}\n\nfunction rowToRelation(row: RelationRow): Relation {\n return {\n sourceId: row.source_id,\n targetId: row.target_id,\n relationType: row.relation_type as RelationType,\n createdAt: row.created_at,\n };\n}\n\nexport class RelationRepo {\n readonly #stmts;\n\n constructor(db: Database.Database) {\n this.#stmts = {\n insert: db.prepare(`\n INSERT OR IGNORE INTO relations (source_id, target_id, relation_type)\n VALUES (?, ?, ?)\n `),\n getBySource: db.prepare('SELECT * FROM relations WHERE source_id = ?'),\n getByTarget: db.prepare('SELECT * FROM relations WHERE target_id = ?'),\n getByMemory: db.prepare(`\n SELECT * FROM relations WHERE source_id = ? OR target_id = ?\n `),\n delete: db.prepare(`\n DELETE FROM relations WHERE source_id = ? AND target_id = ? AND relation_type = ?\n `),\n countByMemory: db.prepare(`\n SELECT COUNT(*) as count FROM relations WHERE source_id = ? OR target_id = ?\n `),\n count: db.prepare('SELECT COUNT(*) as count FROM relations'),\n getAll: db.prepare('SELECT * FROM relations'),\n deleteOrphaned: db.prepare(`\n DELETE FROM relations\n WHERE source_id NOT IN (SELECT id FROM memories)\n OR target_id NOT IN (SELECT id FROM memories)\n `),\n };\n }\n\n create(sourceId: string, targetId: string, relationType: RelationType): boolean {\n const result = this.#stmts.insert.run(sourceId, targetId, relationType);\n return result.changes > 0;\n }\n\n getBySource(sourceId: string): readonly Relation[] {\n const rows = this.#stmts.getBySource.all(sourceId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n getByTarget(targetId: string): readonly Relation[] {\n const rows = this.#stmts.getByTarget.all(targetId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n getByMemory(memoryId: string): readonly Relation[] {\n const rows = this.#stmts.getByMemory.all(memoryId, memoryId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n delete(sourceId: string, targetId: string, relationType: RelationType): boolean {\n const result = this.#stmts.delete.run(sourceId, targetId, relationType);\n return result.changes > 0;\n }\n\n countByMemory(memoryId: string): number {\n const row = this.#stmts.countByMemory.get(memoryId, memoryId) as { count: number };\n return row.count;\n }\n\n count(): number {\n const row = this.#stmts.count.get() as { count: number };\n return row.count;\n }\n\n getAll(): readonly Relation[] {\n const rows = this.#stmts.getAll.all() as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n deleteOrphaned(): number {\n const result = this.#stmts.deleteOrphaned.run();\n return result.changes;\n }\n}\n","import type Database from 'better-sqlite3';\nimport type { FtsMatch, MemoryType } from '../types.js';\n\n// ── FTS5 Search ───────────────────────────────────────────────\n\nexport interface FtsSearchOptions {\n readonly query: string;\n readonly limit: number;\n readonly type?: MemoryType;\n readonly minImportance?: number;\n readonly project?: string;\n}\n\n\nexport class SearchRepo {\n readonly #stmts;\n\n constructor(db: Database.Database) {\n // FTS5 search with BM25 ranking (weights: title=5.0, content=1.0, tags=2.0)\n this.#stmts = {\n ftsSearch: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchByProject: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND (m.project = @project OR m.project IS NULL)\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchFiltered: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND m.type = @type\n AND m.importance >= @minImportance\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchFilteredByProject: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND m.type = @type\n AND m.importance >= @minImportance\n AND (m.project = @project OR m.project IS NULL)\n ORDER BY rank\n LIMIT @limit\n `),\n };\n }\n\n /**\n * Full-text search using BM25 ranking.\n * Returns matches sorted by relevance (most relevant first).\n */\n searchFts(options: FtsSearchOptions): readonly FtsMatch[] {\n const ftsQuery = toFtsQuery(options.query);\n if (!ftsQuery) return [];\n\n try {\n const hasType = !!options.type;\n const hasProject = !!options.project;\n\n let rows: FtsRow[];\n if (hasType && hasProject) {\n rows = this.#stmts.ftsSearchFilteredByProject.all({\n query: ftsQuery, limit: options.limit,\n type: options.type, minImportance: options.minImportance ?? 0,\n project: options.project,\n }) as FtsRow[];\n } else if (hasType) {\n rows = this.#stmts.ftsSearchFiltered.all({\n query: ftsQuery, limit: options.limit,\n type: options.type, minImportance: options.minImportance ?? 0,\n }) as FtsRow[];\n } else if (hasProject) {\n rows = this.#stmts.ftsSearchByProject.all({\n query: ftsQuery, limit: options.limit,\n project: options.project,\n }) as FtsRow[];\n } else {\n rows = this.#stmts.ftsSearch.all({\n query: ftsQuery, limit: options.limit,\n }) as FtsRow[];\n }\n\n return rows.map(r => ({\n rowid: r.rowid,\n memoryId: r.memory_id,\n rank: r.rank,\n }));\n } catch (err) {\n // FTS5 MATCH throws on invalid query syntax - degrade gracefully\n console.error('[agentic-memory] FTS5 search error:', err instanceof Error ? err.message : err);\n return [];\n }\n }\n\n}\n\n// ── Internal helpers ──────────────────────────────────────────\n\ninterface FtsRow {\n rowid: number;\n memory_id: string;\n rank: number;\n}\n\n// Synonym expansion for common dev terms\nconst SYNONYMS: Record<string, readonly string[]> = {\n auth: ['authentication', 'login', 'oauth', 'jwt'],\n authentication: ['auth', 'login', 'oauth'],\n login: ['auth', 'authentication', 'signin'],\n db: ['database', 'sql', 'sqlite', 'postgres'],\n database: ['db', 'sql', 'sqlite', 'postgres'],\n api: ['endpoint', 'route', 'rest', 'graphql'],\n deploy: ['deployment', 'release', 'ship', 'publish'],\n test: ['testing', 'spec', 'jest', 'vitest'],\n config: ['configuration', 'settings', 'setup'],\n err: ['error', 'exception', 'crash', 'bug'],\n error: ['err', 'exception', 'crash', 'bug'],\n};\n\n/**\n * Convert a natural language query to FTS5 query syntax.\n * Expands synonyms and wraps words in quotes for safe matching.\n */\nfunction toFtsQuery(input: string): string | null {\n const words = input\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 0);\n\n if (words.length === 0) return null;\n\n const expanded = words.flatMap((w) => {\n const lower = w.toLowerCase();\n const syns = SYNONYMS[lower];\n return syns ? [w, ...syns] : [w];\n });\n\n return [...new Set(expanded)].map(w => `\"${w}\"`).join(' OR ');\n}\n"],"mappings":"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","names":["rows","row"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/config.ts","../src/commands/memory/storage/database.ts","../src/commands/memory/storage/migrations/001-initial.ts","../src/commands/memory/storage/migrations/002-add-project.ts","../src/commands/memory/storage/migrator.ts"],"sourcesContent":["import { z } from 'zod';\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DecayParams } from './types.js';\n\n// ── Config Schema ─────────────────────────────────────────────\n\nconst ConfigSchema = z.object({\n dataDir: z.string().default('~/.agentic-memory'),\n injectionBudget: z.number().int().min(100).max(20000).default(3000),\n consolidationInterval: z.number().int().min(1).default(10),\n enableReranker: z.boolean().default(true),\n logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('warn'),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\n// ── Defaults ──────────────────────────────────────────────────\n\nexport const DEFAULT_CONFIG: Config = {\n dataDir: '~/.agentic-memory',\n injectionBudget: 3000,\n consolidationInterval: 10,\n enableReranker: true,\n logLevel: 'warn',\n};\n\nexport const DEFAULT_DECAY_PARAMS: DecayParams = {\n tauByType: {\n working: 0, // cleared each session, tau irrelevant\n episodic: 30, // fast decay (was 60, cognitive science: unrehearsed episodes fade in ~30d)\n semantic: 540, // slow decay (was 365, extracted facts are stable for years)\n procedural: 730, // near-permanent\n pattern: 180, // medium decay\n },\n accessModifiers: [\n { maxCount: 3, multiplier: 1.0 },\n { maxCount: 10, multiplier: 2.0 },\n { maxCount: Infinity, multiplier: 4.0 },\n ],\n relationModifier: {\n connectedThreshold: 3,\n connectedMultiplier: 1.8, // higher tau = slower decay for connected memories\n isolatedMultiplier: 0.8, // lower tau = slightly faster decay for isolated memories\n highlyConnectedThreshold: 6,\n highlyConnectedMultiplier: 2.5, // near-immune: ~2.5x longer effective half-life\n },\n importanceFloor: 0.05,\n pruneThreshold: 0.1,\n pruneMinAgeDays: 90,\n};\n\nexport const SCORING_WEIGHTS = {\n text: 0.35,\n importance: 0.20,\n recency: 0.20,\n access: 0.10,\n context: 0.15,\n} as const;\n\n// ── Injection Algorithm Constants ──────────────────────────────\n\nexport const INJECTION_WEIGHTS = {\n context: 0.30,\n value: 0.25,\n importance: 0.20,\n recency: 0.15,\n typeBonus: 0.05,\n noise: 0.05,\n} as const;\n\nexport const TYPE_INJECTION_BONUS: Record<string, number> = {\n procedural: 1.0,\n pattern: 0.8,\n semantic: 0.6,\n episodic: 0.3,\n working: 0.0,\n};\n\nexport const RECENCY_HALF_LIFE: Record<string, number> = {\n working: 1,\n episodic: 7,\n pattern: 14,\n semantic: 30,\n procedural: 90,\n};\n\nexport const INJECTION_MIN_SCORE = 0.25;\nexport const INJECTION_COLD_START_THRESHOLD = 5;\nexport const INJECTION_COLD_START_RAMP_END = 20;\nexport const INJECTION_HEADER_TOKENS = 50;\nexport const INJECTION_MAX_SAME_TYPE_FULL = 2;\nexport const INJECTION_PINNED_BUDGET_PCT = 0.10;\n\n// ── Config Loader ─────────────────────────────────────────────\n\nexport function resolveDataDir(dataDir: string): string {\n if (dataDir.startsWith('~')) {\n return join(homedir(), dataDir.slice(1));\n }\n return dataDir;\n}\n\nexport function loadConfig(overrides?: Partial<Config>): Config {\n const envOverrides: Record<string, unknown> = {};\n\n const envBudget = process.env['AGENTIC_MEMORY_INJECTION_BUDGET'];\n if (envBudget !== undefined) {\n envOverrides['injectionBudget'] = parseInt(envBudget, 10);\n }\n\n const envLogLevel = process.env['AGENTIC_MEMORY_LOG_LEVEL'];\n if (envLogLevel !== undefined) {\n envOverrides['logLevel'] = envLogLevel;\n }\n\n const envDataDir = process.env['AGENTIC_MEMORY_DATA_DIR'];\n if (envDataDir !== undefined) {\n envOverrides['dataDir'] = envDataDir;\n }\n\n // Try loading config.json from data dir\n let fileConfig: Record<string, unknown> = {};\n const baseDir = resolveDataDir(overrides?.dataDir ?? envOverrides['dataDir'] as string ?? DEFAULT_CONFIG.dataDir);\n try {\n const raw = readFileSync(join(baseDir, 'config.json'), 'utf-8');\n fileConfig = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n const isNotFound = err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT';\n if (!isNotFound) {\n // Malformed JSON or permissions error - warn, don't silently ignore\n console.error('[agentic-memory] Failed to load config.json:', err instanceof Error ? err.message : err);\n }\n }\n\n const merged = { ...DEFAULT_CONFIG, ...fileConfig, ...envOverrides, ...overrides };\n return ConfigSchema.parse(merged);\n}\n\n// ── Token Estimation ──────────────────────────────────────────\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n","import type DatabaseConstructor from 'better-sqlite3';\nimport { resolveDataDir } from '../config.js';\nimport { mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { cwdRequire } from '../utils/require-deps.js';\n\nexport interface DatabaseOptions {\n readonly dbPath?: string; // full path override (e.g. ':memory:' for tests)\n readonly dataDir?: string; // resolved data dir (default ~/.agentic-memory)\n}\n\nexport function createDatabase(options: DatabaseOptions = {}): DatabaseConstructor.Database {\n const dbPath = options.dbPath ?? resolveDbPath(options.dataDir);\n\n if (dbPath !== ':memory:') {\n mkdirSync(dirname(dbPath), { recursive: true });\n }\n\n const Database = cwdRequire('better-sqlite3') as typeof DatabaseConstructor;\n const sqliteVec = cwdRequire('sqlite-vec') as { load: (db: DatabaseConstructor.Database) => void };\n\n const db = new Database(dbPath);\n\n // Load sqlite-vec extension\n sqliteVec.load(db);\n\n // Configure PRAGMAs (order matters: foreign_keys before any ops, journal_mode is persistent)\n db.pragma('journal_mode = WAL');\n db.pragma('busy_timeout = 5000');\n db.pragma('foreign_keys = ON');\n db.pragma('cache_size = -64000');\n db.pragma('mmap_size = 268435456');\n db.pragma('synchronous = NORMAL');\n db.pragma('temp_store = MEMORY');\n db.pragma('journal_size_limit = 33554432');\n\n return db;\n}\n\nexport function closeDatabase(db: DatabaseConstructor.Database): void {\n try {\n db.pragma('wal_checkpoint(TRUNCATE)');\n } catch {\n // Checkpoint may fail on :memory: - that's fine\n }\n db.close();\n}\n\nfunction resolveDbPath(dataDir?: string): string {\n const dir = resolveDataDir(dataDir ?? '~/.agentic-memory');\n return join(dir, 'memory.db');\n}\n","import type Database from 'better-sqlite3';\n\nexport const version = 1;\n\nexport function up(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT\n );\n\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('episodic','semantic','procedural','working','pattern')),\n title TEXT,\n content TEXT NOT NULL,\n context TEXT,\n source TEXT CHECK(source IN ('manual','session_end','consolidation','hook','import')),\n tags TEXT NOT NULL DEFAULT '[]',\n importance REAL NOT NULL DEFAULT 0.5 CHECK(importance >= 0.0 AND importance <= 1.0),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n access_count INTEGER NOT NULL DEFAULT 0 CHECK(access_count >= 0),\n last_accessed TEXT,\n injection_count INTEGER NOT NULL DEFAULT 0 CHECK(injection_count >= 0),\n embedding BLOB\n );\n\n CREATE TABLE IF NOT EXISTS relations (\n source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n relation_type TEXT NOT NULL CHECK(relation_type IN (\n 'relates_to','depends_on','contradicts','extends','implements','derived_from'\n )),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (source_id, target_id, relation_type)\n );\n\n -- FTS5 external content (no data duplication)\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n title, content, tags,\n content=memories,\n content_rowid=rowid,\n tokenize='porter unicode61'\n );\n\n -- FTS5 sync triggers\n CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, title, content, tags)\n VALUES (new.rowid, new.title, new.content, new.tags);\n END;\n\n CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)\n VALUES ('delete', old.rowid, old.title, old.content, old.tags);\n END;\n\n CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)\n VALUES ('delete', old.rowid, old.title, old.content, old.tags);\n INSERT INTO memories_fts(rowid, title, content, tags)\n VALUES (new.rowid, new.title, new.content, new.tags);\n END;\n\n -- Vector search (synced manually in application code)\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_vec USING vec0(\n memory_id TEXT PRIMARY KEY,\n embedding float[384] distance_metric=cosine\n );\n\n -- Indexes\n CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);\n CREATE INDEX IF NOT EXISTS idx_memories_importance ON memories(importance);\n CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories(created_at);\n CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_id);\n `);\n}\n","import type Database from 'better-sqlite3';\n\nexport const version = 2;\n\nexport function up(db: Database.Database): void {\n db.exec(`\n ALTER TABLE memories ADD COLUMN project TEXT;\n CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project);\n `);\n}\n","import type Database from 'better-sqlite3';\nimport * as migration001 from './migrations/001-initial.js';\nimport * as migration002 from './migrations/002-add-project.js';\n\ninterface Migration {\n readonly version: number;\n readonly up: (db: Database.Database) => void;\n}\n\nconst migrations: readonly Migration[] = [\n migration001,\n migration002,\n];\n\nexport function getSchemaVersion(db: Database.Database): number {\n try {\n const row = db.prepare(\"SELECT value FROM meta WHERE key = 'schema_version'\").get() as\n { value: string } | undefined;\n return row ? parseInt(row.value, 10) : 0;\n } catch {\n return 0;\n }\n}\n\nexport function migrate(db: Database.Database): void {\n const current = getSchemaVersion(db);\n const pending = migrations.filter(m => m.version > current);\n\n if (pending.length === 0) return;\n\n const runMigrations = db.transaction(() => {\n for (const m of pending) {\n m.up(db);\n db.prepare(\"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\")\n .run(String(m.version));\n }\n });\n\n runMigrations();\n}\n"],"mappings":"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","names":["join","join","up","version"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/utils/gist-transport.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { homedir } from 'node:os';\n\nexport interface SyncConfig {\n readonly gistId: string;\n}\n\nconst EXEC_OPTS = { encoding: 'utf-8' as const, timeout: 30_000 };\nconst GIST_DESCRIPTION = 'agentic-memory sync';\nconst SYNC_CONFIG_FILE = 'sync-config.json';\nconst DATA_DIR = join(homedir(), '.agentic-memory');\n\nfunction syncConfigPath(): string {\n return join(DATA_DIR, SYNC_CONFIG_FILE);\n}\n\nfunction slugify(project: string): string {\n return project.replace(/[^a-zA-Z0-9._-]/g, '-');\n}\n\nexport function projectToFilename(project: string): string {\n if (!project) throw new Error('Project name cannot be empty');\n return `memories-${slugify(project)}.json`;\n}\n\nexport function filenameToProject(filename: string): string | null {\n const match = filename.match(/^memories-(.+)\\.json$/);\n return match?.[1] ?? null;\n}\n\n\nexport function assertGhAvailable(): void {\n try {\n execSync('gh --version', { ...EXEC_OPTS, stdio: 'pipe' });\n } catch {\n throw new Error(\n 'Memory sync requires the GitHub CLI.\\n' +\n 'Install: https://cli.github.com/\\n' +\n 'Then run: gh auth login'\n );\n }\n try {\n execSync('gh auth status', { ...EXEC_OPTS, stdio: 'pipe' });\n } catch {\n throw new Error(\n 'gh is installed but not authenticated.\\n' +\n 'Run: gh auth login'\n );\n }\n}\n\n/**\n * Read sync config from disk only — no network discovery.\n * Safe to call from lightweight contexts like doctor analyzers.\n */\nexport function readSyncConfig(): SyncConfig | null {\n try {\n const raw = readFileSync(syncConfigPath(), 'utf-8');\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n if (typeof parsed.gistId === 'string' && /^[a-f0-9]+$/.test(parsed.gistId)) {\n return { gistId: parsed.gistId };\n }\n } catch { /* no config file */ }\n return null;\n}\n\nexport function loadSyncConfig(): SyncConfig | null {\n try {\n const raw = readFileSync(syncConfigPath(), 'utf-8');\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n if (typeof parsed.gistId === 'string' && /^[a-f0-9]+$/.test(parsed.gistId)) {\n return { gistId: parsed.gistId };\n }\n } catch { /* no local config */ }\n\n const discovered = discoverSyncGist();\n if (discovered) {\n saveSyncConfig({ gistId: discovered });\n return { gistId: discovered };\n }\n return null;\n}\n\nfunction discoverSyncGist(): string | null {\n try {\n const output = execSync(\n 'gh gist list --limit 100',\n { ...EXEC_OPTS, stdio: ['pipe', 'pipe', 'pipe'] },\n );\n for (const line of output.split('\\n')) {\n const cols = line.split('\\t');\n if (cols[1]?.trim() === GIST_DESCRIPTION) {\n const gistId = cols[0]?.trim();\n if (gistId && /^[a-f0-9]+$/.test(gistId)) return gistId;\n }\n }\n } catch { /* gh list failed */ }\n return null;\n}\n\nexport function saveSyncConfig(config: SyncConfig): void {\n const filePath = syncConfigPath();\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function createGist(filename: string, content: string): string {\n const safeFilename = slugify(filename.replace(/\\.json$/, '')) + '.json';\n const tmpFile = join(tmpdir(), safeFilename);\n try {\n writeFileSync(tmpFile, content, 'utf-8');\n const result = execSync(\n `gh gist create \"${tmpFile}\" --desc \"${GIST_DESCRIPTION}\" --public=false`,\n { ...EXEC_OPTS, stdio: ['pipe', 'pipe', 'pipe'] },\n ).trim();\n const gistId = result.split('/').pop()?.trim() ?? '';\n if (!gistId || !/^[a-f0-9]+$/.test(gistId)) {\n throw new Error(`Failed to parse gist ID from: ${result}`);\n }\n saveSyncConfig({ gistId });\n return gistId;\n } finally {\n try { unlinkSync(tmpFile); } catch { /* ignore */ }\n }\n}\n\nexport function readGistFile(gistId: string, filename: string): string | null {\n try {\n const escapedFilename = JSON.stringify(filename);\n return execSync(\n `gh api \"/gists/${gistId}\" --jq '.files[${escapedFilename}].content'`,\n { ...EXEC_OPTS, stdio: ['pipe', 'pipe', 'pipe'] },\n ).trimEnd();\n } catch {\n return null;\n }\n}\n\nexport function listGistFiles(gistId: string): readonly string[] {\n try {\n const output = execSync(\n `gh api \"/gists/${gistId}\" --jq '.files | keys[]'`,\n { ...EXEC_OPTS, stdio: ['pipe', 'pipe', 'pipe'] },\n );\n return output.trim().split('\\n').filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport function updateGistFiles(\n gistId: string,\n files: Record<string, string>,\n): void {\n const payload = {\n files: Object.fromEntries(\n Object.entries(files).map(([name, content]) => [name, { content }]),\n ),\n };\n const tmpFile = join(tmpdir(), `gist-patch-${Date.now()}.json`);\n try {\n writeFileSync(tmpFile, JSON.stringify(payload), 'utf-8');\n execSync(\n `gh api --method PATCH \"/gists/${gistId}\" --input \"${tmpFile}\"`,\n { ...EXEC_OPTS, stdio: ['pipe', 'pipe', 'pipe'] },\n );\n } finally {\n try { unlinkSync(tmpFile); } catch { /* ignore */ }\n }\n}\n"],"mappings":"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","names":[]}