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.
- package/AGENTS.template.md +207 -0
- package/CODEBASE_CHANGELOG.template.md +145 -0
- package/CODEBASE_ESSENTIALS.template.md +382 -0
- package/LICENSE +21 -0
- package/README.md +714 -0
- package/bin/cli.js +81 -0
- package/lib/commands/init.js +227 -0
- package/lib/commands/install-agents.js +100 -0
- package/lib/commands/install-skills.js +92 -0
- package/lib/commands/migrate.js +161 -0
- package/lib/commands/scan.js +418 -0
- package/lib/utils.js +93 -0
- package/package.json +53 -0
- package/scripts/migrate-existing.sh +222 -0
- package/scripts/scan-codebase.sh +379 -0
- package/scripts/setup.sh +273 -0
- package/templates/agents/README.md +270 -0
- package/templates/agents/architect.agent.template.md +58 -0
- package/templates/agents/developer.agent.template.md +27 -0
- package/templates/agents/setup-agents.sh +65 -0
- package/templates/skills/code-refactoring/SKILL.md +662 -0
- package/templates/skills/dependency-updates/SKILL.md +561 -0
- package/templates/skills/documentation-management/SKILL.md +744 -0
- package/templates/skills/skill-creator/SKILL.md +252 -0
- package/templates/skills/skill-creator/template.md +89 -0
|
@@ -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
|
+
}
|