pruneguard 0.3.1 → 0.4.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.
package/dist/index.d.mts CHANGED
@@ -126,6 +126,8 @@ type AnalysisReport = {
126
126
  ruleName?: string;
127
127
  primaryActionKind?: string;
128
128
  actionKinds?: string[];
129
+ trustNotes?: string[];
130
+ frameworkContext?: string[];
129
131
  }>;
130
132
  entrypoints: Array<{
131
133
  path: string;
@@ -133,6 +135,9 @@ type AnalysisReport = {
133
135
  profile: string;
134
136
  workspace?: string;
135
137
  source: string;
138
+ framework?: string;
139
+ reason?: string;
140
+ heuristic?: boolean;
136
141
  }>;
137
142
  stats: {
138
143
  durationMs: number;
@@ -147,6 +152,7 @@ type AnalysisReport = {
147
152
  tsconfigPathMiss: number;
148
153
  exportsConditionMiss: number;
149
154
  externalized: number;
155
+ workspaceExportsMiss: number;
150
156
  };
151
157
  resolvedViaExports: number;
152
158
  entrypointsDetected: number;
@@ -177,6 +183,16 @@ type AnalysisReport = {
177
183
  cacheEntriesRead: number;
178
184
  cacheEntriesWritten: number;
179
185
  affectedScopeIncomplete: boolean;
186
+ frameworksDetected: string[];
187
+ heuristicFrameworks: string[];
188
+ heuristicEntrypoints: number;
189
+ compatibilityWarnings: string[];
190
+ strictTrustApplied: boolean;
191
+ frameworkConfidenceCounts: {
192
+ exact: number;
193
+ heuristic: number;
194
+ unsupported: number;
195
+ };
180
196
  executionMode?: "oneshot" | "daemon";
181
197
  indexWarm?: boolean;
182
198
  indexAgeMs?: number;
@@ -223,6 +239,7 @@ type ReviewOptions = {
223
239
  baseRef?: string;
224
240
  noCache?: boolean;
225
241
  noBaseline?: boolean;
242
+ strictTrust?: boolean;
226
243
  };
227
244
  type ReviewReport = {
228
245
  baseRef?: string;
@@ -239,6 +256,7 @@ type ReviewReport = {
239
256
  medium: number;
240
257
  low: number;
241
258
  };
259
+ executionMode?: "oneshot" | "daemon";
242
260
  };
243
261
  recommendations: string[];
244
262
  proposedActions?: Array<{
@@ -256,6 +274,15 @@ type ReviewReport = {
256
274
  risk: "low" | "medium" | "high";
257
275
  confidence: "high" | "medium" | "low";
258
276
  }>;
277
+ compatibilityWarnings?: string[];
278
+ strictTrustApplied?: boolean;
279
+ recommendedActions?: Array<{
280
+ kind: string;
281
+ description: string;
282
+ priority: number;
283
+ command?: string;
284
+ targets?: string[];
285
+ }>;
259
286
  executionMode?: "oneshot" | "daemon";
260
287
  latencyMs?: number;
261
288
  };
@@ -270,20 +297,45 @@ type SafeDeleteReport = {
270
297
  targets: string[];
271
298
  safe: Array<{
272
299
  target: string;
300
+ classification: "safe" | "needs-review" | "blocked";
273
301
  confidence?: "high" | "medium" | "low";
274
302
  reasons: string[];
303
+ evidence: Array<{
304
+ kind: string;
305
+ file?: string;
306
+ line?: number;
307
+ description: string;
308
+ }>;
275
309
  }>;
276
310
  needsReview: Array<{
277
311
  target: string;
312
+ classification: "safe" | "needs-review" | "blocked";
278
313
  confidence?: "high" | "medium" | "low";
279
314
  reasons: string[];
315
+ evidence: Array<{
316
+ kind: string;
317
+ file?: string;
318
+ line?: number;
319
+ description: string;
320
+ }>;
280
321
  }>;
281
322
  blocked: Array<{
282
323
  target: string;
324
+ classification: "safe" | "needs-review" | "blocked";
283
325
  confidence?: "high" | "medium" | "low";
284
326
  reasons: string[];
327
+ evidence: Array<{
328
+ kind: string;
329
+ file?: string;
330
+ line?: number;
331
+ description: string;
332
+ }>;
333
+ }>;
334
+ deletionOrder: Array<{
335
+ target: string;
336
+ step: number;
337
+ reason?: string;
285
338
  }>;
286
- deletionOrder: string[];
287
339
  evidence: Array<{
288
340
  kind: string;
289
341
  file?: string;
@@ -312,26 +364,41 @@ type SuggestRulesReport = {
312
364
  configFragment: Record<string, unknown>;
313
365
  confidence: "high" | "medium" | "low";
314
366
  evidence?: string[];
367
+ rationale?: string;
315
368
  }>;
316
369
  tags?: Array<{
317
370
  name: string;
318
371
  glob: string;
319
372
  rationale: string;
373
+ source?: string;
320
374
  }>;
321
375
  ownershipHints?: Array<{
322
376
  pathGlob: string;
323
377
  suggestedOwner: string;
324
378
  crossTeamEdges: number;
325
379
  rationale: string;
380
+ touchedPackages?: string[];
326
381
  }>;
327
382
  hotspots?: Array<{
328
383
  file: string;
384
+ workspace?: string;
385
+ package?: string;
329
386
  crossPackageImports: number;
330
387
  crossOwnerImports: number;
331
388
  incomingEdges: number;
332
389
  outgoingEdges: number;
390
+ rank: number;
391
+ teamsInvolved?: string[];
333
392
  suggestion: string;
334
393
  }>;
394
+ governanceActions?: Array<{
395
+ priority: number;
396
+ kind: string;
397
+ description: string;
398
+ effort: "low" | "medium" | "high";
399
+ impact: "low" | "medium" | "high";
400
+ configFragment?: Record<string, unknown>;
401
+ }>;
335
402
  rationale?: string[];
336
403
  };
337
404
  type FixPlanReport = {
@@ -351,11 +418,22 @@ type FixPlanReport = {
351
418
  verification: string[];
352
419
  risk: "low" | "medium" | "high";
353
420
  confidence: "high" | "medium" | "low";
421
+ rank?: number;
422
+ phase?: string;
423
+ findingIds: string[];
354
424
  }>;
355
425
  blockedBy: string[];
356
426
  verificationSteps: string[];
357
427
  riskLevel: "low" | "medium" | "high";
358
428
  confidence: "high" | "medium" | "low";
429
+ totalActions: number;
430
+ highConfidenceActions: number;
431
+ phaseSummary: Array<{
432
+ name: string;
433
+ order: number;
434
+ actionCount: number;
435
+ description: string;
436
+ }>;
359
437
  };
360
438
  type DaemonStatusReport = {
361
439
  running: boolean;
@@ -364,6 +442,72 @@ type DaemonStatusReport = {
364
442
  version?: string;
365
443
  startedAt?: string;
366
444
  projectRoot?: string;
445
+ indexWarm?: boolean;
446
+ lastUpdateMs?: number;
447
+ graphNodes?: number;
448
+ graphEdges?: number;
449
+ watchedFiles?: number;
450
+ watcherLagMs?: number;
451
+ pendingInvalidations?: number;
452
+ generation?: number;
453
+ uptimeSecs?: number;
454
+ binaryPath?: string;
455
+ initialBuildMs?: number;
456
+ lastRebuildMs?: number;
457
+ incrementalRebuilds?: number;
458
+ totalInvalidations?: number;
459
+ configChangePending?: boolean;
460
+ };
461
+ type CompatibilityReportOptions = {
462
+ cwd?: string;
463
+ config?: string;
464
+ profile?: Profile;
465
+ };
466
+ type DebugFrameworksOptions = {
467
+ cwd?: string;
468
+ config?: string;
469
+ profile?: Profile;
470
+ };
471
+ type CompatibilityReport = {
472
+ supportedFrameworks: string[];
473
+ heuristicFrameworks: string[];
474
+ unsupportedSignals: Array<{
475
+ signal: string;
476
+ source: string;
477
+ suggestion?: string;
478
+ }>;
479
+ warnings: Array<{
480
+ code: string;
481
+ message: string;
482
+ affectedScope?: string;
483
+ severity: "low" | "medium" | "high";
484
+ }>;
485
+ trustDowngrades: Array<{
486
+ reason: string;
487
+ scope: string;
488
+ severity: "low" | "medium" | "high";
489
+ }>;
490
+ };
491
+ type FrameworkDebugReport = {
492
+ detectedPacks: Array<{
493
+ name: string;
494
+ confidence: string;
495
+ signals: string[];
496
+ reasons: string[];
497
+ }>;
498
+ allEntrypoints: Array<{
499
+ path: string;
500
+ framework: string;
501
+ kind: string;
502
+ heuristic: boolean;
503
+ reason: string;
504
+ }>;
505
+ allIgnorePatterns: string[];
506
+ allClassificationRules: Array<{
507
+ pattern: string;
508
+ classification: string;
509
+ }>;
510
+ heuristicDetections: string[];
367
511
  };
368
512
  declare function scan(options?: ScanOptions): Promise<AnalysisReport>;
369
513
  declare function scanDot(options?: ScanOptions): Promise<string>;
@@ -397,5 +541,7 @@ declare function migrateDepcruise(options?: {
397
541
  declare function daemonStatus(options?: {
398
542
  cwd?: string;
399
543
  }): Promise<DaemonStatusReport>;
544
+ declare function compatibilityReport(options?: CompatibilityReportOptions): Promise<CompatibilityReport>;
545
+ declare function debugFrameworks(options?: DebugFrameworksOptions): Promise<FrameworkDebugReport>;
400
546
  //#endregion
401
- export { AnalysisReport, type CommandResult, DaemonStatusReport, DebugEntrypointsOptions, DebugResolveOptions, ExplainOptions, ExplainReport, FixPlanOptions, FixPlanReport, ImpactOptions, ImpactReport, MigrationOutput, Profile, PruneguardConfig, PruneguardExecutionError, type ResolutionInfo, type ResolutionSource, ReviewOptions, ReviewReport, SafeDeleteOptions, SafeDeleteReport, ScanOptions, SuggestRulesOptions, SuggestRulesReport, binaryPath, daemonStatus, debugEntrypoints, debugResolve, explain, fixPlan, impact, loadConfig, migrateDepcruise, migrateKnip, resolutionInfo, review, run, safeDelete, scan, scanDot, schemaPath, suggestRules };
547
+ export { AnalysisReport, type CommandResult, CompatibilityReport, CompatibilityReportOptions, DaemonStatusReport, DebugEntrypointsOptions, DebugFrameworksOptions, DebugResolveOptions, ExplainOptions, ExplainReport, FixPlanOptions, FixPlanReport, FrameworkDebugReport, ImpactOptions, ImpactReport, MigrationOutput, Profile, PruneguardConfig, PruneguardExecutionError, type ResolutionInfo, type ResolutionSource, ReviewOptions, ReviewReport, SafeDeleteOptions, SafeDeleteReport, ScanOptions, SuggestRulesOptions, SuggestRulesReport, binaryPath, compatibilityReport, daemonStatus, debugEntrypoints, debugFrameworks, debugResolve, explain, fixPlan, impact, loadConfig, migrateDepcruise, migrateKnip, resolutionInfo, review, run, safeDelete, scan, scanDot, schemaPath, suggestRules };
package/dist/index.mjs CHANGED
@@ -126,6 +126,7 @@ async function review(options = {}) {
126
126
  if (options.baseRef) args.push("--changed-since", options.baseRef);
127
127
  if (options.noCache) args.push("--no-cache");
128
128
  if (options.noBaseline) args.push("--no-baseline");
129
+ if (options.strictTrust) args.push("--strict-trust");
129
130
  args.push("review");
130
131
  const result = await run$1(args, { cwd: options.cwd });
131
132
  if (result.exitCode !== 0 && result.exitCode !== 1) requireSuccess(result);
@@ -199,5 +200,21 @@ async function daemonStatus(options) {
199
200
  }
200
201
  return report;
201
202
  }
203
+ async function compatibilityReport(options = {}) {
204
+ const args = ["--format", "json"];
205
+ pushGlobalFlags(args, options);
206
+ args.push("compatibility-report");
207
+ const result = await run$1(args, { cwd: options.cwd });
208
+ requireSuccess(result);
209
+ return parseJson(result);
210
+ }
211
+ async function debugFrameworks(options = {}) {
212
+ const args = ["--format", "json"];
213
+ pushGlobalFlags(args, options);
214
+ args.push("debug", "frameworks");
215
+ const result = await run$1(args, { cwd: options.cwd });
216
+ requireSuccess(result);
217
+ return parseJson(result);
218
+ }
202
219
  //#endregion
203
- export { PruneguardExecutionError, binaryPath, daemonStatus, debugEntrypoints, debugResolve, explain, fixPlan, impact, loadConfig, migrateDepcruise, migrateKnip, resolutionInfo, review, run, safeDelete, scan, scanDot, schemaPath, suggestRules };
220
+ export { PruneguardExecutionError, binaryPath, compatibilityReport, daemonStatus, debugEntrypoints, debugFrameworks, debugResolve, explain, fixPlan, impact, loadConfig, migrateDepcruise, migrateKnip, resolutionInfo, review, run, safeDelete, scan, scanDot, schemaPath, suggestRules };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pruneguard",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "Repo truth engine for JS/TS monorepos",
5
5
  "keywords": [
6
6
  "javascript",
@@ -29,6 +29,8 @@
29
29
  "report_schema.json",
30
30
  "review_report_schema.json",
31
31
  "safe_delete_report_schema.json",
32
+ "suggest_rules_report_schema.json",
33
+ "daemon_status_report_schema.json",
32
34
  "dist",
33
35
  "README.md",
34
36
  "bin/pruneguard"
@@ -43,14 +45,14 @@
43
45
  }
44
46
  },
45
47
  "optionalDependencies": {
46
- "@pruneguard/cli-darwin-arm64": "0.3.1",
47
- "@pruneguard/cli-darwin-x64": "0.3.1",
48
- "@pruneguard/cli-linux-arm64-gnu": "0.3.1",
49
- "@pruneguard/cli-linux-arm64-musl": "0.3.1",
50
- "@pruneguard/cli-linux-x64-gnu": "0.3.1",
51
- "@pruneguard/cli-linux-x64-musl": "0.3.1",
52
- "@pruneguard/cli-win32-arm64-msvc": "0.3.1",
53
- "@pruneguard/cli-win32-x64-msvc": "0.3.1"
48
+ "@pruneguard/cli-darwin-arm64": "0.4.1",
49
+ "@pruneguard/cli-darwin-x64": "0.4.1",
50
+ "@pruneguard/cli-linux-arm64-gnu": "0.4.1",
51
+ "@pruneguard/cli-linux-arm64-musl": "0.4.1",
52
+ "@pruneguard/cli-linux-x64-gnu": "0.4.1",
53
+ "@pruneguard/cli-linux-x64-musl": "0.4.1",
54
+ "@pruneguard/cli-win32-arm64-msvc": "0.4.1",
55
+ "@pruneguard/cli-win32-x64-msvc": "0.4.1"
54
56
  },
55
57
  "engines": {
56
58
  "node": ">=18.0.0"
@@ -41,6 +41,17 @@
41
41
  }
42
42
  ]
43
43
  },
44
+ "parityScore": {
45
+ "description": "External parity corpus score, if available.",
46
+ "anyOf": [
47
+ {
48
+ "$ref": "#/definitions/ExternalParityReport"
49
+ },
50
+ {
51
+ "type": "null"
52
+ }
53
+ ]
54
+ },
44
55
  "profile": {
45
56
  "description": "The profile used for this analysis.",
46
57
  "type": "string"
@@ -191,6 +202,218 @@
191
202
  "daemon"
192
203
  ]
193
204
  },
205
+ "ExternalParityCaseResult": {
206
+ "description": "Result of a single parity case in the external report.",
207
+ "type": "object",
208
+ "required": [
209
+ "family",
210
+ "name",
211
+ "passed",
212
+ "passedChecks",
213
+ "referenceTool",
214
+ "totalChecks"
215
+ ],
216
+ "properties": {
217
+ "failures": {
218
+ "type": "array",
219
+ "items": {
220
+ "type": "string"
221
+ }
222
+ },
223
+ "family": {
224
+ "type": "string"
225
+ },
226
+ "name": {
227
+ "type": "string"
228
+ },
229
+ "passed": {
230
+ "type": "boolean"
231
+ },
232
+ "passedChecks": {
233
+ "type": "integer",
234
+ "format": "uint",
235
+ "minimum": 0.0
236
+ },
237
+ "referenceTool": {
238
+ "type": "string"
239
+ },
240
+ "totalChecks": {
241
+ "type": "integer",
242
+ "format": "uint",
243
+ "minimum": 0.0
244
+ }
245
+ }
246
+ },
247
+ "ExternalParityFamilyScore": {
248
+ "description": "Per-family score in the external parity report.",
249
+ "type": "object",
250
+ "required": [
251
+ "family",
252
+ "passedCases",
253
+ "pct",
254
+ "totalCases"
255
+ ],
256
+ "properties": {
257
+ "family": {
258
+ "type": "string"
259
+ },
260
+ "passedCases": {
261
+ "type": "integer",
262
+ "format": "uint",
263
+ "minimum": 0.0
264
+ },
265
+ "pct": {
266
+ "type": "number",
267
+ "format": "double"
268
+ },
269
+ "totalCases": {
270
+ "type": "integer",
271
+ "format": "uint",
272
+ "minimum": 0.0
273
+ }
274
+ }
275
+ },
276
+ "ExternalParityReport": {
277
+ "description": "External parity report from the fixture-derived corpus.",
278
+ "type": "object",
279
+ "required": [
280
+ "overallPct",
281
+ "passedCases",
282
+ "passedChecks",
283
+ "totalCases",
284
+ "totalChecks"
285
+ ],
286
+ "properties": {
287
+ "byFamily": {
288
+ "description": "Per-family parity breakdown.",
289
+ "type": "array",
290
+ "items": {
291
+ "$ref": "#/definitions/ExternalParityFamilyScore"
292
+ }
293
+ },
294
+ "byReferenceTool": {
295
+ "description": "Per-reference-tool parity breakdown.",
296
+ "type": "array",
297
+ "items": {
298
+ "$ref": "#/definitions/ExternalParityToolScore"
299
+ }
300
+ },
301
+ "caseResults": {
302
+ "description": "Individual case results.",
303
+ "type": "array",
304
+ "items": {
305
+ "$ref": "#/definitions/ExternalParityCaseResult"
306
+ }
307
+ },
308
+ "overallPct": {
309
+ "description": "Overall parity percentage (0-100).",
310
+ "type": "number",
311
+ "format": "double"
312
+ },
313
+ "passedCases": {
314
+ "description": "Number of fully passing cases.",
315
+ "type": "integer",
316
+ "format": "uint",
317
+ "minimum": 0.0
318
+ },
319
+ "passedChecks": {
320
+ "description": "Number of individual checks that passed.",
321
+ "type": "integer",
322
+ "format": "uint",
323
+ "minimum": 0.0
324
+ },
325
+ "staleDeltas": {
326
+ "description": "Stale matrix deltas (features where the hand-authored tracker disagrees with reality).",
327
+ "type": "array",
328
+ "items": {
329
+ "$ref": "#/definitions/ParityStaleDelta"
330
+ }
331
+ },
332
+ "totalCases": {
333
+ "description": "Total number of parity test cases.",
334
+ "type": "integer",
335
+ "format": "uint",
336
+ "minimum": 0.0
337
+ },
338
+ "totalChecks": {
339
+ "description": "Total number of individual checks across all cases.",
340
+ "type": "integer",
341
+ "format": "uint",
342
+ "minimum": 0.0
343
+ }
344
+ }
345
+ },
346
+ "ExternalParitySummary": {
347
+ "description": "Summary of external parity score for the stats section.",
348
+ "type": "object",
349
+ "required": [
350
+ "overallPct",
351
+ "passedCases",
352
+ "passedChecks",
353
+ "totalCases",
354
+ "totalChecks"
355
+ ],
356
+ "properties": {
357
+ "overallPct": {
358
+ "description": "Overall parity percentage (0-100).",
359
+ "type": "number",
360
+ "format": "double"
361
+ },
362
+ "passedCases": {
363
+ "description": "Cases that fully passed.",
364
+ "type": "integer",
365
+ "format": "uint",
366
+ "minimum": 0.0
367
+ },
368
+ "passedChecks": {
369
+ "description": "Individual checks that passed.",
370
+ "type": "integer",
371
+ "format": "uint",
372
+ "minimum": 0.0
373
+ },
374
+ "totalCases": {
375
+ "description": "Total cases evaluated.",
376
+ "type": "integer",
377
+ "format": "uint",
378
+ "minimum": 0.0
379
+ },
380
+ "totalChecks": {
381
+ "description": "Total individual checks.",
382
+ "type": "integer",
383
+ "format": "uint",
384
+ "minimum": 0.0
385
+ }
386
+ }
387
+ },
388
+ "ExternalParityToolScore": {
389
+ "description": "Per-tool score in the external parity report.",
390
+ "type": "object",
391
+ "required": [
392
+ "passedCases",
393
+ "pct",
394
+ "tool",
395
+ "totalCases"
396
+ ],
397
+ "properties": {
398
+ "passedCases": {
399
+ "type": "integer",
400
+ "format": "uint",
401
+ "minimum": 0.0
402
+ },
403
+ "pct": {
404
+ "type": "number",
405
+ "format": "double"
406
+ },
407
+ "tool": {
408
+ "type": "string"
409
+ },
410
+ "totalCases": {
411
+ "type": "integer",
412
+ "format": "uint",
413
+ "minimum": 0.0
414
+ }
415
+ }
416
+ },
194
417
  "FileInfo": {
195
418
  "description": "Info about a discovered file.",
196
419
  "type": "object",
@@ -378,16 +601,34 @@
378
601
  }
379
602
  },
380
603
  "FindingCategory": {
381
- "type": "string",
382
- "enum": [
383
- "unused-export",
384
- "unused-file",
385
- "unused-package",
386
- "unused-dependency",
387
- "cycle",
388
- "boundary-violation",
389
- "ownership-violation",
390
- "impact"
604
+ "oneOf": [
605
+ {
606
+ "type": "string",
607
+ "enum": [
608
+ "unused-export",
609
+ "unused-file",
610
+ "unused-package",
611
+ "unused-dependency",
612
+ "cycle",
613
+ "boundary-violation",
614
+ "ownership-violation",
615
+ "impact"
616
+ ]
617
+ },
618
+ {
619
+ "description": "An exported class member, enum variant, or namespace member is unused.",
620
+ "type": "string",
621
+ "enum": [
622
+ "unused-member"
623
+ ]
624
+ },
625
+ {
626
+ "description": "The same symbol is exported from multiple paths (barrel re-export collision).",
627
+ "type": "string",
628
+ "enum": [
629
+ "duplicate-export"
630
+ ]
631
+ }
391
632
  ]
392
633
  },
393
634
  "FindingConfidence": {
@@ -487,6 +728,29 @@
487
728
  }
488
729
  }
489
730
  },
731
+ "ParityStaleDelta": {
732
+ "description": "A stale delta where the hand-authored parity matrix disagrees with actual test results.",
733
+ "type": "object",
734
+ "required": [
735
+ "actualLevel",
736
+ "feature",
737
+ "matrixLevel"
738
+ ],
739
+ "properties": {
740
+ "actualLevel": {
741
+ "description": "Actual level observed from test results.",
742
+ "type": "string"
743
+ },
744
+ "feature": {
745
+ "description": "Feature or test case name.",
746
+ "type": "string"
747
+ },
748
+ "matrixLevel": {
749
+ "description": "Level claimed in the parity matrix.",
750
+ "type": "string"
751
+ }
752
+ }
753
+ },
490
754
  "RemediationActionKind": {
491
755
  "description": "The kind of remediation action to take.",
492
756
  "type": "string",
@@ -619,6 +883,25 @@
619
883
  }
620
884
  ]
621
885
  },
886
+ "externalParity": {
887
+ "description": "External parity score summary, if available.",
888
+ "anyOf": [
889
+ {
890
+ "$ref": "#/definitions/ExternalParitySummary"
891
+ },
892
+ {
893
+ "type": "null"
894
+ }
895
+ ]
896
+ },
897
+ "externalParityPct": {
898
+ "description": "External parity score percentage (0-100), if computed.",
899
+ "type": [
900
+ "number",
901
+ "null"
902
+ ],
903
+ "format": "double"
904
+ },
622
905
  "filesCached": {
623
906
  "type": "integer",
624
907
  "format": "uint",
@@ -776,6 +1059,13 @@
776
1059
  "format": "uint",
777
1060
  "minimum": 0.0
778
1061
  },
1062
+ "unsupportedFrameworks": {
1063
+ "description": "Names of unsupported frameworks detected in the workspace.",
1064
+ "type": "array",
1065
+ "items": {
1066
+ "type": "string"
1067
+ }
1068
+ },
779
1069
  "watcherLagMs": {
780
1070
  "description": "Lag of the file-system watcher in milliseconds.",
781
1071
  "type": [