aiblueprint-cli 1.4.58 → 1.4.60
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 +19 -36
- package/agents-config/agents/action.md +1 -1
- package/agents-config/agents/explore-codebase.md +53 -53
- package/agents-config/agents/explore-docs.md +50 -69
- package/agents-config/agents/websearch.md +36 -40
- package/agents-config/claude-config/scripts/.claude/skills/fix-on-my-computer/SKILL.md +81 -0
- package/agents-config/claude-config/scripts/CLAUDE.md +10 -4
- package/agents-config/claude-config/scripts/bun.lockb +0 -0
- package/agents-config/claude-config/scripts/package.json +22 -30
- package/agents-config/claude-config/scripts/statusline/CLAUDE.md +37 -155
- package/agents-config/claude-config/scripts/statusline/README.md +18 -94
- package/agents-config/claude-config/scripts/statusline/defaults.json +13 -10
- package/agents-config/claude-config/scripts/statusline/fixtures/mock-transcript.jsonl +4 -4
- package/agents-config/claude-config/scripts/statusline/fixtures/test-input.json +4 -4
- package/agents-config/claude-config/scripts/statusline/src/commands/interactive-config.ts +403 -0
- package/agents-config/claude-config/scripts/statusline/src/index.ts +33 -82
- package/agents-config/claude-config/scripts/statusline/src/lib/config-types.ts +7 -1
- package/agents-config/claude-config/scripts/statusline/src/lib/formatters.ts +40 -0
- package/agents-config/claude-config/scripts/statusline/src/lib/presets.ts +13 -13
- package/agents-config/claude-config/scripts/statusline/src/lib/render-pure.ts +24 -5
- package/agents-config/claude-config/scripts/statusline/statusline.config.free.json +79 -0
- package/agents-config/claude-config/scripts/statusline/statusline.config.json +77 -77
- package/agents-config/commands/prompts/create-vitejs-app.md +272 -0
- package/agents-config/commands/prompts/nextjs-add-prisma-db.md +136 -0
- package/agents-config/commands/prompts/nextjs-setup-better-auth.md +173 -0
- package/agents-config/commands/prompts/nextjs-setup-project.md +200 -0
- package/agents-config/commands/prompts/prompt.md +55 -0
- package/agents-config/commands/prompts/saas-challenge-idea.md +135 -0
- package/agents-config/commands/prompts/saas-create-architecture.md +242 -0
- package/agents-config/commands/prompts/saas-create-headline.md +132 -0
- package/agents-config/commands/prompts/saas-create-landing-copywritting.md +267 -0
- package/agents-config/commands/prompts/saas-create-legals-docs.md +176 -0
- package/agents-config/commands/prompts/saas-create-logos.md +240 -0
- package/agents-config/commands/prompts/saas-create-prd.md +195 -0
- package/agents-config/commands/prompts/saas-create-tasks.md +240 -0
- package/agents-config/commands/prompts/saas-define-pricing.md +293 -0
- package/agents-config/commands/prompts/saas-find-domain-name.md +190 -0
- package/agents-config/commands/prompts/saas-implement-landing-page.md +257 -0
- package/agents-config/commands/prompts/setup-tmux.md +160 -0
- package/agents-config/commands/prompts/tools.md +148 -0
- package/agents-config/scripts/.claude/skills/fix-on-my-computer/SKILL.md +81 -0
- package/agents-config/scripts/CLAUDE.md +37 -0
- package/agents-config/scripts/biome.json +37 -0
- package/agents-config/scripts/bun.lockb +0 -0
- package/agents-config/scripts/package.json +24 -0
- package/agents-config/scripts/statusline/CLAUDE.md +87 -0
- package/agents-config/scripts/statusline/README.md +117 -0
- package/agents-config/scripts/statusline/__tests__/context.test.ts +229 -0
- package/agents-config/scripts/statusline/__tests__/formatters.test.ts +108 -0
- package/agents-config/scripts/statusline/__tests__/statusline.test.ts +309 -0
- package/agents-config/scripts/statusline/defaults.json +82 -0
- package/agents-config/scripts/statusline/fixtures/mock-transcript.jsonl +4 -0
- package/agents-config/scripts/statusline/fixtures/test-input.json +35 -0
- package/agents-config/scripts/statusline/src/commands/interactive-config.ts +403 -0
- package/agents-config/scripts/statusline/src/index.ts +141 -0
- package/agents-config/scripts/statusline/src/lib/config-types.ts +110 -0
- package/agents-config/scripts/statusline/src/lib/config.ts +21 -0
- package/agents-config/scripts/statusline/src/lib/context.ts +103 -0
- package/agents-config/scripts/statusline/src/lib/formatters.ts +426 -0
- package/agents-config/scripts/statusline/src/lib/git.ts +100 -0
- package/agents-config/scripts/statusline/src/lib/menu-factories.ts +224 -0
- package/agents-config/scripts/statusline/src/lib/presets.ts +177 -0
- package/agents-config/scripts/statusline/src/lib/render-pure.ts +516 -0
- package/agents-config/scripts/statusline/src/lib/types.ts +36 -0
- package/agents-config/scripts/statusline/src/lib/utils.ts +15 -0
- package/agents-config/scripts/statusline/statusline.config.free.json +79 -0
- package/agents-config/scripts/statusline/statusline.config.json +79 -0
- package/agents-config/scripts/statusline/test-with-fixtures.ts +37 -0
- package/agents-config/scripts/statusline/test.ts +20 -0
- package/agents-config/scripts/statusline/tsconfig.json +27 -0
- package/agents-config/scripts/tsconfig.json +27 -0
- package/agents-config/skills/{subagent-creator → agents-managers}/SKILL.md +47 -47
- package/agents-config/skills/{subagent-creator/references/subagents.md → agents-managers/references/agents.md} +45 -45
- package/agents-config/skills/{subagent-creator → agents-managers}/references/context-management.md +20 -20
- package/agents-config/skills/{subagent-creator → agents-managers}/references/debugging-agents.md +27 -27
- package/agents-config/skills/{subagent-creator → agents-managers}/references/error-handling-and-recovery.md +19 -19
- package/agents-config/skills/{subagent-creator → agents-managers}/references/evaluation-and-testing.md +29 -29
- package/agents-config/skills/{subagent-creator → agents-managers}/references/orchestration-patterns.md +5 -5
- package/agents-config/skills/{subagent-creator/references/writing-subagent-prompts.md → agents-managers/references/writing-agent-prompts.md} +23 -23
- package/agents-config/skills/codex-environment/SKILL.md +2 -0
- package/agents-config/skills/commit/SKILL.md +2 -0
- package/agents-config/skills/create-pr/SKILL.md +2 -0
- package/agents-config/skills/environments-manager/SKILL.md +271 -0
- package/agents-config/skills/environments-manager/examples/claude/.worktreeinclude +3 -0
- package/agents-config/skills/environments-manager/examples/claude/commands/dev.md +5 -0
- package/agents-config/skills/environments-manager/examples/claude/commands/lint.md +5 -0
- package/agents-config/skills/environments-manager/examples/claude/commands/test.md +5 -0
- package/agents-config/skills/environments-manager/examples/claude/commands/typecheck.md +5 -0
- package/agents-config/skills/environments-manager/examples/claude/settings.json +24 -0
- package/agents-config/skills/environments-manager/examples/codex/environments/environment.toml +29 -0
- package/agents-config/skills/environments-manager/examples/cursor/worktrees.json +3 -0
- package/agents-config/skills/environments-manager/examples/scripts/claude-worktree-create.sh +96 -0
- package/agents-config/skills/environments-manager/examples/scripts/claude-worktree-remove.sh +66 -0
- package/agents-config/skills/environments-manager/examples/scripts/dev.sh +15 -0
- package/agents-config/skills/environments-manager/examples/scripts/worktree-down.sh +22 -0
- package/agents-config/skills/environments-manager/examples/scripts/worktree-up.sh +50 -0
- package/agents-config/skills/environments-manager/references/claude.md +156 -0
- package/agents-config/skills/environments-manager/references/codex.md +97 -0
- package/agents-config/skills/environments-manager/references/cursor.md +88 -0
- package/agents-config/skills/fix-pr-comments/SKILL.md +2 -0
- package/agents-config/skills/grill-me/SKILL.md +10 -0
- package/agents-config/skills/merge/SKILL.md +2 -0
- package/agents-config/skills/rules-manager/SKILL.md +191 -0
- package/agents-config/skills/rules-manager/references/agents-vs-claude.md +66 -0
- package/agents-config/skills/rules-manager/references/examples.md +117 -0
- package/agents-config/skills/skill-manager/SKILL.md +83 -0
- package/agents-config/skills/skill-manager/references/claude-code.md +81 -0
- package/agents-config/skills/skill-manager/references/codex.md +288 -0
- package/agents-config/skills/skill-manager/references/cursor.md +125 -0
- package/agents-config/skills/ultrathink/SKILL.md +2 -0
- package/dist/cli.js +618 -182
- package/package.json +1 -1
- package/agents-config/claude-config/scripts/statusline/data/.gitignore +0 -8
- package/agents-config/claude-config/scripts/statusline/data/.gitkeep +0 -0
- package/agents-config/claude-config/scripts/statusline/docs/ARCHITECTURE.md +0 -166
- package/agents-config/claude-config/scripts/statusline/src/tests/spend-v2.test.ts +0 -306
- package/agents-config/skills/apex/SKILL.md +0 -261
- package/agents-config/skills/apex/scripts/setup-templates.sh +0 -100
- package/agents-config/skills/apex/scripts/update-progress.sh +0 -80
- package/agents-config/skills/apex/steps/step-00-init.md +0 -267
- package/agents-config/skills/apex/steps/step-00b-branch.md +0 -126
- package/agents-config/skills/apex/steps/step-00b-economy.md +0 -244
- package/agents-config/skills/apex/steps/step-00b-interactive.md +0 -153
- package/agents-config/skills/apex/steps/step-01-analyze.md +0 -361
- package/agents-config/skills/apex/steps/step-02-plan.md +0 -264
- package/agents-config/skills/apex/steps/step-03-execute.md +0 -239
- package/agents-config/skills/apex/steps/step-04-validate.md +0 -251
- package/agents-config/skills/apex/templates/00-context.md +0 -43
- package/agents-config/skills/apex/templates/01-analyze.md +0 -10
- package/agents-config/skills/apex/templates/02-plan.md +0 -10
- package/agents-config/skills/apex/templates/03-execute.md +0 -10
- package/agents-config/skills/apex/templates/04-validate.md +0 -10
- package/agents-config/skills/apex/templates/README.md +0 -176
- package/agents-config/skills/apex/templates/step-complete.md +0 -7
- package/agents-config/skills/claude-memory/SKILL.md +0 -293
- package/agents-config/skills/claude-memory/references/comprehensive-example.md +0 -175
- package/agents-config/skills/claude-memory/references/optimize-guide.md +0 -300
- package/agents-config/skills/claude-memory/references/project-patterns.md +0 -334
- package/agents-config/skills/claude-memory/references/prompting-techniques.md +0 -411
- package/agents-config/skills/claude-memory/references/rules-directory-guide.md +0 -298
- package/agents-config/skills/claude-memory/references/section-templates.md +0 -347
- package/agents-config/skills/fix-errors/SKILL.md +0 -61
- package/agents-config/skills/fix-grammar/SKILL.md +0 -59
- package/agents-config/skills/ralph-loop/SKILL.md +0 -117
- package/agents-config/skills/ralph-loop/scripts/setup.sh +0 -278
- package/agents-config/skills/ralph-loop/steps/step-00-init.md +0 -215
- package/agents-config/skills/ralph-loop/steps/step-01-interactive-prd.md +0 -366
- package/agents-config/skills/ralph-loop/steps/step-02-create-stories.md +0 -273
- package/agents-config/skills/ralph-loop/steps/step-03-finish.md +0 -245
- package/agents-config/skills/skill-creator/LICENSE.txt +0 -202
- package/agents-config/skills/skill-creator/SKILL.md +0 -421
- package/agents-config/skills/skill-creator/package.json +0 -5
- package/agents-config/skills/skill-creator/references/output-patterns.md +0 -82
- package/agents-config/skills/skill-creator/references/progressive-disclosure-patterns.md +0 -374
- package/agents-config/skills/skill-creator/references/prompting-integration.md +0 -363
- package/agents-config/skills/skill-creator/references/real-world-examples.md +0 -513
- package/agents-config/skills/skill-creator/references/script-patterns.md +0 -385
- package/agents-config/skills/skill-creator/references/workflows.md +0 -28
- package/agents-config/skills/skill-creator/references/xml-tag-guide.md +0 -606
- package/agents-config/skills/skill-creator/scripts/init-skill.ts +0 -214
- package/agents-config/skills/skill-creator/scripts/package-skill.ts +0 -146
- package/agents-config/skills/skill-creator/scripts/validate.ts +0 -138
- package/agents-config/skills/workflow-apex-free/SKILL.md +0 -261
- package/agents-config/skills/workflow-apex-free/scripts/setup-templates.sh +0 -100
- package/agents-config/skills/workflow-apex-free/scripts/update-progress.sh +0 -80
- package/agents-config/skills/workflow-apex-free/steps/step-00-init.md +0 -267
- package/agents-config/skills/workflow-apex-free/steps/step-00b-branch.md +0 -126
- package/agents-config/skills/workflow-apex-free/steps/step-00b-economy.md +0 -244
- package/agents-config/skills/workflow-apex-free/steps/step-00b-interactive.md +0 -153
- package/agents-config/skills/workflow-apex-free/steps/step-01-analyze.md +0 -361
- package/agents-config/skills/workflow-apex-free/steps/step-02-plan.md +0 -264
- package/agents-config/skills/workflow-apex-free/steps/step-03-execute.md +0 -239
- package/agents-config/skills/workflow-apex-free/steps/step-04-validate.md +0 -251
- package/agents-config/skills/workflow-apex-free/templates/00-context.md +0 -43
- package/agents-config/skills/workflow-apex-free/templates/01-analyze.md +0 -10
- package/agents-config/skills/workflow-apex-free/templates/02-plan.md +0 -10
- package/agents-config/skills/workflow-apex-free/templates/03-execute.md +0 -10
- package/agents-config/skills/workflow-apex-free/templates/04-validate.md +0 -10
- package/agents-config/skills/workflow-apex-free/templates/README.md +0 -176
- 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
|
|
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
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
"
|
|
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:
|
|
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
|
-
|
|
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,
|