@hanzlaa/rcode 4.3.3 → 4.4.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.
Files changed (113) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/README.md +10 -4
  3. package/cli/doctor.js +21 -3
  4. package/cli/index.js +5 -1
  5. package/cli/install.js +2 -2
  6. package/cli/postinstall.js +1 -1
  7. package/cli/uninstall.js +48 -6
  8. package/dist/rcode.js +174 -170
  9. package/package.json +12 -22
  10. package/rcode/agents/rcode-codebase-mapper.md +12 -0
  11. package/rcode/agents/rcode-phase-researcher.md +13 -0
  12. package/rcode/agents/rcode-project-researcher.md +32 -0
  13. package/rcode/agents/rcode-roadmapper.md +15 -0
  14. package/rcode/agents/rules/planner/common-patterns.md +40 -0
  15. package/rcode/bin/lib/roadmap.cjs +184 -11
  16. package/rcode/bin/rcode-hooks.cjs +102 -151
  17. package/rcode/bin/rcode-tools.cjs +669 -55
  18. package/rcode/data/intent-table.json +87 -0
  19. package/rcode/modules/seo.yaml +22 -0
  20. package/rcode/references/project-types.yaml +75 -0
  21. package/rcode/skills/SKILLS_INDEX.md +17 -0
  22. package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/SKILL.md +4 -21
  23. package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/templates/heartbeat.sh +0 -0
  24. package/rcode/skills/actions/4-implementation/rcode-scaffold-project/SKILL.md +60 -1
  25. package/rcode/skills/core/rcode-init/scripts/__pycache__/rcode_init.cpython-38.pyc +0 -0
  26. package/rcode/skills/core/rcode-init/scripts/tests/__pycache__/test_rcode_init.cpython-38.pyc +0 -0
  27. package/rcode/skills/seo/module.yaml +20 -0
  28. package/rcode/skills/seo/on-page-seo-auditor/SKILL.md +308 -0
  29. package/rcode/skills/seo/on-page-seo-auditor/references/audit-example.md +109 -0
  30. package/rcode/skills/seo/on-page-seo-auditor/references/audit-templates.md +427 -0
  31. package/rcode/skills/seo/on-page-seo-auditor/references/bulk-audit-playbook.md +116 -0
  32. package/rcode/skills/seo/on-page-seo-auditor/references/scoring-rubric.md +525 -0
  33. package/rcode/skills/seo/rank-and-rent-local-seo/SKILL.md +94 -0
  34. package/rcode/skills/seo/rank-and-rent-local-seo/rules/city-matrix-and-pages.md +76 -0
  35. package/rcode/skills/seo/rank-and-rent-local-seo/rules/monetization.md +70 -0
  36. package/rcode/skills/seo/rank-and-rent-local-seo/rules/niche-selection.md +60 -0
  37. package/rcode/skills/seo/rank-and-rent-local-seo/rules/subniche-discovery.md +66 -0
  38. package/rcode/skills/seo/rank-and-rent-local-seo/templates/service-city-page.md +36 -0
  39. package/rcode/skills/seo/rank-and-rent-local-seo/templates/subniche-research-prompt.md +34 -0
  40. package/rcode/skills/seo/seo-audit/SKILL.md +412 -0
  41. package/rcode/skills/seo/seo-audit/evals/evals.json +136 -0
  42. package/rcode/skills/seo/seo-audit/references/ai-writing-detection.md +200 -0
  43. package/rcode/skills/seo/seo-content-factory/SKILL.md +130 -0
  44. package/rcode/skills/seo/seo-content-factory/rules/agents.md +80 -0
  45. package/rcode/skills/seo/seo-content-factory/rules/herdr-wave-mapping.md +80 -0
  46. package/rcode/skills/seo/seo-content-factory/rules/pipeline.md +102 -0
  47. package/rcode/skills/seo/seo-content-factory/rules/programmatic-pages.md +107 -0
  48. package/rcode/skills/seo/seo-content-factory/rules/quality-gates.md +68 -0
  49. package/rcode/skills/seo/seo-content-factory/rules/weekly-cadence.md +61 -0
  50. package/rcode/skills/seo/seo-content-factory/templates/BACKLOG.md +23 -0
  51. package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/01-funnel-A1-A4.md +63 -0
  52. package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/02-fanout-editorial-A5-A6-A8.md +28 -0
  53. package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/03-fanout-programmatic-A7-A6-A8.md +25 -0
  54. package/rcode/skills/seo/seo-content-factory/templates/agent-prompts/04-loop-A9-A10.md +34 -0
  55. package/rcode/skills/seo/seo-content-factory/templates/article.mdx +39 -0
  56. package/rcode/skills/seo/seo-content-factory/templates/cluster.schema.json +52 -0
  57. package/rcode/skills/seo/seo-content-factory/templates/content-brief.md +51 -0
  58. package/rcode/skills/seo/seo-content-factory/templates/jsonld-builders.ts +49 -0
  59. package/rcode/skills/seo/seo-content-factory/templates/keywords.csv +13 -0
  60. package/rcode/skills/seo/seo-content-factory/templates/programmatic-page.tsx +58 -0
  61. package/rcode/skills/seo/seo-content-writer/SKILL.md +263 -0
  62. package/rcode/skills/seo/seo-content-writer/references/content-structure-templates.md +875 -0
  63. package/rcode/skills/seo/seo-content-writer/references/instructions-detail.md +239 -0
  64. package/rcode/skills/seo/seo-content-writer/references/seo-writing-checklist.md +250 -0
  65. package/rcode/skills/seo/seo-content-writer/references/title-formulas.md +339 -0
  66. package/rcode/skills/seo/seo-growth-orchestrator/SKILL.md +79 -0
  67. package/rcode/skills/seo/seo-growth-orchestrator/rules/backlinks.md +29 -0
  68. package/rcode/skills/seo/seo-growth-orchestrator/rules/content-engine.md +27 -0
  69. package/rcode/skills/seo/seo-growth-orchestrator/rules/dos-and-donts.md +40 -0
  70. package/rcode/skills/seo/seo-growth-orchestrator/rules/goals-protocol.md +34 -0
  71. package/rcode/skills/seo/seo-growth-orchestrator/rules/local-seo-stack.md +35 -0
  72. package/rcode/skills/seo/seo-growth-orchestrator/rules/mrr-sprint.md +27 -0
  73. package/rcode/skills/seo/seo-growth-orchestrator/rules/tools.md +19 -0
  74. package/rcode/skills/seo/seo-growth-orchestrator/templates/backlink-research.md +29 -0
  75. package/rcode/skills/seo/seo-growth-orchestrator/templates/goal-protocol.md +35 -0
  76. package/rcode/skills/seo/seo-growth-orchestrator/templates/local-citations.md +24 -0
  77. package/rcode/skills/seo/seo-growth-orchestrator/templates/local-city-pages.md +27 -0
  78. package/rcode/skills/seo/seo-growth-orchestrator/templates/local-gbp-categories.md +23 -0
  79. package/rcode/skills/seo/seo-growth-orchestrator/templates/local-gsc-goldmine.md +27 -0
  80. package/rcode/skills/seo/seo-growth-orchestrator/templates/local-review-mining.md +26 -0
  81. package/rcode/skills/seo/seo-growth-orchestrator/templates/mrr-30day-plan.md +19 -0
  82. package/rcode/skills/seo/seo-growth-orchestrator/templates/mrr-cut.md +13 -0
  83. package/rcode/skills/seo/seo-growth-orchestrator/templates/mrr-opportunity-finder.md +17 -0
  84. package/rcode/skills/seo/seo-growth-orchestrator/templates/mrr-role-model.md +18 -0
  85. package/rcode/skills/seo/seo-site-builder/SKILL.md +149 -0
  86. package/rcode/skills/seo/seo-site-builder/rules/01-niche-discovery.md +64 -0
  87. package/rcode/skills/seo/seo-site-builder/rules/02-deep-research.md +164 -0
  88. package/rcode/skills/seo/seo-site-builder/rules/03-keyword-strategy.md +82 -0
  89. package/rcode/skills/seo/seo-site-builder/rules/04-content-plan.md +173 -0
  90. package/rcode/skills/seo/seo-site-builder/rules/05-site-build.md +187 -0
  91. package/rcode/skills/seo/seo-site-builder/rules/06-yolo.md +127 -0
  92. package/rcode/skills/seo/seo-site-builder/templates/article-stub.mdx +62 -0
  93. package/rcode/skills/seo/seo-site-builder/templates/image-prompt.md +97 -0
  94. package/rcode/skills/seo/seo-site-builder/templates/keyword-export.md +45 -0
  95. package/rcode/skills/seo/seo-site-builder/templates/niche-scorecard.md +28 -0
  96. package/rcode/skills/seo/technical-seo-checker/SKILL.md +329 -0
  97. package/rcode/skills/seo/technical-seo-checker/references/bulk-audit-playbook.md +118 -0
  98. package/rcode/skills/seo/technical-seo-checker/references/ecommerce-platform-patterns.md +166 -0
  99. package/rcode/skills/seo/technical-seo-checker/references/http-status-codes.md +705 -0
  100. package/rcode/skills/seo/technical-seo-checker/references/llm-crawler-handling.md +257 -0
  101. package/rcode/skills/seo/technical-seo-checker/references/pre-migration-playbook.md +137 -0
  102. package/rcode/skills/seo/technical-seo-checker/references/robots-txt-reference.md +717 -0
  103. package/rcode/skills/seo/technical-seo-checker/references/technical-audit-example.md +169 -0
  104. package/rcode/skills/seo/technical-seo-checker/references/technical-audit-templates.md +436 -0
  105. package/rcode/templates/settings-hooks.json +4 -0
  106. package/rcode/workflows/do.md +16 -0
  107. package/rcode/workflows/execute-sprint.md +22 -0
  108. package/rcode/workflows/execute.md +17 -3
  109. package/rcode/workflows/new-milestone.md +21 -9
  110. package/rcode/workflows/new-project-create-roadmap.md +2 -0
  111. package/rcode/workflows/new-project-roadmap.md +2 -0
  112. package/rcode/workflows/new-project.md +3 -0
  113. package/rcode/workflows/plan.md +15 -2
@@ -10,7 +10,9 @@
10
10
  * pre-compact — refresh HANDOFF.json before context compaction (#743)
11
11
  * stop-verify — syntax-check files changed during the response (#744)
12
12
  * cost-track — append per-response token usage to cost.jsonl (#745)
13
+ * stop — unified Stop hook: hedging-language detection (#744) + token logging (#745)
13
14
  * compact-nudge — advise /rcode-trim or /clear after N Edit/Write calls (#749)
15
+ * pre-tool-use — stderr warning before large file reads to avoid context bloat (#749)
14
16
  * prompt-router — nudge toward rcode commands for memory consistency (#892)
15
17
  *
16
18
  * All subcommands read stdin JSON from the hook execution context.
@@ -621,136 +623,15 @@ async function costTrack() {
621
623
  }
622
624
  }
623
625
 
624
- // ─────────────────────────────────────────────────────────────────────────────
625
- // INTENT_TABLE keyword map for prompt-router (#892)
626
- //
627
- // WHY: When a user types a free-form prompt that matches a known rcode workflow,
628
- // we nudge them toward the matching command so the outcome is captured in
629
- // .rcode/state.json. Work done outside rcode commands never lands in state.
630
- //
631
- // Single source of truth: rcode/workflows/do.md routing table (lines ~285-320,
632
- // "If the text describes..."). Keep in sync — see test/prompt-router-table-sync.test.cjs
633
- // (Sprint 38.3).
634
- //
635
- // Order: first-match-wins, mirroring do.md's "Apply the first matching rule".
636
- // More-specific keyword sets come before broad ones.
637
- // ─────────────────────────────────────────────────────────────────────────────
638
- const INTENT_TABLE = [
639
- // do.md: "Starting a new project, 'set up', 'initialize'" → /rcode-new-project
640
- {
641
- intent: 'new-project',
642
- keywords: ['set up a new project', 'initialize a new project', 'start a new project', 'create a new project'],
643
- command: '/rcode-new-project',
644
- },
645
- // do.md: "Mapping or analyzing an existing codebase" → /rcode-map-codebase
646
- {
647
- intent: 'map-codebase',
648
- keywords: ['map the codebase', 'map this codebase', 'analyze the codebase', 'analyse the codebase', 'map existing codebase'],
649
- command: '/rcode-map-codebase',
650
- },
651
- // do.md: "A bug, error, crash, failure, or something broken" → /rcode-debug
652
- // 'error' alone is too broad (matches "what does this error mean?" etc.).
653
- // Use multi-word forms that signal debug intent rather than a question.
654
- {
655
- intent: 'debug',
656
- keywords: ['bug', 'getting an error', 'throwing an error', 'error in the', 'fix the error', 'debug this', 'crash', 'failure', 'broken', 'not working', 'fails', 'exception', 'traceback'],
657
- command: '/rcode-debug',
658
- },
659
- // do.md: "Audit code quality, 'review changes', 'karpathy', 'check my diff', 'too complex'" → /rcode-review --karpathy
660
- {
661
- intent: 'audit-karpathy',
662
- keywords: ['audit', 'review changes', 'check my diff', 'karpathy', 'too complex', 'complexity', 'code review'],
663
- command: '/rcode-review --karpathy',
664
- },
665
- // do.md: "Make it simpler, 'be lazy', 'simplest solution', 'yagni', 'over-engineered'" → /rcode-lazy
666
- // Generative simplicity lens (before code is written); /rcode-trim removes bloat after.
667
- // 'simplify' alone is too broad (overlaps rcode-trim's existing-code territory) — use intent-bearing phrases.
668
- {
669
- intent: 'lazy',
670
- keywords: ['be lazy', 'lazy mode', 'simplest solution', 'yagni', 'over-engineered', 'over-engineering', 'kam code likho'],
671
- command: '/rcode-lazy',
672
- },
673
- // do.md: "Walk through a change, 'checkpoint', 'explain this diff', 'human review'" → /rcode-checkpoint-preview
674
- {
675
- intent: 'checkpoint',
676
- keywords: ['checkpoint', 'explain this diff', 'human review', 'walk through the change', 'walk through this change'],
677
- command: '/rcode-checkpoint-preview',
678
- },
679
- // do.md: "Brainstorm, generate ideas, 'explore options', 'what could we do'" → /rcode-brainstorm
680
- {
681
- intent: 'brainstorm',
682
- keywords: ['brainstorm', 'generate ideas', 'explore options', 'what could we do', 'ideate', 'ideas for'],
683
- command: '/rcode-brainstorm',
684
- },
685
- // do.md: "Exploring, researching, comparing, or 'how does X work'" → /rcode-research-phase
686
- // 'research' alone fires on "based on my research..." (past-tense reference, not navigation intent).
687
- // 'how does'/'how do' fire on any factual question — removed in favour of intent-bearing phrases.
688
- {
689
- intent: 'explore',
690
- keywords: ['explore', 'research phase', 'do some research', 'comparing', 'investigate', 'look into', 'understand how'],
691
- command: '/rcode-research-phase',
692
- },
693
- // do.md: "Scope unclear, 'which one', 'better UX', 'how should X look'" → /rcode-discuss-phase
694
- {
695
- intent: 'discuss',
696
- keywords: ['which one', 'better ux', 'how should', 'still have confusion', 'conflicting', 'discuss the scope', 'design this', 'architect this'],
697
- command: '/rcode-discuss-phase',
698
- },
699
- // do.md: "A complex task: refactoring, migration, multi-file architecture, system redesign,
700
- // integrating a new system/service" → /rcode-add-phase
701
- // 'integration'/'integrate' catch "let's do X integration", "integrate with Y" — feature-sized
702
- // architectural work that belongs in a phase, not an ad-hoc edit (#907).
703
- // Known mild false-positive: "run the integration tests" also matches → a harmless soft
704
- // nudge toward /rcode-add-phase. Accepted: catching real integration work outweighs it,
705
- // and no clean substring separates "X integration" from "integration test".
706
- {
707
- intent: 'add-phase',
708
- keywords: ['refactor', 'migration', 'multi-file', 'system redesign', 'multi file', 'large refactor', 'architectural', 'integration', 'integrate'],
709
- command: '/rcode-add-phase',
710
- },
711
- // do.md: "'Sprint planning', 'plan the sprint', 'next sprint'" → /rcode-sprint-planning
712
- {
713
- intent: 'sprint-planning',
714
- keywords: ['sprint planning', 'plan the sprint', 'next sprint', 'what\'s in this sprint', "what's in this sprint"],
715
- command: '/rcode-sprint-planning',
716
- },
717
- // do.md: "Executing a sprint, 'run the sprint', 'start sprint'" → /rcode-execute-sprint
718
- {
719
- intent: 'execute-sprint',
720
- keywords: ['run the sprint', 'start sprint', 'execute sprint', 'work on sprint'],
721
- command: '/rcode-execute-sprint',
722
- },
723
- // do.md: "Planning a specific phase, 'plan phase N'" → /rcode-plan
724
- {
725
- intent: 'plan',
726
- keywords: ["let's plan", 'plan phase', 'plan this', 'let me plan', 'planning phase', 'create a plan', 'please plan', 'plan and think', 'scope this', 'scope the feature'],
727
- command: '/rcode-plan',
728
- },
729
- // do.md: "'Create milestones', 'plan milestones', 'create roadmap'" → /rcode-new-milestone
730
- {
731
- intent: 'new-milestone',
732
- keywords: ['create milestones', 'plan milestones', 'create roadmap', 'break project into milestones', 'new milestone', 'what milestones'],
733
- command: '/rcode-new-milestone',
734
- },
735
- // do.md: "Break milestone into epics/stories, 'create stories', 'user stories', 'epics'" → /rcode-create-epics-and-stories
736
- {
737
- intent: 'epics-stories',
738
- keywords: ['create epics', 'user stories', 'create stories', 'epics and stories', 'break into epics'],
739
- command: '/rcode-create-epics-and-stories',
740
- },
741
- // do.md: "Drift / out-of-date / 'audit feature docs' / 'fill out existing PRD'" → /rcode-feature-drift
742
- {
743
- intent: 'feature-drift',
744
- keywords: ['out of date', 'out-of-date', 'verify docs', 'audit feature docs', 'fill out existing', 'prd drift', 'docs vs code'],
745
- command: '/rcode-feature-drift',
746
- },
747
- // do.md: "General audit / re-audit / extend / fill out / expand an existing artifact" → /rcode-audit
748
- {
749
- intent: 'audit',
750
- keywords: ['re-audit', 'extend the audit', 'fill out the', 'expand the', 're audit'],
751
- command: '/rcode-audit',
752
- },
753
- ];
626
+ // INTENT_TABLE — keyword map for prompt-router (#892).
627
+ // Source of truth: rcode/workflows/do.md routing table (~285-320). First-match-wins.
628
+ // Loaded from data file to keep this file under 1000 lines (#896).
629
+ const INTENT_TABLE = JSON.parse(
630
+ require('fs').readFileSync(
631
+ require('path').join(__dirname, '..', 'data', 'intent-table.json'),
632
+ 'utf8'
633
+ )
634
+ );
754
635
 
755
636
  /**
756
637
  * Inline flat-YAML parser — mirrors parseSimpleYaml in rcode-tools.cjs:91.
@@ -792,13 +673,8 @@ function readPromptNudgeToggle(cwd) {
792
673
  }
793
674
 
794
675
  /**
795
- * Determine whether a nudge is stale enough to fire under 'when-stale' mode.
796
- *
797
- * Heuristic: fire when .rcode/state.json exists AND its mtime is older than
798
- * the most recent git commit timestamp, OR when state.json is absent in a
799
- * .planning/ project. This is cheap and best-effort — if any check fails the
800
- * function returns true (treat as stale = fire). All I/O is wrapped in
801
- * try/catch to preserve the fail-open contract.
676
+ * Returns true when state.json is older than the last commit, or absent in a .planning/ project.
677
+ * Fail-open: returns true on any I/O error so the nudge fires rather than silently skips.
802
678
  */
803
679
  function isStateStaleFallbackTrue(cwd) {
804
680
  try {
@@ -830,14 +706,9 @@ function isStateStaleFallbackTrue(cwd) {
830
706
  }
831
707
 
832
708
  /**
833
- * prompt-router: Nudge user toward rcode commands for memory consistency (#892).
834
- *
835
- * Runs on UserPromptSubmit. Reads stdin JSON synchronously (mirror
836
- * cli/rcode-slash-router.cjs — NOT the async readInputJson() which rejects on
837
- * bad JSON). Keyword-matches against INTENT_TABLE (derived from
838
- * rcode/workflows/do.md lines ~285-320). On match, emits a one-line advisory
839
- * via hookSpecificOutput.additionalContext. Gated by prompt_nudge config toggle.
840
- * Always exits 0 with no output on any error or non-match.
709
+ * prompt-router: Nudge toward rcode commands for memory consistency (#892).
710
+ * Reads stdin synchronously (NOT async — rejects bad JSON). Keyword-matches INTENT_TABLE,
711
+ * emits additionalContext advisory. Gated by prompt_nudge config. Always exits 0.
841
712
  */
842
713
  function promptRouter() {
843
714
  try {
@@ -956,11 +827,7 @@ function promptRouter() {
956
827
 
957
828
  /**
958
829
  * compact-nudge: Advise /rcode-trim or /clear after N Edit/Write calls (#749).
959
- *
960
- * Triggered by the PreToolUse:Edit|Write hook. Maintains a per-session call
961
- * counter in a temp file and, once the count crosses RCODE_NUDGE_THRESHOLD
962
- * (default 50), prints an advisory to reclaim context budget. Purely
963
- * advisory — always exits 0, never blocks a tool call.
830
+ * Maintains a per-session counter; warns at RCODE_NUDGE_THRESHOLD (default 50). Advisory only.
964
831
  */
965
832
  async function compactNudge() {
966
833
  try {
@@ -998,6 +865,84 @@ async function compactNudge() {
998
865
  }
999
866
  }
1000
867
 
868
+ /** Returns true when a Read/Bash targets known large planning files (RESEARCH/SUMMARY/ROADMAP). */
869
+ function shouldNudgeCompact(toolName, toolInput) {
870
+ if (toolName !== 'Read' && toolName !== 'Bash') return false;
871
+ const target = toolInput?.file_path || toolInput?.command || '';
872
+ return /RESEARCH\.md|SUMMARY\.md|ROADMAP\.md/.test(target);
873
+ }
874
+
875
+ /**
876
+ * pre-tool-use: Strategic compact nudge before large file reads (#749).
877
+ *
878
+ * Triggered by the PreToolUse hook (Read + Bash tool names). Checks whether
879
+ * the tool call targets a known large planning file and, if so, writes an
880
+ * advisory line to stderr so the executor sees it without being interrupted.
881
+ * Always exits 0 — never blocks the tool call.
882
+ */
883
+ async function preToolUse() {
884
+ try {
885
+ const input = await readInputJson();
886
+ const toolName = input.tool_name || input.toolName || '';
887
+ const toolInput = input.tool_input || input.toolInput || {};
888
+
889
+ if (shouldNudgeCompact(toolName, toolInput)) {
890
+ process.stderr.write(
891
+ '[rcode] Context nearing limit — consider /compact before the next large file read\n'
892
+ );
893
+ }
894
+
895
+ process.exit(0);
896
+ } catch {
897
+ // Advisory hook must never break the session.
898
+ process.exit(0);
899
+ }
900
+ }
901
+
902
+ /**
903
+ * stop: Stop hook — hedging-language detection (#744) + token/cost logging (#745).
904
+ * Warns when response text suggests incomplete execution ("I'll implement this", etc.).
905
+ * Appends per-response token usage to ~/.rcode/logs/token-usage.jsonl.
906
+ * Rates: $3/M input, $15/M output (Sonnet 4.x approximation).
907
+ * Never blocks.
908
+ */
909
+ async function stopHandler() {
910
+ try {
911
+ const input = await readInputJson();
912
+ const responseText = input?.response || '';
913
+ const HEDGING_PATTERNS = [
914
+ /I'll\s+implement\s+this/i,
915
+ /I\s+would\s+add/i,
916
+ /you\s+could\s+add/i,
917
+ /TODO:/,
918
+ ];
919
+ const incomplete = HEDGING_PATTERNS.some((re) => re.test(responseText));
920
+ if (incomplete) {
921
+ process.stderr.write(
922
+ '[rcode] Stop hook: response contains hedging language — verify implementation is complete\n'
923
+ );
924
+ }
925
+ const usage = input?.usage;
926
+ if (usage && typeof usage === 'object') {
927
+ const logDir = path.join(os.homedir(), '.rcode', 'logs');
928
+ fs.mkdirSync(logDir, { recursive: true });
929
+ const entry = JSON.stringify({
930
+ ts: new Date().toISOString(),
931
+ input: usage.input_tokens || 0,
932
+ output: usage.output_tokens || 0,
933
+ cost_usd:
934
+ ((usage.input_tokens || 0) * 3) / 1e6 +
935
+ ((usage.output_tokens || 0) * 15) / 1e6,
936
+ });
937
+ fs.appendFileSync(path.join(logDir, 'token-usage.jsonl'), entry + '\n');
938
+ }
939
+ process.exit(0);
940
+ } catch (err) {
941
+ console.error(`Hook error: ${err.message}`);
942
+ process.exit(1);
943
+ }
944
+ }
945
+
1001
946
  /**
1002
947
  * Main entry point.
1003
948
  */
@@ -1026,15 +971,21 @@ async function main() {
1026
971
  case 'cost-track':
1027
972
  await costTrack();
1028
973
  break;
974
+ case 'stop':
975
+ await stopHandler();
976
+ break;
1029
977
  case 'compact-nudge':
1030
978
  await compactNudge();
1031
979
  break;
980
+ case 'pre-tool-use':
981
+ await preToolUse();
982
+ break;
1032
983
  case 'prompt-router':
1033
984
  promptRouter(); // synchronous — exits inside; never falls through to async path
1034
985
  break;
1035
986
  default:
1036
987
  console.error(`Unknown subcommand: ${subcommand}`);
1037
- console.error('Usage: rcode-hooks.cjs pre-edit|pre-workflow|post-commit|bash-guard|pre-compact|stop-verify|cost-track|compact-nudge|prompt-router');
988
+ console.error('Usage: rcode-hooks.cjs pre-edit|pre-workflow|post-commit|bash-guard|pre-compact|stop-verify|cost-track|stop|compact-nudge|pre-tool-use|prompt-router');
1038
989
  process.exit(1);
1039
990
  }
1040
991
  }