getprismo 0.1.10 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,6 +41,7 @@ after you code npx getprismo cc timeline
41
41
  - missing `.claudeignore` / `.cursorignore` (the biggest single fix for most repos)
42
42
  - lockfiles entering context (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`)
43
43
  - generated artifacts leaking in (`__pycache__`, `dist/`, `coverage/`, `.next/`)
44
+ - operational source-stream dumps leaking in (`events/`, `source-streams/`, inbox/calendar/GitHub JSONL exports)
44
45
  - oversized instruction files (`CLAUDE.md` or `AGENTS.md` over 500 tokens)
45
46
  - tool output dominating sessions (repeated reads, large command output)
46
47
  - long-running sessions with stale context accumulation
@@ -396,6 +397,8 @@ if an existing `.claudeignore` or `.cursorignore` already covers prismo's recomm
396
397
 
397
398
  backend and frontend summaries include load-bearing candidates ranked by import references, text-reference signals, recent git touches when available, and file size, not just directory listings.
398
399
 
400
+ prismo also flags source-stream dumps separately from normal build artifacts. large inbox/calendar/github/event payload files are treated as operational noise because they often get summarized once, written near the repo, and then accidentally re-read by later coding sessions.
401
+
399
402
  what doctor never touches:
400
403
 
401
404
  - your real `CLAUDE.md`
@@ -656,7 +659,7 @@ then your team can run `npm run ai:doctor` without remembering the full command.
656
659
  - openai codex
657
660
  - cursor
658
661
  - any tool that respects `.claudeignore` or `.cursorignore`
659
- - any repo (node, python, go, rust, monorepos, whatever)
662
+ - any repo (node, python, go, rust, vue, svelte, astro, monorepos, whatever)
660
663
 
661
664
  ---
662
665
 
@@ -84,6 +84,10 @@ const SOURCE_EXTENSIONS = new Set([
84
84
  ".html",
85
85
  ".vue",
86
86
  ".svelte",
87
+ ".mjs",
88
+ ".cjs",
89
+ ".mts",
90
+ ".cts",
87
91
  ]);
88
92
 
89
93
  const INSTRUCTION_FILES = [
@@ -120,8 +124,15 @@ const DEFAULT_CLAUDEIGNORE = [
120
124
  "package-lock.json",
121
125
  "yarn.lock",
122
126
  "pnpm-lock.yaml",
127
+ "bun.lockb",
123
128
  "test-results/",
124
129
  "playwright-report/",
130
+ "events/",
131
+ "event-dumps/",
132
+ "session-dumps/",
133
+ "source-streams/",
134
+ "inbox-dumps/",
135
+ "calendar-dumps/",
125
136
  "models/",
126
137
  "state-backups/",
127
138
  "backups/",
@@ -158,6 +169,7 @@ const GENERATED_ARTIFACT_PATTERNS = [
158
169
  /(^|\/)coverage\//,
159
170
  /(^|\/)playwright-report\//,
160
171
  /(^|\/)test-results\//,
172
+ /(^|\/)(events|event-dumps|session-dumps|source-streams|inbox-dumps|calendar-dumps)\//,
161
173
  /(^|\/)__pycache__\//,
162
174
  /(^|\/)\.pytest_cache\//,
163
175
  /(^|\/)\.cache\//,
@@ -26,6 +26,11 @@ function detectFrameworks(root, result) {
26
26
  const deps = { ...(pkg && pkg.dependencies), ...(pkg && pkg.devDependencies) };
27
27
  if (deps.next) frameworks.add("Next.js");
28
28
  if (deps.react) frameworks.add("React");
29
+ if (deps.vue || deps["@vue/runtime-core"]) frameworks.add("Vue");
30
+ if (deps.svelte || deps["@sveltejs/kit"]) frameworks.add(deps["@sveltejs/kit"] ? "SvelteKit" : "Svelte");
31
+ if (deps["solid-js"]) frameworks.add("Solid");
32
+ if (deps.astro) frameworks.add("Astro");
33
+ if (deps.nuxt) frameworks.add("Nuxt");
29
34
  if (deps.express) frameworks.add("Express");
30
35
  if (deps["@nestjs/core"]) frameworks.add("NestJS");
31
36
  if (deps.prisma || deps["@prisma/client"]) frameworks.add("Prisma");
@@ -75,6 +80,11 @@ function detectFrameworks(root, result) {
75
80
  if ([...textFiles.keys()].some((rel) => rel.includes("prisma/schema.prisma"))) frameworks.add("Prisma");
76
81
  if ([...textFiles.keys()].some((rel) => rel.includes("next.config."))) frameworks.add("Next.js");
77
82
  if ([...textFiles.keys()].some((rel) => rel.includes("vite.config."))) frameworks.add("Vite");
83
+ if ([...textFiles.keys()].some((rel) => rel.includes("svelte.config."))) frameworks.add("SvelteKit");
84
+ if ([...textFiles.keys()].some((rel) => rel.includes("astro.config."))) frameworks.add("Astro");
85
+ if ([...textFiles.keys()].some((rel) => rel.includes("nuxt.config."))) frameworks.add("Nuxt");
86
+ if ([...textFiles.keys()].some((rel) => rel.endsWith(".vue"))) frameworks.add("Vue");
87
+ if ([...textFiles.keys()].some((rel) => rel.endsWith(".svelte"))) frameworks.add("Svelte");
78
88
  if ([...textFiles.keys()].some((rel) => rel.includes("tailwind.config."))) frameworks.add("Tailwind");
79
89
  if ([...textFiles.keys()].some((rel) => rel.endsWith("tsconfig.json"))) frameworks.add("TypeScript");
80
90
  if ([...textFiles.keys()].some((rel) => rel.includes("alembic/") || rel.endsWith("alembic.ini"))) frameworks.add("Alembic");
@@ -109,6 +119,11 @@ function detectEntrypoints(result) {
109
119
  "src/app/page.tsx",
110
120
  "src/main.tsx",
111
121
  "src/index.tsx",
122
+ "src/App.vue",
123
+ "src/App.svelte",
124
+ "src/routes/+page.svelte",
125
+ "src/pages/index.astro",
126
+ "app.vue",
112
127
  "server.js",
113
128
  "index.js",
114
129
  "docker/docker-compose.yml",
@@ -173,12 +188,18 @@ function detectBackendPaths(result) {
173
188
  }
174
189
 
175
190
  function detectFrontendPaths(result) {
191
+ const appSurface = /(^|\/)(frontend\/)?src\/(app|pages|routes)\//;
192
+ const appFile = /(^|\/)(frontend\/)?src\/(App|main|index)\.(jsx?|tsx?|vue|svelte)$/;
193
+ const componentFile = /(^|\/)(frontend\/)?src\/(components|ui|widgets)\//;
194
+ const apiFile = /(^|\/)(frontend\/)?src\/(lib|hooks|composables|stores|services|api)\/.*(api|client|query|fetch|request|finops)/;
195
+ const stylingFile = /tailwind\.config|globals\.css|app\.css|\.module\.css|\.scss$|(^|\/)(frontend\/)?src\/styles?\//;
196
+ const stateFile = /providers?\.(tsx?|jsx?)|react-query|use[A-Z].*\.(ts|tsx|js|jsx)|(^|\/)(stores?|state|pinia|zustand|redux)\//;
176
197
  return {
177
- app: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && (/frontend\/src\/app\//.test(rel) || /frontend\/src\/App\.[jt]sx?$/.test(rel) || /src\/App\.[jt]sx?$/.test(rel) || /src\/app\//.test(rel) || /apps\/[^/]+\/app\//.test(rel) || /apps\/[^/]+\/src\/app\//.test(rel)), 24).map((f) => f.path),
178
- components: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && (/frontend\/src\/components\//.test(rel) || /src\/components\//.test(rel) || /apps\/[^/]+\/.*components\//.test(rel) || /packages\/[^/]+\/.*components\//.test(rel)), 20).map((f) => f.path),
179
- apiClient: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && (/frontend\/src\/(lib|hooks)\/.*(api|client|query|finops)/.test(rel) || /src\/(lib|hooks)\/.*(api|client|query)/.test(rel)), 20).map((f) => f.path),
180
- styling: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && (/tailwind\.config|globals\.css|\.module\.css|frontend\/src\/app\/globals/.test(rel)), 20).map((f) => f.path),
181
- state: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && (/providers\.tsx|react-query|use[A-Z].*\.ts/.test(rel)), 20).map((f) => f.path),
198
+ app: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && (appSurface.test(rel) || appFile.test(rel) || /(^|\/)app\.vue$/.test(rel) || /apps\/[^/]+\/(app|pages|routes|src\/app|src\/pages|src\/routes)\//.test(rel)), 24).map((f) => f.path),
199
+ components: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && (componentFile.test(rel) || /apps\/[^/]+\/.*(components|ui|widgets)\//.test(rel) || /packages\/[^/]+\/.*(components|ui|widgets)\//.test(rel)), 24).map((f) => f.path),
200
+ apiClient: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && (apiFile.test(rel) || /apps\/[^/]+\/.*(lib|hooks|composables|services|api)\/.*(api|client|query|fetch|request)/.test(rel)), 24).map((f) => f.path),
201
+ styling: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && stylingFile.test(rel), 24).map((f) => f.path),
202
+ state: findRepoFiles(result, (rel) => !isNonSourcePath(rel) && stateFile.test(rel), 24).map((f) => f.path),
182
203
  };
183
204
  }
184
205
 
@@ -194,7 +215,7 @@ function createOptimizeContext(rootDir = process.cwd(), scope = null) {
194
215
  frameworks.some((name) => ["FastAPI", "Django", "Flask"].includes(name)) ||
195
216
  Boolean(backend.api.length || backend.services.length || backend.db.length || backend.auth.length);
196
217
  const frontendDetected = folders.includes("frontend") ||
197
- frameworks.some((name) => ["Next.js", "React", "Vite"].includes(name)) ||
218
+ frameworks.some((name) => ["Next.js", "React", "Vite", "Vue", "Svelte", "SvelteKit", "Solid", "Astro", "Nuxt"].includes(name)) ||
198
219
  Boolean(frontend.app.length || frontend.components.length || frontend.apiClient.length || frontend.state.length);
199
220
  const warnings = [];
200
221
  if (scan.exposedLargeFiles.length) warnings.push(`${scan.exposedLargeFiles.length} exposed large file(s) may bloat AI context.`);
@@ -321,7 +342,7 @@ function formatGitActivity(activity) {
321
342
  }
322
343
 
323
344
  function topLoadBearing(root, files, allFiles, gitActivity, limit = 8) {
324
- const textFiles = (allFiles || []).filter((file) => !file.ignored && file.kind !== "binary" && /\.(py|tsx?|jsx?)$/.test(file.path));
345
+ const textFiles = (allFiles || []).filter((file) => !file.ignored && file.kind !== "binary" && /\.(py|tsx?|jsx?|mjs|cjs|vue|svelte)$/.test(file.path));
325
346
  const sourcePaths = new Set(textFiles.map((file) => file.path));
326
347
  const pythonModuleToPath = new Map();
327
348
  for (const file of textFiles.filter((candidate) => candidate.path.endsWith(".py"))) {
@@ -338,7 +359,7 @@ function topLoadBearing(root, files, allFiles, gitActivity, limit = 8) {
338
359
  const target = pythonModuleToPath.get(imported) || pythonModuleToPath.get(imported.split(".").pop());
339
360
  if (target && target !== file.path) importRefs.set(target, (importRefs.get(target) || 0) + 1);
340
361
  }
341
- } else if (/\.(tsx?|jsx?)$/.test(file.path)) {
362
+ } else if (/\.(tsx?|jsx?|mjs|cjs|vue|svelte)$/.test(file.path)) {
342
363
  for (const target of extractJsImports(file.path, text, sourcePaths)) {
343
364
  if (target !== file.path) importRefs.set(target, (importRefs.get(target) || 0) + 1);
344
365
  }
@@ -520,7 +541,7 @@ function renderBackendSummary(ctx) {
520
541
  }
521
542
 
522
543
  function renderFrontendSummary(ctx) {
523
- const frontendCandidates = topLoadBearing(ctx.root, ctx.scan.files.filter((file) => /\.(tsx?|jsx?)$/.test(file.path) && /(^|\/)(frontend|src|app|components|hooks)\//.test(file.path)), ctx.scan.files, ctx.gitActivity, 8);
544
+ const frontendCandidates = topLoadBearing(ctx.root, ctx.scan.files.filter((file) => /\.(tsx?|jsx?|mjs|cjs|vue|svelte)$/.test(file.path) && /(^|\/)(frontend|src|app|pages|routes|components|ui|hooks|composables|stores)\//.test(file.path)), ctx.scan.files, ctx.gitActivity, 8);
524
545
  return [
525
546
  "# Frontend Summary",
526
547
  "",
@@ -78,7 +78,15 @@ function buildBlockedContext(ctx) {
78
78
  "playwright-report/**",
79
79
  "test-results/**",
80
80
  "logs/**",
81
+ "events/**",
82
+ "event-dumps/**",
83
+ "session-dumps/**",
84
+ "source-streams/**",
85
+ "inbox-dumps/**",
86
+ "calendar-dumps/**",
81
87
  "**/*.log",
88
+ "**/*.jsonl",
89
+ "**/*.ndjson",
82
90
  "**/*.map",
83
91
  "**/__pycache__/**",
84
92
  "package-lock.json",
@@ -68,6 +68,13 @@ function renderTerminalReport(result, options = {}) {
68
68
  if (result.toolOutputRisk.exposedNoisyDirectories.length) lines.push(`- Exposed noisy dirs: ${result.toolOutputRisk.exposedNoisyDirectories.slice(0, 6).join(", ")}`);
69
69
  if (result.toolOutputRisk.exposedNoisyFiles.length) lines.push(`- Exposed noisy files: ${result.toolOutputRisk.exposedNoisyFiles.slice(0, 4).map((file) => file.path).join(", ")}`);
70
70
  lines.push("");
71
+ if (result.operationalNoise && result.operationalNoise.level !== "Low") {
72
+ lines.push(color("Operational Noise Risk", "bold", useColor));
73
+ lines.push(`- Level: ${result.operationalNoise.level}`);
74
+ lines.push(`- ${result.operationalNoise.summary}`);
75
+ result.operationalNoise.files.slice(0, 4).forEach((file) => lines.push(`- ${file.path}: ${file.signals.join(", ")}`));
76
+ lines.push("");
77
+ }
71
78
  lines.push(color("Prismo Proxy Tracking", "bold", useColor));
72
79
  lines.push("- Exact API tracking: available when traffic uses the Prismo OpenAI/Anthropic base URL");
73
80
  lines.push(`- Codex API/base-url mode: ${result.proxyTrackingReadiness.codingAgentBaseUrlMode.codex}`);
@@ -233,6 +240,18 @@ function renderMarkdownReport(result) {
233
240
  });
234
241
  }
235
242
  lines.push("");
243
+ lines.push("## Operational Source-Stream Noise");
244
+ lines.push("");
245
+ if (result.operationalNoise && result.operationalNoise.files.length) {
246
+ lines.push(`- Level: ${result.operationalNoise.level}`);
247
+ lines.push(`- ${result.operationalNoise.summary}`);
248
+ result.operationalNoise.files.slice(0, 20).forEach((file) => {
249
+ lines.push(`- \`${file.path}\` - ${formatBytes(file.sizeBytes)} - ${file.signals.join(", ")} - ~${file.estimatedTokensIfRead.toLocaleString()} tokens if read`);
250
+ });
251
+ } else {
252
+ lines.push("- No obvious inbox/calendar/GitHub/source-stream dumps detected.");
253
+ }
254
+ lines.push("");
236
255
  lines.push("## Prismo Proxy Tracking Readiness");
237
256
  lines.push("");
238
257
  lines.push("- Exact API tracking: available when app/tool traffic uses the Prismo OpenAI/Anthropic base URL.");
@@ -364,6 +364,57 @@ function detectToolOutputRisk({ exposedLargeFiles, exposedHighRiskDirs, highRisk
364
364
  };
365
365
  }
366
366
 
367
+ function detectOperationalNoise(files) {
368
+ const candidates = files
369
+ .filter((file) => !file.ignored && file.size >= 16 * 1024 && file.kind !== "binary")
370
+ .filter((file) => /\.(json|jsonl|ndjson|log|md|txt)$/i.test(file.path) || /(events?|inbox|calendar|github|issues?|heartbeat|poll|source-stream|session-dump|activity|notifications?)/i.test(file.path))
371
+ .slice(0, 120);
372
+ const findings = [];
373
+
374
+ for (const file of candidates) {
375
+ const text = readIfText(file.fullPath, 512 * 1024) || "";
376
+ if (!text) continue;
377
+ const signals = [];
378
+ const timestampCount = (text.match(/\b20\d{2}-\d{2}-\d{2}[T ][0-2]\d:/g) || []).length;
379
+ const emailCount = (text.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi) || []).length;
380
+ const eventKeyCount = (text.match(/"(event|type|timestamp|created_at|updated_at|attendees|organizer|sender|subject|body|issue|pull_request|repository|payload)"\s*:/gi) || []).length;
381
+ const markdownEventCount = (text.match(/\b(calendar|inbox|email|github|issue|pull request|notification|attendee|heartbeat|poll(ed|ing)?)\b/gi) || []).length;
382
+ const repeatedObjectCount = (text.match(/^\s*\{.*\}\s*$/gm) || []).length;
383
+
384
+ if (timestampCount >= 12) signals.push(`${timestampCount} timestamps`);
385
+ if (emailCount >= 8) signals.push(`${emailCount} email-like strings`);
386
+ if (eventKeyCount >= 30) signals.push(`${eventKeyCount} event-shaped JSON keys`);
387
+ if (markdownEventCount >= 20) signals.push(`${markdownEventCount} operational keywords`);
388
+ if (repeatedObjectCount >= 15) signals.push(`${repeatedObjectCount} JSONL-style objects`);
389
+
390
+ if (signals.length >= 2 || eventKeyCount >= 60 || (timestampCount >= 20 && markdownEventCount >= 15)) {
391
+ findings.push({
392
+ path: file.path,
393
+ sizeBytes: file.size,
394
+ estimatedTokensIfRead: estimateTokens(file.size),
395
+ signals: signals.slice(0, 4),
396
+ });
397
+ }
398
+ }
399
+
400
+ const estimatedExposureTokens = findings.reduce((sum, item) => sum + item.estimatedTokensIfRead, 0);
401
+ let level = "Low";
402
+ if (findings.length >= 3 || estimatedExposureTokens >= 150000) level = "High";
403
+ else if (findings.length || estimatedExposureTokens >= 25000) level = "Medium";
404
+
405
+ return {
406
+ level,
407
+ files: findings.slice(0, 12),
408
+ estimatedExposureTokens,
409
+ summary:
410
+ level === "High"
411
+ ? "Operational source-stream dumps may be leaking inbox/calendar/GitHub-style noise back into coding context."
412
+ : level === "Medium"
413
+ ? "Possible operational source-stream dumps detected; these can become second-order context leaks."
414
+ : "No obvious operational source-stream dumps detected.",
415
+ };
416
+ }
417
+
367
418
  function buildProxyTrackingReadiness({ codexConfig, claudeConfig, realUsage }) {
368
419
  return {
369
420
  exactApiTracking: {
@@ -578,7 +629,7 @@ function addIssue(issues, severity, category, title, description, recommendation
578
629
  });
579
630
  }
580
631
 
581
- function buildRecommendations({ hasClaudeIgnore, gitignorePatterns, exposedHighRiskDirs, largeFiles, instructionFiles, claudeConfig, toolOutputRisk, agentReadiness }) {
632
+ function buildRecommendations({ hasClaudeIgnore, gitignorePatterns, exposedHighRiskDirs, largeFiles, instructionFiles, claudeConfig, toolOutputRisk, operationalNoise, agentReadiness }) {
582
633
  const recs = [];
583
634
  if (!hasClaudeIgnore) {
584
635
  recs.push("Create .claudeignore with generated/cache folders and large artifacts excluded.");
@@ -595,6 +646,9 @@ function buildRecommendations({ hasClaudeIgnore, gitignorePatterns, exposedHighR
595
646
  if (toolOutputRisk && toolOutputRisk.level !== "Low") {
596
647
  recs.push("Use command-output filtering or narrower shell commands for noisy tests, logs, diffs, and generated reports.");
597
648
  }
649
+ if (operationalNoise && operationalNoise.level !== "Low") {
650
+ recs.push("Keep inbox/calendar/GitHub polling dumps out of coding-agent context; summarize them outside the repo or add them to AI ignore files.");
651
+ }
598
652
  if (instructionFiles.some((file) => file.isClaude && file.tokens > 1500)) {
599
653
  recs.push("Review CLAUDE.md for content that could move to linked docs; keep persistent instructions focused on durable rules.");
600
654
  }
@@ -665,7 +719,7 @@ function calculateReductionPercent(beforeTokens, afterTokens) {
665
719
 
666
720
  function chooseRecommendedScope(ctx) {
667
721
  if (ctx.scope) return ctx.scope;
668
- if (ctx.frameworks.some((name) => ["Next.js", "React", "Vite"].includes(name))) return "frontend";
722
+ if (ctx.frameworks.some((name) => ["Next.js", "React", "Vite", "Vue", "Svelte", "SvelteKit", "Solid", "Astro", "Nuxt"].includes(name))) return "frontend";
669
723
  if (ctx.frameworks.some((name) => ["FastAPI", "Django", "Flask", "Python"].includes(name))) return "backend";
670
724
  return null;
671
725
  }
@@ -720,6 +774,7 @@ function toJsonPayload(result) {
720
774
  agentReadiness: result.agentReadiness,
721
775
  optimizationStack: result.optimizationStack,
722
776
  toolOutputRisk: result.toolOutputRisk,
777
+ operationalNoise: result.operationalNoise,
723
778
  proxyTrackingReadiness: result.proxyTrackingReadiness,
724
779
  suggestedClaudeIgnore: result.recommendedClaudeIgnore,
725
780
  suggestedCursorIgnore: result.recommendedCursorIgnore,
@@ -1010,6 +1065,7 @@ function scanRepo(rootDir = process.cwd(), options = {}) {
1010
1065
  const optimizationStack = detectOptimizationStack(root, claudeConfig, codexConfig);
1011
1066
  const agentReadiness = detectAgentReadiness(root, claudeConfig, codexConfig, realUsage);
1012
1067
  const toolOutputRisk = detectToolOutputRisk({ exposedLargeFiles, exposedHighRiskDirs, highRiskDirs });
1068
+ const operationalNoise = detectOperationalNoise(files);
1013
1069
  const proxyTrackingReadiness = buildProxyTrackingReadiness({ codexConfig, claudeConfig, realUsage });
1014
1070
 
1015
1071
  if (toolOutputRisk.level !== "Low") {
@@ -1026,6 +1082,20 @@ function scanRepo(rootDir = process.cwd(), options = {}) {
1026
1082
  );
1027
1083
  }
1028
1084
 
1085
+ if (operationalNoise.level !== "Low") {
1086
+ addIssue(
1087
+ issues,
1088
+ operationalNoise.level === "High" ? "high" : "medium",
1089
+ "operational_noise",
1090
+ `${operationalNoise.files.length} source-stream dump${operationalNoise.files.length === 1 ? "" : "s"} may leak into context`,
1091
+ operationalNoise.files.slice(0, 5).map((file) => `${file.path} (${file.signals.join(", ")})`).join(", "),
1092
+ "Do not feed raw inbox/calendar/GitHub/event dumps back into coding sessions; summarize externally or add them to .claudeignore/.cursorignore.",
1093
+ operationalNoise.estimatedExposureTokens
1094
+ ? `Likely avoidable token exposure: up to ~${operationalNoise.estimatedExposureTokens.toLocaleString()} tokens from operational noise files.`
1095
+ : "Potential savings estimate: prevents source-stream dumps from becoming recurring context."
1096
+ );
1097
+ }
1098
+
1029
1099
  if (optimizationStack.mcpServerTotal >= 8) {
1030
1100
  addIssue(
1031
1101
  issues,
@@ -1074,10 +1144,12 @@ function scanRepo(rootDir = process.cwd(), options = {}) {
1074
1144
  const largeFileSuggestions = exposedLargeFiles
1075
1145
  .filter((file) => file.size >= 1024 * 1024 || ["log", "json", "minified", "lock/generated"].includes(file.kind))
1076
1146
  .map((file) => file.path);
1147
+ const operationalNoiseSuggestions = operationalNoise.files.map((file) => file.path);
1077
1148
  const recommendedClaudeIgnore = Array.from(new Set([
1078
1149
  ...DEFAULT_CLAUDEIGNORE,
1079
1150
  ...gitignorePatterns.filter((line) => !line.startsWith("!")),
1080
1151
  ...largeFileSuggestions,
1152
+ ...operationalNoiseSuggestions,
1081
1153
  ]));
1082
1154
  const recommendedCursorIgnore = Array.from(new Set([
1083
1155
  ...recommendedClaudeIgnore,
@@ -1094,6 +1166,7 @@ function scanRepo(rootDir = process.cwd(), options = {}) {
1094
1166
  instructionFiles,
1095
1167
  claudeConfig,
1096
1168
  toolOutputRisk,
1169
+ operationalNoise,
1097
1170
  agentReadiness,
1098
1171
  });
1099
1172
  buildRealUsageRecommendations(realUsage).forEach((rec) => recommendations.push(rec));
@@ -1109,6 +1182,7 @@ function scanRepo(rootDir = process.cwd(), options = {}) {
1109
1182
  agentReadiness,
1110
1183
  optimizationStack,
1111
1184
  toolOutputRisk,
1185
+ operationalNoise,
1112
1186
  proxyTrackingReadiness,
1113
1187
  frameworks,
1114
1188
  files,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getprismo",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Local AI coding workflow scanner for Codex, Claude Code, Cursor, and token-waste diagnostics.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/shanirsh/prismodev#readme",