@phuc1403/musketeer 0.9.0 → 0.10.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/INSTALLATION.md +52 -52
- package/bin/musketeer.js +168 -168
- package/package.json +48 -48
- package/src/dotnet-scaffold-copier.js +79 -79
- package/src/provisioner/detect.js +93 -93
- package/src/self-update.js +77 -77
- package/template/.claude/agents/git-manager.md +18 -18
- package/template/.claude/agents/hallmark-auditor.md +78 -78
- package/template/.claude/agents/researcher.md +33 -33
- package/template/.claude/hooks/block-unsafe-adr-title.cjs +85 -85
- package/template/.claude/hooks/init-adr-dir.cjs +173 -173
- package/template/.claude/hooks/inject-adr-flags.cjs +94 -94
- package/template/.claude/hooks/lib/adr/command-scan.cjs +115 -115
- package/template/.claude/hooks/lib/characteristics/checker.cjs +357 -357
- package/template/.claude/hooks/lib/git-info-cache.cjs +191 -191
- package/template/.claude/hooks/sync-adr-toc.cjs +146 -146
- package/template/.claude/hooks/usage-quota-cache-refresh.cjs +166 -166
- package/template/.claude/hooks/validate-characteristics-hook.cjs +66 -66
- package/template/.claude/hooks/validate-cml-hook.js +145 -145
- package/template/.claude/skills/adr-writer/SKILL.md +48 -48
- package/template/.claude/skills/adr-writer/references/adr-example.md +35 -35
- package/template/.claude/skills/architecture-characteristic-writer/SKILL.md +215 -215
- package/template/.claude/skills/architecture-characteristic-writer/assets/worksheet-template.md +29 -29
- package/template/.claude/skills/architecture-characteristic-writer/references/characteristics-catalog.md +40 -40
- package/template/.claude/skills/architecture-characteristic-writer/scripts/ranking-table.cjs +171 -171
- package/template/.claude/skills/context-map/SKILL.md +80 -80
- package/template/.claude/skills/context-map/example.cml +106 -106
- package/template/.claude/skills/context-map/reference/Bounded Context/Bounded Context.md +40 -40
- package/template/.claude/skills/context-map/reference/Bounded Context/businessModel.md +5 -5
- package/template/.claude/skills/context-map/reference/Bounded Context/domainVisionStatement.md +2 -2
- package/template/.claude/skills/context-map/reference/Bounded Context/evolution.md +5 -5
- package/template/.claude/skills/context-map/reference/Bounded Context/implementationTechnology.md +1 -1
- package/template/.claude/skills/context-map/reference/Bounded Context/implements.md +1 -1
- package/template/.claude/skills/context-map/reference/Bounded Context/knowledgeLevel.md +4 -4
- package/template/.claude/skills/context-map/reference/Bounded Context/realizes.md +9 -9
- package/template/.claude/skills/context-map/reference/Bounded Context/refines.md +10 -10
- package/template/.claude/skills/context-map/reference/Bounded Context/responsibilities.md +26 -26
- package/template/.claude/skills/context-map/reference/Bounded Context/type.md +23 -23
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Anticorruption Layer.md +5 -5
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Bounded Context Relationship.md +12 -12
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Conformist.md +5 -5
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Customer-Supplier (C-S).md +22 -22
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Open Host Service.md +4 -4
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Partnership (P).md +13 -13
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Published Language.md +4 -4
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Shared Kernel (SK).md +12 -12
- package/template/.claude/skills/context-map/reference/Context Map.md +62 -62
- package/template/.claude/skills/context-map/reference/Domain/Domain.md +30 -30
- package/template/.claude/skills/context-map/reference/Domain/supports.md +33 -33
- package/template/.claude/skills/context-map/reference/Domain/type.md +3 -3
- package/template/.claude/skills/context-map/reference/Semantic Rules.md +32 -32
- package/template/.claude/skills/hallmark/SKILL.md +552 -552
- package/template/.claude/skills/hallmark/references/anti-patterns.md +412 -412
- package/template/.claude/skills/hallmark/references/assets.md +406 -406
- package/template/.claude/skills/hallmark/references/color.md +95 -95
- package/template/.claude/skills/hallmark/references/component-cookbook.md +256 -256
- package/template/.claude/skills/hallmark/references/components/c1-outlined-chip.md +12 -12
- package/template/.claude/skills/hallmark/references/components/c2-inline-form-as-cta.md +16 -16
- package/template/.claude/skills/hallmark/references/components/c3-typographic-link.md +8 -8
- package/template/.claude/skills/hallmark/references/components/c4-sticky-bottom-bar.md +16 -16
- package/template/.claude/skills/hallmark/references/components/f1-bento-grid.md +20 -20
- package/template/.claude/skills/hallmark/references/components/f2-sticky-scroll-stack.md +20 -20
- package/template/.claude/skills/hallmark/references/components/f3-tabular-spec-sheet.md +11 -11
- package/template/.claude/skills/hallmark/references/components/f4-step-sequence.md +11 -11
- package/template/.claude/skills/hallmark/references/components/f5-annotated-screenshot.md +11 -11
- package/template/.claude/skills/hallmark/references/components/f6-product-card-grid.md +41 -41
- package/template/.claude/skills/hallmark/references/components/ft1-mast-headed.md +13 -13
- package/template/.claude/skills/hallmark/references/components/ft2-inline-rule-single-line.md +10 -10
- package/template/.claude/skills/hallmark/references/components/ft3-index-style-category-list.md +12 -12
- package/template/.claude/skills/hallmark/references/components/ft4-dense-typographic.md +10 -10
- package/template/.claude/skills/hallmark/references/components/ft5-statement.md +21 -21
- package/template/.claude/skills/hallmark/references/components/ft6-letter-close.md +19 -19
- package/template/.claude/skills/hallmark/references/components/ft7-newsletter-first.md +27 -27
- package/template/.claude/skills/hallmark/references/components/ft8-marquee-scroll.md +25 -25
- package/template/.claude/skills/hallmark/references/components/h1-marquee.md +15 -15
- package/template/.claude/skills/hallmark/references/components/h2-split-diptych.md +15 -15
- package/template/.claude/skills/hallmark/references/components/h3-quote-led.md +11 -11
- package/template/.claude/skills/hallmark/references/components/h4-stat-led.md +14 -14
- package/template/.claude/skills/hallmark/references/components/h5-letter-hero.md +11 -11
- package/template/.claude/skills/hallmark/references/components/h6-photographic-fold.md +16 -16
- package/template/.claude/skills/hallmark/references/components/h7-demo-video-clipped-by-viewport-edge.md +27 -27
- package/template/.claude/skills/hallmark/references/components/h8-mockup-split-browser-framed.md +23 -23
- package/template/.claude/skills/hallmark/references/components/h9-custom-illustration-centerpiece.md +27 -27
- package/template/.claude/skills/hallmark/references/components/n1-wordmark-2-links.md +12 -12
- package/template/.claude/skills/hallmark/references/components/n10-floating-on-scroll-morph.md +19 -19
- package/template/.claude/skills/hallmark/references/components/n2-floating-chip.md +14 -14
- package/template/.claude/skills/hallmark/references/components/n3-side-rail.md +14 -14
- package/template/.claude/skills/hallmark/references/components/n4-hidden-behind-k.md +9 -9
- package/template/.claude/skills/hallmark/references/components/n5-floating-pill.md +28 -28
- package/template/.claude/skills/hallmark/references/components/n6-newspaper-masthead.md +24 -24
- package/template/.claude/skills/hallmark/references/components/n7-brutal-slab.md +22 -22
- package/template/.claude/skills/hallmark/references/components/n8-terminal-command.md +21 -21
- package/template/.claude/skills/hallmark/references/components/n9-edge-aligned-minimal.md +17 -17
- package/template/.claude/skills/hallmark/references/components/s1-left-margin-numbered.md +15 -15
- package/template/.claude/skills/hallmark/references/components/s2-hanging.md +13 -13
- package/template/.claude/skills/hallmark/references/components/s3-sticky-pinned.md +19 -19
- package/template/.claude/skills/hallmark/references/components/s4-inline-no-break.md +11 -11
- package/template/.claude/skills/hallmark/references/components/s5-bottom-anchored.md +13 -13
- package/template/.claude/skills/hallmark/references/components/t1-pull-quote-with-marginalia.md +12 -12
- package/template/.claude/skills/hallmark/references/components/t2-logo-wall-hairline.md +19 -19
- package/template/.claude/skills/hallmark/references/components/t3-single-huge-quote.md +11 -11
- package/template/.claude/skills/hallmark/references/components/t4-numbered-stat-strip.md +14 -14
- package/template/.claude/skills/hallmark/references/contract.md +24 -24
- package/template/.claude/skills/hallmark/references/copy.md +182 -182
- package/template/.claude/skills/hallmark/references/custom-craft.md +626 -626
- package/template/.claude/skills/hallmark/references/custom-theme.md +329 -329
- package/template/.claude/skills/hallmark/references/design-md.md +116 -116
- package/template/.claude/skills/hallmark/references/export-formats.md +328 -328
- package/template/.claude/skills/hallmark/references/floating-nav.md +89 -89
- package/template/.claude/skills/hallmark/references/genres/atmospheric.md +65 -65
- package/template/.claude/skills/hallmark/references/genres/editorial.md +70 -70
- package/template/.claude/skills/hallmark/references/genres/modern-minimal.md +67 -67
- package/template/.claude/skills/hallmark/references/genres/playful.md +65 -65
- package/template/.claude/skills/hallmark/references/hero-enrichment.md +474 -474
- package/template/.claude/skills/hallmark/references/imagery-kit.md +170 -170
- package/template/.claude/skills/hallmark/references/interaction-and-states.md +207 -207
- package/template/.claude/skills/hallmark/references/layout-and-space.md +111 -111
- package/template/.claude/skills/hallmark/references/macrostructures/01-bento-grid.md +35 -35
- package/template/.claude/skills/hallmark/references/macrostructures/02-long-document.md +34 -34
- package/template/.claude/skills/hallmark/references/macrostructures/03-marquee-hero.md +31 -31
- package/template/.claude/skills/hallmark/references/macrostructures/04-stat-led.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/05-workbench.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/06-conversational-faq.md +33 -33
- package/template/.claude/skills/hallmark/references/macrostructures/07-manifesto.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/08-photographic.md +34 -34
- package/template/.claude/skills/hallmark/references/macrostructures/09-quote-led.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/10-specimen.md +32 -32
- package/template/.claude/skills/hallmark/references/macrostructures/11-catalogue.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/12-letter.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/13-index-first.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/14-narrative-workflow.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/15-split-studio.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/17-type-specimen.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/18-portfolio-grid.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/19-map-diagram.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/20-ecosystem-index.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures/21-component-playground.md +23 -23
- package/template/.claude/skills/hallmark/references/macrostructures.md +89 -89
- package/template/.claude/skills/hallmark/references/microinteractions.md +260 -260
- package/template/.claude/skills/hallmark/references/motion.md +109 -109
- package/template/.claude/skills/hallmark/references/preview-examples.md +49 -49
- package/template/.claude/skills/hallmark/references/responsive.md +138 -138
- package/template/.claude/skills/hallmark/references/slop-test.md +205 -205
- package/template/.claude/skills/hallmark/references/structure.md +164 -164
- package/template/.claude/skills/hallmark/references/study.md +511 -511
- package/template/.claude/skills/hallmark/references/typography.md +243 -243
- package/template/.claude/skills/hallmark/references/verbs/audit.md +25 -25
- package/template/.claude/skills/hallmark/references/verbs/redesign.md +269 -269
- package/template/.claude/skills/hallmark-loop/SKILL.md +105 -105
- package/template/.claude/skills/hallmark-loop/references/auditor-call.md +60 -60
- package/template/.claude/skills/hallmark-loop/references/capture.md +78 -78
- package/template/.claude/skills/hallmark-loop/references/loop-control.md +79 -79
- package/template/.claude/skills/handoff/SKILL.md +15 -15
- package/template/.claude/skills/knowledge-crunching/SKILL.md +94 -94
- package/template/.claude/skills/research/SKILL.md +69 -69
- package/template/.claude/skills/tdd/SKILL.md +142 -142
- package/template/.claude/skills/tdd/deep-modules.md +15 -15
- package/template/.claude/skills/tdd/interface-design.md +31 -31
- package/template/.claude/skills/tdd/mocking.md +59 -59
- package/template/.claude/skills/tdd/refactoring.md +10 -10
- package/template/.claude/skills/tdd/tests.md +61 -61
- package/template/.claude/statusline.cjs +100 -37
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Usage Cache Writer - UserPromptSubmit & PostToolUse Hook
|
|
4
|
-
*
|
|
5
|
-
* Fetches Claude Code usage limits from Anthropic OAuth API and writes to cache.
|
|
6
|
-
* The cache is read by statusline.cjs to show the 5-hour rate-limit budget.
|
|
7
|
-
*
|
|
8
|
-
* Self-contained port (no .ck.json / hook-logger deps). Fails open: any error
|
|
9
|
-
* just emits {continue:true} so it can never block a prompt or tool call.
|
|
10
|
-
*
|
|
11
|
-
* Features:
|
|
12
|
-
* - Cross-platform credential retrieval (macOS Keychain, file-based)
|
|
13
|
-
* - API response caching (60s TTL)
|
|
14
|
-
* - Throttled API calls (1 min for prompts, 5 mins for tool use)
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const fs = require("fs");
|
|
19
|
-
const path = require("path");
|
|
20
|
-
const os = require("os");
|
|
21
|
-
const { execSync } = require("child_process");
|
|
22
|
-
|
|
23
|
-
// Cache configuration
|
|
24
|
-
const USAGE_CACHE_FILE = path.join(os.tmpdir(), "ck-usage-limits-cache.json");
|
|
25
|
-
const FETCH_INTERVAL_MS = 300000; // 5 minutes for PostToolUse
|
|
26
|
-
const FETCH_INTERVAL_PROMPT_MS = 60000; // 1 minute for UserPromptSubmit
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get Claude OAuth credentials (cross-platform)
|
|
30
|
-
*/
|
|
31
|
-
function getClaudeCredentials() {
|
|
32
|
-
// macOS: Try Keychain first
|
|
33
|
-
if (os.platform() === "darwin") {
|
|
34
|
-
try {
|
|
35
|
-
const result = execSync('security find-generic-password -s "Claude Code-credentials" -w', {
|
|
36
|
-
timeout: 5000,
|
|
37
|
-
encoding: "utf-8",
|
|
38
|
-
stdio: ["pipe", "pipe", "ignore"],
|
|
39
|
-
}).trim();
|
|
40
|
-
const parsed = JSON.parse(result);
|
|
41
|
-
if (parsed.claudeAiOauth?.accessToken) {
|
|
42
|
-
return parsed.claudeAiOauth.accessToken;
|
|
43
|
-
}
|
|
44
|
-
} catch {
|
|
45
|
-
// Fallback to file-based
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// File-based credentials (Linux/Windows, or macOS fallback)
|
|
50
|
-
const credPath = path.join(os.homedir(), ".claude", ".credentials.json");
|
|
51
|
-
try {
|
|
52
|
-
const content = fs.readFileSync(credPath, "utf-8");
|
|
53
|
-
const parsed = JSON.parse(content);
|
|
54
|
-
return parsed.claudeAiOauth?.accessToken || null;
|
|
55
|
-
} catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Check if we should fetch (throttled)
|
|
62
|
-
*/
|
|
63
|
-
function shouldFetch(isUserPrompt = false) {
|
|
64
|
-
const interval = isUserPrompt ? FETCH_INTERVAL_PROMPT_MS : FETCH_INTERVAL_MS;
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
if (fs.existsSync(USAGE_CACHE_FILE)) {
|
|
68
|
-
const cache = JSON.parse(fs.readFileSync(USAGE_CACHE_FILE, "utf-8"));
|
|
69
|
-
if (Date.now() - cache.timestamp < interval) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
} catch {}
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Write cache atomically (temp+rename prevents partial reads by statusline)
|
|
79
|
-
*/
|
|
80
|
-
function writeCache(status, data = null) {
|
|
81
|
-
const tmpFile = `${USAGE_CACHE_FILE}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
82
|
-
try {
|
|
83
|
-
fs.writeFileSync(
|
|
84
|
-
tmpFile,
|
|
85
|
-
JSON.stringify({
|
|
86
|
-
timestamp: Date.now(),
|
|
87
|
-
status,
|
|
88
|
-
data,
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
fs.renameSync(tmpFile, USAGE_CACHE_FILE);
|
|
92
|
-
} catch {
|
|
93
|
-
try { fs.unlinkSync(tmpFile); } catch {}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Fetch usage limits from Anthropic OAuth API and write to cache
|
|
99
|
-
* Always writes status to cache (available or unavailable) for statusline fallback
|
|
100
|
-
*/
|
|
101
|
-
async function fetchAndCacheUsageLimits() {
|
|
102
|
-
const token = getClaudeCredentials();
|
|
103
|
-
if (!token) {
|
|
104
|
-
writeCache("unavailable");
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
const response = await fetch("https://api.anthropic.com/api/oauth/usage", {
|
|
110
|
-
method: "GET",
|
|
111
|
-
headers: {
|
|
112
|
-
Accept: "application/json",
|
|
113
|
-
"Content-Type": "application/json",
|
|
114
|
-
Authorization: `Bearer ${token}`,
|
|
115
|
-
"anthropic-beta": "oauth-2025-04-20",
|
|
116
|
-
"User-Agent": "claudekit-engineer/1.0",
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
if (!response.ok) {
|
|
121
|
-
writeCache("unavailable");
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const data = await response.json();
|
|
126
|
-
writeCache("available", data);
|
|
127
|
-
} catch {
|
|
128
|
-
writeCache("unavailable");
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Main hook execution - just fetch and cache, no injection
|
|
134
|
-
*/
|
|
135
|
-
async function main() {
|
|
136
|
-
const result = { continue: true };
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
// Read hook input
|
|
140
|
-
let inputStr = "";
|
|
141
|
-
try {
|
|
142
|
-
inputStr = fs.readFileSync(0, "utf-8");
|
|
143
|
-
} catch {}
|
|
144
|
-
|
|
145
|
-
const input = JSON.parse(inputStr || "{}");
|
|
146
|
-
|
|
147
|
-
// Detect hook type (UserPromptSubmit vs PostToolUse) for throttle interval
|
|
148
|
-
const isUserPrompt = typeof input.prompt === "string";
|
|
149
|
-
|
|
150
|
-
// Check if we should fetch (throttled)
|
|
151
|
-
if (shouldFetch(isUserPrompt)) {
|
|
152
|
-
await fetchAndCacheUsageLimits();
|
|
153
|
-
}
|
|
154
|
-
} catch {}
|
|
155
|
-
|
|
156
|
-
// Output result (no injection, just continue)
|
|
157
|
-
console.log(JSON.stringify(result));
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
main().catch(() => {
|
|
161
|
-
console.log(JSON.stringify({ continue: true }));
|
|
162
|
-
process.exit(0);
|
|
163
|
-
});
|
|
164
|
-
} catch (e) {
|
|
165
|
-
process.exit(0); // fail-open
|
|
166
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Usage Cache Writer - UserPromptSubmit & PostToolUse Hook
|
|
4
|
+
*
|
|
5
|
+
* Fetches Claude Code usage limits from Anthropic OAuth API and writes to cache.
|
|
6
|
+
* The cache is read by statusline.cjs to show the 5-hour rate-limit budget.
|
|
7
|
+
*
|
|
8
|
+
* Self-contained port (no .ck.json / hook-logger deps). Fails open: any error
|
|
9
|
+
* just emits {continue:true} so it can never block a prompt or tool call.
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Cross-platform credential retrieval (macOS Keychain, file-based)
|
|
13
|
+
* - API response caching (60s TTL)
|
|
14
|
+
* - Throttled API calls (1 min for prompts, 5 mins for tool use)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const fs = require("fs");
|
|
19
|
+
const path = require("path");
|
|
20
|
+
const os = require("os");
|
|
21
|
+
const { execSync } = require("child_process");
|
|
22
|
+
|
|
23
|
+
// Cache configuration
|
|
24
|
+
const USAGE_CACHE_FILE = path.join(os.tmpdir(), "ck-usage-limits-cache.json");
|
|
25
|
+
const FETCH_INTERVAL_MS = 300000; // 5 minutes for PostToolUse
|
|
26
|
+
const FETCH_INTERVAL_PROMPT_MS = 60000; // 1 minute for UserPromptSubmit
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get Claude OAuth credentials (cross-platform)
|
|
30
|
+
*/
|
|
31
|
+
function getClaudeCredentials() {
|
|
32
|
+
// macOS: Try Keychain first
|
|
33
|
+
if (os.platform() === "darwin") {
|
|
34
|
+
try {
|
|
35
|
+
const result = execSync('security find-generic-password -s "Claude Code-credentials" -w', {
|
|
36
|
+
timeout: 5000,
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
39
|
+
}).trim();
|
|
40
|
+
const parsed = JSON.parse(result);
|
|
41
|
+
if (parsed.claudeAiOauth?.accessToken) {
|
|
42
|
+
return parsed.claudeAiOauth.accessToken;
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
// Fallback to file-based
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// File-based credentials (Linux/Windows, or macOS fallback)
|
|
50
|
+
const credPath = path.join(os.homedir(), ".claude", ".credentials.json");
|
|
51
|
+
try {
|
|
52
|
+
const content = fs.readFileSync(credPath, "utf-8");
|
|
53
|
+
const parsed = JSON.parse(content);
|
|
54
|
+
return parsed.claudeAiOauth?.accessToken || null;
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check if we should fetch (throttled)
|
|
62
|
+
*/
|
|
63
|
+
function shouldFetch(isUserPrompt = false) {
|
|
64
|
+
const interval = isUserPrompt ? FETCH_INTERVAL_PROMPT_MS : FETCH_INTERVAL_MS;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
if (fs.existsSync(USAGE_CACHE_FILE)) {
|
|
68
|
+
const cache = JSON.parse(fs.readFileSync(USAGE_CACHE_FILE, "utf-8"));
|
|
69
|
+
if (Date.now() - cache.timestamp < interval) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch {}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Write cache atomically (temp+rename prevents partial reads by statusline)
|
|
79
|
+
*/
|
|
80
|
+
function writeCache(status, data = null) {
|
|
81
|
+
const tmpFile = `${USAGE_CACHE_FILE}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
82
|
+
try {
|
|
83
|
+
fs.writeFileSync(
|
|
84
|
+
tmpFile,
|
|
85
|
+
JSON.stringify({
|
|
86
|
+
timestamp: Date.now(),
|
|
87
|
+
status,
|
|
88
|
+
data,
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
fs.renameSync(tmpFile, USAGE_CACHE_FILE);
|
|
92
|
+
} catch {
|
|
93
|
+
try { fs.unlinkSync(tmpFile); } catch {}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Fetch usage limits from Anthropic OAuth API and write to cache
|
|
99
|
+
* Always writes status to cache (available or unavailable) for statusline fallback
|
|
100
|
+
*/
|
|
101
|
+
async function fetchAndCacheUsageLimits() {
|
|
102
|
+
const token = getClaudeCredentials();
|
|
103
|
+
if (!token) {
|
|
104
|
+
writeCache("unavailable");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const response = await fetch("https://api.anthropic.com/api/oauth/usage", {
|
|
110
|
+
method: "GET",
|
|
111
|
+
headers: {
|
|
112
|
+
Accept: "application/json",
|
|
113
|
+
"Content-Type": "application/json",
|
|
114
|
+
Authorization: `Bearer ${token}`,
|
|
115
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
116
|
+
"User-Agent": "claudekit-engineer/1.0",
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
writeCache("unavailable");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const data = await response.json();
|
|
126
|
+
writeCache("available", data);
|
|
127
|
+
} catch {
|
|
128
|
+
writeCache("unavailable");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Main hook execution - just fetch and cache, no injection
|
|
134
|
+
*/
|
|
135
|
+
async function main() {
|
|
136
|
+
const result = { continue: true };
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
// Read hook input
|
|
140
|
+
let inputStr = "";
|
|
141
|
+
try {
|
|
142
|
+
inputStr = fs.readFileSync(0, "utf-8");
|
|
143
|
+
} catch {}
|
|
144
|
+
|
|
145
|
+
const input = JSON.parse(inputStr || "{}");
|
|
146
|
+
|
|
147
|
+
// Detect hook type (UserPromptSubmit vs PostToolUse) for throttle interval
|
|
148
|
+
const isUserPrompt = typeof input.prompt === "string";
|
|
149
|
+
|
|
150
|
+
// Check if we should fetch (throttled)
|
|
151
|
+
if (shouldFetch(isUserPrompt)) {
|
|
152
|
+
await fetchAndCacheUsageLimits();
|
|
153
|
+
}
|
|
154
|
+
} catch {}
|
|
155
|
+
|
|
156
|
+
// Output result (no injection, just continue)
|
|
157
|
+
console.log(JSON.stringify(result));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
main().catch(() => {
|
|
161
|
+
console.log(JSON.stringify({ continue: true }));
|
|
162
|
+
process.exit(0);
|
|
163
|
+
});
|
|
164
|
+
} catch (e) {
|
|
165
|
+
process.exit(0); // fail-open
|
|
166
|
+
}
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// PostToolUse validation hook for the two architecture-characteristic documents.
|
|
3
|
-
//
|
|
4
|
-
// .claude/settings.json calls this after every Write/Edit/MultiEdit. If the
|
|
5
|
-
// edited file is the ranking or the worksheet, both are checked together — the
|
|
6
|
-
// worksheet is a derivation of the ranking, so neither can be judged alone.
|
|
7
|
-
//
|
|
8
|
-
// Hook exit-code contract:
|
|
9
|
-
// exit 0 -> ok (stdout shown in transcript)
|
|
10
|
-
// exit 2 -> blocking error (stderr fed back to Claude to fix)
|
|
11
|
-
// An unrelated edit, a missing file, or an unparseable payload all exit 0.
|
|
12
|
-
//
|
|
13
|
-
// Only structure is checked. The ranking ORDER is the architect's call and is
|
|
14
|
-
// never second-guessed here.
|
|
15
|
-
|
|
16
|
-
const fs = require('fs');
|
|
17
|
-
const path = require('path');
|
|
18
|
-
|
|
19
|
-
const RANKING = 'docs/architecture-characteristics-ranking.md';
|
|
20
|
-
const WORKSHEET = 'docs/architecture-characteristics.md';
|
|
21
|
-
|
|
22
|
-
function read(root, rel) {
|
|
23
|
-
try {
|
|
24
|
-
return fs.readFileSync(path.join(root, rel), 'utf8');
|
|
25
|
-
} catch {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
32
|
-
const payload = JSON.parse(fs.readFileSync(0, 'utf8'));
|
|
33
|
-
const edited = payload?.tool_input?.file_path;
|
|
34
|
-
|
|
35
|
-
if (!edited) process.exit(0);
|
|
36
|
-
|
|
37
|
-
// Windows resolves paths case-insensitively, so the same document can arrive
|
|
38
|
-
// spelled several ways. Comparing case-sensitively there would let an edit
|
|
39
|
-
// slip past the gate unchecked, which is worse than checking one file twice.
|
|
40
|
-
const fold = (p) => (process.platform === 'win32' ? p.toLowerCase() : p);
|
|
41
|
-
const rel = path.relative(root, path.resolve(root, edited)).split(path.sep).join('/');
|
|
42
|
-
if (fold(rel) !== fold(RANKING) && fold(rel) !== fold(WORKSHEET)) process.exit(0);
|
|
43
|
-
|
|
44
|
-
const { check } = require('./lib/characteristics/checker.cjs');
|
|
45
|
-
const ranking = read(root, RANKING);
|
|
46
|
-
|
|
47
|
-
// Editing the ranking alone, before any worksheet exists, is the normal path
|
|
48
|
-
// through Phase A: `read` returns null and the worksheet rules stay quiet.
|
|
49
|
-
const worksheet = read(root, WORKSHEET);
|
|
50
|
-
|
|
51
|
-
const errors = check({ ranking, worksheet });
|
|
52
|
-
|
|
53
|
-
if (errors.length) {
|
|
54
|
-
process.stderr.write(
|
|
55
|
-
`Architecture characteristics: ${errors.length} structural problem(s) in ${rel}\n\n` +
|
|
56
|
-
errors.map((e) => ` - ${e}`).join('\n') +
|
|
57
|
-
'\n\nFix the file. These are mechanical rules, not judgement calls: the ranking must ' +
|
|
58
|
-
'cover the catalog exactly once each, every Reason must name the row directly below it, ' +
|
|
59
|
-
'and the worksheet must derive from the top 7.\n'
|
|
60
|
-
);
|
|
61
|
-
process.exit(2);
|
|
62
|
-
}
|
|
63
|
-
} catch {
|
|
64
|
-
/* fail open — a structure checker must never be the thing that breaks a session */
|
|
65
|
-
}
|
|
66
|
-
process.exit(0);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// PostToolUse validation hook for the two architecture-characteristic documents.
|
|
3
|
+
//
|
|
4
|
+
// .claude/settings.json calls this after every Write/Edit/MultiEdit. If the
|
|
5
|
+
// edited file is the ranking or the worksheet, both are checked together — the
|
|
6
|
+
// worksheet is a derivation of the ranking, so neither can be judged alone.
|
|
7
|
+
//
|
|
8
|
+
// Hook exit-code contract:
|
|
9
|
+
// exit 0 -> ok (stdout shown in transcript)
|
|
10
|
+
// exit 2 -> blocking error (stderr fed back to Claude to fix)
|
|
11
|
+
// An unrelated edit, a missing file, or an unparseable payload all exit 0.
|
|
12
|
+
//
|
|
13
|
+
// Only structure is checked. The ranking ORDER is the architect's call and is
|
|
14
|
+
// never second-guessed here.
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const RANKING = 'docs/architecture-characteristics-ranking.md';
|
|
20
|
+
const WORKSHEET = 'docs/architecture-characteristics.md';
|
|
21
|
+
|
|
22
|
+
function read(root, rel) {
|
|
23
|
+
try {
|
|
24
|
+
return fs.readFileSync(path.join(root, rel), 'utf8');
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
32
|
+
const payload = JSON.parse(fs.readFileSync(0, 'utf8'));
|
|
33
|
+
const edited = payload?.tool_input?.file_path;
|
|
34
|
+
|
|
35
|
+
if (!edited) process.exit(0);
|
|
36
|
+
|
|
37
|
+
// Windows resolves paths case-insensitively, so the same document can arrive
|
|
38
|
+
// spelled several ways. Comparing case-sensitively there would let an edit
|
|
39
|
+
// slip past the gate unchecked, which is worse than checking one file twice.
|
|
40
|
+
const fold = (p) => (process.platform === 'win32' ? p.toLowerCase() : p);
|
|
41
|
+
const rel = path.relative(root, path.resolve(root, edited)).split(path.sep).join('/');
|
|
42
|
+
if (fold(rel) !== fold(RANKING) && fold(rel) !== fold(WORKSHEET)) process.exit(0);
|
|
43
|
+
|
|
44
|
+
const { check } = require('./lib/characteristics/checker.cjs');
|
|
45
|
+
const ranking = read(root, RANKING);
|
|
46
|
+
|
|
47
|
+
// Editing the ranking alone, before any worksheet exists, is the normal path
|
|
48
|
+
// through Phase A: `read` returns null and the worksheet rules stay quiet.
|
|
49
|
+
const worksheet = read(root, WORKSHEET);
|
|
50
|
+
|
|
51
|
+
const errors = check({ ranking, worksheet });
|
|
52
|
+
|
|
53
|
+
if (errors.length) {
|
|
54
|
+
process.stderr.write(
|
|
55
|
+
`Architecture characteristics: ${errors.length} structural problem(s) in ${rel}\n\n` +
|
|
56
|
+
errors.map((e) => ` - ${e}`).join('\n') +
|
|
57
|
+
'\n\nFix the file. These are mechanical rules, not judgement calls: the ranking must ' +
|
|
58
|
+
'cover the catalog exactly once each, every Reason must name the row directly below it, ' +
|
|
59
|
+
'and the worksheet must derive from the top 7.\n'
|
|
60
|
+
);
|
|
61
|
+
process.exit(2);
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
/* fail open — a structure checker must never be the thing that breaks a session */
|
|
65
|
+
}
|
|
66
|
+
process.exit(0);
|