cmp-standards 3.5.1 ā 3.7.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/README.md +399 -633
- package/dist/analytics/CrossProjectAnalytics.js +65 -65
- package/dist/cli/index.js +255 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/tokens.js +173 -173
- package/dist/db/cloud.d.ts +1 -0
- package/dist/db/cloud.d.ts.map +1 -1
- package/dist/db/migrations.js +256 -256
- package/dist/db/turso-client.js +2 -2
- package/dist/db/upstash-client.d.ts +9 -0
- package/dist/db/upstash-client.d.ts.map +1 -1
- package/dist/db/upstash-client.js +11 -0
- package/dist/db/upstash-client.js.map +1 -1
- package/dist/eslint/rules/no-async-useeffect.js +6 -6
- package/dist/experts/ExpertVotePersistence.js +9 -9
- package/dist/hooks/auto-learning-hook.d.ts +48 -0
- package/dist/hooks/auto-learning-hook.d.ts.map +1 -0
- package/dist/hooks/auto-learning-hook.js +258 -0
- package/dist/hooks/auto-learning-hook.js.map +1 -0
- package/dist/hooks/cloud-post-tool-use.d.ts.map +1 -1
- package/dist/hooks/cloud-post-tool-use.js +72 -10
- package/dist/hooks/cloud-post-tool-use.js.map +1 -1
- package/dist/hooks/cloud-pre-tool-use.d.ts +12 -9
- package/dist/hooks/cloud-pre-tool-use.d.ts.map +1 -1
- package/dist/hooks/cloud-pre-tool-use.js +227 -99
- package/dist/hooks/cloud-pre-tool-use.js.map +1 -1
- package/dist/hooks/cloud-session-start.js +5 -5
- package/dist/hooks/fast-session-start.d.ts +24 -0
- package/dist/hooks/fast-session-start.d.ts.map +1 -0
- package/dist/hooks/fast-session-start.js +354 -0
- package/dist/hooks/fast-session-start.js.map +1 -0
- package/dist/hooks/resilient-hook-runner.d.ts +78 -0
- package/dist/hooks/resilient-hook-runner.d.ts.map +1 -0
- package/dist/hooks/resilient-hook-runner.js +201 -0
- package/dist/hooks/resilient-hook-runner.js.map +1 -0
- package/dist/hooks/session-end.js +14 -14
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/patterns/registry.js +90 -90
- package/dist/schema/codewiki-types.d.ts +10 -10
- package/dist/schema/docs-types.d.ts +8 -8
- package/dist/schema/ecosystem-types.d.ts +12 -12
- package/dist/services/BootstrapService.d.ts +123 -0
- package/dist/services/BootstrapService.d.ts.map +1 -0
- package/dist/services/BootstrapService.js +309 -0
- package/dist/services/BootstrapService.js.map +1 -0
- package/dist/services/CodeWikiIndexer.js +3 -3
- package/dist/services/ContextGenerator.js +7 -7
- package/dist/services/FeedbackCollector.js +11 -11
- package/dist/services/GitIntegration.js +9 -9
- package/dist/services/HookVerifier.js +70 -70
- package/dist/services/KnowledgeGapDetector.d.ts +122 -0
- package/dist/services/KnowledgeGapDetector.d.ts.map +1 -0
- package/dist/services/KnowledgeGapDetector.js +530 -0
- package/dist/services/KnowledgeGapDetector.js.map +1 -0
- package/dist/services/ProjectScaffold.d.ts.map +1 -1
- package/dist/services/ProjectScaffold.js +79 -78
- package/dist/services/ProjectScaffold.js.map +1 -1
- package/dist/services/auto-evolution-trigger.d.ts +101 -0
- package/dist/services/auto-evolution-trigger.d.ts.map +1 -0
- package/dist/services/auto-evolution-trigger.js +359 -0
- package/dist/services/auto-evolution-trigger.js.map +1 -0
- package/dist/services/cloud-memory-service.d.ts +101 -0
- package/dist/services/cloud-memory-service.d.ts.map +1 -0
- package/dist/services/cloud-memory-service.js +363 -0
- package/dist/services/cloud-memory-service.js.map +1 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +6 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/knowledge-graph.d.ts +121 -0
- package/dist/services/knowledge-graph.d.ts.map +1 -0
- package/dist/services/knowledge-graph.js +446 -0
- package/dist/services/knowledge-graph.js.map +1 -0
- package/dist/services/memory-keeper-client.d.ts +106 -0
- package/dist/services/memory-keeper-client.d.ts.map +1 -0
- package/dist/services/memory-keeper-client.js +319 -0
- package/dist/services/memory-keeper-client.js.map +1 -0
- package/dist/services/memory-router.d.ts +25 -0
- package/dist/services/memory-router.d.ts.map +1 -1
- package/dist/services/memory-router.js +236 -98
- package/dist/services/memory-router.js.map +1 -1
- package/dist/services/pattern-learning.d.ts +79 -0
- package/dist/services/pattern-learning.d.ts.map +1 -0
- package/dist/services/pattern-learning.js +312 -0
- package/dist/services/pattern-learning.js.map +1 -0
- package/dist/services/pattern-tracker.js +95 -95
- package/dist/services/semantic-search.js +2 -2
- package/dist/services/skill-learning-bridge.d.ts +100 -0
- package/dist/services/skill-learning-bridge.d.ts.map +1 -0
- package/dist/services/skill-learning-bridge.js +331 -0
- package/dist/services/skill-learning-bridge.js.map +1 -0
- package/dist/services/unified-memory-router.d.ts +123 -0
- package/dist/services/unified-memory-router.d.ts.map +1 -0
- package/dist/services/unified-memory-router.js +555 -0
- package/dist/services/unified-memory-router.js.map +1 -0
- package/package.json +124 -116
- package/standards/README.md +94 -50
- package/standards/experts/expert-routing.md +215 -215
- package/standards/general/code-quality.md +86 -86
- package/standards/general/ecosystem.md +243 -0
- package/standards/general/learning-loop.md +192 -0
- package/standards/general/memory-usage.md +205 -205
- package/standards/general/project-onboarding.md +339 -0
- package/standards/general/sync-workflow.md +235 -235
- package/standards/general/workflow.md +82 -82
- package/standards/hooks/mandatory-tracking.md +446 -446
- package/standards/infrastructure/cloud-database.md +287 -287
- package/standards/mcp/server-design.md +243 -243
- package/standards/mcp/tool-patterns.md +354 -354
- package/standards/skills/skill-structure.md +286 -286
- package/standards/skills/workflow-design.md +323 -323
- package/standards/tools/tool-design.md +297 -297
- package/templates/agents/architecture-expert.md +61 -61
- package/templates/agents/database-expert.md +62 -62
- package/templates/agents/documentation-expert.md +57 -57
- package/templates/agents/ecosystem-expert.md +104 -0
- package/templates/agents/memory-expert.md +88 -88
- package/templates/agents/performance-expert.md +61 -61
- package/templates/agents/security-expert.md +59 -59
- package/templates/agents/ux-expert.md +63 -63
- package/templates/agents/worker.md +75 -75
- package/templates/ai-skills/SKILL_TEMPLATE.md +55 -55
- package/templates/claude-settings.json +72 -72
- package/templates/commands/experts.md +138 -138
- package/templates/hooks/README.md +158 -158
- package/templates/hooks/project.config.json.template +77 -77
- package/templates/hooks/settings.local.json.template +57 -57
- package/templates/hooks.config.json +21 -0
- package/templates/memory-config.json +56 -56
- package/templates/memory-config.schema.json +212 -212
- package/templates/settings.json +58 -58
- package/templates/skills/continue.md +205 -205
- package/templates/workflows/business-improvement.md +264 -264
- package/templates/workflows/expert-review.md +153 -153
- package/templates/workflows/internal-app.md +245 -245
- package/templates/workflows/sync-docs.md +187 -187
|
@@ -28,8 +28,8 @@ export class CrossProjectAnalyticsService {
|
|
|
28
28
|
const db = turso.getClient();
|
|
29
29
|
const metrics = [];
|
|
30
30
|
// Get all systems
|
|
31
|
-
const systemsResult = await db.execute(`
|
|
32
|
-
SELECT DISTINCT system FROM items WHERE status = 'active'
|
|
31
|
+
const systemsResult = await db.execute(`
|
|
32
|
+
SELECT DISTINCT system FROM items WHERE status = 'active'
|
|
33
33
|
`);
|
|
34
34
|
const systems = systemsResult.rows
|
|
35
35
|
.map(r => r.system)
|
|
@@ -37,14 +37,14 @@ export class CrossProjectAnalyticsService {
|
|
|
37
37
|
for (const system of systems) {
|
|
38
38
|
const [itemsResult, sessionsResult, lastActivityResult] = await Promise.all([
|
|
39
39
|
db.execute({
|
|
40
|
-
sql: `SELECT type, COUNT(*) as count FROM items
|
|
41
|
-
WHERE system = ? AND status = 'active'
|
|
40
|
+
sql: `SELECT type, COUNT(*) as count FROM items
|
|
41
|
+
WHERE system = ? AND status = 'active'
|
|
42
42
|
GROUP BY type`,
|
|
43
43
|
args: [system],
|
|
44
44
|
}),
|
|
45
45
|
db.execute({
|
|
46
|
-
sql: `SELECT COUNT(*) as count FROM items
|
|
47
|
-
WHERE system = ? AND type = 'agent_session'
|
|
46
|
+
sql: `SELECT COUNT(*) as count FROM items
|
|
47
|
+
WHERE system = ? AND type = 'agent_session'
|
|
48
48
|
AND created_at > datetime('now', '-7 days')`,
|
|
49
49
|
args: [system],
|
|
50
50
|
}),
|
|
@@ -117,18 +117,18 @@ export class CrossProjectAnalyticsService {
|
|
|
117
117
|
const insights = [];
|
|
118
118
|
const db = turso.getClient();
|
|
119
119
|
// Find shared patterns across projects
|
|
120
|
-
const sharedPatternsResult = await db.execute(`
|
|
121
|
-
SELECT
|
|
122
|
-
json_extract(content, '$.patternId') as patternId,
|
|
123
|
-
COUNT(DISTINCT system) as systemCount,
|
|
124
|
-
GROUP_CONCAT(DISTINCT system) as systems,
|
|
125
|
-
SUM(json_extract(content, '$.count')) as totalCount
|
|
126
|
-
FROM items
|
|
127
|
-
WHERE type = 'pattern' AND status = 'active'
|
|
128
|
-
GROUP BY patternId
|
|
129
|
-
HAVING systemCount > 1
|
|
130
|
-
ORDER BY totalCount DESC
|
|
131
|
-
LIMIT 10
|
|
120
|
+
const sharedPatternsResult = await db.execute(`
|
|
121
|
+
SELECT
|
|
122
|
+
json_extract(content, '$.patternId') as patternId,
|
|
123
|
+
COUNT(DISTINCT system) as systemCount,
|
|
124
|
+
GROUP_CONCAT(DISTINCT system) as systems,
|
|
125
|
+
SUM(json_extract(content, '$.count')) as totalCount
|
|
126
|
+
FROM items
|
|
127
|
+
WHERE type = 'pattern' AND status = 'active'
|
|
128
|
+
GROUP BY patternId
|
|
129
|
+
HAVING systemCount > 1
|
|
130
|
+
ORDER BY totalCount DESC
|
|
131
|
+
LIMIT 10
|
|
132
132
|
`);
|
|
133
133
|
for (const row of sharedPatternsResult.rows) {
|
|
134
134
|
// Skip rows with missing or invalid systems data
|
|
@@ -187,15 +187,15 @@ export class CrossProjectAnalyticsService {
|
|
|
187
187
|
async comparePatterns(options) {
|
|
188
188
|
const db = turso.getClient();
|
|
189
189
|
const comparisons = [];
|
|
190
|
-
const result = await db.execute(`
|
|
191
|
-
SELECT
|
|
192
|
-
json_extract(content, '$.patternId') as patternId,
|
|
193
|
-
json_extract(content, '$.description') as description,
|
|
194
|
-
system,
|
|
195
|
-
json_extract(content, '$.count') as count
|
|
196
|
-
FROM items
|
|
197
|
-
WHERE type = 'pattern' AND status = 'active'
|
|
198
|
-
ORDER BY patternId
|
|
190
|
+
const result = await db.execute(`
|
|
191
|
+
SELECT
|
|
192
|
+
json_extract(content, '$.patternId') as patternId,
|
|
193
|
+
json_extract(content, '$.description') as description,
|
|
194
|
+
system,
|
|
195
|
+
json_extract(content, '$.count') as count
|
|
196
|
+
FROM items
|
|
197
|
+
WHERE type = 'pattern' AND status = 'active'
|
|
198
|
+
ORDER BY patternId
|
|
199
199
|
`);
|
|
200
200
|
// Group by pattern
|
|
201
201
|
const patternGroups = new Map();
|
|
@@ -236,25 +236,25 @@ export class CrossProjectAnalyticsService {
|
|
|
236
236
|
const db = turso.getClient();
|
|
237
237
|
const opportunities = [];
|
|
238
238
|
// Find high-value memories that could benefit other projects
|
|
239
|
-
const memoriesResult = await db.execute(`
|
|
240
|
-
SELECT
|
|
241
|
-
id,
|
|
242
|
-
system,
|
|
243
|
-
json_extract(content, '$.title') as title,
|
|
244
|
-
json_extract(content, '$.domain') as domain,
|
|
245
|
-
json_extract(content, '$.feedbackScore') as feedbackScore,
|
|
246
|
-
json_extract(content, '$.accessCount') as accessCount
|
|
247
|
-
FROM items
|
|
248
|
-
WHERE type = 'memory'
|
|
249
|
-
AND status = 'active'
|
|
250
|
-
AND COALESCE(json_extract(content, '$.feedbackScore'), 0.5) >= 0.7
|
|
251
|
-
AND COALESCE(json_extract(content, '$.accessCount'), 0) >= 3
|
|
252
|
-
ORDER BY feedbackScore DESC, accessCount DESC
|
|
253
|
-
LIMIT 50
|
|
239
|
+
const memoriesResult = await db.execute(`
|
|
240
|
+
SELECT
|
|
241
|
+
id,
|
|
242
|
+
system,
|
|
243
|
+
json_extract(content, '$.title') as title,
|
|
244
|
+
json_extract(content, '$.domain') as domain,
|
|
245
|
+
json_extract(content, '$.feedbackScore') as feedbackScore,
|
|
246
|
+
json_extract(content, '$.accessCount') as accessCount
|
|
247
|
+
FROM items
|
|
248
|
+
WHERE type = 'memory'
|
|
249
|
+
AND status = 'active'
|
|
250
|
+
AND COALESCE(json_extract(content, '$.feedbackScore'), 0.5) >= 0.7
|
|
251
|
+
AND COALESCE(json_extract(content, '$.accessCount'), 0) >= 3
|
|
252
|
+
ORDER BY feedbackScore DESC, accessCount DESC
|
|
253
|
+
LIMIT 50
|
|
254
254
|
`);
|
|
255
255
|
// Get all active systems
|
|
256
|
-
const systemsResult = await db.execute(`
|
|
257
|
-
SELECT DISTINCT system FROM items WHERE status = 'active'
|
|
256
|
+
const systemsResult = await db.execute(`
|
|
257
|
+
SELECT DISTINCT system FROM items WHERE status = 'active'
|
|
258
258
|
`);
|
|
259
259
|
const allSystems = systemsResult.rows.map(r => r.system);
|
|
260
260
|
for (const row of memoriesResult.rows) {
|
|
@@ -288,16 +288,16 @@ export class CrossProjectAnalyticsService {
|
|
|
288
288
|
async getActivityTimeline(days = 30) {
|
|
289
289
|
const db = turso.getClient();
|
|
290
290
|
const result = await db.execute({
|
|
291
|
-
sql: `
|
|
292
|
-
SELECT
|
|
293
|
-
DATE(created_at) as date,
|
|
294
|
-
system,
|
|
295
|
-
COUNT(*) as itemsCreated,
|
|
296
|
-
SUM(CASE WHEN type = 'agent_session' THEN 1 ELSE 0 END) as sessionsStarted
|
|
297
|
-
FROM items
|
|
298
|
-
WHERE created_at > datetime('now', '-' || ? || ' days')
|
|
299
|
-
GROUP BY DATE(created_at), system
|
|
300
|
-
ORDER BY date DESC
|
|
291
|
+
sql: `
|
|
292
|
+
SELECT
|
|
293
|
+
DATE(created_at) as date,
|
|
294
|
+
system,
|
|
295
|
+
COUNT(*) as itemsCreated,
|
|
296
|
+
SUM(CASE WHEN type = 'agent_session' THEN 1 ELSE 0 END) as sessionsStarted
|
|
297
|
+
FROM items
|
|
298
|
+
WHERE created_at > datetime('now', '-' || ? || ' days')
|
|
299
|
+
GROUP BY DATE(created_at), system
|
|
300
|
+
ORDER BY date DESC
|
|
301
301
|
`,
|
|
302
302
|
args: [days],
|
|
303
303
|
});
|
|
@@ -314,17 +314,17 @@ export class CrossProjectAnalyticsService {
|
|
|
314
314
|
async getTopContributors(limit = 5) {
|
|
315
315
|
const db = turso.getClient();
|
|
316
316
|
const result = await db.execute({
|
|
317
|
-
sql: `
|
|
318
|
-
SELECT
|
|
319
|
-
system,
|
|
320
|
-
SUM(CASE WHEN type = 'memory' THEN 1 ELSE 0 END) as memoriesCreated,
|
|
321
|
-
SUM(CASE WHEN type = 'task' AND json_extract(content, '$.status') = 'completed' THEN 1 ELSE 0 END) as tasksCompleted,
|
|
322
|
-
SUM(CASE WHEN type = 'pattern' THEN 1 ELSE 0 END) as patternsDetected
|
|
323
|
-
FROM items
|
|
324
|
-
WHERE status = 'active' AND created_at > datetime('now', '-30 days')
|
|
325
|
-
GROUP BY system
|
|
326
|
-
ORDER BY memoriesCreated DESC
|
|
327
|
-
LIMIT ?
|
|
317
|
+
sql: `
|
|
318
|
+
SELECT
|
|
319
|
+
system,
|
|
320
|
+
SUM(CASE WHEN type = 'memory' THEN 1 ELSE 0 END) as memoriesCreated,
|
|
321
|
+
SUM(CASE WHEN type = 'task' AND json_extract(content, '$.status') = 'completed' THEN 1 ELSE 0 END) as tasksCompleted,
|
|
322
|
+
SUM(CASE WHEN type = 'pattern' THEN 1 ELSE 0 END) as patternsDetected
|
|
323
|
+
FROM items
|
|
324
|
+
WHERE status = 'active' AND created_at > datetime('now', '-30 days')
|
|
325
|
+
GROUP BY system
|
|
326
|
+
ORDER BY memoriesCreated DESC
|
|
327
|
+
LIMIT ?
|
|
328
328
|
`,
|
|
329
329
|
args: [limit],
|
|
330
330
|
});
|
package/dist/cli/index.js
CHANGED
|
@@ -394,21 +394,44 @@ program
|
|
|
394
394
|
ui.dim('Run: cmp-standards init');
|
|
395
395
|
return;
|
|
396
396
|
}
|
|
397
|
-
// Check registry
|
|
398
|
-
const registryPath = path.join(projectRoot, '.claude/
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
'
|
|
406
|
-
|
|
397
|
+
// Check registry - now in .claude/cache (not knowledge)
|
|
398
|
+
const registryPath = path.join(projectRoot, '.claude/cache/registry.json');
|
|
399
|
+
const legacyRegistryPath = path.join(projectRoot, '.claude/knowledge/registry.json');
|
|
400
|
+
let foundRegistry = false;
|
|
401
|
+
for (const regPath of [registryPath, legacyRegistryPath]) {
|
|
402
|
+
try {
|
|
403
|
+
const registryContent = await fs.readFile(regPath, 'utf-8');
|
|
404
|
+
const registry = JSON.parse(registryContent);
|
|
405
|
+
ui.success('Registry found');
|
|
406
|
+
ui.keyValue({
|
|
407
|
+
'Sections': registry.sections.length,
|
|
408
|
+
'Generated': registry.generatedAt || 'pending',
|
|
409
|
+
});
|
|
410
|
+
foundRegistry = true;
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
// Continue to next path
|
|
415
|
+
}
|
|
407
416
|
}
|
|
408
|
-
|
|
417
|
+
if (!foundRegistry) {
|
|
409
418
|
ui.warning('No registry found');
|
|
410
419
|
ui.dim('Run: cmp-standards generate');
|
|
411
420
|
}
|
|
421
|
+
// Check for LOCAL knowledge files (VIOLATION of Cloud > Local philosophy)
|
|
422
|
+
const knowledgeDir = path.join(projectRoot, '.claude/knowledge');
|
|
423
|
+
try {
|
|
424
|
+
const knowledgeFiles = await fs.readdir(knowledgeDir);
|
|
425
|
+
const mdFiles = knowledgeFiles.filter(f => f.endsWith('.md'));
|
|
426
|
+
if (mdFiles.length > 0) {
|
|
427
|
+
console.log(chalk.red(`\n ā ļø PHILOSOPHY VIOLATION: ${mdFiles.length} local knowledge files found`));
|
|
428
|
+
console.log(chalk.gray(' Cloud > Local - knowledge should be in Turso, not local files'));
|
|
429
|
+
console.log(chalk.yellow(' Run: cmp-standards cloud push-knowledge --delete-local'));
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
// No knowledge directory = good (cloud-first)
|
|
434
|
+
}
|
|
412
435
|
// Check hooks
|
|
413
436
|
const hooksDir = getHooksDir(projectRoot);
|
|
414
437
|
try {
|
|
@@ -1100,6 +1123,127 @@ cloudCmd
|
|
|
1100
1123
|
}
|
|
1101
1124
|
}
|
|
1102
1125
|
});
|
|
1126
|
+
cloudCmd
|
|
1127
|
+
.command('push-knowledge')
|
|
1128
|
+
.description('Push local knowledge files to Turso cloud (Cloud > Local philosophy)')
|
|
1129
|
+
.option('-s, --system <system>', 'System identifier')
|
|
1130
|
+
.option('--delete-local', 'Delete local files after successful push')
|
|
1131
|
+
.option('--dry-run', 'Show what would be pushed without pushing')
|
|
1132
|
+
.action(async (options) => {
|
|
1133
|
+
const projectRoot = await getProjectRoot();
|
|
1134
|
+
let system = options.system;
|
|
1135
|
+
if (!system) {
|
|
1136
|
+
try {
|
|
1137
|
+
const config = await loadConfig(projectRoot);
|
|
1138
|
+
system = config.system;
|
|
1139
|
+
}
|
|
1140
|
+
catch {
|
|
1141
|
+
console.log(chalk.red('Error: No system specified and no config found'));
|
|
1142
|
+
process.exit(1);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
const knowledgeDir = path.join(projectRoot, '.claude/knowledge');
|
|
1146
|
+
const domainsDir = path.join(knowledgeDir, 'domains');
|
|
1147
|
+
// Check for local knowledge files
|
|
1148
|
+
const fsSync = await import('fs');
|
|
1149
|
+
const files = [];
|
|
1150
|
+
if (fsSync.existsSync(knowledgeDir)) {
|
|
1151
|
+
for (const file of fsSync.readdirSync(knowledgeDir)) {
|
|
1152
|
+
if (file.endsWith('.md') && !file.startsWith('.')) {
|
|
1153
|
+
files.push({ file: path.join(knowledgeDir, file), domain: 'general' });
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
if (fsSync.existsSync(domainsDir)) {
|
|
1158
|
+
for (const file of fsSync.readdirSync(domainsDir)) {
|
|
1159
|
+
if (file.endsWith('.md')) {
|
|
1160
|
+
const domain = file.replace('.md', '');
|
|
1161
|
+
files.push({ file: path.join(domainsDir, file), domain });
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
if (files.length === 0) {
|
|
1166
|
+
console.log(chalk.green('āļø No local knowledge files found - already cloud-first!'));
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
console.log(chalk.yellow(`\nā ļø Found ${files.length} local knowledge files`));
|
|
1170
|
+
console.log(chalk.gray(' Philosophy: Cloud > Local - knowledge should be in Turso\n'));
|
|
1171
|
+
if (options.dryRun) {
|
|
1172
|
+
console.log(chalk.blue('š Dry run - would push:\n'));
|
|
1173
|
+
for (const { file, domain } of files) {
|
|
1174
|
+
const content = fsSync.readFileSync(file, 'utf-8');
|
|
1175
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
1176
|
+
const title = titleMatch ? titleMatch[1] : path.basename(file, '.md');
|
|
1177
|
+
console.log(` ā ${title} (${domain})`);
|
|
1178
|
+
}
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
// Initialize cloud
|
|
1182
|
+
const { cloud } = await import('../db/cloud.js');
|
|
1183
|
+
await cloud.init();
|
|
1184
|
+
let migrated = 0;
|
|
1185
|
+
let skipped = 0;
|
|
1186
|
+
for (const { file, domain } of files) {
|
|
1187
|
+
const content = fsSync.readFileSync(file, 'utf-8');
|
|
1188
|
+
const filename = path.basename(file, '.md');
|
|
1189
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
1190
|
+
const title = titleMatch ? titleMatch[1] : filename;
|
|
1191
|
+
const sections = content.match(/^##\s+(.+)$/gm) || [];
|
|
1192
|
+
const tags = sections.map(s => s.replace('## ', '').toLowerCase().replace(/\s+/g, '-'));
|
|
1193
|
+
let importance = 'normal';
|
|
1194
|
+
if (filename.includes('critical') || content.toLowerCase().includes('critical')) {
|
|
1195
|
+
importance = 'critical';
|
|
1196
|
+
}
|
|
1197
|
+
const knowledgeContent = {
|
|
1198
|
+
title,
|
|
1199
|
+
domain,
|
|
1200
|
+
body: content,
|
|
1201
|
+
tags: [...new Set([domain, ...tags])],
|
|
1202
|
+
importance,
|
|
1203
|
+
source: 'migration',
|
|
1204
|
+
createdAt: new Date().toISOString()
|
|
1205
|
+
};
|
|
1206
|
+
// Check if exists using raw client
|
|
1207
|
+
const client = cloud.turso.getClient();
|
|
1208
|
+
const existing = await client.execute({
|
|
1209
|
+
sql: `SELECT id FROM items WHERE system = ? AND type = 'knowledge' AND json_extract(content, '$.title') = ?`,
|
|
1210
|
+
args: [system, title]
|
|
1211
|
+
});
|
|
1212
|
+
if (existing.rows.length > 0) {
|
|
1213
|
+
console.log(chalk.gray(` āļø Skipped: ${title} (already in cloud)`));
|
|
1214
|
+
skipped++;
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
await cloud.turso.create('knowledge', system, knowledgeContent, 'active');
|
|
1218
|
+
console.log(chalk.green(` ā
Pushed: ${title} (${domain})`));
|
|
1219
|
+
migrated++;
|
|
1220
|
+
}
|
|
1221
|
+
console.log(chalk.blue(`\nš Push complete:`));
|
|
1222
|
+
console.log(` Pushed: ${migrated}`);
|
|
1223
|
+
console.log(` Skipped: ${skipped}`);
|
|
1224
|
+
if (options.deleteLocal && migrated > 0) {
|
|
1225
|
+
console.log(chalk.yellow('\nšļø Deleting local files (Cloud > Local)...'));
|
|
1226
|
+
for (const { file } of files) {
|
|
1227
|
+
fsSync.unlinkSync(file);
|
|
1228
|
+
console.log(chalk.gray(` Deleted: ${path.basename(file)}`));
|
|
1229
|
+
}
|
|
1230
|
+
// Clean up empty directories
|
|
1231
|
+
if (fsSync.existsSync(domainsDir) && fsSync.readdirSync(domainsDir).length === 0) {
|
|
1232
|
+
fsSync.rmdirSync(domainsDir);
|
|
1233
|
+
}
|
|
1234
|
+
const remaining = fsSync.readdirSync(knowledgeDir).filter(f => f.endsWith('.md'));
|
|
1235
|
+
if (remaining.length === 0 && fsSync.existsSync(domainsDir) === false) {
|
|
1236
|
+
// Only remove if truly empty (no registry.json, etc.)
|
|
1237
|
+
const allFiles = fsSync.readdirSync(knowledgeDir);
|
|
1238
|
+
if (allFiles.every(f => f === 'registry.json' || f.startsWith('.'))) {
|
|
1239
|
+
console.log(chalk.green('\nā Local knowledge directory cleaned'));
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
else if (migrated > 0 && !options.deleteLocal) {
|
|
1244
|
+
console.log(chalk.yellow('\nš” Tip: Run with --delete-local to remove local files after push'));
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1103
1247
|
// =============================================================================
|
|
1104
1248
|
// QUICKSTART WIZARD
|
|
1105
1249
|
// =============================================================================
|
|
@@ -1966,6 +2110,104 @@ wikiCmd
|
|
|
1966
2110
|
}
|
|
1967
2111
|
});
|
|
1968
2112
|
// =============================================================================
|
|
2113
|
+
// BOOTSTRAP COMMAND
|
|
2114
|
+
// =============================================================================
|
|
2115
|
+
program
|
|
2116
|
+
.command('bootstrap')
|
|
2117
|
+
.description('Full project bootstrap: scaffold ā index ā docs ā sync ā gaps')
|
|
2118
|
+
.requiredOption('-s, --system <system>', 'System identifier (PANEL, SWARMSCALE, etc.)')
|
|
2119
|
+
.option('-n, --name <name>', 'Project name')
|
|
2120
|
+
.option('-f, --force', 'Overwrite existing files')
|
|
2121
|
+
.option('--phases <phases>', 'Phases to run (comma-separated: scan,scaffold,index,docs,sync,gaps)', 'scan,scaffold,index,docs,sync,gaps')
|
|
2122
|
+
.option('--depth <depth>', 'Index depth: quick, standard, thorough', 'standard')
|
|
2123
|
+
.option('--skip-agents', 'Skip installing standard agents')
|
|
2124
|
+
.option('--skip-hooks', 'Skip installing hooks')
|
|
2125
|
+
.option('--skip-commands', 'Skip installing commands')
|
|
2126
|
+
.option('-v, --verbose', 'Show detailed progress')
|
|
2127
|
+
.action(async (options) => {
|
|
2128
|
+
const { BootstrapService } = await import('../services/BootstrapService.js');
|
|
2129
|
+
const projectRoot = await getProjectRoot();
|
|
2130
|
+
const bootstrap = new BootstrapService(projectRoot);
|
|
2131
|
+
const phases = options.phases.split(',').map((p) => p.trim());
|
|
2132
|
+
await bootstrap.run({
|
|
2133
|
+
system: options.system.toUpperCase(),
|
|
2134
|
+
projectName: options.name,
|
|
2135
|
+
phases,
|
|
2136
|
+
force: options.force,
|
|
2137
|
+
skipAgents: options.skipAgents,
|
|
2138
|
+
skipHooks: options.skipHooks,
|
|
2139
|
+
skipCommands: options.skipCommands,
|
|
2140
|
+
indexDepth: options.depth,
|
|
2141
|
+
verbose: options.verbose,
|
|
2142
|
+
});
|
|
2143
|
+
});
|
|
2144
|
+
// =============================================================================
|
|
2145
|
+
// GAPS COMMAND
|
|
2146
|
+
// =============================================================================
|
|
2147
|
+
program
|
|
2148
|
+
.command('gaps')
|
|
2149
|
+
.description('Analyze knowledge gaps in the project')
|
|
2150
|
+
.requiredOption('-s, --system <system>', 'System identifier (PANEL, SWARMSCALE, etc.)')
|
|
2151
|
+
.option('--json', 'Output as JSON')
|
|
2152
|
+
.action(async (options) => {
|
|
2153
|
+
const { KnowledgeGapDetector } = await import('../services/KnowledgeGapDetector.js');
|
|
2154
|
+
const projectRoot = await getProjectRoot();
|
|
2155
|
+
console.log(chalk.cyan('\nš Analyzing Knowledge Gaps\n'));
|
|
2156
|
+
const detector = new KnowledgeGapDetector(options.system.toUpperCase(), projectRoot);
|
|
2157
|
+
const analysis = await detector.analyze();
|
|
2158
|
+
if (options.json) {
|
|
2159
|
+
console.log(JSON.stringify(analysis, null, 2));
|
|
2160
|
+
return;
|
|
2161
|
+
}
|
|
2162
|
+
// Summary
|
|
2163
|
+
console.log(chalk.white(' Coverage Scores:'));
|
|
2164
|
+
console.log(` Structure: ${analysis.coverage.structureCoverage}%`);
|
|
2165
|
+
console.log(` Patterns: ${analysis.coverage.patternCoverage}%`);
|
|
2166
|
+
console.log(` Integrations: ${analysis.coverage.integrationCoverage}%`);
|
|
2167
|
+
console.log(chalk.cyan(` Overall: ${analysis.coverage.overallScore}%`));
|
|
2168
|
+
console.log();
|
|
2169
|
+
// Gaps by severity
|
|
2170
|
+
const bySeverity = {
|
|
2171
|
+
critical: analysis.gaps.filter(g => g.severity === 'critical'),
|
|
2172
|
+
high: analysis.gaps.filter(g => g.severity === 'high'),
|
|
2173
|
+
medium: analysis.gaps.filter(g => g.severity === 'medium'),
|
|
2174
|
+
low: analysis.gaps.filter(g => g.severity === 'low'),
|
|
2175
|
+
};
|
|
2176
|
+
if (bySeverity.critical.length > 0) {
|
|
2177
|
+
console.log(chalk.red(` š“ Critical (${bySeverity.critical.length}):`));
|
|
2178
|
+
for (const gap of bySeverity.critical) {
|
|
2179
|
+
console.log(chalk.red(` ⢠${gap.title}`));
|
|
2180
|
+
console.log(chalk.gray(` ${gap.suggestedAction}`));
|
|
2181
|
+
}
|
|
2182
|
+
console.log();
|
|
2183
|
+
}
|
|
2184
|
+
if (bySeverity.high.length > 0) {
|
|
2185
|
+
console.log(chalk.yellow(` š High (${bySeverity.high.length}):`));
|
|
2186
|
+
for (const gap of bySeverity.high) {
|
|
2187
|
+
console.log(chalk.yellow(` ⢠${gap.title}`));
|
|
2188
|
+
}
|
|
2189
|
+
console.log();
|
|
2190
|
+
}
|
|
2191
|
+
if (bySeverity.medium.length > 0) {
|
|
2192
|
+
console.log(chalk.blue(` šµ Medium (${bySeverity.medium.length}):`));
|
|
2193
|
+
for (const gap of bySeverity.medium.slice(0, 5)) {
|
|
2194
|
+
console.log(chalk.blue(` ⢠${gap.title}`));
|
|
2195
|
+
}
|
|
2196
|
+
if (bySeverity.medium.length > 5) {
|
|
2197
|
+
console.log(chalk.dim(` ... and ${bySeverity.medium.length - 5} more`));
|
|
2198
|
+
}
|
|
2199
|
+
console.log();
|
|
2200
|
+
}
|
|
2201
|
+
// Recommendations
|
|
2202
|
+
if (analysis.recommendations.length > 0) {
|
|
2203
|
+
console.log(chalk.white(' Recommendations:'));
|
|
2204
|
+
for (const rec of analysis.recommendations) {
|
|
2205
|
+
console.log(chalk.dim(` ${rec}`));
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
console.log();
|
|
2209
|
+
});
|
|
2210
|
+
// =============================================================================
|
|
1969
2211
|
// COMPLETION COMMAND
|
|
1970
2212
|
// =============================================================================
|
|
1971
2213
|
program
|
|
@@ -1977,7 +2219,8 @@ program
|
|
|
1977
2219
|
'init', 'sync', 'validate', 'verify-hooks', 'generate', 'scan', 'improve',
|
|
1978
2220
|
'status', 'dashboard', 'mcp', 'analytics', 'cross-analytics', 'feedback',
|
|
1979
2221
|
'tasks', 'ideas', 'improvements', 'plan', 'capture', 'export',
|
|
1980
|
-
'cloud', 'quickstart', 'doctor', 'opportunities', '
|
|
2222
|
+
'cloud', 'quickstart', 'doctor', 'opportunities', 'wiki',
|
|
2223
|
+
'bootstrap', 'gaps', 'completion'
|
|
1981
2224
|
];
|
|
1982
2225
|
const subcommands = {
|
|
1983
2226
|
cloud: ['status', 'init', 'improvements', 'tasks', 'session']
|