@cloudstreamsoftware/claude-tools 1.0.0 → 1.1.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/README.md +152 -37
- package/agents/INDEX.md +183 -0
- package/agents/architect.md +247 -0
- package/agents/build-error-resolver.md +555 -0
- package/agents/catalyst-deployer.md +132 -0
- package/agents/code-reviewer.md +121 -0
- package/agents/compliance-auditor.md +148 -0
- package/agents/creator-architect.md +395 -0
- package/agents/deluge-reviewer.md +98 -0
- package/agents/doc-updater.md +471 -0
- package/agents/e2e-runner.md +711 -0
- package/agents/planner.md +122 -0
- package/agents/refactor-cleaner.md +309 -0
- package/agents/security-reviewer.md +582 -0
- package/agents/tdd-guide.md +302 -0
- package/config/versions.json +63 -0
- package/dist/hooks/hooks.json +209 -0
- package/dist/index.js +47 -0
- package/dist/lib/asset-value.js +609 -0
- package/dist/lib/client-manager.js +300 -0
- package/dist/lib/command-matcher.js +242 -0
- package/dist/lib/cross-session-patterns.js +754 -0
- package/dist/lib/intent-classifier.js +1075 -0
- package/dist/lib/package-manager.js +374 -0
- package/dist/lib/recommendation-engine.js +597 -0
- package/dist/lib/session-memory.js +489 -0
- package/dist/lib/skill-effectiveness.js +486 -0
- package/dist/lib/skill-matcher.js +595 -0
- package/dist/lib/tutorial-metrics.js +242 -0
- package/dist/lib/tutorial-progress.js +209 -0
- package/dist/lib/tutorial-renderer.js +431 -0
- package/dist/lib/utils.js +380 -0
- package/dist/lib/verify-formatter.js +143 -0
- package/dist/lib/workflow-state.js +249 -0
- package/hooks/hooks.json +209 -0
- package/package.json +5 -1
- package/scripts/aggregate-sessions.js +290 -0
- package/scripts/branch-name-validator.js +291 -0
- package/scripts/build.js +101 -0
- package/scripts/commands/client-switch.js +231 -0
- package/scripts/deprecate-skill.js +610 -0
- package/scripts/diagnose.js +324 -0
- package/scripts/doc-freshness.js +168 -0
- package/scripts/generate-weekly-digest.js +393 -0
- package/scripts/health-check.js +270 -0
- package/scripts/hooks/credential-check.js +101 -0
- package/scripts/hooks/evaluate-session.js +81 -0
- package/scripts/hooks/pre-compact.js +66 -0
- package/scripts/hooks/prompt-analyzer.js +276 -0
- package/scripts/hooks/prompt-router.js +422 -0
- package/scripts/hooks/quality-gate-enforcer.js +371 -0
- package/scripts/hooks/session-end.js +156 -0
- package/scripts/hooks/session-start.js +195 -0
- package/scripts/hooks/skill-injector.js +333 -0
- package/scripts/hooks/suggest-compact.js +58 -0
- package/scripts/lib/asset-value.js +609 -0
- package/scripts/lib/client-manager.js +300 -0
- package/scripts/lib/command-matcher.js +242 -0
- package/scripts/lib/cross-session-patterns.js +754 -0
- package/scripts/lib/intent-classifier.js +1075 -0
- package/scripts/lib/package-manager.js +374 -0
- package/scripts/lib/recommendation-engine.js +597 -0
- package/scripts/lib/session-memory.js +489 -0
- package/scripts/lib/skill-effectiveness.js +486 -0
- package/scripts/lib/skill-matcher.js +595 -0
- package/scripts/lib/tutorial-metrics.js +242 -0
- package/scripts/lib/tutorial-progress.js +209 -0
- package/scripts/lib/tutorial-renderer.js +431 -0
- package/scripts/lib/utils.js +380 -0
- package/scripts/lib/verify-formatter.js +143 -0
- package/scripts/lib/workflow-state.js +249 -0
- package/scripts/onboard.js +363 -0
- package/scripts/quarterly-report.js +692 -0
- package/scripts/setup-package-manager.js +204 -0
- package/scripts/sync-upstream.js +391 -0
- package/scripts/test.js +108 -0
- package/scripts/tutorial-runner.js +351 -0
- package/scripts/validate-all.js +201 -0
- package/scripts/verifiers/agents.js +245 -0
- package/scripts/verifiers/config.js +186 -0
- package/scripts/verifiers/environment.js +123 -0
- package/scripts/verifiers/hooks.js +188 -0
- package/scripts/verifiers/index.js +38 -0
- package/scripts/verifiers/persistence.js +140 -0
- package/scripts/verifiers/plugin.js +215 -0
- package/scripts/verifiers/skills.js +209 -0
- package/scripts/verify-setup.js +164 -0
- package/skills/INDEX.md +157 -0
- package/skills/backend-patterns/SKILL.md +586 -0
- package/skills/backend-patterns/catalyst-patterns.md +128 -0
- package/skills/bigquery-patterns/SKILL.md +27 -0
- package/skills/bigquery-patterns/performance-optimization.md +518 -0
- package/skills/bigquery-patterns/query-patterns.md +372 -0
- package/skills/bigquery-patterns/schema-design.md +78 -0
- package/skills/cloudstream-project-template/SKILL.md +20 -0
- package/skills/cloudstream-project-template/structure.md +65 -0
- package/skills/coding-standards/SKILL.md +524 -0
- package/skills/coding-standards/deluge-standards.md +83 -0
- package/skills/compliance-patterns/SKILL.md +28 -0
- package/skills/compliance-patterns/hipaa/audit-requirements.md +251 -0
- package/skills/compliance-patterns/hipaa/baa-process.md +298 -0
- package/skills/compliance-patterns/hipaa/data-archival-strategy.md +387 -0
- package/skills/compliance-patterns/hipaa/phi-handling.md +52 -0
- package/skills/compliance-patterns/pci-dss/saq-a-requirements.md +307 -0
- package/skills/compliance-patterns/pci-dss/tokenization-patterns.md +382 -0
- package/skills/compliance-patterns/pci-dss/zoho-checkout-patterns.md +56 -0
- package/skills/compliance-patterns/soc2/access-controls.md +344 -0
- package/skills/compliance-patterns/soc2/audit-logging.md +458 -0
- package/skills/compliance-patterns/soc2/change-management.md +403 -0
- package/skills/compliance-patterns/soc2/deluge-execution-logging.md +407 -0
- package/skills/consultancy-workflows/SKILL.md +19 -0
- package/skills/consultancy-workflows/client-isolation.md +21 -0
- package/skills/consultancy-workflows/documentation-automation.md +454 -0
- package/skills/consultancy-workflows/handoff-procedures.md +257 -0
- package/skills/consultancy-workflows/knowledge-capture.md +513 -0
- package/skills/consultancy-workflows/time-tracking.md +26 -0
- package/skills/continuous-learning/SKILL.md +84 -0
- package/skills/continuous-learning/config.json +18 -0
- package/skills/continuous-learning/evaluate-session.sh +60 -0
- package/skills/continuous-learning-v2/SKILL.md +126 -0
- package/skills/continuous-learning-v2/config.json +61 -0
- package/skills/frontend-patterns/SKILL.md +635 -0
- package/skills/frontend-patterns/zoho-widget-patterns.md +103 -0
- package/skills/gcp-data-engineering/SKILL.md +36 -0
- package/skills/gcp-data-engineering/bigquery/performance-optimization.md +337 -0
- package/skills/gcp-data-engineering/dataflow/error-handling.md +496 -0
- package/skills/gcp-data-engineering/dataflow/pipeline-patterns.md +444 -0
- package/skills/gcp-data-engineering/dbt/model-organization.md +63 -0
- package/skills/gcp-data-engineering/dbt/testing-patterns.md +503 -0
- package/skills/gcp-data-engineering/medallion-architecture/bronze-layer.md +60 -0
- package/skills/gcp-data-engineering/medallion-architecture/gold-layer.md +311 -0
- package/skills/gcp-data-engineering/medallion-architecture/layer-transitions.md +517 -0
- package/skills/gcp-data-engineering/medallion-architecture/silver-layer.md +305 -0
- package/skills/gcp-data-engineering/zoho-to-gcp/data-extraction.md +543 -0
- package/skills/gcp-data-engineering/zoho-to-gcp/real-time-vs-batch.md +337 -0
- package/skills/security-review/SKILL.md +498 -0
- package/skills/security-review/compliance-checklist.md +53 -0
- package/skills/strategic-compact/SKILL.md +67 -0
- package/skills/tdd-workflow/SKILL.md +413 -0
- package/skills/tdd-workflow/zoho-testing.md +124 -0
- package/skills/tutorial/SKILL.md +249 -0
- package/skills/tutorial/docs/ACCESSIBILITY.md +169 -0
- package/skills/tutorial/lessons/00-philosophy-and-workflow.md +198 -0
- package/skills/tutorial/lessons/01-basics.md +81 -0
- package/skills/tutorial/lessons/02-training.md +86 -0
- package/skills/tutorial/lessons/03-commands.md +109 -0
- package/skills/tutorial/lessons/04-workflows.md +115 -0
- package/skills/tutorial/lessons/05-compliance.md +116 -0
- package/skills/tutorial/lessons/06-zoho.md +121 -0
- package/skills/tutorial/lessons/07-hooks-system.md +277 -0
- package/skills/tutorial/lessons/08-mcp-servers.md +316 -0
- package/skills/tutorial/lessons/09-client-management.md +215 -0
- package/skills/tutorial/lessons/10-testing-e2e.md +260 -0
- package/skills/tutorial/lessons/11-skills-deep-dive.md +272 -0
- package/skills/tutorial/lessons/12-rules-system.md +326 -0
- package/skills/tutorial/lessons/13-golden-standard-graduation.md +213 -0
- package/skills/tutorial/lessons/14-fork-setup-and-sync.md +312 -0
- package/skills/tutorial/lessons/15-living-examples-system.md +221 -0
- package/skills/tutorial/tracks/accelerated/README.md +134 -0
- package/skills/tutorial/tracks/accelerated/assessment/checkpoint-1.md +161 -0
- package/skills/tutorial/tracks/accelerated/assessment/checkpoint-2.md +175 -0
- package/skills/tutorial/tracks/accelerated/day-1-core-concepts.md +234 -0
- package/skills/tutorial/tracks/accelerated/day-2-essential-commands.md +270 -0
- package/skills/tutorial/tracks/accelerated/day-3-workflow-mastery.md +305 -0
- package/skills/tutorial/tracks/accelerated/day-4-compliance-zoho.md +304 -0
- package/skills/tutorial/tracks/accelerated/day-5-hooks-skills.md +344 -0
- package/skills/tutorial/tracks/accelerated/day-6-client-testing.md +386 -0
- package/skills/tutorial/tracks/accelerated/day-7-graduation.md +369 -0
- package/skills/zoho-patterns/CHANGELOG.md +108 -0
- package/skills/zoho-patterns/SKILL.md +446 -0
- package/skills/zoho-patterns/analytics/dashboard-patterns.md +352 -0
- package/skills/zoho-patterns/analytics/zoho-to-bigquery-pipeline.md +427 -0
- package/skills/zoho-patterns/catalyst/appsail-deployment.md +349 -0
- package/skills/zoho-patterns/catalyst/context-close-patterns.md +354 -0
- package/skills/zoho-patterns/catalyst/cron-batch-processing.md +374 -0
- package/skills/zoho-patterns/catalyst/function-patterns.md +439 -0
- package/skills/zoho-patterns/creator/form-design.md +304 -0
- package/skills/zoho-patterns/creator/publish-api-patterns.md +313 -0
- package/skills/zoho-patterns/creator/widget-integration.md +306 -0
- package/skills/zoho-patterns/creator/workflow-automation.md +253 -0
- package/skills/zoho-patterns/deluge/api-patterns.md +468 -0
- package/skills/zoho-patterns/deluge/batch-processing.md +403 -0
- package/skills/zoho-patterns/deluge/cross-app-integration.md +356 -0
- package/skills/zoho-patterns/deluge/error-handling.md +423 -0
- package/skills/zoho-patterns/deluge/syntax-reference.md +65 -0
- package/skills/zoho-patterns/integration/cors-proxy-architecture.md +426 -0
- package/skills/zoho-patterns/integration/crm-books-native-sync.md +277 -0
- package/skills/zoho-patterns/integration/oauth-token-management.md +461 -0
- package/skills/zoho-patterns/integration/zoho-flow-patterns.md +334 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agents Verifier - Dynamic agent validation using versions.json as source of truth
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { createCheck, createResult, SEVERITY } = require('../lib/verify-formatter');
|
|
8
|
+
const { getPluginRoot } = require('./plugin');
|
|
9
|
+
|
|
10
|
+
const NAME = 'Agents';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Load versions.json registry
|
|
14
|
+
*/
|
|
15
|
+
function loadRegistry() {
|
|
16
|
+
const pluginRoot = getPluginRoot();
|
|
17
|
+
const versionsPath = path.join(pluginRoot, 'config', 'versions.json');
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const content = fs.readFileSync(versionsPath, 'utf8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get active agents from registry
|
|
29
|
+
*/
|
|
30
|
+
function getRegisteredAgents(versions) {
|
|
31
|
+
if (!versions || !versions.agents) return [];
|
|
32
|
+
|
|
33
|
+
return Object.entries(versions.agents)
|
|
34
|
+
.filter(([, info]) => info.status === 'active')
|
|
35
|
+
.map(([name]) => name);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get agents directory path
|
|
40
|
+
*/
|
|
41
|
+
function getAgentsDir() {
|
|
42
|
+
const pluginRoot = getPluginRoot();
|
|
43
|
+
|
|
44
|
+
// Check multiple possible locations
|
|
45
|
+
const locations = [
|
|
46
|
+
path.join(pluginRoot, 'agents'),
|
|
47
|
+
path.join(pluginRoot, '..', 'agents'),
|
|
48
|
+
path.join(process.cwd(), 'agents'),
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
for (const loc of locations) {
|
|
52
|
+
if (fs.existsSync(loc)) {
|
|
53
|
+
return loc;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return path.join(pluginRoot, 'agents');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get existing agent files
|
|
62
|
+
*/
|
|
63
|
+
function getExistingAgents() {
|
|
64
|
+
const agentsDir = getAgentsDir();
|
|
65
|
+
|
|
66
|
+
if (!fs.existsSync(agentsDir)) return [];
|
|
67
|
+
|
|
68
|
+
return fs
|
|
69
|
+
.readdirSync(agentsDir)
|
|
70
|
+
.filter((f) => f.endsWith('.md') && f !== 'INDEX.md')
|
|
71
|
+
.map((f) => f.replace('.md', ''));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check registry vs disk bidirectionally
|
|
76
|
+
*/
|
|
77
|
+
function checkRegistrySync() {
|
|
78
|
+
const versions = loadRegistry();
|
|
79
|
+
const checks = [];
|
|
80
|
+
|
|
81
|
+
if (!versions) {
|
|
82
|
+
return [
|
|
83
|
+
createCheck('Agents registry', false, {
|
|
84
|
+
severity: SEVERITY.WARNING,
|
|
85
|
+
message: 'cannot load versions.json',
|
|
86
|
+
remediation: 'Fix or create config/versions.json',
|
|
87
|
+
}),
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const registered = getRegisteredAgents(versions);
|
|
92
|
+
const existing = getExistingAgents();
|
|
93
|
+
|
|
94
|
+
// Check: All registered agents exist on disk
|
|
95
|
+
const missing = registered.filter((a) => !existing.includes(a));
|
|
96
|
+
if (missing.length > 0) {
|
|
97
|
+
checks.push(
|
|
98
|
+
createCheck('Registered agents exist', false, {
|
|
99
|
+
severity: SEVERITY.WARNING,
|
|
100
|
+
message: `missing: ${missing.slice(0, 3).join(', ')}${missing.length > 3 ? '...' : ''}`,
|
|
101
|
+
remediation: `Create missing agent files or update versions.json`,
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
} else {
|
|
105
|
+
checks.push(
|
|
106
|
+
createCheck('Registered agents exist', true, {
|
|
107
|
+
message: `${registered.length} verified`,
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check: All existing agents are registered
|
|
113
|
+
const unregistered = existing.filter((a) => !registered.includes(a));
|
|
114
|
+
if (unregistered.length > 0) {
|
|
115
|
+
checks.push(
|
|
116
|
+
createCheck('Agents are registered', false, {
|
|
117
|
+
severity: SEVERITY.WARNING,
|
|
118
|
+
message: `unregistered: ${unregistered.slice(0, 3).join(', ')}${unregistered.length > 3 ? '...' : ''}`,
|
|
119
|
+
remediation: `Add agents to versions.json or remove files`,
|
|
120
|
+
})
|
|
121
|
+
);
|
|
122
|
+
} else {
|
|
123
|
+
checks.push(
|
|
124
|
+
createCheck('Agents are registered', true, {
|
|
125
|
+
message: `${existing.length} on disk`,
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return checks;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Parse YAML frontmatter from markdown
|
|
135
|
+
*/
|
|
136
|
+
function parseFrontmatter(content) {
|
|
137
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
138
|
+
if (!match) return null;
|
|
139
|
+
|
|
140
|
+
const frontmatter = {};
|
|
141
|
+
const lines = match[1].split('\n');
|
|
142
|
+
|
|
143
|
+
for (const line of lines) {
|
|
144
|
+
const colonIndex = line.indexOf(':');
|
|
145
|
+
if (colonIndex > 0) {
|
|
146
|
+
const key = line.slice(0, colonIndex).trim();
|
|
147
|
+
const value = line.slice(colonIndex + 1).trim();
|
|
148
|
+
frontmatter[key] = value;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return frontmatter;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Check agents have valid frontmatter
|
|
157
|
+
*/
|
|
158
|
+
function checkAgentFrontmatter() {
|
|
159
|
+
const agentsDir = getAgentsDir();
|
|
160
|
+
const checks = [];
|
|
161
|
+
|
|
162
|
+
if (!fs.existsSync(agentsDir)) {
|
|
163
|
+
return [
|
|
164
|
+
createCheck('Agent frontmatter', false, {
|
|
165
|
+
severity: SEVERITY.WARNING,
|
|
166
|
+
message: 'agents/ directory not found',
|
|
167
|
+
}),
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const agentFiles = fs.readdirSync(agentsDir).filter((f) => f.endsWith('.md') && f !== 'INDEX.md');
|
|
172
|
+
|
|
173
|
+
let validCount = 0;
|
|
174
|
+
let invalidAgents = [];
|
|
175
|
+
|
|
176
|
+
for (const file of agentFiles) {
|
|
177
|
+
const filePath = path.join(agentsDir, file);
|
|
178
|
+
try {
|
|
179
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
180
|
+
const frontmatter = parseFrontmatter(content);
|
|
181
|
+
|
|
182
|
+
if (!frontmatter) {
|
|
183
|
+
invalidAgents.push({ file, reason: 'no frontmatter' });
|
|
184
|
+
} else if (!frontmatter.name) {
|
|
185
|
+
invalidAgents.push({ file, reason: 'missing name' });
|
|
186
|
+
} else if (!frontmatter.model) {
|
|
187
|
+
invalidAgents.push({ file, reason: 'missing model' });
|
|
188
|
+
} else {
|
|
189
|
+
validCount++;
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
invalidAgents.push({ file, reason: 'read error' });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (invalidAgents.length > 0) {
|
|
197
|
+
const examples = invalidAgents.slice(0, 2).map((a) => `${a.file} (${a.reason})`);
|
|
198
|
+
checks.push(
|
|
199
|
+
createCheck('Agent frontmatter', false, {
|
|
200
|
+
severity: SEVERITY.WARNING,
|
|
201
|
+
message: `${invalidAgents.length} invalid`,
|
|
202
|
+
remediation: `Fix: ${examples.join(', ')}${invalidAgents.length > 2 ? '...' : ''}`,
|
|
203
|
+
})
|
|
204
|
+
);
|
|
205
|
+
} else {
|
|
206
|
+
checks.push(
|
|
207
|
+
createCheck('Agent frontmatter', true, {
|
|
208
|
+
message: `${validCount} valid`,
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return checks;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Check INDEX.md exists
|
|
218
|
+
*/
|
|
219
|
+
function checkIndexFile() {
|
|
220
|
+
const agentsDir = getAgentsDir();
|
|
221
|
+
const indexPath = path.join(agentsDir, 'INDEX.md');
|
|
222
|
+
|
|
223
|
+
if (fs.existsSync(indexPath)) {
|
|
224
|
+
return createCheck('INDEX.md', true, {
|
|
225
|
+
message: 'found',
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return createCheck('INDEX.md', false, {
|
|
230
|
+
severity: SEVERITY.WARNING,
|
|
231
|
+
message: 'not found',
|
|
232
|
+
remediation: 'Create agents/INDEX.md listing all agents',
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Run all agents checks
|
|
238
|
+
*/
|
|
239
|
+
function verify() {
|
|
240
|
+
const checks = [...checkRegistrySync(), ...checkAgentFrontmatter(), checkIndexFile()];
|
|
241
|
+
|
|
242
|
+
return createResult(NAME, checks);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
module.exports = { verify, NAME };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Verifier - JSON configuration file validation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { createCheck, createResult, SEVERITY } = require('../lib/verify-formatter');
|
|
8
|
+
const { getPluginRoot } = require('./plugin');
|
|
9
|
+
|
|
10
|
+
const NAME = 'Config';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check a JSON config file
|
|
14
|
+
*/
|
|
15
|
+
function checkConfigFile(name, filePath, requiredFields = []) {
|
|
16
|
+
if (!fs.existsSync(filePath)) {
|
|
17
|
+
return createCheck(name, false, {
|
|
18
|
+
severity: SEVERITY.WARNING,
|
|
19
|
+
message: 'not found',
|
|
20
|
+
remediation: `Create ${name} configuration file`,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
26
|
+
const config = JSON.parse(content);
|
|
27
|
+
|
|
28
|
+
// Check required fields
|
|
29
|
+
const missingFields = requiredFields.filter((field) => !config[field]);
|
|
30
|
+
if (missingFields.length > 0) {
|
|
31
|
+
return createCheck(name, false, {
|
|
32
|
+
severity: SEVERITY.WARNING,
|
|
33
|
+
message: `missing: ${missingFields.join(', ')}`,
|
|
34
|
+
remediation: `Add missing fields to ${name}`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return createCheck(name, true, {
|
|
39
|
+
message: 'valid',
|
|
40
|
+
});
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return createCheck(name, false, {
|
|
43
|
+
severity: SEVERITY.CRITICAL,
|
|
44
|
+
message: 'JSON parse error',
|
|
45
|
+
remediation: `Fix JSON syntax in ${name}`,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check versions.json (critical - source of truth)
|
|
52
|
+
*/
|
|
53
|
+
function checkVersionsJson() {
|
|
54
|
+
const pluginRoot = getPluginRoot();
|
|
55
|
+
const configPath = path.join(pluginRoot, 'config', 'versions.json');
|
|
56
|
+
|
|
57
|
+
const check = checkConfigFile('versions.json', configPath, ['skills', 'agents']);
|
|
58
|
+
|
|
59
|
+
if (check.passed) {
|
|
60
|
+
try {
|
|
61
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
62
|
+
const config = JSON.parse(content);
|
|
63
|
+
const skillCount = Object.keys(config.skills || {}).length;
|
|
64
|
+
const agentCount = Object.keys(config.agents || {}).length;
|
|
65
|
+
check.message = `${skillCount} skills, ${agentCount} agents`;
|
|
66
|
+
} catch {
|
|
67
|
+
// Already handled
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
check.severity = SEVERITY.CRITICAL;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return check;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Check quality-gates.json
|
|
78
|
+
*/
|
|
79
|
+
function checkQualityGatesJson() {
|
|
80
|
+
const pluginRoot = getPluginRoot();
|
|
81
|
+
const configPath = path.join(pluginRoot, 'config', 'quality-gates.json');
|
|
82
|
+
|
|
83
|
+
const check = checkConfigFile('quality-gates.json', configPath, ['gates']);
|
|
84
|
+
|
|
85
|
+
if (check.passed) {
|
|
86
|
+
try {
|
|
87
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
88
|
+
const config = JSON.parse(content);
|
|
89
|
+
const gateCount = Object.keys(config.gates || {}).length;
|
|
90
|
+
check.message = `${gateCount} gates defined`;
|
|
91
|
+
} catch {
|
|
92
|
+
// Already handled
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return check;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check for .env in repo root (should not exist)
|
|
101
|
+
*/
|
|
102
|
+
function checkNoEnvInRepo() {
|
|
103
|
+
const pluginRoot = getPluginRoot();
|
|
104
|
+
// Check both plugin root and parent
|
|
105
|
+
const envLocations = [
|
|
106
|
+
path.join(pluginRoot, '.env'),
|
|
107
|
+
path.join(pluginRoot, '..', '.env'),
|
|
108
|
+
path.join(pluginRoot, '.env.local'),
|
|
109
|
+
path.join(pluginRoot, '..', '.env.local'),
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
for (const envPath of envLocations) {
|
|
113
|
+
if (fs.existsSync(envPath)) {
|
|
114
|
+
return createCheck('No .env in repo', false, {
|
|
115
|
+
severity: SEVERITY.CRITICAL,
|
|
116
|
+
message: 'found .env file',
|
|
117
|
+
remediation: 'Remove .env from repo and add to .gitignore',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return createCheck('No .env in repo', true, {
|
|
123
|
+
message: 'clean',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check other config files
|
|
129
|
+
*/
|
|
130
|
+
function checkOtherConfigs() {
|
|
131
|
+
const pluginRoot = getPluginRoot();
|
|
132
|
+
const configDir = path.join(pluginRoot, 'config');
|
|
133
|
+
const checks = [];
|
|
134
|
+
|
|
135
|
+
const optionalConfigs = [
|
|
136
|
+
'aggregation.json',
|
|
137
|
+
'asset-value.json',
|
|
138
|
+
'onboarding-milestones.json',
|
|
139
|
+
'prompt-router.json',
|
|
140
|
+
'shared-knowledge.json',
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
if (!fs.existsSync(configDir)) {
|
|
144
|
+
return [
|
|
145
|
+
createCheck('config/ directory', false, {
|
|
146
|
+
severity: SEVERITY.WARNING,
|
|
147
|
+
message: 'not found',
|
|
148
|
+
}),
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (const configName of optionalConfigs) {
|
|
153
|
+
const configPath = path.join(configDir, configName);
|
|
154
|
+
if (fs.existsSync(configPath)) {
|
|
155
|
+
const check = checkConfigFile(configName, configPath);
|
|
156
|
+
checks.push(check);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Summary if no optional configs checked
|
|
161
|
+
if (checks.length === 0) {
|
|
162
|
+
checks.push(
|
|
163
|
+
createCheck('Optional configs', true, {
|
|
164
|
+
message: 'none present (ok)',
|
|
165
|
+
})
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return checks;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Run all config checks
|
|
174
|
+
*/
|
|
175
|
+
function verify() {
|
|
176
|
+
const checks = [
|
|
177
|
+
checkVersionsJson(),
|
|
178
|
+
checkQualityGatesJson(),
|
|
179
|
+
checkNoEnvInRepo(),
|
|
180
|
+
...checkOtherConfigs(),
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
return createResult(NAME, checks);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = { verify, NAME };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Verifier - System prerequisites check
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const { createCheck, createResult, SEVERITY } = require('../lib/verify-formatter');
|
|
7
|
+
const { commandExists } = require('../lib/utils');
|
|
8
|
+
|
|
9
|
+
const NAME = 'Environment';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check Node.js version (requires >= 18)
|
|
13
|
+
*/
|
|
14
|
+
function checkNodeVersion() {
|
|
15
|
+
const version = process.versions.node;
|
|
16
|
+
const major = parseInt(version.split('.')[0], 10);
|
|
17
|
+
const passed = major >= 18;
|
|
18
|
+
|
|
19
|
+
return createCheck('Node.js', passed, {
|
|
20
|
+
message: `v${version}`,
|
|
21
|
+
severity: passed ? SEVERITY.INFO : SEVERITY.CRITICAL,
|
|
22
|
+
remediation: 'Install Node.js 18+ from https://nodejs.org',
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check Git is installed
|
|
28
|
+
*/
|
|
29
|
+
function checkGit() {
|
|
30
|
+
try {
|
|
31
|
+
const version = execSync('git --version', { encoding: 'utf8' }).trim();
|
|
32
|
+
const match = version.match(/(\d+\.\d+\.\d+)/);
|
|
33
|
+
return createCheck('Git', true, {
|
|
34
|
+
message: match ? `v${match[1]}` : 'installed',
|
|
35
|
+
});
|
|
36
|
+
} catch {
|
|
37
|
+
return createCheck('Git', false, {
|
|
38
|
+
severity: SEVERITY.CRITICAL,
|
|
39
|
+
remediation: 'Install Git from https://git-scm.com',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check package manager availability
|
|
46
|
+
*/
|
|
47
|
+
function checkPackageManager() {
|
|
48
|
+
const managers = ['npm', 'yarn', 'pnpm', 'bun'];
|
|
49
|
+
let found = null;
|
|
50
|
+
|
|
51
|
+
for (const manager of managers) {
|
|
52
|
+
if (commandExists(manager)) {
|
|
53
|
+
found = manager;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (found) {
|
|
59
|
+
return createCheck('Package Manager', true, {
|
|
60
|
+
message: found,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return createCheck('Package Manager', false, {
|
|
65
|
+
severity: SEVERITY.CRITICAL,
|
|
66
|
+
remediation: 'Install Node.js (includes npm) from https://nodejs.org',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check Git user.email is configured
|
|
72
|
+
*/
|
|
73
|
+
function checkGitEmail() {
|
|
74
|
+
try {
|
|
75
|
+
const email = execSync('git config user.email', { encoding: 'utf8' }).trim();
|
|
76
|
+
return createCheck('Git user.email', !!email, {
|
|
77
|
+
message: email ? 'configured' : 'not set',
|
|
78
|
+
severity: email ? SEVERITY.INFO : SEVERITY.WARNING,
|
|
79
|
+
remediation: 'git config --global user.email "you@example.com"',
|
|
80
|
+
});
|
|
81
|
+
} catch {
|
|
82
|
+
return createCheck('Git user.email', false, {
|
|
83
|
+
severity: SEVERITY.WARNING,
|
|
84
|
+
remediation: 'git config --global user.email "you@example.com"',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check Git user.name is configured
|
|
91
|
+
*/
|
|
92
|
+
function checkGitName() {
|
|
93
|
+
try {
|
|
94
|
+
const name = execSync('git config user.name', { encoding: 'utf8' }).trim();
|
|
95
|
+
return createCheck('Git user.name', !!name, {
|
|
96
|
+
message: name ? 'configured' : 'not set',
|
|
97
|
+
severity: name ? SEVERITY.INFO : SEVERITY.WARNING,
|
|
98
|
+
remediation: 'git config --global user.name "Your Name"',
|
|
99
|
+
});
|
|
100
|
+
} catch {
|
|
101
|
+
return createCheck('Git user.name', false, {
|
|
102
|
+
severity: SEVERITY.WARNING,
|
|
103
|
+
remediation: 'git config --global user.name "Your Name"',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Run all environment checks
|
|
110
|
+
*/
|
|
111
|
+
function verify() {
|
|
112
|
+
const checks = [
|
|
113
|
+
checkNodeVersion(),
|
|
114
|
+
checkGit(),
|
|
115
|
+
checkPackageManager(),
|
|
116
|
+
checkGitEmail(),
|
|
117
|
+
checkGitName(),
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
return createResult(NAME, checks);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = { verify, NAME };
|