devmem 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nikhil Dhaliya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # DevMem
2
+
3
+ > Generate persistent, domain-specific context files for AI tools.
4
+
5
+ DevMem scans your codebase and generates structured context files that any AI tool can use to instantly understand your project - no more re-explaining.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - **Folder-aware output** — generates one `.md` per top-level folder, named to match your project structure
12
+ - **Targeted generation** — generate context for a specific folder, subfolder, or file with `--only`
13
+ - **Multi-provider AI** — supports Gemini, OpenAI, and Anthropic
14
+ - **Smart scanning** — ignores `node_modules`, binaries, lockfiles, and respects size limits
15
+ - **AI-optimized output** — concise, structured, bullet-point context that fits in LLM context windows
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ # Clone and install
23
+ git clone https://github.com/NikhilDhaliya/devmem.git
24
+ cd devmem
25
+ npm install
26
+ npm run build
27
+ npm link
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Usage
33
+
34
+ ### 1. Setup your AI provider
35
+
36
+ ```bash
37
+ devmem setup
38
+ ```
39
+
40
+ Choose between **Gemini**, **OpenAI**, or **Anthropic**, enter your API key, and optionally pick a model.
41
+
42
+ ```bash
43
+ # View current config
44
+ devmem setup --show
45
+
46
+ # Remove config and API key
47
+ devmem setup --remove
48
+ ```
49
+
50
+ ### 2. Generate context
51
+
52
+ Navigate to any project and run:
53
+
54
+ ```bash
55
+ devmem generate
56
+ ```
57
+
58
+ This scans your project and creates `.dev/<folder>.md` for each top-level folder:
59
+
60
+ ```
61
+ my-app/
62
+ ├── client/ → .dev/client.md
63
+ ├── server/ → .dev/server.md
64
+ ├── shared/ → .dev/shared.md
65
+ ├── package.json → .dev/root.md
66
+ ```
67
+
68
+ ### 3. Targeted generation
69
+
70
+ Generate context for specific parts of your project:
71
+
72
+ ```bash
73
+ # Single folder
74
+ devmem generate --only client
75
+
76
+ # Multiple folders
77
+ devmem generate --only "client,server"
78
+
79
+ # Subfolder or feature
80
+ devmem generate --only src/auth
81
+
82
+ # Specific file
83
+ devmem generate --only src/utils/db.ts
84
+ ```
85
+
86
+ > **Note:** Even with `--only`, DevMem sends the **full project** to the AI so it understands the complete picture, but generates documentation only for the targeted area.
87
+
88
+ ### 4. Custom output directory
89
+
90
+ ```bash
91
+ devmem generate -o context/
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Configuration
97
+
98
+ Config is stored in `~/.devmem/config.json`:
99
+
100
+ ```json
101
+ {
102
+ "provider": "gemini",
103
+ "apiKey": "your-api-key",
104
+ "model": "gemini-2.0-flash"
105
+ }
106
+ ```
107
+
108
+ ### Default models
109
+
110
+ | Provider | Default Model |
111
+ |-----------|--------------------------|
112
+ | Gemini | `gemini-2.0-flash` |
113
+ | OpenAI | `gpt-4o-mini` |
114
+ | Anthropic | `claude-3-5-haiku-latest` |
115
+
116
+ ---
117
+
118
+ ## Philosophy
119
+
120
+ DevMem is **not** an AI assistant or agent. It's a **context preservation layer** for developers:
121
+
122
+ - Scan once, reuse everywhere
123
+ - Works with ChatGPT, Claude, Gemini, or any AI tool
124
+ - Structured, compressed, AI-ready context
125
+ - No fluff, no generic explanations
126
+
127
+ ---
128
+
129
+ ## Project Structure
130
+
131
+ ```
132
+ devmem/
133
+ ├── src/
134
+ │ ├── index.ts # CLI entry point
135
+ │ ├── commands/
136
+ │ │ ├── setup.ts # Interactive provider config
137
+ │ │ └── generate.ts # Scan + AI context generation
138
+ │ └── utils/
139
+ │ ├── config.ts # ~/.devmem/config.json management
140
+ │ ├── scanner.ts # File discovery & folder grouping
141
+ │ ├── ai.ts # Multi-provider AI client
142
+ │ └── prompts.ts # Dynamic prompt generation
143
+ ├── package.json
144
+ ├── tsconfig.json
145
+ └── README.md
146
+ ```
147
+
148
+ ---
149
+
150
+ ## License
151
+
152
+ MIT
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerGenerateCommand(program: Command): void;
3
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBpC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuG9D"}
@@ -0,0 +1,105 @@
1
+ import path from 'path';
2
+ import fs from 'fs-extra';
3
+ import pc from 'picocolors';
4
+ import ora from 'ora';
5
+ import { loadConfig } from '../utils/config.js';
6
+ import { createAIClient } from '../utils/ai.js';
7
+ import { scanProjectByFolders, getAllFiles, filterByTargets, } from '../utils/scanner.js';
8
+ import { buildFolderPrompt, buildTargetedPrompt } from '../utils/prompts.js';
9
+ function formatFileContents(files) {
10
+ if (files.length === 0)
11
+ return '';
12
+ return files
13
+ .map((f) => `### ${f.relativePath}\n\`\`\`\n${f.content}\n\`\`\``)
14
+ .join('\n\n');
15
+ }
16
+ export function registerGenerateCommand(program) {
17
+ program
18
+ .command('generate')
19
+ .description('Scan codebase and generate context files')
20
+ .option('-o, --output <dir>', 'Output directory', '.dev')
21
+ .option('--only <targets>', 'Generate only for specific folders, subfolders, or files (comma-separated)')
22
+ .action(async (options) => {
23
+ const projectDir = process.cwd();
24
+ const outputDir = path.resolve(projectDir, options.output);
25
+ // Load config
26
+ let config;
27
+ try {
28
+ config = await loadConfig();
29
+ }
30
+ catch (err) {
31
+ console.log(pc.red(`\n ✗ ${err.message}\n`));
32
+ process.exit(1);
33
+ }
34
+ console.log();
35
+ console.log(pc.bold(' 🧠 DevMem Generate'));
36
+ console.log(pc.dim(' ─────────────────────'));
37
+ console.log(pc.dim(` Provider: ${config.provider} | Model: ${config.model}`));
38
+ console.log();
39
+ // Step 1: Scan full project
40
+ const scanSpinner = ora({ text: ' Scanning project...', indent: 2 }).start();
41
+ const fullScan = await scanProjectByFolders(projectDir);
42
+ const allFiles = getAllFiles(fullScan);
43
+ const folderNames = Object.keys(fullScan);
44
+ if (allFiles.length === 0) {
45
+ scanSpinner.fail(' No relevant files found.');
46
+ console.log(pc.dim(' Make sure you are in the root of a project.\n'));
47
+ return;
48
+ }
49
+ // Determine what to generate
50
+ const isTargeted = !!options.only;
51
+ let targetsToGenerate;
52
+ if (isTargeted) {
53
+ const targets = options.only.split(',').map((t) => t.trim());
54
+ targetsToGenerate = filterByTargets(fullScan, targets);
55
+ if (Object.keys(targetsToGenerate).length === 0) {
56
+ scanSpinner.fail(' No matching targets found.');
57
+ console.log(pc.dim(` Available folders: ${folderNames.join(', ')}\n`));
58
+ return;
59
+ }
60
+ const targetKeys = Object.keys(targetsToGenerate);
61
+ const targetFileCount = Object.values(targetsToGenerate).flat().length;
62
+ scanSpinner.succeed(` Found ${pc.cyan(String(allFiles.length))} total files | Targeting: ${targetKeys.map((t) => pc.yellow(t)).join(', ')} (${targetFileCount} files)`);
63
+ }
64
+ else {
65
+ targetsToGenerate = fullScan;
66
+ const folderSummary = folderNames
67
+ .map((f) => `${f}: ${fullScan[f].length}`)
68
+ .join(', ');
69
+ scanSpinner.succeed(` Found ${pc.cyan(String(allFiles.length))} files across ${pc.cyan(String(folderNames.length))} folders — ${folderSummary}`);
70
+ }
71
+ // Step 2: Generate with AI
72
+ const ai = createAIClient(config);
73
+ await fs.ensureDir(outputDir);
74
+ // Full project context (used for targeted generation)
75
+ const fullContext = formatFileContents(allFiles);
76
+ for (const [folderKey, files] of Object.entries(targetsToGenerate)) {
77
+ const spinner = ora({ text: ` Generating ${pc.cyan(folderKey)} context...`, indent: 2 }).start();
78
+ try {
79
+ let prompt;
80
+ let context;
81
+ if (isTargeted) {
82
+ // Targeted: send FULL project as context, but prompt asks for specific target only
83
+ prompt = buildTargetedPrompt(folderKey);
84
+ context = fullContext;
85
+ }
86
+ else {
87
+ // Full scan: send only the folder's files
88
+ prompt = buildFolderPrompt(folderKey);
89
+ context = formatFileContents(files);
90
+ }
91
+ const result = await ai.summarize(prompt, context);
92
+ const outPath = path.join(outputDir, `${folderKey}.md`);
93
+ await fs.writeFile(outPath, result, 'utf-8');
94
+ spinner.succeed(` ${folderKey} → ${pc.green(path.relative(projectDir, outPath))}`);
95
+ }
96
+ catch (err) {
97
+ spinner.fail(` ${folderKey} failed: ${err.message}`);
98
+ }
99
+ }
100
+ console.log();
101
+ console.log(pc.green(pc.bold(' ✓ Context files generated!')));
102
+ console.log(pc.dim(` Output: ${path.relative(projectDir, outputDir)}/\n`));
103
+ });
104
+ }
105
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerSetupCommand(program: Command): void;
3
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0F3D"}
@@ -0,0 +1,96 @@
1
+ import readline from 'readline';
2
+ import pc from 'picocolors';
3
+ import { saveConfig, loadConfig, maskKey, DEFAULT_MODELS } from '../utils/config.js';
4
+ function createRL() {
5
+ return readline.createInterface({
6
+ input: process.stdin,
7
+ output: process.stdout,
8
+ });
9
+ }
10
+ function ask(rl, question) {
11
+ return new Promise((resolve) => {
12
+ rl.question(question, (answer) => resolve(answer.trim()));
13
+ });
14
+ }
15
+ export function registerSetupCommand(program) {
16
+ program
17
+ .command('setup')
18
+ .description('Configure your AI provider and API key')
19
+ .option('--show', 'Show current configuration')
20
+ .option('--remove', 'Remove current configuration and API key')
21
+ .action(async (options) => {
22
+ if (options.remove) {
23
+ try {
24
+ await import('../utils/config.js').then(m => m.removeConfig());
25
+ console.log(pc.green('\n ✓ Configuration and API key removed successfully.\n'));
26
+ }
27
+ catch (err) {
28
+ console.log(pc.red(`\n ✗ Failed to remove configuration: ${err.message}\n`));
29
+ }
30
+ return;
31
+ }
32
+ if (options.show) {
33
+ try {
34
+ const config = await loadConfig();
35
+ console.log();
36
+ console.log(pc.bold(' DevMem Configuration'));
37
+ console.log(pc.dim(' ─────────────────────'));
38
+ console.log(` Provider : ${pc.cyan(config.provider)}`);
39
+ console.log(` Model : ${pc.cyan(config.model)}`);
40
+ console.log(` API Key : ${pc.yellow(maskKey(config.apiKey))}`);
41
+ console.log();
42
+ }
43
+ catch {
44
+ console.log(pc.red('\n ✗ No configuration found. Run `devmem setup` first.\n'));
45
+ }
46
+ return;
47
+ }
48
+ const rl = createRL();
49
+ try {
50
+ console.log();
51
+ console.log(pc.bold(' 🧠 DevMem Setup'));
52
+ console.log(pc.dim(' ─────────────────'));
53
+ console.log();
54
+ // 1. Choose provider
55
+ console.log(pc.dim(' Available providers:'));
56
+ console.log(` ${pc.cyan('1')} — Gemini`);
57
+ console.log(` ${pc.cyan('2')} — OpenAI`);
58
+ console.log(` ${pc.cyan('3')} — Anthropic`);
59
+ console.log();
60
+ let providerChoice = '';
61
+ while (!['1', '2', '3'].includes(providerChoice)) {
62
+ providerChoice = await ask(rl, pc.bold(' Select provider (1/2/3): '));
63
+ }
64
+ const providerMap = {
65
+ '1': 'gemini',
66
+ '2': 'openai',
67
+ '3': 'anthropic',
68
+ };
69
+ const provider = providerMap[providerChoice];
70
+ // 2. Enter API key
71
+ console.log();
72
+ const apiKey = await ask(rl, pc.bold(` Enter your ${provider} API key: `));
73
+ if (!apiKey) {
74
+ console.log(pc.red('\n ✗ API key cannot be empty.\n'));
75
+ rl.close();
76
+ return;
77
+ }
78
+ // 3. Choose model
79
+ const defaultModel = DEFAULT_MODELS[provider];
80
+ console.log();
81
+ const modelInput = await ask(rl, pc.bold(` Model ${pc.dim(`(default: ${defaultModel})`)}: `));
82
+ const model = modelInput || defaultModel;
83
+ // Save
84
+ const config = { provider, apiKey, model };
85
+ await saveConfig(config);
86
+ console.log();
87
+ console.log(pc.green(' ✓ Configuration saved!'));
88
+ console.log(pc.dim(` Provider: ${provider} | Model: ${model}`));
89
+ console.log();
90
+ }
91
+ finally {
92
+ rl.close();
93
+ }
94
+ });
95
+ }
96
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { registerSetupCommand } from './commands/setup.js';
4
+ import { registerGenerateCommand } from './commands/generate.js';
5
+ const program = new Command();
6
+ program
7
+ .name('devmem')
8
+ .description('Generate persistent, domain-specific context files for AI tools')
9
+ .version('1.0.0');
10
+ registerSetupCommand(program);
11
+ registerGenerateCommand(program);
12
+ program.parse();
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,iEAAiE,CAAC;KAC9E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAEjC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { DevMemConfig } from './config.js';
2
+ export interface AIClient {
3
+ summarize(prompt: string, fileContents: string): Promise<string>;
4
+ }
5
+ export declare function createAIClient(config: DevMemConfig): AIClient;
6
+ //# sourceMappingURL=ai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/utils/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAM3C,MAAM,WAAW,QAAQ;IACvB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAClE;AAwDD,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,QAAQ,CAW7D"}
@@ -0,0 +1,65 @@
1
+ import { GoogleGenerativeAI } from '@google/generative-ai';
2
+ import OpenAI from 'openai';
3
+ import Anthropic from '@anthropic-ai/sdk';
4
+ import { SYSTEM_PROMPT } from './prompts.js';
5
+ function createGeminiClient(config) {
6
+ const genAI = new GoogleGenerativeAI(config.apiKey);
7
+ const model = genAI.getGenerativeModel({ model: config.model });
8
+ return {
9
+ async summarize(prompt, fileContents) {
10
+ const result = await model.generateContent([
11
+ { text: SYSTEM_PROMPT },
12
+ { text: prompt },
13
+ { text: `\n\n--- SOURCE FILES ---\n\n${fileContents}` },
14
+ ]);
15
+ return result.response.text();
16
+ },
17
+ };
18
+ }
19
+ function createOpenAIClient(config) {
20
+ const client = new OpenAI({ apiKey: config.apiKey });
21
+ return {
22
+ async summarize(prompt, fileContents) {
23
+ const response = await client.chat.completions.create({
24
+ model: config.model,
25
+ messages: [
26
+ { role: 'system', content: SYSTEM_PROMPT },
27
+ { role: 'user', content: `${prompt}\n\n--- SOURCE FILES ---\n\n${fileContents}` },
28
+ ],
29
+ temperature: 0.3,
30
+ max_tokens: 4096,
31
+ });
32
+ return response.choices[0]?.message?.content ?? '';
33
+ },
34
+ };
35
+ }
36
+ function createAnthropicClient(config) {
37
+ const client = new Anthropic({ apiKey: config.apiKey });
38
+ return {
39
+ async summarize(prompt, fileContents) {
40
+ const response = await client.messages.create({
41
+ model: config.model,
42
+ max_tokens: 4096,
43
+ system: SYSTEM_PROMPT,
44
+ messages: [
45
+ { role: 'user', content: `${prompt}\n\n--- SOURCE FILES ---\n\n${fileContents}` },
46
+ ],
47
+ });
48
+ const block = response.content[0];
49
+ return block.type === 'text' ? block.text : '';
50
+ },
51
+ };
52
+ }
53
+ export function createAIClient(config) {
54
+ switch (config.provider) {
55
+ case 'gemini':
56
+ return createGeminiClient(config);
57
+ case 'openai':
58
+ return createOpenAIClient(config);
59
+ case 'anthropic':
60
+ return createAnthropicClient(config);
61
+ default:
62
+ throw new Error(`Unsupported provider: ${config.provider}`);
63
+ }
64
+ }
65
+ //# sourceMappingURL=ai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/utils/ai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface DevMemConfig {
2
+ provider: 'gemini' | 'openai' | 'anthropic';
3
+ apiKey: string;
4
+ model: string;
5
+ }
6
+ export declare function getConfigPath(): string;
7
+ export declare function loadConfig(): Promise<DevMemConfig>;
8
+ export declare function saveConfig(config: DevMemConfig): Promise<void>;
9
+ export declare function removeConfig(): Promise<void>;
10
+ export declare function maskKey(key: string): string;
11
+ export declare const DEFAULT_MODELS: Record<string, string>;
12
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAKD,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAGD,wBAAsB,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC,CAiBxD;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG3C;AAED,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIjD,CAAC"}
@@ -0,0 +1,37 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ const CONFIG_DIR = path.join(os.homedir(), '.devmem');
5
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
6
+ export function getConfigPath() {
7
+ return CONFIG_FILE;
8
+ }
9
+ export async function loadConfig() {
10
+ const exists = await fs.pathExists(CONFIG_FILE);
11
+ if (!exists) {
12
+ throw new Error('DevMem is not configured yet. Run `devmem setup` first.');
13
+ }
14
+ const raw = await fs.readJSON(CONFIG_FILE);
15
+ if (!raw.provider || !raw.apiKey) {
16
+ throw new Error('Invalid config. Run `devmem setup` to reconfigure.');
17
+ }
18
+ return raw;
19
+ }
20
+ export async function saveConfig(config) {
21
+ await fs.ensureDir(CONFIG_DIR);
22
+ await fs.writeJSON(CONFIG_FILE, config, { spaces: 2 });
23
+ }
24
+ export async function removeConfig() {
25
+ await fs.remove(CONFIG_FILE);
26
+ }
27
+ export function maskKey(key) {
28
+ if (key.length <= 8)
29
+ return '****';
30
+ return key.slice(0, 4) + '...' + key.slice(-4);
31
+ }
32
+ export const DEFAULT_MODELS = {
33
+ gemini: 'gemini-2.0-flash',
34
+ openai: 'gpt-4o-mini',
35
+ anthropic: 'claude-3-5-haiku-latest',
36
+ };
37
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAQpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AACtD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEzD,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC;AAGD,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,yDAAyD,CAC1D,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAE3C,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,oDAAoD,CACrD,CAAC;IACJ,CAAC;IAED,OAAO,GAAmB,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAoB;IACnD,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IACnC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,MAAM,EAAE,kBAAkB;IAC1B,MAAM,EAAE,aAAa;IACrB,SAAS,EAAE,yBAAyB;CACrC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare const SYSTEM_PROMPT = "You are DevMem, a context extraction engine. Your job is to analyze source code and produce structured, concise, AI-ready context documentation.\n\nRules:\n- Include only high-signal information: architecture, patterns, structure, conventions\n- Preserve actual project decisions \u2014 do not assume or generalize beyond the codebase\n- Optimize for AI usage: concise, structured, no fluff\n- Prefer bullet points\n- Keep output concise enough to fit in an LLM context window\n- Do NOT generate code\n- Do NOT hallucinate missing details\n- Do NOT include low-value information";
2
+ /**
3
+ * Build a context-generation prompt for a specific folder/target.
4
+ */
5
+ export declare function buildFolderPrompt(folderName: string): string;
6
+ /**
7
+ * Build a prompt that provides full project context but asks to generate
8
+ * documentation only for a specific target (folder, subfolder, or file).
9
+ */
10
+ export declare function buildTargetedPrompt(targetName: string): string;
11
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,ukBAUa,CAAC;AAExC;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAiB5D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAmB9D"}
@@ -0,0 +1,60 @@
1
+ export const SYSTEM_PROMPT = `You are DevMem, a context extraction engine. Your job is to analyze source code and produce structured, concise, AI-ready context documentation.
2
+
3
+ Rules:
4
+ - Include only high-signal information: architecture, patterns, structure, conventions
5
+ - Preserve actual project decisions — do not assume or generalize beyond the codebase
6
+ - Optimize for AI usage: concise, structured, no fluff
7
+ - Prefer bullet points
8
+ - Keep output concise enough to fit in an LLM context window
9
+ - Do NOT generate code
10
+ - Do NOT hallucinate missing details
11
+ - Do NOT include low-value information`;
12
+ /**
13
+ * Build a context-generation prompt for a specific folder/target.
14
+ */
15
+ export function buildFolderPrompt(folderName) {
16
+ return `Analyze the following source files from the "${folderName}" part of the project and generate a structured context document.
17
+
18
+ Include:
19
+ - Tech stack and frameworks used in this area
20
+ - Folder structure overview
21
+ - Key patterns and conventions
22
+ - Important modules/components and their responsibilities
23
+ - How this area connects to other parts of the project
24
+ - Any notable design decisions or constraints
25
+
26
+ Avoid:
27
+ - Trivial descriptions
28
+ - Listing every single file
29
+ - Generic explanations not specific to this codebase
30
+
31
+ Output a clean markdown document titled "# ${capitalize(folderName)} Context".`;
32
+ }
33
+ /**
34
+ * Build a prompt that provides full project context but asks to generate
35
+ * documentation only for a specific target (folder, subfolder, or file).
36
+ */
37
+ export function buildTargetedPrompt(targetName) {
38
+ return `You are given the FULL project source code for context. However, generate documentation ONLY for the "${targetName}" part of the project.
39
+
40
+ Use the full codebase to understand relationships, dependencies, imports, and how this area fits into the bigger picture, but ONLY document "${targetName}".
41
+
42
+ Include:
43
+ - Tech stack and frameworks used in this specific area
44
+ - Structure overview
45
+ - Key patterns and conventions
46
+ - Important modules/components and their responsibilities
47
+ - How this area connects to other parts of the project
48
+ - Dependencies and relationships with other parts of the codebase
49
+
50
+ Avoid:
51
+ - Documenting parts of the project outside "${targetName}"
52
+ - Trivial descriptions
53
+ - Generic explanations not specific to this codebase
54
+
55
+ Output a clean markdown document titled "# ${capitalize(targetName)} Context".`;
56
+ }
57
+ function capitalize(s) {
58
+ return s.charAt(0).toUpperCase() + s.slice(1);
59
+ }
60
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;uCAUU,CAAC;AAExC;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB;IAClD,OAAO,gDAAgD,UAAU;;;;;;;;;;;;;;;6CAetB,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC;AAChF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAkB;IACpD,OAAO,yGAAyG,UAAU;;+IAEmB,UAAU;;;;;;;;;;;8CAW3G,UAAU;;;;6CAIX,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC;AAChF,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,21 @@
1
+ export interface FileEntry {
2
+ relativePath: string;
3
+ content: string;
4
+ }
5
+ /** Map of folder name → files in that folder */
6
+ export type FolderScanResult = Record<string, FileEntry[]>;
7
+ /**
8
+ * Scan a project and group files by their top-level folder.
9
+ * Root-level files are grouped under "root".
10
+ */
11
+ export declare function scanProjectByFolders(projectDir: string): Promise<FolderScanResult>;
12
+ /**
13
+ * Get all files from a FolderScanResult as a flat list.
14
+ */
15
+ export declare function getAllFiles(scan: FolderScanResult): FileEntry[];
16
+ /**
17
+ * Filter a scan result to only include specific targets.
18
+ * Targets can be top-level folder names, subfolder paths, or file paths.
19
+ */
20
+ export declare function filterByTargets(scan: FolderScanResult, targets: string[]): FolderScanResult;
21
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/utils/scanner.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gDAAgD;AAChD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;AA8B3D;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAsCxF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAE/D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,MAAM,EAAE,GAChB,gBAAgB,CAmClB"}
@@ -0,0 +1,106 @@
1
+ import { glob } from 'glob';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ const IGNORE_PATTERNS = [
5
+ 'node_modules/**',
6
+ 'dist/**',
7
+ 'build/**',
8
+ '.next/**',
9
+ '.git/**',
10
+ '.dev/**',
11
+ '*.lock',
12
+ 'package-lock.json',
13
+ 'yarn.lock',
14
+ 'pnpm-lock.yaml',
15
+ '*.map',
16
+ '*.min.*',
17
+ '.env',
18
+ '.env.*',
19
+ '!.env.example',
20
+ ];
21
+ const BINARY_EXTENSIONS = new Set([
22
+ '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.webp',
23
+ '.woff', '.woff2', '.ttf', '.eot', '.otf',
24
+ '.mp4', '.webm', '.mp3', '.wav', '.ogg',
25
+ '.pdf', '.zip', '.tar', '.gz', '.bz2',
26
+ '.exe', '.dll', '.so', '.dylib',
27
+ ]);
28
+ const MAX_FILE_SIZE = 50 * 1024; // 50KB
29
+ /**
30
+ * Scan a project and group files by their top-level folder.
31
+ * Root-level files are grouped under "root".
32
+ */
33
+ export async function scanProjectByFolders(projectDir) {
34
+ const files = await glob('**/*', {
35
+ cwd: projectDir,
36
+ nodir: true,
37
+ ignore: IGNORE_PATTERNS,
38
+ dot: false,
39
+ });
40
+ const result = {};
41
+ for (const file of files) {
42
+ const absPath = path.join(projectDir, file);
43
+ // Skip large files
44
+ const stat = await fs.stat(absPath);
45
+ if (stat.size > MAX_FILE_SIZE)
46
+ continue;
47
+ // Skip binary files
48
+ const ext = path.extname(file).toLowerCase();
49
+ if (BINARY_EXTENSIONS.has(ext))
50
+ continue;
51
+ // Determine the top-level folder (or "root")
52
+ const parts = file.split(path.sep);
53
+ const folderKey = parts.length > 1 ? parts[0] : 'root';
54
+ try {
55
+ const content = await fs.readFile(absPath, 'utf-8');
56
+ if (!result[folderKey]) {
57
+ result[folderKey] = [];
58
+ }
59
+ result[folderKey].push({ relativePath: file, content });
60
+ }
61
+ catch {
62
+ // Skip unreadable files
63
+ }
64
+ }
65
+ return result;
66
+ }
67
+ /**
68
+ * Get all files from a FolderScanResult as a flat list.
69
+ */
70
+ export function getAllFiles(scan) {
71
+ return Object.values(scan).flat();
72
+ }
73
+ /**
74
+ * Filter a scan result to only include specific targets.
75
+ * Targets can be top-level folder names, subfolder paths, or file paths.
76
+ */
77
+ export function filterByTargets(scan, targets) {
78
+ const filtered = {};
79
+ for (const target of targets) {
80
+ const normalizedTarget = target.replace(/\/$/, ''); // remove trailing slash
81
+ // 1. Exact top-level folder match
82
+ if (scan[normalizedTarget]) {
83
+ filtered[normalizedTarget] = scan[normalizedTarget];
84
+ continue;
85
+ }
86
+ // 2. Subfolder or file match — search across all folders
87
+ for (const [folder, files] of Object.entries(scan)) {
88
+ const matching = files.filter((f) => {
89
+ // Match if the file path starts with the target (subfolder)
90
+ // or equals the target (exact file)
91
+ return (f.relativePath === normalizedTarget ||
92
+ f.relativePath.startsWith(normalizedTarget + '/'));
93
+ });
94
+ if (matching.length > 0) {
95
+ // Use the target as the key for the output file name
96
+ const key = normalizedTarget.replace(/\//g, '-');
97
+ if (!filtered[key]) {
98
+ filtered[key] = [];
99
+ }
100
+ filtered[key].push(...matching);
101
+ }
102
+ }
103
+ }
104
+ return filtered;
105
+ }
106
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/utils/scanner.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "devmem",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool that scans a codebase and generates persistent, domain-specific context files for AI tools",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "devmem": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx src/index.ts",
13
+ "start": "node dist/index.js"
14
+ },
15
+ "keywords": [
16
+ "cli",
17
+ "ai",
18
+ "context",
19
+ "devmem",
20
+ "llm",
21
+ "developer-tools",
22
+ "codebase-analysis"
23
+ ],
24
+ "author": "nikhildhaliya",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/NikhilDhaliya/devmem.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/NikhilDhaliya/devmem/issues"
32
+ },
33
+ "homepage": "https://github.com/NikhilDhaliya/devmem#readme",
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "engines": {
40
+ "node": ">=18"
41
+ },
42
+ "dependencies": {
43
+ "@anthropic-ai/sdk": "^0.80.0",
44
+ "@google/generative-ai": "^0.24.1",
45
+ "commander": "^14.0.3",
46
+ "fs-extra": "^11.3.4",
47
+ "glob": "^13.0.6",
48
+ "openai": "^6.33.0",
49
+ "ora": "^9.3.0",
50
+ "picocolors": "^1.1.1"
51
+ },
52
+ "devDependencies": {
53
+ "@types/fs-extra": "^11.0.4",
54
+ "@types/node": "^25.5.0",
55
+ "tsx": "^4.21.0",
56
+ "typescript": "^6.0.2"
57
+ }
58
+ }