projscan 0.9.0 → 0.9.1

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 (48) hide show
  1. package/README.md +72 -72
  2. package/dist/analyzers/deadCodeCheck.d.ts +2 -2
  3. package/dist/analyzers/deadCodeCheck.js +4 -4
  4. package/dist/analyzers/unusedDependencyCheck.js +1 -1
  5. package/dist/cli/index.js +11 -11
  6. package/dist/core/ast.d.ts +1 -1
  7. package/dist/core/ast.js +2 -2
  8. package/dist/core/auditRunner.d.ts +1 -1
  9. package/dist/core/auditRunner.js +6 -6
  10. package/dist/core/coverageJoin.d.ts +1 -1
  11. package/dist/core/coverageJoin.js +1 -1
  12. package/dist/core/coverageParser.js +3 -3
  13. package/dist/core/dependencyAnalyzer.js +6 -6
  14. package/dist/core/embeddings.d.ts +1 -1
  15. package/dist/core/embeddings.js +2 -2
  16. package/dist/core/fileInspector.js +6 -6
  17. package/dist/core/hotspotAnalyzer.js +2 -2
  18. package/dist/core/importGraph.d.ts +1 -1
  19. package/dist/core/importGraph.js +1 -1
  20. package/dist/core/indexCache.d.ts +2 -2
  21. package/dist/core/indexCache.js +4 -4
  22. package/dist/core/outdatedDetector.d.ts +1 -1
  23. package/dist/core/outdatedDetector.js +1 -1
  24. package/dist/core/searchIndex.js +2 -2
  25. package/dist/core/semanticSearch.d.ts +1 -1
  26. package/dist/core/semanticSearch.js +2 -2
  27. package/dist/core/upgradePreview.js +1 -1
  28. package/dist/fixes/prettierFix.js +1 -1
  29. package/dist/fixes/testFix.js +1 -1
  30. package/dist/mcp/chunker.d.ts +1 -1
  31. package/dist/mcp/chunker.js +1 -1
  32. package/dist/mcp/pagination.d.ts +2 -2
  33. package/dist/mcp/pagination.js +2 -2
  34. package/dist/mcp/progress.d.ts +1 -1
  35. package/dist/mcp/prompts.js +3 -3
  36. package/dist/mcp/server.js +1 -1
  37. package/dist/mcp/tokenBudget.d.ts +1 -1
  38. package/dist/mcp/tokenBudget.js +2 -2
  39. package/dist/mcp/tools.js +8 -8
  40. package/dist/reporters/consoleReporter.js +11 -11
  41. package/dist/reporters/markdownReporter.js +14 -14
  42. package/dist/reporters/sarifReporter.js +1 -1
  43. package/dist/utils/banner.d.ts +3 -3
  44. package/dist/utils/banner.js +9 -9
  45. package/dist/utils/config.js +1 -1
  46. package/dist/utils/packageJsonLocator.d.ts +1 -1
  47. package/dist/utils/packageJsonLocator.js +1 -1
  48. package/package.json +2 -2
@@ -55,7 +55,7 @@ export function reportHealthMarkdown(issues) {
55
55
  lines.push('');
56
56
  for (const issue of issues) {
57
57
  const icon = issue.severity === 'error' ? '❌' : issue.severity === 'warning' ? '⚠️' : 'ℹ️';
58
- lines.push(`- ${icon} **${issue.title}** ${issue.description}`);
58
+ lines.push(`- ${icon} **${issue.title}** - ${issue.description}`);
59
59
  }
60
60
  }
61
61
  console.log(lines.join('\n'));
@@ -64,7 +64,7 @@ export function reportCiMarkdown(issues, threshold) {
64
64
  const { score, grade } = calculateScore(issues);
65
65
  const pass = score >= threshold;
66
66
  const lines = [
67
- `# Projscan CI ${pass ? 'PASS' : 'FAIL'}`,
67
+ `# Projscan CI - ${pass ? 'PASS' : 'FAIL'}`,
68
68
  '',
69
69
  `| Metric | Value |`,
70
70
  `| --- | --- |`,
@@ -77,14 +77,14 @@ export function reportCiMarkdown(issues, threshold) {
77
77
  lines.push('', '## Issues', '');
78
78
  for (const issue of issues) {
79
79
  const icon = issue.severity === 'error' ? '❌' : issue.severity === 'warning' ? '⚠️' : 'ℹ️';
80
- lines.push(`- ${icon} **${issue.title}** ${issue.description}`);
80
+ lines.push(`- ${icon} **${issue.title}** - ${issue.description}`);
81
81
  }
82
82
  }
83
83
  console.log(lines.join('\n'));
84
84
  }
85
85
  export function reportDiffMarkdown(diff) {
86
86
  const delta = diff.scoreDelta > 0 ? `+${diff.scoreDelta}` : String(diff.scoreDelta);
87
- const arrow = diff.scoreDelta > 0 ? '↑' : diff.scoreDelta < 0 ? '↓' : '';
87
+ const arrow = diff.scoreDelta > 0 ? '↑' : diff.scoreDelta < 0 ? '↓' : '-';
88
88
  const lines = [
89
89
  '# Health Diff',
90
90
  '',
@@ -224,7 +224,7 @@ export function reportFileMarkdown(insp) {
224
224
  if (h.daysSinceLastChange !== null)
225
225
  lines.push(`- **Last change:** ${h.daysSinceLastChange} days ago`);
226
226
  if (h.busFactorOne)
227
- lines.push('- ⚠️ **Bus factor 1** only one author has touched this.');
227
+ lines.push('- ⚠️ **Bus factor 1** - only one author has touched this.');
228
228
  if (h.reasons.length > 0)
229
229
  lines.push(`- ${h.reasons.join(', ')}`);
230
230
  }
@@ -232,7 +232,7 @@ export function reportFileMarkdown(insp) {
232
232
  lines.push('', '## Related Issues', '');
233
233
  for (const issue of insp.issues) {
234
234
  const icon = issue.severity === 'error' ? '❌' : issue.severity === 'warning' ? '⚠️' : 'ℹ️';
235
- lines.push(`- ${icon} **${issue.title}** ${issue.description}`);
235
+ lines.push(`- ${icon} **${issue.title}** - ${issue.description}`);
236
236
  }
237
237
  }
238
238
  if (insp.potentialIssues.length > 0) {
@@ -273,7 +273,7 @@ export function reportHotspotsMarkdown(report) {
273
273
  lines.push('| --- | ---: | --- | ---: | ---: | ---: | --- |');
274
274
  for (let i = 0; i < report.hotspots.length; i++) {
275
275
  const h = report.hotspots[i];
276
- const reasons = h.reasons.length > 0 ? h.reasons.join(', ') : '';
276
+ const reasons = h.reasons.length > 0 ? h.reasons.join(', ') : '-';
277
277
  lines.push(`| ${i + 1} | ${h.riskScore.toFixed(1)} | \`${h.relativePath}\` | ${h.churn} | ${h.lineCount} | ${h.issueCount} | ${reasons} |`);
278
278
  }
279
279
  console.log(lines.join('\n'));
@@ -298,7 +298,7 @@ export function reportOutdatedMarkdown(report) {
298
298
  lines.push('| Package | Scope | Declared | Installed | Drift |');
299
299
  lines.push('| --- | --- | --- | --- | --- |');
300
300
  for (const p of drifting) {
301
- lines.push(`| \`${p.name}\` | ${p.scope === 'devDependency' ? 'dev' : 'prod'} | ${p.declared} | ${p.installed ?? ''} | ${p.drift} |`);
301
+ lines.push(`| \`${p.name}\` | ${p.scope === 'devDependency' ? 'dev' : 'prod'} | ${p.declared} | ${p.installed ?? '-'} | ${p.drift} |`);
302
302
  }
303
303
  console.log(lines.join('\n'));
304
304
  }
@@ -313,7 +313,7 @@ export function reportAuditMarkdown(report) {
313
313
  }
314
314
  const s = report.summary;
315
315
  const total = s.critical + s.high + s.moderate + s.low + s.info;
316
- lines.push(`**${total}** findings ${s.critical} critical · ${s.high} high · ${s.moderate} moderate · ${s.low} low · ${s.info} info`);
316
+ lines.push(`**${total}** findings - ${s.critical} critical · ${s.high} high · ${s.moderate} moderate · ${s.low} low · ${s.info} info`);
317
317
  lines.push('');
318
318
  if (report.findings.length === 0) {
319
319
  lines.push('_No known vulnerabilities._');
@@ -330,15 +330,15 @@ export function reportAuditMarkdown(report) {
330
330
  }
331
331
  export function reportUpgradeMarkdown(preview) {
332
332
  const lines = [];
333
- lines.push(`# Upgrade Preview \`${preview.name}\``);
333
+ lines.push(`# Upgrade Preview - \`${preview.name}\``);
334
334
  lines.push('');
335
335
  if (!preview.available) {
336
336
  lines.push(`_${preview.reason ?? 'unavailable'}_`);
337
337
  console.log(lines.join('\n'));
338
338
  return;
339
339
  }
340
- lines.push(`- Declared: \`${preview.declared ?? ''}\``);
341
- lines.push(`- Installed: \`${preview.installed ?? ''}\``);
340
+ lines.push(`- Declared: \`${preview.declared ?? '-'}\``);
341
+ lines.push(`- Installed: \`${preview.installed ?? '-'}\``);
342
342
  lines.push(`- Drift: **${preview.drift}**`);
343
343
  lines.push('');
344
344
  if (preview.breakingMarkers.length > 0) {
@@ -383,8 +383,8 @@ export function reportCoverageMarkdown(report) {
383
383
  lines.push('| Priority | Coverage | Risk | Churn | File | Reasons |');
384
384
  lines.push('| ---: | ---: | ---: | ---: | --- | --- |');
385
385
  for (const e of report.entries) {
386
- const cov = e.coverage === null ? '' : `${e.coverage.toFixed(0)}%`;
387
- const reasons = e.reasons.length > 0 ? e.reasons.join(', ') : '';
386
+ const cov = e.coverage === null ? '-' : `${e.coverage.toFixed(0)}%`;
387
+ const reasons = e.reasons.length > 0 ? e.reasons.join(', ') : '-';
388
388
  lines.push(`| ${e.priority.toFixed(1)} | ${cov} | ${e.riskScore.toFixed(1)} | ${e.churn} | \`${e.relativePath}\` | ${reasons} |`);
389
389
  }
390
390
  console.log(lines.join('\n'));
@@ -2,7 +2,7 @@ const TOOL_INFO = {
2
2
  name: 'projscan',
3
3
  informationUri: 'https://github.com/abhiyoheswaran1/projscan',
4
4
  shortDescription: {
5
- text: 'Instant codebase insights doctor, x-ray, and architecture map.',
5
+ text: 'Instant codebase insights - doctor, x-ray, and architecture map.',
6
6
  },
7
7
  };
8
8
  const SEVERITY_TO_LEVEL = {
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Full two-panel welcome screen shown only on the default `projscan` command.
2
+ * Full two-panel welcome screen - shown only on the default `projscan` command.
3
3
  * Left panel: ASCII logo + version. Right panel: commands + what's new.
4
4
  */
5
5
  export declare function showBanner(): void;
6
6
  /**
7
- * Compact one-liner shown on subcommands (doctor, fix, etc.).
7
+ * Compact one-liner - shown on subcommands (doctor, fix, etc.).
8
8
  */
9
9
  export declare function showCompactBanner(): void;
10
10
  /**
11
- * Help screen shown by `projscan help`.
11
+ * Help screen - shown by `projscan help`.
12
12
  * Displays the full banner + detailed command reference.
13
13
  */
14
14
  export declare function showHelp(): void;
@@ -14,7 +14,7 @@ function getVersion() {
14
14
  }
15
15
  }
16
16
  /**
17
- * Full two-panel welcome screen shown only on the default `projscan` command.
17
+ * Full two-panel welcome screen - shown only on the default `projscan` command.
18
18
  * Left panel: ASCII logo + version. Right panel: commands + what's new.
19
19
  */
20
20
  export function showBanner() {
@@ -74,7 +74,7 @@ export function showBanner() {
74
74
  console.log('');
75
75
  }
76
76
  /**
77
- * Compact one-liner shown on subcommands (doctor, fix, etc.).
77
+ * Compact one-liner - shown on subcommands (doctor, fix, etc.).
78
78
  */
79
79
  export function showCompactBanner() {
80
80
  const version = getVersion();
@@ -82,7 +82,7 @@ export function showCompactBanner() {
82
82
  console.log(` ${chalk.cyan('◆')} ${chalk.white.bold('ProjScan')} ${chalk.dim(`v${version}`)}`);
83
83
  }
84
84
  /**
85
- * Help screen shown by `projscan help`.
85
+ * Help screen - shown by `projscan help`.
86
86
  * Displays the full banner + detailed command reference.
87
87
  */
88
88
  export function showHelp() {
@@ -93,26 +93,26 @@ export function showHelp() {
93
93
  const g = chalk.gray;
94
94
  const commands = [
95
95
  { cmd: 'projscan', desc: 'Full project analysis (default)' },
96
- { cmd: 'projscan doctor', desc: 'Health check detect issues and score your project' },
97
- { cmd: 'projscan hotspots', desc: 'Rank files by risk churn × complexity × issues × ownership' },
96
+ { cmd: 'projscan doctor', desc: 'Health check - detect issues and score your project' },
97
+ { cmd: 'projscan hotspots', desc: 'Rank files by risk - churn × complexity × issues × ownership' },
98
98
  { cmd: 'projscan search <query>', desc: 'BM25-ranked search across content, symbols, and paths' },
99
- { cmd: 'projscan file <path>', desc: 'Drill into a file purpose, risk, ownership, issues' },
99
+ { cmd: 'projscan file <path>', desc: 'Drill into a file - purpose, risk, ownership, issues' },
100
100
  { cmd: 'projscan fix', desc: 'Auto-fix detected issues (interactive)' },
101
101
  { cmd: 'projscan fix -y', desc: 'Auto-fix without prompting' },
102
- { cmd: 'projscan ci', desc: 'CI gate exit 1 if score below threshold' },
102
+ { cmd: 'projscan ci', desc: 'CI gate - exit 1 if score below threshold' },
103
103
  { cmd: 'projscan ci --min-score 80', desc: 'Set custom minimum score' },
104
104
  { cmd: 'projscan ci --changed-only', desc: 'Gate only on issues in this PR\'s diff' },
105
105
  { cmd: 'projscan ci --format sarif', desc: 'Emit SARIF 2.1.0 for GitHub Code Scanning' },
106
106
  { cmd: 'projscan diff', desc: 'Compare current health against saved baseline' },
107
107
  { cmd: 'projscan diff --save-baseline', desc: 'Save current state as baseline' },
108
- { cmd: 'projscan explain <file>', desc: 'Explain a file purpose, imports, exports' },
108
+ { cmd: 'projscan explain <file>', desc: 'Explain a file - purpose, imports, exports' },
109
109
  { cmd: 'projscan diagram', desc: 'Show architecture layer diagram' },
110
110
  { cmd: 'projscan structure', desc: 'Show directory structure overview' },
111
111
  { cmd: 'projscan dependencies', desc: 'Analyze project dependencies' },
112
112
  { cmd: 'projscan outdated', desc: 'Declared-vs-installed drift (offline)' },
113
113
  { cmd: 'projscan audit', desc: 'Run npm audit; SARIF-ready vulnerability report' },
114
114
  { cmd: 'projscan upgrade <pkg>', desc: 'Preview upgrade impact (CHANGELOG + importers, offline)' },
115
- { cmd: 'projscan coverage', desc: 'Coverage × hotspots surface scariest untested files' },
115
+ { cmd: 'projscan coverage', desc: 'Coverage × hotspots - surface scariest untested files' },
116
116
  { cmd: 'projscan badge', desc: 'Generate a health badge for your README' },
117
117
  { cmd: 'projscan mcp', desc: 'Run as MCP server for AI agents (Claude Code, Cursor, …)' },
118
118
  ];
@@ -19,7 +19,7 @@ export async function loadConfig(rootPath, explicitPath) {
19
19
  raw = await fs.readFile(candidate, 'utf-8');
20
20
  }
21
21
  catch {
22
- // File not present try next candidate.
22
+ // File not present - try next candidate.
23
23
  continue;
24
24
  }
25
25
  const parsed = safeParse(raw, candidate);
@@ -5,7 +5,7 @@ export interface PackageJsonLocations {
5
5
  /**
6
6
  * Parse package.json and find the line number of each dependency name
7
7
  * (within dependencies, devDependencies, peerDependencies, optionalDependencies).
8
- * Line numbers are 1-based. Uses regex against the raw text robust enough
8
+ * Line numbers are 1-based. Uses regex against the raw text - robust enough
9
9
  * for typical formatted package.json files.
10
10
  */
11
11
  export declare function findDependencyLines(rootPath: string): Promise<PackageJsonLocations | null>;
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  /**
4
4
  * Parse package.json and find the line number of each dependency name
5
5
  * (within dependencies, devDependencies, peerDependencies, optionalDependencies).
6
- * Line numbers are 1-based. Uses regex against the raw text robust enough
6
+ * Line numbers are 1-based. Uses regex against the raw text - robust enough
7
7
  * for typical formatted package.json files.
8
8
  */
9
9
  export async function findDependencyLines(rootPath) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "projscan",
3
- "version": "0.9.0",
4
- "description": "Agent-first code intelligence MCP server (2025-03-26) with AST parsing, code graph, BM25 + optional semantic search, cursor pagination, progress notifications, and context-budgeted output; CLI on the side",
3
+ "version": "0.9.1",
4
+ "description": "Agent-first code intelligence. MCP server (2025-03-26) with AST parsing, code graph, BM25 + optional semantic search, cursor pagination, progress notifications, and context-budgeted output. CLI on the side.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",