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,37 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
3
+ "vcs": {
4
+ "enabled": true,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": true
7
+ },
8
+ "files": {
9
+ "ignoreUnknown": false
10
+ },
11
+ "formatter": {
12
+ "enabled": true,
13
+ "indentStyle": "tab"
14
+ },
15
+ "linter": {
16
+ "enabled": true,
17
+ "rules": {
18
+ "recommended": true,
19
+ "suspicious": {
20
+ "noControlCharactersInRegex": "off"
21
+ }
22
+ }
23
+ },
24
+ "javascript": {
25
+ "formatter": {
26
+ "quoteStyle": "double"
27
+ }
28
+ },
29
+ "assist": {
30
+ "enabled": true,
31
+ "actions": {
32
+ "source": {
33
+ "organizeImports": "on"
34
+ }
35
+ }
36
+ }
37
+ }
Binary file
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "scripts",
3
+ "type": "module",
4
+ "scripts": {
5
+ "test": "bun test statusline",
6
+ "statusline:start": "bun statusline/src/index.ts",
7
+ "statusline:test": "bun test statusline",
8
+ "statusline:test-fixtures": "bun statusline/test-with-fixtures.ts",
9
+ "statusline:config": "bun statusline/src/commands/interactive-config.ts",
10
+ "statusline:lint": "biome check --write statusline",
11
+ "lint": "biome check --write .",
12
+ "format": "biome format --write ."
13
+ },
14
+ "dependencies": {
15
+ "picocolors": "^1.1.1"
16
+ },
17
+ "devDependencies": {
18
+ "@biomejs/biome": "^2.3.2",
19
+ "@types/bun": "latest"
20
+ },
21
+ "peerDependencies": {
22
+ "typescript": "^5.0.0"
23
+ }
24
+ }
@@ -0,0 +1,87 @@
1
+ # Claude Code Statusline - Project Memory
2
+
3
+ ## Overview
4
+
5
+ Lightweight, type-safe statusline implementation for Claude Code using Bun and TypeScript. Displays session context, git status, model information, duration, and context usage without premium spend or usage-limit tracking.
6
+
7
+ ## Project Setup & Configuration
8
+
9
+ ### Dependencies
10
+
11
+ - **Bun**: Runtime
12
+ - **picocolors**: Terminal colors
13
+ - **@biomejs/biome**: Linting and formatting
14
+ - **TypeScript**: Type safety
15
+
16
+ ### Configuration in Claude Code
17
+
18
+ Add to `~/.claude/settings.json`:
19
+
20
+ ```json
21
+ {
22
+ "statusLine": {
23
+ "type": "command",
24
+ "command": "bun /Users/melvynx/.claude/scripts/statusline/src/index.ts",
25
+ "padding": 0
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## Architecture
31
+
32
+ ```
33
+ src/
34
+ ├── index.ts # Main entry point
35
+ └── lib/
36
+ ├── types.ts # TypeScript interfaces
37
+ ├── git.ts # Git operations
38
+ ├── context.ts # Payload/transcript context calculation
39
+ ├── render-pure.ts # Pure rendering logic
40
+ └── formatters.ts # Display utilities and colors
41
+ ```
42
+
43
+ ## Data Flow
44
+
45
+ ```
46
+ Claude Code hook -> stdin JSON -> index.ts
47
+ -> get git status
48
+ -> get context data
49
+ -> render statusline
50
+ -> stdout
51
+ ```
52
+
53
+ ## Component Notes
54
+
55
+ - `lib/context.ts` calculates context tokens from the hook payload when available, falling back to transcript parsing.
56
+ - `lib/git.ts` detects branch and staged/unstaged changes.
57
+ - `lib/render-pure.ts` renders output from prepared data and config.
58
+ - `src/commands/interactive-config.ts` must stay in sync with `statusline.config.json`.
59
+
60
+ ## Development
61
+
62
+ ```bash
63
+ bun run test
64
+ bun run statusline:test-fixtures
65
+ bun run statusline:config
66
+ ```
67
+
68
+ Manual test:
69
+
70
+ ```bash
71
+ echo '{ ... }' | bun run statusline:start
72
+ ```
73
+
74
+ ## Error Handling
75
+
76
+ The statusline should fail softly:
77
+
78
+ - Missing transcript -> 0 tokens, 0%
79
+ - Git errors -> no-git fallback
80
+ - Missing config -> default config
81
+ - Invalid stdin -> concise error output
82
+
83
+ ## Critical Requirements
84
+
85
+ - Keep `statusline.config.json`, `defaults.json`, and `src/commands/interactive-config.ts` aligned.
86
+ - Use Bun for runtime and tests.
87
+ - Keep this free version lightweight: no spend database, no usage-limit API, no OAuth credential dependency.
@@ -0,0 +1,117 @@
1
+ # Claude Code Statusline
2
+
3
+ Lightweight statusline for Claude Code with TypeScript + Bun.
4
+
5
+ ## Features
6
+
7
+ - Git branch with staged/unstaged indicators
8
+ - Current working directory
9
+ - Model name and thinking status
10
+ - Session duration
11
+ - Context tokens and percentage
12
+
13
+ ## Structure
14
+
15
+ ```
16
+ src/
17
+ ├── index.ts # Main entry point
18
+ └── lib/
19
+ ├── types.ts # TypeScript interfaces
20
+ ├── git.ts # Git status
21
+ ├── context.ts # Context calculation from payload/transcript
22
+ └── formatters.ts # Formatting utilities
23
+ ```
24
+
25
+ ## Development
26
+
27
+ ```bash
28
+ # Install dependencies
29
+ bun install
30
+
31
+ # Run the statusline (needs stdin JSON)
32
+ echo '{ ... }' | bun run statusline:start
33
+
34
+ # Interactive config
35
+ bun run statusline:config
36
+
37
+ # Format code
38
+ bun run format
39
+
40
+ # Lint code
41
+ bun run lint
42
+ ```
43
+
44
+ ## Interactive Config
45
+
46
+ Explore all configuration options with a live preview:
47
+
48
+ ```bash
49
+ bun run statusline:config
50
+ ```
51
+
52
+ This opens an interactive menu where you can:
53
+ - Toggle any config option with arrow keys and spacebar
54
+ - See instant preview of how the statusline changes
55
+ - Navigate through all available settings
56
+ - Reset to defaults with `R`
57
+ - Explore session, context, path, and git display options
58
+
59
+ **Controls:**
60
+ - `↑↓` or `j/k` - Navigate options
61
+ - `Space` - Toggle selected option
62
+ - `R` - Reset to defaults
63
+ - `Q` - Quit
64
+
65
+ ## Configuration
66
+
67
+ The statusline can be customized via `statusline.config.json`.
68
+
69
+ ### Other Configuration Options
70
+
71
+ - **Session display**: Duration, tokens, context percentage
72
+ - **Git display**: Branch, changes, staged/unstaged files
73
+ - **Path display**: Full, truncated, or basename modes
74
+ - **Progress bars**: Multiple styles and color schemes
75
+
76
+ See `statusline.config.json` for all available options and defaults.
77
+
78
+ ## Usage in Claude Code
79
+
80
+ Update your `~/.claude/settings.json`:
81
+
82
+ ```json
83
+ {
84
+ "statusLine": {
85
+ "type": "command",
86
+ "command": "bun /Users/melvynx/.claude/scripts/statusline/src/index.ts",
87
+ "padding": 0
88
+ }
89
+ }
90
+ ```
91
+
92
+ ## Testing
93
+
94
+ ```bash
95
+ echo '{
96
+ "session_id": "test",
97
+ "transcript_path": "/path/to/transcript.jsonl",
98
+ "cwd": "/path",
99
+ "model": {
100
+ "id": "claude-sonnet-4-5",
101
+ "display_name": "Sonnet 4.5"
102
+ },
103
+ "workspace": {
104
+ "current_dir": "/path",
105
+ "project_dir": "/path"
106
+ },
107
+ "version": "2.0.31",
108
+ "output_style": { "name": "default" },
109
+ "cost": {
110
+ "total_cost_usd": 0.15,
111
+ "total_duration_ms": 300000,
112
+ "total_api_duration_ms": 200000,
113
+ "total_lines_added": 100,
114
+ "total_lines_removed": 50
115
+ }
116
+ }' | bun run statusline:start
117
+ ```
@@ -0,0 +1,229 @@
1
+ import { afterAll, beforeAll, describe, expect, it } from "bun:test";
2
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { getContextData, getContextLength } from "../src/lib/context";
5
+
6
+ const TEST_DIR = join(import.meta.dir, "..", "fixtures", "test-transcripts");
7
+
8
+ beforeAll(() => {
9
+ mkdirSync(TEST_DIR, { recursive: true });
10
+ });
11
+
12
+ afterAll(() => {
13
+ rmSync(TEST_DIR, { recursive: true, force: true });
14
+ });
15
+
16
+ function createTranscript(lines: object[]): string {
17
+ return lines.map((l) => JSON.stringify(l)).join("\n");
18
+ }
19
+
20
+ describe("getContextLength", () => {
21
+ it("should return 0 for empty transcript", async () => {
22
+ const path = join(TEST_DIR, "empty.jsonl");
23
+ writeFileSync(path, "");
24
+ expect(await getContextLength(path)).toBe(0);
25
+ });
26
+
27
+ it("should return 0 for transcript with no usage data", async () => {
28
+ const path = join(TEST_DIR, "no-usage.jsonl");
29
+ const content = createTranscript([
30
+ { type: "user", message: { role: "user", content: "hello" } },
31
+ ]);
32
+ writeFileSync(path, content);
33
+ expect(await getContextLength(path)).toBe(0);
34
+ });
35
+
36
+ it("should calculate tokens from most recent entry", async () => {
37
+ const path = join(TEST_DIR, "with-usage.jsonl");
38
+ const content = createTranscript([
39
+ {
40
+ timestamp: "2025-01-01T10:00:00Z",
41
+ message: {
42
+ role: "assistant",
43
+ usage: { input_tokens: 1000, output_tokens: 100 },
44
+ },
45
+ },
46
+ {
47
+ timestamp: "2025-01-01T10:05:00Z",
48
+ message: {
49
+ role: "assistant",
50
+ usage: { input_tokens: 5000, output_tokens: 200 },
51
+ },
52
+ },
53
+ ]);
54
+ writeFileSync(path, content);
55
+ expect(await getContextLength(path)).toBe(5000);
56
+ });
57
+
58
+ it("should include cache tokens in calculation", async () => {
59
+ const path = join(TEST_DIR, "with-cache.jsonl");
60
+ const content = createTranscript([
61
+ {
62
+ timestamp: "2025-01-01T10:00:00Z",
63
+ message: {
64
+ role: "assistant",
65
+ usage: {
66
+ input_tokens: 1000,
67
+ cache_read_input_tokens: 2000,
68
+ cache_creation_input_tokens: 3000,
69
+ output_tokens: 100,
70
+ },
71
+ },
72
+ },
73
+ ]);
74
+ writeFileSync(path, content);
75
+ expect(await getContextLength(path)).toBe(6000);
76
+ });
77
+
78
+ it("should skip sidechain entries", async () => {
79
+ const path = join(TEST_DIR, "with-sidechain.jsonl");
80
+ const content = createTranscript([
81
+ {
82
+ timestamp: "2025-01-01T10:00:00Z",
83
+ message: {
84
+ role: "assistant",
85
+ usage: { input_tokens: 1000, output_tokens: 100 },
86
+ },
87
+ },
88
+ {
89
+ timestamp: "2025-01-01T10:05:00Z",
90
+ isSidechain: true,
91
+ message: {
92
+ role: "assistant",
93
+ usage: { input_tokens: 99999, output_tokens: 200 },
94
+ },
95
+ },
96
+ ]);
97
+ writeFileSync(path, content);
98
+ expect(await getContextLength(path)).toBe(1000);
99
+ });
100
+
101
+ it("should skip API error messages", async () => {
102
+ const path = join(TEST_DIR, "with-error.jsonl");
103
+ const content = createTranscript([
104
+ {
105
+ timestamp: "2025-01-01T10:00:00Z",
106
+ message: {
107
+ role: "assistant",
108
+ usage: { input_tokens: 1000, output_tokens: 100 },
109
+ },
110
+ },
111
+ {
112
+ timestamp: "2025-01-01T10:05:00Z",
113
+ isApiErrorMessage: true,
114
+ message: {
115
+ role: "assistant",
116
+ usage: { input_tokens: 99999, output_tokens: 200 },
117
+ },
118
+ },
119
+ ]);
120
+ writeFileSync(path, content);
121
+ expect(await getContextLength(path)).toBe(1000);
122
+ });
123
+
124
+ it("should return 0 for non-existent file", async () => {
125
+ expect(await getContextLength("/non/existent/path.jsonl")).toBe(0);
126
+ });
127
+ });
128
+
129
+ describe("getContextData", () => {
130
+ it("should return zeros for non-existent file", async () => {
131
+ const result = await getContextData({
132
+ transcriptPath: "/non/existent/path.jsonl",
133
+ maxContextTokens: 200000,
134
+ autocompactBufferTokens: 45000,
135
+ });
136
+ expect(result).toEqual({ tokens: 0, percentage: 0 });
137
+ });
138
+
139
+ it("should calculate percentage correctly", async () => {
140
+ const path = join(TEST_DIR, "percentage.jsonl");
141
+ const content = createTranscript([
142
+ {
143
+ timestamp: "2025-01-01T10:00:00Z",
144
+ message: {
145
+ role: "assistant",
146
+ usage: { input_tokens: 100000, output_tokens: 100 },
147
+ },
148
+ },
149
+ ]);
150
+ writeFileSync(path, content);
151
+
152
+ const result = await getContextData({
153
+ transcriptPath: path,
154
+ maxContextTokens: 200000,
155
+ autocompactBufferTokens: 45000,
156
+ });
157
+
158
+ expect(result.tokens).toBe(100000);
159
+ expect(result.percentage).toBe(50);
160
+ });
161
+
162
+ it("should add autocompact buffer when useUsableContextOnly is true", async () => {
163
+ const path = join(TEST_DIR, "usable.jsonl");
164
+ const content = createTranscript([
165
+ {
166
+ timestamp: "2025-01-01T10:00:00Z",
167
+ message: {
168
+ role: "assistant",
169
+ usage: { input_tokens: 50000, output_tokens: 100 },
170
+ },
171
+ },
172
+ ]);
173
+ writeFileSync(path, content);
174
+
175
+ const result = await getContextData({
176
+ transcriptPath: path,
177
+ maxContextTokens: 200000,
178
+ autocompactBufferTokens: 45000,
179
+ useUsableContextOnly: true,
180
+ });
181
+
182
+ expect(result.tokens).toBe(95000);
183
+ });
184
+
185
+ it("should add overhead tokens", async () => {
186
+ const path = join(TEST_DIR, "overhead.jsonl");
187
+ const content = createTranscript([
188
+ {
189
+ timestamp: "2025-01-01T10:00:00Z",
190
+ message: {
191
+ role: "assistant",
192
+ usage: { input_tokens: 50000, output_tokens: 100 },
193
+ },
194
+ },
195
+ ]);
196
+ writeFileSync(path, content);
197
+
198
+ const result = await getContextData({
199
+ transcriptPath: path,
200
+ maxContextTokens: 200000,
201
+ autocompactBufferTokens: 45000,
202
+ overheadTokens: 20000,
203
+ });
204
+
205
+ expect(result.tokens).toBe(70000);
206
+ });
207
+
208
+ it("should cap percentage at 100", async () => {
209
+ const path = join(TEST_DIR, "over100.jsonl");
210
+ const content = createTranscript([
211
+ {
212
+ timestamp: "2025-01-01T10:00:00Z",
213
+ message: {
214
+ role: "assistant",
215
+ usage: { input_tokens: 250000, output_tokens: 100 },
216
+ },
217
+ },
218
+ ]);
219
+ writeFileSync(path, content);
220
+
221
+ const result = await getContextData({
222
+ transcriptPath: path,
223
+ maxContextTokens: 200000,
224
+ autocompactBufferTokens: 45000,
225
+ });
226
+
227
+ expect(result.percentage).toBe(100);
228
+ });
229
+ });
@@ -0,0 +1,108 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import {
3
+ formatCost,
4
+ formatDuration,
5
+ formatPath,
6
+ formatResetTime,
7
+ formatTokens,
8
+ } from "../src/lib/formatters";
9
+
10
+ describe("formatPath", () => {
11
+ it("should return basename for basename mode", () => {
12
+ expect(formatPath("/Users/test/project/src/file.ts", "basename")).toBe(
13
+ "file.ts",
14
+ );
15
+ });
16
+
17
+ it("should truncate long paths in truncated mode", () => {
18
+ const result = formatPath("/Users/test/deep/nested/path/file.ts");
19
+ expect(result).toContain("path");
20
+ expect(result).toContain("file.ts");
21
+ });
22
+
23
+ it("should handle Windows-style paths", () => {
24
+ expect(formatPath("C:\\Users\\test\\project\\file.ts", "basename")).toBe(
25
+ "file.ts",
26
+ );
27
+ });
28
+
29
+ it("should handle mixed separators", () => {
30
+ expect(formatPath("/Users/test\\mixed/path", "basename")).toBe("path");
31
+ });
32
+ });
33
+
34
+ describe("formatCost", () => {
35
+ it("should format with 1 decimal by default", () => {
36
+ expect(formatCost(1.234)).toBe("1.2");
37
+ });
38
+
39
+ it("should format as integer when specified", () => {
40
+ expect(formatCost(1.789, "integer")).toBe("2");
41
+ });
42
+
43
+ it("should format with 2 decimals when specified", () => {
44
+ expect(formatCost(1.789, "decimal2")).toBe("1.79");
45
+ });
46
+ });
47
+
48
+ describe("formatTokens", () => {
49
+ it("should format thousands with k suffix", () => {
50
+ const result = formatTokens(5000);
51
+ expect(result).toContain("5.0");
52
+ expect(result).toContain("k");
53
+ });
54
+
55
+ it("should format millions with m suffix", () => {
56
+ const result = formatTokens(1500000);
57
+ expect(result).toContain("1.5");
58
+ expect(result).toContain("m");
59
+ });
60
+
61
+ it("should return raw number for small values", () => {
62
+ const result = formatTokens(500);
63
+ expect(result).toContain("500");
64
+ });
65
+
66
+ it("should hide decimals when showDecimals is false", () => {
67
+ const result = formatTokens(5500, false);
68
+ expect(result).toContain("6");
69
+ });
70
+ });
71
+
72
+ describe("formatDuration", () => {
73
+ it("should format minutes only for short durations", () => {
74
+ expect(formatDuration(300000)).toBe("5m");
75
+ });
76
+
77
+ it("should format hours and minutes for long durations", () => {
78
+ expect(formatDuration(5400000)).toBe("1h 30m");
79
+ });
80
+
81
+ it("should handle zero duration", () => {
82
+ expect(formatDuration(0)).toBe("0m");
83
+ });
84
+ });
85
+
86
+ describe("formatResetTime", () => {
87
+ it("should return 'now' for past times", () => {
88
+ const pastTime = new Date(Date.now() - 60000).toISOString();
89
+ expect(formatResetTime(pastTime)).toBe("now");
90
+ });
91
+
92
+ it("should format future times with hours and minutes", () => {
93
+ const futureTime = new Date(Date.now() + 3700000).toISOString();
94
+ const result = formatResetTime(futureTime);
95
+ expect(result).toContain("h");
96
+ expect(result).toContain("m");
97
+ });
98
+
99
+ it("should format minutes only for short durations", () => {
100
+ const futureTime = new Date(Date.now() + 1800000).toISOString();
101
+ const result = formatResetTime(futureTime);
102
+ expect(result).toMatch(/^\d+m$/);
103
+ });
104
+
105
+ it("should return N/A for invalid dates", () => {
106
+ expect(formatResetTime("invalid-date")).toBe("N/A");
107
+ });
108
+ });