aiblueprint-cli 1.4.81 → 1.4.82
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 +21 -17
- package/agents-config/claude-config/scripts/statusline/data/.gitignore +8 -0
- package/agents-config/claude-config/scripts/statusline/data/.gitkeep +0 -0
- package/agents-config/claude-config/scripts/statusline/defaults.json +10 -10
- package/agents-config/claude-config/scripts/statusline/src/commands/interactive-config.ts +118 -6
- package/agents-config/claude-config/scripts/statusline/src/index.ts +100 -9
- package/agents-config/claude-config/scripts/statusline/src/lib/config.ts +28 -2
- package/agents-config/claude-config/scripts/statusline/src/lib/features/limits/commands/weekly-analysis.ts +108 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/limits/index.ts +164 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/limits/types.ts +15 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/spend/commands/migrate-to-sqlite.ts +136 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/spend/commands/spend-day.ts +79 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/spend/commands/spend-month.ts +66 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/spend/commands/spend-project.ts +85 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/spend/database.ts +395 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/spend/index.ts +178 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/spend/payload-logger.ts +163 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/features/spend/types.ts +37 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/presets.ts +13 -13
- package/agents-config/claude-config/scripts/statusline/statusline.config.free.json +4 -1
- package/agents-config/claude-config/scripts/statusline/statusline.config.json +44 -23
- package/agents-config/scripts/statusline/data/.gitignore +8 -0
- package/agents-config/scripts/statusline/data/.gitkeep +0 -0
- package/agents-config/scripts/statusline/defaults.json +10 -10
- package/agents-config/scripts/statusline/src/commands/interactive-config.ts +118 -6
- package/agents-config/scripts/statusline/src/index.ts +100 -9
- package/agents-config/scripts/statusline/src/lib/config.ts +28 -2
- package/agents-config/scripts/statusline/src/lib/features/limits/commands/weekly-analysis.ts +108 -0
- package/agents-config/scripts/statusline/src/lib/features/limits/index.ts +164 -0
- package/agents-config/scripts/statusline/src/lib/features/limits/types.ts +15 -0
- package/agents-config/scripts/statusline/src/lib/features/spend/commands/migrate-to-sqlite.ts +136 -0
- package/agents-config/scripts/statusline/src/lib/features/spend/commands/spend-day.ts +79 -0
- package/agents-config/scripts/statusline/src/lib/features/spend/commands/spend-month.ts +66 -0
- package/agents-config/scripts/statusline/src/lib/features/spend/commands/spend-project.ts +85 -0
- package/agents-config/scripts/statusline/src/lib/features/spend/database.ts +395 -0
- package/agents-config/scripts/statusline/src/lib/features/spend/index.ts +178 -0
- package/agents-config/scripts/statusline/src/lib/features/spend/payload-logger.ts +163 -0
- package/agents-config/scripts/statusline/src/lib/features/spend/types.ts +37 -0
- package/agents-config/scripts/statusline/src/lib/presets.ts +13 -13
- package/agents-config/scripts/statusline/statusline.config.free.json +4 -1
- package/agents-config/scripts/statusline/statusline.config.json +44 -23
- package/agents-config/skills/agents-managers/SKILL.md +1 -1
- package/agents-config/skills/agents-managers/references/writing-agent-prompts.md +1 -1
- package/agents-config/{commands/prompts/create-vitejs-app.md → skills/create-vitejs-app/SKILL.md} +2 -1
- package/agents-config/skills/environments-manager/SKILL.md +6 -6
- package/agents-config/skills/environments-manager/examples/{claude/commands/dev.md → skills/dev/SKILL.md} +2 -1
- package/agents-config/skills/environments-manager/examples/{claude/commands/lint.md → skills/lint/SKILL.md} +2 -1
- package/agents-config/skills/environments-manager/examples/{claude/commands/test.md → skills/test/SKILL.md} +2 -1
- package/agents-config/skills/environments-manager/examples/{claude/commands/typecheck.md → skills/typecheck/SKILL.md} +2 -1
- package/agents-config/skills/environments-manager/references/claude.md +13 -9
- package/agents-config/skills/environments-manager/references/cursor.md +2 -2
- package/agents-config/{commands/prompts/nextjs-add-prisma-db.md → skills/nextjs-add-prisma-db/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/nextjs-setup-better-auth.md → skills/nextjs-setup-better-auth/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/nextjs-setup-project.md → skills/nextjs-setup-project/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/prompt.md → skills/prompt/SKILL.md} +5 -0
- package/agents-config/{commands/prompts/saas-challenge-idea.md → skills/saas-challenge-idea/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-create-architecture.md → skills/saas-create-architecture/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-create-headline.md → skills/saas-create-headline/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-create-landing-copywritting.md → skills/saas-create-landing-copywritting/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-create-legals-docs.md → skills/saas-create-legals-docs/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-create-logos.md → skills/saas-create-logos/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-create-prd.md → skills/saas-create-prd/SKILL.md} +4 -3
- package/agents-config/{commands/prompts/saas-create-tasks.md → skills/saas-create-tasks/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-define-pricing.md → skills/saas-define-pricing/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-find-domain-name.md → skills/saas-find-domain-name/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/saas-implement-landing-page.md → skills/saas-implement-landing-page/SKILL.md} +1 -0
- package/agents-config/{commands/prompts/setup-tmux.md → skills/setup-tmux/SKILL.md} +5 -0
- package/agents-config/{commands/prompts/tools.md → skills/tools/SKILL.md} +1 -0
- package/agents-config/skills/ultrathink/SKILL.md +1 -1
- package/agents-config/skills/use-style/SKILL.md +7 -4
- package/agents-config/skills/use-style/examples/luma.html +221 -0
- package/agents-config/skills/use-style/examples/testspirite.html +340 -0
- package/agents-config/skills/use-style/styles/ios-app.md +350 -0
- package/agents-config/skills/use-style/styles/luma.md +422 -0
- package/agents-config/skills/use-style/styles/new-york-times.md +1 -1
- package/agents-config/skills/use-style/styles/split-auth.md +2 -2
- package/agents-config/skills/use-style/styles/testspirite.md +397 -0
- package/dist/cli.js +17 -80
- package/package.json +1 -1
- package/agents-config/claude-config/scripts/.claude/commands/fix-on-my-computer.md +0 -87
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AIBlueprint CLI
|
|
2
2
|
|
|
3
|
-
Supercharge Claude Code with security hooks,
|
|
3
|
+
Supercharge Claude Code and Codex with security hooks, reusable skills, a lightweight statusline, and workflow automation.
|
|
4
4
|
|
|
5
5
|
📚 **[Full Documentation](https://codelynx.dev/docs)** | 🎯 [Premium Features](https://mlv.sh/claude-cli)
|
|
6
6
|
|
|
@@ -15,7 +15,7 @@ npx aiblueprint-cli@latest agents setup
|
|
|
15
15
|
|
|
16
16
|
- **🛡️ Security** - Command validation hooks blocking dangerous operations
|
|
17
17
|
- **📊 Statusline** - Git status and session context display
|
|
18
|
-
- **🤖
|
|
18
|
+
- **🤖 Skills** - 30+ reusable workflow skills
|
|
19
19
|
- **🎭 Agents** - 3 specialized AI agents for codebase exploration
|
|
20
20
|
- **⚡ Scripts** - Built-in statusline utilities
|
|
21
21
|
|
|
@@ -67,10 +67,6 @@ npx aiblueprint-cli@latest agents setup
|
|
|
67
67
|
# Add specific hooks
|
|
68
68
|
npx aiblueprint-cli@latest agents add hook post-edit-typescript
|
|
69
69
|
|
|
70
|
-
# Manage commands
|
|
71
|
-
npx aiblueprint-cli@latest agents add commands
|
|
72
|
-
npx aiblueprint-cli@latest agents add commands commit
|
|
73
|
-
|
|
74
70
|
# Create symlinks between tools
|
|
75
71
|
npx aiblueprint-cli@latest agents symlink
|
|
76
72
|
|
|
@@ -104,23 +100,26 @@ npx aiblueprint-cli@latest agents config unify sessions
|
|
|
104
100
|
- Session context and duration
|
|
105
101
|
- Colored visual indicators
|
|
106
102
|
|
|
107
|
-
###
|
|
103
|
+
### Workflow Skills
|
|
108
104
|
|
|
109
105
|
**Development:**
|
|
110
106
|
- `commit` - Fast conventional commits
|
|
111
|
-
- `create-
|
|
107
|
+
- `create-pr` - Auto-generated PRs
|
|
112
108
|
- `fix-pr-comments` - Resolve PR comments
|
|
113
|
-
- `
|
|
109
|
+
- `merge` - Context-aware branch merging
|
|
114
110
|
|
|
115
|
-
**
|
|
116
|
-
- `
|
|
117
|
-
- `
|
|
118
|
-
- `
|
|
111
|
+
**Project setup:**
|
|
112
|
+
- `nextjs-setup-project` - Scaffold the preferred Next.js stack
|
|
113
|
+
- `nextjs-add-prisma-db` - Add Prisma and PostgreSQL
|
|
114
|
+
- `nextjs-setup-better-auth` - Wire Better Auth with email OTP
|
|
115
|
+
- `create-vitejs-app` - Create a Vite app with Tailwind and shadcn/ui
|
|
119
116
|
|
|
120
|
-
**
|
|
121
|
-
- `
|
|
122
|
-
- `
|
|
123
|
-
- `
|
|
117
|
+
**SaaS planning:**
|
|
118
|
+
- `saas-create-prd` - Build a lean Product Requirements Document
|
|
119
|
+
- `saas-create-architecture` - Design technical architecture
|
|
120
|
+
- `saas-create-tasks` - Generate implementation tasks
|
|
121
|
+
- `saas-define-pricing` - Create pricing strategy
|
|
122
|
+
- `saas-find-domain-name` - Generate and validate domains
|
|
124
123
|
|
|
125
124
|
### Agents (3 Specialized)
|
|
126
125
|
|
|
@@ -158,6 +157,11 @@ npx skills add Melvynx/aiblueprint --skill skill-manager
|
|
|
158
157
|
| `merge` | Context-aware branch merging |
|
|
159
158
|
| `prompt-creator` | Expert prompt engineering |
|
|
160
159
|
| `skill-manager` | Manage skills and rules across Claude Code, Codex, and Cursor |
|
|
160
|
+
| `saas-create-prd` | Build a lean SaaS PRD |
|
|
161
|
+
| `saas-create-architecture` | Design SaaS technical architecture |
|
|
162
|
+
| `saas-create-tasks` | Generate implementation task files |
|
|
163
|
+
| `nextjs-setup-project` | Set up a production-ready Next.js project |
|
|
164
|
+
| `create-vitejs-app` | Create a Vite app with Tailwind and shadcn/ui |
|
|
161
165
|
| `use-style` | Apply named UI style guides before implementation |
|
|
162
166
|
| `rules-manager` | Create and maintain AGENTS.md and agent rule files |
|
|
163
167
|
| `agents-managers` | Manage Claude Code agents and Task-tool orchestration |
|
|
File without changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"features": {
|
|
3
|
-
"usageLimits":
|
|
4
|
-
"spendTracking":
|
|
3
|
+
"usageLimits": true,
|
|
4
|
+
"spendTracking": true
|
|
5
5
|
},
|
|
6
6
|
"oneLine": true,
|
|
7
7
|
"showSonnetModel": false,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"separator": "•",
|
|
18
18
|
"session": {
|
|
19
19
|
"infoSeparator": null,
|
|
20
|
-
"cost": { "enabled":
|
|
20
|
+
"cost": { "enabled": true, "format": "decimal1" },
|
|
21
21
|
"duration": { "enabled": true },
|
|
22
22
|
"tokens": { "enabled": true, "showMax": false, "showDecimals": false },
|
|
23
23
|
"percentage": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"overheadTokens": 0
|
|
41
41
|
},
|
|
42
42
|
"limits": {
|
|
43
|
-
"enabled":
|
|
44
|
-
"showTimeLeft":
|
|
45
|
-
"showPacingDelta":
|
|
43
|
+
"enabled": true,
|
|
44
|
+
"showTimeLeft": true,
|
|
45
|
+
"showPacingDelta": true,
|
|
46
46
|
"cost": { "enabled": false, "format": "decimal1" },
|
|
47
47
|
"percentage": {
|
|
48
48
|
"enabled": true,
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
"weeklyUsage": {
|
|
60
|
-
"enabled":
|
|
61
|
-
"showTimeLeft":
|
|
62
|
-
"showPacingDelta":
|
|
60
|
+
"enabled": "90%",
|
|
61
|
+
"showTimeLeft": true,
|
|
62
|
+
"showPacingDelta": true,
|
|
63
63
|
"cost": { "enabled": false, "format": "decimal1" },
|
|
64
64
|
"percentage": {
|
|
65
65
|
"enabled": true,
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
76
|
"dailySpend": {
|
|
77
|
-
"cost": { "enabled":
|
|
77
|
+
"cost": { "enabled": true, "format": "decimal1" }
|
|
78
78
|
},
|
|
79
79
|
"thinking": {
|
|
80
80
|
"showDisabledWarning": true
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
defaultConfig,
|
|
7
|
+
loadConfig as loadStatuslineConfig,
|
|
8
|
+
type StatuslineConfig,
|
|
9
|
+
} from "../lib/config";
|
|
6
10
|
import { colors } from "../lib/formatters";
|
|
7
11
|
import {
|
|
8
12
|
cycle,
|
|
@@ -161,6 +165,7 @@ const tabs: Tab[] = [
|
|
|
161
165
|
id: "session",
|
|
162
166
|
label: "SESSION",
|
|
163
167
|
options: [
|
|
168
|
+
toggle("session.cost.enabled", "Cost display"),
|
|
164
169
|
toggle("session.duration.enabled", "Duration"),
|
|
165
170
|
toggle("session.tokens.enabled", "Token count"),
|
|
166
171
|
toggle("session.tokens.showMax", " Show max", {
|
|
@@ -200,6 +205,116 @@ const tabs: Tab[] = [
|
|
|
200
205
|
toggle("context.useUsableContextOnly", "45k buffer"),
|
|
201
206
|
],
|
|
202
207
|
},
|
|
208
|
+
{
|
|
209
|
+
id: "limits",
|
|
210
|
+
label: "5-HOUR",
|
|
211
|
+
options: [
|
|
212
|
+
{
|
|
213
|
+
path: "limits.enabled",
|
|
214
|
+
label: "5-hour limit",
|
|
215
|
+
type: "cycle" as const,
|
|
216
|
+
choices: ["Enabled", "Disabled"],
|
|
217
|
+
getValue: (c) => (c.limits.enabled ? "Enabled" : "Disabled"),
|
|
218
|
+
cycle: (c) => {
|
|
219
|
+
c.limits.enabled = !c.limits.enabled;
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
toggle("limits.showTimeLeft", " Time remaining", {
|
|
223
|
+
hidden: (c) => !c.limits.enabled,
|
|
224
|
+
}),
|
|
225
|
+
toggle("limits.showPacingDelta", " Pacing delta", {
|
|
226
|
+
hidden: (c) => !c.limits.enabled,
|
|
227
|
+
}),
|
|
228
|
+
toggle("limits.cost.enabled", " Period cost", {
|
|
229
|
+
hidden: (c) => !c.limits.enabled,
|
|
230
|
+
}),
|
|
231
|
+
toggle("limits.percentage.showValue", " Show % value", {
|
|
232
|
+
hidden: (c) => !c.limits.enabled,
|
|
233
|
+
}),
|
|
234
|
+
progressStyleCycle("limits.percentage", (c) => !c.limits.enabled),
|
|
235
|
+
cycle(
|
|
236
|
+
"limits.percentage.progressBar.length",
|
|
237
|
+
" Length",
|
|
238
|
+
PROGRESS_BAR_LENGTHS,
|
|
239
|
+
{
|
|
240
|
+
hidden: (c) =>
|
|
241
|
+
!c.limits.enabled || !c.limits.percentage.progressBar.enabled,
|
|
242
|
+
},
|
|
243
|
+
),
|
|
244
|
+
cycle(
|
|
245
|
+
"limits.percentage.progressBar.color",
|
|
246
|
+
" Color",
|
|
247
|
+
PROGRESS_BAR_COLORS,
|
|
248
|
+
{
|
|
249
|
+
hidden: (c) =>
|
|
250
|
+
!c.limits.enabled || !c.limits.percentage.progressBar.enabled,
|
|
251
|
+
},
|
|
252
|
+
),
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
id: "weekly",
|
|
257
|
+
label: "WEEKLY",
|
|
258
|
+
options: [
|
|
259
|
+
{
|
|
260
|
+
path: "weeklyUsage.enabled",
|
|
261
|
+
label: "Weekly limit",
|
|
262
|
+
type: "cycle" as const,
|
|
263
|
+
choices: ["Always", "At 90%", "Never"],
|
|
264
|
+
getValue: (c) => {
|
|
265
|
+
if (c.weeklyUsage.enabled === true) return "Always";
|
|
266
|
+
if (c.weeklyUsage.enabled === "90%") return "At 90%";
|
|
267
|
+
return "Never";
|
|
268
|
+
},
|
|
269
|
+
cycle: (c, dir) => {
|
|
270
|
+
const modes = [true, "90%", false] as const;
|
|
271
|
+
const idx =
|
|
272
|
+
c.weeklyUsage.enabled === true
|
|
273
|
+
? 0
|
|
274
|
+
: c.weeklyUsage.enabled === "90%"
|
|
275
|
+
? 1
|
|
276
|
+
: 2;
|
|
277
|
+
c.weeklyUsage.enabled = modes[(idx + dir + 3) % 3];
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
toggle("weeklyUsage.showTimeLeft", " Time remaining", {
|
|
281
|
+
hidden: (c) => c.weeklyUsage.enabled === false,
|
|
282
|
+
}),
|
|
283
|
+
toggle("weeklyUsage.showPacingDelta", " Pacing delta", {
|
|
284
|
+
hidden: (c) => c.weeklyUsage.enabled === false,
|
|
285
|
+
}),
|
|
286
|
+
toggle("weeklyUsage.cost.enabled", " Cost", {
|
|
287
|
+
hidden: (c) => c.weeklyUsage.enabled === false,
|
|
288
|
+
}),
|
|
289
|
+
toggle("weeklyUsage.percentage.showValue", " Show % value", {
|
|
290
|
+
hidden: (c) => c.weeklyUsage.enabled === false,
|
|
291
|
+
}),
|
|
292
|
+
progressStyleCycle(
|
|
293
|
+
"weeklyUsage.percentage",
|
|
294
|
+
(c) => c.weeklyUsage.enabled === false,
|
|
295
|
+
),
|
|
296
|
+
cycle(
|
|
297
|
+
"weeklyUsage.percentage.progressBar.length",
|
|
298
|
+
" Length",
|
|
299
|
+
PROGRESS_BAR_LENGTHS,
|
|
300
|
+
{
|
|
301
|
+
hidden: (c) =>
|
|
302
|
+
c.weeklyUsage.enabled === false ||
|
|
303
|
+
!c.weeklyUsage.percentage.progressBar.enabled,
|
|
304
|
+
},
|
|
305
|
+
),
|
|
306
|
+
cycle(
|
|
307
|
+
"weeklyUsage.percentage.progressBar.color",
|
|
308
|
+
" Color",
|
|
309
|
+
PROGRESS_BAR_COLORS,
|
|
310
|
+
{
|
|
311
|
+
hidden: (c) =>
|
|
312
|
+
c.weeklyUsage.enabled === false ||
|
|
313
|
+
!c.weeklyUsage.percentage.progressBar.enabled,
|
|
314
|
+
},
|
|
315
|
+
),
|
|
316
|
+
],
|
|
317
|
+
},
|
|
203
318
|
{
|
|
204
319
|
id: "git",
|
|
205
320
|
label: "GIT",
|
|
@@ -239,6 +354,7 @@ const tabs: Tab[] = [
|
|
|
239
354
|
cycle("pathDisplayMode", "Path display", PATH_DISPLAY_MODES),
|
|
240
355
|
toggle("showSonnetModel", "Show Sonnet model"),
|
|
241
356
|
toggle("oneLine", "Single line mode"),
|
|
357
|
+
toggle("dailySpend.cost.enabled", "Daily spend"),
|
|
242
358
|
],
|
|
243
359
|
},
|
|
244
360
|
];
|
|
@@ -248,11 +364,7 @@ const tabs: Tab[] = [
|
|
|
248
364
|
// ─────────────────────────────────────────────────────────────
|
|
249
365
|
|
|
250
366
|
function loadConfig(): StatuslineConfig {
|
|
251
|
-
|
|
252
|
-
return JSON.parse(readFileSync(CONFIG_FILE_PATH, "utf-8"));
|
|
253
|
-
} catch {
|
|
254
|
-
return JSON.parse(JSON.stringify(defaultConfig));
|
|
255
|
-
}
|
|
367
|
+
return loadStatuslineConfig();
|
|
256
368
|
}
|
|
257
369
|
|
|
258
370
|
function saveConfig(config: StatuslineConfig): void {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
loadConfig as loadStatuslineConfig,
|
|
7
|
+
type StatuslineConfig,
|
|
8
|
+
} from "./lib/config";
|
|
6
9
|
import { getContextData } from "./lib/context";
|
|
7
10
|
import {
|
|
8
11
|
colors,
|
|
@@ -19,6 +22,45 @@ import {
|
|
|
19
22
|
} from "./lib/render-pure";
|
|
20
23
|
import type { HookInput } from "./lib/types";
|
|
21
24
|
|
|
25
|
+
// Optional feature imports - just delete the folder to disable!
|
|
26
|
+
let getUsageLimits: any = null;
|
|
27
|
+
let normalizeResetsAt: any = null;
|
|
28
|
+
let getPeriodCost: any = null;
|
|
29
|
+
let getTodayCostV2: any = null;
|
|
30
|
+
let saveSessionV2: any = null;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const limitsModule = await import("./lib/features/limits");
|
|
34
|
+
getUsageLimits = limitsModule.getUsageLimits;
|
|
35
|
+
} catch {
|
|
36
|
+
// Limits feature not available - that's OK!
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const utilsModule = await import("./lib/utils");
|
|
41
|
+
normalizeResetsAt = utilsModule.normalizeResetsAt;
|
|
42
|
+
} catch {
|
|
43
|
+
// Fallback normalizeResetsAt
|
|
44
|
+
normalizeResetsAt = (resetsAt: string) => resetsAt;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let getTodayRealCost: (() => number) | null = null;
|
|
48
|
+
try {
|
|
49
|
+
const spendModule = await import("./lib/features/spend");
|
|
50
|
+
getPeriodCost = spendModule.getPeriodCost;
|
|
51
|
+
getTodayCostV2 = spendModule.getTodayCostV2;
|
|
52
|
+
saveSessionV2 = spendModule.saveSessionV2;
|
|
53
|
+
} catch {
|
|
54
|
+
// Spend tracking feature not available - that's OK!
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const loggerModule = await import("./lib/features/spend/payload-logger");
|
|
59
|
+
getTodayRealCost = loggerModule.getTodayRealCost;
|
|
60
|
+
} catch {
|
|
61
|
+
// Payload logger not available
|
|
62
|
+
}
|
|
63
|
+
|
|
22
64
|
// Re-export from render-pure for backwards compatibility
|
|
23
65
|
export {
|
|
24
66
|
renderStatusline,
|
|
@@ -26,7 +68,12 @@ export {
|
|
|
26
68
|
type UsageLimit,
|
|
27
69
|
} from "./lib/render-pure";
|
|
28
70
|
|
|
29
|
-
const
|
|
71
|
+
const LAST_PAYLOAD_PATH = join(
|
|
72
|
+
import.meta.dir,
|
|
73
|
+
"..",
|
|
74
|
+
"data",
|
|
75
|
+
"last_payload.txt",
|
|
76
|
+
);
|
|
30
77
|
const CLAUDE_SETTINGS_PATH = join(
|
|
31
78
|
process.env.HOME || "",
|
|
32
79
|
".claude",
|
|
@@ -48,21 +95,30 @@ async function loadClaudeSettings(): Promise<ClaudeSettings> {
|
|
|
48
95
|
}
|
|
49
96
|
|
|
50
97
|
async function loadConfig(): Promise<StatuslineConfig> {
|
|
51
|
-
|
|
52
|
-
const content = await readFile(CONFIG_FILE_PATH, "utf-8");
|
|
53
|
-
return JSON.parse(content);
|
|
54
|
-
} catch {
|
|
55
|
-
return defaultConfig;
|
|
56
|
-
}
|
|
98
|
+
return loadStatuslineConfig();
|
|
57
99
|
}
|
|
58
100
|
|
|
59
101
|
async function main() {
|
|
60
102
|
try {
|
|
61
103
|
const input: HookInput = await Bun.stdin.json();
|
|
62
104
|
|
|
105
|
+
// Save last payload for debugging
|
|
106
|
+
await writeFile(LAST_PAYLOAD_PATH, JSON.stringify(input, null, 2));
|
|
107
|
+
|
|
63
108
|
const config = await loadConfig();
|
|
64
109
|
const claudeSettings = await loadClaudeSettings();
|
|
65
110
|
|
|
111
|
+
// Get usage limits (if feature exists)
|
|
112
|
+
const usageLimits = getUsageLimits
|
|
113
|
+
? await getUsageLimits()
|
|
114
|
+
: { five_hour: null, seven_day: null };
|
|
115
|
+
const currentResetsAt = usageLimits.five_hour?.resets_at ?? undefined;
|
|
116
|
+
|
|
117
|
+
// Save session with current period context (if feature exists)
|
|
118
|
+
if (saveSessionV2) {
|
|
119
|
+
await saveSessionV2(input, currentResetsAt);
|
|
120
|
+
}
|
|
121
|
+
|
|
66
122
|
const git = await getGitStatus();
|
|
67
123
|
|
|
68
124
|
let contextTokens: number | null;
|
|
@@ -102,6 +158,24 @@ async function main() {
|
|
|
102
158
|
contextPercentage = contextData.percentage;
|
|
103
159
|
}
|
|
104
160
|
|
|
161
|
+
// Get period cost from SQLite (if feature exists)
|
|
162
|
+
let periodCost: number | undefined;
|
|
163
|
+
let todayCost: number | undefined;
|
|
164
|
+
|
|
165
|
+
if (getPeriodCost && normalizeResetsAt) {
|
|
166
|
+
const normalizedPeriodId = currentResetsAt
|
|
167
|
+
? normalizeResetsAt(currentResetsAt)
|
|
168
|
+
: null;
|
|
169
|
+
periodCost = normalizedPeriodId ? getPeriodCost(normalizedPeriodId) : 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Get today's cost from payloads (more accurate than DB)
|
|
173
|
+
if (getTodayRealCost) {
|
|
174
|
+
todayCost = getTodayRealCost();
|
|
175
|
+
} else if (getTodayCostV2) {
|
|
176
|
+
todayCost = getTodayCostV2();
|
|
177
|
+
}
|
|
178
|
+
|
|
105
179
|
const data: StatuslineData = {
|
|
106
180
|
branch: formatBranch(git, config.git),
|
|
107
181
|
dirPath: formatPath(input.workspace.current_dir, config.pathDisplayMode),
|
|
@@ -121,6 +195,23 @@ async function main() {
|
|
|
121
195
|
sessionDuration: formatDuration(input.cost.total_duration_ms),
|
|
122
196
|
contextTokens,
|
|
123
197
|
contextPercentage,
|
|
198
|
+
...(getUsageLimits && {
|
|
199
|
+
usageLimits: {
|
|
200
|
+
five_hour: usageLimits.five_hour
|
|
201
|
+
? {
|
|
202
|
+
utilization: usageLimits.five_hour.utilization,
|
|
203
|
+
resets_at: usageLimits.five_hour.resets_at,
|
|
204
|
+
}
|
|
205
|
+
: null,
|
|
206
|
+
seven_day: usageLimits.seven_day
|
|
207
|
+
? {
|
|
208
|
+
utilization: usageLimits.seven_day.utilization,
|
|
209
|
+
resets_at: usageLimits.seven_day.resets_at,
|
|
210
|
+
}
|
|
211
|
+
: null,
|
|
212
|
+
},
|
|
213
|
+
}),
|
|
214
|
+
...((getPeriodCost || getTodayCostV2) && { periodCost, todayCost }),
|
|
124
215
|
thinkingEnabled: claudeSettings.alwaysThinkingEnabled ?? true,
|
|
125
216
|
};
|
|
126
217
|
|
|
@@ -10,11 +10,37 @@ export const defaultConfig: StatuslineConfig = JSON.parse(
|
|
|
10
10
|
readFileSync(DEFAULTS_PATH, "utf-8"),
|
|
11
11
|
);
|
|
12
12
|
|
|
13
|
+
function cloneDefaultConfig(): StatuslineConfig {
|
|
14
|
+
return JSON.parse(JSON.stringify(defaultConfig));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
18
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function mergeConfigDefaults<T>(defaults: T, overrides: unknown): T {
|
|
22
|
+
if (!isRecord(defaults) || !isRecord(overrides)) {
|
|
23
|
+
return overrides === undefined ? defaults : (overrides as T);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const merged: Record<string, unknown> = { ...defaults };
|
|
27
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
28
|
+
merged[key] = mergeConfigDefaults(
|
|
29
|
+
(defaults as Record<string, unknown>)[key],
|
|
30
|
+
value,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return merged as T;
|
|
34
|
+
}
|
|
35
|
+
|
|
13
36
|
export function loadConfig(): StatuslineConfig {
|
|
14
37
|
try {
|
|
15
|
-
return
|
|
38
|
+
return mergeConfigDefaults(
|
|
39
|
+
defaultConfig,
|
|
40
|
+
JSON.parse(readFileSync(CONFIG_PATH, "utf-8")),
|
|
41
|
+
);
|
|
16
42
|
} catch {
|
|
17
|
-
return
|
|
43
|
+
return cloneDefaultConfig();
|
|
18
44
|
}
|
|
19
45
|
}
|
|
20
46
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { colors, formatProgressBar } from "../../../formatters";
|
|
4
|
+
import { getUsageLimits } from "../index";
|
|
5
|
+
|
|
6
|
+
const WEEKLY_HOURS = 168; // 7 days * 24 hours
|
|
7
|
+
|
|
8
|
+
function calculateTimeProgress(resetsAt: string | null): {
|
|
9
|
+
hoursRemaining: number;
|
|
10
|
+
hoursElapsed: number;
|
|
11
|
+
timeElapsedPercent: number;
|
|
12
|
+
} {
|
|
13
|
+
if (!resetsAt) {
|
|
14
|
+
return {
|
|
15
|
+
hoursRemaining: 0,
|
|
16
|
+
hoursElapsed: WEEKLY_HOURS,
|
|
17
|
+
timeElapsedPercent: 100,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const resetDate = new Date(resetsAt);
|
|
22
|
+
const now = new Date();
|
|
23
|
+
const diffMs = resetDate.getTime() - now.getTime();
|
|
24
|
+
const hoursRemaining = Math.max(0, diffMs / 3600000);
|
|
25
|
+
const hoursElapsed = WEEKLY_HOURS - hoursRemaining;
|
|
26
|
+
const timeElapsedPercent = (hoursElapsed / WEEKLY_HOURS) * 100;
|
|
27
|
+
|
|
28
|
+
return { hoursRemaining, hoursElapsed, timeElapsedPercent };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function formatDelta(delta: number): string {
|
|
32
|
+
const sign = delta >= 0 ? "+" : "";
|
|
33
|
+
const value = `${sign}${delta.toFixed(1)}%`;
|
|
34
|
+
|
|
35
|
+
if (delta > 5) return colors.green(value);
|
|
36
|
+
if (delta > 0) return colors.lightGray(value);
|
|
37
|
+
if (delta > -5) return colors.yellow(value);
|
|
38
|
+
if (delta > -15) return colors.orange(value);
|
|
39
|
+
return colors.red(value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function main() {
|
|
43
|
+
const limits = await getUsageLimits();
|
|
44
|
+
|
|
45
|
+
console.log("");
|
|
46
|
+
console.log(colors.bold("📊 Weekly Usage Analysis"));
|
|
47
|
+
console.log(colors.gray("─".repeat(40)));
|
|
48
|
+
|
|
49
|
+
if (!limits.seven_day) {
|
|
50
|
+
console.log(colors.red("No weekly limit data available"));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const { utilization, resets_at } = limits.seven_day;
|
|
55
|
+
const { timeElapsedPercent } = calculateTimeProgress(resets_at);
|
|
56
|
+
|
|
57
|
+
const expectedUsage = timeElapsedPercent;
|
|
58
|
+
const delta = utilization - expectedUsage;
|
|
59
|
+
|
|
60
|
+
console.log("");
|
|
61
|
+
console.log(colors.gray("Weekly Limits Overview"));
|
|
62
|
+
console.log(colors.gray("─".repeat(50)));
|
|
63
|
+
console.log("");
|
|
64
|
+
|
|
65
|
+
const usageBar = formatProgressBar({
|
|
66
|
+
percentage: utilization,
|
|
67
|
+
length: 20,
|
|
68
|
+
style: "filled",
|
|
69
|
+
colorMode: "blue",
|
|
70
|
+
background: "none",
|
|
71
|
+
});
|
|
72
|
+
console.log(
|
|
73
|
+
`${colors.blue("Usage")} ${usageBar} ${colors.lightGray(utilization.toFixed(1))}${colors.gray("%")}`,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const timeBar = formatProgressBar({
|
|
77
|
+
percentage: timeElapsedPercent,
|
|
78
|
+
length: 20,
|
|
79
|
+
style: "filled",
|
|
80
|
+
colorMode: "purple",
|
|
81
|
+
background: "none",
|
|
82
|
+
});
|
|
83
|
+
console.log(
|
|
84
|
+
`${colors.purple("Time ")} ${timeBar} ${colors.lightGray(timeElapsedPercent.toFixed(1))}${colors.gray("%")} ${colors.gray("·")} ${formatDelta(delta)}`,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
console.log("");
|
|
88
|
+
console.log(colors.gray("─".repeat(50)));
|
|
89
|
+
console.log("");
|
|
90
|
+
|
|
91
|
+
if (limits.five_hour) {
|
|
92
|
+
console.log(colors.gray("─".repeat(40)));
|
|
93
|
+
console.log("");
|
|
94
|
+
console.log(colors.gray("Session Limit (5h):"));
|
|
95
|
+
console.log(
|
|
96
|
+
` ${formatProgressBar({
|
|
97
|
+
percentage: limits.five_hour.utilization,
|
|
98
|
+
length: 15,
|
|
99
|
+
style: "filled",
|
|
100
|
+
colorMode: "progressive",
|
|
101
|
+
background: "none",
|
|
102
|
+
})} ${colors.lightGray(limits.five_hour.utilization.toString())}${colors.gray("%")}`,
|
|
103
|
+
);
|
|
104
|
+
console.log("");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
main();
|