aiblueprint-cli 1.4.59 → 1.4.61

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.
Files changed (184) hide show
  1. package/README.md +16 -36
  2. package/agents-config/agents/action.md +1 -1
  3. package/agents-config/agents/explore-codebase.md +53 -53
  4. package/agents-config/agents/explore-docs.md +50 -69
  5. package/agents-config/agents/websearch.md +36 -40
  6. package/agents-config/claude-config/scripts/.claude/skills/fix-on-my-computer/SKILL.md +81 -0
  7. package/agents-config/claude-config/scripts/CLAUDE.md +10 -4
  8. package/agents-config/claude-config/scripts/bun.lockb +0 -0
  9. package/agents-config/claude-config/scripts/package.json +22 -30
  10. package/agents-config/claude-config/scripts/statusline/CLAUDE.md +37 -155
  11. package/agents-config/claude-config/scripts/statusline/README.md +18 -94
  12. package/agents-config/claude-config/scripts/statusline/defaults.json +13 -10
  13. package/agents-config/claude-config/scripts/statusline/fixtures/mock-transcript.jsonl +4 -4
  14. package/agents-config/claude-config/scripts/statusline/fixtures/test-input.json +4 -4
  15. package/agents-config/claude-config/scripts/statusline/src/commands/interactive-config.ts +403 -0
  16. package/agents-config/claude-config/scripts/statusline/src/index.ts +33 -82
  17. package/agents-config/claude-config/scripts/statusline/src/lib/config-types.ts +7 -1
  18. package/agents-config/claude-config/scripts/statusline/src/lib/formatters.ts +40 -0
  19. package/agents-config/claude-config/scripts/statusline/src/lib/presets.ts +13 -13
  20. package/agents-config/claude-config/scripts/statusline/src/lib/render-pure.ts +24 -5
  21. package/agents-config/claude-config/scripts/statusline/statusline.config.free.json +79 -0
  22. package/agents-config/claude-config/scripts/statusline/statusline.config.json +77 -77
  23. package/agents-config/codex-config/config.toml +9 -0
  24. package/agents-config/codex-config/hooks/command-deny-list.ts +203 -0
  25. package/agents-config/commands/prompts/create-vitejs-app.md +272 -0
  26. package/agents-config/commands/prompts/nextjs-add-prisma-db.md +136 -0
  27. package/agents-config/commands/prompts/nextjs-setup-better-auth.md +173 -0
  28. package/agents-config/commands/prompts/nextjs-setup-project.md +200 -0
  29. package/agents-config/commands/prompts/prompt.md +55 -0
  30. package/agents-config/commands/prompts/saas-challenge-idea.md +135 -0
  31. package/agents-config/commands/prompts/saas-create-architecture.md +242 -0
  32. package/agents-config/commands/prompts/saas-create-headline.md +132 -0
  33. package/agents-config/commands/prompts/saas-create-landing-copywritting.md +267 -0
  34. package/agents-config/commands/prompts/saas-create-legals-docs.md +176 -0
  35. package/agents-config/commands/prompts/saas-create-logos.md +240 -0
  36. package/agents-config/commands/prompts/saas-create-prd.md +195 -0
  37. package/agents-config/commands/prompts/saas-create-tasks.md +240 -0
  38. package/agents-config/commands/prompts/saas-define-pricing.md +293 -0
  39. package/agents-config/commands/prompts/saas-find-domain-name.md +190 -0
  40. package/agents-config/commands/prompts/saas-implement-landing-page.md +257 -0
  41. package/agents-config/commands/prompts/setup-tmux.md +160 -0
  42. package/agents-config/commands/prompts/tools.md +148 -0
  43. package/agents-config/scripts/.claude/skills/fix-on-my-computer/SKILL.md +81 -0
  44. package/agents-config/scripts/CLAUDE.md +37 -0
  45. package/agents-config/scripts/biome.json +37 -0
  46. package/agents-config/scripts/bun.lockb +0 -0
  47. package/agents-config/scripts/package.json +24 -0
  48. package/agents-config/scripts/statusline/CLAUDE.md +87 -0
  49. package/agents-config/scripts/statusline/README.md +117 -0
  50. package/agents-config/scripts/statusline/__tests__/context.test.ts +229 -0
  51. package/agents-config/scripts/statusline/__tests__/formatters.test.ts +108 -0
  52. package/agents-config/scripts/statusline/__tests__/statusline.test.ts +309 -0
  53. package/agents-config/scripts/statusline/defaults.json +82 -0
  54. package/agents-config/scripts/statusline/fixtures/mock-transcript.jsonl +4 -0
  55. package/agents-config/scripts/statusline/fixtures/test-input.json +35 -0
  56. package/agents-config/scripts/statusline/src/commands/interactive-config.ts +403 -0
  57. package/agents-config/scripts/statusline/src/index.ts +141 -0
  58. package/agents-config/scripts/statusline/src/lib/config-types.ts +110 -0
  59. package/agents-config/scripts/statusline/src/lib/config.ts +21 -0
  60. package/agents-config/scripts/statusline/src/lib/context.ts +103 -0
  61. package/agents-config/scripts/statusline/src/lib/formatters.ts +426 -0
  62. package/agents-config/scripts/statusline/src/lib/git.ts +100 -0
  63. package/agents-config/scripts/statusline/src/lib/menu-factories.ts +224 -0
  64. package/agents-config/scripts/statusline/src/lib/presets.ts +177 -0
  65. package/agents-config/scripts/statusline/src/lib/render-pure.ts +516 -0
  66. package/agents-config/scripts/statusline/src/lib/types.ts +36 -0
  67. package/agents-config/scripts/statusline/src/lib/utils.ts +15 -0
  68. package/agents-config/scripts/statusline/statusline.config.free.json +79 -0
  69. package/agents-config/scripts/statusline/statusline.config.json +79 -0
  70. package/agents-config/scripts/statusline/test-with-fixtures.ts +37 -0
  71. package/agents-config/scripts/statusline/test.ts +20 -0
  72. package/agents-config/scripts/statusline/tsconfig.json +27 -0
  73. package/agents-config/scripts/tsconfig.json +27 -0
  74. package/agents-config/skills/{subagent-creator → agents-managers}/SKILL.md +47 -47
  75. package/agents-config/skills/{subagent-creator/references/subagents.md → agents-managers/references/agents.md} +45 -45
  76. package/agents-config/skills/{subagent-creator → agents-managers}/references/context-management.md +20 -20
  77. package/agents-config/skills/{subagent-creator → agents-managers}/references/debugging-agents.md +27 -27
  78. package/agents-config/skills/{subagent-creator → agents-managers}/references/error-handling-and-recovery.md +19 -19
  79. package/agents-config/skills/{subagent-creator → agents-managers}/references/evaluation-and-testing.md +29 -29
  80. package/agents-config/skills/{subagent-creator → agents-managers}/references/orchestration-patterns.md +5 -5
  81. package/agents-config/skills/{subagent-creator/references/writing-subagent-prompts.md → agents-managers/references/writing-agent-prompts.md} +23 -23
  82. package/agents-config/skills/codex-environment/SKILL.md +2 -0
  83. package/agents-config/skills/commit/SKILL.md +2 -0
  84. package/agents-config/skills/create-pr/SKILL.md +2 -0
  85. package/agents-config/skills/environments-manager/SKILL.md +271 -0
  86. package/agents-config/skills/environments-manager/examples/claude/.worktreeinclude +3 -0
  87. package/agents-config/skills/environments-manager/examples/claude/commands/dev.md +5 -0
  88. package/agents-config/skills/environments-manager/examples/claude/commands/lint.md +5 -0
  89. package/agents-config/skills/environments-manager/examples/claude/commands/test.md +5 -0
  90. package/agents-config/skills/environments-manager/examples/claude/commands/typecheck.md +5 -0
  91. package/agents-config/skills/environments-manager/examples/claude/settings.json +24 -0
  92. package/agents-config/skills/environments-manager/examples/codex/environments/environment.toml +29 -0
  93. package/agents-config/skills/environments-manager/examples/cursor/worktrees.json +3 -0
  94. package/agents-config/skills/environments-manager/examples/scripts/claude-worktree-create.sh +96 -0
  95. package/agents-config/skills/environments-manager/examples/scripts/claude-worktree-remove.sh +66 -0
  96. package/agents-config/skills/environments-manager/examples/scripts/dev.sh +15 -0
  97. package/agents-config/skills/environments-manager/examples/scripts/worktree-down.sh +22 -0
  98. package/agents-config/skills/environments-manager/examples/scripts/worktree-up.sh +50 -0
  99. package/agents-config/skills/environments-manager/references/claude.md +156 -0
  100. package/agents-config/skills/environments-manager/references/codex.md +97 -0
  101. package/agents-config/skills/environments-manager/references/cursor.md +88 -0
  102. package/agents-config/skills/fix-pr-comments/SKILL.md +2 -0
  103. package/agents-config/skills/grill-me/SKILL.md +10 -0
  104. package/agents-config/skills/merge/SKILL.md +2 -0
  105. package/agents-config/skills/rules-manager/SKILL.md +191 -0
  106. package/agents-config/skills/rules-manager/references/agents-vs-claude.md +66 -0
  107. package/agents-config/skills/rules-manager/references/examples.md +117 -0
  108. package/agents-config/skills/skill-manager/SKILL.md +101 -0
  109. package/agents-config/skills/skill-manager/references/claude-code.md +81 -0
  110. package/agents-config/skills/skill-manager/references/codex.md +288 -0
  111. package/agents-config/skills/skill-manager/references/cursor.md +125 -0
  112. package/agents-config/skills/skill-manager/references/description-recommandation.md +97 -0
  113. package/agents-config/skills/skill-manager/scripts/inspect-description.ts +743 -0
  114. package/agents-config/skills/ultrathink/SKILL.md +2 -0
  115. package/dist/cli.js +581 -299
  116. package/package.json +1 -1
  117. package/agents-config/claude-config/scripts/statusline/data/.gitignore +0 -8
  118. package/agents-config/claude-config/scripts/statusline/data/.gitkeep +0 -0
  119. package/agents-config/claude-config/scripts/statusline/docs/ARCHITECTURE.md +0 -166
  120. package/agents-config/claude-config/scripts/statusline/src/tests/spend-v2.test.ts +0 -306
  121. package/agents-config/skills/apex/SKILL.md +0 -261
  122. package/agents-config/skills/apex/scripts/setup-templates.sh +0 -100
  123. package/agents-config/skills/apex/scripts/update-progress.sh +0 -80
  124. package/agents-config/skills/apex/steps/step-00-init.md +0 -267
  125. package/agents-config/skills/apex/steps/step-00b-branch.md +0 -126
  126. package/agents-config/skills/apex/steps/step-00b-economy.md +0 -244
  127. package/agents-config/skills/apex/steps/step-00b-interactive.md +0 -153
  128. package/agents-config/skills/apex/steps/step-01-analyze.md +0 -361
  129. package/agents-config/skills/apex/steps/step-02-plan.md +0 -264
  130. package/agents-config/skills/apex/steps/step-03-execute.md +0 -239
  131. package/agents-config/skills/apex/steps/step-04-validate.md +0 -251
  132. package/agents-config/skills/apex/templates/00-context.md +0 -43
  133. package/agents-config/skills/apex/templates/01-analyze.md +0 -10
  134. package/agents-config/skills/apex/templates/02-plan.md +0 -10
  135. package/agents-config/skills/apex/templates/03-execute.md +0 -10
  136. package/agents-config/skills/apex/templates/04-validate.md +0 -10
  137. package/agents-config/skills/apex/templates/README.md +0 -176
  138. package/agents-config/skills/apex/templates/step-complete.md +0 -7
  139. package/agents-config/skills/claude-memory/SKILL.md +0 -293
  140. package/agents-config/skills/claude-memory/references/comprehensive-example.md +0 -175
  141. package/agents-config/skills/claude-memory/references/optimize-guide.md +0 -300
  142. package/agents-config/skills/claude-memory/references/project-patterns.md +0 -334
  143. package/agents-config/skills/claude-memory/references/prompting-techniques.md +0 -411
  144. package/agents-config/skills/claude-memory/references/rules-directory-guide.md +0 -298
  145. package/agents-config/skills/claude-memory/references/section-templates.md +0 -347
  146. package/agents-config/skills/fix-errors/SKILL.md +0 -61
  147. package/agents-config/skills/fix-grammar/SKILL.md +0 -59
  148. package/agents-config/skills/ralph-loop/SKILL.md +0 -117
  149. package/agents-config/skills/ralph-loop/scripts/setup.sh +0 -278
  150. package/agents-config/skills/ralph-loop/steps/step-00-init.md +0 -215
  151. package/agents-config/skills/ralph-loop/steps/step-01-interactive-prd.md +0 -366
  152. package/agents-config/skills/ralph-loop/steps/step-02-create-stories.md +0 -273
  153. package/agents-config/skills/ralph-loop/steps/step-03-finish.md +0 -245
  154. package/agents-config/skills/skill-creator/LICENSE.txt +0 -202
  155. package/agents-config/skills/skill-creator/SKILL.md +0 -421
  156. package/agents-config/skills/skill-creator/package.json +0 -5
  157. package/agents-config/skills/skill-creator/references/output-patterns.md +0 -82
  158. package/agents-config/skills/skill-creator/references/progressive-disclosure-patterns.md +0 -374
  159. package/agents-config/skills/skill-creator/references/prompting-integration.md +0 -363
  160. package/agents-config/skills/skill-creator/references/real-world-examples.md +0 -513
  161. package/agents-config/skills/skill-creator/references/script-patterns.md +0 -385
  162. package/agents-config/skills/skill-creator/references/workflows.md +0 -28
  163. package/agents-config/skills/skill-creator/references/xml-tag-guide.md +0 -606
  164. package/agents-config/skills/skill-creator/scripts/init-skill.ts +0 -214
  165. package/agents-config/skills/skill-creator/scripts/package-skill.ts +0 -146
  166. package/agents-config/skills/skill-creator/scripts/validate.ts +0 -138
  167. package/agents-config/skills/workflow-apex-free/SKILL.md +0 -261
  168. package/agents-config/skills/workflow-apex-free/scripts/setup-templates.sh +0 -100
  169. package/agents-config/skills/workflow-apex-free/scripts/update-progress.sh +0 -80
  170. package/agents-config/skills/workflow-apex-free/steps/step-00-init.md +0 -267
  171. package/agents-config/skills/workflow-apex-free/steps/step-00b-branch.md +0 -126
  172. package/agents-config/skills/workflow-apex-free/steps/step-00b-economy.md +0 -244
  173. package/agents-config/skills/workflow-apex-free/steps/step-00b-interactive.md +0 -153
  174. package/agents-config/skills/workflow-apex-free/steps/step-01-analyze.md +0 -361
  175. package/agents-config/skills/workflow-apex-free/steps/step-02-plan.md +0 -264
  176. package/agents-config/skills/workflow-apex-free/steps/step-03-execute.md +0 -239
  177. package/agents-config/skills/workflow-apex-free/steps/step-04-validate.md +0 -251
  178. package/agents-config/skills/workflow-apex-free/templates/00-context.md +0 -43
  179. package/agents-config/skills/workflow-apex-free/templates/01-analyze.md +0 -10
  180. package/agents-config/skills/workflow-apex-free/templates/02-plan.md +0 -10
  181. package/agents-config/skills/workflow-apex-free/templates/03-execute.md +0 -10
  182. package/agents-config/skills/workflow-apex-free/templates/04-validate.md +0 -10
  183. package/agents-config/skills/workflow-apex-free/templates/README.md +0 -176
  184. package/agents-config/skills/workflow-apex-free/templates/step-complete.md +0 -7
@@ -0,0 +1,403 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { readFileSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { defaultConfig, type StatuslineConfig } from "../lib/config";
6
+ import { colors } from "../lib/formatters";
7
+ import {
8
+ cycle,
9
+ type MenuOption,
10
+ PATH_DISPLAY_MODES,
11
+ PROGRESS_BAR_COLORS,
12
+ PROGRESS_BAR_LENGTHS,
13
+ SEPARATORS,
14
+ toggle,
15
+ } from "../lib/menu-factories";
16
+ import { PRESETS } from "../lib/presets";
17
+ import {
18
+ type RawStatuslineData,
19
+ renderStatuslineRaw,
20
+ } from "../lib/render-pure";
21
+
22
+ const CONFIG_FILE_PATH = join(
23
+ import.meta.dir,
24
+ "..",
25
+ "..",
26
+ "statusline.config.json",
27
+ );
28
+
29
+ // ─────────────────────────────────────────────────────────────
30
+ // RAW MOCK DATA
31
+ // ─────────────────────────────────────────────────────────────
32
+
33
+ const MOCK_DATA: RawStatuslineData = {
34
+ git: {
35
+ branch: "main",
36
+ dirty: true,
37
+ staged: { files: 2, added: 45, deleted: 12 },
38
+ unstaged: { files: 3, added: 23, deleted: 8 },
39
+ },
40
+ path: "/Users/dev/.claude/project",
41
+ modelName: "Sonnet 4.5",
42
+ cost: 0.24,
43
+ durationMs: 720000,
44
+ contextTokens: 75000,
45
+ contextPercentage: 38,
46
+ usageLimits: {
47
+ five_hour: {
48
+ utilization: 29,
49
+ resets_at: new Date(Date.now() + 3 * 60 * 60 * 1000).toISOString(),
50
+ },
51
+ seven_day: {
52
+ utilization: 45,
53
+ resets_at: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000).toISOString(),
54
+ },
55
+ },
56
+ periodCost: 36,
57
+ todayCost: 12.5,
58
+ };
59
+
60
+ // ─────────────────────────────────────────────────────────────
61
+ // HELPER: Progress bar style cycle (includes "None")
62
+ // ─────────────────────────────────────────────────────────────
63
+
64
+ const PROGRESS_STYLES = ["None", "Braille", "Rectangle", "Filled"] as const;
65
+
66
+ function progressStyleCycle(
67
+ basePath: string,
68
+ parentHidden: (c: StatuslineConfig) => boolean,
69
+ ): MenuOption {
70
+ return {
71
+ path: `${basePath}.progressBar.style`,
72
+ label: "Progress bar",
73
+ type: "cycle",
74
+ choices: [...PROGRESS_STYLES],
75
+ getValue: (c) => {
76
+ const bar = getNestedValue(c, `${basePath}.progressBar`) as {
77
+ enabled: boolean;
78
+ style: string;
79
+ };
80
+ if (!bar.enabled) return "None";
81
+ return bar.style.charAt(0).toUpperCase() + bar.style.slice(1);
82
+ },
83
+ cycle: (c, dir) => {
84
+ const bar = getNestedValue(c, `${basePath}.progressBar`) as {
85
+ enabled: boolean;
86
+ style: string;
87
+ };
88
+ const current = bar.enabled
89
+ ? bar.style.charAt(0).toUpperCase() + bar.style.slice(1)
90
+ : "None";
91
+ const idx = PROGRESS_STYLES.indexOf(
92
+ current as (typeof PROGRESS_STYLES)[number],
93
+ );
94
+ const next =
95
+ PROGRESS_STYLES[
96
+ (idx + dir + PROGRESS_STYLES.length) % PROGRESS_STYLES.length
97
+ ];
98
+ if (next === "None") {
99
+ setNestedValue(c, `${basePath}.progressBar.enabled`, false);
100
+ } else {
101
+ setNestedValue(c, `${basePath}.progressBar.enabled`, true);
102
+ setNestedValue(c, `${basePath}.progressBar.style`, next.toLowerCase());
103
+ }
104
+ },
105
+ hidden: parentHidden,
106
+ };
107
+ }
108
+
109
+ function getNestedValue(obj: unknown, path: string): unknown {
110
+ return path.split(".").reduce((current, key) => {
111
+ if (current && typeof current === "object" && key in current) {
112
+ return (current as Record<string, unknown>)[key];
113
+ }
114
+ return undefined;
115
+ }, obj);
116
+ }
117
+
118
+ function setNestedValue(obj: unknown, path: string, value: unknown): void {
119
+ const keys = path.split(".");
120
+ const lastKey = keys.pop();
121
+ if (!lastKey) return;
122
+ let current = obj;
123
+ for (const key of keys) {
124
+ if (current && typeof current === "object" && key in current) {
125
+ current = (current as Record<string, unknown>)[key];
126
+ } else {
127
+ return;
128
+ }
129
+ }
130
+ if (current && typeof current === "object") {
131
+ (current as Record<string, unknown>)[lastKey] = value;
132
+ }
133
+ }
134
+
135
+ // ─────────────────────────────────────────────────────────────
136
+ // MENU STRUCTURE
137
+ // ─────────────────────────────────────────────────────────────
138
+
139
+ interface Tab {
140
+ id: string;
141
+ label: string;
142
+ options: MenuOption[];
143
+ }
144
+
145
+ const tabs: Tab[] = [
146
+ {
147
+ id: "presets",
148
+ label: "PRESETS",
149
+ options: PRESETS.map((preset, index) => ({
150
+ path: `preset.${index}`,
151
+ label: preset.name,
152
+ description: preset.description,
153
+ type: "boolean" as const,
154
+ getValue: () => false,
155
+ toggle: () => {},
156
+ isPreset: true,
157
+ presetIndex: index,
158
+ })),
159
+ },
160
+ {
161
+ id: "session",
162
+ label: "SESSION",
163
+ options: [
164
+ toggle("session.duration.enabled", "Duration"),
165
+ toggle("session.tokens.enabled", "Token count"),
166
+ toggle("session.tokens.showMax", " Show max", {
167
+ hidden: (c) => !c.session.tokens.enabled,
168
+ }),
169
+ toggle("session.tokens.showDecimals", " Decimals", {
170
+ hidden: (c) => !c.session.tokens.enabled,
171
+ }),
172
+ toggle("session.percentage.enabled", "Context %"),
173
+ toggle("session.percentage.showValue", " Show value", {
174
+ hidden: (c) => !c.session.percentage.enabled,
175
+ }),
176
+ progressStyleCycle(
177
+ "session.percentage",
178
+ (c) => !c.session.percentage.enabled,
179
+ ),
180
+ cycle(
181
+ "session.percentage.progressBar.length",
182
+ " Length",
183
+ PROGRESS_BAR_LENGTHS,
184
+ {
185
+ hidden: (c) =>
186
+ !c.session.percentage.enabled ||
187
+ !c.session.percentage.progressBar.enabled,
188
+ },
189
+ ),
190
+ cycle(
191
+ "session.percentage.progressBar.color",
192
+ " Color",
193
+ PROGRESS_BAR_COLORS,
194
+ {
195
+ hidden: (c) =>
196
+ !c.session.percentage.enabled ||
197
+ !c.session.percentage.progressBar.enabled,
198
+ },
199
+ ),
200
+ toggle("context.useUsableContextOnly", "45k buffer"),
201
+ ],
202
+ },
203
+ {
204
+ id: "git",
205
+ label: "GIT",
206
+ options: [
207
+ {
208
+ path: "git.enabled",
209
+ label: "Git info",
210
+ type: "cycle" as const,
211
+ choices: ["Enabled", "Disabled"],
212
+ getValue: (c) => (c.git.enabled ? "Enabled" : "Disabled"),
213
+ cycle: (c) => {
214
+ c.git.enabled = !c.git.enabled;
215
+ },
216
+ },
217
+ toggle("git.showBranch", " Branch name", {
218
+ hidden: (c) => !c.git.enabled,
219
+ }),
220
+ toggle("git.showDirtyIndicator", " Dirty indicator (*)", {
221
+ hidden: (c) => !c.git.enabled,
222
+ }),
223
+ toggle("git.showChanges", " Line changes (+/-)", {
224
+ hidden: (c) => !c.git.enabled,
225
+ }),
226
+ toggle("git.showStaged", " Staged files", {
227
+ hidden: (c) => !c.git.enabled,
228
+ }),
229
+ toggle("git.showUnstaged", " Unstaged files", {
230
+ hidden: (c) => !c.git.enabled,
231
+ }),
232
+ ],
233
+ },
234
+ {
235
+ id: "global",
236
+ label: "GLOBAL",
237
+ options: [
238
+ cycle("separator", "Separator", SEPARATORS),
239
+ cycle("pathDisplayMode", "Path display", PATH_DISPLAY_MODES),
240
+ toggle("showSonnetModel", "Show Sonnet model"),
241
+ toggle("oneLine", "Single line mode"),
242
+ ],
243
+ },
244
+ ];
245
+
246
+ // ─────────────────────────────────────────────────────────────
247
+ // CONFIG I/O
248
+ // ─────────────────────────────────────────────────────────────
249
+
250
+ function loadConfig(): StatuslineConfig {
251
+ try {
252
+ return JSON.parse(readFileSync(CONFIG_FILE_PATH, "utf-8"));
253
+ } catch {
254
+ return JSON.parse(JSON.stringify(defaultConfig));
255
+ }
256
+ }
257
+
258
+ function saveConfig(config: StatuslineConfig): void {
259
+ writeFileSync(CONFIG_FILE_PATH, JSON.stringify(config, null, 2), "utf-8");
260
+ }
261
+
262
+ // ─────────────────────────────────────────────────────────────
263
+ // RENDERING
264
+ // ─────────────────────────────────────────────────────────────
265
+
266
+ function renderPreview(config: StatuslineConfig): string {
267
+ return renderStatuslineRaw(MOCK_DATA, config);
268
+ }
269
+
270
+ function renderTabs(activeIdx: number): string {
271
+ return tabs
272
+ .map((t, i) =>
273
+ i === activeIdx
274
+ ? colors.yellow(`[${t.label}]`)
275
+ : colors.gray(` ${t.label} `),
276
+ )
277
+ .join("");
278
+ }
279
+
280
+ function renderOptions(
281
+ config: StatuslineConfig,
282
+ tab: Tab,
283
+ selIdx: number,
284
+ ): string {
285
+ const visible = tab.options.filter((o) => !o.hidden || !o.hidden(config));
286
+ return visible
287
+ .map((opt, i) => {
288
+ const sel = i === selIdx;
289
+ const val = opt.getValue?.(config);
290
+ const isPreset = "isPreset" in opt;
291
+
292
+ let display: string;
293
+ if (isPreset) {
294
+ const desc =
295
+ "description" in opt ? colors.gray(` - ${opt.description}`) : "";
296
+ display = `${colors.cyan("◈")} ${opt.label}${desc}`;
297
+ } else if (opt.type === "boolean") {
298
+ display = `${val ? colors.green("●") : colors.gray("○")} ${opt.label}`;
299
+ } else {
300
+ display = `${opt.label}: ${colors.yellow(String(val))}`;
301
+ }
302
+
303
+ const cursor = sel ? colors.yellow("›") : " ";
304
+ return `${cursor} ${sel ? colors.white(display) : colors.lightGray(display)}`;
305
+ })
306
+ .join("\n");
307
+ }
308
+
309
+ function render(
310
+ config: StatuslineConfig,
311
+ tabIdx: number,
312
+ selIdx: number,
313
+ ): string {
314
+ const tab = tabs[tabIdx];
315
+ const preview = renderPreview(config);
316
+ const previewLines = preview.split("\n");
317
+
318
+ return [
319
+ colors.purple("━━━ PREVIEW ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"),
320
+ ...previewLines,
321
+ "",
322
+ renderTabs(tabIdx),
323
+ colors.gray("─".repeat(52)),
324
+ renderOptions(config, tab, selIdx),
325
+ "",
326
+ colors.gray("←→ tabs ↑↓ select Enter toggle s save r reset q quit"),
327
+ ].join("\n");
328
+ }
329
+
330
+ // ─────────────────────────────────────────────────────────────
331
+ // MAIN LOOP
332
+ // ─────────────────────────────────────────────────────────────
333
+
334
+ async function main() {
335
+ let config = loadConfig();
336
+ let tabIdx = 0;
337
+ let selIdx = 0;
338
+
339
+ process.stdout.write("\x1b[?25l");
340
+ process.stdin.setRawMode(true);
341
+ process.stdin.resume();
342
+
343
+ const draw = () => {
344
+ const visible = tabs[tabIdx].options.filter(
345
+ (o) => !o.hidden || !o.hidden(config),
346
+ );
347
+ if (selIdx >= visible.length) selIdx = Math.max(0, visible.length - 1);
348
+ process.stdout.write("\x1b[2J\x1b[H" + render(config, tabIdx, selIdx));
349
+ };
350
+
351
+ draw();
352
+
353
+ for await (const chunk of process.stdin) {
354
+ const key = chunk.toString();
355
+
356
+ if (key === "\u001b[D" || key === "h") {
357
+ tabIdx = (tabIdx - 1 + tabs.length) % tabs.length;
358
+ selIdx = 0;
359
+ } else if (key === "\u001b[C" || key === "l") {
360
+ tabIdx = (tabIdx + 1) % tabs.length;
361
+ selIdx = 0;
362
+ } else if (key === "\u001b[A" || key === "k") {
363
+ if (selIdx > 0) selIdx--;
364
+ } else if (key === "\u001b[B" || key === "j") {
365
+ const visible = tabs[tabIdx].options.filter(
366
+ (o) => !o.hidden || !o.hidden(config),
367
+ );
368
+ if (selIdx < visible.length - 1) selIdx++;
369
+ } else if (key === "\r" || key === " ") {
370
+ const visible = tabs[tabIdx].options.filter(
371
+ (o) => !o.hidden || !o.hidden(config),
372
+ );
373
+ const opt = visible[selIdx];
374
+ if ("isPreset" in opt && "presetIndex" in opt) {
375
+ config = JSON.parse(
376
+ JSON.stringify(PRESETS[opt.presetIndex as number].config),
377
+ );
378
+ } else if (opt.type === "cycle" && opt.cycle) {
379
+ opt.cycle(config, 1);
380
+ } else if (opt.toggle) {
381
+ opt.toggle(config);
382
+ }
383
+ } else if (key.toLowerCase() === "r") {
384
+ config = JSON.parse(JSON.stringify(defaultConfig));
385
+ } else if (key.toLowerCase() === "s") {
386
+ saveConfig(config);
387
+ process.stdout.write("\x1b[2J\x1b[H");
388
+ console.log(colors.green("✓ Config saved!"));
389
+ await Bun.sleep(400);
390
+ } else if (key.toLowerCase() === "q" || key === "\u0003") {
391
+ saveConfig(config);
392
+ process.stdin.setRawMode(false);
393
+ process.stdout.write("\x1b[?25h");
394
+ console.clear();
395
+ console.log(colors.green("✓ Config saved!\n"));
396
+ process.exit(0);
397
+ }
398
+
399
+ draw();
400
+ }
401
+ }
402
+
403
+ main();
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- import { readFile, writeFile } from "node:fs/promises";
3
+ import { readFile } from "node:fs/promises";
4
4
  import { join } from "node:path";
5
5
  import { defaultConfig, type StatuslineConfig } from "./lib/config";
6
6
  import { getContextData } from "./lib/context";
@@ -19,37 +19,6 @@ import {
19
19
  } from "./lib/render-pure";
20
20
  import type { HookInput } from "./lib/types";
21
21
 
22
- // Optional feature imports - just delete the folder to disable!
23
- let getUsageLimits: any = null;
24
- let normalizeResetsAt: any = null;
25
- let getPeriodCost: any = null;
26
- let getTodayCostV2: any = null;
27
- let saveSessionV2: any = null;
28
-
29
- try {
30
- const limitsModule = await import("./lib/features/limits");
31
- getUsageLimits = limitsModule.getUsageLimits;
32
- } catch {
33
- // Limits feature not available - that's OK!
34
- }
35
-
36
- try {
37
- const utilsModule = await import("./lib/utils");
38
- normalizeResetsAt = utilsModule.normalizeResetsAt;
39
- } catch {
40
- // Fallback normalizeResetsAt
41
- normalizeResetsAt = (resetsAt: string) => resetsAt;
42
- }
43
-
44
- try {
45
- const spendModule = await import("./lib/features/spend");
46
- getPeriodCost = spendModule.getPeriodCost;
47
- getTodayCostV2 = spendModule.getTodayCostV2;
48
- saveSessionV2 = spendModule.saveSessionV2;
49
- } catch {
50
- // Spend tracking feature not available - that's OK!
51
- }
52
-
53
22
  // Re-export from render-pure for backwards compatibility
54
23
  export {
55
24
  renderStatusline,
@@ -58,13 +27,26 @@ export {
58
27
  } from "./lib/render-pure";
59
28
 
60
29
  const CONFIG_FILE_PATH = join(import.meta.dir, "..", "statusline.config.json");
61
- const LAST_PAYLOAD_PATH = join(
62
- import.meta.dir,
63
- "..",
64
- "data",
65
- "last_payload.txt",
30
+ const CLAUDE_SETTINGS_PATH = join(
31
+ process.env.HOME || "",
32
+ ".claude",
33
+ "settings.json",
66
34
  );
67
35
 
36
+ interface ClaudeSettings {
37
+ alwaysThinkingEnabled?: boolean;
38
+ effortLevel?: string;
39
+ }
40
+
41
+ async function loadClaudeSettings(): Promise<ClaudeSettings> {
42
+ try {
43
+ const content = await readFile(CLAUDE_SETTINGS_PATH, "utf-8");
44
+ return JSON.parse(content);
45
+ } catch {
46
+ return {};
47
+ }
48
+ }
49
+
68
50
  async function loadConfig(): Promise<StatuslineConfig> {
69
51
  try {
70
52
  const content = await readFile(CONFIG_FILE_PATH, "utf-8");
@@ -78,21 +60,8 @@ async function main() {
78
60
  try {
79
61
  const input: HookInput = await Bun.stdin.json();
80
62
 
81
- // Save last payload for debugging
82
- await writeFile(LAST_PAYLOAD_PATH, JSON.stringify(input, null, 2));
83
-
84
63
  const config = await loadConfig();
85
-
86
- // Get usage limits (if feature exists)
87
- const usageLimits = getUsageLimits
88
- ? await getUsageLimits()
89
- : { five_hour: null, seven_day: null };
90
- const currentResetsAt = usageLimits.five_hour?.resets_at ?? undefined;
91
-
92
- // Save session with current period context (if feature exists)
93
- if (saveSessionV2) {
94
- await saveSessionV2(input, currentResetsAt);
95
- }
64
+ const claudeSettings = await loadClaudeSettings();
96
65
 
97
66
  const git = await getGitStatus();
98
67
 
@@ -133,22 +102,18 @@ async function main() {
133
102
  contextPercentage = contextData.percentage;
134
103
  }
135
104
 
136
- // Get period cost from SQLite (if feature exists)
137
- let periodCost: number | undefined;
138
- let todayCost: number | undefined;
139
-
140
- if (getPeriodCost && getTodayCostV2 && normalizeResetsAt) {
141
- const normalizedPeriodId = currentResetsAt
142
- ? normalizeResetsAt(currentResetsAt)
143
- : null;
144
- periodCost = normalizedPeriodId ? getPeriodCost(normalizedPeriodId) : 0;
145
- todayCost = getTodayCostV2();
146
- }
147
-
148
105
  const data: StatuslineData = {
149
106
  branch: formatBranch(git, config.git),
150
107
  dirPath: formatPath(input.workspace.current_dir, config.pathDisplayMode),
151
- modelName: input.model.display_name,
108
+ modelName: (() => {
109
+ const shortName = input.model.display_name.replace(
110
+ /\s*\((\d+[KM])\s+context\)/i,
111
+ " $1",
112
+ );
113
+ return claudeSettings.effortLevel
114
+ ? `${shortName} [${claudeSettings.effortLevel}]`
115
+ : shortName;
116
+ })(),
152
117
  sessionCost: formatCost(
153
118
  input.cost.total_cost_usd,
154
119
  config.session.cost.format,
@@ -156,23 +121,7 @@ async function main() {
156
121
  sessionDuration: formatDuration(input.cost.total_duration_ms),
157
122
  contextTokens,
158
123
  contextPercentage,
159
- ...(getUsageLimits && {
160
- usageLimits: {
161
- five_hour: usageLimits.five_hour
162
- ? {
163
- utilization: usageLimits.five_hour.utilization,
164
- resets_at: usageLimits.five_hour.resets_at,
165
- }
166
- : null,
167
- seven_day: usageLimits.seven_day
168
- ? {
169
- utilization: usageLimits.seven_day.utilization,
170
- resets_at: usageLimits.seven_day.resets_at,
171
- }
172
- : null,
173
- },
174
- }),
175
- ...((getPeriodCost || getTodayCostV2) && { periodCost, todayCost }),
124
+ thinkingEnabled: claudeSettings.alwaysThinkingEnabled ?? true,
176
125
  };
177
126
 
178
127
  const output = renderStatusline(data, config);
@@ -187,4 +136,6 @@ async function main() {
187
136
  }
188
137
  }
189
138
 
190
- main();
139
+ if (import.meta.main) {
140
+ main();
141
+ }
@@ -19,7 +19,10 @@ export type ProgressBarColor =
19
19
  | "red"
20
20
  | "peach"
21
21
  | "black"
22
- | "white";
22
+ | "white"
23
+ | "purple"
24
+ | "blue"
25
+ | "cyan";
23
26
  export type ProgressBarBackground =
24
27
  | "none"
25
28
  | "dark"
@@ -101,4 +104,7 @@ export interface StatuslineConfig {
101
104
  dailySpend: {
102
105
  cost: CostConfig;
103
106
  };
107
+ thinking: {
108
+ showDisabledWarning: boolean;
109
+ };
104
110
  }
@@ -201,6 +201,9 @@ function getProgressBarColor(
201
201
  if (colorMode === "peach") return colors.peach;
202
202
  if (colorMode === "black") return colors.black;
203
203
  if (colorMode === "white") return colors.white;
204
+ if (colorMode === "purple") return colors.purple;
205
+ if (colorMode === "blue") return colors.blue;
206
+ if (colorMode === "cyan") return colors.cyan;
204
207
  return colors.red;
205
208
  }
206
209
 
@@ -322,6 +325,43 @@ export function formatProgressBar({
322
325
  return formatProgressBarFilled(percentage, length, colorMode, background);
323
326
  }
324
327
 
328
+ export function formatDualBar({
329
+ leftLabel,
330
+ leftPercentage,
331
+ leftColorFn,
332
+ rightLabel,
333
+ rightValue,
334
+ rightColorFn,
335
+ barLength,
336
+ }: {
337
+ leftLabel: string;
338
+ leftPercentage: number;
339
+ leftColorFn: ColorFunction;
340
+ rightLabel: string;
341
+ rightValue: number;
342
+ rightColorFn: ColorFunction;
343
+ barLength: number;
344
+ }): string {
345
+ const leftFilled = Math.round((leftPercentage / 100) * barLength);
346
+ const leftEmpty = barLength - leftFilled;
347
+ const leftBar = leftColorFn("█".repeat(leftFilled) + "░".repeat(leftEmpty));
348
+
349
+ const absRightValue = Math.abs(rightValue);
350
+ const rightFilled = Math.round(
351
+ (Math.min(absRightValue, 50) / 50) * barLength,
352
+ );
353
+ const rightEmpty = barLength - rightFilled;
354
+ const rightBar = rightColorFn(
355
+ "█".repeat(rightFilled) + "░".repeat(rightEmpty),
356
+ );
357
+
358
+ const leftText = `${leftColorFn(leftLabel)} ${leftBar} ${colors.lightGray(leftPercentage.toFixed(1))}${colors.gray("%")}`;
359
+ const sign = rightValue >= 0 ? "+" : "";
360
+ const rightText = `${rightColorFn(rightLabel)} ${rightBar} ${rightColorFn(`${sign}${rightValue.toFixed(1)}%`)}`;
361
+
362
+ return `${leftText}\n${rightText}`;
363
+ }
364
+
325
365
  export function formatSession(
326
366
  cost: string,
327
367
  duration: string,