projscan 1.11.0 → 2.0.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 (38) hide show
  1. package/README.md +26 -24
  2. package/dist/cli/_shared.d.ts +1 -1
  3. package/dist/cli/_shared.js +4 -15
  4. package/dist/cli/_shared.js.map +1 -1
  5. package/dist/cli/commands/explain.js +4 -5
  6. package/dist/cli/commands/explain.js.map +1 -1
  7. package/dist/cli/commands/plugin.d.ts +3 -3
  8. package/dist/cli/commands/plugin.js +8 -8
  9. package/dist/cli/commands/plugin.js.map +1 -1
  10. package/dist/core/fileInspector.d.ts +2 -5
  11. package/dist/core/fileInspector.js +28 -103
  12. package/dist/core/fileInspector.js.map +1 -1
  13. package/dist/core/languages/LanguageAdapter.d.ts +3 -1
  14. package/dist/core/languages/LanguageAdapter.js +13 -1
  15. package/dist/core/languages/LanguageAdapter.js.map +1 -1
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.js +1 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/mcp/tools/_shared.d.ts +1 -1
  20. package/dist/mcp/tools/_shared.js +3 -15
  21. package/dist/mcp/tools/_shared.js.map +1 -1
  22. package/dist/mcp/tools/explain.js +1 -3
  23. package/dist/mcp/tools/explain.js.map +1 -1
  24. package/dist/mcp/tools/plugin.d.ts +4 -7
  25. package/dist/mcp/tools/plugin.js +6 -9
  26. package/dist/mcp/tools/plugin.js.map +1 -1
  27. package/dist/reporters/jsonReporter.d.ts +1 -0
  28. package/dist/reporters/jsonReporter.js +25 -19
  29. package/dist/reporters/jsonReporter.js.map +1 -1
  30. package/dist/tool-manifest.json +4 -4
  31. package/docs/2.0-MIGRATION.md +80 -0
  32. package/docs/PLUGIN-AUTHORING.md +209 -0
  33. package/docs/examples/plugins/policy.mjs +16 -0
  34. package/docs/examples/plugins/policy.projscan-plugin.json +8 -0
  35. package/docs/examples/plugins/team-radar.mjs +17 -0
  36. package/docs/examples/plugins/team-radar.projscan-plugin.json +8 -0
  37. package/docs/plugin.schema.json +70 -0
  38. package/package.json +7 -3
@@ -0,0 +1,209 @@
1
+ # Plugin Authoring
2
+
3
+ projscan 2.0 stabilizes the local analyzer and reporter plugin contract.
4
+ Plugin execution is opt-in via `PROJSCAN_PLUGINS_PREVIEW=1` so repositories
5
+ must explicitly trust local plugin code before it runs.
6
+
7
+ Plugins are local code. Enabling the opt-in flag means you trust the plugin code in
8
+ the repository, the same way you trust project scripts in `package.json`.
9
+ projscan does not fetch remote plugin code.
10
+
11
+ ## Layout
12
+
13
+ Plugin manifests live under `.projscan-plugins/`:
14
+
15
+ ```text
16
+ .projscan-plugins/
17
+ policy.projscan-plugin.json
18
+ policy.mjs
19
+ team-summary.projscan-plugin.json
20
+ team-summary.mjs
21
+ ```
22
+
23
+ ## Manifest
24
+
25
+ Analyzer plugins add issues to the normal projscan issue stream:
26
+
27
+ ```json
28
+ {
29
+ "schemaVersion": 1,
30
+ "name": "policy",
31
+ "kind": "analyzer",
32
+ "module": "./policy.mjs",
33
+ "category": "custom",
34
+ "description": "Project-specific policy checks"
35
+ }
36
+ ```
37
+
38
+ Reporter plugins render CLI output for selected commands:
39
+
40
+ ```json
41
+ {
42
+ "schemaVersion": 1,
43
+ "name": "team-summary",
44
+ "kind": "reporter",
45
+ "module": "./team-summary.mjs",
46
+ "commands": ["doctor", "analyze", "ci"],
47
+ "description": "Compact team health summary"
48
+ }
49
+ ```
50
+
51
+ Fields:
52
+
53
+ - `schemaVersion`: must be `1`.
54
+ - `name`: stable plugin identifier. Issue ids are prefixed with `plugin:<name>:`.
55
+ - `kind`: `analyzer` or `reporter`.
56
+ - `module`: relative path inside the plugin directory. Absolute paths and `..` are rejected.
57
+ - `category`: analyzer-only fallback issue category when a plugin issue omits one.
58
+ - `commands`: reporter-only list of CLI commands the reporter supports: `doctor`, `analyze`, `ci`.
59
+ - `description`: optional summary for humans and agents.
60
+
61
+ ## Schema
62
+
63
+ The machine-readable manifest schema lives at
64
+ [`docs/plugin.schema.json`](plugin.schema.json). The examples under
65
+ [`docs/examples/plugins/`](examples/plugins/) are tested in CI.
66
+
67
+ ## Analyzer Module
68
+
69
+ The module must export a `check(rootPath, files)` function, either as the
70
+ default export or a named export.
71
+
72
+ ```js
73
+ export default {
74
+ check: async (rootPath, files) => {
75
+ return files
76
+ .filter((file) => file.relativePath.endsWith('.ts'))
77
+ .filter((file) => file.relativePath.includes('legacy'))
78
+ .map((file) => ({
79
+ id: 'legacy-typescript-file',
80
+ title: 'Legacy TypeScript file',
81
+ description: `${file.relativePath} is under the legacy tree.`,
82
+ severity: 'warning',
83
+ category: 'custom',
84
+ fixAvailable: false,
85
+ locations: [{ file: file.relativePath, line: 1 }],
86
+ }));
87
+ },
88
+ };
89
+ ```
90
+
91
+ Required issue fields:
92
+
93
+ - `id`
94
+ - `title`
95
+ - `description`
96
+ - `severity`: `error`, `warning`, or `info`
97
+ - `category`
98
+ - `fixAvailable`
99
+
100
+ Malformed issues are dropped so one bad plugin cannot poison the issue stream.
101
+
102
+ ## Reporter Module
103
+
104
+ Reporter plugins are CLI-only. The module must export a
105
+ `render(context)` function, either as the default export or a named export.
106
+
107
+ ```js
108
+ export default {
109
+ render: async ({ command, payload }) => {
110
+ if (command === 'ci') {
111
+ return `CI ${payload.ci.pass ? 'passed' : 'failed'}: ${payload.ci.score}/100`;
112
+ }
113
+
114
+ const issues = payload.issues ?? [];
115
+ const score = payload.health?.score ?? 'analysis';
116
+ return `${command}: ${issues.length} issue(s), score ${score}`;
117
+ },
118
+ };
119
+ ```
120
+
121
+ `context` contains:
122
+
123
+ - `command`: `doctor`, `analyze`, or `ci`.
124
+ - `rootPath`: absolute project root.
125
+ - `manifest`: the validated reporter manifest.
126
+ - `payload`: the command payload.
127
+
128
+ Payloads:
129
+
130
+ - `doctor`: `{ health, issues }`
131
+ - `analyze`: the same `AnalysisReport` shape returned by `--format json`
132
+ - `ci`: `{ ci: { score, grade, pass, threshold, totalIssues, errors, warnings, info, issues } }`
133
+
134
+ Renderers must return a string. They should not write directly to stdout or
135
+ stderr; projscan writes the returned text after the renderer succeeds.
136
+
137
+ ## Custom Presentation
138
+
139
+ Reporter plugins are the customization boundary for team-specific presentation.
140
+ Use them for white-label reports, team-branded summaries, and output shaped for
141
+ local workflows. The built-in HTML reporter stays the default core renderer
142
+ instead of growing project-specific theming flags.
143
+
144
+ ## Validate
145
+
146
+ ```sh
147
+ projscan plugin validate .projscan-plugins/policy.projscan-plugin.json
148
+ projscan plugin validate .projscan-plugins/policy.projscan-plugin.json --format json
149
+ ```
150
+
151
+ Validation reports structured diagnostics with a stable `code`, the manifest
152
+ `field` when applicable, a `message`, and sometimes a `hint`.
153
+
154
+ ## List
155
+
156
+ ```sh
157
+ projscan plugin list
158
+ projscan plugin list --format json
159
+ ```
160
+
161
+ The list command discovers manifests whether or not execution is enabled. It
162
+ shows `enabled:false` until the opt-in flag is set.
163
+
164
+ ## Enable
165
+
166
+ ```sh
167
+ PROJSCAN_PLUGINS_PREVIEW=1 projscan doctor
168
+ PROJSCAN_PLUGINS_PREVIEW=1 projscan ci
169
+ PROJSCAN_PLUGINS_PREVIEW=1 projscan analyze
170
+ PROJSCAN_PLUGINS_PREVIEW=1 projscan doctor --reporter team-summary
171
+ PROJSCAN_PLUGINS_PREVIEW=1 projscan analyze --reporter team-summary
172
+ PROJSCAN_PLUGINS_PREVIEW=1 projscan ci --reporter team-summary
173
+ ```
174
+
175
+ When enabled, analyzer plugin issues are merged into the same issue stream as
176
+ built-in analyzer issues. That means they affect health scores and CI gates in
177
+ the same way.
178
+
179
+ Reporter plugins are selected with `--reporter <name>` on supported commands.
180
+ Do not combine `--reporter` with `--format json`, `markdown`, `sarif`, or
181
+ `html`; reporter output is its own stdout text.
182
+
183
+ ## MCP
184
+
185
+ The `projscan_plugin` MCP tool supports:
186
+
187
+ - `action: "list"`
188
+ - `action: "validate"` with `manifest_path`
189
+
190
+ Plugin execution for MCP `projscan_doctor` and `projscan_analyze` follows the
191
+ same `PROJSCAN_PLUGINS_PREVIEW` flag as the CLI.
192
+
193
+ Reporter rendering is CLI-only. MCP tools continue to return structured
194
+ payloads.
195
+
196
+ ## Failure Isolation
197
+
198
+ - One plugin failing to load does not stop other plugins.
199
+ - One plugin throwing during `check` does not stop built-in analyzers.
200
+ - Malformed issues are dropped.
201
+ - One reporter failing to load or render exits that CLI command with a
202
+ diagnostic instead of falling back to a misleading built-in report.
203
+ - Runtime plugin warnings go to stderr so JSON stdout stays parseable.
204
+
205
+ ## Compatibility
206
+
207
+ This is the stable 2.0 plugin contract for local analyzer and reporter plugins.
208
+ New optional manifest fields may be added in 2.x; existing required fields keep
209
+ their names and types.
@@ -0,0 +1,16 @@
1
+ export default {
2
+ check: async (_rootPath, files) => {
3
+ return files
4
+ .filter((file) => file.relativePath.endsWith('.ts'))
5
+ .filter((file) => file.relativePath.includes('legacy'))
6
+ .map((file) => ({
7
+ id: 'legacy-typescript-file',
8
+ title: 'Legacy TypeScript file',
9
+ description: `${file.relativePath} is under the legacy tree.`,
10
+ severity: 'warning',
11
+ category: 'custom',
12
+ fixAvailable: false,
13
+ locations: [{ file: file.relativePath, line: 1 }],
14
+ }));
15
+ },
16
+ };
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "name": "policy",
4
+ "kind": "analyzer",
5
+ "module": "./policy.mjs",
6
+ "category": "custom",
7
+ "description": "Flags legacy TypeScript files for team review"
8
+ }
@@ -0,0 +1,17 @@
1
+ export default {
2
+ render: async ({ command, payload }) => {
3
+ if (command === 'ci') {
4
+ const ci = payload.ci;
5
+ return `team-radar ci ${ci.pass ? 'pass' : 'fail'} ${ci.score}/100 ${ci.grade} ${ci.totalIssues} issue(s)`;
6
+ }
7
+
8
+ if (command === 'doctor') {
9
+ const health = payload.health;
10
+ const issues = Array.isArray(payload.issues) ? payload.issues.length : 0;
11
+ return `team-radar doctor ${health.score}/100 ${health.grade} ${issues} issue(s)`;
12
+ }
13
+
14
+ const issues = Array.isArray(payload.issues) ? payload.issues.length : 0;
15
+ return `team-radar analyze ${issues} issue(s)`;
16
+ },
17
+ };
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "name": "team-radar",
4
+ "kind": "reporter",
5
+ "module": "./team-radar.mjs",
6
+ "commands": ["doctor", "analyze", "ci"],
7
+ "description": "Compact team health summary"
8
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/abhiyoheswaran1/projscan/blob/main/docs/plugin.schema.json",
4
+ "title": "projscan plugin manifest",
5
+ "description": "Manifest schema for local projscan analyzer and reporter plugins.",
6
+ "oneOf": [
7
+ {
8
+ "title": "Analyzer plugin",
9
+ "type": "object",
10
+ "additionalProperties": false,
11
+ "required": ["schemaVersion", "name", "kind", "module", "category"],
12
+ "properties": {
13
+ "schemaVersion": {
14
+ "const": 1
15
+ },
16
+ "name": {
17
+ "type": "string",
18
+ "pattern": "^[a-z0-9._/-]{1,65}$"
19
+ },
20
+ "kind": {
21
+ "const": "analyzer"
22
+ },
23
+ "module": {
24
+ "type": "string",
25
+ "minLength": 1
26
+ },
27
+ "category": {
28
+ "type": "string",
29
+ "minLength": 1
30
+ },
31
+ "description": {
32
+ "type": "string"
33
+ }
34
+ }
35
+ },
36
+ {
37
+ "title": "Reporter plugin",
38
+ "type": "object",
39
+ "additionalProperties": false,
40
+ "required": ["schemaVersion", "name", "kind", "module", "commands"],
41
+ "properties": {
42
+ "schemaVersion": {
43
+ "const": 1
44
+ },
45
+ "name": {
46
+ "type": "string",
47
+ "pattern": "^[a-z0-9._/-]{1,65}$"
48
+ },
49
+ "kind": {
50
+ "const": "reporter"
51
+ },
52
+ "module": {
53
+ "type": "string",
54
+ "minLength": 1
55
+ },
56
+ "commands": {
57
+ "type": "array",
58
+ "minItems": 1,
59
+ "items": {
60
+ "enum": ["doctor", "analyze", "ci"]
61
+ },
62
+ "uniqueItems": true
63
+ },
64
+ "description": {
65
+ "type": "string"
66
+ }
67
+ }
68
+ }
69
+ ]
70
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "projscan",
3
3
  "mcpName": "io.github.abhiyoheswaran1/projscan",
4
- "version": "1.11.0",
5
- "description": "Agent-first code intelligence. MCP server (2025-03-26) with AST parsing for JavaScript, TypeScript, Python, Go, Java, Ruby, Rust, PHP, C#, Kotlin, Swift, and C++; code graph, file + per-function AST cyclomatic complexity, per-function fan-in + fan-out, coupling + cycle detection, structural PR diff with HTML reporter, coverage report with HTML reporter, intent-grounded one-call PR review (projscan_review with optional `intent` arg) and long-running PR-watch mode with structured per-bucket deltas (projscan_review_watch), rule-driven fix suggestions + mechanical apply layer with rollback (projscan_apply_fix, projscan_fix_suggest, projscan_explain_issue), source-to-sink taint analysis (projscan_taint) with truncation reporting, transitive blast-radius analysis with cross-repo mode (projscan_impact for files and symbols), cross-repo workspace registration + intelligence (projscan_workspace_graph), per-function semantic search chunks (sub-file embeddings), per-rule confidence + severity drift + cost-summary analytics with live streaming (projscan_cost_summary), analyzer + reporter plugin API preview (projscan_plugin, CLI --reporter, gated by PROJSCAN_PLUGINS_PREVIEW=1), monorepo workspace awareness with cross-package import policy + per-package dependencies / outdated / audit, BM25 + optional semantic search, cursor pagination, progress notifications, context-budgeted output, and a stable-surface CI guard. CLI on the side.",
4
+ "version": "2.0.0",
5
+ "description": "Agent-first code intelligence. MCP server (2025-03-26) with AST parsing for JavaScript, TypeScript, Python, Go, Java, Ruby, Rust, PHP, C#, Kotlin, Swift, and C++; code graph, file + per-function AST cyclomatic complexity, per-function fan-in + fan-out, coupling + cycle detection, structural PR diff with HTML reporter, coverage report with HTML reporter, intent-grounded one-call PR review (projscan_review with optional `intent` arg) and long-running PR-watch mode with structured per-bucket deltas (projscan_review_watch), rule-driven fix suggestions + mechanical apply layer with rollback (projscan_apply_fix, projscan_fix_suggest, projscan_explain_issue), source-to-sink taint analysis (projscan_taint) with truncation reporting, transitive blast-radius analysis with cross-repo mode (projscan_impact for files and symbols), cross-repo workspace registration + intelligence (projscan_workspace_graph), per-function semantic search chunks (sub-file embeddings), per-rule confidence + severity drift + cost-summary analytics with live streaming (projscan_cost_summary), stable local analyzer + reporter plugin API (projscan_plugin, CLI --reporter, opt-in via PROJSCAN_PLUGINS_PREVIEW=1), monorepo workspace awareness with cross-package import policy + per-package dependencies / outdated / audit, BM25 + optional semantic search, cursor pagination, progress notifications, context-budgeted output, and a stable-surface CI guard. CLI on the side.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
@@ -11,7 +11,11 @@
11
11
  },
12
12
  "files": [
13
13
  "dist",
14
- "README.md"
14
+ "README.md",
15
+ "docs/2.0-MIGRATION.md",
16
+ "docs/PLUGIN-AUTHORING.md",
17
+ "docs/plugin.schema.json",
18
+ "docs/examples/plugins"
15
19
  ],
16
20
  "scripts": {
17
21
  "build": "tsc && node scripts/copy-wasm.mjs && node scripts/generate-tool-manifest.mjs",