@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,195 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* SessionStart Hook - Load previous context on new session
|
|
4
|
+
*
|
|
5
|
+
* Cross-platform (Windows, macOS, Linux)
|
|
6
|
+
*
|
|
7
|
+
* Runs when a new Claude session starts. Checks for recent session
|
|
8
|
+
* files and notifies Claude of available context to load.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const {
|
|
14
|
+
getSessionsDir,
|
|
15
|
+
getLearnedSkillsDir,
|
|
16
|
+
getClaudeDir,
|
|
17
|
+
findFiles,
|
|
18
|
+
ensureDir,
|
|
19
|
+
log,
|
|
20
|
+
} = require('../lib/utils');
|
|
21
|
+
const { getPackageManager, getSelectionPrompt } = require('../lib/package-manager');
|
|
22
|
+
|
|
23
|
+
// Try to load recommendation engine
|
|
24
|
+
let getSessionStartRecommendations = null;
|
|
25
|
+
try {
|
|
26
|
+
const recEngine = require('../lib/recommendation-engine');
|
|
27
|
+
getSessionStartRecommendations = recEngine.getSessionStartRecommendations;
|
|
28
|
+
} catch {
|
|
29
|
+
// Recommendation engine not available
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function main() {
|
|
33
|
+
const sessionsDir = getSessionsDir();
|
|
34
|
+
const learnedDir = getLearnedSkillsDir();
|
|
35
|
+
|
|
36
|
+
// Ensure directories exist
|
|
37
|
+
ensureDir(sessionsDir);
|
|
38
|
+
ensureDir(learnedDir);
|
|
39
|
+
|
|
40
|
+
// Check for recent session files (last 7 days)
|
|
41
|
+
const recentSessions = findFiles(sessionsDir, '*.tmp', { maxAge: 7 });
|
|
42
|
+
|
|
43
|
+
if (recentSessions.length > 0) {
|
|
44
|
+
const latest = recentSessions[0];
|
|
45
|
+
log(`[SessionStart] Found ${recentSessions.length} recent session(s)`);
|
|
46
|
+
log(`[SessionStart] Latest: ${latest.path}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check for learned skills
|
|
50
|
+
const learnedSkills = findFiles(learnedDir, '*.md');
|
|
51
|
+
|
|
52
|
+
if (learnedSkills.length > 0) {
|
|
53
|
+
log(`[SessionStart] ${learnedSkills.length} learned skill(s) available in ${learnedDir}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Detect and report package manager
|
|
57
|
+
const pm = getPackageManager();
|
|
58
|
+
log(`[SessionStart] Package manager: ${pm.name} (${pm.source})`);
|
|
59
|
+
|
|
60
|
+
// If package manager was detected via fallback, show selection prompt
|
|
61
|
+
if (pm.source === 'fallback' || pm.source === 'default') {
|
|
62
|
+
log('[SessionStart] No package manager preference found.');
|
|
63
|
+
log(getSelectionPrompt());
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Load client context if available
|
|
67
|
+
const clientId = process.env.CLOUDSTREAM_CLIENT_ID;
|
|
68
|
+
const complianceMode = process.env.CLOUDSTREAM_COMPLIANCE_MODE || 'standard';
|
|
69
|
+
|
|
70
|
+
if (clientId) {
|
|
71
|
+
log(`[SessionStart] Client: ${clientId} | Compliance: ${complianceMode}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check for pre-compact context restoration
|
|
75
|
+
const contextFile = path.join(sessionsDir, 'pre-compact-context.json');
|
|
76
|
+
if (fs.existsSync(contextFile)) {
|
|
77
|
+
try {
|
|
78
|
+
const savedContext = JSON.parse(fs.readFileSync(contextFile, 'utf8'));
|
|
79
|
+
log(
|
|
80
|
+
`[SessionStart] Restored context: Client=${savedContext.activeClient}, Compliance=${savedContext.complianceMode}`
|
|
81
|
+
);
|
|
82
|
+
} catch (e) {
|
|
83
|
+
// Ignore parse errors
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check if this is a first-time user (no sessions and no tutorial progress)
|
|
88
|
+
const milestonesFile = path.join(getClaudeDir(), 'onboarding', 'milestones.json');
|
|
89
|
+
const isFirstTime = recentSessions.length === 0 && !fs.existsSync(milestonesFile);
|
|
90
|
+
|
|
91
|
+
if (isFirstTime) {
|
|
92
|
+
log('');
|
|
93
|
+
log('Welcome to CloudStream Claude Code!');
|
|
94
|
+
log('');
|
|
95
|
+
log('Get started:');
|
|
96
|
+
log(' /onboard - Interactive setup wizard (recommended)');
|
|
97
|
+
log(' /health-check - Verify your environment is configured correctly');
|
|
98
|
+
log(' /tutorial - Interactive 15-lesson tutorial');
|
|
99
|
+
log(' /plan - Plan a feature before coding');
|
|
100
|
+
log('');
|
|
101
|
+
log('Need help? Run /diagnose for troubleshooting');
|
|
102
|
+
log('Documentation: README.md, GETTING-STARTED.md');
|
|
103
|
+
log('');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Check for tutorial progress
|
|
107
|
+
try {
|
|
108
|
+
const tutorialProgress = require('../lib/tutorial-progress');
|
|
109
|
+
if (tutorialProgress.hasProgress()) {
|
|
110
|
+
const progress = tutorialProgress.loadProgress();
|
|
111
|
+
if (!tutorialProgress.isComplete(progress)) {
|
|
112
|
+
const percent = tutorialProgress.getCompletionPercent(progress);
|
|
113
|
+
log(
|
|
114
|
+
`[SessionStart] Tutorial in progress: ${percent}% complete (${progress.completedLessons.length}/9 lessons)`
|
|
115
|
+
);
|
|
116
|
+
log(`[SessionStart] Resume with: /tutorial ${progress.currentLesson}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
// Tutorial module not available, skip
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Surface recommendations from cross-session analysis
|
|
124
|
+
await surfaceRecommendations();
|
|
125
|
+
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Load aggregation config
|
|
131
|
+
*/
|
|
132
|
+
function loadAggregationConfig() {
|
|
133
|
+
const configPath = path.join(__dirname, '..', '..', 'config', 'aggregation.json');
|
|
134
|
+
try {
|
|
135
|
+
if (fs.existsSync(configPath)) {
|
|
136
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
137
|
+
}
|
|
138
|
+
} catch {
|
|
139
|
+
// Config not available
|
|
140
|
+
}
|
|
141
|
+
return { recommendations: { enabled: false } };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Surface recommendations at session start
|
|
146
|
+
*/
|
|
147
|
+
async function surfaceRecommendations() {
|
|
148
|
+
const config = loadAggregationConfig();
|
|
149
|
+
|
|
150
|
+
// Check if recommendations are enabled
|
|
151
|
+
if (!config.recommendations?.enabled || !config.recommendations?.showAtSessionStart) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Check if recommendation engine is available
|
|
156
|
+
if (!getSessionStartRecommendations) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
const maxRecs = config.recommendations.maxAtSessionStart || 3;
|
|
162
|
+
const recommendations = getSessionStartRecommendations(maxRecs);
|
|
163
|
+
|
|
164
|
+
if (recommendations.length === 0) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
log('');
|
|
169
|
+
log('[SessionStart] Insights from your recent sessions:');
|
|
170
|
+
log('');
|
|
171
|
+
|
|
172
|
+
for (const rec of recommendations) {
|
|
173
|
+
const emoji = rec.priority === 'high' ? '[!]' : rec.priority === 'medium' ? '[*]' : '[-]';
|
|
174
|
+
|
|
175
|
+
log(` ${emoji} ${rec.title}`);
|
|
176
|
+
log(` ${rec.message}`);
|
|
177
|
+
|
|
178
|
+
if (rec.action) {
|
|
179
|
+
log(` Action: ${rec.action}`);
|
|
180
|
+
}
|
|
181
|
+
log('');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
log(' Run /recommendations for full list');
|
|
185
|
+
log('');
|
|
186
|
+
} catch (err) {
|
|
187
|
+
// Don't block session start on recommendation errors
|
|
188
|
+
log(`[SessionStart] Could not load recommendations: ${err.message}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
main().catch((err) => {
|
|
193
|
+
console.error('[SessionStart] Error:', err.message);
|
|
194
|
+
process.exit(0); // Don't block on errors
|
|
195
|
+
});
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Skill Injector Hook - Auto-Apply Relevant Skills
|
|
5
|
+
*
|
|
6
|
+
* This hook runs on PreToolUse (Edit, Write, Read) to detect relevant
|
|
7
|
+
* skills based on file context and inject them as guidance.
|
|
8
|
+
*
|
|
9
|
+
* Performance: Lightweight matching, only reads skill content for high-confidence matches.
|
|
10
|
+
*
|
|
11
|
+
* Hook Type: PreToolUse
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const { readStdinJson, log, output, readFile, getClaudeDir } = require('../lib/utils');
|
|
17
|
+
const {
|
|
18
|
+
buildContext,
|
|
19
|
+
matchSkills,
|
|
20
|
+
formatMatchedSkills,
|
|
21
|
+
getSkillContent,
|
|
22
|
+
loadLearnedSkills,
|
|
23
|
+
} = require('../lib/skill-matcher');
|
|
24
|
+
const { loadSessionMemory, updateContext } = require('../lib/session-memory');
|
|
25
|
+
|
|
26
|
+
// Cache to avoid re-matching for same file in same session
|
|
27
|
+
const matchCache = new Map();
|
|
28
|
+
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get cached match or compute new one
|
|
32
|
+
*/
|
|
33
|
+
function getCachedOrMatch(filePath, content) {
|
|
34
|
+
const cacheKey = `${filePath}:${content?.length || 0}`;
|
|
35
|
+
|
|
36
|
+
const cached = matchCache.get(cacheKey);
|
|
37
|
+
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
|
38
|
+
return cached.matches;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Build context and match
|
|
42
|
+
const sessionMemory = loadSessionMemory();
|
|
43
|
+
const context = buildContext(filePath, content, {
|
|
44
|
+
complianceMode: sessionMemory.context?.complianceMode || null,
|
|
45
|
+
technologies: sessionMemory.context?.technologies || [],
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const matches = matchSkills(context);
|
|
49
|
+
|
|
50
|
+
// Cache result
|
|
51
|
+
matchCache.set(cacheKey, {
|
|
52
|
+
matches,
|
|
53
|
+
timestamp: Date.now(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Update session context with detected technologies
|
|
57
|
+
if (context.technologies.size > 0) {
|
|
58
|
+
updateContext({
|
|
59
|
+
files: [filePath],
|
|
60
|
+
technologies: Array.from(context.technologies),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return matches;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get the most important skill guidance to show
|
|
69
|
+
*/
|
|
70
|
+
function getKeyGuidance(match) {
|
|
71
|
+
const content = getSkillContent(match);
|
|
72
|
+
if (!content) return null;
|
|
73
|
+
|
|
74
|
+
// Extract key sections based on skill type
|
|
75
|
+
const lines = content.split('\n');
|
|
76
|
+
const keyLines = [];
|
|
77
|
+
|
|
78
|
+
let inKeySection = false;
|
|
79
|
+
const keySectionHeaders = [
|
|
80
|
+
/^#+\s*(critical|important|must|always|never|constraints?|limits?|warnings?)/i,
|
|
81
|
+
/^#+\s*(quick reference|key points|summary)/i,
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
for (let i = 0; i < lines.length && keyLines.length < 10; i++) {
|
|
85
|
+
const line = lines[i];
|
|
86
|
+
|
|
87
|
+
// Check if entering a key section
|
|
88
|
+
if (keySectionHeaders.some((pattern) => pattern.test(line))) {
|
|
89
|
+
inKeySection = true;
|
|
90
|
+
keyLines.push(line);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check if leaving section (next header)
|
|
95
|
+
if (inKeySection && /^#+\s/.test(line) && !keySectionHeaders.some((p) => p.test(line))) {
|
|
96
|
+
inKeySection = false;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Collect content from key sections
|
|
101
|
+
if (inKeySection && line.trim()) {
|
|
102
|
+
keyLines.push(line);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Also collect bullet points that look important
|
|
106
|
+
if (/^[-*]\s*(CRITICAL|IMPORTANT|MUST|ALWAYS|NEVER|WARNING|CAUTION):/i.test(line)) {
|
|
107
|
+
keyLines.push(line);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (keyLines.length === 0) {
|
|
112
|
+
// Fallback: first 5 non-empty lines after first header
|
|
113
|
+
let foundHeader = false;
|
|
114
|
+
for (const line of lines) {
|
|
115
|
+
if (/^#/.test(line)) {
|
|
116
|
+
foundHeader = true;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (foundHeader && line.trim() && keyLines.length < 5) {
|
|
120
|
+
keyLines.push(line);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return keyLines.join('\n');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Format deprecation warning for a match
|
|
130
|
+
*/
|
|
131
|
+
function formatDeprecationWarning(match) {
|
|
132
|
+
if (!match.deprecation) return null;
|
|
133
|
+
|
|
134
|
+
let warning = ` [DEPRECATED] This skill is deprecated`;
|
|
135
|
+
|
|
136
|
+
if (match.deprecation.supersededBy) {
|
|
137
|
+
warning += ` - use "${match.deprecation.supersededBy}" instead`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (match.deprecation.reason) {
|
|
141
|
+
warning += `\n Reason: ${match.deprecation.reason}`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (match.deprecation.migrationGuide) {
|
|
145
|
+
warning += `\n Migration guide: ${match.deprecation.migrationGuide}`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (match.deprecation.removalTarget) {
|
|
149
|
+
warning += `\n Removal target: ${match.deprecation.removalTarget}`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return warning + '\n';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Format skill guidance for stderr output
|
|
157
|
+
*/
|
|
158
|
+
function formatSkillGuidance(matches) {
|
|
159
|
+
if (matches.length === 0) return null;
|
|
160
|
+
|
|
161
|
+
let output = '';
|
|
162
|
+
|
|
163
|
+
// Show matched skills summary
|
|
164
|
+
output += '[Skill] Relevant patterns detected:\n';
|
|
165
|
+
|
|
166
|
+
for (const match of matches) {
|
|
167
|
+
const confidence = Math.round(match.score * 100);
|
|
168
|
+
const typeLabel = match.type === 'learned' ? '(learned)' : '';
|
|
169
|
+
const versionLabel = match.version ? ` v${match.version}` : '';
|
|
170
|
+
|
|
171
|
+
output += `\n[Skill] ${match.skill}${versionLabel} ${typeLabel} - ${confidence}% match\n`;
|
|
172
|
+
|
|
173
|
+
// Show deprecation warning if deprecated
|
|
174
|
+
if (match.deprecation) {
|
|
175
|
+
const deprecationWarning = formatDeprecationWarning(match);
|
|
176
|
+
if (deprecationWarning) {
|
|
177
|
+
output += deprecationWarning;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Get key guidance for high-confidence matches
|
|
182
|
+
if (match.score >= 0.6) {
|
|
183
|
+
const guidance = getKeyGuidance(match);
|
|
184
|
+
if (guidance) {
|
|
185
|
+
// Indent guidance
|
|
186
|
+
const indentedGuidance = guidance
|
|
187
|
+
.split('\n')
|
|
188
|
+
.map((line) => ` ${line}`)
|
|
189
|
+
.join('\n');
|
|
190
|
+
output += indentedGuidance + '\n';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return output;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Check for anti-patterns from session memory
|
|
200
|
+
*/
|
|
201
|
+
function checkAntiPatterns(content) {
|
|
202
|
+
const sessionMemory = loadSessionMemory();
|
|
203
|
+
const warnings = [];
|
|
204
|
+
|
|
205
|
+
// Check against session anti-patterns
|
|
206
|
+
if (sessionMemory.antiPatterns) {
|
|
207
|
+
for (const antiPattern of sessionMemory.antiPatterns) {
|
|
208
|
+
if (antiPattern.name && content.includes(antiPattern.name)) {
|
|
209
|
+
warnings.push({
|
|
210
|
+
type: 'anti-pattern',
|
|
211
|
+
name: antiPattern.name,
|
|
212
|
+
avoidance: antiPattern.avoidance,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Check against corrections (things we've been told not to do)
|
|
219
|
+
if (sessionMemory.corrections) {
|
|
220
|
+
for (const correction of sessionMemory.corrections) {
|
|
221
|
+
if (correction.original && correction.count >= 2) {
|
|
222
|
+
// Only warn for repeated corrections
|
|
223
|
+
if (content.toLowerCase().includes(correction.original.toLowerCase())) {
|
|
224
|
+
warnings.push({
|
|
225
|
+
type: 'previous-correction',
|
|
226
|
+
original: correction.original,
|
|
227
|
+
corrected: correction.corrected,
|
|
228
|
+
count: correction.count,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return warnings;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Format anti-pattern warnings
|
|
240
|
+
*/
|
|
241
|
+
function formatAntiPatternWarnings(warnings) {
|
|
242
|
+
if (warnings.length === 0) return null;
|
|
243
|
+
|
|
244
|
+
let output = '\n[Learning] Potential issues detected based on session history:\n';
|
|
245
|
+
|
|
246
|
+
for (const warning of warnings) {
|
|
247
|
+
if (warning.type === 'anti-pattern') {
|
|
248
|
+
output += ` - Anti-pattern: "${warning.name}"\n`;
|
|
249
|
+
if (warning.avoidance) {
|
|
250
|
+
output += ` Instead: ${warning.avoidance}\n`;
|
|
251
|
+
}
|
|
252
|
+
} else if (warning.type === 'previous-correction') {
|
|
253
|
+
output += ` - Previously corrected (${warning.count}x): "${warning.original}"\n`;
|
|
254
|
+
if (warning.corrected) {
|
|
255
|
+
output += ` Preferred: ${warning.corrected}\n`;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return output;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Main hook execution
|
|
265
|
+
*/
|
|
266
|
+
async function main() {
|
|
267
|
+
try {
|
|
268
|
+
const input = await readStdinJson();
|
|
269
|
+
const tool = input.tool;
|
|
270
|
+
const toolInput = input.tool_input || {};
|
|
271
|
+
|
|
272
|
+
// Get file path based on tool
|
|
273
|
+
let filePath = null;
|
|
274
|
+
let content = null;
|
|
275
|
+
|
|
276
|
+
if (tool === 'Edit') {
|
|
277
|
+
filePath = toolInput.file_path;
|
|
278
|
+
content = toolInput.new_string || '';
|
|
279
|
+
} else if (tool === 'Write') {
|
|
280
|
+
filePath = toolInput.file_path;
|
|
281
|
+
content = toolInput.content || '';
|
|
282
|
+
} else if (tool === 'Read') {
|
|
283
|
+
filePath = toolInput.file_path;
|
|
284
|
+
// For Read, we don't have content yet, but can still match on file path
|
|
285
|
+
content = '';
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (!filePath) {
|
|
289
|
+
output(JSON.stringify(input));
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Skip for non-code files
|
|
294
|
+
const codeExtensions = ['.ts', '.tsx', '.js', '.jsx', '.ds', '.sql', '.py', '.md'];
|
|
295
|
+
const ext = path.extname(filePath);
|
|
296
|
+
if (!codeExtensions.includes(ext)) {
|
|
297
|
+
output(JSON.stringify(input));
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Get matched skills
|
|
302
|
+
const matches = getCachedOrMatch(filePath, content);
|
|
303
|
+
|
|
304
|
+
// Format and output skill guidance
|
|
305
|
+
if (matches.length > 0) {
|
|
306
|
+
const guidance = formatSkillGuidance(matches);
|
|
307
|
+
if (guidance) {
|
|
308
|
+
log(guidance);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Check for anti-patterns in content being written
|
|
313
|
+
if (content && (tool === 'Edit' || tool === 'Write')) {
|
|
314
|
+
const warnings = checkAntiPatterns(content);
|
|
315
|
+
if (warnings.length > 0) {
|
|
316
|
+
const warningOutput = formatAntiPatternWarnings(warnings);
|
|
317
|
+
if (warningOutput) {
|
|
318
|
+
log(warningOutput);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Pass through input unchanged
|
|
324
|
+
output(JSON.stringify(input));
|
|
325
|
+
} catch (err) {
|
|
326
|
+
// On error, log but don't block
|
|
327
|
+
log(`[SkillInjector] Error: ${err.message}`);
|
|
328
|
+
output('{}');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Run
|
|
333
|
+
main();
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Strategic Compact Suggester
|
|
4
|
+
*
|
|
5
|
+
* Cross-platform (Windows, macOS, Linux)
|
|
6
|
+
*
|
|
7
|
+
* Runs on PreToolUse or periodically to suggest manual compaction at logical intervals
|
|
8
|
+
*
|
|
9
|
+
* Why manual over auto-compact:
|
|
10
|
+
* - Auto-compact happens at arbitrary points, often mid-task
|
|
11
|
+
* - Strategic compacting preserves context through logical phases
|
|
12
|
+
* - Compact after exploration, before execution
|
|
13
|
+
* - Compact after completing a milestone, before starting next
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const { getTempDir, readFile, writeFile, log } = require('../lib/utils');
|
|
18
|
+
|
|
19
|
+
async function main() {
|
|
20
|
+
// Track tool call count (increment in a temp file)
|
|
21
|
+
// Use a session-specific counter file based on PID from parent process
|
|
22
|
+
// or session ID from environment
|
|
23
|
+
const sessionId = process.env.CLAUDE_SESSION_ID || process.ppid || 'default';
|
|
24
|
+
const counterFile = path.join(getTempDir(), `claude-tool-count-${sessionId}`);
|
|
25
|
+
const threshold = parseInt(process.env.COMPACT_THRESHOLD || '50', 10);
|
|
26
|
+
|
|
27
|
+
let count = 1;
|
|
28
|
+
|
|
29
|
+
// Read existing count or start at 1
|
|
30
|
+
const existing = readFile(counterFile);
|
|
31
|
+
if (existing) {
|
|
32
|
+
count = parseInt(existing.trim(), 10) + 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Save updated count
|
|
36
|
+
writeFile(counterFile, String(count));
|
|
37
|
+
|
|
38
|
+
// Suggest compact after threshold tool calls
|
|
39
|
+
if (count === threshold) {
|
|
40
|
+
log(
|
|
41
|
+
`[StrategicCompact] ${threshold} tool calls reached - consider /compact if transitioning phases`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Suggest at regular intervals after threshold
|
|
46
|
+
if (count > threshold && count % 25 === 0) {
|
|
47
|
+
log(
|
|
48
|
+
`[StrategicCompact] ${count} tool calls - good checkpoint for /compact if context is stale`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
main().catch((err) => {
|
|
56
|
+
console.error('[StrategicCompact] Error:', err.message);
|
|
57
|
+
process.exit(0);
|
|
58
|
+
});
|