aiknowsys 0.0.1

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.
@@ -0,0 +1,418 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import { getPackageDir } from '../utils.js';
6
+
7
+ export async function scan(options) {
8
+ const targetDir = path.resolve(options.dir);
9
+ const outputFile = options.output;
10
+
11
+ console.log('');
12
+ console.log(chalk.cyan.bold('🔍 Scanning Codebase...'));
13
+ console.log('');
14
+
15
+ const projectName = path.basename(targetDir);
16
+ console.log(chalk.blue(`📁 Project: ${projectName}`));
17
+ console.log('');
18
+
19
+ const spinner = ora('Detecting project configuration...').start();
20
+
21
+ const findings = {
22
+ projectName,
23
+ frontendFramework: '',
24
+ backendFramework: '',
25
+ language: '',
26
+ buildTool: '',
27
+ testFramework: '',
28
+ packageManager: '',
29
+ database: '',
30
+ testCommands: [],
31
+ lintCommands: [],
32
+ typeCheckCommands: [],
33
+ hasOpenSpec: false,
34
+ openSpecVersion: ''
35
+ };
36
+
37
+ try {
38
+ // Detect package.json (Node.js projects)
39
+ const packageJsonPath = path.join(targetDir, 'package.json');
40
+ if (fs.existsSync(packageJsonPath)) {
41
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
42
+ findings.packageManager = 'npm';
43
+
44
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
45
+
46
+ // Detect frontend framework
47
+ if (deps.vue) findings.frontendFramework = `Vue ${deps.vue}`;
48
+ else if (deps.react) findings.frontendFramework = `React ${deps.react}`;
49
+ else if (deps['@angular/core']) findings.frontendFramework = 'Angular';
50
+ else if (deps.svelte) findings.frontendFramework = 'Svelte';
51
+
52
+ // Detect build tool
53
+ if (deps.vite) findings.buildTool = 'Vite';
54
+ else if (deps.webpack) findings.buildTool = 'Webpack';
55
+ else if (deps.next) findings.buildTool = 'Next.js';
56
+
57
+ // Detect test framework
58
+ if (deps.vitest) {
59
+ findings.testFramework = 'Vitest';
60
+ if (pkg.scripts?.test) findings.testCommands.push('npm test');
61
+ else if (pkg.scripts?.['test:run']) findings.testCommands.push('npm run test:run');
62
+ } else if (deps.jest) {
63
+ findings.testFramework = 'Jest';
64
+ findings.testCommands.push('npm test');
65
+ }
66
+
67
+ // Detect type checking
68
+ if (pkg.scripts?.['type-check']) {
69
+ findings.typeCheckCommands.push('npm run type-check');
70
+ }
71
+
72
+ // Detect linting
73
+ if (pkg.scripts?.lint) {
74
+ findings.lintCommands.push('npm run lint');
75
+ }
76
+ }
77
+
78
+ // Detect TypeScript
79
+ if (fs.existsSync(path.join(targetDir, 'tsconfig.json'))) {
80
+ findings.language = 'TypeScript';
81
+ if (findings.typeCheckCommands.length === 0) {
82
+ findings.typeCheckCommands.push('npx tsc --noEmit');
83
+ }
84
+ }
85
+
86
+ // Detect Python
87
+ const pyprojectPath = path.join(targetDir, 'pyproject.toml');
88
+ const requirementsPath = path.join(targetDir, 'requirements.txt');
89
+
90
+ if (fs.existsSync(pyprojectPath) || fs.existsSync(requirementsPath)) {
91
+ findings.language = findings.language || 'Python';
92
+ findings.packageManager = 'pip';
93
+
94
+ let pyContent = '';
95
+ if (fs.existsSync(pyprojectPath)) {
96
+ pyContent = fs.readFileSync(pyprojectPath, 'utf-8');
97
+ }
98
+ if (fs.existsSync(requirementsPath)) {
99
+ pyContent += fs.readFileSync(requirementsPath, 'utf-8');
100
+ }
101
+
102
+ if (pyContent.includes('django')) {
103
+ findings.backendFramework = 'Django';
104
+ findings.testCommands.push('python manage.py test');
105
+ } else if (pyContent.includes('fastapi')) {
106
+ findings.backendFramework = 'FastAPI';
107
+ findings.testCommands.push('pytest');
108
+ } else if (pyContent.includes('flask')) {
109
+ findings.backendFramework = 'Flask';
110
+ findings.testCommands.push('pytest');
111
+ }
112
+
113
+ if (pyContent.includes('pytest')) {
114
+ findings.testFramework = 'pytest';
115
+ if (!findings.testCommands.includes('pytest')) {
116
+ findings.testCommands.push('pytest');
117
+ }
118
+ }
119
+
120
+ if (pyContent.includes('mypy')) {
121
+ findings.typeCheckCommands.push('mypy .');
122
+ }
123
+
124
+ if (pyContent.includes('ruff')) {
125
+ findings.lintCommands.push('ruff check .');
126
+ } else if (pyContent.includes('flake8')) {
127
+ findings.lintCommands.push('flake8');
128
+ }
129
+ }
130
+
131
+ // Detect Rust
132
+ if (fs.existsSync(path.join(targetDir, 'Cargo.toml'))) {
133
+ findings.language = 'Rust';
134
+ findings.packageManager = 'cargo';
135
+ findings.testCommands.push('cargo test');
136
+ findings.typeCheckCommands.push('cargo check');
137
+ findings.lintCommands.push('cargo clippy');
138
+ }
139
+
140
+ // Detect Go
141
+ if (fs.existsSync(path.join(targetDir, 'go.mod'))) {
142
+ findings.language = 'Go';
143
+ findings.packageManager = 'go mod';
144
+ findings.testCommands.push('go test ./...');
145
+ findings.lintCommands.push('golangci-lint run');
146
+ }
147
+
148
+ // Detect Docker
149
+ if (fs.existsSync(path.join(targetDir, 'docker-compose.yml')) ||
150
+ fs.existsSync(path.join(targetDir, 'docker-compose.yaml'))) {
151
+ findings.containerPlatform = 'Docker Compose';
152
+ } else if (fs.existsSync(path.join(targetDir, 'Dockerfile'))) {
153
+ findings.containerPlatform = 'Docker';
154
+ }
155
+
156
+ // Detect OpenSpec
157
+ const openSpecDir = path.join(targetDir, 'openspec');
158
+ if (fs.existsSync(openSpecDir) && fs.existsSync(path.join(openSpecDir, 'project.md'))) {
159
+ findings.hasOpenSpec = true;
160
+ // Try to detect version from package.json or openspec config
161
+ const openSpecPkgPath = path.join(targetDir, 'node_modules', 'openspec', 'package.json');
162
+ if (fs.existsSync(openSpecPkgPath)) {
163
+ try {
164
+ const openSpecPkg = JSON.parse(fs.readFileSync(openSpecPkgPath, 'utf-8'));
165
+ findings.openSpecVersion = openSpecPkg.version || '';
166
+ } catch (e) {
167
+ // Ignore version detection errors
168
+ }
169
+ }
170
+ }
171
+
172
+ spinner.succeed('Project analysis complete');
173
+
174
+ // Display findings
175
+ console.log('');
176
+ console.log(chalk.white.bold('📊 Detected Configuration:'));
177
+ console.log('');
178
+ if (findings.language) console.log(chalk.gray(` Language: ${findings.language}`));
179
+ if (findings.frontendFramework) console.log(chalk.gray(` Frontend: ${findings.frontendFramework}`));
180
+ if (findings.backendFramework) console.log(chalk.gray(` Backend: ${findings.backendFramework}`));
181
+ if (findings.buildTool) console.log(chalk.gray(` Build Tool: ${findings.buildTool}`));
182
+ if (findings.testFramework) console.log(chalk.gray(` Test Runner: ${findings.testFramework}`));
183
+ if (findings.packageManager) console.log(chalk.gray(` Package Mgr: ${findings.packageManager}`));
184
+ if (findings.hasOpenSpec) {
185
+ const version = findings.openSpecVersion ? ` (v${findings.openSpecVersion})` : '';
186
+ console.log(chalk.gray(` OpenSpec: Detected${version}`));
187
+ }
188
+ console.log('');
189
+
190
+ // Generate draft ESSENTIALS
191
+ const draftSpinner = ora('Generating draft CODEBASE_ESSENTIALS...').start();
192
+
193
+ const draft = generateEssentialsDraft(findings);
194
+ // Support both relative and absolute output paths
195
+ const outputPath = path.isAbsolute(outputFile) ? outputFile : path.join(targetDir, outputFile);
196
+ fs.writeFileSync(outputPath, draft);
197
+
198
+ draftSpinner.succeed(`Generated ${outputFile}`);
199
+
200
+ console.log('');
201
+ console.log(chalk.yellow.bold('📝 Next Steps:'));
202
+ console.log(chalk.white(` 1. Review and complete TODO sections in ${outputFile}`));
203
+ console.log(chalk.white(` 2. Rename to CODEBASE_ESSENTIALS.md when ready`));
204
+ console.log(chalk.white(` 3. Run: ${chalk.cyan('npx aiknowsys install-agents')}`));
205
+ console.log('');
206
+
207
+ return findings;
208
+
209
+ } catch (error) {
210
+ spinner.fail('Scan failed');
211
+ console.error(chalk.red(error.message));
212
+ process.exit(1);
213
+ }
214
+ }
215
+
216
+ function generateEssentialsDraft(findings) {
217
+ const date = new Date().toLocaleDateString('en-US', {
218
+ year: 'numeric', month: 'long', day: 'numeric'
219
+ });
220
+
221
+ let techStack = '';
222
+ if (findings.frontendFramework) {
223
+ techStack += `| Frontend | ${findings.frontendFramework} |\n`;
224
+ }
225
+ if (findings.backendFramework) {
226
+ techStack += `| Backend | ${findings.backendFramework} |\n`;
227
+ }
228
+ if (findings.language) {
229
+ techStack += `| Language | ${findings.language} |\n`;
230
+ }
231
+ if (findings.buildTool) {
232
+ techStack += `| Build Tool | ${findings.buildTool} |\n`;
233
+ }
234
+ if (findings.testFramework) {
235
+ techStack += `| Testing | ${findings.testFramework} |\n`;
236
+ }
237
+ if (findings.packageManager) {
238
+ techStack += `| Package Manager | ${findings.packageManager} |\n`;
239
+ }
240
+
241
+ let validationMatrix = '';
242
+ for (const cmd of findings.testCommands) {
243
+ validationMatrix += `| \`${cmd}\` | Tests | All tests must pass |\n`;
244
+ }
245
+ for (const cmd of findings.typeCheckCommands) {
246
+ validationMatrix += `| \`${cmd}\` | Type Check | No type errors |\n`;
247
+ }
248
+ for (const cmd of findings.lintCommands) {
249
+ validationMatrix += `| \`${cmd}\` | Lint | No lint errors |\n`;
250
+ }
251
+
252
+ if (!validationMatrix) {
253
+ validationMatrix = '| `TODO: Add test command` | Tests | All tests must pass |\n';
254
+ }
255
+
256
+ return `# ${findings.projectName} - Codebase Essentials
257
+
258
+ > **Last Updated:** ${date}
259
+ > **Status:** DRAFT - Complete TODO sections before using
260
+
261
+ ---
262
+
263
+ ## 1. Technology Snapshot
264
+
265
+ | Component | Technology |
266
+ |-----------|------------|
267
+ ${techStack || '| TODO | Add your stack |\n'}
268
+
269
+ ---
270
+
271
+ ## 2. Validation Matrix
272
+
273
+ | Command | Purpose | Expected |
274
+ |---------|---------|----------|
275
+ ${validationMatrix}
276
+
277
+ ---
278
+
279
+ ## 3. Core Patterns
280
+
281
+ <!-- TODO: Document how your project handles common concerns -->
282
+
283
+ ### API Calls
284
+ \`\`\`
285
+ TODO: How do you make API calls? What's the standard pattern?
286
+ Example: useApi() composable, axios instance, fetch wrapper, etc.
287
+ \`\`\`
288
+
289
+ ### State Management
290
+ \`\`\`
291
+ TODO: How is state managed?
292
+ Example: Pinia stores, Redux, Context API, etc.
293
+ \`\`\`
294
+
295
+ ### Authentication
296
+ \`\`\`
297
+ TODO: How does auth work?
298
+ Example: JWT tokens, session cookies, OAuth flow, etc.
299
+ \`\`\`
300
+
301
+ ### Error Handling
302
+ \`\`\`
303
+ TODO: Standard error handling pattern
304
+ Example: Global error boundary, toast notifications, error logging, etc.
305
+ \`\`\`
306
+
307
+ ---
308
+
309
+ ## 4. Critical Invariants
310
+
311
+ <!-- TODO: Rules that must NEVER be violated -->
312
+
313
+ 1. **TODO:** Add your first invariant
314
+ - Example: "All API endpoints must be authenticated except /public/*"
315
+
316
+ 2. **TODO:** Add another invariant
317
+ - Example: "Database migrations must be backwards-compatible"
318
+
319
+ 3. **TODO:** Add testing requirement
320
+ - Example: "All new features must have tests before merging"
321
+
322
+ ---
323
+
324
+ ## 5. Common Gotchas
325
+
326
+ <!-- TODO: Things that trip up new contributors -->
327
+
328
+ 1. **TODO:** First common gotcha
329
+ - Example: "Run \`npm install\` after pulling - we update deps frequently"
330
+
331
+ 2. **TODO:** Second common gotcha
332
+ - Example: "The dev database resets on restart - use \`npm run seed\` to restore data"
333
+
334
+ ---
335
+
336
+ ## 6. Quick Reference
337
+
338
+ ### Development Setup
339
+ \`\`\`bash
340
+ # TODO: Add your setup commands
341
+ # Example:
342
+ # npm install
343
+ # cp .env.example .env
344
+ # npm run dev
345
+ \`\`\`
346
+
347
+ ### Running Tests
348
+ \`\`\`bash
349
+ ${findings.testCommands.join('\n') || '# TODO: Add test commands'}
350
+ \`\`\`
351
+
352
+ ---
353
+
354
+ ## 7. Architecture Decisions
355
+
356
+ <!-- TODO: Key decisions and their rationale -->
357
+
358
+ ### Why ${findings.frontendFramework || findings.backendFramework || 'this stack'}?
359
+ TODO: Explain why you chose this technology
360
+
361
+ ### Project Structure
362
+ TODO: Brief overview of folder organization
363
+
364
+ ---
365
+
366
+ ## 8. Change Management (OpenSpec)
367
+
368
+ ${findings.hasOpenSpec ? `**✅ OpenSpec Detected** - This project uses spec-driven development.
369
+
370
+ **Commands:**
371
+ \`\`\`bash
372
+ openspec list # List active changes
373
+ openspec list --specs # List specifications
374
+ openspec validate --strict # Validate all specs
375
+ \`\`\`
376
+
377
+ **Workflow:**
378
+ 1. Create proposal: \`openspec create add-feature-name\`
379
+ 2. Fill out \`proposal.md\` and \`tasks.md\`
380
+ 3. Validate: \`openspec validate add-feature-name --strict\`
381
+ 4. Get approval, then implement
382
+ 5. Archive after deployment
383
+
384
+ **See:** \`openspec/AGENTS.md\` for full workflow.
385
+ ` : `**Recommended:** Consider using OpenSpec for spec-driven development.
386
+
387
+ OpenSpec helps manage:
388
+ - Breaking changes and API contracts
389
+ - Architecture decisions with proposals
390
+ - Feature planning with structured tasks
391
+ - Change tracking and archiving
392
+
393
+ **Setup:**
394
+ \`\`\`bash
395
+ npm install -g openspec # Install CLI
396
+ openspec init # Initialize in project
397
+ \`\`\`
398
+
399
+ **When to use OpenSpec proposals:**
400
+ - New features or capabilities
401
+ - Breaking changes (API, schema)
402
+ - Architecture changes
403
+ - Security-related changes
404
+
405
+ **Skip proposals for:**
406
+ - Bug fixes, typos, formatting
407
+ - Non-breaking dependency updates
408
+ - Configuration changes
409
+
410
+ **Learn more:** https://github.com/your-org/openspec
411
+ `}
412
+
413
+ ---
414
+
415
+ *This file is the single source of truth for AI assistants working on this project.*
416
+ *Keep it updated and concise.*
417
+ `;
418
+ }
package/lib/utils.js ADDED
@@ -0,0 +1,93 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ /**
6
+ * Get the package installation directory
7
+ */
8
+ export function getPackageDir() {
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+ return path.resolve(__dirname, '..');
12
+ }
13
+
14
+ /**
15
+ * Check if directory has an existing project
16
+ */
17
+ export function hasExistingProject(dir) {
18
+ const indicators = [
19
+ 'src',
20
+ 'backend',
21
+ 'frontend',
22
+ 'package.json',
23
+ 'pyproject.toml',
24
+ 'Cargo.toml',
25
+ 'go.mod',
26
+ 'pom.xml',
27
+ 'build.gradle'
28
+ ];
29
+
30
+ for (const indicator of indicators) {
31
+ if (fs.existsSync(path.join(dir, indicator))) {
32
+ return true;
33
+ }
34
+ }
35
+
36
+ return false;
37
+ }
38
+
39
+ /**
40
+ * Copy a template file with optional variable replacement
41
+ */
42
+ export function copyTemplate(source, dest, replacements = {}) {
43
+ if (!fs.existsSync(source)) {
44
+ throw new Error(`Template not found: ${source}`);
45
+ }
46
+
47
+ let content = fs.readFileSync(source, 'utf-8');
48
+
49
+ for (const [key, value] of Object.entries(replacements)) {
50
+ content = content.replace(new RegExp(escapeRegExp(key), 'g'), value);
51
+ }
52
+
53
+ // Ensure destination directory exists
54
+ const destDir = path.dirname(dest);
55
+ if (!fs.existsSync(destDir)) {
56
+ fs.mkdirSync(destDir, { recursive: true });
57
+ }
58
+
59
+ fs.writeFileSync(dest, content);
60
+ }
61
+
62
+ /**
63
+ * Recursively copy a directory
64
+ */
65
+ export function copyDirectory(source, dest) {
66
+ if (!fs.existsSync(source)) {
67
+ throw new Error(`Source directory not found: ${source}`);
68
+ }
69
+
70
+ if (!fs.existsSync(dest)) {
71
+ fs.mkdirSync(dest, { recursive: true });
72
+ }
73
+
74
+ const entries = fs.readdirSync(source, { withFileTypes: true });
75
+
76
+ for (const entry of entries) {
77
+ const sourcePath = path.join(source, entry.name);
78
+ const destPath = path.join(dest, entry.name);
79
+
80
+ if (entry.isDirectory()) {
81
+ copyDirectory(sourcePath, destPath);
82
+ } else {
83
+ fs.copyFileSync(sourcePath, destPath);
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Escape special regex characters
90
+ */
91
+ function escapeRegExp(string) {
92
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
93
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "aiknowsys",
3
+ "version": "0.0.1",
4
+ "description": "AI-Powered Development Workflow for Consistent, High-Quality Code",
5
+ "keywords": [
6
+ "ai",
7
+ "copilot",
8
+ "claude",
9
+ "agents",
10
+ "knowledge-management",
11
+ "documentation",
12
+ "developer-workflow",
13
+ "code-review"
14
+ ],
15
+ "author": "arpa73",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/arpa73/aiknowsys.git"
20
+ },
21
+ "homepage": "https://github.com/arpa73/aiknowsys#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/arpa73/aiknowsys/issues"
24
+ },
25
+ "type": "module",
26
+ "bin": {
27
+ "aiknowsys": "./bin/cli.js",
28
+ "aks": "./bin/cli.js"
29
+ },
30
+ "files": [
31
+ "bin/",
32
+ "lib/",
33
+ "templates/",
34
+ "scripts/",
35
+ "AGENTS.template.md",
36
+ "CODEBASE_CHANGELOG.template.md",
37
+ "CODEBASE_ESSENTIALS.template.md"
38
+ ],
39
+ "engines": {
40
+ "node": ">=20.0.0"
41
+ },
42
+ "scripts": {
43
+ "test": "node bin/cli.js --help",
44
+ "prepublishOnly": "node bin/cli.js --help && npm pack --dry-run",
45
+ "postversion": "git push && git push --tags"
46
+ },
47
+ "dependencies": {
48
+ "chalk": "^5.6.2",
49
+ "commander": "^14.0.2",
50
+ "inquirer": "^13.2.1",
51
+ "ora": "^9.1.0"
52
+ }
53
+ }