projscan 2.9.0 → 3.0.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 (76) hide show
  1. package/README.md +31 -23
  2. package/dist/cli/commands/dataflow.d.ts +1 -0
  3. package/dist/cli/commands/dataflow.js +81 -0
  4. package/dist/cli/commands/dataflow.js.map +1 -0
  5. package/dist/cli/commands/semanticGraph.d.ts +1 -0
  6. package/dist/cli/commands/semanticGraph.js +55 -0
  7. package/dist/cli/commands/semanticGraph.js.map +1 -0
  8. package/dist/cli/index.js +4 -0
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/core/agentBrief.js +31 -1
  11. package/dist/core/agentBrief.js.map +1 -1
  12. package/dist/core/dataflow.d.ts +11 -0
  13. package/dist/core/dataflow.js +277 -0
  14. package/dist/core/dataflow.js.map +1 -0
  15. package/dist/core/dataflowFilters.d.ts +10 -0
  16. package/dist/core/dataflowFilters.js +44 -0
  17. package/dist/core/dataflowFilters.js.map +1 -0
  18. package/dist/core/graphCorpus.d.ts +5 -0
  19. package/dist/core/graphCorpus.js +46 -0
  20. package/dist/core/graphCorpus.js.map +1 -0
  21. package/dist/core/impact.js +34 -0
  22. package/dist/core/impact.js.map +1 -1
  23. package/dist/core/intent.d.ts +1 -1
  24. package/dist/core/intent.js +16 -0
  25. package/dist/core/intent.js.map +1 -1
  26. package/dist/core/issueEngine.js +25 -1
  27. package/dist/core/issueEngine.js.map +1 -1
  28. package/dist/core/plugins.d.ts +10 -3
  29. package/dist/core/plugins.js +2 -2
  30. package/dist/core/plugins.js.map +1 -1
  31. package/dist/core/prDiff.js +25 -1
  32. package/dist/core/prDiff.js.map +1 -1
  33. package/dist/core/preflight.js +75 -6
  34. package/dist/core/preflight.js.map +1 -1
  35. package/dist/core/regressionPlan.js +2 -0
  36. package/dist/core/regressionPlan.js.map +1 -1
  37. package/dist/core/review.js +109 -3
  38. package/dist/core/review.js.map +1 -1
  39. package/dist/core/reviewDataflow.d.ts +6 -0
  40. package/dist/core/reviewDataflow.js +21 -0
  41. package/dist/core/reviewDataflow.js.map +1 -0
  42. package/dist/core/semanticGraph.d.ts +7 -0
  43. package/dist/core/semanticGraph.js +167 -0
  44. package/dist/core/semanticGraph.js.map +1 -0
  45. package/dist/core/taint.d.ts +5 -5
  46. package/dist/core/taint.js +35 -6
  47. package/dist/core/taint.js.map +1 -1
  48. package/dist/core/watcher.d.ts +2 -2
  49. package/dist/core/watcher.js +103 -17
  50. package/dist/core/watcher.js.map +1 -1
  51. package/dist/core/workplan.js +8 -8
  52. package/dist/core/workplan.js.map +1 -1
  53. package/dist/index.d.ts +4 -1
  54. package/dist/index.js +3 -0
  55. package/dist/index.js.map +1 -1
  56. package/dist/mcp/tools/costSummary.js +2 -0
  57. package/dist/mcp/tools/costSummary.js.map +1 -1
  58. package/dist/mcp/tools/dataflow.d.ts +2 -0
  59. package/dist/mcp/tools/dataflow.js +69 -0
  60. package/dist/mcp/tools/dataflow.js.map +1 -0
  61. package/dist/mcp/tools/semanticGraph.d.ts +2 -0
  62. package/dist/mcp/tools/semanticGraph.js +40 -0
  63. package/dist/mcp/tools/semanticGraph.js.map +1 -0
  64. package/dist/mcp/tools.js +4 -0
  65. package/dist/mcp/tools.js.map +1 -1
  66. package/dist/projscan-sbom.cdx.json +6 -6
  67. package/dist/tool-manifest.json +63 -3
  68. package/dist/types.d.ts +144 -3
  69. package/dist/utils/formatSupport.d.ts +2 -0
  70. package/dist/utils/formatSupport.js +2 -0
  71. package/dist/utils/formatSupport.js.map +1 -1
  72. package/docs/PLUGIN-AUTHORING.md +11 -3
  73. package/docs/PLUGIN-GALLERY.md +8 -0
  74. package/docs/examples/plugins/graph-context.mjs +27 -0
  75. package/docs/examples/plugins/graph-context.projscan-plugin.json +8 -0
  76. package/package.json +4 -3
@@ -0,0 +1,69 @@
1
+ import { scanRepository } from '../../core/repositoryScanner.js';
2
+ import { buildCodeGraph } from '../../core/codeGraph.js';
3
+ import { computeDataflow } from '../../core/dataflow.js';
4
+ import { loadConfig } from '../../utils/config.js';
5
+ export const dataflowTool = {
6
+ name: 'projscan_dataflow',
7
+ description: 'Return v3 dataflow risks over the function graph. Includes legacy direct/propagated taint projections plus bridge-helper risks where a wrapper calls both a source reader and a dangerous sink.',
8
+ inputSchema: {
9
+ type: 'object',
10
+ properties: {
11
+ sources: {
12
+ type: 'array',
13
+ items: { type: 'string' },
14
+ description: 'Additional source names to merge with defaults and .projscanrc taint.sources.',
15
+ },
16
+ sinks: {
17
+ type: 'array',
18
+ items: { type: 'string' },
19
+ description: 'Additional sink names to merge with defaults and .projscanrc taint.sinks.',
20
+ },
21
+ max_risks: {
22
+ type: 'number',
23
+ description: 'Maximum risks to return. Default 50, max 500.',
24
+ },
25
+ include_tests: {
26
+ type: 'boolean',
27
+ description: 'Include dataflow risks that touch test files. Default false.',
28
+ },
29
+ include_broad_file_io: {
30
+ type: 'boolean',
31
+ description: 'Include broad readFile/writeFile-style default risks. Default false.',
32
+ },
33
+ max_tokens: {
34
+ type: 'number',
35
+ description: 'Cap the response to roughly this many tokens.',
36
+ },
37
+ },
38
+ },
39
+ handler: async (args, rootPath) => {
40
+ const scan = await scanRepository(rootPath);
41
+ const graph = await buildCodeGraph(rootPath, scan.files);
42
+ const { config } = await loadConfig(rootPath);
43
+ const sources = [
44
+ ...(config.taint?.sources ?? []),
45
+ ...(Array.isArray(args.sources)
46
+ ? args.sources.filter((value) => typeof value === 'string')
47
+ : []),
48
+ ];
49
+ const sinks = [
50
+ ...(config.taint?.sinks ?? []),
51
+ ...(Array.isArray(args.sinks)
52
+ ? args.sinks.filter((value) => typeof value === 'string')
53
+ : []),
54
+ ];
55
+ const maxRisks = typeof args.max_risks === 'number' && Number.isFinite(args.max_risks)
56
+ ? Math.max(1, Math.min(500, Math.floor(args.max_risks)))
57
+ : 50;
58
+ const report = computeDataflow(graph, { sources, sinks }, {
59
+ includeTests: args.include_tests === true,
60
+ includeBroadFileIo: args.include_broad_file_io === true,
61
+ });
62
+ return {
63
+ ...report,
64
+ risks: report.risks.slice(0, maxRisks),
65
+ truncated: report.risks.length > maxRisks || report.truncated,
66
+ };
67
+ },
68
+ };
69
+ //# sourceMappingURL=dataflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataflow.js","sourceRoot":"","sources":["../../../src/mcp/tools/dataflow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpTool } from './_shared.js';
2
+ export declare const semanticGraphTool: McpTool;
@@ -0,0 +1,40 @@
1
+ import { scanRepository } from '../../core/repositoryScanner.js';
2
+ import { buildCodeGraph } from '../../core/codeGraph.js';
3
+ import { buildSemanticGraph } from '../../core/semanticGraph.js';
4
+ import { loadCachedGraph, saveCachedGraph } from '../../core/indexCache.js';
5
+ export const semanticGraphTool = {
6
+ name: 'projscan_semantic_graph',
7
+ description: 'Return the stable v3 semantic graph: file/function/package/symbol nodes plus imports, exports, defines, and calls edges. Use when an agent needs one normalized graph contract instead of several targeted graph queries.',
8
+ inputSchema: {
9
+ type: 'object',
10
+ properties: {
11
+ max_nodes: {
12
+ type: 'number',
13
+ description: 'Maximum graph nodes to return. Default 10000.',
14
+ },
15
+ max_edges: {
16
+ type: 'number',
17
+ description: 'Maximum graph edges to return. Default 25000.',
18
+ },
19
+ max_tokens: {
20
+ type: 'number',
21
+ description: 'Cap the response to roughly this many tokens.',
22
+ },
23
+ },
24
+ },
25
+ handler: async (args, rootPath) => {
26
+ const scan = await scanRepository(rootPath);
27
+ const cached = await loadCachedGraph(rootPath);
28
+ const graph = await buildCodeGraph(rootPath, scan.files, cached);
29
+ await saveCachedGraph(rootPath, graph);
30
+ return buildSemanticGraph(graph, {
31
+ maxNodes: typeof args.max_nodes === 'number' && Number.isFinite(args.max_nodes)
32
+ ? args.max_nodes
33
+ : undefined,
34
+ maxEdges: typeof args.max_edges === 'number' && Number.isFinite(args.max_edges)
35
+ ? args.max_edges
36
+ : undefined,
37
+ });
38
+ },
39
+ };
40
+ //# sourceMappingURL=semanticGraph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semanticGraph.js","sourceRoot":"","sources":["../../../src/mcp/tools/semanticGraph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG5E,MAAM,CAAC,MAAM,iBAAiB,GAAY;IACxC,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EACT,2NAA2N;IAC7N,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+CAA+C;aAC7D;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+CAA+C;aAC7D;YACD,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+CAA+C;aAC7D;SACF;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACjE,MAAM,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACvC,OAAO,kBAAkB,CAAC,KAAK,EAAE;YAC/B,QAAQ,EACN,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;gBACnE,CAAC,CAAC,IAAI,CAAC,SAAS;gBAChB,CAAC,CAAC,SAAS;YACf,QAAQ,EACN,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;gBACnE,CAAC,CAAC,IAAI,CAAC,SAAS;gBAChB,CAAC,CAAC,SAAS;SAChB,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
package/dist/mcp/tools.js CHANGED
@@ -20,6 +20,7 @@ import { auditTool } from './tools/audit.js';
20
20
  import { upgradeTool } from './tools/upgrade.js';
21
21
  import { coverageTool } from './tools/coverage.js';
22
22
  import { graphTool } from './tools/graph.js';
23
+ import { semanticGraphTool } from './tools/semanticGraph.js';
23
24
  import { couplingTool } from './tools/coupling.js';
24
25
  import { workspacesTool } from './tools/workspaces.js';
25
26
  import { prDiffTool } from './tools/prDiff.js';
@@ -33,6 +34,7 @@ import { memoryTool } from './tools/memory.js';
33
34
  import { workspaceGraphTool } from './tools/workspaceGraph.js';
34
35
  import { applyFixTool } from './tools/applyFix.js';
35
36
  import { taintTool } from './tools/taint.js';
37
+ import { dataflowTool } from './tools/dataflow.js';
36
38
  import { costSummaryTool } from './tools/costSummary.js';
37
39
  import { reviewWatchTool } from './tools/reviewWatch.js';
38
40
  import { pluginTool } from './tools/plugin.js';
@@ -58,6 +60,7 @@ const tools = [
58
60
  upgradeTool,
59
61
  coverageTool,
60
62
  graphTool,
63
+ semanticGraphTool,
61
64
  couplingTool,
62
65
  workspacesTool,
63
66
  prDiffTool,
@@ -71,6 +74,7 @@ const tools = [
71
74
  workspaceGraphTool,
72
75
  applyFixTool,
73
76
  taintTool,
77
+ dataflowTool,
74
78
  costSummaryTool,
75
79
  reviewWatchTool,
76
80
  pluginTool,
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "bomFormat": "CycloneDX",
3
3
  "specVersion": "1.5",
4
- "serialNumber": "urn:uuid:b12746dd-8a61-4284-98be-050dd759568d",
4
+ "serialNumber": "urn:uuid:43e993dc-55dd-4723-a95a-ad09b6117db4",
5
5
  "version": 1,
6
6
  "metadata": {
7
- "timestamp": "2026-05-23T13:07:23.569Z",
7
+ "timestamp": "2026-05-26T20:40:36.688Z",
8
8
  "tools": [
9
9
  {
10
10
  "vendor": "projscan",
11
11
  "name": "projscan-sbom-generator",
12
- "version": "2.9.0"
12
+ "version": "3.0.1"
13
13
  }
14
14
  ],
15
15
  "component": {
16
16
  "type": "application",
17
- "bom-ref": "pkg:npm/projscan@2.9.0",
17
+ "bom-ref": "pkg:npm/projscan@3.0.1",
18
18
  "name": "projscan",
19
- "version": "2.9.0",
20
- "purl": "pkg:npm/projscan@2.9.0"
19
+ "version": "3.0.1",
20
+ "purl": "pkg:npm/projscan@3.0.1"
21
21
  }
22
22
  },
23
23
  "components": [
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "projscan",
3
- "version": "2.9.0",
3
+ "version": "3.0.1",
4
4
  "mcpProtocolVersion": "2025-03-26",
5
- "generatedAt": "2026-05-23T13:07:28.575Z",
6
- "toolCount": 37,
5
+ "generatedAt": "2026-05-26T20:40:40.856Z",
6
+ "toolCount": 39,
7
7
  "tools": [
8
8
  {
9
9
  "name": "projscan_analyze",
@@ -264,6 +264,27 @@
264
264
  ]
265
265
  }
266
266
  },
267
+ {
268
+ "name": "projscan_semantic_graph",
269
+ "description": "Return the stable v3 semantic graph: file/function/package/symbol nodes plus imports, exports, defines, and calls edges. Use when an agent needs one normalized graph contract instead of several targeted graph queries.",
270
+ "inputSchema": {
271
+ "type": "object",
272
+ "properties": {
273
+ "max_nodes": {
274
+ "type": "number",
275
+ "description": "Maximum graph nodes to return. Default 10000."
276
+ },
277
+ "max_edges": {
278
+ "type": "number",
279
+ "description": "Maximum graph edges to return. Default 25000."
280
+ },
281
+ "max_tokens": {
282
+ "type": "number",
283
+ "description": "Cap the response to roughly this many tokens."
284
+ }
285
+ }
286
+ }
287
+ },
267
288
  {
268
289
  "name": "projscan_coupling",
269
290
  "description": "Per-file coupling metrics (fan-in, fan-out, instability) and circular-import cycles, derived from the AST code graph. Use `direction` to focus the result: \"all\" returns every file sorted by fan-in; \"high_fan_in\" / \"high_fan_out\" sort accordingly; \"cycles_only\" returns just the files participating in import cycles. Cycles are reported separately as strongly-connected components of size >= 2.",
@@ -647,6 +668,45 @@
647
668
  }
648
669
  }
649
670
  },
671
+ {
672
+ "name": "projscan_dataflow",
673
+ "description": "Return v3 dataflow risks over the function graph. Includes legacy direct/propagated taint projections plus bridge-helper risks where a wrapper calls both a source reader and a dangerous sink.",
674
+ "inputSchema": {
675
+ "type": "object",
676
+ "properties": {
677
+ "sources": {
678
+ "type": "array",
679
+ "items": {
680
+ "type": "string"
681
+ },
682
+ "description": "Additional source names to merge with defaults and .projscanrc taint.sources."
683
+ },
684
+ "sinks": {
685
+ "type": "array",
686
+ "items": {
687
+ "type": "string"
688
+ },
689
+ "description": "Additional sink names to merge with defaults and .projscanrc taint.sinks."
690
+ },
691
+ "max_risks": {
692
+ "type": "number",
693
+ "description": "Maximum risks to return. Default 50, max 500."
694
+ },
695
+ "include_tests": {
696
+ "type": "boolean",
697
+ "description": "Include dataflow risks that touch test files. Default false."
698
+ },
699
+ "include_broad_file_io": {
700
+ "type": "boolean",
701
+ "description": "Include broad readFile/writeFile-style default risks. Default false."
702
+ },
703
+ "max_tokens": {
704
+ "type": "number",
705
+ "description": "Cap the response to roughly this many tokens."
706
+ }
707
+ }
708
+ }
709
+ },
650
710
  {
651
711
  "name": "projscan_cost_summary",
652
712
  "description": "Aggregate token-cost analytics from the current session's tool-call history. action:\"snapshot\" (default) returns total tokens spent, top spenders, per-tool typical/p95 estimates, and a static expected-cost catalog so the agent can budget pre-call. 1.10+: action:\"start_stream\" / \"stop_stream\" / \"list_streams\" turns this into a live cost dashboard — the server polls the session log on an interval and emits notifications/projscan/cost_delta whenever new tool calls have accrued, with the per-tool deltas and the new cumulative totals inline. Pairs with the `_cost` sidecar attached to every tool result. Read-only. Note: the session event log is bounded at 500 entries — for long-running sessions, older calls are dropped from the snapshot.",
package/dist/types.d.ts CHANGED
@@ -212,7 +212,7 @@ export interface HealthScore {
212
212
  }
213
213
  export type PreflightMode = 'before_edit' | 'before_commit' | 'before_merge';
214
214
  export type PreflightVerdict = 'proceed' | 'caution' | 'block';
215
- export type PreflightReasonSource = 'doctor' | 'review' | 'taint' | 'session' | 'plugin' | 'supply-chain' | 'memory' | 'changed-files' | 'hotspots' | 'git' | 'format';
215
+ export type PreflightReasonSource = 'doctor' | 'review' | 'taint' | 'session' | 'plugin' | 'supply-chain' | 'memory' | 'changed-files' | 'hotspots' | 'git' | 'format' | 'release';
216
216
  export interface PreflightReason {
217
217
  severity: IssueSeverity;
218
218
  source: PreflightReasonSource;
@@ -232,6 +232,15 @@ export interface PreflightSuggestedAction {
232
232
  tool?: string;
233
233
  args?: Record<string, unknown>;
234
234
  }
235
+ export interface PreflightReleaseScaleEvidence {
236
+ detected: boolean;
237
+ changedFiles: number;
238
+ threshold: number;
239
+ reviewVerdict?: ReviewReport['verdict'];
240
+ reviewSummary?: string;
241
+ concreteBlockers: string[];
242
+ explanation: string;
243
+ }
235
244
  export interface PreflightEvidence {
236
245
  health?: {
237
246
  score: number;
@@ -274,6 +283,7 @@ export interface PreflightEvidence {
274
283
  errorIssues: number;
275
284
  warningIssues: number;
276
285
  };
286
+ releaseScale?: PreflightReleaseScaleEvidence;
277
287
  }
278
288
  export interface PreflightReport {
279
289
  schemaVersion: 1;
@@ -290,7 +300,7 @@ export interface PreflightReport {
290
300
  export type WorkplanMode = PreflightMode | 'refactor' | 'release' | 'bug_hunt' | 'hardening';
291
301
  export type WorkplanPriority = 'p0' | 'p1' | 'p2';
292
302
  export interface WorkplanEvidence {
293
- source: PreflightReasonSource | 'coordination' | 'release' | 'verification';
303
+ source: PreflightReasonSource | 'coordination' | 'release' | 'verification' | 'graph';
294
304
  message: string;
295
305
  severity?: IssueSeverity;
296
306
  file?: string;
@@ -477,6 +487,16 @@ export interface AgentBriefGuardrail {
477
487
  reason: string;
478
488
  command: string;
479
489
  }
490
+ export interface GraphEvidenceSummary {
491
+ schemaVersion: 1;
492
+ changedFiles?: number;
493
+ changedFunctions?: number;
494
+ totalFunctions: number;
495
+ totalPackages: number;
496
+ totalCallEdges: number;
497
+ dataflowRisks: number;
498
+ topPackages: string[];
499
+ }
480
500
  export interface AgentBriefReport {
481
501
  schemaVersion: 1;
482
502
  intent: AgentBriefIntent;
@@ -491,12 +511,29 @@ export interface AgentBriefReport {
491
511
  }>;
492
512
  touchedFiles: string[];
493
513
  conflicts: number;
514
+ graph?: GraphEvidenceSummary;
494
515
  };
495
516
  focus: AgentBriefItem[];
496
517
  guardrails: AgentBriefGuardrail[];
497
518
  suggestedNextActions: PreflightSuggestedAction[];
498
519
  truncated?: boolean;
499
520
  }
521
+ export interface GraphCorpusFixtureMetrics {
522
+ name: string;
523
+ fixture: string;
524
+ files: number;
525
+ functions: number;
526
+ packages: number;
527
+ symbols: number;
528
+ importEdges: number;
529
+ callEdges: number;
530
+ dataflowRisks: number;
531
+ }
532
+ export interface GraphCorpusReport {
533
+ schemaVersion: 1;
534
+ fixtures: GraphCorpusFixtureMetrics[];
535
+ totals: Omit<GraphCorpusFixtureMetrics, 'name' | 'fixture'>;
536
+ }
500
537
  export type QualityScorecardVerdict = 'excellent' | 'healthy' | 'needs_attention' | 'blocked';
501
538
  export type QualityScorecardStatus = 'pass' | 'watch' | 'fail';
502
539
  export interface QualityScorecardDimension {
@@ -906,6 +943,76 @@ export interface PrDiffReport {
906
943
  filesModified: FileAstDiff[];
907
944
  totalFilesChanged: number;
908
945
  }
946
+ export type SemanticGraphNodeKind = 'file' | 'function' | 'package' | 'symbol';
947
+ export interface SemanticGraphNode {
948
+ id: string;
949
+ kind: SemanticGraphNodeKind;
950
+ label: string;
951
+ file?: string;
952
+ line?: number;
953
+ endLine?: number;
954
+ adapterId?: string;
955
+ metrics?: {
956
+ lineCount?: number;
957
+ cyclomaticComplexity?: number;
958
+ fanIn?: number;
959
+ fanOut?: number;
960
+ };
961
+ }
962
+ export type SemanticGraphEdgeKind = 'defines' | 'imports' | 'imports_package' | 'exports' | 'calls';
963
+ export interface SemanticGraphEdge {
964
+ from: string;
965
+ to: string;
966
+ kind: SemanticGraphEdgeKind;
967
+ label?: string;
968
+ }
969
+ export interface SemanticGraphReport {
970
+ schemaVersion: 3;
971
+ nodes: SemanticGraphNode[];
972
+ edges: SemanticGraphEdge[];
973
+ metrics: {
974
+ totalFiles: number;
975
+ totalFunctions: number;
976
+ totalPackages: number;
977
+ totalSymbols: number;
978
+ totalEdges: number;
979
+ };
980
+ truncated: boolean;
981
+ limits: {
982
+ maxNodes: number;
983
+ maxEdges: number;
984
+ };
985
+ }
986
+ export type DataflowRiskKind = 'direct' | 'propagated' | 'bridge';
987
+ export type DataflowRiskSeverity = 'warning' | 'error';
988
+ export type DataflowRiskConfidence = 'low' | 'medium' | 'high';
989
+ export interface DataflowRisk {
990
+ key: string;
991
+ kind: DataflowRiskKind;
992
+ severity: DataflowRiskSeverity;
993
+ confidence: DataflowRiskConfidence;
994
+ sourceFn: string;
995
+ sinkFn: string;
996
+ bridgeFn?: string;
997
+ source: string;
998
+ sink: string;
999
+ path: string[];
1000
+ sourcePath?: string[];
1001
+ sinkPath?: string[];
1002
+ pathLength: number;
1003
+ files: string[];
1004
+ }
1005
+ export interface DataflowReport {
1006
+ available: boolean;
1007
+ reason?: string;
1008
+ riskCount: number;
1009
+ risks: DataflowRisk[];
1010
+ effectiveSources: string[];
1011
+ effectiveSinks: string[];
1012
+ truncated?: boolean;
1013
+ truncatedSources?: string[];
1014
+ maxDepth?: number;
1015
+ }
909
1016
  /**
910
1017
  * One changed file enriched with risk signals. The agent calling
911
1018
  * projscan_review uses these to decide which files need careful review.
@@ -981,6 +1088,24 @@ export interface ReviewTaintFlow {
981
1088
  /** 1.9+ — set when `projscan_review` was called with an `intent` arg. Absent otherwise. */
982
1089
  intentAlignment?: 'expected' | 'unexpected' | 'out-of-scope' | 'unknown';
983
1090
  }
1091
+ /**
1092
+ * 3.0+ — Review-time dataflow risks that are not represented by legacy
1093
+ * taint reachability, especially bridge helpers that call both a source
1094
+ * wrapper and a sink wrapper.
1095
+ */
1096
+ export interface ReviewDataflowRisk {
1097
+ kind: DataflowRiskKind;
1098
+ sourceFn: string;
1099
+ sinkFn: string;
1100
+ bridgeFn?: string;
1101
+ source: string;
1102
+ sink: string;
1103
+ pathLength: number;
1104
+ files: string[];
1105
+ severity: DataflowRiskSeverity;
1106
+ confidence: DataflowRiskConfidence;
1107
+ intentAlignment?: 'expected' | 'unexpected' | 'out-of-scope' | 'unknown';
1108
+ }
984
1109
  /** Workspace-package-scoped dependency change. Aggregates root + workspaces. */
985
1110
  export interface ReviewDependencyChange {
986
1111
  /** Workspace name; '' for the root manifest. */
@@ -1046,6 +1171,13 @@ export interface ReviewReport {
1046
1171
  * (no per-function callSites at either side).
1047
1172
  */
1048
1173
  newTaintFlows: ReviewTaintFlow[];
1174
+ /**
1175
+ * 3.0+ — NEW dataflow risks introduced by this PR that are outside the
1176
+ * legacy source-to-sink taint flow list. Empty when unavailable or clean.
1177
+ */
1178
+ newDataflowRisks: ReviewDataflowRisk[];
1179
+ /** 3.5+ — compact graph/dataflow evidence for review consumers. */
1180
+ graphEvidence?: GraphEvidenceSummary;
1049
1181
  /** 'ok' = ship it; 'review' = needs careful look; 'block' = strongly suggests rework. */
1050
1182
  verdict: 'ok' | 'review' | 'block';
1051
1183
  /** One-line bullets explaining the verdict. */
@@ -1074,7 +1206,7 @@ export interface ReviewReport {
1074
1206
  intentAnalysis?: {
1075
1207
  totals: Record<'expected' | 'unexpected' | 'out-of-scope' | 'unknown', number>;
1076
1208
  notable: Array<{
1077
- kind: 'file' | 'function' | 'cycle' | 'taint' | 'dependency';
1209
+ kind: 'file' | 'function' | 'cycle' | 'taint' | 'dataflow' | 'dependency';
1078
1210
  label: string;
1079
1211
  alignment: 'expected' | 'unexpected' | 'out-of-scope' | 'unknown';
1080
1212
  reason: string;
@@ -1096,6 +1228,13 @@ export interface ImpactNode {
1096
1228
  */
1097
1229
  repo?: string;
1098
1230
  }
1231
+ export interface ImpactBoundarySummary {
1232
+ repo: string;
1233
+ packageName: string;
1234
+ owner: string;
1235
+ files: string[];
1236
+ reachableFiles: number;
1237
+ }
1099
1238
  export interface ImpactReport {
1100
1239
  available: boolean;
1101
1240
  reason?: string;
@@ -1126,6 +1265,8 @@ export interface ImpactReport {
1126
1265
  * was false or the workspace had no siblings.
1127
1266
  */
1128
1267
  totalReachableByRepo?: Record<string, number>;
1268
+ /** 3.5+ — cross-repo package/ownership boundaries that mention the target. */
1269
+ boundarySummary?: ImpactBoundarySummary[];
1129
1270
  /**
1130
1271
  * True when traversal hit `maxDistance` before exhausting the graph.
1131
1272
  * Items beyond the limit are omitted from `reachable`.
@@ -11,6 +11,7 @@ export declare const COMMAND_FORMAT_SUPPORT: {
11
11
  readonly coupling: readonly ["console", "json", "markdown", "html"];
12
12
  readonly coverage: readonly ["console", "json", "markdown", "html"];
13
13
  readonly dependencies: readonly ["console", "json", "markdown"];
14
+ readonly dataflow: readonly ["console", "json"];
14
15
  readonly diagram: readonly ["console", "json", "markdown"];
15
16
  readonly diff: readonly ["console", "json", "markdown"];
16
17
  readonly doctor: readonly ["console", "json", "markdown", "sarif", "html"];
@@ -46,6 +47,7 @@ export declare const COMMAND_FORMAT_SUPPORT: {
46
47
  readonly recipes: readonly ["console", "json"];
47
48
  readonly review: readonly ["console", "json", "markdown", "html"];
48
49
  readonly search: readonly ["console", "json", "markdown"];
50
+ readonly 'semantic-graph': readonly ["console", "json"];
49
51
  readonly session: readonly ["console", "json"];
50
52
  readonly 'session touched': readonly ["console", "json"];
51
53
  readonly 'session events': readonly ["console", "json"];
@@ -10,6 +10,7 @@ export const COMMAND_FORMAT_SUPPORT = {
10
10
  coupling: ['console', 'json', 'markdown', 'html'],
11
11
  coverage: ['console', 'json', 'markdown', 'html'],
12
12
  dependencies: ['console', 'json', 'markdown'],
13
+ dataflow: ['console', 'json'],
13
14
  diagram: ['console', 'json', 'markdown'],
14
15
  diff: ['console', 'json', 'markdown'],
15
16
  doctor: ['console', 'json', 'markdown', 'sarif', 'html'],
@@ -45,6 +46,7 @@ export const COMMAND_FORMAT_SUPPORT = {
45
46
  recipes: ['console', 'json'],
46
47
  review: ['console', 'json', 'markdown', 'html'],
47
48
  search: ['console', 'json', 'markdown'],
49
+ 'semantic-graph': ['console', 'json'],
48
50
  session: ['console', 'json'],
49
51
  'session touched': ['console', 'json'],
50
52
  'session events': ['console', 'json'],
@@ -1 +1 @@
1
- {"version":3,"file":"formatSupport.js","sourceRoot":"","sources":["../../src/utils/formatSupport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"formatSupport.js","sourceRoot":"","sources":["../../src/utils/formatSupport.ts"],"names":[],"mappings":"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"}
@@ -65,7 +65,7 @@ The machine-readable manifest schema lives at
65
65
  [`docs/examples/plugins/`](examples/plugins/) are tested in CI.
66
66
 
67
67
  For packaged examples you can copy into a repo, see the
68
- [Plugin Gallery](PLUGIN-GALLERY.md). It includes policy, team health, security,
68
+ [Plugin Gallery](PLUGIN-GALLERY.md). It includes policy, graph-context, team health, security,
69
69
  and release-readiness examples.
70
70
 
71
71
  ## Scaffold
@@ -84,8 +84,8 @@ It refuses to overwrite existing files.
84
84
 
85
85
  ## Analyzer Module
86
86
 
87
- The module must export a `check(rootPath, files)` function, either as the
88
- default export or a named export.
87
+ The module must export a `check(rootPath, files, context?)` function, either as the
88
+ default export or a named export. The optional third argument exposes lazy read-only graph helpers for analyzers that need deeper context.
89
89
 
90
90
  ```js
91
91
  export default {
@@ -117,6 +117,14 @@ Required issue fields:
117
117
 
118
118
  Malformed issues are dropped so one bad plugin cannot poison the issue stream.
119
119
 
120
+ The analyzer `context` argument currently exposes:
121
+
122
+ - `getCodeGraph()`: the underlying code graph used by core analysis.
123
+ - `getSemanticGraph()`: the stable v3 semantic graph payload.
124
+ - `getDataflow()`: the focused dataflow report.
125
+
126
+ The packaged `graph-context` example under `docs/examples/plugins/` demonstrates the pattern without requiring a manifest schema bump.
127
+
120
128
  ## Reporter Module
121
129
 
122
130
  Reporter plugins are CLI-only. The module must export a
@@ -32,6 +32,14 @@ Files:
32
32
  - `docs/examples/plugins/security-radar.projscan-plugin.json`
33
33
  - `docs/examples/plugins/security-radar.mjs`
34
34
 
35
+ ### `graph-context`
36
+
37
+ Demonstrates analyzer access to the optional graph/dataflow context. It reads the semantic graph and dataflow report through `context.getSemanticGraph()` and `context.getDataflow()` and emits a compact architecture summary issue.
38
+
39
+ Files:
40
+ - `docs/examples/plugins/graph-context.projscan-plugin.json`
41
+ - `docs/examples/plugins/graph-context.mjs`
42
+
35
43
  ## Reporter Plugins
36
44
 
37
45
  ### `team-radar`
@@ -0,0 +1,27 @@
1
+ export default {
2
+ check: async (_rootPath, files, context) => {
3
+ if (!context) return [];
4
+
5
+ const [semanticGraph, dataflow] = await Promise.all([
6
+ context.getSemanticGraph(),
7
+ context.getDataflow(),
8
+ ]);
9
+
10
+ const severity = dataflow.riskCount > 0 ? 'warning' : 'info';
11
+ const fileCount = files.length;
12
+ const functionCount = semanticGraph.metrics.totalFunctions;
13
+ const callEdges = semanticGraph.metrics.totalEdges;
14
+
15
+ return [
16
+ {
17
+ id: 'graph-context-summary',
18
+ title: 'Graph context available',
19
+ description:
20
+ `Plugin received ${fileCount} file(s), ${functionCount} function(s), ${callEdges} semantic edge(s), and ${dataflow.riskCount} dataflow risk(s).`,
21
+ severity,
22
+ category: 'architecture',
23
+ fixAvailable: false,
24
+ },
25
+ ];
26
+ },
27
+ };