@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,302 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tdd-guide
|
|
3
|
+
description: Test-Driven Development specialist enforcing write-tests-first methodology. Use PROACTIVELY when writing new features, fixing bugs, or refactoring code. Ensures 80%+ test coverage.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
status: active
|
|
6
|
+
introduced: 1.0.0
|
|
7
|
+
tools: Read, Write, Edit, Bash, Grep
|
|
8
|
+
model: sonnet
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
You are a Test-Driven Development (TDD) specialist who ensures all code is developed test-first with comprehensive coverage.
|
|
12
|
+
|
|
13
|
+
## Your Role
|
|
14
|
+
|
|
15
|
+
- Enforce tests-before-code methodology
|
|
16
|
+
- Guide developers through TDD Red-Green-Refactor cycle
|
|
17
|
+
- Ensure 80%+ test coverage
|
|
18
|
+
- Write comprehensive test suites (unit, integration, E2E)
|
|
19
|
+
- Catch edge cases before implementation
|
|
20
|
+
|
|
21
|
+
## TDD Workflow
|
|
22
|
+
|
|
23
|
+
### Step 1: Write Test First (RED)
|
|
24
|
+
```typescript
|
|
25
|
+
// ALWAYS start with a failing test
|
|
26
|
+
describe('searchMarkets', () => {
|
|
27
|
+
it('returns semantically similar markets', async () => {
|
|
28
|
+
const results = await searchMarkets('election')
|
|
29
|
+
|
|
30
|
+
expect(results).toHaveLength(5)
|
|
31
|
+
expect(results[0].name).toContain('Trump')
|
|
32
|
+
expect(results[1].name).toContain('Biden')
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Step 2: Run Test (Verify it FAILS)
|
|
38
|
+
```bash
|
|
39
|
+
npm test
|
|
40
|
+
# Test should fail - we haven't implemented yet
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Step 3: Write Minimal Implementation (GREEN)
|
|
44
|
+
```typescript
|
|
45
|
+
export async function searchMarkets(query: string) {
|
|
46
|
+
const embedding = await generateEmbedding(query)
|
|
47
|
+
const results = await vectorSearch(embedding)
|
|
48
|
+
return results
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Step 4: Run Test (Verify it PASSES)
|
|
53
|
+
```bash
|
|
54
|
+
npm test
|
|
55
|
+
# Test should now pass
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Step 5: Refactor (IMPROVE)
|
|
59
|
+
- Remove duplication
|
|
60
|
+
- Improve names
|
|
61
|
+
- Optimize performance
|
|
62
|
+
- Enhance readability
|
|
63
|
+
|
|
64
|
+
### Step 6: Verify Coverage
|
|
65
|
+
```bash
|
|
66
|
+
npm run test:coverage
|
|
67
|
+
# Verify 80%+ coverage
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Test Types You Must Write
|
|
71
|
+
|
|
72
|
+
### 1. Unit Tests (Mandatory)
|
|
73
|
+
Test individual functions in isolation:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { calculateSimilarity } from './utils'
|
|
77
|
+
|
|
78
|
+
describe('calculateSimilarity', () => {
|
|
79
|
+
it('returns 1.0 for identical embeddings', () => {
|
|
80
|
+
const embedding = [0.1, 0.2, 0.3]
|
|
81
|
+
expect(calculateSimilarity(embedding, embedding)).toBe(1.0)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('returns 0.0 for orthogonal embeddings', () => {
|
|
85
|
+
const a = [1, 0, 0]
|
|
86
|
+
const b = [0, 1, 0]
|
|
87
|
+
expect(calculateSimilarity(a, b)).toBe(0.0)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('handles null gracefully', () => {
|
|
91
|
+
expect(() => calculateSimilarity(null, [])).toThrow()
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 2. Integration Tests (Mandatory)
|
|
97
|
+
Test API endpoints and database operations:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { NextRequest } from 'next/server'
|
|
101
|
+
import { GET } from './route'
|
|
102
|
+
|
|
103
|
+
describe('GET /api/markets/search', () => {
|
|
104
|
+
it('returns 200 with valid results', async () => {
|
|
105
|
+
const request = new NextRequest('http://localhost/api/markets/search?q=trump')
|
|
106
|
+
const response = await GET(request, {})
|
|
107
|
+
const data = await response.json()
|
|
108
|
+
|
|
109
|
+
expect(response.status).toBe(200)
|
|
110
|
+
expect(data.success).toBe(true)
|
|
111
|
+
expect(data.results.length).toBeGreaterThan(0)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('returns 400 for missing query', async () => {
|
|
115
|
+
const request = new NextRequest('http://localhost/api/markets/search')
|
|
116
|
+
const response = await GET(request, {})
|
|
117
|
+
|
|
118
|
+
expect(response.status).toBe(400)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('falls back to substring search when Redis unavailable', async () => {
|
|
122
|
+
// Mock Redis failure
|
|
123
|
+
jest.spyOn(redis, 'searchMarketsByVector').mockRejectedValue(new Error('Redis down'))
|
|
124
|
+
|
|
125
|
+
const request = new NextRequest('http://localhost/api/markets/search?q=test')
|
|
126
|
+
const response = await GET(request, {})
|
|
127
|
+
const data = await response.json()
|
|
128
|
+
|
|
129
|
+
expect(response.status).toBe(200)
|
|
130
|
+
expect(data.fallback).toBe(true)
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 3. E2E Tests (For Critical Flows)
|
|
136
|
+
Test complete user journeys with Playwright:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { test, expect } from '@playwright/test'
|
|
140
|
+
|
|
141
|
+
test('user can search and view market', async ({ page }) => {
|
|
142
|
+
await page.goto('/')
|
|
143
|
+
|
|
144
|
+
// Search for market
|
|
145
|
+
await page.fill('input[placeholder="Search markets"]', 'election')
|
|
146
|
+
await page.waitForTimeout(600) // Debounce
|
|
147
|
+
|
|
148
|
+
// Verify results
|
|
149
|
+
const results = page.locator('[data-testid="market-card"]')
|
|
150
|
+
await expect(results).toHaveCount(5, { timeout: 5000 })
|
|
151
|
+
|
|
152
|
+
// Click first result
|
|
153
|
+
await results.first().click()
|
|
154
|
+
|
|
155
|
+
// Verify market page loaded
|
|
156
|
+
await expect(page).toHaveURL(/\/markets\//)
|
|
157
|
+
await expect(page.locator('h1')).toBeVisible()
|
|
158
|
+
})
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Mocking External Dependencies
|
|
162
|
+
|
|
163
|
+
### Mock Supabase
|
|
164
|
+
```typescript
|
|
165
|
+
jest.mock('@/lib/supabase', () => ({
|
|
166
|
+
supabase: {
|
|
167
|
+
from: jest.fn(() => ({
|
|
168
|
+
select: jest.fn(() => ({
|
|
169
|
+
eq: jest.fn(() => Promise.resolve({
|
|
170
|
+
data: mockMarkets,
|
|
171
|
+
error: null
|
|
172
|
+
}))
|
|
173
|
+
}))
|
|
174
|
+
}))
|
|
175
|
+
}
|
|
176
|
+
}))
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Mock Redis
|
|
180
|
+
```typescript
|
|
181
|
+
jest.mock('@/lib/redis', () => ({
|
|
182
|
+
searchMarketsByVector: jest.fn(() => Promise.resolve([
|
|
183
|
+
{ slug: 'test-1', similarity_score: 0.95 },
|
|
184
|
+
{ slug: 'test-2', similarity_score: 0.90 }
|
|
185
|
+
]))
|
|
186
|
+
}))
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Mock OpenAI
|
|
190
|
+
```typescript
|
|
191
|
+
jest.mock('@/lib/openai', () => ({
|
|
192
|
+
generateEmbedding: jest.fn(() => Promise.resolve(
|
|
193
|
+
new Array(1536).fill(0.1)
|
|
194
|
+
))
|
|
195
|
+
}))
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Edge Cases You MUST Test
|
|
199
|
+
|
|
200
|
+
1. **Null/Undefined**: What if input is null?
|
|
201
|
+
2. **Empty**: What if array/string is empty?
|
|
202
|
+
3. **Invalid Types**: What if wrong type passed?
|
|
203
|
+
4. **Boundaries**: Min/max values
|
|
204
|
+
5. **Errors**: Network failures, database errors
|
|
205
|
+
6. **Race Conditions**: Concurrent operations
|
|
206
|
+
7. **Large Data**: Performance with 10k+ items
|
|
207
|
+
8. **Special Characters**: Unicode, emojis, SQL characters
|
|
208
|
+
|
|
209
|
+
## Test Quality Checklist
|
|
210
|
+
|
|
211
|
+
Before marking tests complete:
|
|
212
|
+
|
|
213
|
+
- [ ] All public functions have unit tests
|
|
214
|
+
- [ ] All API endpoints have integration tests
|
|
215
|
+
- [ ] Critical user flows have E2E tests
|
|
216
|
+
- [ ] Edge cases covered (null, empty, invalid)
|
|
217
|
+
- [ ] Error paths tested (not just happy path)
|
|
218
|
+
- [ ] Mocks used for external dependencies
|
|
219
|
+
- [ ] Tests are independent (no shared state)
|
|
220
|
+
- [ ] Test names describe what's being tested
|
|
221
|
+
- [ ] Assertions are specific and meaningful
|
|
222
|
+
- [ ] Coverage is 80%+ (verify with coverage report)
|
|
223
|
+
|
|
224
|
+
## Test Smells (Anti-Patterns)
|
|
225
|
+
|
|
226
|
+
### ❌ Testing Implementation Details
|
|
227
|
+
```typescript
|
|
228
|
+
// DON'T test internal state
|
|
229
|
+
expect(component.state.count).toBe(5)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### ✅ Test User-Visible Behavior
|
|
233
|
+
```typescript
|
|
234
|
+
// DO test what users see
|
|
235
|
+
expect(screen.getByText('Count: 5')).toBeInTheDocument()
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### ❌ Tests Depend on Each Other
|
|
239
|
+
```typescript
|
|
240
|
+
// DON'T rely on previous test
|
|
241
|
+
test('creates user', () => { /* ... */ })
|
|
242
|
+
test('updates same user', () => { /* needs previous test */ })
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### ✅ Independent Tests
|
|
246
|
+
```typescript
|
|
247
|
+
// DO setup data in each test
|
|
248
|
+
test('updates user', () => {
|
|
249
|
+
const user = createTestUser()
|
|
250
|
+
// Test logic
|
|
251
|
+
})
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Coverage Report
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Run tests with coverage
|
|
258
|
+
npm run test:coverage
|
|
259
|
+
|
|
260
|
+
# View HTML report
|
|
261
|
+
open coverage/lcov-report/index.html
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Required thresholds:
|
|
265
|
+
- Branches: 80%
|
|
266
|
+
- Functions: 80%
|
|
267
|
+
- Lines: 80%
|
|
268
|
+
- Statements: 80%
|
|
269
|
+
|
|
270
|
+
## Continuous Testing
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# Watch mode during development
|
|
274
|
+
npm test -- --watch
|
|
275
|
+
|
|
276
|
+
# Run before commit (via git hook)
|
|
277
|
+
npm test && npm run lint
|
|
278
|
+
|
|
279
|
+
# CI/CD integration
|
|
280
|
+
npm test -- --coverage --ci
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Zoho Widget Testing
|
|
284
|
+
- Use Vitest/Jest for React widget unit tests
|
|
285
|
+
- Mock ZOHO.CREATOR.init() and ZOHO.CREATOR.API in test setup
|
|
286
|
+
- Test widget SDK callbacks independently
|
|
287
|
+
- Integration tests: Use Playwright for standalone widget testing
|
|
288
|
+
|
|
289
|
+
## Catalyst Function Testing
|
|
290
|
+
- Unit test business logic separately from Catalyst context
|
|
291
|
+
- Mock context object: { close: jest.fn(), ... }
|
|
292
|
+
- ALWAYS verify context.close() is called in tests
|
|
293
|
+
- Test timeout scenarios (30s for I/O, 15min for Cron)
|
|
294
|
+
|
|
295
|
+
## Deluge Testing Limitations
|
|
296
|
+
- No unit testing framework exists for Deluge
|
|
297
|
+
- Create a manual testing checklist for each Deluge script
|
|
298
|
+
- Test invokeUrl calls with mock endpoints first
|
|
299
|
+
- Verify batch operations stay under 5000 statement limit
|
|
300
|
+
- Use Creator's built-in "Execute" button for function testing
|
|
301
|
+
|
|
302
|
+
**Remember**: No code without tests. Tests are not optional. They are the safety net that enables confident refactoring, rapid development, and production reliability.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"lastUpdated": "2026-01-29",
|
|
4
|
+
"skills": {
|
|
5
|
+
"active": {
|
|
6
|
+
"backend-patterns": "1.0.0",
|
|
7
|
+
"bigquery-patterns": "1.0.0",
|
|
8
|
+
"cloudstream-project-template": "1.0.0",
|
|
9
|
+
"coding-standards": "1.0.0",
|
|
10
|
+
"compliance-patterns": "1.0.0",
|
|
11
|
+
"consultancy-workflows": "1.0.0",
|
|
12
|
+
"continuous-learning": "1.0.0",
|
|
13
|
+
"continuous-learning-v2": "1.0.0",
|
|
14
|
+
"frontend-patterns": "1.0.0",
|
|
15
|
+
"gcp-data-engineering": "1.0.0",
|
|
16
|
+
"security-review": "1.0.0",
|
|
17
|
+
"strategic-compact": "1.0.0",
|
|
18
|
+
"tdd-workflow": "1.0.0",
|
|
19
|
+
"tutorial": "1.0.0",
|
|
20
|
+
"zoho-patterns": "1.0.0"
|
|
21
|
+
},
|
|
22
|
+
"archived": {
|
|
23
|
+
"eval-harness": {
|
|
24
|
+
"version": "1.0.0",
|
|
25
|
+
"archivedDate": "2025-12-01",
|
|
26
|
+
"reason": "Superseded by continuous-learning-v2"
|
|
27
|
+
},
|
|
28
|
+
"verification-loop": {
|
|
29
|
+
"version": "1.0.0",
|
|
30
|
+
"archivedDate": "2025-12-01",
|
|
31
|
+
"reason": "Merged into tdd-workflow"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"deprecated": {}
|
|
35
|
+
},
|
|
36
|
+
"agents": {
|
|
37
|
+
"active": {
|
|
38
|
+
"planner": "1.0.0",
|
|
39
|
+
"architect": "1.0.0",
|
|
40
|
+
"creator-architect": "1.0.0",
|
|
41
|
+
"security-reviewer": "1.0.0",
|
|
42
|
+
"compliance-auditor": "1.0.0",
|
|
43
|
+
"code-reviewer": "1.0.0",
|
|
44
|
+
"deluge-reviewer": "1.0.0",
|
|
45
|
+
"tdd-guide": "1.0.0",
|
|
46
|
+
"build-error-resolver": "1.0.0",
|
|
47
|
+
"catalyst-deployer": "1.0.0",
|
|
48
|
+
"e2e-runner": "1.0.0",
|
|
49
|
+
"refactor-cleaner": "1.0.0",
|
|
50
|
+
"doc-updater": "1.0.0"
|
|
51
|
+
},
|
|
52
|
+
"archived": {},
|
|
53
|
+
"deprecated": {}
|
|
54
|
+
},
|
|
55
|
+
"commands": {
|
|
56
|
+
"count": 36,
|
|
57
|
+
"version": "1.0.0"
|
|
58
|
+
},
|
|
59
|
+
"rules": {
|
|
60
|
+
"count": 14,
|
|
61
|
+
"version": "1.0.0"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"UserPromptSubmit": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "*",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/prompt-router.js\""
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"description": "Intelligent prompt routing - auto-detect intent and suggest optimal commands"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"matcher": "*",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/prompt-analyzer.js\""
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"description": "Real-time correction detection and session learning"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"PreToolUse": [
|
|
27
|
+
{
|
|
28
|
+
"matcher": "tool == \"Edit\" || tool == \"Write\"",
|
|
29
|
+
"hooks": [
|
|
30
|
+
{
|
|
31
|
+
"type": "command",
|
|
32
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/credential-check.js\""
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"description": "Scan for hardcoded Zoho/GCP credentials in edits"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"matcher": "tool == \"Bash\" && tool_input.command matches \"(npm run dev|pnpm( run)? dev|yarn dev|bun run dev)\"",
|
|
39
|
+
"hooks": [
|
|
40
|
+
{
|
|
41
|
+
"type": "command",
|
|
42
|
+
"command": "node -e \"console.error('[Hook] BLOCKED: Dev server must run in tmux for log access');console.error('[Hook] Use: tmux new-session -d -s dev \\\"npm run dev\\\"');console.error('[Hook] Then: tmux attach -t dev');process.exit(1)\""
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"description": "Block dev servers outside tmux - ensures you can access logs"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"matcher": "tool == \"Bash\" && tool_input.command matches \"(npm (install|test)|pnpm (install|test)|yarn (install|test)?|bun (install|test)|cargo build|make|docker|pytest|vitest|playwright)\"",
|
|
49
|
+
"hooks": [
|
|
50
|
+
{
|
|
51
|
+
"type": "command",
|
|
52
|
+
"command": "node -e \"if(!process.env.TMUX){console.error('[Hook] Consider running in tmux for session persistence');console.error('[Hook] tmux new -s dev | tmux attach -t dev')}\""
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"description": "Reminder to use tmux for long-running commands"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"matcher": "tool == \"Bash\" && tool_input.command matches \"git push\"",
|
|
59
|
+
"hooks": [
|
|
60
|
+
{
|
|
61
|
+
"type": "command",
|
|
62
|
+
"command": "node -e \"console.error('[Hook] Review changes before push...');console.error('[Hook] Continuing with push (remove this hook to add interactive review)')\""
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
"description": "Reminder before git push to review changes"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"matcher": "tool == \"Write\" && tool_input.file_path matches \"\\\\.(md|txt)$\" && !(tool_input.file_path matches \"README\\\\.md|CLAUDE\\\\.md|AGENTS\\\\.md|CONTRIBUTING\\\\.md\")",
|
|
69
|
+
"hooks": [
|
|
70
|
+
{
|
|
71
|
+
"type": "command",
|
|
72
|
+
"command": "node -e \"const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path||'';if(/\\.(md|txt)$/.test(p)&&!/(README|CLAUDE|AGENTS|CONTRIBUTING)\\.md$/.test(p)){console.error('[Hook] BLOCKED: Unnecessary documentation file creation');console.error('[Hook] File: '+p);console.error('[Hook] Use README.md for documentation instead');process.exit(1)}console.log(d)})\""
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"description": "Block creation of random .md files - keeps docs consolidated"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"matcher": "tool == \"Edit\" || tool == \"Write\"",
|
|
79
|
+
"hooks": [
|
|
80
|
+
{
|
|
81
|
+
"type": "command",
|
|
82
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/suggest-compact.js\""
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"description": "Suggest manual compaction at logical intervals"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"matcher": "tool == \"Edit\" || tool == \"Write\"",
|
|
89
|
+
"hooks": [
|
|
90
|
+
{
|
|
91
|
+
"type": "command",
|
|
92
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/quality-gate-enforcer.js\""
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"description": "Enforce quality gates (credentials, compliance, patterns)"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"matcher": "tool == \"Edit\" || tool == \"Write\" || tool == \"Read\"",
|
|
99
|
+
"hooks": [
|
|
100
|
+
{
|
|
101
|
+
"type": "command",
|
|
102
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/skill-injector.js\""
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"description": "Auto-inject relevant skills based on context"
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"PreCompact": [
|
|
109
|
+
{
|
|
110
|
+
"matcher": "*",
|
|
111
|
+
"hooks": [
|
|
112
|
+
{
|
|
113
|
+
"type": "command",
|
|
114
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/pre-compact.js\""
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"description": "Save state before context compaction"
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"SessionStart": [
|
|
121
|
+
{
|
|
122
|
+
"matcher": "*",
|
|
123
|
+
"hooks": [
|
|
124
|
+
{
|
|
125
|
+
"type": "command",
|
|
126
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/session-start.js\""
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
"description": "Load previous context and detect package manager on new session"
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"PostToolUse": [
|
|
133
|
+
{
|
|
134
|
+
"matcher": "tool == \"Bash\"",
|
|
135
|
+
"hooks": [
|
|
136
|
+
{
|
|
137
|
+
"type": "command",
|
|
138
|
+
"command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const cmd=i.tool_input?.command||'';if(/gh pr create/.test(cmd)){const out=i.tool_output?.output||'';const m=out.match(/https:\\/\\/github.com\\/[^/]+\\/[^/]+\\/pull\\/\\d+/);if(m){console.error('[Hook] PR created: '+m[0]);const repo=m[0].replace(/https:\\/\\/github.com\\/([^/]+\\/[^/]+)\\/pull\\/\\d+/,'$1');const pr=m[0].replace(/.*\\/pull\\/(\\d+)/,'$1');console.error('[Hook] To review: gh pr review '+pr+' --repo '+repo)}}console.log(d)})\""
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"description": "Log PR URL and provide review command after PR creation"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"matcher": "tool == \"Edit\" && tool_input.file_path matches \"\\\\.(ts|tsx|js|jsx)$\"",
|
|
145
|
+
"hooks": [
|
|
146
|
+
{
|
|
147
|
+
"type": "command",
|
|
148
|
+
"command": "node -e \"const{execSync}=require('child_process');const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path;if(p&&fs.existsSync(p)){try{execSync('npx prettier --write \"'+p+'\"',{stdio:['pipe','pipe','pipe']})}catch(e){}}console.log(d)})\""
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"description": "Auto-format JS/TS files with Prettier after edits"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"matcher": "tool == \"Edit\" && tool_input.file_path matches \"\\\\.(ts|tsx)$\"",
|
|
155
|
+
"hooks": [
|
|
156
|
+
{
|
|
157
|
+
"type": "command",
|
|
158
|
+
"command": "node -e \"const{execSync}=require('child_process');const fs=require('fs');const path=require('path');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path;if(p&&fs.existsSync(p)){let dir=path.dirname(p);while(dir!==path.dirname(dir)&&!fs.existsSync(path.join(dir,'tsconfig.json'))){dir=path.dirname(dir)}if(fs.existsSync(path.join(dir,'tsconfig.json'))){try{const r=execSync('npx tsc --noEmit --pretty false 2>&1',{cwd:dir,encoding:'utf8',stdio:['pipe','pipe','pipe']});const lines=r.split('\\n').filter(l=>l.includes(p)).slice(0,10);if(lines.length)console.error(lines.join('\\n'))}catch(e){const lines=(e.stdout||'').split('\\n').filter(l=>l.includes(p)).slice(0,10);if(lines.length)console.error(lines.join('\\n'))}}}console.log(d)})\""
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
"description": "TypeScript check after editing .ts/.tsx files"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"matcher": "tool == \"Edit\" && tool_input.file_path matches \"\\\\.(ts|tsx|js|jsx)$\"",
|
|
165
|
+
"hooks": [
|
|
166
|
+
{
|
|
167
|
+
"type": "command",
|
|
168
|
+
"command": "node -e \"const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path;if(p&&fs.existsSync(p)){const c=fs.readFileSync(p,'utf8');const lines=c.split('\\n');const matches=[];lines.forEach((l,idx)=>{if(/console\\.log/.test(l))matches.push((idx+1)+': '+l.trim())});if(matches.length){console.error('[Hook] WARNING: console.log found in '+p);matches.slice(0,5).forEach(m=>console.error(m));console.error('[Hook] Remove console.log before committing')}}console.log(d)})\""
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
"description": "Warn about console.log statements after edits"
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
"Stop": [
|
|
175
|
+
{
|
|
176
|
+
"matcher": "*",
|
|
177
|
+
"hooks": [
|
|
178
|
+
{
|
|
179
|
+
"type": "command",
|
|
180
|
+
"command": "node -e \"const{execSync}=require('child_process');const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{execSync('git rev-parse --git-dir',{stdio:'pipe'})}catch{console.log(d);process.exit(0)}try{const files=execSync('git diff --name-only HEAD',{encoding:'utf8',stdio:['pipe','pipe','pipe']}).split('\\n').filter(f=>/\\.(ts|tsx|js|jsx)$/.test(f)&&fs.existsSync(f));let hasConsole=false;for(const f of files){if(fs.readFileSync(f,'utf8').includes('console.log')){console.error('[Hook] WARNING: console.log found in '+f);hasConsole=true}}if(hasConsole)console.error('[Hook] Remove console.log statements before committing')}catch(e){}console.log(d)})\""
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
"description": "Check for console.log in modified files after each response"
|
|
184
|
+
}
|
|
185
|
+
],
|
|
186
|
+
"SessionEnd": [
|
|
187
|
+
{
|
|
188
|
+
"matcher": "*",
|
|
189
|
+
"hooks": [
|
|
190
|
+
{
|
|
191
|
+
"type": "command",
|
|
192
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/session-end.js\""
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
"description": "Persist session state on end"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"matcher": "*",
|
|
199
|
+
"hooks": [
|
|
200
|
+
{
|
|
201
|
+
"type": "command",
|
|
202
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/evaluate-session.js\""
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
"description": "Evaluate session for extractable patterns"
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloudstreamsoftware/claude-tools
|
|
3
|
+
* CloudStream Claude Code productivity tools
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
// Export package paths for programmatic use
|
|
11
|
+
module.exports = {
|
|
12
|
+
// Root directory of the installed package
|
|
13
|
+
root: path.resolve(__dirname, '..'),
|
|
14
|
+
|
|
15
|
+
// Paths to key directories
|
|
16
|
+
paths: {
|
|
17
|
+
hooks: path.resolve(__dirname, '..', 'hooks'),
|
|
18
|
+
scripts: path.resolve(__dirname, '..', 'scripts'),
|
|
19
|
+
skills: path.resolve(__dirname, '..', 'skills'),
|
|
20
|
+
agents: path.resolve(__dirname, '..', 'agents'),
|
|
21
|
+
config: path.resolve(__dirname, '..', 'config'),
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Get the hooks configuration
|
|
25
|
+
getHooksConfig: function() {
|
|
26
|
+
const hooksPath = path.join(this.paths.hooks, 'hooks.json');
|
|
27
|
+
return require(hooksPath);
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
// Get available skills
|
|
31
|
+
getSkills: function() {
|
|
32
|
+
const skillsDir = this.paths.skills;
|
|
33
|
+
if (!require('fs').existsSync(skillsDir)) return [];
|
|
34
|
+
return require('fs').readdirSync(skillsDir, { withFileTypes: true })
|
|
35
|
+
.filter(d => d.isDirectory())
|
|
36
|
+
.map(d => d.name);
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
// Get available agents
|
|
40
|
+
getAgents: function() {
|
|
41
|
+
const agentsDir = this.paths.agents;
|
|
42
|
+
if (!require('fs').existsSync(agentsDir)) return [];
|
|
43
|
+
return require('fs').readdirSync(agentsDir)
|
|
44
|
+
.filter(f => f.endsWith('.md'))
|
|
45
|
+
.map(f => f.replace('.md', ''));
|
|
46
|
+
}
|
|
47
|
+
};
|