rhachet-roles-bhrain 0.2.0 → 0.3.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 (130) hide show
  1. package/dist/.test/getContextOpenAI.js +1 -1
  2. package/dist/.test/getContextOpenAI.js.map +1 -1
  3. package/dist/domain.operations/review/compileReviewPrompt.d.ts +22 -0
  4. package/dist/domain.operations/review/compileReviewPrompt.js +95 -0
  5. package/dist/domain.operations/review/compileReviewPrompt.js.map +1 -0
  6. package/dist/domain.operations/review/enumFilesFromDiffs.d.ts +8 -0
  7. package/dist/domain.operations/review/enumFilesFromDiffs.js +74 -0
  8. package/dist/domain.operations/review/enumFilesFromDiffs.js.map +1 -0
  9. package/dist/domain.operations/review/enumFilesFromGlob.d.ts +8 -0
  10. package/dist/domain.operations/review/enumFilesFromGlob.js +31 -0
  11. package/dist/domain.operations/review/enumFilesFromGlob.js.map +1 -0
  12. package/dist/domain.operations/review/estimateTokenCount.d.ts +9 -0
  13. package/dist/domain.operations/review/estimateTokenCount.js +20 -0
  14. package/dist/domain.operations/review/estimateTokenCount.js.map +1 -0
  15. package/dist/domain.operations/review/formatReviewOutput.d.ts +14 -0
  16. package/dist/domain.operations/review/formatReviewOutput.js +42 -0
  17. package/dist/domain.operations/review/formatReviewOutput.js.map +1 -0
  18. package/dist/domain.operations/review/genTokenBreakdownMarkdown.d.ts +19 -0
  19. package/dist/domain.operations/review/genTokenBreakdownMarkdown.js +110 -0
  20. package/dist/domain.operations/review/genTokenBreakdownMarkdown.js.map +1 -0
  21. package/dist/domain.operations/review/genTokenBreakdownReport.d.ts +24 -0
  22. package/dist/domain.operations/review/genTokenBreakdownReport.js +64 -0
  23. package/dist/domain.operations/review/genTokenBreakdownReport.js.map +1 -0
  24. package/dist/domain.operations/review/invokeClaudeCode.d.ts +22 -0
  25. package/dist/domain.operations/review/invokeClaudeCode.js +92 -0
  26. package/dist/domain.operations/review/invokeClaudeCode.js.map +1 -0
  27. package/dist/domain.operations/review/writeInputArtifacts.d.ts +27 -0
  28. package/dist/domain.operations/review/writeInputArtifacts.js +50 -0
  29. package/dist/domain.operations/review/writeInputArtifacts.js.map +1 -0
  30. package/dist/domain.operations/review/writeOutputArtifacts.d.ts +12 -0
  31. package/dist/domain.operations/review/writeOutputArtifacts.js +46 -0
  32. package/dist/domain.operations/review/writeOutputArtifacts.js.map +1 -0
  33. package/dist/roles/getRoleRegistry.js +2 -1
  34. package/dist/roles/getRoleRegistry.js.map +1 -1
  35. package/dist/roles/getRoleRegistry.readme.js +6 -0
  36. package/dist/roles/getRoleRegistry.readme.js.map +1 -1
  37. package/dist/roles/reviewer/briefs/review.tactics.md +60 -0
  38. package/dist/roles/reviewer/getReviewerRole.d.ts +6 -0
  39. package/dist/roles/reviewer/getReviewerRole.js +80 -0
  40. package/dist/roles/reviewer/getReviewerRole.js.map +1 -0
  41. package/dist/roles/reviewer/skills/review/review.d.ts +57 -0
  42. package/dist/roles/reviewer/skills/review/review.js +445 -0
  43. package/dist/roles/reviewer/skills/review/review.js.map +1 -0
  44. package/dist/roles/reviewer/skills/review/review.sh +21 -0
  45. package/dist/roles/reviewer/skills/review/review.ts +575 -0
  46. package/dist/roles/thinker/getThinkerRole.js +1 -1
  47. package/dist/roles/thinker/getThinkerRole.js.map +1 -1
  48. package/dist/roles/thinker/skills/brief.articulate/.demo/article.vision.v2025_08_19..i1.via_chatgpt.md +47 -0
  49. package/dist/roles/thinker/skills/brief.articulate/.demo/article.vision.v2025_08_19.i2.via_rhachet.md +60 -0
  50. package/dist/roles/thinker/skills/brief.articulate/.demo/diverge.v2025_08_17.i1.md +62 -0
  51. package/dist/roles/thinker/skills/brief.articulate/.demo/diverge.v2025_08_17.i1.with_feedback.md +89 -0
  52. package/dist/roles/thinker/skills/brief.articulate/.demo/diverge.v2025_08_17.i2.md +47 -0
  53. package/dist/roles/thinker/skills/brief.articulate/.demo/joke.v2025_08_15.i1.md +44 -0
  54. package/dist/roles/thinker/skills/brief.articulate/.demo/joke.v2025_08_15.i2.md +63 -0
  55. package/dist/roles/thinker/skills/brief.articulate/.demo/joke.v2025_08_15.i3.md +51 -0
  56. package/dist/roles/thinker/skills/brief.articulate/.demo/user-journey.v2025_08_17.i1.md +62 -0
  57. package/dist/roles/thinker/skills/brief.articulate/.demo/user-journey.v2025_08_17.i2.md +49 -0
  58. package/dist/roles/thinker/skills/brief.articulate/.readme.md +0 -0
  59. package/dist/roles/thinker/skills/brief.articulate/stepArticulate.skill.js +1 -1
  60. package/dist/roles/thinker/skills/brief.articulate/stepArticulate.skill.js.map +1 -1
  61. package/dist/roles/thinker/skills/brief.articulate/stepArticulate.skill.ts +168 -0
  62. package/dist/roles/thinker/skills/brief.articulate/stepArticulate.ts +157 -0
  63. package/dist/roles/thinker/skills/brief.catalogize/.demo/joke.types.v2025_08_28.i1.md +93 -0
  64. package/dist/roles/thinker/skills/brief.catalogize/.demo/joke.types.v2025_08_28.i2.md +84 -0
  65. package/dist/roles/thinker/skills/brief.catalogize/.demo/joke.types.v2025_09_28.i1.no_focus_context.md +8 -0
  66. package/dist/roles/thinker/skills/brief.catalogize/.demo/joke.types.v2025_09_28.i2.md +54 -0
  67. package/dist/roles/thinker/skills/brief.catalogize/.demo/persona.usecases.v2025_08_28.i1.md +62 -0
  68. package/dist/roles/thinker/skills/brief.catalogize/.demo/persona.usecases.v2025_08_28.i2.md +64 -0
  69. package/dist/roles/thinker/skills/brief.catalogize/.readme.md +5 -0
  70. package/dist/roles/thinker/skills/brief.catalogize/stepCatalogize.skill.js +1 -1
  71. package/dist/roles/thinker/skills/brief.catalogize/stepCatalogize.skill.js.map +1 -1
  72. package/dist/roles/thinker/skills/brief.catalogize/stepCatalogize.skill.ts +173 -0
  73. package/dist/roles/thinker/skills/brief.catalogize/stepCatalogize.ts +132 -0
  74. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.input.example.i4.md +3 -0
  75. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.input.example.i5.md +3 -0
  76. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.input.example.i6.md +3 -0
  77. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.input.example.md +3 -0
  78. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.v2025_08_27.i1.md +52 -0
  79. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.v2025_08_27.i2.md +51 -0
  80. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.v2025_08_27.i3.md +47 -0
  81. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.v2025_08_27.i4.md +62 -0
  82. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.v2025_08_27.i5.md +47 -0
  83. package/dist/roles/thinker/skills/brief.demonstrate/.demo/user.journey.roadtrip.v2025_08_27.i6.md +53 -0
  84. package/dist/roles/thinker/skills/brief.demonstrate/.readme +3 -0
  85. package/dist/roles/thinker/skills/brief.demonstrate/stepDemonstrate.skill.js +1 -1
  86. package/dist/roles/thinker/skills/brief.demonstrate/stepDemonstrate.skill.js.map +1 -1
  87. package/dist/roles/thinker/skills/brief.demonstrate/stepDemonstrate.skill.ts +190 -0
  88. package/dist/roles/thinker/skills/brief.demonstrate/stepDemonstrate.ts +164 -0
  89. package/dist/roles/thinker/skills/khue.cluster/.demo/user.journeys.input1.cluster.v2025_08_17.i1.md +72 -0
  90. package/dist/roles/thinker/skills/khue.cluster/.demo/user.journeys.input1.cluster.v2025_08_17.i2.md +53 -0
  91. package/dist/roles/thinker/skills/khue.cluster/.demo/user.journeys.input1.cluster.v2025_08_17.i3.which_objectives.md +58 -0
  92. package/dist/roles/thinker/skills/khue.cluster/.demo/user.journeys.input1.cluster.v2025_08_17.i5.which_personas.md +64 -0
  93. package/dist/roles/thinker/skills/khue.cluster/.demo/user.journeys.input2.cluster.v2025_08_17.i1.md +67 -0
  94. package/dist/roles/thinker/skills/khue.cluster/.demo/user.journeys.input2.cluster.v2025_08_17.i2.md +49 -0
  95. package/dist/roles/thinker/skills/khue.cluster/.demo/user.journeys.input2.cluster.v2025_08_17.i3.md +59 -0
  96. package/dist/roles/thinker/skills/khue.cluster/.readme.md +0 -0
  97. package/dist/roles/thinker/skills/khue.cluster/stepCluster.skill.js +1 -1
  98. package/dist/roles/thinker/skills/khue.cluster/stepCluster.skill.js.map +1 -1
  99. package/dist/roles/thinker/skills/khue.cluster/stepCluster.skill.ts +174 -0
  100. package/dist/roles/thinker/skills/khue.cluster/stepCluster.ts +150 -0
  101. package/dist/roles/thinker/skills/khue.decompose/.readme.md +9 -0
  102. package/dist/roles/thinker/skills/khue.diverge/.demo/joke.examples.v2025_08_17.i2.md +23 -0
  103. package/dist/roles/thinker/skills/khue.diverge/.demo/joke.examples.v2025_08_17.i3.md +23 -0
  104. package/dist/roles/thinker/skills/khue.diverge/.demo/joke.varieties.v2025_08_17.i1.md +23 -0
  105. package/dist/roles/thinker/skills/khue.diverge/.demo/userjourney.examples.v2025_08_17.i1.md +9 -0
  106. package/dist/roles/thinker/skills/khue.diverge/.demo/userjourney.examples.v2025_08_17.i2.md +9 -0
  107. package/dist/roles/thinker/skills/khue.diverge/.demo/userjourney.examples.v2025_08_17.i3.md +23 -0
  108. package/dist/roles/thinker/skills/khue.diverge/.demo/userjourney.examples.v2025_08_17.i4.folksy.md +9 -0
  109. package/dist/roles/thinker/skills/khue.diverge/.demo/userjourney.examples.v2025_08_17.i5.folksy.md +23 -0
  110. package/dist/roles/thinker/skills/khue.diverge/.readme.md +0 -0
  111. package/dist/roles/thinker/skills/khue.diverge/stepDiverge.skill.js +1 -1
  112. package/dist/roles/thinker/skills/khue.diverge/stepDiverge.skill.js.map +1 -1
  113. package/dist/roles/thinker/skills/khue.diverge/stepDiverge.skill.ts +149 -0
  114. package/dist/roles/thinker/skills/khue.diverge/stepDiverge.ts +151 -0
  115. package/dist/roles/thinker/skills/khue.encompose/.readme.md +7 -0
  116. package/dist/roles/thinker/skills/khue.instantiate/.readme.md +14 -0
  117. package/dist/roles/thinker/skills/khue.instantiate/stepInstantiate.skill.js +1 -1
  118. package/dist/roles/thinker/skills/khue.instantiate/stepInstantiate.skill.js.map +1 -1
  119. package/dist/roles/thinker/skills/khue.instantiate/stepInstantiate.skill.ts +190 -0
  120. package/dist/roles/thinker/skills/khue.instantiate/stepInstantiate.ts +132 -0
  121. package/dist/roles/thinker/skills/khue.triage/.demo/laughs.v2025_08_18.i1.md +29 -0
  122. package/dist/roles/thinker/skills/khue.triage/.demo/user.journeys.v2025_08_17.i1.md +86 -0
  123. package/dist/roles/thinker/skills/khue.triage/.demo/user.journeys.v2025_08_17.i2.md +68 -0
  124. package/dist/roles/thinker/skills/khue.triage/.readme.md +0 -0
  125. package/dist/roles/thinker/skills/khue.triage/stepTriage.skill.js +1 -1
  126. package/dist/roles/thinker/skills/khue.triage/stepTriage.skill.js.map +1 -1
  127. package/dist/roles/thinker/skills/khue.triage/stepTriage.skill.ts +174 -0
  128. package/dist/roles/thinker/skills/khue.triage/stepTriage.ts +153 -0
  129. package/package.json +7 -6
  130. package/readme.md +55 -0
@@ -5,7 +5,7 @@ const helpful_errors_1 = require("helpful-errors");
5
5
  const getContextOpenAI = () => ({
6
6
  openai: {
7
7
  auth: {
8
- key: process.env.PREP_OPENAI_KEY ??
8
+ key: process.env.OPENAI_API_KEY ??
9
9
  helpful_errors_1.UnexpectedCodePathError.throw('prep openai key not declared in env'),
10
10
  },
11
11
  llm: {
@@ -1 +1 @@
1
- {"version":3,"file":"getContextOpenAI.js","sourceRoot":"","sources":["../../src/.test/getContextOpenAI.ts"],"names":[],"mappings":";;;AAAA,mDAAyD;AAIlD,MAAM,gBAAgB,GAAG,GAAkB,EAAE,CAAC,CAAC;IACpD,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,GAAG,EACD,OAAO,CAAC,GAAG,CAAC,eAAe;gBAC3B,wCAAuB,CAAC,KAAK,CAAC,qCAAqC,CAAC;SACvE;QACD,GAAG,EAAE;YACH,mCAAmC;YACnC,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,OAAO;SAChB;KACF;CACF,CAAC,CAAC;AAbU,QAAA,gBAAgB,oBAa1B"}
1
+ {"version":3,"file":"getContextOpenAI.js","sourceRoot":"","sources":["../../src/.test/getContextOpenAI.ts"],"names":[],"mappings":";;;AAAA,mDAAyD;AAIlD,MAAM,gBAAgB,GAAG,GAAkB,EAAE,CAAC,CAAC;IACpD,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,GAAG,EACD,OAAO,CAAC,GAAG,CAAC,cAAc;gBAC1B,wCAAuB,CAAC,KAAK,CAAC,qCAAqC,CAAC;SACvE;QACD,GAAG,EAAE;YACH,mCAAmC;YACnC,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,OAAO;SAChB;KACF;CACF,CAAC,CAAC;AAbU,QAAA,gBAAgB,oBAa1B"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * .what = compiles the review prompt from rules and target files
3
+ * .why = prepares the prompt for brain invocation with token safeguards
4
+ */
5
+ export declare const compileReviewPrompt: (input: {
6
+ rules: Array<{
7
+ path: string;
8
+ content: string;
9
+ }>;
10
+ targets: Array<{
11
+ path: string;
12
+ content: string;
13
+ }>;
14
+ mode: 'soft' | 'hard';
15
+ contextWindowSize?: number;
16
+ }) => {
17
+ prompt: string;
18
+ tokenEstimate: number;
19
+ contextWindowPercent: number;
20
+ costEstimate: number;
21
+ warnings: string[];
22
+ };
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compileReviewPrompt = void 0;
4
+ const helpful_errors_1 = require("helpful-errors");
5
+ const estimateTokenCount_1 = require("./estimateTokenCount");
6
+ /**
7
+ * .what = compiles the review prompt from rules and target files
8
+ * .why = prepares the prompt for brain invocation with token safeguards
9
+ */
10
+ const compileReviewPrompt = (input) => {
11
+ // default context window size for claude
12
+ const contextWindow = input.contextWindowSize ?? 200000;
13
+ const warnings = [];
14
+ // build rules section (always include content for rules)
15
+ const rulesSection = input.rules
16
+ .map((rule) => `### ${rule.path}\n\n${rule.content}`)
17
+ .join('\n\n---\n\n');
18
+ // build target section based on mode
19
+ const targetSection = (() => {
20
+ if (input.mode === 'soft') {
21
+ // soft mode: paths only, instruct brain to open files
22
+ const pathList = input.targets.map((t) => `- ${t.path}`).join('\n');
23
+ return `the following files are in scope for review. please open and read them as needed:\n\n${pathList}`;
24
+ }
25
+ // hard mode: inject contents
26
+ return input.targets
27
+ .map((target) => `### ${target.path}\n\n\`\`\`\n${target.content}\n\`\`\``)
28
+ .join('\n\n---\n\n');
29
+ })();
30
+ // build full prompt
31
+ const prompt = `# review task
32
+
33
+ you are a reviewer. apply the rules below to the target files.
34
+
35
+ ## rules
36
+
37
+ <rules>
38
+ ${rulesSection}
39
+ </rules>
40
+
41
+ ## target
42
+
43
+ <target>
44
+ ${targetSection}
45
+ </target>
46
+
47
+ ## output format
48
+
49
+ emit your review as a JSON object with the following structure:
50
+
51
+ \`\`\`json
52
+ {
53
+ "issues": [
54
+ {
55
+ "type": "blocker" | "nitpick",
56
+ "message": "description of the issue",
57
+ "file": "path/to/file.ts",
58
+ "line": 42
59
+ }
60
+ ]
61
+ }
62
+ \`\`\`
63
+
64
+ emit blockers first, then nitpicks. if no issues found, emit an empty issues array.
65
+ `;
66
+ // estimate tokens
67
+ const tokenEstimate = (0, estimateTokenCount_1.estimateTokenCount)({ content: prompt });
68
+ const contextWindowPercent = (tokenEstimate / contextWindow) * 100;
69
+ // check thresholds (only in hard mode - soft mode is inherently lighter)
70
+ if (input.mode === 'hard') {
71
+ // failfast if >75%
72
+ if (contextWindowPercent > 75) {
73
+ throw new helpful_errors_1.BadRequestError(`prompt exceeds 75% of context window (${contextWindowPercent.toFixed(1)}% of ${contextWindow} tokens). ` +
74
+ `reduce scope or use --soft mode to avoid quality degradation.`, { tokenEstimate, contextWindowPercent, contextWindow });
75
+ }
76
+ // warn if >60%
77
+ if (contextWindowPercent > 60) {
78
+ warnings.push(`potential quality degradation: prompt uses ${contextWindowPercent.toFixed(1)}% of context window`);
79
+ }
80
+ }
81
+ // estimate cost (claude: ~$3/1M input tokens, ~$15/1M output tokens)
82
+ // assume output is ~10% of input for reviews
83
+ const inputCost = (tokenEstimate / 1000000) * 3;
84
+ const outputCost = ((tokenEstimate * 0.1) / 1000000) * 15;
85
+ const costEstimate = Math.round((inputCost + outputCost) * 1000) / 1000;
86
+ return {
87
+ prompt,
88
+ tokenEstimate,
89
+ contextWindowPercent: Math.round(contextWindowPercent * 10) / 10,
90
+ costEstimate,
91
+ warnings,
92
+ };
93
+ };
94
+ exports.compileReviewPrompt = compileReviewPrompt;
95
+ //# sourceMappingURL=compileReviewPrompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compileReviewPrompt.js","sourceRoot":"","sources":["../../../src/domain.operations/review/compileReviewPrompt.ts"],"names":[],"mappings":";;;AAAA,mDAAiD;AAEjD,6DAA0D;AAE1D;;;GAGG;AACI,MAAM,mBAAmB,GAAG,CAAC,KAKnC,EAMC,EAAE;IACF,yCAAyC;IACzC,MAAM,aAAa,GAAG,KAAK,CAAC,iBAAiB,IAAI,MAAM,CAAC;IACxD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,yDAAyD;IACzD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK;SAC7B,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;SACpD,IAAI,CAAC,aAAa,CAAC,CAAC;IAEvB,qCAAqC;IACrC,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE;QAC1B,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC1B,sDAAsD;YACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpE,OAAO,wFAAwF,QAAQ,EAAE,CAAC;QAC5G,CAAC;QAED,6BAA6B;QAC7B,OAAO,KAAK,CAAC,OAAO;aACjB,GAAG,CACF,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,MAAM,CAAC,IAAI,eAAe,MAAM,CAAC,OAAO,UAAU,CACtE;aACA,IAAI,CAAC,aAAa,CAAC,CAAC;IACzB,CAAC,CAAC,EAAE,CAAC;IAEL,oBAAoB;IACpB,MAAM,MAAM,GAAG;;;;;;;EAOf,YAAY;;;;;;EAMZ,aAAa;;;;;;;;;;;;;;;;;;;;;CAqBd,CAAC;IAEA,kBAAkB;IAClB,MAAM,aAAa,GAAG,IAAA,uCAAkB,EAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9D,MAAM,oBAAoB,GAAG,CAAC,aAAa,GAAG,aAAa,CAAC,GAAG,GAAG,CAAC;IAEnE,yEAAyE;IACzE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,mBAAmB;QACnB,IAAI,oBAAoB,GAAG,EAAE,EAAE,CAAC;YAC9B,MAAM,IAAI,gCAAe,CACvB,yCAAyC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,aAAa,YAAY;gBACvG,+DAA+D,EACjE,EAAE,aAAa,EAAE,oBAAoB,EAAE,aAAa,EAAE,CACvD,CAAC;QACJ,CAAC;QAED,eAAe;QACf,IAAI,oBAAoB,GAAG,EAAE,EAAE,CAAC;YAC9B,QAAQ,CAAC,IAAI,CACX,8CAA8C,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CACnG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qEAAqE;IACrE,6CAA6C;IAC7C,MAAM,SAAS,GAAG,CAAC,aAAa,GAAG,OAAS,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,CAAC,CAAC,aAAa,GAAG,GAAG,CAAC,GAAG,OAAS,CAAC,GAAG,EAAE,CAAC;IAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAExE,OAAO;QACL,MAAM;QACN,aAAa;QACb,oBAAoB,EAAE,IAAI,CAAC,KAAK,CAAC,oBAAoB,GAAG,EAAE,CAAC,GAAG,EAAE;QAChE,YAAY;QACZ,QAAQ;KACT,CAAC;AACJ,CAAC,CAAC;AA9GW,QAAA,mBAAmB,uBA8G9B"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * .what = enumerates files changed in a git diff range
3
+ * .why = supports --diffs input for reviewing changed files
4
+ */
5
+ export declare const enumFilesFromDiffs: (input: {
6
+ range: 'uptil-main' | 'uptil-commit' | 'uptil-staged';
7
+ cwd?: string;
8
+ }) => Promise<string[]>;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.enumFilesFromDiffs = void 0;
27
+ const child_process_1 = require("child_process");
28
+ const fs = __importStar(require("fs/promises"));
29
+ const helpful_errors_1 = require("helpful-errors");
30
+ const path = __importStar(require("path"));
31
+ /**
32
+ * .what = enumerates files changed in a git diff range
33
+ * .why = supports --diffs input for reviewing changed files
34
+ */
35
+ const enumFilesFromDiffs = async (input) => {
36
+ const cwd = input.cwd ?? process.cwd();
37
+ // build git command based on range
38
+ const gitCommand = (() => {
39
+ if (input.range === 'uptil-main') {
40
+ return 'git diff main --name-only';
41
+ }
42
+ if (input.range === 'uptil-commit') {
43
+ return 'git diff HEAD --name-only';
44
+ }
45
+ if (input.range === 'uptil-staged') {
46
+ return 'git diff --staged --name-only';
47
+ }
48
+ throw new helpful_errors_1.UnexpectedCodePathError('invalid range', { range: input.range });
49
+ })();
50
+ // execute git command
51
+ const output = (0, child_process_1.execSync)(gitCommand, {
52
+ cwd,
53
+ encoding: 'utf-8',
54
+ });
55
+ // parse output into file paths
56
+ const paths = output
57
+ .split('\n')
58
+ .map((line) => line.trim())
59
+ .filter((line) => line.length > 0);
60
+ // filter to only include files (exclude directories and symlinks to directories)
61
+ const files = await Promise.all(paths.map(async (filePath) => {
62
+ try {
63
+ const stat = await fs.stat(path.join(cwd, filePath));
64
+ return stat.isFile() ? filePath : null;
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }));
70
+ // return sorted, deduplicated file paths
71
+ return [...new Set(files.filter((f) => f !== null))].sort();
72
+ };
73
+ exports.enumFilesFromDiffs = enumFilesFromDiffs;
74
+ //# sourceMappingURL=enumFilesFromDiffs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enumFilesFromDiffs.js","sourceRoot":"","sources":["../../../src/domain.operations/review/enumFilesFromDiffs.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAyC;AACzC,gDAAkC;AAClC,mDAAyD;AACzD,2CAA6B;AAE7B;;;GAGG;AACI,MAAM,kBAAkB,GAAG,KAAK,EAAE,KAGxC,EAAqB,EAAE;IACtB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEvC,mCAAmC;IACnC,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE;QACvB,IAAI,KAAK,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;YACjC,OAAO,2BAA2B,CAAC;QACrC,CAAC;QACD,IAAI,KAAK,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC;YACnC,OAAO,2BAA2B,CAAC;QACrC,CAAC;QACD,IAAI,KAAK,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC;YACnC,OAAO,+BAA+B,CAAC;QACzC,CAAC;QACD,MAAM,IAAI,wCAAuB,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC,EAAE,CAAC;IAEL,sBAAsB;IACtB,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,UAAU,EAAE;QAClC,GAAG;QACH,QAAQ,EAAE,OAAO;KAClB,CAAC,CAAC;IAEH,+BAA+B;IAC/B,MAAM,KAAK,GAAG,MAAM;SACjB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAErC,iFAAiF;IACjF,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;YACrD,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,yCAAyC;IACzC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3E,CAAC,CAAC;AA9CW,QAAA,kBAAkB,sBA8C7B"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * .what = enumerates files matching a glob pattern
3
+ * .why = supports --rules and --paths inputs for file discovery
4
+ */
5
+ export declare const enumFilesFromGlob: (input: {
6
+ glob: string | string[];
7
+ cwd?: string;
8
+ }) => Promise<string[]>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.enumFilesFromGlob = void 0;
7
+ const fast_glob_1 = __importDefault(require("fast-glob"));
8
+ /**
9
+ * .what = enumerates files matching a glob pattern
10
+ * .why = supports --rules and --paths inputs for file discovery
11
+ */
12
+ const enumFilesFromGlob = async (input) => {
13
+ // normalize to array
14
+ const patterns = Array.isArray(input.glob) ? input.glob : [input.glob];
15
+ // separate positive and negative patterns
16
+ const positivePatterns = patterns.filter((p) => !p.startsWith('!'));
17
+ const negativePatterns = patterns
18
+ .filter((p) => p.startsWith('!'))
19
+ .map((p) => p.slice(1)); // remove ! prefix for ignore
20
+ // enumerate files
21
+ const files = await (0, fast_glob_1.default)(positivePatterns, {
22
+ cwd: input.cwd,
23
+ ignore: negativePatterns,
24
+ onlyFiles: true,
25
+ dot: true, // include dotfiles
26
+ });
27
+ // return sorted, deduplicated paths
28
+ return [...new Set(files)].sort();
29
+ };
30
+ exports.enumFilesFromGlob = enumFilesFromGlob;
31
+ //# sourceMappingURL=enumFilesFromGlob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enumFilesFromGlob.js","sourceRoot":"","sources":["../../../src/domain.operations/review/enumFilesFromGlob.ts"],"names":[],"mappings":";;;;;;AAAA,0DAA2B;AAE3B;;;GAGG;AACI,MAAM,iBAAiB,GAAG,KAAK,EAAE,KAGvC,EAAqB,EAAE;IACtB,qBAAqB;IACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEvE,0CAA0C;IAC1C,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IACpE,MAAM,gBAAgB,GAAG,QAAQ;SAC9B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,6BAA6B;IAExD,kBAAkB;IAClB,MAAM,KAAK,GAAG,MAAM,IAAA,mBAAE,EAAC,gBAAgB,EAAE;QACvC,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,gBAAgB;QACxB,SAAS,EAAE,IAAI;QACf,GAAG,EAAE,IAAI,EAAE,mBAAmB;KAC/B,CAAC,CAAC;IAEH,oCAAoC;IACpC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACpC,CAAC,CAAC;AAvBW,QAAA,iBAAiB,qBAuB5B"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * .what = estimates the token count of a string using a heuristic
3
+ * .why = enables context window calculations without external dependencies
4
+ *
5
+ * .note = uses ~4 chars per token heuristic which aligns with typical LLM tokenizers
6
+ */
7
+ export declare const estimateTokenCount: (input: {
8
+ content: string;
9
+ }) => number;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.estimateTokenCount = void 0;
4
+ /**
5
+ * .what = estimates the token count of a string using a heuristic
6
+ * .why = enables context window calculations without external dependencies
7
+ *
8
+ * .note = uses ~4 chars per token heuristic which aligns with typical LLM tokenizers
9
+ */
10
+ const estimateTokenCount = (input) => {
11
+ // handle empty content
12
+ if (!input.content)
13
+ return 0;
14
+ // estimate tokens using chars/4 heuristic (common for english text + code)
15
+ const charCount = input.content.length;
16
+ const estimatedTokens = Math.ceil(charCount / 4);
17
+ return estimatedTokens;
18
+ };
19
+ exports.estimateTokenCount = estimateTokenCount;
20
+ //# sourceMappingURL=estimateTokenCount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimateTokenCount.js","sourceRoot":"","sources":["../../../src/domain.operations/review/estimateTokenCount.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACI,MAAM,kBAAkB,GAAG,CAAC,KAA0B,EAAU,EAAE;IACvE,uBAAuB;IACvB,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO,CAAC,CAAC;IAE7B,2EAA2E;IAC3E,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;IACvC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAEjD,OAAO,eAAe,CAAC;AACzB,CAAC,CAAC;AATW,QAAA,kBAAkB,sBAS7B"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * .what = formats brain response into review markdown
3
+ * .why = ensures consistent, machine-parseable review output
4
+ */
5
+ export declare const formatReviewOutput: (input: {
6
+ response: {
7
+ issues: Array<{
8
+ type: 'blocker' | 'nitpick';
9
+ message: string;
10
+ file?: string;
11
+ line?: number;
12
+ }>;
13
+ };
14
+ }) => string;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatReviewOutput = void 0;
4
+ /**
5
+ * .what = formats brain response into review markdown
6
+ * .why = ensures consistent, machine-parseable review output
7
+ */
8
+ const formatReviewOutput = (input) => {
9
+ // handle empty or missing issues
10
+ const issues = input.response?.issues ?? [];
11
+ if (!issues.length) {
12
+ return '# review complete\n\nno issues found.\n';
13
+ }
14
+ // separate blockers and nitpicks
15
+ const blockers = issues.filter((f) => f.type === 'blocker');
16
+ const nitpicks = issues.filter((f) => f.type === 'nitpick');
17
+ // build output with blockers first (per template)
18
+ const sections = [];
19
+ // emit blockers
20
+ blockers.forEach((issue, index) => {
21
+ const header = `# blocker.${index + 1}`;
22
+ const location = issue.file
23
+ ? issue.line
24
+ ? `\n\n**location**: ${issue.file}:${issue.line}`
25
+ : `\n\n**location**: ${issue.file}`
26
+ : '';
27
+ sections.push(`${header}${location}\n\n${issue.message}`);
28
+ });
29
+ // emit nitpicks
30
+ nitpicks.forEach((issue, index) => {
31
+ const header = `# nitpick.${index + 1}`;
32
+ const location = issue.file
33
+ ? issue.line
34
+ ? `\n\n**location**: ${issue.file}:${issue.line}`
35
+ : `\n\n**location**: ${issue.file}`
36
+ : '';
37
+ sections.push(`${header}${location}\n\n${issue.message}`);
38
+ });
39
+ return sections.join('\n\n---\n\n') + '\n';
40
+ };
41
+ exports.formatReviewOutput = formatReviewOutput;
42
+ //# sourceMappingURL=formatReviewOutput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatReviewOutput.js","sourceRoot":"","sources":["../../../src/domain.operations/review/formatReviewOutput.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACI,MAAM,kBAAkB,GAAG,CAAC,KASlC,EAAU,EAAE;IACX,iCAAiC;IACjC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,yCAAyC,CAAC;IACnD,CAAC;IAED,iCAAiC;IACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAE5D,kDAAkD;IAClD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,gBAAgB;IAChB,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAChC,MAAM,MAAM,GAAG,aAAa,KAAK,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI;YACzB,CAAC,CAAC,KAAK,CAAC,IAAI;gBACV,CAAC,CAAC,qBAAqB,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE;gBACjD,CAAC,CAAC,qBAAqB,KAAK,CAAC,IAAI,EAAE;YACrC,CAAC,CAAC,EAAE,CAAC;QACP,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,gBAAgB;IAChB,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAChC,MAAM,MAAM,GAAG,aAAa,KAAK,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI;YACzB,CAAC,CAAC,KAAK,CAAC,IAAI;gBACV,CAAC,CAAC,qBAAqB,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE;gBACjD,CAAC,CAAC,qBAAqB,KAAK,CAAC,IAAI,EAAE;YACrC,CAAC,CAAC,EAAE,CAAC;QACP,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;AAC7C,CAAC,CAAC;AA9CW,QAAA,kBAAkB,sBA8C7B"}
@@ -0,0 +1,19 @@
1
+ import type { TokenBreakdownEntry } from './genTokenBreakdownReport';
2
+ /**
3
+ * .what = generates a markdown tree view of token breakdown
4
+ * .why = enables easy visual comprehension of token distribution
5
+ */
6
+ export declare const genTokenBreakdownMarkdown: (input: {
7
+ all: {
8
+ entries: TokenBreakdownEntry[];
9
+ total: number;
10
+ };
11
+ rules: {
12
+ entries: TokenBreakdownEntry[];
13
+ total: number;
14
+ };
15
+ targets: {
16
+ entries: TokenBreakdownEntry[];
17
+ total: number;
18
+ };
19
+ }) => string;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.genTokenBreakdownMarkdown = void 0;
4
+ /**
5
+ * .what = generates a markdown tree view of token breakdown
6
+ * .why = enables easy visual comprehension of token distribution
7
+ */
8
+ const genTokenBreakdownMarkdown = (input) => {
9
+ const lines = [];
10
+ lines.push('# token breakdown');
11
+ lines.push('');
12
+ lines.push(`total: ${formatTokens(input.all.total)} tokens`);
13
+ lines.push('');
14
+ // render blended all section
15
+ lines.push('## all');
16
+ lines.push('');
17
+ lines.push('```');
18
+ lines.push(...renderTree(input.all.entries, input.all.total));
19
+ lines.push('```');
20
+ lines.push('');
21
+ // render rules section
22
+ lines.push('## rules');
23
+ lines.push('');
24
+ lines.push(`total: ${formatTokens(input.rules.total)} tokens`);
25
+ lines.push('');
26
+ lines.push('```');
27
+ lines.push(...renderTree(input.rules.entries, input.all.total));
28
+ lines.push('```');
29
+ lines.push('');
30
+ // render targets section
31
+ lines.push('## targets');
32
+ lines.push('');
33
+ lines.push(`total: ${formatTokens(input.targets.total)} tokens`);
34
+ lines.push('');
35
+ lines.push('```');
36
+ lines.push(...renderTree(input.targets.entries, input.all.total));
37
+ lines.push('```');
38
+ return lines.join('\n');
39
+ };
40
+ exports.genTokenBreakdownMarkdown = genTokenBreakdownMarkdown;
41
+ /**
42
+ * .what = formats token count for display
43
+ * .why = human-readable numbers
44
+ */
45
+ const formatTokens = (tokens) => {
46
+ if (tokens >= 1000000)
47
+ return `${(tokens / 1000000).toFixed(1)}M`;
48
+ if (tokens >= 1000)
49
+ return `${(tokens / 1000).toFixed(1)}k`;
50
+ return `${tokens}`;
51
+ };
52
+ /**
53
+ * .what = renders entries as a tree structure
54
+ * .why = visual hierarchy of token consumption
55
+ */
56
+ const renderTree = (entries, grandTotal) => {
57
+ // build tree structure
58
+ const root = {
59
+ name: '',
60
+ tokens: 0,
61
+ children: new Map(),
62
+ isFile: false,
63
+ };
64
+ for (const entry of entries) {
65
+ if (entry.type !== 'FILE')
66
+ continue;
67
+ const parts = entry.path.split('/');
68
+ let current = root;
69
+ for (let i = 0; i < parts.length; i++) {
70
+ const part = parts[i];
71
+ const isLast = i === parts.length - 1;
72
+ if (!current.children.has(part)) {
73
+ current.children.set(part, {
74
+ name: part,
75
+ tokens: 0,
76
+ children: new Map(),
77
+ isFile: isLast,
78
+ });
79
+ }
80
+ const child = current.children.get(part);
81
+ child.tokens += entry.tokens;
82
+ current = child;
83
+ }
84
+ }
85
+ // render tree recursively
86
+ const lines = [];
87
+ renderNode(root, '', true, grandTotal, lines);
88
+ return lines;
89
+ };
90
+ /**
91
+ * .what = recursively renders a tree node
92
+ * .why = builds visual tree output
93
+ */
94
+ const renderNode = (node, prefix, isRoot, grandTotal, lines) => {
95
+ // sort children by tokens desc
96
+ const children = Array.from(node.children.values()).sort((a, b) => b.tokens - a.tokens);
97
+ for (let i = 0; i < children.length; i++) {
98
+ const child = children[i];
99
+ const isLast = i === children.length - 1;
100
+ const branch = isLast ? '└─' : '├─';
101
+ const childPrefix = isLast ? ' ' : '│ ';
102
+ const pct = ((child.tokens / grandTotal) * 100).toFixed(1);
103
+ const suffix = child.isFile ? '' : '/';
104
+ lines.push(`${prefix}${branch} ${child.name}${suffix} (${formatTokens(child.tokens)}, ${pct}%)`);
105
+ if (!child.isFile && child.children.size > 0) {
106
+ renderNode(child, prefix + childPrefix, false, grandTotal, lines);
107
+ }
108
+ }
109
+ };
110
+ //# sourceMappingURL=genTokenBreakdownMarkdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genTokenBreakdownMarkdown.js","sourceRoot":"","sources":["../../../src/domain.operations/review/genTokenBreakdownMarkdown.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACI,MAAM,yBAAyB,GAAG,CAAC,KAIzC,EAAU,EAAE;IACX,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAChC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,UAAU,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,6BAA6B;IAC7B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,uBAAuB;IACvB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,UAAU,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,yBAAyB;IACzB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,UAAU,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACjE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAClE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAElB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC,CAAC;AAxCW,QAAA,yBAAyB,6BAwCpC;AAEF;;;GAGG;AACH,MAAM,YAAY,GAAG,CAAC,MAAc,EAAU,EAAE;IAC9C,IAAI,MAAM,IAAI,OAAS;QAAE,OAAO,GAAG,CAAC,MAAM,GAAG,OAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACtE,IAAI,MAAM,IAAI,IAAK;QAAE,OAAO,GAAG,CAAC,MAAM,GAAG,IAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9D,OAAO,GAAG,MAAM,EAAE,CAAC;AACrB,CAAC,CAAC;AAaF;;;GAGG;AACH,MAAM,UAAU,GAAG,CACjB,OAA8B,EAC9B,UAAkB,EACR,EAAE;IACZ,uBAAuB;IACvB,MAAM,IAAI,GAAa;QACrB,IAAI,EAAE,EAAE;QACR,MAAM,EAAE,CAAC;QACT,QAAQ,EAAE,IAAI,GAAG,EAAE;QACnB,MAAM,EAAE,KAAK;KACd,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,OAAO,GAAG,IAAI,CAAC;QAEnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;YACvB,MAAM,MAAM,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;YAEtC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE;oBACzB,IAAI,EAAE,IAAI;oBACV,MAAM,EAAE,CAAC;oBACT,QAAQ,EAAE,IAAI,GAAG,EAAE;oBACnB,MAAM,EAAE,MAAM;iBACf,CAAC,CAAC;YACL,CAAC;YAED,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;YAC1C,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;YAC7B,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,UAAU,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,GAAG,CACjB,IAAc,EACd,MAAc,EACd,MAAe,EACf,UAAkB,EAClB,KAAe,EACT,EAAE;IACR,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CACtD,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAC9B,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,CAAC,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACpC,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QAC3C,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAEvC,KAAK,CAAC,IAAI,CACR,GAAG,MAAM,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,GAAG,MAAM,KAAK,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CACrF,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC7C,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * .what = content entry for token breakdown
3
+ * .why = enables analysis of which files consume most tokens
4
+ */
5
+ export interface TokenBreakdownEntry {
6
+ path: string;
7
+ type: 'FILE' | 'DIRECTORY';
8
+ tokens: number;
9
+ tokensHuman: string;
10
+ tokensScale: string;
11
+ }
12
+ /**
13
+ * .what = generates token breakdown report grouped by directory
14
+ * .why = helps identify which files/dirs consume most context window
15
+ */
16
+ export declare const genTokenBreakdownReport: (input: {
17
+ files: Array<{
18
+ path: string;
19
+ content: string;
20
+ }>;
21
+ }) => {
22
+ entries: TokenBreakdownEntry[];
23
+ total: number;
24
+ };
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.genTokenBreakdownReport = void 0;
4
+ const estimateTokenCount_1 = require("./estimateTokenCount");
5
+ /**
6
+ * .what = formats token count for human readability
7
+ * .why = makes large numbers easier to scan
8
+ */
9
+ const formatTokens = (tokens) => {
10
+ if (tokens >= 1000000)
11
+ return `${(tokens / 1000000).toFixed(1)}M`;
12
+ if (tokens >= 1000)
13
+ return `${(tokens / 1000).toFixed(1)}k`;
14
+ return `${tokens}`;
15
+ };
16
+ /**
17
+ * .what = rounds to hundredths for percentage display
18
+ * .why = consistent precision in scale values
19
+ */
20
+ const roundToHundredths = (num) => Math.round(num * 100) / 100;
21
+ /**
22
+ * .what = generates token breakdown report grouped by directory
23
+ * .why = helps identify which files/dirs consume most context window
24
+ */
25
+ const genTokenBreakdownReport = (input) => {
26
+ // calculate tokens per file
27
+ const fileEntries = input.files.map((file) => {
28
+ const tokens = (0, estimateTokenCount_1.estimateTokenCount)({ content: file.content });
29
+ return {
30
+ path: file.path,
31
+ type: 'FILE',
32
+ tokens,
33
+ };
34
+ });
35
+ // build directory token sums
36
+ const dirTokens = new Map();
37
+ for (const file of fileEntries) {
38
+ const parts = file.path.split('/');
39
+ let current = '';
40
+ for (let i = 0; i < parts.length - 1; i++) {
41
+ current = current ? `${current}/${parts[i]}` : parts[i];
42
+ dirTokens.set(current, (dirTokens.get(current) ?? 0) + file.tokens);
43
+ }
44
+ }
45
+ // create directory entries
46
+ const dirEntries = Array.from(dirTokens.entries()).map(([path, tokens]) => ({
47
+ path,
48
+ type: 'DIRECTORY',
49
+ tokens,
50
+ }));
51
+ // combine and sort by tokens descending
52
+ const allEntries = [...fileEntries, ...dirEntries].sort((a, b) => b.tokens - a.tokens);
53
+ // calculate total
54
+ const total = fileEntries.reduce((sum, f) => sum + f.tokens, 0);
55
+ // add human-readable fields
56
+ const entries = allEntries.map((entry) => ({
57
+ ...entry,
58
+ tokensHuman: formatTokens(entry.tokens),
59
+ tokensScale: `${roundToHundredths((entry.tokens / total) * 100)}%`,
60
+ }));
61
+ return { entries, total };
62
+ };
63
+ exports.genTokenBreakdownReport = genTokenBreakdownReport;
64
+ //# sourceMappingURL=genTokenBreakdownReport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genTokenBreakdownReport.js","sourceRoot":"","sources":["../../../src/domain.operations/review/genTokenBreakdownReport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * .what = usage metrics from claude invocation
3
+ * .why = enables cost tracking and optimization
4
+ */
5
+ export interface ClaudeUsage {
6
+ inputTokens: number;
7
+ inputTokensCacheCreation: number;
8
+ inputTokensCacheRead: number;
9
+ outputTokens: number;
10
+ }
11
+ /**
12
+ * .what = invokes claude-code cli with the prompt
13
+ * .why = executes the review via the specified brain (claude-code)
14
+ */
15
+ export declare const invokeClaudeCode: (input: {
16
+ prompt: string;
17
+ cwd?: string;
18
+ }) => Promise<{
19
+ response: object;
20
+ review: string;
21
+ usage: ClaudeUsage;
22
+ }>;