@aabadin/project-memory-context 0.1.2 → 0.1.4

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/cli/setup.mjs CHANGED
@@ -12,13 +12,22 @@ import { installAgentTemplates } from '../src/template-installer.mjs';
12
12
 
13
13
  const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
14
14
 
15
+ const AGENT_FLAGS = {
16
+ '--opencode': 'opencode',
17
+ '--claude': 'claude-code',
18
+ '--cursor': 'cursor',
19
+ '--generic': 'generic',
20
+ };
21
+
15
22
  function installGraphify() {
16
23
  const candidates = process.platform === 'win32' ? ['python', 'py'] : ['python3', 'python'];
17
24
  for (const command of candidates) {
18
25
  const result = spawnSync(command, ['-m', 'pip', 'install', 'graphifyy'], { stdio: 'inherit' });
19
26
  if (result.status === 0) return command;
20
27
  }
21
- console.warn('\n⚠ Could not install graphifyy automatically. Run: pip install graphifyy\n');
28
+ console.warn(`\n⚠ Could not install graphifyy automatically.`);
29
+ console.warn(` Python not found? Download it from: https://www.python.org/downloads/`);
30
+ console.warn(` Then run: pip install graphifyy\n`);
22
31
  return null;
23
32
  }
24
33
 
@@ -28,13 +37,13 @@ function spawnCheck(bin, args) {
28
37
  }
29
38
 
30
39
  function parseArgs(args) {
31
- const parsed = { agent: null };
32
- for (let i = 0; i < args.length; i++) {
33
- if (args[i] === '--agent' && args[i + 1]) {
34
- parsed.agent = args[++i];
40
+ const agents = [];
41
+ for (const arg of args) {
42
+ if (AGENT_FLAGS[arg]) {
43
+ agents.push(AGENT_FLAGS[arg]);
35
44
  }
36
45
  }
37
- return parsed;
46
+ return { agents };
38
47
  }
39
48
 
40
49
  const rl = createInterface({ input, output });
@@ -42,7 +51,17 @@ const cwd = resolve(process.cwd());
42
51
 
43
52
  try {
44
53
  console.log('\n─── pmc setup ───────────────────────────────────────\n');
45
- const { agent: requestedAgent } = parseArgs(process.argv.slice(2));
54
+ const { agents: requestedAgents } = parseArgs(process.argv.slice(2));
55
+
56
+ let agents;
57
+ if (requestedAgents.length > 0) {
58
+ agents = [...new Set(requestedAgents)];
59
+ console.log(` Target agents: ${agents.join(', ')}`);
60
+ } else {
61
+ const detected = detectSetupAgentType(cwd);
62
+ agents = [detected];
63
+ console.log(` Auto-detected agent: ${detected}`);
64
+ }
46
65
 
47
66
  const ollamaBaseUrl =
48
67
  (await rl.question('Ollama base URL [http://localhost:11434]: ')).trim() ||
@@ -54,31 +73,33 @@ try {
54
73
 
55
74
  installGraphify();
56
75
 
76
+ const { globalConfig } = resolveConfigDirs(cwd);
77
+
57
78
  const result = await bootstrapProjectInstall({
58
79
  projectRoot: cwd,
59
80
  packageRoot,
60
81
  ollamaBaseUrl,
61
82
  ollamaModel,
83
+ agents,
62
84
  });
63
85
 
64
- const agent = detectSetupAgentType(cwd, { requestedAgent });
65
- const { globalConfig } = resolveConfigDirs(cwd);
66
- console.log(`\n Detected agent: ${agent}`);
67
- await installAgentTemplates({
68
- projectRoot: cwd,
69
- agent,
70
- packageRoot,
71
- globalConfigDir: agent === 'opencode' ? globalConfig : undefined,
72
- });
73
- console.log(` Installed ${agent} templates.`);
86
+ for (const agent of agents) {
87
+ await installAgentTemplates({
88
+ projectRoot: cwd,
89
+ agent,
90
+ packageRoot,
91
+ globalConfigDir: agent === 'opencode' ? globalConfig : undefined,
92
+ });
93
+ console.log(` ✓ Installed ${agent} templates.`);
94
+ }
74
95
 
75
96
  console.log('\n─── Installation complete ───────────────────────────\n');
76
97
  console.log(` Memory DB path: ${result.installState.memoryDbPath}`);
77
98
  console.log(` Embedding cache: ${result.installState.embeddingCachePath}`);
78
99
  console.log(` MCP config: ${result.configPath}`);
79
100
  console.log(` Command template: ${result.commandPath}`);
101
+ console.log(` Agents configured: ${agents.join(', ')}`);
80
102
 
81
- // Run doctor to surface any remaining issues
82
103
  console.log('\n─── Environment check ───────────────────────────────\n');
83
104
  const env = {
84
105
  ...process.env,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aabadin/project-memory-context",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Portable project memory context CLI — bootstraps semantic enrichment workflows for any AI coding agent.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
package/src/doctor.mjs CHANGED
@@ -34,7 +34,7 @@ async function checkNodeVersion() {
34
34
  async function checkPython(resolvePythonBin, spawnCheck) {
35
35
  const bin = resolvePythonBin?.() ?? null;
36
36
  if (!bin) {
37
- return { name: 'python', status: 'fail', message: 'Python 3 not found in PATH install python3 or set PATH' };
37
+ return { name: 'python', status: 'fail', message: 'Python 3 not found download from https://www.python.org/downloads/ or set PATH' };
38
38
  }
39
39
  if (!spawnCheck) {
40
40
  return { name: 'python', status: 'ok', message: `${bin} found (not verified — no spawn check provided)` };
@@ -1,9 +1,8 @@
1
1
  import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
- import { basename, dirname, join } from 'node:path';
2
+ import { dirname, join } from 'node:path';
3
3
 
4
4
  import { ensureProjectMemoryContextDirs, writeJsonArtifact } from './artifacts.mjs';
5
5
  import { PMC_ENRICHMENT_CONFIG_FILE } from './enrichment-config.mjs';
6
- import { resolveConfigDirs } from './platform.mjs';
7
6
 
8
7
  async function readJson(filePath, fallback) {
9
8
  try {
@@ -63,52 +62,65 @@ async function writeMcpJson(projectRoot, installState) {
63
62
  return mcpPath;
64
63
  }
65
64
 
66
- async function ensureAgentConfigRegistration(projectRoot, installState) {
67
- const { projectConfig } = resolveConfigDirs(projectRoot);
68
- const agentDir = basename(projectConfig);
69
-
70
- if (agentDir === '.opencode') {
71
- const configPath = join(projectConfig, 'opencode.json');
72
- const config = await readJson(configPath, { $schema: 'https://opencode.ai/config.json' });
73
- const existing = Array.isArray(config.plugin) ? config.plugin : [];
74
- if (!existing.includes('@aabadin/project-memory-context')) {
75
- config.plugin = [...existing, '@aabadin/project-memory-context'];
76
- }
77
- config.mcp = {
78
- ...(config.mcp ?? {}),
79
- ...buildOpencodeMcpConfig(installState).mcp,
80
- };
81
- await mkdir(dirname(configPath), { recursive: true });
82
- await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
83
- // Also write .mcp.json so agent-memory is available immediately
84
- await writeMcpJson(projectRoot, installState);
85
- return configPath;
65
+ async function ensureOpencodeConfig(projectRoot, installState) {
66
+ const opencodeDir = join(projectRoot, '.opencode');
67
+ await mkdir(opencodeDir, { recursive: true });
68
+ const configPath = join(opencodeDir, 'opencode.json');
69
+ const config = await readJson(configPath, { $schema: 'https://opencode.ai/config.json' });
70
+ const existing = Array.isArray(config.plugin) ? config.plugin : [];
71
+ if (!existing.includes('@aabadin/project-memory-context')) {
72
+ config.plugin = [...existing, '@aabadin/project-memory-context'];
86
73
  }
74
+ config.mcp = {
75
+ ...(config.mcp ?? {}),
76
+ ...buildOpencodeMcpConfig(installState).mcp,
77
+ };
78
+ await mkdir(dirname(configPath), { recursive: true });
79
+ await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
80
+ return configPath;
81
+ }
87
82
 
88
- if (agentDir === '.claude' || agentDir === '.cursor' || agentDir === '.pmc') {
89
- // For Claude Code, Cursor, and generic PMC setups: write .mcp.json directly
90
- const mcpPath = await writeMcpJson(projectRoot, installState);
91
- // Also persist enrichment config
92
- const enrichPath = join(projectConfig, PMC_ENRICHMENT_CONFIG_FILE);
93
- const existingConfig = await readJson(enrichPath, {});
94
- const config = {
95
- ...existingConfig,
96
- enrichment: {
97
- ...existingConfig.enrichment,
98
- localModel: {
99
- ...existingConfig.enrichment?.localModel,
100
- baseUrl: installState.ollamaBaseUrl,
101
- model: installState.ollamaModel,
102
- },
83
+ async function ensureEnrichmentConfig(projectRoot, configDir, installState) {
84
+ const enrichPath = join(configDir, PMC_ENRICHMENT_CONFIG_FILE);
85
+ const existingConfig = await readJson(enrichPath, {});
86
+ const config = {
87
+ ...existingConfig,
88
+ enrichment: {
89
+ ...existingConfig.enrichment,
90
+ localModel: {
91
+ ...existingConfig.enrichment?.localModel,
92
+ baseUrl: installState.ollamaBaseUrl,
93
+ model: installState.ollamaModel,
103
94
  },
104
- };
105
- await mkdir(dirname(enrichPath), { recursive: true });
106
- await writeFile(enrichPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
107
- return mcpPath;
95
+ },
96
+ };
97
+ await mkdir(dirname(enrichPath), { recursive: true });
98
+ await writeFile(enrichPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
99
+ }
100
+
101
+ async function ensureAgentConfigs(projectRoot, installState, agents) {
102
+ let primaryConfigPath = null;
103
+
104
+ for (const agent of agents) {
105
+ if (agent === 'opencode') {
106
+ primaryConfigPath = primaryConfigPath ?? await ensureOpencodeConfig(projectRoot, installState);
107
+ }
108
+ if (agent === 'claude-code') {
109
+ const claudeDir = join(projectRoot, '.claude');
110
+ await mkdir(claudeDir, { recursive: true });
111
+ await ensureEnrichmentConfig(projectRoot, claudeDir, installState);
112
+ primaryConfigPath = primaryConfigPath ?? join(projectRoot, '.mcp.json');
113
+ }
114
+ if (agent === 'cursor') {
115
+ const cursorDir = join(projectRoot, '.cursor');
116
+ await mkdir(cursorDir, { recursive: true });
117
+ await ensureEnrichmentConfig(projectRoot, cursorDir, installState);
118
+ primaryConfigPath = primaryConfigPath ?? join(projectRoot, '.mcp.json');
119
+ }
108
120
  }
109
121
 
110
- // Fallback: no agent dir detected — write .mcp.json at project root
111
- return writeMcpJson(projectRoot, installState);
122
+ await writeMcpJson(projectRoot, installState);
123
+ return primaryConfigPath ?? join(projectRoot, '.mcp.json');
112
124
  }
113
125
 
114
126
  async function copyTemplate(packageRoot, templateName, projectRoot) {
@@ -126,7 +138,10 @@ export async function bootstrapProjectInstall({
126
138
  ollamaBaseUrl,
127
139
  ollamaModel,
128
140
  embeddingCachePath,
141
+ agents = [],
142
+ agent,
129
143
  }) {
144
+ const resolvedAgents = agents.length > 0 ? agents : (agent ? [agent] : ['generic']);
130
145
  const dirs = await ensureProjectMemoryContextDirs(projectRoot);
131
146
  const memoryDbPath = join(dirs.base, 'memory-db');
132
147
  const installState = {
@@ -140,7 +155,7 @@ export async function bootstrapProjectInstall({
140
155
 
141
156
  await mkdir(memoryDbPath, { recursive: true });
142
157
  await writeJsonArtifact(join(dirs.base, 'install.json'), installState);
143
- const configPath = await ensureAgentConfigRegistration(projectRoot, installState);
158
+ const configPath = await ensureAgentConfigs(projectRoot, installState, resolvedAgents);
144
159
  const commandPath = await copyTemplate(packageRoot, 'project-memory-context.md', projectRoot);
145
160
  const workflowPath = await copyTemplate(packageRoot, 'project-memory-context workflow.md', projectRoot);
146
161
 
@@ -149,5 +164,6 @@ export async function bootstrapProjectInstall({
149
164
  configPath,
150
165
  commandPath,
151
166
  workflowPath,
167
+ agents: resolvedAgents,
152
168
  };
153
169
  }