@haposoft/cafekit 0.3.11 → 0.4.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 +83 -28
- package/bin/install.js +125 -1
- package/package.json +5 -3
- package/src/claude/hooks/agent.cjs +203 -0
- package/src/claude/hooks/lib/color.cjs +95 -0
- package/src/claude/hooks/lib/config.cjs +831 -0
- package/src/claude/hooks/lib/context.cjs +616 -0
- package/src/claude/hooks/lib/counter.cjs +103 -0
- package/src/claude/hooks/lib/detect.cjs +474 -0
- package/src/claude/hooks/lib/git.cjs +143 -0
- package/src/claude/hooks/lib/parser.cjs +182 -0
- package/src/claude/hooks/session.cjs +360 -0
- package/src/claude/hooks/usage.cjs +179 -0
- package/src/claude/migration-manifest.json +27 -2
- package/src/claude/settings/status.settings.json +54 -0
- package/src/claude/status.cjs +539 -0
- package/src/common/skills/code/SKILL.md +55 -0
- package/src/common/skills/code/references/execution-loop.md +21 -0
- package/src/common/skills/impact-analysis/references/change-detection.md +16 -16
- package/src/common/skills/impact-analysis/references/dependency-scouting.md +8 -8
- package/src/common/skills/impact-analysis/references/edge-case-identification.md +11 -11
- package/src/common/skills/impact-analysis/references/industry-techniques.md +36 -36
- package/src/common/skills/impact-analysis/references/practical-techniques-guide.md +16 -16
- package/src/common/skills/impact-analysis/references/project-detection.md +1 -1
- package/src/common/skills/impact-analysis/references/report-template.md +2 -2
- package/src/common/skills/impact-analysis/scripts/README.md +3 -3
- package/src/common/skills/review/SKILL.md +46 -0
- package/src/common/skills/review/references/review-focus.md +28 -0
- package/src/common/skills/spec-design/SKILL.md +66 -0
- package/src/common/skills/spec-design/references/design-discovery.md +46 -0
- package/src/common/skills/spec-init/SKILL.md +61 -0
- package/src/common/skills/spec-requirements/SKILL.md +59 -0
- package/src/common/skills/spec-requirements/references/requirements-workflow.md +36 -0
- package/src/common/skills/spec-tasks/SKILL.md +60 -0
- package/src/common/skills/spec-tasks/references/task-sizing.md +36 -0
- package/src/common/skills/test/SKILL.md +40 -0
|
@@ -0,0 +1,179 @@
|
|
|
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:
|
|
7
|
+
* - status.cjs (for display)
|
|
8
|
+
* - context.cjs (for injection)
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Cross-platform credential retrieval (macOS Keychain, file-based)
|
|
12
|
+
* - API response caching (60s TTL)
|
|
13
|
+
* - Throttled API calls (1 min for prompts, 5 mins for tool use)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Crash wrapper
|
|
17
|
+
try {
|
|
18
|
+
const fs = require("fs");
|
|
19
|
+
const path = require("path");
|
|
20
|
+
const os = require("os");
|
|
21
|
+
const { execSync } = require("child_process");
|
|
22
|
+
const { isHookEnabled } = require('./lib/config.cjs');
|
|
23
|
+
|
|
24
|
+
// Early exit if hook disabled in config
|
|
25
|
+
if (!isHookEnabled('usage-context-awareness')) {
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Cache configuration
|
|
30
|
+
const USAGE_CACHE_FILE = path.join(os.tmpdir(), "ck-usage-limits-cache.json");
|
|
31
|
+
const CACHE_TTL_MS = 60000; // 60 seconds
|
|
32
|
+
const FETCH_INTERVAL_MS = 300000; // 5 minutes for PostToolUse
|
|
33
|
+
const FETCH_INTERVAL_PROMPT_MS = 60000; // 1 minute for UserPromptSubmit
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get Claude OAuth credentials (cross-platform)
|
|
37
|
+
*/
|
|
38
|
+
function getClaudeCredentials() {
|
|
39
|
+
// macOS: Try Keychain first
|
|
40
|
+
if (os.platform() === "darwin") {
|
|
41
|
+
try {
|
|
42
|
+
const result = execSync('security find-generic-password -s "Claude Code-credentials" -w', {
|
|
43
|
+
timeout: 5000,
|
|
44
|
+
encoding: "utf-8",
|
|
45
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
46
|
+
}).trim();
|
|
47
|
+
const parsed = JSON.parse(result);
|
|
48
|
+
if (parsed.claudeAiOauth?.accessToken) {
|
|
49
|
+
return parsed.claudeAiOauth.accessToken;
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
// Fallback to file-based
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// File-based credentials (Linux/Windows, or macOS fallback)
|
|
57
|
+
const credPath = path.join(os.homedir(), ".claude", ".credentials.json");
|
|
58
|
+
try {
|
|
59
|
+
const content = fs.readFileSync(credPath, "utf-8");
|
|
60
|
+
const parsed = JSON.parse(content);
|
|
61
|
+
return parsed.claudeAiOauth?.accessToken || null;
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Check if we should fetch (throttled)
|
|
69
|
+
*/
|
|
70
|
+
function shouldFetch(isUserPrompt = false) {
|
|
71
|
+
const interval = isUserPrompt ? FETCH_INTERVAL_PROMPT_MS : FETCH_INTERVAL_MS;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
if (fs.existsSync(USAGE_CACHE_FILE)) {
|
|
75
|
+
const cache = JSON.parse(fs.readFileSync(USAGE_CACHE_FILE, "utf-8"));
|
|
76
|
+
if (Date.now() - cache.timestamp < interval) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} catch {}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Write cache with status (available or unavailable)
|
|
86
|
+
*/
|
|
87
|
+
function writeCache(status, data = null) {
|
|
88
|
+
fs.writeFileSync(
|
|
89
|
+
USAGE_CACHE_FILE,
|
|
90
|
+
JSON.stringify({
|
|
91
|
+
timestamp: Date.now(),
|
|
92
|
+
status,
|
|
93
|
+
data,
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Fetch usage limits from Anthropic OAuth API and write to cache
|
|
100
|
+
* Always writes status to cache (available or unavailable) for statusline fallback
|
|
101
|
+
*/
|
|
102
|
+
async function fetchAndCacheUsageLimits() {
|
|
103
|
+
const token = getClaudeCredentials();
|
|
104
|
+
if (!token) {
|
|
105
|
+
writeCache("unavailable");
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const response = await fetch("https://api.anthropic.com/api/oauth/usage", {
|
|
111
|
+
method: "GET",
|
|
112
|
+
headers: {
|
|
113
|
+
Accept: "application/json",
|
|
114
|
+
"Content-Type": "application/json",
|
|
115
|
+
Authorization: `Bearer ${token}`,
|
|
116
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
117
|
+
"User-Agent": "claudekit-engineer/1.0",
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
writeCache("unavailable");
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const data = await response.json();
|
|
127
|
+
writeCache("available", data);
|
|
128
|
+
return true;
|
|
129
|
+
} catch {
|
|
130
|
+
writeCache("unavailable");
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Main hook execution - just fetch and cache, no injection
|
|
137
|
+
*/
|
|
138
|
+
async function main() {
|
|
139
|
+
// Always allow operation to continue
|
|
140
|
+
const result = { continue: true };
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
// Read hook input
|
|
144
|
+
let inputStr = "";
|
|
145
|
+
try {
|
|
146
|
+
inputStr = fs.readFileSync(0, "utf-8");
|
|
147
|
+
} catch {}
|
|
148
|
+
|
|
149
|
+
const input = JSON.parse(inputStr || "{}");
|
|
150
|
+
|
|
151
|
+
// Detect hook type
|
|
152
|
+
const isUserPrompt = typeof input.prompt === "string";
|
|
153
|
+
|
|
154
|
+
// Check if we should fetch (throttled)
|
|
155
|
+
if (shouldFetch(isUserPrompt)) {
|
|
156
|
+
await fetchAndCacheUsageLimits();
|
|
157
|
+
}
|
|
158
|
+
} catch {}
|
|
159
|
+
|
|
160
|
+
// Output result (no injection, just continue)
|
|
161
|
+
console.log(JSON.stringify(result));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
main().catch(() => {
|
|
165
|
+
console.log(JSON.stringify({ continue: true }));
|
|
166
|
+
process.exit(0);
|
|
167
|
+
});
|
|
168
|
+
} catch (e) {
|
|
169
|
+
// Minimal crash logging (zero deps — only Node builtins)
|
|
170
|
+
try {
|
|
171
|
+
const fs = require('fs');
|
|
172
|
+
const p = require('path');
|
|
173
|
+
const logDir = p.join(__dirname, '.logs');
|
|
174
|
+
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
|
|
175
|
+
fs.appendFileSync(p.join(logDir, 'hook-log.jsonl'),
|
|
176
|
+
JSON.stringify({ ts: new Date().toISOString(), hook: p.basename(__filename, '.cjs'), status: 'crash', error: e.message }) + '\n');
|
|
177
|
+
} catch (_) {}
|
|
178
|
+
process.exit(0); // fail-open
|
|
179
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 2,
|
|
3
3
|
"scope": "claude-only",
|
|
4
4
|
"commands": {
|
|
5
5
|
"core": [
|
|
@@ -20,7 +20,14 @@
|
|
|
20
20
|
"skills": {
|
|
21
21
|
"required": [
|
|
22
22
|
"specs",
|
|
23
|
-
"impact-analysis"
|
|
23
|
+
"impact-analysis",
|
|
24
|
+
"spec-init",
|
|
25
|
+
"spec-requirements",
|
|
26
|
+
"spec-design",
|
|
27
|
+
"spec-tasks",
|
|
28
|
+
"code",
|
|
29
|
+
"test",
|
|
30
|
+
"review"
|
|
24
31
|
]
|
|
25
32
|
},
|
|
26
33
|
"agents": {
|
|
@@ -36,5 +43,23 @@
|
|
|
36
43
|
},
|
|
37
44
|
"hooks": {
|
|
38
45
|
"assumed": []
|
|
46
|
+
},
|
|
47
|
+
"runtime": {
|
|
48
|
+
"files": [
|
|
49
|
+
"status.cjs",
|
|
50
|
+
"hooks/session.cjs",
|
|
51
|
+
"hooks/agent.cjs",
|
|
52
|
+
"hooks/usage.cjs",
|
|
53
|
+
"hooks/lib/color.cjs",
|
|
54
|
+
"hooks/lib/parser.cjs",
|
|
55
|
+
"hooks/lib/counter.cjs",
|
|
56
|
+
"hooks/lib/git.cjs",
|
|
57
|
+
"hooks/lib/config.cjs",
|
|
58
|
+
"hooks/lib/context.cjs",
|
|
59
|
+
"hooks/lib/detect.cjs"
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
"settings": {
|
|
63
|
+
"template": "settings/status.settings.json"
|
|
39
64
|
}
|
|
40
65
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"statusLine": {
|
|
3
|
+
"type": "command",
|
|
4
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/status.cjs\"",
|
|
5
|
+
"padding": 0
|
|
6
|
+
},
|
|
7
|
+
"hooks": {
|
|
8
|
+
"SessionStart": [
|
|
9
|
+
{
|
|
10
|
+
"matcher": "startup|resume|clear|compact",
|
|
11
|
+
"hooks": [
|
|
12
|
+
{
|
|
13
|
+
"type": "command",
|
|
14
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/session.cjs\""
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"SubagentStart": [
|
|
20
|
+
{
|
|
21
|
+
"matcher": "*",
|
|
22
|
+
"hooks": [
|
|
23
|
+
{
|
|
24
|
+
"type": "command",
|
|
25
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/agent.cjs\""
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"UserPromptSubmit": [
|
|
31
|
+
{
|
|
32
|
+
"hooks": [
|
|
33
|
+
{
|
|
34
|
+
"type": "command",
|
|
35
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/usage.cjs\"",
|
|
36
|
+
"timeout": 30
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"PostToolUse": [
|
|
42
|
+
{
|
|
43
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
44
|
+
"hooks": [
|
|
45
|
+
{
|
|
46
|
+
"type": "command",
|
|
47
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/usage.cjs\"",
|
|
48
|
+
"timeout": 30
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|