@herbertgao/pi-extensions 2026.9.1 → 2026.9.2
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/node_modules/@narumitw/pi-btw/README.md +57 -141
- package/node_modules/@narumitw/pi-btw/dist/index.ts +466 -41
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
- package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
- package/node_modules/@narumitw/pi-btw/package.json +2 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +15 -1
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
- package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
- package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
- package/node_modules/pi-lens/CHANGELOG.md +84 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -1
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -6
- package/node_modules/pi-lens/dist/clients/bootstrap.js +4 -4
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +1 -1
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +0 -5
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +1 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +1 -6
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +2 -2
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
- package/node_modules/pi-lens/dist/clients/config-core/index.js +11 -8
- package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/provenance.js +2 -9
- package/node_modules/pi-lens/dist/clients/config-core/records.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/schema.js +3 -5
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-resolve.js +4 -4
- package/node_modules/pi-lens/dist/clients/config-schema.js +39 -2
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +1 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +0 -26
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +1 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +6 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +4 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +1 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +1 -0
- package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +2 -2
- package/node_modules/pi-lens/dist/clients/file-kinds.js +1 -38
- package/node_modules/pi-lens/dist/clients/file-time.js +1 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-service.js +0 -1
- package/node_modules/pi-lens/dist/clients/formatters.js +110 -3
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +3 -4
- package/node_modules/pi-lens/dist/clients/git-guard.js +5 -0
- package/node_modules/pi-lens/dist/clients/grammar-source.js +3 -3
- package/node_modules/pi-lens/dist/clients/installer/index.js +220 -9
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +6 -6
- package/node_modules/pi-lens/dist/clients/language-profile.js +0 -9
- package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
- package/node_modules/pi-lens/dist/clients/latency-logger.js +5 -7
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +19 -0
- package/node_modules/pi-lens/dist/clients/lens-engine.js +3 -4
- package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +18 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -36
- package/node_modules/pi-lens/dist/clients/lsp/client.js +4 -3
- package/node_modules/pi-lens/dist/clients/lsp/config.js +1 -0
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +3 -3
- package/node_modules/pi-lens/dist/clients/lsp/index.js +216 -25
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -8
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -2
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -1
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +5 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -1
- package/node_modules/pi-lens/dist/clients/metrics-history.js +28 -107
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +1 -1
- package/node_modules/pi-lens/dist/clients/module-report.js +1 -1
- package/node_modules/pi-lens/dist/clients/mutating-tool.js +3 -3
- package/node_modules/pi-lens/dist/clients/mutation-attribution.js +3 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +9 -9
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +2 -6
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/path-utils.js +23 -2
- package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/pipeline.js +2 -2
- package/node_modules/pi-lens/dist/clients/project-changes.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +46 -1
- package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
- package/node_modules/pi-lens/dist/clients/python-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +5 -2
- package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +3 -5
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +1 -1
- package/node_modules/pi-lens/dist/clients/runtime-session.js +45 -10
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +11 -1
- package/node_modules/pi-lens/dist/clients/sanitize.js +0 -11
- package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
- package/node_modules/pi-lens/dist/clients/session-summary.js +0 -24
- package/node_modules/pi-lens/dist/clients/sgconfig.js +1 -5
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
- package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +77 -72
- package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +1 -52
- package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -4
- package/node_modules/pi-lens/dist/clients/user-notify.js +0 -4
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/word-index-store.js +3 -7
- package/node_modules/pi-lens/dist/clients/word-index.js +9 -16
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +1 -1
- package/node_modules/pi-lens/dist/index.js +1062 -538
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -1
- package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +1 -1
- package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +1 -1
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +37 -6
- package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
- package/node_modules/pi-lens/dist/tools/render-compact.js +1 -1
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -2
- package/node_modules/pi-lens/docs/globalconfig.md +20 -0
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +6 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +12 -1
- package/node_modules/pi-lens/docs/release-qa-baseline.md +12 -4
- package/node_modules/pi-lens/docs/servercapabilities.md +7 -3
- package/node_modules/pi-lens/docs/word-index.md +1 -1
- package/node_modules/pi-lens/package.json +6 -15
- package/node_modules/pi-lens/rules/typos/_typos.toml +4 -2
- package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +1 -1
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
- package/package.json +3 -3
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* builtin -> global -> project root -> nested-project -> env -> cli -> host
|
|
14
14
|
*
|
|
15
|
-
* It is `config-core`'s own `
|
|
15
|
+
* It is `config-core`'s own `SOURCE_TIERS`, not a second ordering: this
|
|
16
16
|
* module places files into tiers and the core sorts them. `docs/configuration.md`
|
|
17
17
|
* documents the same order once, and `tests/clients/config-resolve.test.ts`
|
|
18
18
|
* walks it.
|
|
@@ -151,7 +151,7 @@ function collectDocuments(dir, locations, tier, onReadError) {
|
|
|
151
151
|
* is `nested-project`, which is what makes "nearest wins, per field" fall out
|
|
152
152
|
* of the core's tier precedence instead of being re-implemented here.
|
|
153
153
|
*/
|
|
154
|
-
|
|
154
|
+
function collectPiLensConfigDocuments(options) {
|
|
155
155
|
const documents = [];
|
|
156
156
|
const { globalDir, onReadError } = options;
|
|
157
157
|
const globalConfigPath = canonicalGlobalFile(options);
|
|
@@ -408,7 +408,7 @@ function assignRaw(target, key, value) {
|
|
|
408
408
|
* half-migrated the file it was written in is the defect this whole change
|
|
409
409
|
* exists to remove.
|
|
410
410
|
*/
|
|
411
|
-
|
|
411
|
+
function configSources(documents) {
|
|
412
412
|
const sources = [];
|
|
413
413
|
for (const document of documents) {
|
|
414
414
|
const value = document.value;
|
|
@@ -576,7 +576,7 @@ function record(input) {
|
|
|
576
576
|
* duplicate notice about a config that failed to load is noise, while silence
|
|
577
577
|
* about it is the failure mode this module exists to prevent.
|
|
578
578
|
*/
|
|
579
|
-
|
|
579
|
+
function configRecordOwner(record) {
|
|
580
580
|
const key = record.canonicalKey ?? record.key;
|
|
581
581
|
if (key.length === 0)
|
|
582
582
|
return undefined;
|
|
@@ -43,7 +43,7 @@ import { LEGACY_ROOT_LSP_KEYS, LSP_NAMESPACE_KEY } from "./config-locations.js";
|
|
|
43
43
|
import { DENY_KEY, } from "./config-core/schema.js";
|
|
44
44
|
import { flagConfigSectionKeys, GLOBAL_NON_FLAG_CONFIG_SECTIONS, LENS_FLAGS, PROJECT_FOREIGN_CONFIG_NAMESPACES, PROJECT_NON_FLAG_CONFIG_SECTIONS, } from "./lens-flag-registry.js";
|
|
45
45
|
/** The JSON Schema dialect the published artifact declares. */
|
|
46
|
-
|
|
46
|
+
const CONFIG_SCHEMA_DIALECT = "https://json-schema.org/draft/2020-12/schema";
|
|
47
47
|
/**
|
|
48
48
|
* A node the schema says nothing else about. `config-core` treats a node with
|
|
49
49
|
* no `type` as opaque and walks its children OPEN, so an undeclared section
|
|
@@ -109,7 +109,6 @@ export { LSP_KEY_TYPES };
|
|
|
109
109
|
const LSP_KEY_DENY = {
|
|
110
110
|
disabledServers: "array-union",
|
|
111
111
|
};
|
|
112
|
-
export { LSP_KEY_DENY };
|
|
113
112
|
/** The `x-deny` annotation for a key, or nothing when it carries no denial. */
|
|
114
113
|
function denyAnnotation(key) {
|
|
115
114
|
const policy = LSP_KEY_DENY[key];
|
|
@@ -161,6 +160,44 @@ function buildConfigSchema() {
|
|
|
161
160
|
for (const key of PROJECT_FOREIGN_CONFIG_NAMESPACES) {
|
|
162
161
|
properties[key] ??= opaque("experimental");
|
|
163
162
|
}
|
|
163
|
+
for (const key of [
|
|
164
|
+
"knip",
|
|
165
|
+
"jscpd",
|
|
166
|
+
"madge",
|
|
167
|
+
"gitleaks",
|
|
168
|
+
"govulncheck",
|
|
169
|
+
"deadCode",
|
|
170
|
+
"complexity",
|
|
171
|
+
]) {
|
|
172
|
+
properties[key] = {
|
|
173
|
+
type: "object",
|
|
174
|
+
additionalProperties: true,
|
|
175
|
+
properties: {
|
|
176
|
+
enabled: { type: "boolean", [STABILITY_TIER_KEY]: "experimental" },
|
|
177
|
+
},
|
|
178
|
+
[STABILITY_TIER_KEY]: "stable",
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
properties.startup = {
|
|
182
|
+
type: "object",
|
|
183
|
+
additionalProperties: true,
|
|
184
|
+
properties: {
|
|
185
|
+
mode: {
|
|
186
|
+
type: "string",
|
|
187
|
+
enum: ["quick", "full", "minimal"],
|
|
188
|
+
[STABILITY_TIER_KEY]: "experimental",
|
|
189
|
+
},
|
|
190
|
+
scans: {
|
|
191
|
+
type: "object",
|
|
192
|
+
additionalProperties: true,
|
|
193
|
+
properties: {
|
|
194
|
+
enabled: { type: "boolean", [STABILITY_TIER_KEY]: "experimental" },
|
|
195
|
+
},
|
|
196
|
+
[STABILITY_TIER_KEY]: "experimental",
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
[STABILITY_TIER_KEY]: "stable",
|
|
200
|
+
};
|
|
164
201
|
// The four legacy ROOT LSP keys. Still accepted for their deprecation window
|
|
165
202
|
// (#2418 registry), and `experimental` because they are scheduled for
|
|
166
203
|
// removal — a `stable` tier on a key with a `removeNotBefore` would be two
|
|
@@ -28,7 +28,3 @@ export function logDeadCodeScan(event) {
|
|
|
28
28
|
return;
|
|
29
29
|
writer.log({ ts: new Date().toISOString(), ...event });
|
|
30
30
|
}
|
|
31
|
-
/** Resolve once all enqueued dead-code writes are on disk (tests/shutdown). */
|
|
32
|
-
export function flushDeadCodeLog() {
|
|
33
|
-
return writer.flush();
|
|
34
|
-
}
|
|
@@ -128,7 +128,7 @@ export function computeStrictAnchor(args) {
|
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
130
|
/** Intent-level anchor — see module doc. Used for defer/flagged/suppress. */
|
|
131
|
-
|
|
131
|
+
function computeWeakAnchor(args) {
|
|
132
132
|
return stableFindingId("ddw:", {
|
|
133
133
|
cwd: args.cwd,
|
|
134
134
|
filePath: args.filePath,
|
|
@@ -23,7 +23,7 @@ export function getDiagnosticLogger() {
|
|
|
23
23
|
}
|
|
24
24
|
return _logger;
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
function createDiagnosticLogger() {
|
|
27
27
|
// Lazy filePath: the log file is keyed on the current date, resolved per
|
|
28
28
|
// drain so a long-lived logger rolls over at midnight. A daily rollover
|
|
29
29
|
// is NOT a size bound (#2505): one very busy day, or a long-lived
|
|
@@ -33,7 +33,3 @@ export function observeRunnerLatency(options) {
|
|
|
33
33
|
export function resetObservedRunnerLatency() {
|
|
34
34
|
slowRunners.clear();
|
|
35
35
|
}
|
|
36
|
-
/** Test-only inspection without exposing mutable state. */
|
|
37
|
-
export function observedRunnerTierForTests(projectRoot, runnerId) {
|
|
38
|
-
return classifyObservedRunner(projectRoot, runnerId);
|
|
39
|
-
}
|
|
@@ -1237,29 +1237,3 @@ async function runRunner(ctx, runner, defaultSemantic) {
|
|
|
1237
1237
|
}
|
|
1238
1238
|
}
|
|
1239
1239
|
// --- Simple Integration Helper ---
|
|
1240
|
-
/**
|
|
1241
|
-
* @internal
|
|
1242
|
-
* Low-level dispatch entry point. Use `dispatchLint` from `./integration.js` instead —
|
|
1243
|
-
* that version provides session-persistent baselines and FactStore.
|
|
1244
|
-
* This function creates an ephemeral FactStore per call; facts do not persist across calls.
|
|
1245
|
-
*/
|
|
1246
|
-
export async function dispatchLint(filePath, cwd, pi, facts, registry) {
|
|
1247
|
-
// By default, only run BLOCKING rules for fast feedback on file write
|
|
1248
|
-
const ctx = createDispatchContext(filePath, cwd, pi, facts, true);
|
|
1249
|
-
// Get runners for this file kind
|
|
1250
|
-
if (!ctx.kind)
|
|
1251
|
-
return "";
|
|
1252
|
-
const runners = registry.getForKind(ctx.kind, ctx.filePath);
|
|
1253
|
-
if (runners.length === 0) {
|
|
1254
|
-
return "";
|
|
1255
|
-
}
|
|
1256
|
-
// Create groups from registered runners (all in fallback mode)
|
|
1257
|
-
const groups = [
|
|
1258
|
-
{
|
|
1259
|
-
mode: "fallback",
|
|
1260
|
-
runnerIds: runners.map((r) => r.id),
|
|
1261
|
-
},
|
|
1262
|
-
];
|
|
1263
|
-
const result = await dispatchForFile(ctx, groups, registry);
|
|
1264
|
-
return result.output;
|
|
1265
|
-
}
|
|
@@ -1489,7 +1489,9 @@ export async function computeCascadeForFile(filePath, cwd, options = {}) {
|
|
|
1489
1489
|
try {
|
|
1490
1490
|
const snapshots = (await lspService.getCapabilitySnapshots?.(neighborPath)) ?? [];
|
|
1491
1491
|
const tier = classifyCascadeWaitTier(lspService, neighborPath, snapshots);
|
|
1492
|
-
if (tier === "tier3-silent" ||
|
|
1492
|
+
if (tier === "tier3-silent" ||
|
|
1493
|
+
tier === "collect-later" ||
|
|
1494
|
+
tier === "diagnostics-unsupported") {
|
|
1493
1495
|
const spawnedForTouch = await lspService.getClientForFile(neighborPath);
|
|
1494
1496
|
if (spawnedForTouch) {
|
|
1495
1497
|
// Sampled BEFORE the touchFile notify: a publish landing
|
|
@@ -1505,6 +1507,21 @@ export async function computeCascadeForFile(filePath, cwd, options = {}) {
|
|
|
1505
1507
|
source: "cascade",
|
|
1506
1508
|
clientScope: "primary",
|
|
1507
1509
|
});
|
|
1510
|
+
if (tier === "diagnostics-unsupported") {
|
|
1511
|
+
logCascade({
|
|
1512
|
+
phase: "cascade_skip",
|
|
1513
|
+
filePath,
|
|
1514
|
+
neighborFile: neighborPath,
|
|
1515
|
+
durationMs: Date.now() - neighborStart,
|
|
1516
|
+
lspServerCount: configuredServerCount,
|
|
1517
|
+
coldSnapshot: isColdSnapshot,
|
|
1518
|
+
metadata: {
|
|
1519
|
+
serverId: spawnedForTouch.client.serverId,
|
|
1520
|
+
waitTier: tier,
|
|
1521
|
+
},
|
|
1522
|
+
});
|
|
1523
|
+
return undefined;
|
|
1524
|
+
}
|
|
1508
1525
|
recordOutstandingCascadeTouch({
|
|
1509
1526
|
filePath: neighborPath,
|
|
1510
1527
|
serverId: spawnedForTouch.client.serverId,
|
|
@@ -9,9 +9,3 @@ export function warmDispatchIntegration() {
|
|
|
9
9
|
export function loadDispatchIntegration() {
|
|
10
10
|
return warmDispatchIntegration();
|
|
11
11
|
}
|
|
12
|
-
/** Test-only reset; production sessions intentionally retain the promise
|
|
13
|
-
* across successful loads (a rejection already evicts itself — see
|
|
14
|
-
* `createLazyImport`). */
|
|
15
|
-
export function resetDispatchIntegrationForTests() {
|
|
16
|
-
lazyIntegration.resetForTests();
|
|
17
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Turn-end handoff for runners moved off the post-write critical path. */
|
|
2
2
|
import { incrementDegradationCount } from "../degradation-ledger.js";
|
|
3
3
|
const pending = [];
|
|
4
|
-
|
|
4
|
+
const MAX_PENDING_RUNNER_FINDINGS = 50;
|
|
5
5
|
export function deferRunnerFindings(entry) {
|
|
6
6
|
const tracked = { ...entry, settled: false };
|
|
7
7
|
// Attach exactly once at ownership time. Re-attaching at every turn end
|
|
@@ -3,8 +3,8 @@ import { isTestSuiteOrganizer } from "./framework-call-noise.js";
|
|
|
3
3
|
// projects without a config. Project-specific overrides are read from the
|
|
4
4
|
// per-dispatch context; these mutable fallbacks exist for tests/legacy direct
|
|
5
5
|
// rule evaluation only.
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const DEFAULT_HIGH_COMPLEXITY_THRESHOLD = 15;
|
|
7
|
+
const DEFAULT_HIGH_COMPLEXITY_DEPTH_THRESHOLD = 6;
|
|
8
8
|
let ccThreshold = DEFAULT_HIGH_COMPLEXITY_THRESHOLD;
|
|
9
9
|
let depthThreshold = DEFAULT_HIGH_COMPLEXITY_DEPTH_THRESHOLD;
|
|
10
10
|
function isPositiveFiniteThreshold(value) {
|
|
@@ -3,7 +3,7 @@ import { isTestFrameworkNoiseCall, isTestSuiteOrganizer, } from "./framework-cal
|
|
|
3
3
|
// projects without a config. Project-specific overrides are read from the
|
|
4
4
|
// per-dispatch context; this mutable fallback exists for tests/legacy direct
|
|
5
5
|
// rule evaluation only.
|
|
6
|
-
|
|
6
|
+
const DEFAULT_HIGH_FAN_OUT_THRESHOLD = 20;
|
|
7
7
|
let fanOutThreshold = DEFAULT_HIGH_FAN_OUT_THRESHOLD;
|
|
8
8
|
/** Override fallback threshold for tests/legacy direct rule evaluation. */
|
|
9
9
|
export function setHighFanOutThreshold(n) {
|
|
@@ -184,7 +184,9 @@ export async function loadSg() {
|
|
|
184
184
|
}
|
|
185
185
|
})();
|
|
186
186
|
sgLoadPromise = task;
|
|
187
|
-
task
|
|
187
|
+
// `task` never rejects (the IIFE catches), so the derived promise is inert;
|
|
188
|
+
// `void` records that no consumer awaits it (oxlint no-floating-promises).
|
|
189
|
+
void task.finally(() => {
|
|
188
190
|
if (sgLoadPromise === task)
|
|
189
191
|
sgLoadPromise = undefined;
|
|
190
192
|
});
|
|
@@ -97,6 +97,10 @@ async function resolveCompiler(absPath, cwd) {
|
|
|
97
97
|
flavor: "msvc",
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
|
+
// Mirrors the deliberate global-PATH probes in utils/runner-helpers.ts:
|
|
101
|
+
// this never resolves a config file or a target path, so there is no cwd
|
|
102
|
+
// for it to get wrong.
|
|
103
|
+
// cwd-exempt: presence probe only -- `cl` with no args and no target file, used solely to detect whether MSVC is on PATH
|
|
100
104
|
const clProbe = await safeSpawnAsync("cl", [], { timeout: 5000 });
|
|
101
105
|
if (!clProbe.error && clProbe.status !== null) {
|
|
102
106
|
return {
|
|
@@ -489,7 +489,7 @@ const OUR_RENDER_FLAGS = ["--output-dir"];
|
|
|
489
489
|
*
|
|
490
490
|
* Returns the matched flag (for the message) or null.
|
|
491
491
|
*/
|
|
492
|
-
|
|
492
|
+
function rejectedOurInvocation(output) {
|
|
493
493
|
if (!output)
|
|
494
494
|
return null;
|
|
495
495
|
const complaint = /unknown flag|unknown shorthand flag|flag provided but not defined|unknown command|unrecognized (?:flag|option)/i.test(output);
|
|
@@ -26,8 +26,10 @@ const PS_TIMEOUT_MS = 30000;
|
|
|
26
26
|
* `spawnFailure.kind` and the errno on `error` — which is what lets the
|
|
27
27
|
* availability policy tell a stall from an absence.
|
|
28
28
|
*/
|
|
29
|
-
function spawnPs(cmd, args,
|
|
29
|
+
function spawnPs(cmd, args, options = {}) {
|
|
30
|
+
const { timeoutMs = PS_TIMEOUT_MS, cwd } = options;
|
|
30
31
|
return safeSpawnAsync(cmd, args, {
|
|
32
|
+
cwd,
|
|
31
33
|
timeout: timeoutMs,
|
|
32
34
|
resourceLabel: "psscriptanalyzer",
|
|
33
35
|
});
|
|
@@ -124,6 +126,7 @@ async function resolvePowerShellCmd() {
|
|
|
124
126
|
for (const candidate of ["pwsh", "powershell"]) {
|
|
125
127
|
const sampler = startHostStallSampler();
|
|
126
128
|
const startedAt = Date.now();
|
|
129
|
+
// cwd-exempt: global interpreter-presence probe ("is pwsh/powershell on PATH at all"), not tied to any project
|
|
127
130
|
const result = await spawnPs(candidate, [
|
|
128
131
|
"-NoProfile",
|
|
129
132
|
"-NonInteractive",
|
|
@@ -175,6 +178,7 @@ async function checkModuleAvailable(cmd) {
|
|
|
175
178
|
return memo;
|
|
176
179
|
const sampler = startHostStallSampler();
|
|
177
180
|
const startedAt = Date.now();
|
|
181
|
+
// cwd-exempt: global module-presence probe -- PSScriptAnalyzer resolves from PowerShell's module search path, not a per-project install
|
|
178
182
|
const result = await spawnPs(cmd, [
|
|
179
183
|
"-NoProfile",
|
|
180
184
|
"-NonInteractive",
|
|
@@ -303,7 +307,7 @@ const psScriptAnalyzerRunner = {
|
|
|
303
307
|
tmpScript,
|
|
304
308
|
"-FilePath",
|
|
305
309
|
absPath,
|
|
306
|
-
]);
|
|
310
|
+
], { timeoutMs: PS_TIMEOUT_MS, cwd });
|
|
307
311
|
const hostStallMs = sampler.stop();
|
|
308
312
|
const elapsedMs = Date.now() - startedAt;
|
|
309
313
|
// The two probes above use `-Command`, which PowerShell's execution
|
|
@@ -63,7 +63,7 @@ const ruffRunner = {
|
|
|
63
63
|
// builder, so the package-owned fallback config can never drift.
|
|
64
64
|
const configArgs = ruffConfigArgs(cwd);
|
|
65
65
|
// Step 1: Capture diagnostics (before fixing) — teaching signal for the agent
|
|
66
|
-
const checkResult = await safeSpawnAsync(cmd, ["check", "--output-format", "json", ...configArgs, ctx.filePath], { timeout: 30000 });
|
|
66
|
+
const checkResult = await safeSpawnAsync(cmd, ["check", "--output-format", "json", ...configArgs, ctx.filePath], { cwd, timeout: 30000 });
|
|
67
67
|
const raw = stripAnsi(checkResult.stdout + checkResult.stderr);
|
|
68
68
|
const diagnostics = parseRuffJson(checkResult.stdout || "", ctx.filePath);
|
|
69
69
|
const parsedDiagnostics = diagnostics.length > 0 ? diagnostics : parseRuffOutput(raw, ctx.filePath);
|
|
@@ -149,7 +149,7 @@ const shellcheckRunner = {
|
|
|
149
149
|
args.push("--severity", "info");
|
|
150
150
|
}
|
|
151
151
|
args.push(ctx.filePath);
|
|
152
|
-
const result = await safeSpawnAsync(cmd, args, { timeout: 15000 });
|
|
152
|
+
const result = await safeSpawnAsync(cmd, args, { cwd, timeout: 15000 });
|
|
153
153
|
// shellcheck exits with code 1 if issues found, 0 if clean
|
|
154
154
|
if (result.status === 0 && !result.stdout?.trim()) {
|
|
155
155
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
@@ -82,15 +82,17 @@ const spellcheckRunner = {
|
|
|
82
82
|
priority: PRIORITY.DOC_QUALITY,
|
|
83
83
|
skipTestFiles: false, // Check docs in test files too
|
|
84
84
|
async run(ctx) {
|
|
85
|
+
const cwd = ctx.cwd || process.cwd();
|
|
85
86
|
// Skip if typos-cli is not installed
|
|
86
|
-
if (!(await typos.isAvailableAsync(
|
|
87
|
+
if (!(await typos.isAvailableAsync(cwd))) {
|
|
87
88
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
88
89
|
}
|
|
89
90
|
// Run typos-cli with JSON output
|
|
90
91
|
// --format json: Output JSON Lines
|
|
91
92
|
// --exclude <pattern>: Could be used to exclude code blocks if needed
|
|
92
93
|
const args = ["--format", "json", ctx.filePath];
|
|
93
|
-
const result = await safeSpawnAsync(typos.getCommand(
|
|
94
|
+
const result = await safeSpawnAsync(typos.getCommand(cwd), args, {
|
|
95
|
+
cwd,
|
|
94
96
|
timeout: 15000,
|
|
95
97
|
});
|
|
96
98
|
// #1816: typos-cli exits 0 clean, 2 with typos found, and 1 on an ERROR
|
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
* Supports the common `file:line:col: message` format used by most linters.
|
|
6
6
|
*/
|
|
7
7
|
import { stripAnsi } from "../../../sanitize.js";
|
|
8
|
-
import { escapeRegExp } from "../../../string-utils.js";
|
|
9
8
|
import { getAutofixCapability } from "../../../tool-policy.js";
|
|
10
9
|
/**
|
|
11
10
|
* Create a parser for line-based tool output.
|
|
12
11
|
* Common format: file:line:col: message (with variations)
|
|
13
12
|
*/
|
|
14
|
-
|
|
13
|
+
function createLineParser(config) {
|
|
15
14
|
return (raw, filePath) => {
|
|
16
15
|
const diagnostics = [];
|
|
17
16
|
// Optionally strip ANSI codes (for tools that output colored text)
|
|
@@ -81,68 +80,6 @@ export const parseGoVetOutput = createLineParser({
|
|
|
81
80
|
generateId: (m) => `go-vet-${m[2]}`,
|
|
82
81
|
defectClass: "correctness",
|
|
83
82
|
});
|
|
84
|
-
/**
|
|
85
|
-
* Parse Biome output: file:line:col message (category)
|
|
86
|
-
* With autofix support for fix suggestions
|
|
87
|
-
*/
|
|
88
|
-
export function createBiomeParser(_autofix = false) {
|
|
89
|
-
const biomeAutofix = getAutofixCapability("biome");
|
|
90
|
-
return createLineParser({
|
|
91
|
-
tool: "biome",
|
|
92
|
-
regex: /^(.+?):(\d+):(\d+)\s+(.+?)\s*\((.+?)\)/,
|
|
93
|
-
extractMessage: (m) => `${m[5]}: ${m[4]}`, // category: message
|
|
94
|
-
extractRule: (m) => m[5],
|
|
95
|
-
generateId: (m) => `biome-${m[2]}-${m[5]}`,
|
|
96
|
-
getSeverity: (line) => (line.includes("error") ? "error" : "warning"),
|
|
97
|
-
fixable: true,
|
|
98
|
-
autoFixAvailable: biomeAutofix?.safePipelineAutofix ?? false,
|
|
99
|
-
fixKind: biomeAutofix?.fixKind === "none" ? undefined : biomeAutofix?.fixKind,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
// Backward-compatible default biome parser
|
|
103
|
-
export const parseBiomeOutput = createBiomeParser(false);
|
|
104
83
|
// =============================================================================
|
|
105
84
|
// GENERIC PARSER FACTORY
|
|
106
85
|
// =============================================================================
|
|
107
|
-
/**
|
|
108
|
-
* Create a simple parser for tools using standard file:line:col format.
|
|
109
|
-
* Format variations: :line:col:, line:col, (line,col), etc.
|
|
110
|
-
*/
|
|
111
|
-
export function createSimpleParser(tool, options = {}) {
|
|
112
|
-
const sep = options.separator ?? ":";
|
|
113
|
-
const severity = options.severity ?? "warning";
|
|
114
|
-
const fixable = options.fixable ?? false;
|
|
115
|
-
// Build regex based on separator type
|
|
116
|
-
const escapedSep = sep === " " ? "\\s+" : escapeRegExp(sep);
|
|
117
|
-
const regex = options.includesFileName
|
|
118
|
-
? new RegExp(`^(.+?)${escapedSep}(\\d+)${escapedSep}(\\d+)${escapedSep}(.+)`)
|
|
119
|
-
: new RegExp(`^(\\d+)${escapedSep}(\\d+)${escapedSep}(.+)`);
|
|
120
|
-
return (raw, filePath) => {
|
|
121
|
-
const diagnostics = [];
|
|
122
|
-
const lines = raw.split("\n").filter((l) => l.trim());
|
|
123
|
-
for (const line of lines) {
|
|
124
|
-
const match = line.match(regex);
|
|
125
|
-
if (!match)
|
|
126
|
-
continue;
|
|
127
|
-
const lineNum = options.includesFileName
|
|
128
|
-
? parseInt(match[2], 10)
|
|
129
|
-
: parseInt(match[1], 10);
|
|
130
|
-
const colNum = options.includesFileName
|
|
131
|
-
? parseInt(match[3], 10)
|
|
132
|
-
: parseInt(match[2], 10);
|
|
133
|
-
const message = options.includesFileName ? match[4] : match[3];
|
|
134
|
-
diagnostics.push({
|
|
135
|
-
id: `${tool}-${lineNum}`,
|
|
136
|
-
message: message.trim(),
|
|
137
|
-
filePath,
|
|
138
|
-
line: lineNum,
|
|
139
|
-
column: colNum,
|
|
140
|
-
severity,
|
|
141
|
-
semantic: severity === "error" ? "blocking" : "warning",
|
|
142
|
-
tool,
|
|
143
|
-
fixable,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
return diagnostics;
|
|
147
|
-
};
|
|
148
|
-
}
|
|
@@ -13,24 +13,3 @@ export function readFileContent(filePath) {
|
|
|
13
13
|
return undefined;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Parse common tool output line into a diagnostic
|
|
18
|
-
* Format: file:line:col message (category)
|
|
19
|
-
*/
|
|
20
|
-
export function parseToolLine(line, toolName, filePath) {
|
|
21
|
-
const match = line.match(/^(.+?):(\d+):(\d+)\s+(.+?)\s*\((.+?)\)/);
|
|
22
|
-
if (!match)
|
|
23
|
-
return null;
|
|
24
|
-
return {
|
|
25
|
-
id: `${toolName}-${match[2]}-${match[5]}`,
|
|
26
|
-
message: `${match[5]}: ${match[4]}`,
|
|
27
|
-
filePath,
|
|
28
|
-
line: parseInt(match[2], 10),
|
|
29
|
-
column: parseInt(match[3], 10),
|
|
30
|
-
severity: line.includes("error") ? "error" : "warning",
|
|
31
|
-
semantic: "warning",
|
|
32
|
-
tool: toolName,
|
|
33
|
-
rule: match[5],
|
|
34
|
-
fixable: false,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
@@ -19,14 +19,7 @@ import { BoundedLruCache } from "../../bounded-cache.js";
|
|
|
19
19
|
import { compareOrdinal } from "../../string-utils.js";
|
|
20
20
|
// --- Constants ---
|
|
21
21
|
/** Overly broad patterns that match everything (cause false positive explosions) */
|
|
22
|
-
|
|
23
|
-
"$NAME",
|
|
24
|
-
"$FIELD",
|
|
25
|
-
"$_",
|
|
26
|
-
"$X",
|
|
27
|
-
"$VAR",
|
|
28
|
-
"$EXPR",
|
|
29
|
-
];
|
|
22
|
+
const OVERLY_BROAD_PATTERNS = ["$NAME", "$FIELD", "$_", "$X", "$VAR", "$EXPR"];
|
|
30
23
|
/** Maximum complexity score for rules in blockingOnly mode */
|
|
31
24
|
export const MAX_BLOCKING_RULE_COMPLEXITY = 8;
|
|
32
25
|
/**
|
|
@@ -126,7 +119,7 @@ export function loadYamlRulesFresh(ruleDir, severityFilter) {
|
|
|
126
119
|
cache.set(ruleDir, { rules, signature });
|
|
127
120
|
return rules;
|
|
128
121
|
}
|
|
129
|
-
|
|
122
|
+
function getCachedRules(ruleDir, severityFilter) {
|
|
130
123
|
if (!fs.existsSync(ruleDir)) {
|
|
131
124
|
return [];
|
|
132
125
|
}
|
|
@@ -179,17 +172,6 @@ export function isOverlyBroadPattern(pattern) {
|
|
|
179
172
|
return true;
|
|
180
173
|
return /^\$[A-Z_]+$/i.test(pattern.trim());
|
|
181
174
|
}
|
|
182
|
-
export function isValidCondition(condition) {
|
|
183
|
-
if (!condition)
|
|
184
|
-
return false;
|
|
185
|
-
if (condition.all !== undefined && condition.all.length === 0)
|
|
186
|
-
return false;
|
|
187
|
-
if (condition.any !== undefined && condition.any.length === 0)
|
|
188
|
-
return false;
|
|
189
|
-
if (isOverlyBroadPattern(condition.pattern))
|
|
190
|
-
return false;
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
175
|
export function isStructuredRule(rule) {
|
|
194
176
|
if (!rule.rule)
|
|
195
177
|
return false;
|
|
@@ -54,6 +54,7 @@ const yamllintRunner = {
|
|
|
54
54
|
if (!cmd)
|
|
55
55
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
56
56
|
const result = await safeSpawnAsync(cmd, ["-f", "parsable", ctx.filePath], {
|
|
57
|
+
cwd,
|
|
57
58
|
timeout: 15000,
|
|
58
59
|
});
|
|
59
60
|
// #1816: this runner read `result.status` zero times, so a yamllint
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared formatting utilities for the dispatch system.
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
const EMOJI = {
|
|
5
5
|
blocking: "🔴",
|
|
6
6
|
warning: "🟡",
|
|
7
7
|
fixed: "✅",
|
|
@@ -12,7 +12,7 @@ export const EMOJI = {
|
|
|
12
12
|
/**
|
|
13
13
|
* Format a single diagnostic for display
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
function formatDiagnostic(d) {
|
|
16
16
|
const line = d.line ? `L${d.line}: ` : "";
|
|
17
17
|
const indented = d.message.split("\n").join("\n ");
|
|
18
18
|
const fix = d.fixSuggestion ? `\n 💡 Fix: ${d.fixSuggestion}` : "";
|
|
@@ -30,10 +30,3 @@ export function logDispositionEvent(entry) {
|
|
|
30
30
|
}
|
|
31
31
|
writer.log({ ts: new Date().toISOString(), ...entry });
|
|
32
32
|
}
|
|
33
|
-
export function getDispositionLogPath() {
|
|
34
|
-
return DISPOSITION_LOG_FILE;
|
|
35
|
-
}
|
|
36
|
-
/** Resolve once all enqueued disposition writes are on disk. */
|
|
37
|
-
export function flushDispositionLog() {
|
|
38
|
-
return writer.flush();
|
|
39
|
-
}
|
|
@@ -88,14 +88,14 @@ export function startEventLoopMonitor(resolutionMs = 20) {
|
|
|
88
88
|
* every block that tier cares about while keeping sub-second jitter — where
|
|
89
89
|
* measurement slop rivals the signal — out of the verdict.
|
|
90
90
|
*/
|
|
91
|
-
|
|
91
|
+
const STALL_CLASSIFY_FLOOR_MS = 1000;
|
|
92
92
|
/**
|
|
93
93
|
* Slack allowed to the CPU budget before a block counts as unaccounted.
|
|
94
94
|
* `process.cpuUsage()` and the histogram are sampled at slightly different
|
|
95
95
|
* instants and the histogram quantizes, so a block whose CPU coverage is
|
|
96
96
|
* within this much of exact is called `cpu-accounted`, not a stall.
|
|
97
97
|
*/
|
|
98
|
-
|
|
98
|
+
const STALL_CLASSIFY_SLOP_MS = 250;
|
|
99
99
|
/**
|
|
100
100
|
* Split a block into compute-vs-stall from the CPU it could possibly have
|
|
101
101
|
* burned (#1980). Pure, so the discrimination is testable without the native
|
|
@@ -92,7 +92,7 @@ export const KIND_EXTENSIONS = {
|
|
|
92
92
|
zig: [".zig", ".zon"],
|
|
93
93
|
};
|
|
94
94
|
/** Return whether a path has an extension registered for the given file kind. */
|
|
95
|
-
|
|
95
|
+
function hasKindExtension(filePath, kind) {
|
|
96
96
|
const extension = extname(filePath).toLowerCase();
|
|
97
97
|
return KIND_EXTENSIONS[kind].some((candidate) => candidate === extension);
|
|
98
98
|
}
|
|
@@ -284,18 +284,6 @@ export const NON_CODE_KINDS = new Set([
|
|
|
284
284
|
"toml",
|
|
285
285
|
"yaml",
|
|
286
286
|
]);
|
|
287
|
-
/**
|
|
288
|
-
* Check if a file kind represents a code file (not config/markdown).
|
|
289
|
-
*/
|
|
290
|
-
export function isCodeKind(kind) {
|
|
291
|
-
return CODE_KINDS.has(kind);
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Check if a file kind represents a text/config/doc/markup file.
|
|
295
|
-
*/
|
|
296
|
-
export function isConfigKind(kind) {
|
|
297
|
-
return NON_CODE_KINDS.has(kind);
|
|
298
|
-
}
|
|
299
287
|
/**
|
|
300
288
|
* Check if a file path resolves to a {@link CODE_KINDS} kind. Undetectable
|
|
301
289
|
* files (unknown extension, e.g. `.coffee` from SOURCE_PRECEDENCE) are
|
|
@@ -351,31 +339,6 @@ export function getFileKindLabel(kind) {
|
|
|
351
339
|
};
|
|
352
340
|
return labels[kind] ?? kind;
|
|
353
341
|
}
|
|
354
|
-
/**
|
|
355
|
-
* Get file extensions for a file kind.
|
|
356
|
-
*/
|
|
357
|
-
export function getExtensionsForKind(kind) {
|
|
358
|
-
return [...(KIND_EXTENSIONS[kind] ?? [])];
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Check if a file should be scanned for linting/formatting.
|
|
362
|
-
* Excludes test files, generated files, etc.
|
|
363
|
-
*/
|
|
364
|
-
export function isScannableFile(filePath) {
|
|
365
|
-
const kind = detectFileKind(filePath);
|
|
366
|
-
if (!kind)
|
|
367
|
-
return false;
|
|
368
|
-
// Exclude test files for most kinds
|
|
369
|
-
const base = basename(filePath);
|
|
370
|
-
if (base.includes(".test.") ||
|
|
371
|
-
base.includes(".spec.") ||
|
|
372
|
-
base.startsWith("test-") ||
|
|
373
|
-
base.startsWith("spec-")) {
|
|
374
|
-
return false;
|
|
375
|
-
}
|
|
376
|
-
// Only scan code and config files
|
|
377
|
-
return isCodeKind(kind) || isConfigKind(kind);
|
|
378
|
-
}
|
|
379
342
|
/**
|
|
380
343
|
* Get the language identifier for LSP/tools that use language IDs.
|
|
381
344
|
*/
|