@flagshark/core 2.0.0 → 2.1.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 (68) hide show
  1. package/README.md +2 -0
  2. package/dist/config/schema.d.ts +112 -0
  3. package/dist/config/schema.d.ts.map +1 -1
  4. package/dist/config/schema.js +63 -0
  5. package/dist/config/schema.js.map +1 -1
  6. package/dist/detection/detectors/typescript.d.ts.map +1 -1
  7. package/dist/detection/detectors/typescript.js +41 -0
  8. package/dist/detection/detectors/typescript.js.map +1 -1
  9. package/dist/detection/feature-flag.d.ts +28 -0
  10. package/dist/detection/feature-flag.d.ts.map +1 -1
  11. package/dist/detection/helpers.d.ts +16 -0
  12. package/dist/detection/helpers.d.ts.map +1 -1
  13. package/dist/detection/helpers.js +117 -6
  14. package/dist/detection/helpers.js.map +1 -1
  15. package/dist/detection/import-graph.d.ts +234 -0
  16. package/dist/detection/import-graph.d.ts.map +1 -0
  17. package/dist/detection/import-graph.js +641 -0
  18. package/dist/detection/import-graph.js.map +1 -0
  19. package/dist/detection/interface.d.ts +57 -0
  20. package/dist/detection/interface.d.ts.map +1 -1
  21. package/dist/detection/interface.js.map +1 -1
  22. package/dist/detection/polyglot-analyzer.d.ts +8 -0
  23. package/dist/detection/polyglot-analyzer.d.ts.map +1 -1
  24. package/dist/detection/polyglot-analyzer.js +2 -0
  25. package/dist/detection/polyglot-analyzer.js.map +1 -1
  26. package/dist/detection/tree-sitter/engine.d.ts.map +1 -1
  27. package/dist/detection/tree-sitter/engine.js +62 -15
  28. package/dist/detection/tree-sitter/engine.js.map +1 -1
  29. package/dist/detection/tree-sitter/parser-cache.d.ts +20 -0
  30. package/dist/detection/tree-sitter/parser-cache.d.ts.map +1 -1
  31. package/dist/detection/tree-sitter/parser-cache.js +32 -1
  32. package/dist/detection/tree-sitter/parser-cache.js.map +1 -1
  33. package/dist/output/json.d.ts.map +1 -1
  34. package/dist/output/json.js +28 -0
  35. package/dist/output/json.js.map +1 -1
  36. package/dist/output/markdown.d.ts.map +1 -1
  37. package/dist/output/markdown.js +47 -1
  38. package/dist/output/markdown.js.map +1 -1
  39. package/dist/output/text.d.ts.map +1 -1
  40. package/dist/output/text.js +89 -0
  41. package/dist/output/text.js.map +1 -1
  42. package/dist/providers/cross-reference.d.ts +36 -2
  43. package/dist/providers/cross-reference.d.ts.map +1 -1
  44. package/dist/providers/cross-reference.js +102 -7
  45. package/dist/providers/cross-reference.js.map +1 -1
  46. package/dist/providers/interface.d.ts +116 -2
  47. package/dist/providers/interface.d.ts.map +1 -1
  48. package/dist/providers/launchdarkly/client.d.ts +12 -0
  49. package/dist/providers/launchdarkly/client.d.ts.map +1 -1
  50. package/dist/providers/launchdarkly/client.js +243 -24
  51. package/dist/providers/launchdarkly/client.js.map +1 -1
  52. package/dist/providers/launchdarkly/types.d.ts +318 -0
  53. package/dist/providers/launchdarkly/types.d.ts.map +1 -1
  54. package/dist/providers/launchdarkly/types.js +82 -0
  55. package/dist/providers/launchdarkly/types.js.map +1 -1
  56. package/dist/providers/orchestrate.d.ts +34 -2
  57. package/dist/providers/orchestrate.d.ts.map +1 -1
  58. package/dist/providers/orchestrate.js +59 -7
  59. package/dist/providers/orchestrate.js.map +1 -1
  60. package/dist/scan-repo.d.ts +28 -0
  61. package/dist/scan-repo.d.ts.map +1 -1
  62. package/dist/scan-repo.js +290 -4
  63. package/dist/scan-repo.js.map +1 -1
  64. package/dist/staleness.d.ts +31 -1
  65. package/dist/staleness.d.ts.map +1 -1
  66. package/dist/staleness.js +66 -10
  67. package/dist/staleness.js.map +1 -1
  68. package/package.json +2 -1
@@ -89,6 +89,34 @@ export interface ScanRepoResult {
89
89
  excludedCount?: number;
90
90
  /** Relative paths of excluded files. Only populated when collectExcludedPaths is true. */
91
91
  excludedPaths?: string[];
92
+ /**
93
+ * Count of files where the detector raised at least one parse error
94
+ * (i.e. the file was scanned but the tree-sitter/regex pass bailed). Mirrors
95
+ * `RepositoryAnalysisResult.parseErrorCount` and is exposed here so output
96
+ * formatters (text, json, markdown) can tell the user up front when a
97
+ * non-trivial slice of their code couldn't be analysed. Optional for
98
+ * backward compatibility with test fixtures and external callers that
99
+ * construct ScanRepoResult by hand; treat absent as `0`.
100
+ */
101
+ parseErrorCount?: number;
102
+ /**
103
+ * Flag names that were detected in code AND found in a platform but
104
+ * marked as permanent (LD's `temporary: false`, or equivalent on other
105
+ * platforms). These are filtered out of `staleFlags` because they're
106
+ * intentionally long-lived; surfacing them here lets output formatters
107
+ * show users WHY a flag they expected to see in the table isn't there.
108
+ * Empty array (not undefined) when no platforms are configured or no
109
+ * matches were permanent. Per-platform breakdown lives in the
110
+ * `permanentByPlatform` field below.
111
+ */
112
+ excludedPermanent?: string[];
113
+ /**
114
+ * Per-platform breakdown of `excludedPermanent`. Keyed by the
115
+ * platform's displayName (e.g. 'LaunchDarkly'). Lets the output
116
+ * formatter print 'X flags excluded as permanent in LaunchDarkly'
117
+ * (not just 'in some platform somewhere').
118
+ */
119
+ permanentByPlatform?: Record<string, string[]>;
92
120
  /** Diagnostic — populated only when logger.debug level is active or callers explicitly opt in. */
93
121
  effectiveExcludes?: EffectiveRules;
94
122
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scan-repo.d.ts","sourceRoot":"","sources":["../src/scan-repo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAA;IAEnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,GAAG,aAAa,CAAA;IAEhC;;;OAGG;IACH,MAAM,CAAC,EAAE,eAAe,CAAA;IAExB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB;;OAEG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAE9B,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAA;IAElB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAA;IAEpB;;;;OAIG;IACH,UAAU,EAAE,SAAS,EAAE,CAAA;IAEvB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAE3B,0EAA0E;IAC1E,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEzC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;IAEnB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAA;IAEpB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IAExB,kGAAkG;IAClG,iBAAiB,CAAC,EAAE,cAAc,CAAA;CACnC;AAUD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAmF7E"}
1
+ {"version":3,"file":"scan-repo.d.ts","sourceRoot":"","sources":["../src/scan-repo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAA;IAEnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,GAAG,aAAa,CAAA;IAEhC;;;OAGG;IACH,MAAM,CAAC,EAAE,eAAe,CAAA;IAExB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB;;OAEG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAE9B,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAA;IAElB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAA;IAEpB;;;;OAIG;IACH,UAAU,EAAE,SAAS,EAAE,CAAA;IAEvB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAE3B,0EAA0E;IAC1E,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEzC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;IAEnB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAA;IAEpB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IAExB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;;;;;;;;OASG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAE5B;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IAE9C,kGAAkG;IAClG,iBAAiB,CAAC,EAAE,cAAc,CAAA;CACnC;AAUD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAkK7E"}
package/dist/scan-repo.js CHANGED
@@ -4,6 +4,8 @@
4
4
  */
5
5
  import { collectFiles } from './scanner.js';
6
6
  import { createDefaultRegistry, createRegistryWithEngine } from './detection/index.js';
7
+ import { buildImportGraph, isScannedSourceFile, loadTsconfigAliases } from './detection/import-graph.js';
8
+ import { Languages, getImportPattern } from './detection/interface.js';
7
9
  import { PolyglotAnalyzer } from './detection/polyglot-analyzer.js';
8
10
  import { analyzeStaleness } from './staleness.js';
9
11
  import { buildDefaultConfig } from './config/defaults.js';
@@ -47,15 +49,55 @@ export async function scanRepo(opts) {
47
49
  });
48
50
  logger.debug(`Detected ${files.size} candidate files (excluded ${excludedCount})`);
49
51
  const filesScanned = files.size;
50
- const analysisResult = await analyzer.analyzeFiles(files, opts.signal);
51
- const platformSignals = await orchestratePlatforms({
52
+ // Wrapper-aware detection: build the TS/JS import graph and "lift" the SDK
53
+ // gate for any file that transitively reaches a known SDK through 1-N hops
54
+ // of relative imports. We do this by appending a single-line comment to
55
+ // the file content that mentions every reachable SDK pattern; the per-
56
+ // provider import gate (a substring check in helpers.ts / engine.ts) then
57
+ // passes for wrapper-consumer files. Appending to the END of content keeps
58
+ // every flag's line number correct.
59
+ //
60
+ // Direct importers already pass the gate, so the appended marker is a
61
+ // no-op for them. Files with no SDK reach are untouched.
62
+ //
63
+ // Why scan-repo.ts and not PolyglotAnalyzer: PolyglotAnalyzer is a generic
64
+ // multi-language coordinator. The graph is TS/JS-only and SDK-aware; that
65
+ // knowledge lives at the orchestrator layer where we also know the registry.
66
+ const tsJsSdkPatterns = collectSdkPatterns(registry);
67
+ const filesForAnalysis = augmentForWrapperDetection(files, tsJsSdkPatterns, logger, opts.cwd);
68
+ const analysisResult = await analyzer.analyzeFiles(filesForAnalysis, opts.signal);
69
+ // B3: user-configured custom detectors (struct-field-access only today).
70
+ // Layered on top of the standard detection so it never reduces recall,
71
+ // only adds matches — typically for codebases whose flag system bypasses
72
+ // the SDK model entirely (e.g. Mattermost's typed Config().FeatureFlags.X).
73
+ // Detected flags are tagged confidence: 'low' so cleanup pipelines route
74
+ // them to manual review rather than auto-merge.
75
+ if (config.custom_detectors && config.custom_detectors.length > 0) {
76
+ applyCustomDetectors(files, config.custom_detectors, analysisResult.totalFlags, logger);
77
+ }
78
+ const { signals: platformSignals, permanentByPlatform, metadataByFlag, } = await orchestratePlatforms({
52
79
  platformsConfig: config.platforms,
53
80
  detectedFlags: analysisResult.totalFlags,
54
81
  logger,
55
82
  noCache: opts.noCache,
56
83
  signal: opts.signal,
84
+ // Threshold drives the platform-too-old signal in cross-reference.
85
+ // Same threshold the staleness engine uses for code-age, so the two
86
+ // dimensions stay aligned ("if code older than N is stale, so is a
87
+ // platform record older than N").
88
+ thresholdDays: threshold,
89
+ });
90
+ const staleFlags = await analyzeStaleness(analysisResult.totalFlags, {
91
+ thresholdDays: threshold,
92
+ repoRoot: opts.cwd,
93
+ platformSignals,
94
+ platformMetadata: metadataByFlag,
57
95
  });
58
- const staleFlags = await analyzeStaleness(analysisResult.totalFlags, { thresholdDays: threshold, repoRoot: opts.cwd, platformSignals });
96
+ // Flatten the per-platform breakdown into a single sorted, deduplicated
97
+ // list so callers that only want "did anything get excluded?" don't
98
+ // have to walk the platform record themselves. The per-platform record
99
+ // is retained for output formatters that want to attribute correctly.
100
+ const excludedPermanent = Array.from(new Set(Object.values(permanentByPlatform).flat())).sort();
59
101
  const totalFlags = analysisResult.totalFlags.size;
60
102
  const uniqueStaleNames = new Set(staleFlags.map((f) => f.name)).size;
61
103
  const healthScore = totalFlags === 0 ? 100 : Math.round(((totalFlags - uniqueStaleNames) / totalFlags) * 100);
@@ -68,6 +110,30 @@ export async function scanRepo(opts) {
68
110
  .map((f) => f.provider)
69
111
  .filter((p) => p != null && p !== '')),
70
112
  ];
113
+ const scanDuration = Math.round(performance.now() - start);
114
+ // Structured metric line — one per scan, info-level. Same shape as the
115
+ // SaaS-side piranha_metric events so a single dashboard can join them.
116
+ // CloudWatch Logs Insights query: `filter event="flagshark_scan_complete"`.
117
+ // Off by default at debug-only loggers (e.g. the no-op logger used in
118
+ // tests); info-level loggers (CLI, Action) surface them.
119
+ logger.info('flagshark_scan_complete', {
120
+ event: 'flagshark_scan_complete',
121
+ durationMs: scanDuration,
122
+ filesScanned,
123
+ // Defensive ?? 0 fallbacks: collectFiles always returns excludedCount as
124
+ // a number and PolyglotAnalyzer always populates parseErrorCount, so the
125
+ // RHS of these expressions is unreachable today — kept for type safety
126
+ // against future refactors.
127
+ /* v8 ignore next 2 */
128
+ excludedCount: excludedCount ?? 0,
129
+ parseErrorCount: analysisResult.parseErrorCount ?? 0,
130
+ totalFlags,
131
+ staleFlags: uniqueStaleNames,
132
+ healthScore,
133
+ detectedProviders: detectedProviders.length,
134
+ languages: Object.keys(analysisResult.languages).length,
135
+ detectionEngine: opts.engine ?? 'regex',
136
+ });
71
137
  return {
72
138
  totalFlags,
73
139
  filesScanned,
@@ -76,10 +142,230 @@ export async function scanRepo(opts) {
76
142
  // analysisResult.languages is Map<Language, number> — convert to plain object
77
143
  languageBreakdown: Object.fromEntries(analysisResult.languages),
78
144
  healthScore,
79
- scanDuration: Math.round(performance.now() - start),
145
+ scanDuration,
80
146
  excludedCount,
81
147
  excludedPaths,
148
+ parseErrorCount: analysisResult.parseErrorCount,
149
+ excludedPermanent,
150
+ permanentByPlatform,
82
151
  effectiveExcludes: excluder.effectiveRules,
83
152
  };
84
153
  }
154
+ // -- Wrapper-aware detection helpers ------------------------------------------
155
+ /**
156
+ * Pulls every `importPattern` string registered on the language detectors
157
+ * the import graph supports today (TS/JS + Python). These are the seed
158
+ * packages for the graph — a file is "in SDK scope" iff its imports reach
159
+ * one of these via 1-N hops of relative imports.
160
+ *
161
+ * We pull TS/JS and Python together because the seed list is matched
162
+ * substring-style on each spec and both languages share the same matching
163
+ * surface inside the graph. Python-only seeds (`posthog`, `ldclient`) and
164
+ * TS-only seeds (`@launchdarkly/node-server-sdk`) never collide because
165
+ * their syntactic shapes are different.
166
+ */
167
+ function collectSdkPatterns(registry) {
168
+ const patterns = new Set();
169
+ for (const lang of [Languages.TypeScript, Languages.JavaScript, Languages.Python]) {
170
+ const detector = registry.getDetector(lang);
171
+ // Defensive skip: the default registry always populates TS/JS/Python
172
+ // detectors. Custom engines could theoretically omit one, hence the guard.
173
+ /* v8 ignore next */
174
+ if (!detector)
175
+ continue;
176
+ for (const provider of detector.getProviders()) {
177
+ const pat = getImportPattern(provider);
178
+ if (pat)
179
+ patterns.add(pat);
180
+ }
181
+ }
182
+ return [...patterns];
183
+ }
184
+ /**
185
+ * Marker comment appended to TS/JS files that transitively reach an SDK. The
186
+ * existing per-provider import gate is a `content.includes(importPat)` check;
187
+ * mentioning the SDK pattern in this comment satisfies the gate without
188
+ * touching the detector interface or shifting any line numbers (the marker
189
+ * goes at end-of-file, after the last line of real code).
190
+ *
191
+ * The marker text is recognisable so an operator inspecting an instrumented
192
+ * file or a debug log can tell the difference between a real import and our
193
+ * post-hoc marker.
194
+ */
195
+ const WRAPPER_MARKER_PREFIX = '// flagshark-internal: transitively reaches';
196
+ /**
197
+ * Same marker semantics but in Python comment syntax (`#`). When wrapper
198
+ * augmentation extended to .py files (B4), appending a `//` line would
199
+ * make the file unparseable — Python doesn't have `//` comments. The
200
+ * detector's import-gate is a substring `content.includes(importPat)`
201
+ * check that doesn't care WHICH comment syntax wraps the SDK pattern,
202
+ * so language-appropriate markers work transparently.
203
+ */
204
+ const WRAPPER_MARKER_PREFIX_PYTHON = '# flagshark-internal: transitively reaches';
205
+ /**
206
+ * Returns a new Map<filePath, content> where TS/JS files with transitive SDK
207
+ * reach have a single comment line appended that mentions each reachable SDK
208
+ * pattern. Returns the original Map unchanged if no SDK seeds exist (e.g.
209
+ * registry was constructed without TS/JS detectors).
210
+ *
211
+ * Non-TS/JS files are passed through untouched.
212
+ */
213
+ function augmentForWrapperDetection(files, tsJsSdkPatterns, logger, cwd) {
214
+ // Defensive early-return: every default registry contributes at least
215
+ // one SDK pattern, so this branch only fires for hand-built empty
216
+ // registries — not reachable from public scan paths.
217
+ /* v8 ignore next */
218
+ if (tsJsSdkPatterns.length === 0)
219
+ return files;
220
+ // Load tsconfig path aliases from the scan root, then pass them to the
221
+ // graph builder. Most TS monorepos use `@/foo`-style aliases; without
222
+ // this, the transitive wrapper detection stops at every aliased
223
+ // boundary and under-counts. Falls back gracefully — `loadTsconfigAliases`
224
+ // returns null when there's no tsconfig or no aliases declared, in which
225
+ // case the graph behaves exactly as before.
226
+ const aliases = loadTsconfigAliases(cwd);
227
+ if (aliases) {
228
+ logger.debug('tsconfig path aliases loaded', {
229
+ baseUrl: aliases.baseUrl,
230
+ aliasCount: aliases.paths.size,
231
+ });
232
+ }
233
+ const graph = buildImportGraph(files, {
234
+ seedSdkPatterns: tsJsSdkPatterns,
235
+ // Polyglot scope — graph now walks TS/JS *and* Python wrappers so a
236
+ // Python consumer file that does `from .feature_flags import is_enabled`
237
+ // (where feature_flags.py imports `posthog`) is in scope. The option
238
+ // name is legacy from when TS/JS was the only surface; the helper
239
+ // returns true for .py files too. See B4 in the bug inventory.
240
+ isTsJs: isScannedSourceFile,
241
+ aliases: aliases ?? undefined,
242
+ });
243
+ logger.debug('Import graph built', graph.stats);
244
+ // No transitive reach (seeds didn't propagate beyond themselves, or no seeds
245
+ // at all) -> return the original map. Avoids a wasted clone on repos that
246
+ // don't use any flag SDK.
247
+ if (graph.stats.inScopeFiles === 0) {
248
+ return files;
249
+ }
250
+ const augmented = new Map();
251
+ let augmentedCount = 0;
252
+ for (const [filePath, content] of files) {
253
+ const sdks = graph.transitiveSdks.get(filePath);
254
+ if (!sdks || sdks.size === 0) {
255
+ augmented.set(filePath, content);
256
+ continue;
257
+ }
258
+ // Append at end-of-file with a leading newline so we never glue onto a
259
+ // partial last line. Sorting the SDK list keeps the marker deterministic
260
+ // across runs (useful when diffing logs). Use Python comment syntax for
261
+ // .py files; the substring-based import gate doesn't care which prefix
262
+ // wraps the SDK pattern, so language-appropriate markers stay parseable.
263
+ const sdkList = [...sdks].sort().join(' ');
264
+ const prefix = filePath.toLowerCase().endsWith('.py')
265
+ ? WRAPPER_MARKER_PREFIX_PYTHON
266
+ : WRAPPER_MARKER_PREFIX;
267
+ augmented.set(filePath, `${content}\n${prefix} ${sdkList}\n`);
268
+ augmentedCount++;
269
+ }
270
+ logger.debug(`Wrapper-aware detection augmented ${augmentedCount} files`);
271
+ return augmented;
272
+ }
273
+ // -- Custom detector application (B3) -----------------------------------------
274
+ /**
275
+ * File extensions per language, for routing custom detectors to the right
276
+ * files. Kept in sync with the language detector registry; we duplicate
277
+ * the table here rather than pulling from the registry because the
278
+ * registry is awareness-of-detector, not awareness-of-extensions, and
279
+ * the registry's API is method-call-shaped (asks "do you support this
280
+ * file" per detector) rather than data-shaped.
281
+ */
282
+ const LANGUAGE_EXTENSIONS = {
283
+ go: ['.go'],
284
+ python: ['.py', '.pyx', '.pyi'],
285
+ typescript: ['.ts', '.tsx'],
286
+ javascript: ['.js', '.jsx', '.mjs', '.cjs'],
287
+ java: ['.java'],
288
+ kotlin: ['.kt', '.kts'],
289
+ swift: ['.swift'],
290
+ ruby: ['.rb'],
291
+ csharp: ['.cs'],
292
+ php: ['.php'],
293
+ rust: ['.rs'],
294
+ cpp: ['.c', '.cc', '.cpp', '.h', '.hpp'],
295
+ objc: ['.m', '.mm'],
296
+ };
297
+ /**
298
+ * Runs each configured custom detector over the appropriate file subset
299
+ * and adds matches to `totalFlags`. Mutates the map in place — same shape
300
+ * as the polyglot analyzer's output, so downstream staleness + JSON
301
+ * surfacing pick the new flags up without further wiring.
302
+ *
303
+ * Each match becomes a FeatureFlag with `confidence: 'low'` to signal
304
+ * that the detection came from a user-declared regex rather than a
305
+ * disciplined SDK gate. The legacy `'high'`/`'medium'` flags from the
306
+ * standard detector are left untouched.
307
+ */
308
+ function applyCustomDetectors(files, detectors, totalFlags, logger) {
309
+ for (const detector of detectors) {
310
+ let regex;
311
+ try {
312
+ regex = new RegExp(detector.access_pattern, 'g');
313
+ }
314
+ catch (err) {
315
+ logger.warn(`custom_detector regex failed to compile`, {
316
+ access_pattern: detector.access_pattern,
317
+ /* v8 ignore next */
318
+ error: err instanceof Error ? err.message : String(err),
319
+ });
320
+ continue;
321
+ }
322
+ const allowedExts = LANGUAGE_EXTENSIONS[detector.language] ?? [];
323
+ if (allowedExts.length === 0) {
324
+ logger.warn(`custom_detector skipped — unknown language`, {
325
+ language: detector.language,
326
+ });
327
+ continue;
328
+ }
329
+ const providerName = detector.name ?? 'Custom struct-field detector';
330
+ let matchCount = 0;
331
+ for (const [filePath, content] of files) {
332
+ const lower = filePath.toLowerCase();
333
+ if (!allowedExts.some((ext) => lower.endsWith(ext)))
334
+ continue;
335
+ // Walk every match in the file. Each must capture exactly one
336
+ // group (the flag name) — schemas validated at load time, but we
337
+ // defensively skip captureless matches at runtime too.
338
+ regex.lastIndex = 0;
339
+ let m;
340
+ while ((m = regex.exec(content)) !== null) {
341
+ const flagName = m[1];
342
+ /* v8 ignore next */
343
+ if (!flagName)
344
+ continue;
345
+ // Resolve line number from the match offset. Cheap: count
346
+ // newlines up to the match. Files are typically <10k lines so
347
+ // O(n) per match is fine.
348
+ const lineNumber = content.slice(0, m.index).split('\n').length;
349
+ const existing = totalFlags.get(flagName) ?? [];
350
+ existing.push({
351
+ name: flagName,
352
+ filePath,
353
+ lineNumber,
354
+ language: detector.language,
355
+ provider: providerName,
356
+ confidence: 'low',
357
+ });
358
+ totalFlags.set(flagName, existing);
359
+ matchCount++;
360
+ }
361
+ }
362
+ if (matchCount > 0) {
363
+ logger.debug(`custom_detector matched`, {
364
+ language: detector.language,
365
+ matchCount,
366
+ provider: providerName,
367
+ });
368
+ }
369
+ }
370
+ }
85
371
  //# sourceMappingURL=scan-repo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scan-repo.js","sourceRoot":"","sources":["../src/scan-repo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAoHjE,MAAM,IAAI,GAAiC,GAAG,EAAE,GAAE,CAAC,CAAA;AACnD,MAAM,WAAW,GAAe;IAC9B,KAAK,EAAE,IAAI;IACX,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;CACZ,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAqB;IAClD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,WAAW,CAAA;IAEzC,MAAM,MAAM,GACV,IAAI,CAAC,MAAM;QACX,CAAC,IAAI,CAAC,QAAQ;YACZ,CAAC,CAAC,kBAAkB,EAAE;YACtB,CAAC,CAAC,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,IAAI,kBAAkB,EAAE,CAAC,CAAA;IAEvE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,CAAA;IAEpD,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAE5E,MAAM,QAAQ,GAAG,aAAa,CAAC;QAC7B,MAAM;QACN,kBAAkB,EAAE,UAAU,EAAE,QAAQ,IAAI,EAAE;KAC/C,CAAC,CAAA;IAEF,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAA;IAE3D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM;QAC1B,CAAC,CAAC,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC;QACvC,CAAC,CAAC,qBAAqB,EAAE,CAAA;IAC3B,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,sBAAsB,EAAE,CAAC,CAAA;IACtE,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAEvD,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAA;IACnC,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,GAAG,YAAY,CAAC;QAC3D,IAAI,EAAE,IAAI,CAAC,GAAG;QACd,mBAAmB;QACnB,OAAO,EAAE,IAAI,CAAC,IAAI;QAClB,QAAQ;QACR,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;KAChD,CAAC,CAAA;IAEF,MAAM,CAAC,KAAK,CAAC,YAAY,KAAK,CAAC,IAAI,8BAA8B,aAAa,GAAG,CAAC,CAAA;IAClF,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAA;IAC/B,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;IAEtE,MAAM,eAAe,GAAG,MAAM,oBAAoB,CAAC;QACjD,eAAe,EAAE,MAAM,CAAC,SAAgD;QACxE,aAAa,EAAE,cAAc,CAAC,UAAU;QACxC,MAAM;QACN,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAA;IAEF,MAAM,UAAU,GAAG,MAAM,gBAAgB,CACvC,cAAc,CAAC,UAAU,EACzB,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,eAAe,EAAE,CAClE,CAAA;IAED,MAAM,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,IAAI,CAAA;IACjD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IACpE,MAAM,WAAW,GACf,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,GAAG,gBAAgB,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAA;IAE3F,MAAM,QAAQ,GAAkB,EAAE,CAAA;IAClC,KAAK,MAAM,KAAK,IAAI,cAAc,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;QACvD,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAA;IACzB,CAAC;IACD,MAAM,iBAAiB,GAAG;QACxB,GAAG,IAAI,GAAG,CACR,QAAQ;aACL,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;aACtB,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CACrD;KACF,CAAA;IAED,OAAO;QACL,UAAU;QACV,YAAY;QACZ,UAAU;QACV,iBAAiB;QACjB,8EAA8E;QAC9E,iBAAiB,EAAE,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC;QAC/D,WAAW;QACX,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACnD,aAAa;QACb,aAAa;QACb,iBAAiB,EAAE,QAAQ,CAAC,cAAc;KAC3C,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"scan-repo.js","sourceRoot":"","sources":["../src/scan-repo.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { type FeatureFlag } from './detection/feature-flag.js';
2
2
  export interface StalenessSignal {
3
- type: 'age' | 'hardcoded' | 'low-usage' | 'missing-in-platform' | 'archived-in-platform';
3
+ type: 'age' | 'hardcoded' | 'low-usage' | 'missing-in-platform' | 'archived-in-platform' | 'platform-too-old' | 'platform-inactive' | 'platform-launched' | 'platform-zero-evaluations' | 'platform-low-evaluations';
4
4
  severity: 'error' | 'warning';
5
5
  description: string;
6
6
  }
@@ -13,6 +13,25 @@ export interface StaleFlag {
13
13
  signals: StalenessSignal[];
14
14
  /** Human-readable age, e.g. "14 months ago" */
15
15
  age?: string;
16
+ /**
17
+ * Detection-quality tier inherited from the underlying FeatureFlag.
18
+ * See FlagConfidence in detection/feature-flag.ts for what the values
19
+ * mean. Absent = `'high'`. Surfaced here so consumers of the stale-flag
20
+ * list (the JSON output, the GitHub Action's PR comment) can route
21
+ * medium-confidence flags to manual review rather than auto-cleanup.
22
+ */
23
+ confidence?: 'high' | 'medium' | 'low';
24
+ /**
25
+ * Platform-side metadata propagated through from the cross-reference
26
+ * layer. Populated only when a platform integration is active AND the
27
+ * platform exposed the data. Output formatters surface these
28
+ * alongside each flag so reviewers see who owns it and how the
29
+ * platform classifies it without a context switch.
30
+ */
31
+ tags?: string[];
32
+ maintainer?: string;
33
+ /** LD's per-environment activity verdict; see PlatformFlag.status. */
34
+ platformStatus?: 'new' | 'active' | 'inactive' | 'launched';
16
35
  }
17
36
  export interface StalenessOptions {
18
37
  /** Flag lines older than this are considered stale. Default: 30. */
@@ -21,6 +40,17 @@ export interface StalenessOptions {
21
40
  repoRoot: string;
22
41
  /** Optional: pre-computed platform signals keyed by flag name. */
23
42
  platformSignals?: Map<string, import('./providers/interface.js').PlatformSignal[]>;
43
+ /**
44
+ * Optional: per-flag platform metadata surfaced by the orchestrator.
45
+ * Drives the tags / maintainer / platformStatus fields on each
46
+ * emitted StaleFlag. Keyed by detected flag name; values come
47
+ * straight from the matched PlatformFlag.
48
+ */
49
+ platformMetadata?: Map<string, {
50
+ tags?: string[];
51
+ maintainer?: string;
52
+ status?: 'new' | 'active' | 'inactive' | 'launched';
53
+ }>;
24
54
  }
25
55
  /**
26
56
  * Analyze a set of detected feature flags for staleness signals.
@@ -1 +1 @@
1
- {"version":3,"file":"staleness.d.ts","sourceRoot":"","sources":["../src/staleness.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAI9D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,qBAAqB,GAAG,sBAAsB,CAAA;IACxF,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAA;IACrB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,0BAA0B,EAAE,cAAc,EAAE,CAAC,CAAA;CACnF;AAmKD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,SAAS,EAAE,CAAC,CAmFtB"}
1
+ {"version":3,"file":"staleness.d.ts","sourceRoot":"","sources":["../src/staleness.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAI9D,MAAM,WAAW,eAAe;IAK9B,IAAI,EACA,KAAK,GACL,WAAW,GACX,WAAW,GACX,qBAAqB,GACrB,sBAAsB,GACtB,kBAAkB,GAClB,mBAAmB,GACnB,mBAAmB,GACnB,2BAA2B,GAC3B,0BAA0B,CAAA;IAC9B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAA;IAEtC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sEAAsE;IACtE,cAAc,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAA;CAC5D;AAED,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAA;IACrB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,0BAA0B,EAAE,cAAc,EAAE,CAAC,CAAA;IAClF;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,GAAG,CACpB,MAAM,EACN;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAA;KAAE,CAC9F,CAAA;CACF;AAmKD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyItB"}
package/dist/staleness.js CHANGED
@@ -168,11 +168,18 @@ export async function analyzeStaleness(flags, options) {
168
168
  for (const [flagName, occurrences] of flags) {
169
169
  // Low-usage is per-flag-name (not per-occurrence).
170
170
  const lowUsageSignal = checkLowUsageSignal(flagName, occurrences);
171
+ // Pre-check: is this flag marked permanent by ANY platform? The
172
+ // `platform-permanent` cross-reference signal is a CONTROL marker,
173
+ // not a stale signal — it tells us to suppress age + low-usage
174
+ // (those are false positives on kill-switches / operational config).
175
+ // The marker itself never reaches the user-facing signals array.
176
+ const platformSigs = options.platformSignals?.get(flagName);
177
+ const isPermanent = platformSigs?.some((ps) => ps.type === 'platform-permanent') ?? false;
171
178
  for (const flag of occurrences) {
172
179
  const signals = [];
173
180
  let age;
174
- // Age signal (git blame)
175
- if (!shallow) {
181
+ // Age signal (git blame) — skipped for permanent flags.
182
+ if (!shallow && !isPermanent) {
176
183
  const blame = fileBlames.get(flag.filePath);
177
184
  const authorTime = blame?.get(flag.lineNumber);
178
185
  const ageResult = checkAgeSignal(authorTime, thresholdDays);
@@ -184,17 +191,37 @@ export async function analyzeStaleness(flags, options) {
184
191
  age = formatAge(authorTime);
185
192
  }
186
193
  }
187
- // Low-usage signal
188
- if (lowUsageSignal) {
194
+ else if (!shallow && isPermanent) {
195
+ // Still compute the human-readable age for display, even though
196
+ // we suppress the staleness signal. Operators looking at the
197
+ // output for a permanent flag still benefit from knowing how old
198
+ // it is; we just don't yell about it.
199
+ const blame = fileBlames.get(flag.filePath);
200
+ const authorTime = blame?.get(flag.lineNumber);
201
+ if (authorTime !== undefined) {
202
+ age = formatAge(authorTime);
203
+ }
204
+ }
205
+ // Low-usage signal — skipped for permanent flags.
206
+ if (lowUsageSignal && !isPermanent) {
189
207
  signals.push(lowUsageSignal);
190
208
  }
191
209
  // Hardcoded signal (v2 placeholder — always null for regex v1)
192
210
  // checkHardcodedSignal returns null unconditionally; kept for structural symmetry
193
211
  // with the other signal detectors. No branch emitted here.
194
- // Platform signals (from provider API cross-reference)
195
- const platformSigs = options.platformSignals?.get(flagName);
212
+ // Platform signals (from provider API cross-reference).
213
+ // `platform-permanent` is dropped at this seam — it was a control
214
+ // signal, not a user-facing one. `missing-in-platform` and
215
+ // `archived-in-platform` still fire even for permanent flags
216
+ // because those represent platform-state-vs-code mismatches the
217
+ // user genuinely needs to know about.
196
218
  if (platformSigs) {
197
219
  for (const ps of platformSigs) {
220
+ if (ps.type === 'platform-permanent')
221
+ continue;
222
+ // After the platform-permanent filter, the remaining types are
223
+ // missing-in-platform / archived-in-platform — both narrow to
224
+ // error/warning severities. Help the type checker see that.
198
225
  signals.push({
199
226
  type: ps.type,
200
227
  severity: ps.severity,
@@ -202,9 +229,18 @@ export async function analyzeStaleness(flags, options) {
202
229
  });
203
230
  }
204
231
  }
205
- // Only include flags that have at least one signal.
206
- if (signals.length > 0) {
207
- staleFlags.push({
232
+ // A flag is stale only if it has at least one PRIMARY signal
233
+ // anything other than `low-usage`. The single-file/low-usage
234
+ // signal is contributing context, not a stale verdict on its own:
235
+ // plenty of legitimate flags ARE single-file (small isolated
236
+ // features, kill switches, A/B toggles for one screen) and
237
+ // surfacing them as stale floods the output with false positives.
238
+ // When a flag IS stale for another reason, low-usage stays in
239
+ // the signals list because "this is single-file → small cleanup
240
+ // scope" is useful diagnostic for the reviewer.
241
+ const hasPrimarySignal = signals.some((s) => s.type !== 'low-usage');
242
+ if (hasPrimarySignal) {
243
+ const stale = {
208
244
  name: flag.name,
209
245
  filePath: flag.filePath,
210
246
  lineNumber: flag.lineNumber,
@@ -212,7 +248,27 @@ export async function analyzeStaleness(flags, options) {
212
248
  provider: flag.provider ?? 'unknown',
213
249
  signals,
214
250
  age,
215
- });
251
+ };
252
+ // Propagate the detection confidence only when it's non-default,
253
+ // matching the FeatureFlag emission contract (absent = 'high').
254
+ if (flag.confidence && flag.confidence !== 'high') {
255
+ stale.confidence = flag.confidence;
256
+ }
257
+ // Attach platform-side metadata when available. Each field is
258
+ // optional so the StaleFlag shape stays stable for code-only
259
+ // scans (no platforms configured) and JSON consumers that
260
+ // never expected these fields aren't broken by their presence
261
+ // since they're absent unless explicitly populated.
262
+ const meta = options.platformMetadata?.get(flagName);
263
+ if (meta) {
264
+ if (meta.tags && meta.tags.length > 0)
265
+ stale.tags = meta.tags;
266
+ if (meta.maintainer)
267
+ stale.maintainer = meta.maintainer;
268
+ if (meta.status)
269
+ stale.platformStatus = meta.status;
270
+ }
271
+ staleFlags.push(stale);
216
272
  }
217
273
  }
218
274
  }
@@ -1 +1 @@
1
- {"version":3,"file":"staleness.js","sourceRoot":"","sources":["../src/staleness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"staleness.js","sourceRoot":"","sources":["../src/staleness.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flagshark/core",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "type": "module",
5
5
  "description": "Detection engine for FlagShark — finds feature flag references across 13 languages.",
6
6
  "license": "MIT",
@@ -25,6 +25,7 @@
25
25
  "generate:queries": "node scripts/generate-inline-queries.mjs",
26
26
  "test": "vitest run",
27
27
  "test:coverage": "vitest run --coverage",
28
+ "test:live": "vitest run --config vitest.live.config.ts",
28
29
  "typecheck": "tsc --noEmit"
29
30
  },
30
31
  "dependencies": {