@klitchevo/code-council 0.0.15 → 0.0.16

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.
@@ -0,0 +1,310 @@
1
+ // src/prompts/tps-audit.ts
2
+ var SYSTEM_PROMPT = `You are an expert Toyota Production System (TPS) consultant analyzing software codebases. Your role is to "walk the production line" - examining how code flows from input to output, identifying waste (muda), spotting bottlenecks, and suggesting continuous improvement (kaizen).
3
+
4
+ ## TPS Principles for Software
5
+
6
+ ### 1. FLOW (Nagare)
7
+ Analyze how data and control flow through the system:
8
+ - Identify entry points and exit points
9
+ - Map the critical paths
10
+ - Look for smooth, uninterrupted flow
11
+ - Identify where flow is blocked or redirected
12
+ - Check for single-piece flow vs batch processing
13
+
14
+ ### 2. WASTE (Muda) - The 7 Wastes in Software
15
+ Identify instances of each waste type:
16
+
17
+ **Defects**: Bugs, error-prone code, missing validation
18
+ **Overproduction**: Features nobody uses, over-engineered solutions
19
+ **Waiting**: Blocking I/O, synchronous when async would work, slow tests
20
+ **Non-utilized Talent**: Manual tasks that could be automated, repetitive code
21
+ **Transportation**: Unnecessary data transformation, excessive API calls
22
+ **Inventory**: Dead code, unused imports/exports, stale dependencies
23
+ **Motion**: Complex navigation, scattered related code, poor organization
24
+ **Extra-processing**: Premature optimization, unnecessary abstraction layers
25
+
26
+ ### 3. BOTTLENECKS
27
+ Identify constraints that limit throughput:
28
+ - Synchronous operations that block
29
+ - Single points of failure
30
+ - Resource contention
31
+ - N+1 queries or API calls
32
+ - Sequential operations that could be parallel
33
+
34
+ ### 4. PULL vs PUSH
35
+ Evaluate if work is demand-driven:
36
+ - Lazy evaluation vs eager computation
37
+ - On-demand loading vs preloading everything
38
+ - Event-driven vs polling
39
+ - Streaming vs buffering all data
40
+
41
+ ### 5. JIDOKA (Built-in Quality)
42
+ Assess quality mechanisms:
43
+ - Error handling and recovery
44
+ - Validation at boundaries
45
+ - Fail-fast patterns
46
+ - Type safety usage
47
+ - Test coverage signals
48
+
49
+ ### 6. STANDARDIZATION
50
+ Look for consistency:
51
+ - Code style consistency
52
+ - Pattern usage consistency
53
+ - Error handling patterns
54
+ - Naming conventions
55
+ - File organization
56
+
57
+ ## Scoring Guidelines
58
+
59
+ **Overall Score (0-100)**:
60
+ - 90-100: Exceptional flow, minimal waste, excellent quality
61
+ - 70-89: Good practices, some waste, room for improvement
62
+ - 50-69: Average, significant waste or flow issues
63
+ - 30-49: Poor flow, excessive waste, quality concerns
64
+ - 0-29: Critical issues, major redesign needed
65
+
66
+ **Flow Score**: How smoothly does data/control move through the system?
67
+ **Waste Score**: Higher = less waste (100 = no waste identified)
68
+ **Quality Score**: Built-in quality mechanisms, error handling, type safety
69
+
70
+ ## Output Requirements
71
+
72
+ You MUST respond with valid JSON matching the TpsAnalysis interface. Do not include any text before or after the JSON.
73
+
74
+ Focus on:
75
+ 1. Actionable findings with specific file/line references
76
+ 2. Prioritized recommendations (quick wins first)
77
+ 3. Concrete suggestions, not vague advice
78
+ 4. Balanced assessment - acknowledge strengths too
79
+ 5. Effort estimates for recommendations`;
80
+ function buildUserMessage(aggregatedContent, options) {
81
+ const parts = [];
82
+ if (options?.repoName) {
83
+ parts.push(`## Repository: ${options.repoName}`);
84
+ }
85
+ if (options?.focusAreas && options.focusAreas.length > 0) {
86
+ parts.push(
87
+ `## Focus Areas
88
+ Pay special attention to: ${options.focusAreas.join(", ")}`
89
+ );
90
+ }
91
+ if (options?.additionalContext) {
92
+ parts.push(`## Additional Context
93
+ ${options.additionalContext}`);
94
+ }
95
+ parts.push(`## Codebase to Audit
96
+
97
+ Analyze this codebase using Toyota Production System principles. Walk the production line from entry points through to outputs. Identify waste, bottlenecks, and improvement opportunities.
98
+
99
+ ${aggregatedContent}
100
+
101
+ ## Response Format
102
+
103
+ Respond with ONLY valid JSON matching the TpsAnalysis interface. Include:
104
+ - Scores for overall, flow, waste, and quality (0-100)
105
+ - Flow analysis with entry points and pathways
106
+ - Specific bottlenecks with locations and suggestions
107
+ - Waste items categorized by the 7 types
108
+ - Jidoka (built-in quality) assessment
109
+ - Prioritized recommendations
110
+ - Summary with strengths, concerns, and quick wins
111
+
112
+ Your JSON response:`);
113
+ return parts.join("\n\n");
114
+ }
115
+ var BATCH_SYSTEM_PROMPT = `${SYSTEM_PROMPT}
116
+
117
+ IMPORTANT: You are analyzing a BATCH of files from a larger codebase. This is batch {{BATCH_INDEX}} of {{TOTAL_BATCHES}}.
118
+ - Focus on what you can observe in this batch
119
+ - Note any cross-cutting concerns you see
120
+ - Your analysis will be combined with other batches for a final report
121
+ - Score this batch independently based on what you observe`;
122
+ function buildBatchUserMessage(aggregatedContent, batchIndex, totalBatches, options) {
123
+ const baseMessage = buildUserMessage(aggregatedContent, options);
124
+ return `[BATCH ${batchIndex + 1} of ${totalBatches}]
125
+
126
+ ${baseMessage}`;
127
+ }
128
+ var SYNTHESIS_SYSTEM_PROMPT = `You are a TPS (Toyota Production System) consultant synthesizing multiple batch analyses of a codebase into a unified report.
129
+
130
+ You will receive multiple TPS analysis JSON objects, each analyzing a different portion of the codebase. Your job is to:
131
+
132
+ 1. **Aggregate Scores**: Calculate weighted averages based on batch sizes
133
+ 2. **Merge Findings**: Combine bottlenecks, waste items, and recommendations, removing duplicates
134
+ 3. **Identify Patterns**: Note patterns that appear across multiple batches
135
+ 4. **Prioritize**: Re-prioritize recommendations based on the full picture
136
+ 5. **Synthesize Summary**: Create a cohesive summary of the entire codebase
137
+
138
+ Output a single unified TpsAnalysis JSON that represents the whole codebase.
139
+
140
+ Guidelines:
141
+ - If multiple batches mention the same issue, increase its priority
142
+ - Cross-batch patterns are often more important than single-batch issues
143
+ - Flow analysis should try to connect entry points across batches
144
+ - Be concise - don't repeat the same finding multiple times
145
+ - Final scores should reflect the overall health, not just average`;
146
+ function buildSynthesisUserMessage(batchResults, repoName) {
147
+ const parts = [];
148
+ if (repoName) {
149
+ parts.push(`## Repository: ${repoName}`);
150
+ }
151
+ parts.push(`## Batch Analyses to Synthesize
152
+
153
+ You have ${batchResults.length} batch analyses to combine into a final report.`);
154
+ for (const batch of batchResults) {
155
+ parts.push(
156
+ `### Batch ${batch.batchIndex + 1} (~${batch.tokenCount} tokens)`
157
+ );
158
+ if (batch.analysis) {
159
+ parts.push("```json");
160
+ parts.push(JSON.stringify(batch.analysis, null, 2));
161
+ parts.push("```");
162
+ } else {
163
+ parts.push("*Analysis failed to parse. Raw response:*");
164
+ parts.push(
165
+ batch.rawResponse.substring(0, 1e3) + (batch.rawResponse.length > 1e3 ? "..." : "")
166
+ );
167
+ }
168
+ }
169
+ parts.push(`## Response Format
170
+
171
+ Synthesize all batches into a single unified TpsAnalysis JSON.
172
+ - Combine and deduplicate findings
173
+ - Recalculate overall scores based on all batches
174
+ - Prioritize issues that appear in multiple batches
175
+ - Create a cohesive summary
176
+
177
+ Your unified JSON response:`);
178
+ return parts.join("\n\n");
179
+ }
180
+ function parseTpsAnalysis(response) {
181
+ try {
182
+ let jsonStr = response.trim();
183
+ if (jsonStr.startsWith("```json")) {
184
+ jsonStr = jsonStr.slice(7);
185
+ } else if (jsonStr.startsWith("```")) {
186
+ jsonStr = jsonStr.slice(3);
187
+ }
188
+ if (jsonStr.endsWith("```")) {
189
+ jsonStr = jsonStr.slice(0, -3);
190
+ }
191
+ jsonStr = jsonStr.trim();
192
+ const raw = JSON.parse(jsonStr);
193
+ const scores = normalizeScores(raw);
194
+ if (!scores) {
195
+ return null;
196
+ }
197
+ const analysis = {
198
+ scores,
199
+ flowAnalysis: normalizeFlowAnalysis(raw),
200
+ bottlenecks: normalizeBottlenecks(raw),
201
+ waste: normalizeWaste(raw),
202
+ jidoka: normalizeJidoka(raw),
203
+ recommendations: normalizeRecommendations(raw),
204
+ summary: normalizeSummary(raw)
205
+ };
206
+ return analysis;
207
+ } catch {
208
+ return null;
209
+ }
210
+ }
211
+ function normalizeScores(raw) {
212
+ if (raw.scores && typeof raw.scores === "object") {
213
+ const s = raw.scores;
214
+ return {
215
+ overall: toNumber(s.overall) ?? toNumber(raw.overallScore) ?? 0,
216
+ flow: toNumber(s.flow) ?? 0,
217
+ waste: toNumber(s.waste) ?? 0,
218
+ quality: toNumber(s.quality) ?? 0
219
+ };
220
+ }
221
+ if (typeof raw.overallScore === "number" || typeof raw.overall === "number") {
222
+ return {
223
+ overall: toNumber(raw.overallScore) ?? toNumber(raw.overall) ?? 0,
224
+ flow: toNumber(raw.flowScore) ?? toNumber(raw.flow) ?? 0,
225
+ waste: toNumber(raw.wasteScore) ?? toNumber(raw.waste) ?? 0,
226
+ quality: toNumber(raw.qualityScore) ?? toNumber(raw.quality) ?? 0
227
+ };
228
+ }
229
+ return null;
230
+ }
231
+ function toNumber(val) {
232
+ if (typeof val === "number") return val;
233
+ if (typeof val === "string") {
234
+ const n = parseFloat(val);
235
+ return isNaN(n) ? null : n;
236
+ }
237
+ return null;
238
+ }
239
+ function normalizeFlowAnalysis(raw) {
240
+ const flow = raw.flowAnalysis;
241
+ if (!flow) {
242
+ return { entryPoints: [], diagram: "", pathways: [], observations: [] };
243
+ }
244
+ return {
245
+ entryPoints: normalizeStringArray(flow.entryPoints),
246
+ diagram: typeof flow.diagram === "string" ? flow.diagram : "",
247
+ pathways: normalizeStringArray(flow.pathways),
248
+ observations: normalizeStringArray(flow.observations)
249
+ };
250
+ }
251
+ function normalizeWaste(raw) {
252
+ const waste = raw.waste;
253
+ if (!waste || typeof waste !== "object") {
254
+ return {};
255
+ }
256
+ return waste;
257
+ }
258
+ function normalizeJidoka(raw) {
259
+ const jidoka = raw.jidoka;
260
+ if (!jidoka) {
261
+ return { score: 0, strengths: [], weaknesses: [] };
262
+ }
263
+ return {
264
+ score: toNumber(jidoka.score) ?? 0,
265
+ strengths: normalizeStringArray(jidoka.strengths),
266
+ weaknesses: normalizeStringArray(jidoka.weaknesses)
267
+ };
268
+ }
269
+ function normalizeBottlenecks(raw) {
270
+ const bottlenecks = raw.bottlenecks;
271
+ if (Array.isArray(bottlenecks)) {
272
+ return bottlenecks;
273
+ }
274
+ return [];
275
+ }
276
+ function normalizeRecommendations(raw) {
277
+ const recs = raw.recommendations;
278
+ if (Array.isArray(recs)) {
279
+ return recs;
280
+ }
281
+ return [];
282
+ }
283
+ function normalizeSummary(raw) {
284
+ const summary = raw.summary;
285
+ if (!summary) {
286
+ return { strengths: [], concerns: [], quickWins: [] };
287
+ }
288
+ return {
289
+ strengths: normalizeStringArray(summary.strengths),
290
+ concerns: normalizeStringArray(summary.concerns),
291
+ quickWins: normalizeStringArray(summary.quickWins)
292
+ };
293
+ }
294
+ function normalizeStringArray(val) {
295
+ if (Array.isArray(val)) {
296
+ return val;
297
+ }
298
+ return [];
299
+ }
300
+
301
+ export {
302
+ SYSTEM_PROMPT,
303
+ buildUserMessage,
304
+ BATCH_SYSTEM_PROMPT,
305
+ buildBatchUserMessage,
306
+ SYNTHESIS_SYSTEM_PROMPT,
307
+ buildSynthesisUserMessage,
308
+ parseTpsAnalysis
309
+ };
310
+ //# sourceMappingURL=chunk-W4MFXWTT.js.map
package/dist/index.js CHANGED
@@ -1,8 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ BATCH_SYSTEM_PROMPT,
4
+ SYNTHESIS_SYSTEM_PROMPT,
3
5
  SYSTEM_PROMPT,
6
+ buildBatchUserMessage,
7
+ buildSynthesisUserMessage,
4
8
  buildUserMessage
5
- } from "./chunk-Y77R7523.js";
9
+ } from "./chunk-W4MFXWTT.js";
6
10
 
7
11
  // src/index.ts
8
12
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -540,6 +544,51 @@ var ReviewClient = class {
540
544
  (model) => this.chat(model, SYSTEM_PROMPT, userMessage)
541
545
  );
542
546
  }
547
+ /**
548
+ * Perform TPS audit on a single batch of content
549
+ * @internal Used by batch processing
550
+ */
551
+ async tpsAuditBatch(aggregatedContent, model, batchIndex, totalBatches, options) {
552
+ const systemPrompt = BATCH_SYSTEM_PROMPT.replace(
553
+ "{{BATCH_INDEX}}",
554
+ String(batchIndex + 1)
555
+ ).replace("{{TOTAL_BATCHES}}", String(totalBatches));
556
+ const userMessage = buildBatchUserMessage(
557
+ aggregatedContent,
558
+ batchIndex,
559
+ totalBatches,
560
+ {
561
+ focusAreas: options?.focusAreas,
562
+ repoName: options?.repoName
563
+ }
564
+ );
565
+ logger.debug("Processing TPS batch", {
566
+ batchIndex,
567
+ totalBatches,
568
+ model,
569
+ contentLength: aggregatedContent.length
570
+ });
571
+ return this.chat(model, systemPrompt, userMessage);
572
+ }
573
+ /**
574
+ * Synthesize multiple batch analyses into a unified report
575
+ * @internal Used by batch processing
576
+ */
577
+ async tpsAuditSynthesize(batchResults, model, repoName) {
578
+ const userMessage = buildSynthesisUserMessage(
579
+ batchResults,
580
+ repoName
581
+ );
582
+ logger.debug("Synthesizing TPS batch results", {
583
+ batchCount: batchResults.length,
584
+ model
585
+ });
586
+ return this.chat(
587
+ model,
588
+ SYNTHESIS_SYSTEM_PROMPT,
589
+ userMessage
590
+ );
591
+ }
543
592
  };
544
593
 
545
594
  // src/session/in-memory-store.ts
@@ -1446,12 +1495,14 @@ var SECRET_CONTENT_PATTERNS = [
1446
1495
  // Square tokens
1447
1496
  ];
1448
1497
  var DEFAULT_FILE_EXTENSIONS = [
1498
+ // TypeScript/JavaScript
1449
1499
  ".ts",
1450
1500
  ".tsx",
1451
1501
  ".js",
1452
1502
  ".jsx",
1453
1503
  ".mjs",
1454
1504
  ".cjs",
1505
+ // Other languages
1455
1506
  ".py",
1456
1507
  ".go",
1457
1508
  ".rs",
@@ -1466,9 +1517,31 @@ var DEFAULT_FILE_EXTENSIONS = [
1466
1517
  ".h",
1467
1518
  ".hpp",
1468
1519
  ".swift",
1520
+ // Frontend frameworks
1469
1521
  ".vue",
1470
1522
  ".svelte",
1471
- ".astro"
1523
+ ".astro",
1524
+ // Config & docs (important for understanding project)
1525
+ ".json",
1526
+ ".yaml",
1527
+ ".yml",
1528
+ ".toml",
1529
+ ".md"
1530
+ ];
1531
+ var PRIORITY_DIRS = [
1532
+ ".claude",
1533
+ // Claude Code project configuration
1534
+ ".beads"
1535
+ // Issue tracking
1536
+ ];
1537
+ var PRIORITY_ROOT_FILES = [
1538
+ "CLAUDE.md",
1539
+ "README.md",
1540
+ "package.json",
1541
+ "tsconfig.json",
1542
+ "pyproject.toml",
1543
+ "Cargo.toml",
1544
+ "go.mod"
1472
1545
  ];
1473
1546
  var EXCLUDED_DIRS = [
1474
1547
  "node_modules",
@@ -1638,6 +1711,9 @@ async function scanRepository(startPath, options = {}) {
1638
1711
  continue;
1639
1712
  }
1640
1713
  if (stats2.isDirectory()) {
1714
+ if (depth === 0 && PRIORITY_DIRS.includes(entry)) {
1715
+ continue;
1716
+ }
1641
1717
  scanDir(fullPath, depth + 1);
1642
1718
  } else if (stats2.isFile()) {
1643
1719
  totalFilesFound++;
@@ -1697,6 +1773,56 @@ async function scanRepository(startPath, options = {}) {
1697
1773
  }
1698
1774
  }
1699
1775
  }
1776
+ function scanSingleFile(fullPath, bypassTypeFilter = false) {
1777
+ const relativePath = relative2(repoRoot, fullPath);
1778
+ let stats2;
1779
+ try {
1780
+ stats2 = statSync(fullPath);
1781
+ } catch {
1782
+ return false;
1783
+ }
1784
+ if (!stats2.isFile()) return false;
1785
+ totalFilesFound++;
1786
+ const ext = extname(fullPath).toLowerCase();
1787
+ if (!bypassTypeFilter && !opts.fileTypes.includes(ext)) {
1788
+ return false;
1789
+ }
1790
+ if (stats2.size > opts.maxFileSize) {
1791
+ skipped.push({
1792
+ path: relativePath,
1793
+ reason: `File too large (${stats2.size} bytes)`
1794
+ });
1795
+ return false;
1796
+ }
1797
+ let content;
1798
+ try {
1799
+ const buffer = readFileSync2(fullPath);
1800
+ if (isBinaryContent(buffer)) {
1801
+ return false;
1802
+ }
1803
+ content = buffer.toString("utf-8");
1804
+ } catch {
1805
+ return false;
1806
+ }
1807
+ files.push({ path: relativePath, content });
1808
+ totalSize += stats2.size;
1809
+ return true;
1810
+ }
1811
+ for (const filename of PRIORITY_ROOT_FILES) {
1812
+ const fullPath = join3(repoRoot, filename);
1813
+ scanSingleFile(fullPath, true);
1814
+ }
1815
+ for (const priorityDir of PRIORITY_DIRS) {
1816
+ const dirPath = join3(repoRoot, priorityDir);
1817
+ try {
1818
+ const dirStats = statSync(dirPath);
1819
+ if (dirStats.isDirectory()) {
1820
+ logger.debug("Scanning priority directory", { dir: priorityDir });
1821
+ scanDir(dirPath, 0);
1822
+ }
1823
+ } catch {
1824
+ }
1825
+ }
1700
1826
  scanDir(repoRoot);
1701
1827
  const stats = {
1702
1828
  totalFilesFound,
@@ -1726,6 +1852,84 @@ ${f.content}
1726
1852
  === END FILE: ${f.path} ===`
1727
1853
  ).join("\n\n");
1728
1854
  }
1855
+ var BATCH_TOKEN_BUDGET = 6e4;
1856
+ function createFileBatches(files, tokenBudget = BATCH_TOKEN_BUDGET) {
1857
+ if (files.length === 0) {
1858
+ return [];
1859
+ }
1860
+ const filesByDir = /* @__PURE__ */ new Map();
1861
+ for (const file of files) {
1862
+ const dir = file.path.includes("/") ? file.path.substring(0, file.path.lastIndexOf("/")) : ".";
1863
+ const dirFiles = filesByDir.get(dir) || [];
1864
+ dirFiles.push(file);
1865
+ filesByDir.set(dir, dirFiles);
1866
+ }
1867
+ const dirsWithTokens = [...filesByDir.entries()].map(([dir, dirFiles]) => ({
1868
+ dir,
1869
+ files: dirFiles,
1870
+ tokens: dirFiles.reduce((sum, f) => sum + estimateTokens(f.content), 0)
1871
+ }));
1872
+ dirsWithTokens.sort((a, b) => a.tokens - b.tokens);
1873
+ const batches = [];
1874
+ let currentBatch = [];
1875
+ let currentTokens = 0;
1876
+ for (const { files: dirFiles, tokens: dirTokens } of dirsWithTokens) {
1877
+ if (currentTokens + dirTokens <= tokenBudget) {
1878
+ currentBatch.push(...dirFiles);
1879
+ currentTokens += dirTokens;
1880
+ } else if (dirTokens > tokenBudget) {
1881
+ if (currentBatch.length > 0) {
1882
+ batches.push({
1883
+ files: currentBatch,
1884
+ tokenEstimate: currentTokens,
1885
+ batchIndex: batches.length
1886
+ });
1887
+ currentBatch = [];
1888
+ currentTokens = 0;
1889
+ }
1890
+ for (const file of dirFiles) {
1891
+ const fileTokens = estimateTokens(file.content);
1892
+ if (currentTokens + fileTokens > tokenBudget && currentBatch.length > 0) {
1893
+ batches.push({
1894
+ files: currentBatch,
1895
+ tokenEstimate: currentTokens,
1896
+ batchIndex: batches.length
1897
+ });
1898
+ currentBatch = [];
1899
+ currentTokens = 0;
1900
+ }
1901
+ currentBatch.push(file);
1902
+ currentTokens += fileTokens;
1903
+ }
1904
+ } else {
1905
+ if (currentBatch.length > 0) {
1906
+ batches.push({
1907
+ files: currentBatch,
1908
+ tokenEstimate: currentTokens,
1909
+ batchIndex: batches.length
1910
+ });
1911
+ }
1912
+ currentBatch = [...dirFiles];
1913
+ currentTokens = dirTokens;
1914
+ }
1915
+ }
1916
+ if (currentBatch.length > 0) {
1917
+ batches.push({
1918
+ files: currentBatch,
1919
+ tokenEstimate: currentTokens,
1920
+ batchIndex: batches.length
1921
+ });
1922
+ }
1923
+ logger.debug("Created file batches", {
1924
+ totalFiles: files.length,
1925
+ batchCount: batches.length,
1926
+ batchSizes: batches.map((b) => ({
1927
+ files: b.files.length,
1928
+ tokens: b.tokenEstimate
1929
+ }))
1930
+ });
1931
+ return batches;
1932
+ }
1729
1933
 
1730
1934
  // src/tools/tps-audit.ts
1731
1935
  var tpsAuditSchemaObj = z7.object({
@@ -1741,6 +1945,7 @@ var tpsAuditSchemaObj = z7.object({
1741
1945
  output_format: z7.enum(["html", "markdown", "json"]).optional().describe("Output format (default: html)")
1742
1946
  });
1743
1947
  var tpsAuditSchema = tpsAuditSchemaObj.shape;
1948
+ var BATCH_TOKEN_THRESHOLD = 6e4;
1744
1949
  async function handleTpsAudit(client2, models, input) {
1745
1950
  const startPath = input.path || process.cwd();
1746
1951
  const outputFormat = input.output_format || "html";
@@ -1780,27 +1985,40 @@ async function handleTpsAudit(client2, models, input) {
1780
1985
  warnings: scanResult.warnings
1781
1986
  });
1782
1987
  }
1783
- const aggregatedContent = aggregateFiles(scanResult.files);
1784
1988
  logger.info("Repository scanned", {
1785
1989
  filesIncluded: scanResult.files.length,
1786
1990
  totalSize: scanResult.stats.totalSize,
1787
1991
  tokenEstimate: scanResult.stats.tokenEstimate
1788
1992
  });
1789
- if (scanResult.stats.tokenEstimate > 1e5) {
1790
- logger.warn("Large token count", {
1791
- estimate: scanResult.stats.tokenEstimate
1792
- });
1793
- }
1794
- const results = await client2.tpsAudit(aggregatedContent, models, {
1795
- focusAreas: input.focus_areas,
1796
- repoName: scanResult.repoRoot.split("/").pop()
1797
- });
1993
+ const repoName = scanResult.repoRoot.split("/").pop();
1994
+ const needsBatching = scanResult.stats.tokenEstimate > BATCH_TOKEN_THRESHOLD;
1995
+ let results;
1798
1996
  let analysis = null;
1799
- for (const result of results) {
1800
- if (!result.error && result.review) {
1801
- const { parseTpsAnalysis } = await import("./tps-audit-GNK4VIKA.js");
1802
- analysis = parseTpsAnalysis(result.review);
1803
- if (analysis) break;
1997
+ if (needsBatching) {
1998
+ logger.info("Using batch processing", {
1999
+ tokenEstimate: scanResult.stats.tokenEstimate,
2000
+ threshold: BATCH_TOKEN_THRESHOLD
2001
+ });
2002
+ const batchResults = await handleBatchedTpsAudit(
2003
+ client2,
2004
+ models,
2005
+ scanResult,
2006
+ input.focus_areas
2007
+ );
2008
+ results = batchResults.results;
2009
+ analysis = batchResults.analysis;
2010
+ } else {
2011
+ const aggregatedContent = aggregateFiles(scanResult.files);
2012
+ results = await client2.tpsAudit(aggregatedContent, models, {
2013
+ focusAreas: input.focus_areas,
2014
+ repoName
2015
+ });
2016
+ for (const result of results) {
2017
+ if (!result.error && result.review) {
2018
+ const { parseTpsAnalysis } = await import("./tps-audit-TXNM5HYS.js");
2019
+ analysis = parseTpsAnalysis(result.review);
2020
+ if (analysis) break;
2021
+ }
1804
2022
  }
1805
2023
  }
1806
2024
  return {
@@ -1811,6 +2029,103 @@ async function handleTpsAudit(client2, models, input) {
1811
2029
  outputFormat
1812
2030
  };
1813
2031
  }
2032
+ async function handleBatchedTpsAudit(client2, models, scanResult, focusAreas) {
2033
+ const { parseTpsAnalysis } = await import("./tps-audit-TXNM5HYS.js");
2034
+ const repoName = scanResult.repoRoot.split("/").pop() ?? "unknown";
2035
+ const batches = createFileBatches(scanResult.files);
2036
+ const batchContents = batches.map((batch) => ({
2037
+ content: aggregateFiles(batch.files),
2038
+ tokenEstimate: batch.tokenEstimate,
2039
+ batchIndex: batch.batchIndex
2040
+ }));
2041
+ logger.info("Processing batches with all models", {
2042
+ batchCount: batches.length,
2043
+ modelCount: models.length,
2044
+ totalApiCalls: batches.length * models.length + models.length
2045
+ // batches + synthesis per model
2046
+ });
2047
+ const modelResults = await Promise.all(
2048
+ models.map(async (model) => {
2049
+ const batchAnalyses = await Promise.all(
2050
+ batchContents.map(async (batch) => {
2051
+ try {
2052
+ const response = await client2.tpsAuditBatch(
2053
+ batch.content,
2054
+ model,
2055
+ batch.batchIndex,
2056
+ batches.length,
2057
+ { focusAreas, repoName }
2058
+ );
2059
+ return {
2060
+ batchIndex: batch.batchIndex,
2061
+ tokenCount: batch.tokenEstimate,
2062
+ rawResponse: response,
2063
+ analysis: parseTpsAnalysis(response)
2064
+ };
2065
+ } catch (error) {
2066
+ logger.error("Batch analysis failed", error, {
2067
+ model,
2068
+ batchIndex: batch.batchIndex
2069
+ });
2070
+ return {
2071
+ batchIndex: batch.batchIndex,
2072
+ tokenCount: batch.tokenEstimate,
2073
+ rawResponse: error instanceof Error ? error.message : "Unknown error",
2074
+ analysis: null
2075
+ };
2076
+ }
2077
+ })
2078
+ );
2079
+ const successfulBatches = batchAnalyses.filter(
2080
+ (b) => b.analysis !== null
2081
+ );
2082
+ let finalAnalysis = null;
2083
+ let finalResponse = "";
2084
+ if (batchAnalyses.length > 1 && successfulBatches.length > 0) {
2085
+ try {
2086
+ finalResponse = await client2.tpsAuditSynthesize(
2087
+ batchAnalyses,
2088
+ model,
2089
+ repoName
2090
+ );
2091
+ finalAnalysis = parseTpsAnalysis(finalResponse);
2092
+ } catch (error) {
2093
+ logger.error("Synthesis failed for model", error, { model });
2094
+ const first = successfulBatches[0];
2095
+ finalAnalysis = first?.analysis ?? null;
2096
+ finalResponse = first?.rawResponse ?? "";
2097
+ }
2098
+ } else if (successfulBatches.length === 1) {
2099
+ const first = successfulBatches[0];
2100
+ if (first) {
2101
+ finalAnalysis = first.analysis;
2102
+ finalResponse = first.rawResponse;
2103
+ }
2104
+ }
2105
+ return {
2106
+ model,
2107
+ review: finalResponse,
2108
+ analysis: finalAnalysis,
2109
+ error: finalAnalysis === null ? "Failed to produce analysis" : void 0
2110
+ };
2111
+ })
2112
+ );
2113
+ const results = modelResults.map((r) => ({
2114
+ model: r.model,
2115
+ review: r.review,
2116
+ error: r.error
2117
+ }));
2118
+ const firstSuccess = modelResults.find((r) => r.analysis !== null);
2119
+ logger.info("Batched TPS audit complete", {
2120
+ modelsUsed: models.length,
2121
+ batchesPerModel: batches.length,
2122
+ successfulModels: modelResults.filter((r) => r.analysis !== null).length
2123
+ });
2124
+ return {
2125
+ results,
2126
+ analysis: firstSuccess?.analysis ?? null
2127
+ };
2128
+ }
1814
2129
  function writeReportToFolder(repoRoot, content, format) {
1815
2130
  try {
1816
2131
  const outputDir = join4(repoRoot, ".code-council");
@@ -0,0 +1,19 @@
1
+ import {
2
+ BATCH_SYSTEM_PROMPT,
3
+ SYNTHESIS_SYSTEM_PROMPT,
4
+ SYSTEM_PROMPT,
5
+ buildBatchUserMessage,
6
+ buildSynthesisUserMessage,
7
+ buildUserMessage,
8
+ parseTpsAnalysis
9
+ } from "./chunk-W4MFXWTT.js";
10
+ export {
11
+ BATCH_SYSTEM_PROMPT,
12
+ SYNTHESIS_SYSTEM_PROMPT,
13
+ SYSTEM_PROMPT,
14
+ buildBatchUserMessage,
15
+ buildSynthesisUserMessage,
16
+ buildUserMessage,
17
+ parseTpsAnalysis
18
+ };
19
+ //# sourceMappingURL=tps-audit-TXNM5HYS.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klitchevo/code-council",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "Multi-model AI code review server using OpenRouter - get diverse perspectives from multiple LLMs in parallel",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,142 +0,0 @@
1
- // src/prompts/tps-audit.ts
2
- var SYSTEM_PROMPT = `You are an expert Toyota Production System (TPS) consultant analyzing software codebases. Your role is to "walk the production line" - examining how code flows from input to output, identifying waste (muda), spotting bottlenecks, and suggesting continuous improvement (kaizen).
3
-
4
- ## TPS Principles for Software
5
-
6
- ### 1. FLOW (Nagare)
7
- Analyze how data and control flow through the system:
8
- - Identify entry points and exit points
9
- - Map the critical paths
10
- - Look for smooth, uninterrupted flow
11
- - Identify where flow is blocked or redirected
12
- - Check for single-piece flow vs batch processing
13
-
14
- ### 2. WASTE (Muda) - The 7 Wastes in Software
15
- Identify instances of each waste type:
16
-
17
- **Defects**: Bugs, error-prone code, missing validation
18
- **Overproduction**: Features nobody uses, over-engineered solutions
19
- **Waiting**: Blocking I/O, synchronous when async would work, slow tests
20
- **Non-utilized Talent**: Manual tasks that could be automated, repetitive code
21
- **Transportation**: Unnecessary data transformation, excessive API calls
22
- **Inventory**: Dead code, unused imports/exports, stale dependencies
23
- **Motion**: Complex navigation, scattered related code, poor organization
24
- **Extra-processing**: Premature optimization, unnecessary abstraction layers
25
-
26
- ### 3. BOTTLENECKS
27
- Identify constraints that limit throughput:
28
- - Synchronous operations that block
29
- - Single points of failure
30
- - Resource contention
31
- - N+1 queries or API calls
32
- - Sequential operations that could be parallel
33
-
34
- ### 4. PULL vs PUSH
35
- Evaluate if work is demand-driven:
36
- - Lazy evaluation vs eager computation
37
- - On-demand loading vs preloading everything
38
- - Event-driven vs polling
39
- - Streaming vs buffering all data
40
-
41
- ### 5. JIDOKA (Built-in Quality)
42
- Assess quality mechanisms:
43
- - Error handling and recovery
44
- - Validation at boundaries
45
- - Fail-fast patterns
46
- - Type safety usage
47
- - Test coverage signals
48
-
49
- ### 6. STANDARDIZATION
50
- Look for consistency:
51
- - Code style consistency
52
- - Pattern usage consistency
53
- - Error handling patterns
54
- - Naming conventions
55
- - File organization
56
-
57
- ## Scoring Guidelines
58
-
59
- **Overall Score (0-100)**:
60
- - 90-100: Exceptional flow, minimal waste, excellent quality
61
- - 70-89: Good practices, some waste, room for improvement
62
- - 50-69: Average, significant waste or flow issues
63
- - 30-49: Poor flow, excessive waste, quality concerns
64
- - 0-29: Critical issues, major redesign needed
65
-
66
- **Flow Score**: How smoothly does data/control move through the system?
67
- **Waste Score**: Higher = less waste (100 = no waste identified)
68
- **Quality Score**: Built-in quality mechanisms, error handling, type safety
69
-
70
- ## Output Requirements
71
-
72
- You MUST respond with valid JSON matching the TpsAnalysis interface. Do not include any text before or after the JSON.
73
-
74
- Focus on:
75
- 1. Actionable findings with specific file/line references
76
- 2. Prioritized recommendations (quick wins first)
77
- 3. Concrete suggestions, not vague advice
78
- 4. Balanced assessment - acknowledge strengths too
79
- 5. Effort estimates for recommendations`;
80
- function buildUserMessage(aggregatedContent, options) {
81
- const parts = [];
82
- if (options?.repoName) {
83
- parts.push(`## Repository: ${options.repoName}`);
84
- }
85
- if (options?.focusAreas && options.focusAreas.length > 0) {
86
- parts.push(
87
- `## Focus Areas
88
- Pay special attention to: ${options.focusAreas.join(", ")}`
89
- );
90
- }
91
- if (options?.additionalContext) {
92
- parts.push(`## Additional Context
93
- ${options.additionalContext}`);
94
- }
95
- parts.push(`## Codebase to Audit
96
-
97
- Analyze this codebase using Toyota Production System principles. Walk the production line from entry points through to outputs. Identify waste, bottlenecks, and improvement opportunities.
98
-
99
- ${aggregatedContent}
100
-
101
- ## Response Format
102
-
103
- Respond with ONLY valid JSON matching the TpsAnalysis interface. Include:
104
- - Scores for overall, flow, waste, and quality (0-100)
105
- - Flow analysis with entry points and pathways
106
- - Specific bottlenecks with locations and suggestions
107
- - Waste items categorized by the 7 types
108
- - Jidoka (built-in quality) assessment
109
- - Prioritized recommendations
110
- - Summary with strengths, concerns, and quick wins
111
-
112
- Your JSON response:`);
113
- return parts.join("\n\n");
114
- }
115
- function parseTpsAnalysis(response) {
116
- try {
117
- let jsonStr = response.trim();
118
- if (jsonStr.startsWith("```json")) {
119
- jsonStr = jsonStr.slice(7);
120
- } else if (jsonStr.startsWith("```")) {
121
- jsonStr = jsonStr.slice(3);
122
- }
123
- if (jsonStr.endsWith("```")) {
124
- jsonStr = jsonStr.slice(0, -3);
125
- }
126
- jsonStr = jsonStr.trim();
127
- const parsed = JSON.parse(jsonStr);
128
- if (typeof parsed.scores?.overall !== "number" || !Array.isArray(parsed.bottlenecks) || !Array.isArray(parsed.recommendations)) {
129
- return null;
130
- }
131
- return parsed;
132
- } catch {
133
- return null;
134
- }
135
- }
136
-
137
- export {
138
- SYSTEM_PROMPT,
139
- buildUserMessage,
140
- parseTpsAnalysis
141
- };
142
- //# sourceMappingURL=chunk-Y77R7523.js.map
@@ -1,11 +0,0 @@
1
- import {
2
- SYSTEM_PROMPT,
3
- buildUserMessage,
4
- parseTpsAnalysis
5
- } from "./chunk-Y77R7523.js";
6
- export {
7
- SYSTEM_PROMPT,
8
- buildUserMessage,
9
- parseTpsAnalysis
10
- };
11
- //# sourceMappingURL=tps-audit-GNK4VIKA.js.map