nemonix-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +186 -0
- package/dist/cli.js +6870 -0
- package/package.json +48 -0
- package/src/config/claude-code-config/.claude/commands/setup-tmux.md +0 -0
- package/src/config/claude-code-config/CHANGELOG.md +261 -0
- package/src/config/claude-code-config/README.md +1 -0
- package/src/config/claude-code-config/agents/action.md +36 -0
- package/src/config/claude-code-config/agents/clean-code-runner.md +61 -0
- package/src/config/claude-code-config/agents/code-reviewer.md +172 -0
- package/src/config/claude-code-config/agents/code-simplifier.md +49 -0
- package/src/config/claude-code-config/agents/explore-codebase.md +65 -0
- package/src/config/claude-code-config/agents/explore-docs.md +65 -0
- package/src/config/claude-code-config/agents/explore-fast.md +22 -0
- package/src/config/claude-code-config/agents/implementer.md +181 -0
- package/src/config/claude-code-config/agents/snipper.md +36 -0
- package/src/config/claude-code-config/agents/websearch.md +42 -0
- package/src/config/claude-code-config/commands/prompts/create-vitejs-app.md +272 -0
- package/src/config/claude-code-config/commands/prompts/nextjs-add-prisma-db.md +136 -0
- package/src/config/claude-code-config/commands/prompts/nextjs-setup-better-auth.md +173 -0
- package/src/config/claude-code-config/commands/prompts/nextjs-setup-project.md +200 -0
- package/src/config/claude-code-config/commands/prompts/prompt.md +55 -0
- package/src/config/claude-code-config/commands/prompts/saas-challenge-idea.md +135 -0
- package/src/config/claude-code-config/commands/prompts/saas-create-architecture.md +242 -0
- package/src/config/claude-code-config/commands/prompts/saas-create-headline.md +132 -0
- package/src/config/claude-code-config/commands/prompts/saas-create-landing-copywritting.md +267 -0
- package/src/config/claude-code-config/commands/prompts/saas-create-legals-docs.md +176 -0
- package/src/config/claude-code-config/commands/prompts/saas-create-logos.md +240 -0
- package/src/config/claude-code-config/commands/prompts/saas-create-prd.md +195 -0
- package/src/config/claude-code-config/commands/prompts/saas-create-tasks.md +240 -0
- package/src/config/claude-code-config/commands/prompts/saas-define-pricing.md +293 -0
- package/src/config/claude-code-config/commands/prompts/saas-find-domain-name.md +190 -0
- package/src/config/claude-code-config/commands/prompts/saas-implement-landing-page.md +257 -0
- package/src/config/claude-code-config/commands/prompts/setup-tmux.md +160 -0
- package/src/config/claude-code-config/commands/prompts/tools.md +148 -0
- package/src/config/claude-code-config/hooks/hook-post-file.ts +162 -0
- package/src/config/claude-code-config/scripts/.claude/skills/fix-on-my-computer/SKILL.md +81 -0
- package/src/config/claude-code-config/scripts/CLAUDE.md +50 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/CLAUDE.md +59 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/__tests__/shared.test.ts +185 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/__tests__/title-generation.test.ts +44 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/fixtures/sample-transcript.jsonl +3 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/fixtures/transcript-short-message.jsonl +2 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/fixtures/transcript-with-title.jsonl +3 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/src/index.ts +113 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/src/rename-all.ts +148 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/src/shared.ts +157 -0
- package/src/config/claude-code-config/scripts/auto-rename-session/src/worker.ts +58 -0
- package/src/config/claude-code-config/scripts/biome.json +37 -0
- package/src/config/claude-code-config/scripts/claude-code-ai/CLAUDE.md +84 -0
- package/src/config/claude-code-config/scripts/claude-code-ai/__tests__/claude.test.ts +19 -0
- package/src/config/claude-code-config/scripts/claude-code-ai/__tests__/paths.test.ts +68 -0
- package/src/config/claude-code-config/scripts/claude-code-ai/claude.ts +56 -0
- package/src/config/claude-code-config/scripts/claude-code-ai/cli.ts +46 -0
- package/src/config/claude-code-config/scripts/claude-code-ai/helper/credentials.ts +76 -0
- package/src/config/claude-code-config/scripts/claude-code-ai/helper/index.ts +9 -0
- package/src/config/claude-code-config/scripts/claude-code-ai/helper/paths.ts +51 -0
- package/src/config/claude-code-config/scripts/command-validator/CLAUDE.md +112 -0
- package/src/config/claude-code-config/scripts/command-validator/README.md +147 -0
- package/src/config/claude-code-config/scripts/command-validator/src/__tests__/validator.test.ts +99 -0
- package/src/config/claude-code-config/scripts/command-validator/src/cli.ts +121 -0
- package/src/config/claude-code-config/scripts/command-validator/src/lib/security-rules.ts +174 -0
- package/src/config/claude-code-config/scripts/command-validator/src/lib/types.ts +34 -0
- package/src/config/claude-code-config/scripts/command-validator/src/lib/validator.ts +90 -0
- package/src/config/claude-code-config/scripts/package.json +43 -0
- package/src/config/claude-code-config/scripts/statusline/CLAUDE.md +205 -0
- package/src/config/claude-code-config/scripts/statusline/README.md +193 -0
- package/src/config/claude-code-config/scripts/statusline/__tests__/context.test.ts +229 -0
- package/src/config/claude-code-config/scripts/statusline/__tests__/formatters.test.ts +108 -0
- package/src/config/claude-code-config/scripts/statusline/__tests__/statusline.test.ts +309 -0
- package/src/config/claude-code-config/scripts/statusline/data/.gitkeep +0 -0
- package/src/config/claude-code-config/scripts/statusline/defaults.json +82 -0
- package/src/config/claude-code-config/scripts/statusline/docs/ARCHITECTURE.md +166 -0
- package/src/config/claude-code-config/scripts/statusline/fixtures/mock-transcript.jsonl +4 -0
- package/src/config/claude-code-config/scripts/statusline/fixtures/test-input.json +35 -0
- package/src/config/claude-code-config/scripts/statusline/src/analyze-daily-usage.ts +151 -0
- package/src/config/claude-code-config/scripts/statusline/src/commands/interactive-config.ts +515 -0
- package/src/config/claude-code-config/scripts/statusline/src/debug-payloads.ts +195 -0
- package/src/config/claude-code-config/scripts/statusline/src/index.ts +224 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/config-types.ts +110 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/config.ts +21 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/context.ts +103 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/limits/commands/weekly-analysis.ts +108 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/limits/index.ts +111 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/limits/types.ts +15 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/spend/commands/migrate-to-sqlite.ts +136 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/spend/commands/spend-day.ts +79 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/spend/commands/spend-month.ts +66 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/spend/commands/spend-project.ts +85 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/spend/database.ts +395 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/spend/index.ts +178 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/spend/payload-logger.ts +161 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/features/spend/types.ts +37 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/formatters.ts +426 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/git.ts +100 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/menu-factories.ts +224 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/presets.ts +177 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/render-pure.ts +516 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/types.ts +36 -0
- package/src/config/claude-code-config/scripts/statusline/src/lib/utils.ts +15 -0
- package/src/config/claude-code-config/scripts/statusline/src/stats.ts +119 -0
- package/src/config/claude-code-config/scripts/statusline/src/tests/spend-v2.test.ts +377 -0
- package/src/config/claude-code-config/scripts/statusline/src/tools/fixed-cost-calc.ts +317 -0
- package/src/config/claude-code-config/scripts/statusline/statusline.config.free.json +79 -0
- package/src/config/claude-code-config/scripts/statusline/statusline.config.json +100 -0
- package/src/config/claude-code-config/scripts/statusline/test-with-fixtures.ts +37 -0
- package/src/config/claude-code-config/scripts/statusline/test.ts +20 -0
- package/src/config/claude-code-config/scripts/statusline/tsconfig.json +27 -0
- package/src/config/claude-code-config/scripts/tsconfig.json +27 -0
- package/src/config/claude-code-config/settings.json +92 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/SKILL.md +176 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/references/architecture-template.md +436 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/references/challenge-framework.md +289 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/references/discovery-framework.md +338 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/references/prd-template.md +452 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/references/task-template.md +263 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/references/tools.md +132 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/scripts/rename-project.sh +42 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/scripts/setup.sh +104 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/steps/step-00-init.md +174 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/steps/step-01-discovery.md +342 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/steps/step-02-brainstorm.md +230 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/steps/step-03-validate.md +372 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/steps/step-04-prd.md +364 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/steps/step-05-architecture.md +904 -0
- package/src/config/claude-code-config/skills/aibuilder-create-saas/steps/step-06-tasks.md +446 -0
- package/src/config/claude-code-config/skills/explore/SKILL.md +119 -0
- package/src/config/claude-code-config/skills/frontend-design/LICENSE.txt +177 -0
- package/src/config/claude-code-config/skills/frontend-design/SKILL.md +42 -0
- package/src/config/claude-code-config/skills/git-commit/SKILL.md +42 -0
- package/src/config/claude-code-config/skills/git-create-pr/SKILL.md +53 -0
- package/src/config/claude-code-config/skills/git-fix-pr-comments/SKILL.md +51 -0
- package/src/config/claude-code-config/skills/git-merge/SKILL.md +68 -0
- package/src/config/claude-code-config/skills/marketing-copywriting/SKILL.md +72 -0
- package/src/config/claude-code-config/skills/meta-claude-memory/SKILL.md +694 -0
- package/src/config/claude-code-config/skills/meta-claude-memory/references/comprehensive-example.md +175 -0
- package/src/config/claude-code-config/skills/meta-claude-memory/references/project-patterns.md +334 -0
- package/src/config/claude-code-config/skills/meta-claude-memory/references/prompting-techniques.md +411 -0
- package/src/config/claude-code-config/skills/meta-claude-memory/references/rules-directory-guide.md +298 -0
- package/src/config/claude-code-config/skills/meta-claude-memory/references/section-templates.md +347 -0
- package/src/config/claude-code-config/skills/meta-hooks-creator/SKILL.md +357 -0
- package/src/config/claude-code-config/skills/meta-hooks-creator/references/command-vs-prompt.md +287 -0
- package/src/config/claude-code-config/skills/meta-hooks-creator/references/examples.md +689 -0
- package/src/config/claude-code-config/skills/meta-hooks-creator/references/hook-types.md +495 -0
- package/src/config/claude-code-config/skills/meta-hooks-creator/references/input-output-schemas.md +503 -0
- package/src/config/claude-code-config/skills/meta-hooks-creator/references/matchers.md +517 -0
- package/src/config/claude-code-config/skills/meta-hooks-creator/references/troubleshooting.md +653 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/SKILL.md +285 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/anthropic-best-practices.md +126 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/anti-patterns.md +57 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/clarity-principles.md +54 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/context-management.md +389 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/few-shot-patterns.md +47 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/openai-best-practices.md +50 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/prompt-templates.md +110 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/reasoning-techniques.md +52 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/system-prompt-patterns.md +48 -0
- package/src/config/claude-code-config/skills/meta-prompt-creator/references/xml-structure.md +36 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/LICENSE.txt +202 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/SKILL.md +421 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/package.json +5 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/references/output-patterns.md +82 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/references/progressive-disclosure-patterns.md +374 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/references/prompting-integration.md +363 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/references/real-world-examples.md +513 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/references/script-patterns.md +385 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/references/workflows.md +28 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/references/xml-tag-guide.md +606 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/scripts/init-skill.ts +214 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/scripts/package-skill.ts +146 -0
- package/src/config/claude-code-config/skills/meta-skill-creator/scripts/validate.ts +138 -0
- package/src/config/claude-code-config/skills/meta-skill-workflow-creator/SKILL.md +390 -0
- package/src/config/claude-code-config/skills/meta-skill-workflow-creator/references/ask-patterns.md +225 -0
- package/src/config/claude-code-config/skills/meta-skill-workflow-creator/references/prompt-engineering.md +377 -0
- package/src/config/claude-code-config/skills/meta-skill-workflow-creator/references/state-management.md +275 -0
- package/src/config/claude-code-config/skills/meta-skill-workflow-creator/references/step-template.md +334 -0
- package/src/config/claude-code-config/skills/meta-skill-workflow-creator/references/workflow-patterns.md +300 -0
- package/src/config/claude-code-config/skills/meta-subagent-creator/SKILL.md +451 -0
- package/src/config/claude-code-config/skills/meta-subagent-creator/references/context-management.md +567 -0
- package/src/config/claude-code-config/skills/meta-subagent-creator/references/debugging-agents.md +714 -0
- package/src/config/claude-code-config/skills/meta-subagent-creator/references/error-handling-and-recovery.md +502 -0
- package/src/config/claude-code-config/skills/meta-subagent-creator/references/evaluation-and-testing.md +374 -0
- package/src/config/claude-code-config/skills/meta-subagent-creator/references/orchestration-patterns.md +591 -0
- package/src/config/claude-code-config/skills/meta-subagent-creator/references/subagents.md +599 -0
- package/src/config/claude-code-config/skills/meta-subagent-creator/references/writing-subagent-prompts.md +513 -0
- package/src/config/claude-code-config/skills/ralph-loop/SKILL.md +117 -0
- package/src/config/claude-code-config/skills/ralph-loop/scripts/setup.sh +278 -0
- package/src/config/claude-code-config/skills/ralph-loop/steps/step-00-init.md +215 -0
- package/src/config/claude-code-config/skills/ralph-loop/steps/step-01-interactive-prd.md +366 -0
- package/src/config/claude-code-config/skills/ralph-loop/steps/step-02-create-stories.md +273 -0
- package/src/config/claude-code-config/skills/ralph-loop/steps/step-03-finish.md +245 -0
- package/src/config/claude-code-config/skills/ralph-tasks/SKILL.md +88 -0
- package/src/config/claude-code-config/skills/ralph-tasks/scripts/add-task.sh +36 -0
- package/src/config/claude-code-config/skills/ralph-tasks/scripts/list-tasks.sh +66 -0
- package/src/config/claude-code-config/skills/ralph-tasks/scripts/remove-task.sh +47 -0
- package/src/config/claude-code-config/skills/ralph-tasks/scripts/setup.sh +201 -0
- package/src/config/claude-code-config/skills/ralph-tasks/steps/action-add-search.md +131 -0
- package/src/config/claude-code-config/skills/ralph-tasks/steps/action-add.md +46 -0
- package/src/config/claude-code-config/skills/ralph-tasks/steps/action-init.md +123 -0
- package/src/config/claude-code-config/skills/ralph-tasks/steps/action-list.md +58 -0
- package/src/config/claude-code-config/skills/ralph-tasks/steps/action-remove.md +48 -0
- package/src/config/claude-code-config/skills/ralph-tasks/steps/action-setup.md +46 -0
- package/src/config/claude-code-config/skills/ralph-tasks/steps/action-wake-up.md +62 -0
- package/src/config/claude-code-config/skills/utils-fix-errors/SKILL.md +61 -0
- package/src/config/claude-code-config/skills/utils-fix-grammar/SKILL.md +59 -0
- package/src/config/claude-code-config/skills/utils-oneshot/SKILL.md +56 -0
- package/src/config/claude-code-config/skills/utils-refactor/SKILL.md +89 -0
- package/src/config/claude-code-config/skills/utils-save-docs/SKILL.md +74 -0
- package/src/config/claude-code-config/skills/utils-ultrathink/SKILL.md +42 -0
- package/src/config/claude-code-config/skills/workflow-apex/SKILL.md +116 -0
- package/src/config/claude-code-config/skills/workflow-apex/scripts/setup-templates.sh +144 -0
- package/src/config/claude-code-config/skills/workflow-apex/scripts/update-progress.sh +80 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-00-init.md +273 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-00b-branch.md +126 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-00b-economy.md +244 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-00b-interactive.md +165 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-00b-save.md +123 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-01-analyze.md +361 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-02-plan.md +422 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-02b-tasks.md +301 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-03-execute-teams.md +297 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-03-execute.md +239 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-04-validate.md +264 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-05-examine.md +294 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-06-resolve.md +237 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-07-tests.md +250 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-08-run-tests.md +308 -0
- package/src/config/claude-code-config/skills/workflow-apex/steps/step-09-finish.md +193 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/00-context.md +53 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/01-analyze.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/02-plan.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/03-execute.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/04-validate.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/05-examine.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/06-resolve.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/07-tests.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/08-run-tests.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/09-finish.md +10 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/README.md +195 -0
- package/src/config/claude-code-config/skills/workflow-apex/templates/step-complete.md +7 -0
- package/src/config/claude-code-config/skills/workflow-brainstorm/SKILL.md +127 -0
- package/src/config/claude-code-config/skills/workflow-brainstorm/steps/step-01-explore.md +230 -0
- package/src/config/claude-code-config/skills/workflow-brainstorm/steps/step-02-challenge.md +238 -0
- package/src/config/claude-code-config/skills/workflow-brainstorm/steps/step-03-synthesize.md +337 -0
- package/src/config/claude-code-config/skills/workflow-brainstorm/steps/step-04-action.md +285 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/SKILL.md +150 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/references/cli-commands.md +122 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/references/github-cli.md +243 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/references/troubleshooting.md +362 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/references/vercel-cli.md +192 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/steps/step-00-init.md +157 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/steps/step-01-watch-ci.md +192 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/steps/step-02-analyze-errors.md +263 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/steps/step-03-fix-locally.md +312 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/steps/step-04-commit-push.md +206 -0
- package/src/config/claude-code-config/skills/workflow-ci-fixer/steps/step-05-cleanup.md +196 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/SKILL.md +129 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/references/general-clean-code.md +347 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/references/nextjs-clean-code.md +458 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/references/react-clean-code.md +406 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/references/tanstack-query-best-practices.md +516 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/references/zustand-best-practices.md +491 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/steps/step-01-scan.md +137 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/steps/step-02-apply.md +152 -0
- package/src/config/claude-code-config/skills/workflow-clean-code/steps/step-03-verify.md +143 -0
- package/src/config/claude-code-config/skills/workflow-debug/SKILL.md +126 -0
- package/src/config/claude-code-config/skills/workflow-debug/references/log-technique.md +285 -0
- package/src/config/claude-code-config/skills/workflow-debug/steps/step-00-init.md +94 -0
- package/src/config/claude-code-config/skills/workflow-debug/steps/step-01-analyze.md +180 -0
- package/src/config/claude-code-config/skills/workflow-debug/steps/step-01b-log-instrumentation.md +271 -0
- package/src/config/claude-code-config/skills/workflow-debug/steps/step-02-find-solutions.md +141 -0
- package/src/config/claude-code-config/skills/workflow-debug/steps/step-03-propose.md +142 -0
- package/src/config/claude-code-config/skills/workflow-debug/steps/step-04-fix.md +176 -0
- package/src/config/claude-code-config/skills/workflow-debug/steps/step-05-verify.md +279 -0
- package/src/config/claude-code-config/skills/workflow-review-code/SKILL.md +219 -0
- package/src/config/claude-code-config/skills/workflow-review-code/references/clean-code-principles.md +140 -0
- package/src/config/claude-code-config/skills/workflow-review-code/references/code-quality-metrics.md +174 -0
- package/src/config/claude-code-config/skills/workflow-review-code/references/feedback-patterns.md +149 -0
- package/src/config/claude-code-config/skills/workflow-review-code/references/security-checklist.md +127 -0
- package/src/config/claude-code-config/song/finish.mp3 +0 -0
- package/src/config/claude-code-config/song/need-human.mp3 +0 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
3
|
+
import { existsSync, rmSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const TEST_DB_PATH = join(import.meta.dir, "..", "..", "data", "test.db");
|
|
7
|
+
|
|
8
|
+
describe("SQLite Delta Tracking", () => {
|
|
9
|
+
let db: Database;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
if (existsSync(TEST_DB_PATH)) {
|
|
13
|
+
rmSync(TEST_DB_PATH);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
db = new Database(TEST_DB_PATH);
|
|
17
|
+
|
|
18
|
+
db.run(`
|
|
19
|
+
CREATE TABLE sessions (
|
|
20
|
+
session_id TEXT PRIMARY KEY,
|
|
21
|
+
total_cost REAL NOT NULL DEFAULT 0,
|
|
22
|
+
cwd TEXT NOT NULL,
|
|
23
|
+
date TEXT NOT NULL,
|
|
24
|
+
duration_ms INTEGER NOT NULL DEFAULT 0,
|
|
25
|
+
lines_added INTEGER NOT NULL DEFAULT 0,
|
|
26
|
+
lines_removed INTEGER NOT NULL DEFAULT 0,
|
|
27
|
+
last_resets_at TEXT
|
|
28
|
+
)
|
|
29
|
+
`);
|
|
30
|
+
|
|
31
|
+
db.run(`
|
|
32
|
+
CREATE TABLE session_period_tracking (
|
|
33
|
+
session_id TEXT NOT NULL,
|
|
34
|
+
period_id TEXT NOT NULL,
|
|
35
|
+
counted_cost REAL NOT NULL DEFAULT 0,
|
|
36
|
+
last_session_cost REAL NOT NULL DEFAULT 0,
|
|
37
|
+
PRIMARY KEY (session_id, period_id)
|
|
38
|
+
)
|
|
39
|
+
`);
|
|
40
|
+
|
|
41
|
+
db.run(`
|
|
42
|
+
CREATE TABLE periods (
|
|
43
|
+
period_id TEXT PRIMARY KEY,
|
|
44
|
+
total_cost REAL NOT NULL DEFAULT 0,
|
|
45
|
+
utilization INTEGER NOT NULL DEFAULT 0,
|
|
46
|
+
date TEXT NOT NULL
|
|
47
|
+
)
|
|
48
|
+
`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
db.close();
|
|
53
|
+
if (existsSync(TEST_DB_PATH)) {
|
|
54
|
+
rmSync(TEST_DB_PATH);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("New session: full cost added to period", () => {
|
|
59
|
+
const sessionId = "session-1";
|
|
60
|
+
const periodId = "2025-12-09T10:00:00.000Z";
|
|
61
|
+
const sessionCost = 10.0;
|
|
62
|
+
|
|
63
|
+
db.run(
|
|
64
|
+
"INSERT INTO sessions (session_id, total_cost, cwd, date, last_resets_at) VALUES (?, ?, ?, ?, ?)",
|
|
65
|
+
[sessionId, sessionCost, "/test", "2025-12-09", periodId],
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
db.run(
|
|
69
|
+
"INSERT INTO session_period_tracking (session_id, period_id, counted_cost, last_session_cost) VALUES (?, ?, ?, ?)",
|
|
70
|
+
[sessionId, periodId, sessionCost, sessionCost],
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
db.run(
|
|
74
|
+
"INSERT INTO periods (period_id, total_cost, utilization, date) VALUES (?, ?, ?, ?)",
|
|
75
|
+
[periodId, sessionCost, 0, "2025-12-09"],
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const period = db
|
|
79
|
+
.query<{ total_cost: number }, [string]>(
|
|
80
|
+
"SELECT total_cost FROM periods WHERE period_id = ?",
|
|
81
|
+
)
|
|
82
|
+
.get(periodId);
|
|
83
|
+
|
|
84
|
+
expect(period?.total_cost).toBe(10.0);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("Continued session: only delta added to period", () => {
|
|
88
|
+
const sessionId = "session-1";
|
|
89
|
+
const periodId = "2025-12-09T10:00:00.000Z";
|
|
90
|
+
|
|
91
|
+
db.run(
|
|
92
|
+
"INSERT INTO sessions (session_id, total_cost, cwd, date, last_resets_at) VALUES (?, ?, ?, ?, ?)",
|
|
93
|
+
[sessionId, 10.0, "/test", "2025-12-09", periodId],
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
db.run(
|
|
97
|
+
"INSERT INTO session_period_tracking (session_id, period_id, counted_cost, last_session_cost) VALUES (?, ?, ?, ?)",
|
|
98
|
+
[sessionId, periodId, 10.0, 10.0],
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
db.run(
|
|
102
|
+
"INSERT INTO periods (period_id, total_cost, utilization, date) VALUES (?, ?, ?, ?)",
|
|
103
|
+
[periodId, 10.0, 0, "2025-12-09"],
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const newSessionCost = 24.0;
|
|
107
|
+
const delta = newSessionCost - 10.0;
|
|
108
|
+
|
|
109
|
+
db.run("UPDATE sessions SET total_cost = ? WHERE session_id = ?", [
|
|
110
|
+
newSessionCost,
|
|
111
|
+
sessionId,
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
const tracking = db
|
|
115
|
+
.query<
|
|
116
|
+
{ counted_cost: number; last_session_cost: number },
|
|
117
|
+
[string, string]
|
|
118
|
+
>(
|
|
119
|
+
"SELECT counted_cost, last_session_cost FROM session_period_tracking WHERE session_id = ? AND period_id = ?",
|
|
120
|
+
)
|
|
121
|
+
.get(sessionId, periodId);
|
|
122
|
+
|
|
123
|
+
const newCountedCost = (tracking?.counted_cost ?? 0) + delta;
|
|
124
|
+
|
|
125
|
+
db.run(
|
|
126
|
+
"UPDATE session_period_tracking SET counted_cost = ?, last_session_cost = ? WHERE session_id = ? AND period_id = ?",
|
|
127
|
+
[newCountedCost, newSessionCost, sessionId, periodId],
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
db.run(
|
|
131
|
+
"UPDATE periods SET total_cost = total_cost + ? WHERE period_id = ?",
|
|
132
|
+
[delta, periodId],
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const period = db
|
|
136
|
+
.query<{ total_cost: number }, [string]>(
|
|
137
|
+
"SELECT total_cost FROM periods WHERE period_id = ?",
|
|
138
|
+
)
|
|
139
|
+
.get(periodId);
|
|
140
|
+
const updatedTracking = db
|
|
141
|
+
.query<{ counted_cost: number }, [string, string]>(
|
|
142
|
+
"SELECT counted_cost FROM session_period_tracking WHERE session_id = ? AND period_id = ?",
|
|
143
|
+
)
|
|
144
|
+
.get(sessionId, periodId);
|
|
145
|
+
|
|
146
|
+
expect(period?.total_cost).toBe(24.0);
|
|
147
|
+
expect(updatedTracking?.counted_cost).toBe(24.0);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("Session spanning periods: only new delta in new period", () => {
|
|
151
|
+
const sessionId = "session-1";
|
|
152
|
+
const periodA = "2025-12-09T05:00:00.000Z";
|
|
153
|
+
const periodB = "2025-12-09T10:00:00.000Z";
|
|
154
|
+
|
|
155
|
+
db.run(
|
|
156
|
+
"INSERT INTO sessions (session_id, total_cost, cwd, date, last_resets_at) VALUES (?, ?, ?, ?, ?)",
|
|
157
|
+
[sessionId, 10.0, "/test", "2025-12-09", periodA],
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
db.run(
|
|
161
|
+
"INSERT INTO session_period_tracking (session_id, period_id, counted_cost, last_session_cost) VALUES (?, ?, ?, ?)",
|
|
162
|
+
[sessionId, periodA, 10.0, 10.0],
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
db.run(
|
|
166
|
+
"INSERT INTO periods (period_id, total_cost, utilization, date) VALUES (?, ?, ?, ?)",
|
|
167
|
+
[periodA, 10.0, 0, "2025-12-09"],
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const newSessionCost = 24.0;
|
|
171
|
+
const session = db
|
|
172
|
+
.query<{ total_cost: number }, [string]>(
|
|
173
|
+
"SELECT total_cost FROM sessions WHERE session_id = ?",
|
|
174
|
+
)
|
|
175
|
+
.get(sessionId);
|
|
176
|
+
const delta = newSessionCost - (session?.total_cost ?? 0);
|
|
177
|
+
|
|
178
|
+
db.run(
|
|
179
|
+
"UPDATE sessions SET total_cost = ?, last_resets_at = ? WHERE session_id = ?",
|
|
180
|
+
[newSessionCost, periodB, sessionId],
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
db.run(
|
|
184
|
+
"INSERT INTO session_period_tracking (session_id, period_id, counted_cost, last_session_cost) VALUES (?, ?, ?, ?)",
|
|
185
|
+
[sessionId, periodB, delta, newSessionCost],
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
db.run(
|
|
189
|
+
"INSERT OR IGNORE INTO periods (period_id, total_cost, utilization, date) VALUES (?, ?, ?, ?)",
|
|
190
|
+
[periodB, 0, 0, "2025-12-09"],
|
|
191
|
+
);
|
|
192
|
+
db.run(
|
|
193
|
+
"UPDATE periods SET total_cost = total_cost + ? WHERE period_id = ?",
|
|
194
|
+
[delta, periodB],
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const periodACost = db
|
|
198
|
+
.query<{ total_cost: number }, [string]>(
|
|
199
|
+
"SELECT total_cost FROM periods WHERE period_id = ?",
|
|
200
|
+
)
|
|
201
|
+
.get(periodA);
|
|
202
|
+
const periodBCost = db
|
|
203
|
+
.query<{ total_cost: number }, [string]>(
|
|
204
|
+
"SELECT total_cost FROM periods WHERE period_id = ?",
|
|
205
|
+
)
|
|
206
|
+
.get(periodB);
|
|
207
|
+
const trackingA = db
|
|
208
|
+
.query<{ counted_cost: number }, [string, string]>(
|
|
209
|
+
"SELECT counted_cost FROM session_period_tracking WHERE session_id = ? AND period_id = ?",
|
|
210
|
+
)
|
|
211
|
+
.get(sessionId, periodA);
|
|
212
|
+
const trackingB = db
|
|
213
|
+
.query<{ counted_cost: number }, [string, string]>(
|
|
214
|
+
"SELECT counted_cost FROM session_period_tracking WHERE session_id = ? AND period_id = ?",
|
|
215
|
+
)
|
|
216
|
+
.get(sessionId, periodB);
|
|
217
|
+
|
|
218
|
+
expect(periodACost?.total_cost).toBe(10.0);
|
|
219
|
+
expect(periodBCost?.total_cost).toBe(14.0);
|
|
220
|
+
expect(trackingA?.counted_cost).toBe(10.0);
|
|
221
|
+
expect(trackingB?.counted_cost).toBe(14.0);
|
|
222
|
+
|
|
223
|
+
expect(
|
|
224
|
+
(periodACost?.total_cost ?? 0) + (periodBCost?.total_cost ?? 0),
|
|
225
|
+
).toBe(24.0);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("Multiple sessions in same period: costs sum correctly", () => {
|
|
229
|
+
const periodId = "2025-12-09T10:00:00.000Z";
|
|
230
|
+
|
|
231
|
+
db.run(
|
|
232
|
+
"INSERT INTO periods (period_id, total_cost, utilization, date) VALUES (?, ?, ?, ?)",
|
|
233
|
+
[periodId, 0, 0, "2025-12-09"],
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
const sessions = [
|
|
237
|
+
{ id: "session-1", cost: 10.0 },
|
|
238
|
+
{ id: "session-2", cost: 15.0 },
|
|
239
|
+
{ id: "session-3", cost: 8.0 },
|
|
240
|
+
];
|
|
241
|
+
|
|
242
|
+
for (const session of sessions) {
|
|
243
|
+
db.run(
|
|
244
|
+
"INSERT INTO sessions (session_id, total_cost, cwd, date, last_resets_at) VALUES (?, ?, ?, ?, ?)",
|
|
245
|
+
[session.id, session.cost, "/test", "2025-12-09", periodId],
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
db.run(
|
|
249
|
+
"INSERT INTO session_period_tracking (session_id, period_id, counted_cost, last_session_cost) VALUES (?, ?, ?, ?)",
|
|
250
|
+
[session.id, periodId, session.cost, session.cost],
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
db.run(
|
|
254
|
+
"UPDATE periods SET total_cost = total_cost + ? WHERE period_id = ?",
|
|
255
|
+
[session.cost, periodId],
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const period = db
|
|
260
|
+
.query<{ total_cost: number }, [string]>(
|
|
261
|
+
"SELECT total_cost FROM periods WHERE period_id = ?",
|
|
262
|
+
)
|
|
263
|
+
.get(periodId);
|
|
264
|
+
|
|
265
|
+
expect(period?.total_cost).toBe(33.0);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test("No double counting: continuing old session after restart", () => {
|
|
269
|
+
const sessionId = "session-1";
|
|
270
|
+
const periodId = "2025-12-09T10:00:00.000Z";
|
|
271
|
+
|
|
272
|
+
db.run(
|
|
273
|
+
"INSERT INTO sessions (session_id, total_cost, cwd, date, last_resets_at) VALUES (?, ?, ?, ?, ?)",
|
|
274
|
+
[sessionId, 10.0, "/test", "2025-12-09", periodId],
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
db.run(
|
|
278
|
+
"INSERT INTO session_period_tracking (session_id, period_id, counted_cost, last_session_cost) VALUES (?, ?, ?, ?)",
|
|
279
|
+
[sessionId, periodId, 10.0, 10.0],
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
db.run(
|
|
283
|
+
"INSERT INTO periods (period_id, total_cost, utilization, date) VALUES (?, ?, ?, ?)",
|
|
284
|
+
[periodId, 10.0, 0, "2025-12-09"],
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
const tracking = db
|
|
288
|
+
.query<{ last_session_cost: number }, [string, string]>(
|
|
289
|
+
"SELECT last_session_cost FROM session_period_tracking WHERE session_id = ? AND period_id = ?",
|
|
290
|
+
)
|
|
291
|
+
.get(sessionId, periodId);
|
|
292
|
+
|
|
293
|
+
const currentSessionCost = 10.0;
|
|
294
|
+
const delta = currentSessionCost - (tracking?.last_session_cost ?? 0);
|
|
295
|
+
|
|
296
|
+
expect(delta).toBe(0);
|
|
297
|
+
|
|
298
|
+
const period = db
|
|
299
|
+
.query<{ total_cost: number }, [string]>(
|
|
300
|
+
"SELECT total_cost FROM periods WHERE period_id = ?",
|
|
301
|
+
)
|
|
302
|
+
.get(periodId);
|
|
303
|
+
|
|
304
|
+
expect(period?.total_cost).toBe(10.0);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
describe("Smart Detection Logic", () => {
|
|
309
|
+
// Tests for the /clear vs independent session detection
|
|
310
|
+
// Key insight:
|
|
311
|
+
// - /clear creates NEW session with HIGH cost (billing continues)
|
|
312
|
+
// - Independent terminal creates NEW session with LOW cost
|
|
313
|
+
|
|
314
|
+
test("isClearContinuation: NEW session with cost > projectMax", () => {
|
|
315
|
+
const sessionCumulativeCounted = 0; // NEW session
|
|
316
|
+
const projectMaxCost = 5.0;
|
|
317
|
+
const newTotalCost = 10.0;
|
|
318
|
+
|
|
319
|
+
const isNewSession = sessionCumulativeCounted === 0;
|
|
320
|
+
const isClearContinuation = isNewSession && newTotalCost > projectMaxCost;
|
|
321
|
+
|
|
322
|
+
expect(isClearContinuation).toBe(true);
|
|
323
|
+
|
|
324
|
+
// Delta should be based on project max
|
|
325
|
+
const deltaCost = newTotalCost - projectMaxCost;
|
|
326
|
+
expect(deltaCost).toBe(5.0);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test("Independent terminal: NEW session with cost <= projectMax", () => {
|
|
330
|
+
const sessionCumulativeCounted = 0; // NEW session
|
|
331
|
+
const projectMaxCost = 5.0;
|
|
332
|
+
const newTotalCost = 3.0;
|
|
333
|
+
|
|
334
|
+
const isNewSession = sessionCumulativeCounted === 0;
|
|
335
|
+
const isClearContinuation = isNewSession && newTotalCost > projectMaxCost;
|
|
336
|
+
|
|
337
|
+
expect(isClearContinuation).toBe(false);
|
|
338
|
+
|
|
339
|
+
// Delta should be based on session tracking (which is 0 for new)
|
|
340
|
+
const deltaCost = Math.max(0, newTotalCost - sessionCumulativeCounted);
|
|
341
|
+
expect(deltaCost).toBe(3.0);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("Continuing session: uses session-level tracking even when surpassing projectMax", () => {
|
|
345
|
+
// This is the edge case that was bugged before
|
|
346
|
+
// Session B started with $3, now reports $8, projectMax is $5
|
|
347
|
+
const sessionCumulativeCounted = 3.0; // NOT new, has history
|
|
348
|
+
const projectMaxCost = 5.0;
|
|
349
|
+
const newTotalCost = 8.0;
|
|
350
|
+
|
|
351
|
+
const isNewSession = sessionCumulativeCounted === 0;
|
|
352
|
+
const isClearContinuation = isNewSession && newTotalCost > projectMaxCost;
|
|
353
|
+
|
|
354
|
+
// Should NOT be treated as /clear continuation because session has history
|
|
355
|
+
expect(isClearContinuation).toBe(false);
|
|
356
|
+
|
|
357
|
+
// Delta should be session-based: $8 - $3 = $5
|
|
358
|
+
const deltaCost = Math.max(0, newTotalCost - sessionCumulativeCounted);
|
|
359
|
+
expect(deltaCost).toBe(5.0);
|
|
360
|
+
|
|
361
|
+
// NOT the buggy project-based delta: $8 - $5 = $3
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test("Normal session continuation: uses session-level delta", () => {
|
|
365
|
+
const sessionCumulativeCounted = 10.0;
|
|
366
|
+
const projectMaxCost = 10.0;
|
|
367
|
+
const newTotalCost = 15.0;
|
|
368
|
+
|
|
369
|
+
const isNewSession = sessionCumulativeCounted === 0;
|
|
370
|
+
const isClearContinuation = isNewSession && newTotalCost > projectMaxCost;
|
|
371
|
+
|
|
372
|
+
expect(isClearContinuation).toBe(false);
|
|
373
|
+
|
|
374
|
+
const deltaCost = Math.max(0, newTotalCost - sessionCumulativeCounted);
|
|
375
|
+
expect(deltaCost).toBe(5.0);
|
|
376
|
+
});
|
|
377
|
+
});
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Fixed cost calculator - uses last chunk per message (fixes ccusage bug)
|
|
4
|
+
* Usage: bun run src/tools/fixed-cost-calc.ts [YYYY-MM-DD]
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
8
|
+
import { homedir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
|
|
11
|
+
// Pricing per million tokens
|
|
12
|
+
const PRICING: Record<
|
|
13
|
+
string,
|
|
14
|
+
{ input: number; output: number; cacheCreate: number; cacheRead: number }
|
|
15
|
+
> = {
|
|
16
|
+
"claude-sonnet-4-20250514": {
|
|
17
|
+
input: 3,
|
|
18
|
+
output: 15,
|
|
19
|
+
cacheCreate: 3.75,
|
|
20
|
+
cacheRead: 0.3,
|
|
21
|
+
},
|
|
22
|
+
"claude-opus-4-20250514": {
|
|
23
|
+
input: 15,
|
|
24
|
+
output: 75,
|
|
25
|
+
cacheCreate: 18.75,
|
|
26
|
+
cacheRead: 1.5,
|
|
27
|
+
},
|
|
28
|
+
"claude-opus-4-5-20251101": {
|
|
29
|
+
input: 5,
|
|
30
|
+
output: 25,
|
|
31
|
+
cacheCreate: 6.25,
|
|
32
|
+
cacheRead: 0.5,
|
|
33
|
+
},
|
|
34
|
+
"claude-haiku-4-5-20251001": {
|
|
35
|
+
input: 1,
|
|
36
|
+
output: 5,
|
|
37
|
+
cacheCreate: 1.25,
|
|
38
|
+
cacheRead: 0.1,
|
|
39
|
+
},
|
|
40
|
+
"claude-3-5-sonnet-20241022": {
|
|
41
|
+
input: 3,
|
|
42
|
+
output: 15,
|
|
43
|
+
cacheCreate: 3.75,
|
|
44
|
+
cacheRead: 0.3,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const DEFAULT_PRICING = {
|
|
49
|
+
input: 3,
|
|
50
|
+
output: 15,
|
|
51
|
+
cacheCreate: 3.75,
|
|
52
|
+
cacheRead: 0.3,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
interface UsageData {
|
|
56
|
+
input_tokens?: number;
|
|
57
|
+
output_tokens?: number;
|
|
58
|
+
cache_creation_input_tokens?: number;
|
|
59
|
+
cache_read_input_tokens?: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface MessageEntry {
|
|
63
|
+
timestamp: string;
|
|
64
|
+
type: string;
|
|
65
|
+
message?: {
|
|
66
|
+
id?: string;
|
|
67
|
+
model?: string;
|
|
68
|
+
usage?: UsageData;
|
|
69
|
+
};
|
|
70
|
+
requestId?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function findJsonlFiles(dir: string, targetDate: string): string[] {
|
|
74
|
+
const files: string[] = [];
|
|
75
|
+
|
|
76
|
+
function walk(currentDir: string) {
|
|
77
|
+
try {
|
|
78
|
+
const entries = readdirSync(currentDir);
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
const fullPath = join(currentDir, entry);
|
|
81
|
+
try {
|
|
82
|
+
const stat = statSync(fullPath);
|
|
83
|
+
if (stat.isDirectory()) {
|
|
84
|
+
walk(fullPath);
|
|
85
|
+
} else if (entry.endsWith(".jsonl")) {
|
|
86
|
+
// Check if file was modified on target date
|
|
87
|
+
const mtime = stat.mtime.toISOString().split("T")[0];
|
|
88
|
+
if (mtime === targetDate) {
|
|
89
|
+
files.push(fullPath);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
// Skip inaccessible files
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
// Skip inaccessible directories
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
walk(dir);
|
|
102
|
+
return files;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function parseJsonlFile(filePath: string): MessageEntry[] {
|
|
106
|
+
try {
|
|
107
|
+
const content = readFileSync(filePath, "utf-8");
|
|
108
|
+
const lines = content.split("\n").filter((line) => line.trim());
|
|
109
|
+
return lines
|
|
110
|
+
.map((line) => {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(line) as MessageEntry;
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
.filter((entry): entry is MessageEntry => entry !== null);
|
|
118
|
+
} catch {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function createUniqueHash(entry: MessageEntry): string | null {
|
|
124
|
+
const messageId = entry.message?.id;
|
|
125
|
+
const requestId = entry.requestId;
|
|
126
|
+
if (!messageId || !requestId) return null;
|
|
127
|
+
return `${messageId}:${requestId}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface TokenTotals {
|
|
131
|
+
input: number;
|
|
132
|
+
output: number;
|
|
133
|
+
cacheCreate: number;
|
|
134
|
+
cacheRead: number;
|
|
135
|
+
cost: number;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function main() {
|
|
139
|
+
const targetDate = process.argv[2] || new Date().toISOString().split("T")[0];
|
|
140
|
+
const projectFilter = process.argv[3]; // Optional: filter to specific project
|
|
141
|
+
const claudeDir = join(homedir(), ".claude", "projects");
|
|
142
|
+
|
|
143
|
+
console.log(`\n📊 Fixed Cost Calculator (Last-Chunk Method)`);
|
|
144
|
+
console.log(`📅 Date: ${targetDate}`);
|
|
145
|
+
|
|
146
|
+
let scanDir = claudeDir;
|
|
147
|
+
if (projectFilter) {
|
|
148
|
+
// Find matching project directory
|
|
149
|
+
const entries = readdirSync(claudeDir);
|
|
150
|
+
const match = entries.find((e) =>
|
|
151
|
+
e.toLowerCase().includes(projectFilter.toLowerCase()),
|
|
152
|
+
);
|
|
153
|
+
if (match) {
|
|
154
|
+
scanDir = join(claudeDir, match);
|
|
155
|
+
console.log(`📁 Project: ${match}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
console.log(`📁 Scanning: ${scanDir}\n`);
|
|
159
|
+
|
|
160
|
+
const files = findJsonlFiles(scanDir, targetDate);
|
|
161
|
+
console.log(`Found ${files.length} JSONL files modified on ${targetDate}\n`);
|
|
162
|
+
|
|
163
|
+
// Track last entry per unique hash (THE FIX)
|
|
164
|
+
const lastEntryPerHash = new Map<
|
|
165
|
+
string,
|
|
166
|
+
{ entry: MessageEntry; model: string }
|
|
167
|
+
>();
|
|
168
|
+
|
|
169
|
+
// Also track buggy first-entry for comparison
|
|
170
|
+
const firstEntryPerHash = new Map<
|
|
171
|
+
string,
|
|
172
|
+
{ entry: MessageEntry; model: string }
|
|
173
|
+
>();
|
|
174
|
+
|
|
175
|
+
for (const file of files) {
|
|
176
|
+
const entries = parseJsonlFile(file);
|
|
177
|
+
|
|
178
|
+
for (const entry of entries) {
|
|
179
|
+
if (entry.type !== "assistant" || !entry.message?.usage) continue;
|
|
180
|
+
|
|
181
|
+
const hash = createUniqueHash(entry);
|
|
182
|
+
if (!hash) continue;
|
|
183
|
+
|
|
184
|
+
const model = entry.message.model || "unknown";
|
|
185
|
+
|
|
186
|
+
// FIXED: Keep LAST entry (overwrite)
|
|
187
|
+
lastEntryPerHash.set(hash, { entry, model });
|
|
188
|
+
|
|
189
|
+
// BUGGY: Keep FIRST entry (skip if exists)
|
|
190
|
+
if (!firstEntryPerHash.has(hash)) {
|
|
191
|
+
firstEntryPerHash.set(hash, { entry, model });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Calculate totals per model - FIXED
|
|
197
|
+
const fixedTotals = new Map<string, TokenTotals>();
|
|
198
|
+
for (const { entry, model } of lastEntryPerHash.values()) {
|
|
199
|
+
const usage = entry.message?.usage;
|
|
200
|
+
if (!usage) continue;
|
|
201
|
+
|
|
202
|
+
if (!fixedTotals.has(model)) {
|
|
203
|
+
fixedTotals.set(model, {
|
|
204
|
+
input: 0,
|
|
205
|
+
output: 0,
|
|
206
|
+
cacheCreate: 0,
|
|
207
|
+
cacheRead: 0,
|
|
208
|
+
cost: 0,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const totals = fixedTotals.get(model)!;
|
|
213
|
+
totals.input += usage.input_tokens || 0;
|
|
214
|
+
totals.output += usage.output_tokens || 0;
|
|
215
|
+
totals.cacheCreate += usage.cache_creation_input_tokens || 0;
|
|
216
|
+
totals.cacheRead += usage.cache_read_input_tokens || 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Calculate totals per model - BUGGY
|
|
220
|
+
const buggyTotals = new Map<string, TokenTotals>();
|
|
221
|
+
for (const { entry, model } of firstEntryPerHash.values()) {
|
|
222
|
+
const usage = entry.message?.usage;
|
|
223
|
+
if (!usage) continue;
|
|
224
|
+
|
|
225
|
+
if (!buggyTotals.has(model)) {
|
|
226
|
+
buggyTotals.set(model, {
|
|
227
|
+
input: 0,
|
|
228
|
+
output: 0,
|
|
229
|
+
cacheCreate: 0,
|
|
230
|
+
cacheRead: 0,
|
|
231
|
+
cost: 0,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const totals = buggyTotals.get(model)!;
|
|
236
|
+
totals.input += usage.input_tokens || 0;
|
|
237
|
+
totals.output += usage.output_tokens || 0;
|
|
238
|
+
totals.cacheCreate += usage.cache_creation_input_tokens || 0;
|
|
239
|
+
totals.cacheRead += usage.cache_read_input_tokens || 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Calculate costs
|
|
243
|
+
function calcCost(totals: Map<string, TokenTotals>): number {
|
|
244
|
+
let totalCost = 0;
|
|
245
|
+
for (const [model, t] of totals) {
|
|
246
|
+
const pricing = PRICING[model] || DEFAULT_PRICING;
|
|
247
|
+
t.cost =
|
|
248
|
+
(t.input * pricing.input +
|
|
249
|
+
t.output * pricing.output +
|
|
250
|
+
t.cacheCreate * pricing.cacheCreate +
|
|
251
|
+
t.cacheRead * pricing.cacheRead) /
|
|
252
|
+
1_000_000;
|
|
253
|
+
totalCost += t.cost;
|
|
254
|
+
}
|
|
255
|
+
return totalCost;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const fixedTotal = calcCost(fixedTotals);
|
|
259
|
+
const buggyTotal = calcCost(buggyTotals);
|
|
260
|
+
|
|
261
|
+
// Display results
|
|
262
|
+
console.log("═".repeat(70));
|
|
263
|
+
console.log("FIXED CALCULATION (Last Chunk - Correct)");
|
|
264
|
+
console.log("═".repeat(70));
|
|
265
|
+
|
|
266
|
+
for (const [model, t] of fixedTotals) {
|
|
267
|
+
const shortModel = model
|
|
268
|
+
.replace("claude-", "")
|
|
269
|
+
.replace("-20251001", "")
|
|
270
|
+
.replace("-20251101", "")
|
|
271
|
+
.replace("-20250514", "")
|
|
272
|
+
.replace("-20241022", "");
|
|
273
|
+
console.log(`\n ${shortModel}:`);
|
|
274
|
+
console.log(
|
|
275
|
+
` Input: ${t.input.toLocaleString().padStart(12)} tokens`,
|
|
276
|
+
);
|
|
277
|
+
console.log(
|
|
278
|
+
` Output: ${t.output.toLocaleString().padStart(12)} tokens`,
|
|
279
|
+
);
|
|
280
|
+
console.log(
|
|
281
|
+
` Cache Create: ${t.cacheCreate.toLocaleString().padStart(12)} tokens`,
|
|
282
|
+
);
|
|
283
|
+
console.log(
|
|
284
|
+
` Cache Read: ${t.cacheRead.toLocaleString().padStart(12)} tokens`,
|
|
285
|
+
);
|
|
286
|
+
console.log(` Cost: $${t.cost.toFixed(2)}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
console.log(`\n ${"─".repeat(40)}`);
|
|
290
|
+
console.log(` TOTAL: $${fixedTotal.toFixed(2)}`);
|
|
291
|
+
|
|
292
|
+
// Comparison
|
|
293
|
+
console.log("\n");
|
|
294
|
+
console.log("═".repeat(70));
|
|
295
|
+
console.log("COMPARISON");
|
|
296
|
+
console.log("═".repeat(70));
|
|
297
|
+
|
|
298
|
+
let totalFixedOutput = 0;
|
|
299
|
+
let totalBuggyOutput = 0;
|
|
300
|
+
for (const t of fixedTotals.values()) totalFixedOutput += t.output;
|
|
301
|
+
for (const t of buggyTotals.values()) totalBuggyOutput += t.output;
|
|
302
|
+
|
|
303
|
+
console.log(`\n Fixed (correct): $${fixedTotal.toFixed(2)}`);
|
|
304
|
+
console.log(` Buggy (ccusage): $${buggyTotal.toFixed(2)}`);
|
|
305
|
+
console.log(
|
|
306
|
+
` Difference: $${(fixedTotal - buggyTotal).toFixed(2)} (${((1 - buggyTotal / fixedTotal) * 100).toFixed(1)}% underreported)`,
|
|
307
|
+
);
|
|
308
|
+
console.log(`\n Output tokens:`);
|
|
309
|
+
console.log(` Fixed: ${totalFixedOutput.toLocaleString()}`);
|
|
310
|
+
console.log(` Buggy: ${totalBuggyOutput.toLocaleString()}`);
|
|
311
|
+
console.log(
|
|
312
|
+
` Ratio: ${(totalFixedOutput / totalBuggyOutput).toFixed(1)}x undercount`,
|
|
313
|
+
);
|
|
314
|
+
console.log();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
main();
|