getprismo 0.1.7 → 0.1.8
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 +4 -0
- package/lib/prismo-dev/constants.js +13 -0
- package/lib/prismo-dev/context-optimize.js +13 -5
- package/lib/prismo-dev/fixes.js +8 -2
- package/lib/prismo-dev/report.js +10 -2
- package/lib/prismo-dev/scan.js +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -392,6 +392,10 @@ what doctor creates:
|
|
|
392
392
|
prismo-dev-report.md full diagnostic report
|
|
393
393
|
```
|
|
394
394
|
|
|
395
|
+
if an existing `.claudeignore` or `.cursorignore` already covers prismo's recommendations, doctor skips the suggested ignore file instead of creating redundant noise. the default recommendations include common project state, local db, export, credential, and token patterns such as `*_state.json`, `*_tokens.json`, `*_export.json`, `*.sqlite`, `models/`, and `state-backups/`.
|
|
396
|
+
|
|
397
|
+
backend and frontend summaries include load-bearing candidates ranked by lightweight reference signals plus file size, not just directory listings.
|
|
398
|
+
|
|
395
399
|
what doctor never touches:
|
|
396
400
|
|
|
397
401
|
- your real `CLAUDE.md`
|
|
@@ -122,6 +122,19 @@ const DEFAULT_CLAUDEIGNORE = [
|
|
|
122
122
|
"pnpm-lock.yaml",
|
|
123
123
|
"test-results/",
|
|
124
124
|
"playwright-report/",
|
|
125
|
+
"models/",
|
|
126
|
+
"state-backups/",
|
|
127
|
+
"backups/",
|
|
128
|
+
"*.sqlite",
|
|
129
|
+
"*.sqlite3",
|
|
130
|
+
"*.db",
|
|
131
|
+
"*_state.json",
|
|
132
|
+
"*_tokens.json",
|
|
133
|
+
"*_export.json",
|
|
134
|
+
"*secret*.json",
|
|
135
|
+
"*credential*.json",
|
|
136
|
+
".env",
|
|
137
|
+
".env.*",
|
|
125
138
|
];
|
|
126
139
|
|
|
127
140
|
const NPX_COMMAND = "npx getprismo";
|
|
@@ -217,12 +217,20 @@ function mdList(items, empty = "None detected.") {
|
|
|
217
217
|
return items.map((item) => `- \`${item}\``).join("\n");
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
function
|
|
220
|
+
function topLoadBearing(root, files, allFiles, limit = 8) {
|
|
221
|
+
const textFiles = (allFiles || []).filter((file) => !file.ignored && file.kind !== "binary" && /\.(py|tsx?|jsx?)$/.test(file.path));
|
|
222
|
+
const corpus = textFiles.map((file) => `${file.path}\n${readIfText(path.join(root, file.path)) || ""}`);
|
|
221
223
|
return [...(files || [])]
|
|
222
224
|
.filter((file) => !file.ignored && file.kind !== "binary")
|
|
223
|
-
.
|
|
225
|
+
.map((file) => {
|
|
226
|
+
const base = path.basename(file.path).replace(/\.[^.]+$/, "");
|
|
227
|
+
const importName = base.replace(/[-.]/g, "_");
|
|
228
|
+
const refs = corpus.reduce((sum, text) => sum + (text.includes(base) || text.includes(importName) ? 1 : 0), 0);
|
|
229
|
+
return { file, refs };
|
|
230
|
+
})
|
|
231
|
+
.sort((a, b) => b.refs - a.refs || b.file.size - a.file.size)
|
|
224
232
|
.slice(0, limit)
|
|
225
|
-
.map((file) => `${file.path} (${formatBytes(file.size)})`);
|
|
233
|
+
.map(({ file, refs }) => `${file.path} (${refs} reference signal${refs === 1 ? "" : "s"}, ${formatBytes(file.size)})`);
|
|
226
234
|
}
|
|
227
235
|
|
|
228
236
|
function inferGaps(ctx) {
|
|
@@ -334,7 +342,7 @@ function renderArchitectureSummary(ctx) {
|
|
|
334
342
|
}
|
|
335
343
|
|
|
336
344
|
function renderBackendSummary(ctx) {
|
|
337
|
-
const backendCandidates =
|
|
345
|
+
const backendCandidates = topLoadBearing(ctx.root, ctx.scan.files.filter((file) => file.path.endsWith(".py") && !isNonSourcePath(file.path)), ctx.scan.files, 8);
|
|
338
346
|
return [
|
|
339
347
|
"# Backend Summary",
|
|
340
348
|
"",
|
|
@@ -378,7 +386,7 @@ function renderBackendSummary(ctx) {
|
|
|
378
386
|
}
|
|
379
387
|
|
|
380
388
|
function renderFrontendSummary(ctx) {
|
|
381
|
-
const frontendCandidates =
|
|
389
|
+
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, 8);
|
|
382
390
|
return [
|
|
383
391
|
"# Frontend Summary",
|
|
384
392
|
"",
|
package/lib/prismo-dev/fixes.js
CHANGED
|
@@ -60,18 +60,24 @@ function applyFixes(result, options = {}) {
|
|
|
60
60
|
if (!result.hasClaudeIgnore) {
|
|
61
61
|
if (!options.dryRun) fs.writeFileSync(claudeIgnorePath, `${result.recommendedClaudeIgnore.join("\n")}\n`, "utf8");
|
|
62
62
|
actions.push(`${dryRunPrefix} .claudeignore`);
|
|
63
|
+
} else if (result.missingClaudeIgnoreSuggestions && result.missingClaudeIgnoreSuggestions.length === 0) {
|
|
64
|
+
actions.push("Skipped .claudeignore.prismo-suggested because existing .claudeignore already covers Prismo recommendations");
|
|
63
65
|
} else {
|
|
64
66
|
const backupPath = options.dryRun ? null : backupIfExists(suggestedClaudeIgnorePath);
|
|
65
|
-
|
|
67
|
+
const suggestions = result.missingClaudeIgnoreSuggestions || result.recommendedClaudeIgnore;
|
|
68
|
+
if (!options.dryRun) fs.writeFileSync(suggestedClaudeIgnorePath, `${suggestions.join("\n")}\n`, "utf8");
|
|
66
69
|
actions.push(`${dryRunPrefix} .claudeignore.prismo-suggested because .claudeignore already exists`);
|
|
67
70
|
if (backupPath) actions.push(`Backed up existing .claudeignore.prismo-suggested to ${path.basename(backupPath)}`);
|
|
68
71
|
}
|
|
69
72
|
if (!result.hasCursorIgnore) {
|
|
70
73
|
if (!options.dryRun) fs.writeFileSync(cursorIgnorePath, `${result.recommendedCursorIgnore.join("\n")}\n`, "utf8");
|
|
71
74
|
actions.push(`${dryRunPrefix} .cursorignore`);
|
|
75
|
+
} else if (result.missingCursorIgnoreSuggestions && result.missingCursorIgnoreSuggestions.length === 0) {
|
|
76
|
+
actions.push("Skipped .cursorignore.prismo-suggested because existing .cursorignore already covers Prismo recommendations");
|
|
72
77
|
} else {
|
|
73
78
|
const backupPath = options.dryRun ? null : backupIfExists(suggestedCursorIgnorePath);
|
|
74
|
-
|
|
79
|
+
const suggestions = result.missingCursorIgnoreSuggestions || result.recommendedCursorIgnore;
|
|
80
|
+
if (!options.dryRun) fs.writeFileSync(suggestedCursorIgnorePath, `${suggestions.join("\n")}\n`, "utf8");
|
|
75
81
|
actions.push(`${dryRunPrefix} .cursorignore.prismo-suggested because .cursorignore already exists`);
|
|
76
82
|
if (backupPath) actions.push(`Backed up existing .cursorignore.prismo-suggested to ${path.basename(backupPath)}`);
|
|
77
83
|
}
|
package/lib/prismo-dev/report.js
CHANGED
|
@@ -312,14 +312,22 @@ function renderMarkdownReport(result) {
|
|
|
312
312
|
lines.push("");
|
|
313
313
|
lines.push("## Recommended .claudeignore");
|
|
314
314
|
lines.push("");
|
|
315
|
+
if (result.hasClaudeIgnore && result.missingClaudeIgnoreSuggestions && !result.missingClaudeIgnoreSuggestions.length) {
|
|
316
|
+
lines.push("Existing .claudeignore already covers Prismo recommendations.");
|
|
317
|
+
lines.push("");
|
|
318
|
+
}
|
|
315
319
|
lines.push("```gitignore");
|
|
316
|
-
result.recommendedClaudeIgnore.forEach((line) => lines.push(line));
|
|
320
|
+
(result.hasClaudeIgnore && result.missingClaudeIgnoreSuggestions ? result.missingClaudeIgnoreSuggestions : result.recommendedClaudeIgnore).forEach((line) => lines.push(line));
|
|
317
321
|
lines.push("```");
|
|
318
322
|
lines.push("");
|
|
319
323
|
lines.push("## Recommended .cursorignore");
|
|
320
324
|
lines.push("");
|
|
325
|
+
if (result.hasCursorIgnore && result.missingCursorIgnoreSuggestions && !result.missingCursorIgnoreSuggestions.length) {
|
|
326
|
+
lines.push("Existing .cursorignore already covers Prismo recommendations.");
|
|
327
|
+
lines.push("");
|
|
328
|
+
}
|
|
321
329
|
lines.push("```gitignore");
|
|
322
|
-
result.recommendedCursorIgnore.forEach((line) => lines.push(line));
|
|
330
|
+
(result.hasCursorIgnore && result.missingCursorIgnoreSuggestions ? result.missingCursorIgnoreSuggestions : result.recommendedCursorIgnore).forEach((line) => lines.push(line));
|
|
323
331
|
lines.push("```");
|
|
324
332
|
lines.push("");
|
|
325
333
|
lines.push("## Recommended Next Steps");
|
package/lib/prismo-dev/scan.js
CHANGED
|
@@ -77,6 +77,26 @@ function isIgnored(relPath, patterns, isDir = false) {
|
|
|
77
77
|
return patterns.some((pattern) => patternMatches(pattern, relPath, isDir));
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
function ignoreSuggestionCovered(pattern, existingPatterns) {
|
|
81
|
+
if (!pattern) return true;
|
|
82
|
+
if (existingPatterns.includes(pattern)) return true;
|
|
83
|
+
const sample = pattern
|
|
84
|
+
.replace(/^\*\//, "")
|
|
85
|
+
.replace(/^\*\*/, "sample")
|
|
86
|
+
.replace(/\*/g, "sample")
|
|
87
|
+
.replace(/\/$/, "");
|
|
88
|
+
const isDir = pattern.endsWith("/") || pattern.endsWith("/**");
|
|
89
|
+
return existingPatterns.some((existing) => {
|
|
90
|
+
if (existing === pattern) return true;
|
|
91
|
+
if (existing.endsWith("/") && pattern.startsWith(existing)) return true;
|
|
92
|
+
return patternMatches(existing, sample, isDir);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function missingIgnoreSuggestions(recommended, existingPatterns) {
|
|
97
|
+
return recommended.filter((pattern) => !ignoreSuggestionCovered(pattern, existingPatterns));
|
|
98
|
+
}
|
|
99
|
+
|
|
80
100
|
function getFileKind(filePath) {
|
|
81
101
|
const ext = path.extname(filePath).toLowerCase();
|
|
82
102
|
const name = path.basename(filePath).toLowerCase();
|
|
@@ -703,6 +723,8 @@ function toJsonPayload(result) {
|
|
|
703
723
|
proxyTrackingReadiness: result.proxyTrackingReadiness,
|
|
704
724
|
suggestedClaudeIgnore: result.recommendedClaudeIgnore,
|
|
705
725
|
suggestedCursorIgnore: result.recommendedCursorIgnore,
|
|
726
|
+
missingClaudeIgnoreSuggestions: result.missingClaudeIgnoreSuggestions || [],
|
|
727
|
+
missingCursorIgnoreSuggestions: result.missingCursorIgnoreSuggestions || [],
|
|
706
728
|
nextCommands: getNextCommands(result),
|
|
707
729
|
generatedAt: result.generatedAt,
|
|
708
730
|
scannedPath: result.root,
|
|
@@ -1062,6 +1084,8 @@ function scanRepo(rootDir = process.cwd(), options = {}) {
|
|
|
1062
1084
|
".prismo/",
|
|
1063
1085
|
"prismo-optimized-CLAUDE.template.md",
|
|
1064
1086
|
]));
|
|
1087
|
+
const missingClaudeIgnoreSuggestions = hasClaudeIgnore ? missingIgnoreSuggestions(recommendedClaudeIgnore, claudeIgnorePatterns) : recommendedClaudeIgnore;
|
|
1088
|
+
const missingCursorIgnoreSuggestions = hasCursorIgnore ? missingIgnoreSuggestions(recommendedCursorIgnore, cursorIgnorePatterns) : recommendedCursorIgnore;
|
|
1065
1089
|
const recommendations = buildRecommendations({
|
|
1066
1090
|
hasClaudeIgnore,
|
|
1067
1091
|
gitignorePatterns,
|
|
@@ -1103,6 +1127,8 @@ function scanRepo(rootDir = process.cwd(), options = {}) {
|
|
|
1103
1127
|
repoDetected,
|
|
1104
1128
|
recommendedClaudeIgnore,
|
|
1105
1129
|
recommendedCursorIgnore,
|
|
1130
|
+
missingClaudeIgnoreSuggestions,
|
|
1131
|
+
missingCursorIgnoreSuggestions,
|
|
1106
1132
|
topTokenLeaks: getTopTokenLeaks(issues),
|
|
1107
1133
|
generatedAt: new Date().toISOString(),
|
|
1108
1134
|
};
|
package/package.json
CHANGED