@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,371 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Quality Gate Enforcer Hook
|
|
5
|
+
*
|
|
6
|
+
* Enforces quality gates on Edit/Write operations.
|
|
7
|
+
* Gates can warn, block, or require confirmation based on severity.
|
|
8
|
+
*
|
|
9
|
+
* Hook Type: PreToolUse (Edit, Write, Bash for git commit)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const { readStdinJson, log, output, getClaudeDir, readFile } = require('../lib/utils');
|
|
15
|
+
|
|
16
|
+
// Load gate configuration
|
|
17
|
+
const GATES_CONFIG_PATH = path.join(__dirname, '..', '..', 'config', 'quality-gates.json');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Load quality gates configuration
|
|
21
|
+
*/
|
|
22
|
+
function loadGatesConfig() {
|
|
23
|
+
try {
|
|
24
|
+
const content = fs.readFileSync(GATES_CONFIG_PATH, 'utf8');
|
|
25
|
+
return JSON.parse(content);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
log(`[QualityGate] Error loading config: ${err.message}`);
|
|
28
|
+
return { gates: {}, enforcement: { currentPhase: 'warn_all' } };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get current compliance mode from environment or session
|
|
34
|
+
*/
|
|
35
|
+
function getComplianceMode() {
|
|
36
|
+
// Check environment variable first
|
|
37
|
+
if (process.env.CLOUDSTREAM_COMPLIANCE_MODE) {
|
|
38
|
+
return process.env.CLOUDSTREAM_COMPLIANCE_MODE.toLowerCase();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Try to read from session memory
|
|
42
|
+
try {
|
|
43
|
+
const memoryPath = path.join(getClaudeDir(), 'memory', 'current-session.json');
|
|
44
|
+
if (fs.existsSync(memoryPath)) {
|
|
45
|
+
const memory = JSON.parse(fs.readFileSync(memoryPath, 'utf8'));
|
|
46
|
+
if (memory.context && memory.context.complianceMode) {
|
|
47
|
+
return memory.context.complianceMode;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
// Ignore errors
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check if a gate is bypassed via environment variable
|
|
59
|
+
*/
|
|
60
|
+
function isGateBypassed(gateId) {
|
|
61
|
+
const bypassList = process.env.CLOUDSTREAM_BYPASS_GATES;
|
|
62
|
+
if (!bypassList) return false;
|
|
63
|
+
|
|
64
|
+
return bypassList
|
|
65
|
+
.split(',')
|
|
66
|
+
.map((s) => s.trim())
|
|
67
|
+
.includes(gateId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Log gate override for audit trail
|
|
72
|
+
*/
|
|
73
|
+
function logOverride(gateId, filePath, reason) {
|
|
74
|
+
const logPath = path.join(getClaudeDir(), 'sessions', 'gate-overrides.log');
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const entry = `${new Date().toISOString()} | OVERRIDE | ${gateId} | ${filePath} | ${reason || 'No reason provided'}\n`;
|
|
78
|
+
|
|
79
|
+
// Ensure directory exists
|
|
80
|
+
const dir = path.dirname(logPath);
|
|
81
|
+
if (!fs.existsSync(dir)) {
|
|
82
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fs.appendFileSync(logPath, entry);
|
|
86
|
+
} catch {
|
|
87
|
+
// Ignore logging errors
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check content against a gate's patterns
|
|
93
|
+
*/
|
|
94
|
+
function checkGatePatterns(gate, content, filePath) {
|
|
95
|
+
const violations = [];
|
|
96
|
+
|
|
97
|
+
// Skip if gate has specific file patterns and file doesn't match
|
|
98
|
+
if (gate.filePatterns) {
|
|
99
|
+
const matchesFile = gate.filePatterns.some((pattern) => {
|
|
100
|
+
const regex = new RegExp(pattern);
|
|
101
|
+
return regex.test(filePath);
|
|
102
|
+
});
|
|
103
|
+
if (!matchesFile) return violations;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Skip if gate has exclude patterns and file matches
|
|
107
|
+
if (gate.excludePatterns) {
|
|
108
|
+
const isExcluded = gate.excludePatterns.some((pattern) => {
|
|
109
|
+
const regex = new RegExp(pattern);
|
|
110
|
+
return regex.test(filePath);
|
|
111
|
+
});
|
|
112
|
+
if (isExcluded) return violations;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Check each pattern
|
|
116
|
+
if (gate.patterns) {
|
|
117
|
+
for (const patternStr of gate.patterns) {
|
|
118
|
+
try {
|
|
119
|
+
const regex = new RegExp(patternStr, 'gm');
|
|
120
|
+
const matches = content.match(regex);
|
|
121
|
+
|
|
122
|
+
if (matches && matches.length > 0) {
|
|
123
|
+
// If antiPatterns exist, check if they're present too
|
|
124
|
+
if (gate.antiPatterns) {
|
|
125
|
+
const hasAntiPattern = gate.antiPatterns.some((ap) => {
|
|
126
|
+
const apRegex = new RegExp(ap, 'gm');
|
|
127
|
+
return apRegex.test(content);
|
|
128
|
+
});
|
|
129
|
+
if (hasAntiPattern) continue; // Skip this violation if anti-pattern present
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
violations.push({
|
|
133
|
+
gateId: gate.id,
|
|
134
|
+
gateName: gate.name,
|
|
135
|
+
severity: gate.severity,
|
|
136
|
+
action: gate.action,
|
|
137
|
+
matchCount: matches.length,
|
|
138
|
+
matches: matches.slice(0, 3), // Limit to first 3 matches
|
|
139
|
+
message: gate.message,
|
|
140
|
+
remediation: gate.remediation,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
} catch (err) {
|
|
144
|
+
log(`[QualityGate] Invalid pattern in ${gate.id}: ${patternStr}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Check file size (line count)
|
|
150
|
+
if (gate.checkType === 'line_count' || gate.id === 'large_file') {
|
|
151
|
+
const lineCount = content.split('\n').length;
|
|
152
|
+
if (lineCount > (gate.threshold || 800)) {
|
|
153
|
+
violations.push({
|
|
154
|
+
gateId: gate.id,
|
|
155
|
+
gateName: gate.name,
|
|
156
|
+
severity: gate.severity,
|
|
157
|
+
action: gate.action,
|
|
158
|
+
lineCount,
|
|
159
|
+
threshold: gate.threshold || 800,
|
|
160
|
+
message: gate.message,
|
|
161
|
+
remediation: gate.remediation,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return violations;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Check for Deluge statement count
|
|
171
|
+
*/
|
|
172
|
+
function checkDelugeStatements(content, gate) {
|
|
173
|
+
// Simple statement count heuristic for Deluge
|
|
174
|
+
// Count semicolons and certain keywords
|
|
175
|
+
const statements = (content.match(/;/g) || []).length;
|
|
176
|
+
const ifStatements = (content.match(/\bif\b/gi) || []).length;
|
|
177
|
+
const forStatements = (content.match(/\bfor\b/gi) || []).length;
|
|
178
|
+
const whileStatements = (content.match(/\bwhile\b/gi) || []).length;
|
|
179
|
+
|
|
180
|
+
const estimatedStatements = statements + ifStatements + forStatements + whileStatements;
|
|
181
|
+
|
|
182
|
+
if (estimatedStatements > (gate.threshold || 4500)) {
|
|
183
|
+
return {
|
|
184
|
+
gateId: gate.id,
|
|
185
|
+
gateName: gate.name,
|
|
186
|
+
severity: gate.severity,
|
|
187
|
+
action: gate.action,
|
|
188
|
+
estimatedStatements,
|
|
189
|
+
threshold: gate.threshold || 4500,
|
|
190
|
+
message: `Estimated ${estimatedStatements} statements (limit: 5000). ${gate.message}`,
|
|
191
|
+
remediation: gate.remediation,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Format violation message for output
|
|
200
|
+
*/
|
|
201
|
+
function formatViolation(violation) {
|
|
202
|
+
const severityEmoji = {
|
|
203
|
+
critical: '🛑',
|
|
204
|
+
high: '⚠️',
|
|
205
|
+
medium: '⚡',
|
|
206
|
+
low: 'ℹ️',
|
|
207
|
+
warning: '⚠️',
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const emoji = severityEmoji[violation.severity] || '⚠️';
|
|
211
|
+
let msg = `${emoji} [${violation.severity.toUpperCase()}] ${violation.gateName}`;
|
|
212
|
+
msg += `\n ${violation.message}`;
|
|
213
|
+
|
|
214
|
+
if (violation.matchCount) {
|
|
215
|
+
msg += `\n Found: ${violation.matchCount} occurrence(s)`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (violation.lineCount) {
|
|
219
|
+
msg += `\n Lines: ${violation.lineCount} (threshold: ${violation.threshold})`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (violation.remediation) {
|
|
223
|
+
msg += `\n Fix: ${violation.remediation}`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return msg;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Determine action based on enforcement phase
|
|
231
|
+
*/
|
|
232
|
+
function getEffectiveAction(violation, config) {
|
|
233
|
+
const phase = config.enforcement?.currentPhase || 'full_enforcement';
|
|
234
|
+
|
|
235
|
+
switch (phase) {
|
|
236
|
+
case 'warn_all':
|
|
237
|
+
return 'warn';
|
|
238
|
+
|
|
239
|
+
case 'block_critical':
|
|
240
|
+
return violation.severity === 'critical' ? 'block' : 'warn';
|
|
241
|
+
|
|
242
|
+
case 'full_enforcement':
|
|
243
|
+
default:
|
|
244
|
+
return violation.action;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Main hook execution
|
|
250
|
+
*/
|
|
251
|
+
async function main() {
|
|
252
|
+
try {
|
|
253
|
+
const input = await readStdinJson();
|
|
254
|
+
const config = loadGatesConfig();
|
|
255
|
+
const complianceMode = getComplianceMode();
|
|
256
|
+
|
|
257
|
+
// Determine what we're checking
|
|
258
|
+
const tool = input.tool;
|
|
259
|
+
const toolInput = input.tool_input || {};
|
|
260
|
+
|
|
261
|
+
let filePath = null;
|
|
262
|
+
let content = null;
|
|
263
|
+
|
|
264
|
+
// Get file path and content based on tool
|
|
265
|
+
if (tool === 'Edit' || tool === 'Write') {
|
|
266
|
+
filePath = toolInput.file_path;
|
|
267
|
+
content = toolInput.new_string || toolInput.content || '';
|
|
268
|
+
|
|
269
|
+
// For Edit, we should check the full file after edit
|
|
270
|
+
// For now, just check the new content being written
|
|
271
|
+
} else if (tool === 'Bash') {
|
|
272
|
+
const cmd = toolInput.command || '';
|
|
273
|
+
|
|
274
|
+
// Check if this is a git commit
|
|
275
|
+
if (!cmd.includes('git commit') && !cmd.includes('git push')) {
|
|
276
|
+
// Not a commit-related command, skip
|
|
277
|
+
output(JSON.stringify(input));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// For git operations, we'd need to check staged files
|
|
282
|
+
// This is a simplified check - could be enhanced
|
|
283
|
+
log('[QualityGate] Git operation detected - pre-commit checks apply');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (!filePath || !content) {
|
|
287
|
+
// Nothing to check
|
|
288
|
+
output(JSON.stringify(input));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Collect violations
|
|
293
|
+
const violations = [];
|
|
294
|
+
const blockers = [];
|
|
295
|
+
const warnings = [];
|
|
296
|
+
|
|
297
|
+
// Check each enabled gate
|
|
298
|
+
for (const [gateId, gate] of Object.entries(config.gates)) {
|
|
299
|
+
if (!gate.enabled) continue;
|
|
300
|
+
|
|
301
|
+
// Skip compliance-specific gates if not in that mode
|
|
302
|
+
if (gate.complianceMode && gate.complianceMode !== complianceMode) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Check if bypassed
|
|
307
|
+
if (isGateBypassed(gateId)) {
|
|
308
|
+
logOverride(gateId, filePath, 'ENV_BYPASS');
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Run gate checks
|
|
313
|
+
const gateViolations = checkGatePatterns(gate, content, filePath);
|
|
314
|
+
|
|
315
|
+
// Special check for Deluge files
|
|
316
|
+
if (gate.id === 'deluge_statement_limit' && filePath.endsWith('.ds')) {
|
|
317
|
+
const delugeViolation = checkDelugeStatements(content, gate);
|
|
318
|
+
if (delugeViolation) {
|
|
319
|
+
gateViolations.push(delugeViolation);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Categorize violations
|
|
324
|
+
for (const violation of gateViolations) {
|
|
325
|
+
const effectiveAction = getEffectiveAction(violation, config);
|
|
326
|
+
violation.effectiveAction = effectiveAction;
|
|
327
|
+
|
|
328
|
+
if (effectiveAction === 'block') {
|
|
329
|
+
blockers.push(violation);
|
|
330
|
+
} else {
|
|
331
|
+
warnings.push(violation);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
violations.push(violation);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Output warnings
|
|
339
|
+
if (warnings.length > 0) {
|
|
340
|
+
log('[QualityGate] Warnings:');
|
|
341
|
+
for (const warning of warnings) {
|
|
342
|
+
log(formatViolation(warning));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Handle blockers
|
|
347
|
+
if (blockers.length > 0) {
|
|
348
|
+
log('');
|
|
349
|
+
log('[QualityGate] 🛑 BLOCKED - Critical violations found:');
|
|
350
|
+
for (const blocker of blockers) {
|
|
351
|
+
log(formatViolation(blocker));
|
|
352
|
+
}
|
|
353
|
+
log('');
|
|
354
|
+
log('[QualityGate] Operation blocked. Fix violations before proceeding.');
|
|
355
|
+
log('[QualityGate] To bypass (use with caution): set CLOUDSTREAM_BYPASS_GATES=gate_id');
|
|
356
|
+
|
|
357
|
+
// Exit with error to block the operation
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Pass through if no blockers
|
|
362
|
+
output(JSON.stringify(input));
|
|
363
|
+
} catch (err) {
|
|
364
|
+
log(`[QualityGate] Error: ${err.message}`);
|
|
365
|
+
// On error, pass through to avoid blocking
|
|
366
|
+
output('{}');
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Run
|
|
371
|
+
main();
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Stop Hook (Session End) - Persist learnings when session ends
|
|
4
|
+
*
|
|
5
|
+
* Cross-platform (Windows, macOS, Linux)
|
|
6
|
+
*
|
|
7
|
+
* Runs when Claude session ends. Creates/updates session log file
|
|
8
|
+
* with timestamp for continuity tracking.
|
|
9
|
+
*
|
|
10
|
+
* Also integrates:
|
|
11
|
+
* - Session memory archival (corrections, preferences, patterns)
|
|
12
|
+
* - Skill effectiveness reporting
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const {
|
|
18
|
+
getSessionsDir,
|
|
19
|
+
getDateString,
|
|
20
|
+
getTimeString,
|
|
21
|
+
ensureDir,
|
|
22
|
+
writeFile,
|
|
23
|
+
replaceInFile,
|
|
24
|
+
log,
|
|
25
|
+
} = require('../lib/utils');
|
|
26
|
+
|
|
27
|
+
// Import self-healing modules (with fallback if not yet created)
|
|
28
|
+
let sessionMemory = null;
|
|
29
|
+
let skillEffectiveness = null;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
sessionMemory = require('../lib/session-memory');
|
|
33
|
+
} catch (e) {
|
|
34
|
+
// Module not yet available
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
skillEffectiveness = require('../lib/skill-effectiveness');
|
|
39
|
+
} catch (e) {
|
|
40
|
+
// Module not yet available
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function main() {
|
|
44
|
+
const sessionsDir = getSessionsDir();
|
|
45
|
+
const today = getDateString();
|
|
46
|
+
const sessionFile = path.join(sessionsDir, `${today}-session.tmp`);
|
|
47
|
+
|
|
48
|
+
ensureDir(sessionsDir);
|
|
49
|
+
|
|
50
|
+
const currentTime = getTimeString();
|
|
51
|
+
|
|
52
|
+
// If session file exists for today, update the end time
|
|
53
|
+
if (fs.existsSync(sessionFile)) {
|
|
54
|
+
const success = replaceInFile(
|
|
55
|
+
sessionFile,
|
|
56
|
+
/\*\*Last Updated:\*\*.*/,
|
|
57
|
+
`**Last Updated:** ${currentTime}`
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (success) {
|
|
61
|
+
log(`[SessionEnd] Updated session file: ${sessionFile}`);
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
// Create new session file with template
|
|
65
|
+
const template = `# Session: ${today}
|
|
66
|
+
**Date:** ${today}
|
|
67
|
+
**Started:** ${currentTime}
|
|
68
|
+
**Last Updated:** ${currentTime}
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Current State
|
|
73
|
+
|
|
74
|
+
[Session context goes here]
|
|
75
|
+
|
|
76
|
+
### Completed
|
|
77
|
+
- [ ]
|
|
78
|
+
|
|
79
|
+
### In Progress
|
|
80
|
+
- [ ]
|
|
81
|
+
|
|
82
|
+
### Notes for Next Session
|
|
83
|
+
-
|
|
84
|
+
|
|
85
|
+
### Context to Load
|
|
86
|
+
\`\`\`
|
|
87
|
+
[relevant files]
|
|
88
|
+
\`\`\`
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
writeFile(sessionFile, template);
|
|
92
|
+
log(`[SessionEnd] Created session file: ${sessionFile}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// === Self-Healing Integrations ===
|
|
96
|
+
|
|
97
|
+
// 1. Archive session memory (corrections, preferences, patterns)
|
|
98
|
+
if (sessionMemory) {
|
|
99
|
+
try {
|
|
100
|
+
const summary = sessionMemory.getSessionSummary();
|
|
101
|
+
|
|
102
|
+
if (summary.correctionCount > 0 || summary.effectivePatternCount > 0) {
|
|
103
|
+
log(`[SessionEnd] Session learning summary:`);
|
|
104
|
+
log(` - Corrections recorded: ${summary.correctionCount}`);
|
|
105
|
+
log(` - Effective patterns: ${summary.effectivePatternCount}`);
|
|
106
|
+
log(` - Technologies used: ${summary.technologies.join(', ') || 'none'}`);
|
|
107
|
+
|
|
108
|
+
// Merge corrections to persistent knowledge
|
|
109
|
+
const mergeResult = sessionMemory.mergeCorrectionsToKnowledge();
|
|
110
|
+
if (mergeResult.success && mergeResult.merged > 0) {
|
|
111
|
+
log(` - Merged ${mergeResult.merged} corrections to knowledge base`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Archive the session
|
|
115
|
+
const archiveResult = sessionMemory.archiveSession();
|
|
116
|
+
if (archiveResult.success) {
|
|
117
|
+
log(` - Session archived for future learning`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (e) {
|
|
121
|
+
log(`[SessionEnd] Session memory error: ${e.message}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 2. Generate skill effectiveness summary
|
|
126
|
+
if (skillEffectiveness) {
|
|
127
|
+
try {
|
|
128
|
+
const report = skillEffectiveness.getEffectivenessReport();
|
|
129
|
+
|
|
130
|
+
if (report.summary.totalApplications > 0) {
|
|
131
|
+
log(`[SessionEnd] Skill effectiveness:`);
|
|
132
|
+
log(` - Skills applied: ${report.summary.totalApplications}`);
|
|
133
|
+
log(` - Average effectiveness: ${Math.round(report.summary.averageEffectiveness * 100)}%`);
|
|
134
|
+
|
|
135
|
+
if (report.promotionCandidates.length > 0) {
|
|
136
|
+
log(
|
|
137
|
+
` - Promotion candidates: ${report.promotionCandidates.map((s) => s.name).join(', ')}`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (report.needsImprovement.length > 0) {
|
|
142
|
+
log(` - Needs improvement: ${report.needsImprovement.map((s) => s.name).join(', ')}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} catch (e) {
|
|
146
|
+
log(`[SessionEnd] Skill effectiveness error: ${e.message}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
process.exit(0);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
main().catch((err) => {
|
|
154
|
+
console.error('[SessionEnd] Error:', err.message);
|
|
155
|
+
process.exit(0);
|
|
156
|
+
});
|