@codihaus/claude-skills 1.6.19 → 1.6.21

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.
@@ -73,6 +73,12 @@ You have three layers of knowledge to apply:
73
73
  - "Nuxt" → `knowledge/stacks/nuxt/_index.md`
74
74
  - "Directus" → `knowledge/stacks/directus/_index.md`
75
75
 
76
+ **Deep knowledge loading (for complex features):**
77
+ - First read `knowledge/_knowledge.json` to discover available reference files
78
+ - Load additional references when needed: `knowledge/stacks/{stack}/references/*.md`
79
+ - Example: For performance-critical features, load `references/performance.md`
80
+ - Example: For complex patterns, load `references/patterns.md`
81
+
76
82
  **If you skip this step**, you'll implement using generic patterns instead of framework-specific best practices (e.g., using fetch instead of Server Actions in Next.js).
77
83
 
78
84
  ## Expected Outcome
@@ -186,17 +186,22 @@ export async function init(options) {
186
186
  const knowledgeSpinner = ora('Installing knowledge base...').start();
187
187
 
188
188
  try {
189
- const { copied: knowledgeCopied, errors: knowledgeErrors } = await copyKnowledgeToProject(projectPath);
189
+ const { copied: knowledgeCopied, errors: knowledgeErrors } = await copyKnowledgeToProject(
190
+ projectPath,
191
+ options.knowledge // Custom knowledge path if provided
192
+ );
190
193
 
191
194
  if (knowledgeErrors.length > 0) {
192
195
  knowledgeSpinner.warn(`Installed ${knowledgeCopied.length} knowledge folders with ${knowledgeErrors.length} errors`);
193
196
  } else if (knowledgeCopied.length > 0) {
194
- knowledgeSpinner.succeed(`Installed knowledge: ${knowledgeCopied.join(', ')}`);
197
+ const source = options.knowledge ? ` from ${options.knowledge}` : '';
198
+ knowledgeSpinner.succeed(`Installed knowledge${source}: ${knowledgeCopied.join(', ')}`);
195
199
  } else {
196
200
  knowledgeSpinner.info('No knowledge to install');
197
201
  }
198
202
  } catch (e) {
199
203
  knowledgeSpinner.warn('Failed to install knowledge');
204
+ console.error(chalk.gray(` ${e.message}`));
200
205
  }
201
206
 
202
207
  // Step 6: Copy scripts (graph.py, etc.)
@@ -272,13 +272,24 @@ export async function checkForUpdates(projectPath) {
272
272
 
273
273
  /**
274
274
  * Copy knowledge (stacks, domains) to project
275
+ * @param {string} projectPath - Target project path
276
+ * @param {string} customSource - Optional custom knowledge source path
275
277
  */
276
- export async function copyKnowledgeToProject(projectPath) {
278
+ export async function copyKnowledgeToProject(projectPath, customSource = null) {
277
279
  const targetPath = path.join(projectPath, '.claude', 'knowledge');
280
+ const sourcePath = customSource
281
+ ? path.resolve(customSource)
282
+ : KNOWLEDGE_SOURCE;
278
283
 
279
284
  // Check if source exists
280
- if (!await fs.pathExists(KNOWLEDGE_SOURCE)) {
281
- return { copied: [], errors: [{ name: 'knowledge', error: 'Source not found' }] };
285
+ if (!await fs.pathExists(sourcePath)) {
286
+ return {
287
+ copied: [],
288
+ errors: [{
289
+ name: 'knowledge',
290
+ error: `Source not found: ${sourcePath}`
291
+ }]
292
+ };
282
293
  }
283
294
 
284
295
  // Remove existing and copy fresh
@@ -289,22 +300,27 @@ export async function copyKnowledgeToProject(projectPath) {
289
300
  const errors = [];
290
301
 
291
302
  try {
292
- const items = await fs.readdir(KNOWLEDGE_SOURCE);
303
+ const items = await fs.readdir(sourcePath);
293
304
 
294
305
  for (const item of items) {
295
306
  // Skip hidden files
296
307
  if (item.startsWith('.')) continue;
297
308
 
298
- const sourcePath = path.join(KNOWLEDGE_SOURCE, item);
309
+ const itemSourcePath = path.join(sourcePath, item);
299
310
  const targetItemPath = path.join(targetPath, item);
300
311
 
301
312
  try {
302
- await fs.copy(sourcePath, targetItemPath);
313
+ await fs.copy(itemSourcePath, targetItemPath);
303
314
  copied.push(item);
304
315
  } catch (e) {
305
316
  errors.push({ name: item, error: e.message });
306
317
  }
307
318
  }
319
+
320
+ // Generate knowledge declaration file
321
+ if (copied.length > 0) {
322
+ await generateKnowledgeDeclare(targetPath);
323
+ }
308
324
  } catch (e) {
309
325
  errors.push({ name: 'knowledge', error: e.message });
310
326
  }
@@ -312,6 +328,137 @@ export async function copyKnowledgeToProject(projectPath) {
312
328
  return { copied, errors };
313
329
  }
314
330
 
331
+ /**
332
+ * Generate knowledge declaration file
333
+ * Creates _knowledge.json that maps stacks/domains to their available files
334
+ */
335
+ async function generateKnowledgeDeclare(knowledgePath) {
336
+ const declaration = {
337
+ stacks: {},
338
+ domains: {},
339
+ generated: new Date().toISOString()
340
+ };
341
+
342
+ // Scan stacks
343
+ const stacksPath = path.join(knowledgePath, 'stacks');
344
+ if (await fs.pathExists(stacksPath)) {
345
+ const stacks = await fs.readdir(stacksPath);
346
+
347
+ for (const stack of stacks) {
348
+ if (stack.startsWith('.') || stack === '_index.md') continue;
349
+
350
+ const stackPath = path.join(stacksPath, stack);
351
+ const stat = await fs.stat(stackPath);
352
+
353
+ if (stat.isDirectory()) {
354
+ // Scan files in stack folder
355
+ const files = await scanKnowledgeFiles(stackPath);
356
+ if (files.length > 0) {
357
+ declaration.stacks[stack] = files;
358
+ }
359
+ }
360
+ }
361
+ }
362
+
363
+ // Scan domains
364
+ const domainsPath = path.join(knowledgePath, 'domains');
365
+ if (await fs.pathExists(domainsPath)) {
366
+ const domains = await fs.readdir(domainsPath);
367
+
368
+ for (const domain of domains) {
369
+ if (domain.startsWith('.') || domain === '_index.md') continue;
370
+
371
+ const domainPath = path.join(domainsPath, domain);
372
+ const stat = await fs.stat(domainPath);
373
+
374
+ if (stat.isDirectory()) {
375
+ // Scan files in domain folder
376
+ const files = await scanKnowledgeFiles(domainPath);
377
+ if (files.length > 0) {
378
+ declaration.domains[domain] = files;
379
+ }
380
+ }
381
+ }
382
+ }
383
+
384
+ // Write declaration file
385
+ const declarePath = path.join(knowledgePath, '_knowledge.json');
386
+ await fs.writeJson(declarePath, declaration, { spaces: 2 });
387
+
388
+ // Also create a markdown version for easy reading
389
+ await generateKnowledgeDeclareMd(knowledgePath, declaration);
390
+
391
+ return declaration;
392
+ }
393
+
394
+ /**
395
+ * Scan knowledge folder and return list of files with metadata
396
+ */
397
+ async function scanKnowledgeFiles(folderPath) {
398
+ const files = [];
399
+
400
+ async function scan(dir, relativePath = '') {
401
+ const items = await fs.readdir(dir);
402
+
403
+ for (const item of items) {
404
+ if (item.startsWith('.')) continue;
405
+
406
+ const itemPath = path.join(dir, item);
407
+ const stat = await fs.stat(itemPath);
408
+ const relPath = relativePath ? `${relativePath}/${item}` : item;
409
+
410
+ if (stat.isFile() && item.endsWith('.md')) {
411
+ files.push({
412
+ path: relPath,
413
+ name: item,
414
+ size: stat.size
415
+ });
416
+ } else if (stat.isDirectory()) {
417
+ await scan(itemPath, relPath);
418
+ }
419
+ }
420
+ }
421
+
422
+ await scan(folderPath);
423
+ return files;
424
+ }
425
+
426
+ /**
427
+ * Generate markdown version of knowledge declaration
428
+ */
429
+ async function generateKnowledgeDeclareMd(knowledgePath, declaration) {
430
+ let content = '# Knowledge Base Index\n\n';
431
+ content += `Generated: ${new Date().toLocaleString()}\n\n`;
432
+ content += 'This file is auto-generated. It lists all available knowledge files in this project.\n\n';
433
+
434
+ // Stacks
435
+ if (Object.keys(declaration.stacks).length > 0) {
436
+ content += '## Stacks\n\n';
437
+ for (const [stack, files] of Object.entries(declaration.stacks)) {
438
+ content += `### ${stack}\n\n`;
439
+ for (const file of files) {
440
+ content += `- \`${file.path}\`\n`;
441
+ }
442
+ content += '\n';
443
+ }
444
+ }
445
+
446
+ // Domains
447
+ if (Object.keys(declaration.domains).length > 0) {
448
+ content += '## Domains\n\n';
449
+ for (const [domain, files] of Object.entries(declaration.domains)) {
450
+ content += `### ${domain}\n\n`;
451
+ for (const file of files) {
452
+ content += `- \`${file.path}\`\n`;
453
+ }
454
+ content += '\n';
455
+ }
456
+ }
457
+
458
+ const declarePath = path.join(knowledgePath, '_knowledge.md');
459
+ await fs.writeFile(declarePath, content);
460
+ }
461
+
315
462
  /**
316
463
  * Copy scripts (graph.py, etc.) to project
317
464
  */