baldart 3.6.2
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/CHANGELOG.md +599 -0
- package/README.md +566 -0
- package/VERSION +1 -0
- package/bin/baldart.js +143 -0
- package/framework/.claude/agents/REGISTRY.md +169 -0
- package/framework/.claude/agents/api-perf-cost-auditor.md +291 -0
- package/framework/.claude/agents/code-reviewer.md +350 -0
- package/framework/.claude/agents/codebase-architect.md +391 -0
- package/framework/.claude/agents/coder.md +291 -0
- package/framework/.claude/agents/deep-human-insight.md +198 -0
- package/framework/.claude/agents/doc-reviewer.md +440 -0
- package/framework/.claude/agents/email-deliverability-architect.md +193 -0
- package/framework/.claude/agents/hybrid-ml-architect.md +285 -0
- package/framework/.claude/agents/hyper-gamification-designer.md +149 -0
- package/framework/.claude/agents/legal-counsel-gdpr.md +179 -0
- package/framework/.claude/agents/marketing-conversion-strategist.md +162 -0
- package/framework/.claude/agents/motion-expert.md +108 -0
- package/framework/.claude/agents/onboarding-architect-lead.md +230 -0
- package/framework/.claude/agents/plan-auditor.md +546 -0
- package/framework/.claude/agents/prd-card-writer.md +372 -0
- package/framework/.claude/agents/prd.md +744 -0
- package/framework/.claude/agents/qa-sentinel.md +305 -0
- package/framework/.claude/agents/remotion-animator-orchestrator.md +218 -0
- package/framework/.claude/agents/security-reviewer.md +276 -0
- package/framework/.claude/agents/senior-researcher.md +175 -0
- package/framework/.claude/agents/seo-analytics-strategist.md +156 -0
- package/framework/.claude/agents/skill-improver.md +61 -0
- package/framework/.claude/agents/ui-expert.md +191 -0
- package/framework/.claude/agents/visual-designer.md +190 -0
- package/framework/.claude/agents/website-orchestrator.md +118 -0
- package/framework/.claude/agents/wiki-curator.md +145 -0
- package/framework/.claude/commands/baldart-push.md +15 -0
- package/framework/.claude/commands/check.md +237 -0
- package/framework/.claude/commands/codexreview.md +203 -0
- package/framework/.claude/commands/design-review.md +11 -0
- package/framework/.claude/commands/issue-review.md +34 -0
- package/framework/.claude/commands/new.md +331 -0
- package/framework/.claude/commands/qa.md +257 -0
- package/framework/.claude/hooks/framework-edit-gate.js +208 -0
- package/framework/.claude/hooks/lint-before-commit.sh.template +66 -0
- package/framework/.claude/settings.local.json.example +32 -0
- package/framework/.claude/skills/api-design-principles/SKILL.md +567 -0
- package/framework/.claude/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/framework/.claude/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/framework/.claude/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/framework/.claude/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/framework/.claude/skills/baldart-push/SKILL.md +222 -0
- package/framework/.claude/skills/bug/SKILL.md +200 -0
- package/framework/.claude/skills/bug/references/logging-patterns.md +174 -0
- package/framework/.claude/skills/capture/SKILL.md +125 -0
- package/framework/.claude/skills/capture/references/synthesis-template.md +42 -0
- package/framework/.claude/skills/context-primer/SKILL.md +189 -0
- package/framework/.claude/skills/copywriting/SKILL.md +273 -0
- package/framework/.claude/skills/copywriting/references/copy-frameworks.md +338 -0
- package/framework/.claude/skills/copywriting/references/natural-transitions.md +252 -0
- package/framework/.claude/skills/doc-writing-for-rag/SKILL.md +119 -0
- package/framework/.claude/skills/doc-writing-for-rag/references/before-after-examples.md +291 -0
- package/framework/.claude/skills/doc-writing-for-rag/references/compact-templates.md +183 -0
- package/framework/.claude/skills/doc-writing-for-rag/references/frontmatter-minimal.md +112 -0
- package/framework/.claude/skills/doc-writing-for-rag/references/line-count-targets.md +110 -0
- package/framework/.claude/skills/doc-writing-for-rag/references/schemas-and-errors.md +129 -0
- package/framework/.claude/skills/find-skills/SKILL.md +133 -0
- package/framework/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/framework/.claude/skills/frontend-design/SKILL.md +84 -0
- package/framework/.claude/skills/gamification-design/SKILL.md +130 -0
- package/framework/.claude/skills/issue-review/SKILL.md +45 -0
- package/framework/.claude/skills/kie-ai/SKILL.md +262 -0
- package/framework/.claude/skills/kie-ai/references/models-catalog.md +272 -0
- package/framework/.claude/skills/kie-ai/scripts/kie_api.sh +209 -0
- package/framework/.claude/skills/kie-ai/scripts/remove_greenscreen.py +69 -0
- package/framework/.claude/skills/kie-ai/scripts/setup_api_key.sh +77 -0
- package/framework/.claude/skills/motion-design/LICENSE +21 -0
- package/framework/.claude/skills/motion-design/README.md +82 -0
- package/framework/.claude/skills/motion-design/SKILL.md +336 -0
- package/framework/.claude/skills/motion-design/director/choreography.md +93 -0
- package/framework/.claude/skills/motion-design/director/context-adaptation.md +83 -0
- package/framework/.claude/skills/motion-design/director/core-philosophy.md +53 -0
- package/framework/.claude/skills/motion-design/director/decision-framework.md +91 -0
- package/framework/.claude/skills/motion-design/director/disney-principles.md +102 -0
- package/framework/.claude/skills/motion-design/director/emotion-mapping.md +71 -0
- package/framework/.claude/skills/motion-design/director/motion-personality.md +89 -0
- package/framework/.claude/skills/motion-design/director/narrative-structure.md +62 -0
- package/framework/.claude/skills/motion-design/patterns/ambient-continuous.md +81 -0
- package/framework/.claude/skills/motion-design/patterns/entrance-exit.md +82 -0
- package/framework/.claude/skills/motion-design/patterns/multi-element.md +69 -0
- package/framework/.claude/skills/motion-design/patterns/state-feedback.md +96 -0
- package/framework/.claude/skills/motion-design/reference/property-selection.md +95 -0
- package/framework/.claude/skills/motion-design/reference/quality-checklist.md +67 -0
- package/framework/.claude/skills/motion-design/reference/timing-easing-tables.md +106 -0
- package/framework/.claude/skills/motion-design/reference/troubleshooting.md +73 -0
- package/framework/.claude/skills/new/SKILL.md +1687 -0
- package/framework/.claude/skills/playwright-skill/API_REFERENCE.md +652 -0
- package/framework/.claude/skills/playwright-skill/SKILL.md +157 -0
- package/framework/.claude/skills/playwright-skill/package.json +26 -0
- package/framework/.claude/skills/prd/SKILL.md +228 -0
- package/framework/.claude/skills/prd/assets/card-template.yml +232 -0
- package/framework/.claude/skills/prd/assets/epic-template.yml +190 -0
- package/framework/.claude/skills/prd/assets/prd-template.md +230 -0
- package/framework/.claude/skills/prd/assets/state-template.md +78 -0
- package/framework/.claude/skills/prd/references/api-perf-gate.md +152 -0
- package/framework/.claude/skills/prd/references/audit-phase.md +478 -0
- package/framework/.claude/skills/prd/references/backlog-phase.md +145 -0
- package/framework/.claude/skills/prd/references/discovery-phase.md +359 -0
- package/framework/.claude/skills/prd/references/impact-analysis.md +233 -0
- package/framework/.claude/skills/prd/references/prd-add-phase.md +214 -0
- package/framework/.claude/skills/prd/references/prd-writing-phase.md +145 -0
- package/framework/.claude/skills/prd/references/research-phase.md +216 -0
- package/framework/.claude/skills/prd/references/ui-design-phase.md +61 -0
- package/framework/.claude/skills/prd/references/validation-phase.md +72 -0
- package/framework/.claude/skills/prd-add/SKILL.md +222 -0
- package/framework/.claude/skills/prd-add/references/impact-analysis.md +233 -0
- package/framework/.claude/skills/remotion-best-practices/SKILL.md +48 -0
- package/framework/.claude/skills/remotion-best-practices/rules/3d.md +86 -0
- package/framework/.claude/skills/remotion-best-practices/rules/animations.md +29 -0
- package/framework/.claude/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
- package/framework/.claude/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
- package/framework/.claude/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
- package/framework/.claude/skills/remotion-best-practices/rules/assets.md +78 -0
- package/framework/.claude/skills/remotion-best-practices/rules/audio.md +169 -0
- package/framework/.claude/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
- package/framework/.claude/skills/remotion-best-practices/rules/can-decode.md +75 -0
- package/framework/.claude/skills/remotion-best-practices/rules/charts.md +58 -0
- package/framework/.claude/skills/remotion-best-practices/rules/compositions.md +141 -0
- package/framework/.claude/skills/remotion-best-practices/rules/display-captions.md +184 -0
- package/framework/.claude/skills/remotion-best-practices/rules/extract-frames.md +229 -0
- package/framework/.claude/skills/remotion-best-practices/rules/fonts.md +152 -0
- package/framework/.claude/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
- package/framework/.claude/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
- package/framework/.claude/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
- package/framework/.claude/skills/remotion-best-practices/rules/gifs.md +141 -0
- package/framework/.claude/skills/remotion-best-practices/rules/images.md +130 -0
- package/framework/.claude/skills/remotion-best-practices/rules/import-srt-captions.md +69 -0
- package/framework/.claude/skills/remotion-best-practices/rules/light-leaks.md +73 -0
- package/framework/.claude/skills/remotion-best-practices/rules/lottie.md +67 -0
- package/framework/.claude/skills/remotion-best-practices/rules/maps.md +401 -0
- package/framework/.claude/skills/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
- package/framework/.claude/skills/remotion-best-practices/rules/measuring-text.md +143 -0
- package/framework/.claude/skills/remotion-best-practices/rules/parameters.md +98 -0
- package/framework/.claude/skills/remotion-best-practices/rules/sequencing.md +118 -0
- package/framework/.claude/skills/remotion-best-practices/rules/subtitles.md +36 -0
- package/framework/.claude/skills/remotion-best-practices/rules/tailwind.md +11 -0
- package/framework/.claude/skills/remotion-best-practices/rules/text-animations.md +20 -0
- package/framework/.claude/skills/remotion-best-practices/rules/timing.md +179 -0
- package/framework/.claude/skills/remotion-best-practices/rules/transcribe-captions.md +70 -0
- package/framework/.claude/skills/remotion-best-practices/rules/transitions.md +197 -0
- package/framework/.claude/skills/remotion-best-practices/rules/transparent-videos.md +106 -0
- package/framework/.claude/skills/remotion-best-practices/rules/trimming.md +52 -0
- package/framework/.claude/skills/remotion-best-practices/rules/videos.md +171 -0
- package/framework/.claude/skills/seo-audit/SKILL.md +394 -0
- package/framework/.claude/skills/seo-audit/references/aeo-geo-patterns.md +279 -0
- package/framework/.claude/skills/seo-audit/references/ai-writing-detection.md +190 -0
- package/framework/.claude/skills/simplify/SKILL.md +137 -0
- package/framework/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/framework/.claude/skills/skill-creator/SKILL.md +356 -0
- package/framework/.claude/skills/skill-creator/references/output-patterns.md +82 -0
- package/framework/.claude/skills/skill-creator/references/workflows.md +28 -0
- package/framework/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/framework/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/framework/.claude/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/framework/.claude/skills/ui-design/SKILL.md +199 -0
- package/framework/.claude/skills/ui-design/references/component-discovery.md +54 -0
- package/framework/.claude/skills/ui-design/references/evaluation.md +171 -0
- package/framework/.claude/skills/ui-design/references/generation.md +109 -0
- package/framework/.claude/skills/ui-design/references/inventory.md +59 -0
- package/framework/.claude/skills/webapp-testing/LICENSE.txt +202 -0
- package/framework/.claude/skills/webapp-testing/SKILL.md +123 -0
- package/framework/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
- package/framework/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/framework/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/framework/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
- package/framework/.claude/skills/worktree-manager/SKILL.md +680 -0
- package/framework/AGENTS.md +240 -0
- package/framework/agents/api-contracts.md +137 -0
- package/framework/agents/architecture.md +145 -0
- package/framework/agents/coding-standards.md +148 -0
- package/framework/agents/data-model.md +110 -0
- package/framework/agents/deployment-protocol.md +232 -0
- package/framework/agents/design-review.md +172 -0
- package/framework/agents/env-reference.md +171 -0
- package/framework/agents/github-issue-subagent.md +252 -0
- package/framework/agents/index.md +261 -0
- package/framework/agents/llm-wiki-methodology.md +216 -0
- package/framework/agents/maintenance-protocol.md +305 -0
- package/framework/agents/observability.md +162 -0
- package/framework/agents/performance.md +155 -0
- package/framework/agents/project-context.md +145 -0
- package/framework/agents/runbook.md +208 -0
- package/framework/agents/security.md +168 -0
- package/framework/agents/skills-mapping.md +286 -0
- package/framework/agents/testing.md +111 -0
- package/framework/agents/workflows.md +215 -0
- package/framework/docs/PROJECT-CONFIGURATION.md +336 -0
- package/framework/docs/references/brand-guidelines.md +170 -0
- package/framework/docs/references/ui-guidelines.template.md +182 -0
- package/framework/routines/code-review.routine.yml +46 -0
- package/framework/routines/doc-review.routine.yml +45 -0
- package/framework/routines/ds-drift.routine.yml +52 -0
- package/framework/routines/full-sweep.routine.yml +51 -0
- package/framework/routines/index.yml +70 -0
- package/framework/routines/skill-improve.routine.yml +50 -0
- package/framework/routines/wiki-review.routine.yml +45 -0
- package/framework/templates/baldart.config.template.yml +113 -0
- package/framework/templates/breaking-change-checklist.md +484 -0
- package/framework/templates/feature-card.template.yml +125 -0
- package/framework/templates/overlays/README.md +44 -0
- package/framework/templates/overlays/copywriting.fidelity-example.md +62 -0
- package/framework/templates/overlays/ui-design.fidelity-example.md +75 -0
- package/framework/templates/skill-project-context.snippet.md +19 -0
- package/framework/templates/spec.template.md +208 -0
- package/package.json +51 -0
- package/src/commands/add.js +229 -0
- package/src/commands/configure.js +385 -0
- package/src/commands/doctor.js +486 -0
- package/src/commands/migrate.js +185 -0
- package/src/commands/push.js +0 -0
- package/src/commands/routines.js +269 -0
- package/src/commands/status.js +130 -0
- package/src/commands/update.js +419 -0
- package/src/commands/version.js +88 -0
- package/src/utils/contamination.js +400 -0
- package/src/utils/git.js +181 -0
- package/src/utils/hooks.js +152 -0
- package/src/utils/routine-adapters/claude-code-cloud.js +78 -0
- package/src/utils/routine-adapters/cron.js +138 -0
- package/src/utils/routine-adapters/github-actions.js +141 -0
- package/src/utils/routine-adapters/index.js +21 -0
- package/src/utils/routines.js +166 -0
- package/src/utils/state.js +143 -0
- package/src/utils/symlinks.js +425 -0
- package/src/utils/ui.js +133 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* framework-edit-gate — Claude Code PreToolUse hook.
|
|
4
|
+
*
|
|
5
|
+
* Intercepts Edit / Write / MultiEdit calls whose target resolves (via
|
|
6
|
+
* symlink) to a path inside `.framework/` — i.e. the BALDART subtree that
|
|
7
|
+
* flows upstream via `baldart push`. Runs the contamination scanner on the
|
|
8
|
+
* new content and blocks the call with an informative `reason` if any
|
|
9
|
+
* project-specific tokens are present (Neo-Brutalism, merchant, fidelity,
|
|
10
|
+
* Recharts, hardcoded paths, etc.).
|
|
11
|
+
*
|
|
12
|
+
* Effect: Claude sees the block reason and either reformulates the content
|
|
13
|
+
* generically (referencing `${paths.X}` / `identity.X`) or moves the change
|
|
14
|
+
* into `.baldart/overlays/<skill>.md`. Project-specific tokens never reach
|
|
15
|
+
* the framework subtree silently.
|
|
16
|
+
*
|
|
17
|
+
* Registration: see src/utils/hooks.js — `baldart add` and `baldart update`
|
|
18
|
+
* auto-register this hook in the consumer's `.claude/settings.json`.
|
|
19
|
+
*
|
|
20
|
+
* Fail-safe contract: this hook MUST NOT block legitimate work. If anything
|
|
21
|
+
* unexpected happens (missing scanner, parse error, IO error), it exits 0
|
|
22
|
+
* and lets the tool call through. We optimise for false negatives over
|
|
23
|
+
* false blocks — the scanner is a safety net, not a tribunal.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
'use strict';
|
|
27
|
+
|
|
28
|
+
const fs = require('fs');
|
|
29
|
+
const path = require('path');
|
|
30
|
+
|
|
31
|
+
function safeExit() {
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readStdin() {
|
|
36
|
+
try {
|
|
37
|
+
return fs.readFileSync(0, 'utf8');
|
|
38
|
+
} catch (_) {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseInput(raw) {
|
|
44
|
+
if (!raw) return null;
|
|
45
|
+
try { return JSON.parse(raw); } catch (_) { return null; }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function extractNewContent(toolName, toolInput) {
|
|
49
|
+
if (!toolInput) return '';
|
|
50
|
+
if (toolName === 'Edit') return String(toolInput.new_string || '');
|
|
51
|
+
if (toolName === 'Write') return String(toolInput.content || '');
|
|
52
|
+
if (toolName === 'MultiEdit') {
|
|
53
|
+
const edits = Array.isArray(toolInput.edits) ? toolInput.edits : [];
|
|
54
|
+
return edits.map((e) => String(e.new_string || '')).join('\n');
|
|
55
|
+
}
|
|
56
|
+
if (toolName === 'NotebookEdit') return String(toolInput.new_source || '');
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveReal(targetPath) {
|
|
61
|
+
if (!targetPath) return null;
|
|
62
|
+
// If file exists, realpath resolves symlinks all the way.
|
|
63
|
+
if (fs.existsSync(targetPath)) {
|
|
64
|
+
try { return fs.realpathSync(targetPath); } catch (_) {}
|
|
65
|
+
}
|
|
66
|
+
// For files about to be created, resolve the parent and rejoin.
|
|
67
|
+
try {
|
|
68
|
+
const parent = path.dirname(targetPath);
|
|
69
|
+
if (fs.existsSync(parent)) {
|
|
70
|
+
return path.join(fs.realpathSync(parent), path.basename(targetPath));
|
|
71
|
+
}
|
|
72
|
+
} catch (_) {}
|
|
73
|
+
return path.resolve(targetPath);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function findFrameworkRoot(realPath) {
|
|
77
|
+
// realPath looks like .../<consumer>/.framework/framework/.claude/skills/...
|
|
78
|
+
// Find the segment ".framework" and return the path up through it.
|
|
79
|
+
const sep = path.sep;
|
|
80
|
+
const idx = realPath.lastIndexOf(`${sep}.framework${sep}`);
|
|
81
|
+
if (idx === -1) return null;
|
|
82
|
+
return realPath.slice(0, idx + `${sep}.framework`.length);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function loadScanner(frameworkRoot) {
|
|
86
|
+
// Prefer the scanner from the same framework subtree the file lives in.
|
|
87
|
+
const candidates = [
|
|
88
|
+
path.join(frameworkRoot, 'src', 'utils', 'contamination.js'),
|
|
89
|
+
path.join(process.cwd(), '.framework', 'src', 'utils', 'contamination.js'),
|
|
90
|
+
];
|
|
91
|
+
for (const c of candidates) {
|
|
92
|
+
if (fs.existsSync(c)) {
|
|
93
|
+
try { return require(c); } catch (_) { /* try next */ }
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function blockReason(realPath, decisions, blockings) {
|
|
100
|
+
const findingLines = [...blockings, ...decisions]
|
|
101
|
+
.slice(0, 12)
|
|
102
|
+
.map((f) => ` • L${f.lineNum}: ${f.label} (matched: "${f.match.slice(0, 40)}") — ${f.advice}`)
|
|
103
|
+
.join('\n');
|
|
104
|
+
const more = (decisions.length + blockings.length) > 12
|
|
105
|
+
? `\n • … and ${decisions.length + blockings.length - 12} more`
|
|
106
|
+
: '';
|
|
107
|
+
|
|
108
|
+
const blockNote = blockings.length
|
|
109
|
+
? `\n\nIMPORTANT: ${blockings.length} of these are HARD BLOCKS (look like secrets or credentials). Even forcing through will require manual cleanup.`
|
|
110
|
+
: '';
|
|
111
|
+
|
|
112
|
+
return [
|
|
113
|
+
`framework-edit-gate: you are about to write to`,
|
|
114
|
+
` ${realPath}`,
|
|
115
|
+
`which is inside the BALDART framework subtree (\`.framework/\`).`,
|
|
116
|
+
`Changes here flow UPSTREAM via \`baldart push\`. The contamination`,
|
|
117
|
+
`scanner detected ${decisions.length + blockings.length} project-specific token(s):`,
|
|
118
|
+
``,
|
|
119
|
+
findingLines + more,
|
|
120
|
+
blockNote,
|
|
121
|
+
``,
|
|
122
|
+
`Decide which case this is:`,
|
|
123
|
+
``,
|
|
124
|
+
`(A) Generic improvement (useful to all consumers of the framework)`,
|
|
125
|
+
` → Reformulate WITHOUT these tokens:`,
|
|
126
|
+
` - hardcoded paths → use \${paths.X} (e.g. \${paths.design_system})`,
|
|
127
|
+
` - "Neo-Brutalism" etc. → reference identity.design_philosophy`,
|
|
128
|
+
` - "merchant"/"customer" → reference identity.audience_segments`,
|
|
129
|
+
` - "recharts" / "@nivo" → reference stack.charting.canonical`,
|
|
130
|
+
` Then retry the edit. The scanner will let it through.`,
|
|
131
|
+
``,
|
|
132
|
+
`(B) Project-specific opinion (only relevant to THIS consumer)`,
|
|
133
|
+
` → Do not write to \`.framework/\`. Instead write to:`,
|
|
134
|
+
` .baldart/overlays/<skill-name>.md`,
|
|
135
|
+
` This file is consumer-owned, never pushed upstream.`,
|
|
136
|
+
``,
|
|
137
|
+
`(C) Legitimate illustrative example (e.g. docs that quote the canonical`,
|
|
138
|
+
` paths as examples — \`PROJECT-CONFIGURATION.md\`, \`project-context.md\`)`,
|
|
139
|
+
` → Add the opt-out marker at the top of the file:`,
|
|
140
|
+
` <!-- contamination-scan: skip -->`,
|
|
141
|
+
` or in the YAML frontmatter:`,
|
|
142
|
+
` contamination_scan: skip`,
|
|
143
|
+
` Then retry the edit.`,
|
|
144
|
+
``,
|
|
145
|
+
`If you are sure none of A/B/C apply, ask the user explicitly before`,
|
|
146
|
+
`forcing the change through (e.g. by temporarily disabling this hook).`,
|
|
147
|
+
].join('\n');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function main() {
|
|
151
|
+
const raw = readStdin();
|
|
152
|
+
const input = parseInput(raw);
|
|
153
|
+
if (!input) safeExit();
|
|
154
|
+
|
|
155
|
+
const toolName = input.tool_name;
|
|
156
|
+
if (!['Edit', 'Write', 'MultiEdit', 'NotebookEdit'].includes(toolName)) safeExit();
|
|
157
|
+
|
|
158
|
+
const filePath = input.tool_input && input.tool_input.file_path;
|
|
159
|
+
if (!filePath || typeof filePath !== 'string') safeExit();
|
|
160
|
+
|
|
161
|
+
const realPath = resolveReal(filePath);
|
|
162
|
+
if (!realPath) safeExit();
|
|
163
|
+
|
|
164
|
+
const frameworkRoot = findFrameworkRoot(realPath);
|
|
165
|
+
if (!frameworkRoot) safeExit(); // outside .framework/ — nothing to do.
|
|
166
|
+
|
|
167
|
+
// Allow writes to .baldart/overlays/ even if the realPath has .framework in
|
|
168
|
+
// it for some reason — paranoid guard, shouldn't normally fire.
|
|
169
|
+
if (realPath.includes(`${path.sep}.baldart${path.sep}overlays${path.sep}`)) safeExit();
|
|
170
|
+
|
|
171
|
+
const scanner = loadScanner(frameworkRoot);
|
|
172
|
+
if (!scanner) safeExit(); // fail-safe — scanner missing, let it through.
|
|
173
|
+
|
|
174
|
+
const newContent = extractNewContent(toolName, input.tool_input);
|
|
175
|
+
if (!newContent) safeExit();
|
|
176
|
+
|
|
177
|
+
let findings;
|
|
178
|
+
try {
|
|
179
|
+
const r = scanner.scan(newContent);
|
|
180
|
+
if (r.optedOut) safeExit(); // file declared opt-out — let through.
|
|
181
|
+
findings = r.findings || [];
|
|
182
|
+
} catch (_) {
|
|
183
|
+
safeExit();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const decisions = findings.filter((f) => f.severity === 'requires-decision');
|
|
187
|
+
const blockings = findings.filter((f) => f.severity === 'block');
|
|
188
|
+
if (decisions.length === 0 && blockings.length === 0) safeExit();
|
|
189
|
+
|
|
190
|
+
const reason = blockReason(realPath, decisions, blockings);
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
process.stdout.write(JSON.stringify({
|
|
194
|
+
hookSpecificOutput: {
|
|
195
|
+
hookEventName: 'PreToolUse',
|
|
196
|
+
permissionDecision: 'deny',
|
|
197
|
+
permissionDecisionReason: reason,
|
|
198
|
+
},
|
|
199
|
+
}));
|
|
200
|
+
} catch (_) {
|
|
201
|
+
// Fallback to legacy mode: exit code 2 + stderr.
|
|
202
|
+
process.stderr.write(reason + '\n');
|
|
203
|
+
process.exit(2);
|
|
204
|
+
}
|
|
205
|
+
process.exit(0);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
try { main(); } catch (_) { safeExit(); }
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Lint check hook - runs before git commit to catch errors early
|
|
3
|
+
#
|
|
4
|
+
# Exit codes:
|
|
5
|
+
# 0 = allow command to proceed
|
|
6
|
+
# 2 = block command and show error to Claude
|
|
7
|
+
#
|
|
8
|
+
# SETUP INSTRUCTIONS:
|
|
9
|
+
# 1. Copy this file to .claude/hooks/lint-before-commit.sh
|
|
10
|
+
# 2. Make it executable: chmod +x .claude/hooks/lint-before-commit.sh
|
|
11
|
+
# 3. Customize the lint/build commands for your project
|
|
12
|
+
# 4. Test it: echo '{"command":"git commit -m test"}' | .claude/hooks/lint-before-commit.sh
|
|
13
|
+
|
|
14
|
+
# Read hook input from stdin (JSON with tool_input)
|
|
15
|
+
INPUT=$(cat)
|
|
16
|
+
|
|
17
|
+
# Extract command - handle both direct command and nested structure
|
|
18
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // .command // empty' 2>/dev/null)
|
|
19
|
+
|
|
20
|
+
# Only run lint check for git commit commands
|
|
21
|
+
if echo "$COMMAND" | grep -qE 'git commit'; then
|
|
22
|
+
echo "Running lint check before commit..." >&2
|
|
23
|
+
|
|
24
|
+
# Run linter - CUSTOMIZE THIS FOR YOUR PROJECT
|
|
25
|
+
# Examples:
|
|
26
|
+
# - Node.js/npm: npm run lint
|
|
27
|
+
# - Python: pylint src/ or flake8 src/
|
|
28
|
+
# - Ruby: rubocop
|
|
29
|
+
# - Go: golangci-lint run
|
|
30
|
+
LINT_OUTPUT=$(npm run lint 2>&1) # <-- CUSTOMIZE THIS COMMAND
|
|
31
|
+
LINT_EXIT=$?
|
|
32
|
+
|
|
33
|
+
if [ $LINT_EXIT -ne 0 ]; then
|
|
34
|
+
echo "" >&2
|
|
35
|
+
echo "LINT ERRORS - must fix before committing:" >&2
|
|
36
|
+
echo "$LINT_OUTPUT" >&2
|
|
37
|
+
echo "" >&2
|
|
38
|
+
echo "Fix these errors and try the commit again." >&2
|
|
39
|
+
exit 2 # Block the git commit
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
echo "Lint check passed." >&2
|
|
43
|
+
|
|
44
|
+
# Run build check - CUSTOMIZE THIS FOR YOUR PROJECT
|
|
45
|
+
# Examples:
|
|
46
|
+
# - Node.js/npm: npm run build
|
|
47
|
+
# - Python: python setup.py build
|
|
48
|
+
# - Go: go build
|
|
49
|
+
# - Rust: cargo build
|
|
50
|
+
echo "Running build check before commit..." >&2
|
|
51
|
+
BUILD_OUTPUT=$(npm run build 2>&1) # <-- CUSTOMIZE THIS COMMAND
|
|
52
|
+
BUILD_EXIT=$?
|
|
53
|
+
|
|
54
|
+
if [ $BUILD_EXIT -ne 0 ]; then
|
|
55
|
+
echo "" >&2
|
|
56
|
+
echo "BUILD ERRORS - must fix before committing:" >&2
|
|
57
|
+
echo "$BUILD_OUTPUT" >&2
|
|
58
|
+
echo "" >&2
|
|
59
|
+
echo "Fix these errors and try the commit again." >&2
|
|
60
|
+
exit 2 # Block the git commit
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
echo "Build check passed." >&2
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
exit 0 # Allow the command
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(cd *)",
|
|
5
|
+
"Bash(npm *)",
|
|
6
|
+
"Bash(npx *)",
|
|
7
|
+
"Bash(node *)",
|
|
8
|
+
"Bash(git *)",
|
|
9
|
+
"Bash(gh *)",
|
|
10
|
+
"Bash(ls *)",
|
|
11
|
+
"Bash(cat *)",
|
|
12
|
+
"Bash(head *)",
|
|
13
|
+
"Bash(tail *)",
|
|
14
|
+
"Bash(find *)",
|
|
15
|
+
"Bash(grep *)",
|
|
16
|
+
"Bash(rg *)",
|
|
17
|
+
"Bash(diff *)",
|
|
18
|
+
"Bash(wc *)",
|
|
19
|
+
"Bash(test *)",
|
|
20
|
+
"Bash(echo *)",
|
|
21
|
+
"WebFetch",
|
|
22
|
+
"WebSearch"
|
|
23
|
+
],
|
|
24
|
+
"deny": [
|
|
25
|
+
"Bash(git push --force *)",
|
|
26
|
+
"Bash(git push -f *)",
|
|
27
|
+
"Bash(git reset --hard *)",
|
|
28
|
+
"Bash(git branch -D *)",
|
|
29
|
+
"Bash(rm -rf *)"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|