@herbertgao/pi-extensions 2026.8.7 → 2026.8.9
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/README.md +8 -6
- package/node_modules/@czottmann/pi-automode/CHANGELOG.md +24 -0
- package/node_modules/@czottmann/pi-automode/README.md +78 -112
- package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +18 -14
- package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +44 -0
- package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +5 -0
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +198 -104
- package/node_modules/@czottmann/pi-automode/docs/configuration.md +155 -0
- package/node_modules/@czottmann/pi-automode/docs/defaults.md +55 -14
- package/node_modules/@czottmann/pi-automode/docs/diagnostics.md +90 -0
- package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +61 -26
- package/node_modules/@czottmann/pi-automode/examples/automode.local.json +5 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +172 -18
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +127 -30
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +3 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +273 -31
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/log.ts +60 -5
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +92 -8
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +203 -13
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/state.ts +1 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +11 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/utils.ts +9 -1
- package/node_modules/@czottmann/pi-automode/package.json +9 -2
- package/node_modules/@czottmann/pi-automode/skills/automode-diagnostics/SKILL.md +63 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +8 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +63 -15
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +56 -29
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +78 -16
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +13 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +30 -17
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +29 -0
- package/node_modules/@herbertgao/pi-handoff/README.md +15 -18
- package/node_modules/@herbertgao/pi-handoff/package.json +11 -4
- package/node_modules/@herbertgao/pi-handoff/src/complete-text.ts +33 -0
- package/node_modules/@herbertgao/pi-handoff/src/index.ts +127 -232
- package/node_modules/@herbertgao/pi-handoff/src/session-query.ts +15 -30
- package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +14 -0
- package/node_modules/@herbertgao/pi-mermaid-open/README.md +21 -4
- package/node_modules/@herbertgao/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +11 -0
- package/node_modules/@herbertgao/pi-mermaid-open/herdr-plugin/viewer.mjs +305 -0
- package/node_modules/@herbertgao/pi-mermaid-open/package.json +15 -4
- package/node_modules/@herbertgao/pi-mermaid-open/src/index.ts +351 -101
- package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +12 -0
- package/node_modules/@herbertgao/pi-preferred-thinking/README.md +30 -14
- package/node_modules/@herbertgao/pi-preferred-thinking/package.json +7 -4
- package/node_modules/@herbertgao/pi-preferred-thinking/src/index.ts +140 -85
- package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +12 -0
- package/node_modules/@herbertgao/pi-recap/README.md +5 -3
- package/node_modules/@herbertgao/pi-recap/package.json +9 -3
- package/node_modules/@herbertgao/pi-recap/src/index.ts +3 -7
- package/node_modules/@herbertgao/pi-recap/src/model-picker.ts +6 -19
- package/node_modules/@herbertgao/pi-recap/src/models.ts +9 -21
- package/node_modules/@herbertgao/pi-recap/src/tui.ts +1 -1
- package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +49 -0
- package/node_modules/@herbertgao/pi-rename/README.md +13 -11
- package/node_modules/@herbertgao/pi-rename/package.json +13 -3
- package/node_modules/@herbertgao/pi-rename/src/index.ts +135 -59
- package/node_modules/@herbertgao/pi-rename/src/models.ts +5 -13
- package/node_modules/@herbertgao/pi-rename/src/naming.ts +2 -6
- package/node_modules/@herbertgao/pi-stash/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +16 -3
- package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
- package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +15 -4
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +16 -0
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +5 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +4 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +154 -96
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +3 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +7 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +3 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +137 -96
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +44 -32
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +56 -34
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +50 -4
- package/node_modules/@narumitw/pi-btw/package.json +2 -2
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
- package/node_modules/pi-lens/CHANGELOG.md +90 -0
- package/node_modules/pi-lens/README.md +106 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +97 -6
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +16 -6
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +14 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +22 -1
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +8 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +10 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +10 -15
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +19 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +35 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +8 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +110 -23
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +117 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +16 -14
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +8 -9
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +22 -0
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +5 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +7 -2
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +27 -2
- package/node_modules/pi-lens/dist/clients/lsp/client.js +144 -5
- package/node_modules/pi-lens/dist/clients/lsp/index.js +151 -6
- package/node_modules/pi-lens/dist/clients/module-report.js +14 -1
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +18 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +7 -2
- package/node_modules/pi-lens/dist/clients/read-guard.js +88 -19
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +44 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +41 -0
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +47 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
- package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
- package/node_modules/pi-lens/dist/index.js +1224 -393
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +10 -3
- package/node_modules/pi-lens/package.json +18 -5
- package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
- package/node_modules/pi-web-access/CHANGELOG.md +27 -0
- package/node_modules/pi-web-access/README.md +8 -7
- package/node_modules/pi-web-access/chrome-cookies.ts +96 -20
- package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
- package/node_modules/pi-web-access/extract.ts +12 -2
- package/node_modules/pi-web-access/firecrawl.ts +18 -2
- package/node_modules/pi-web-access/gemini-search.ts +28 -10
- package/node_modules/pi-web-access/github-extract.ts +65 -36
- package/node_modules/pi-web-access/index.ts +43 -14
- package/node_modules/pi-web-access/openai-search.ts +17 -6
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/pdf-extract.ts +18 -5
- package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
- package/package.json +19 -18
|
@@ -2678,6 +2678,23 @@ function isLegacyGlobalState(value) {
|
|
|
2678
2678
|
function getRegisteredLogFiles() {
|
|
2679
2679
|
return registeredLogFiles;
|
|
2680
2680
|
}
|
|
2681
|
+
function getSinkWriteFailures() {
|
|
2682
|
+
if (!ndjsonGlobalState)
|
|
2683
|
+
return [];
|
|
2684
|
+
const result = [];
|
|
2685
|
+
for (const state2 of ndjsonGlobalState.writers.values()) {
|
|
2686
|
+
if (state2.writeFailures > 0) {
|
|
2687
|
+
result.push({ file: state2.file, droppedCount: state2.writeFailures });
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
return result;
|
|
2691
|
+
}
|
|
2692
|
+
function resetSinkWriteFailures() {
|
|
2693
|
+
if (!ndjsonGlobalState)
|
|
2694
|
+
return;
|
|
2695
|
+
for (const state2 of ndjsonGlobalState.writers.values())
|
|
2696
|
+
state2.writeFailures = 0;
|
|
2697
|
+
}
|
|
2681
2698
|
function requireCurrentGlobalState() {
|
|
2682
2699
|
if (ndjsonGlobalState)
|
|
2683
2700
|
return ndjsonGlobalState;
|
|
@@ -2703,16 +2720,28 @@ function assertCompatibleWriterOptions(existing, maxBytes, backupPath) {
|
|
|
2703
2720
|
return;
|
|
2704
2721
|
throw new Error(`createNdjsonLogger: incompatible options for shared path ${existing.file}; the first writer's maxBytes/backupPath must be reused`);
|
|
2705
2722
|
}
|
|
2723
|
+
function writeQueueItemSync(state2, item) {
|
|
2724
|
+
if (item.kind === "truncate") {
|
|
2725
|
+
fs.writeFileSync(state2.file, "");
|
|
2726
|
+
} else {
|
|
2727
|
+
rotateIfNeeded(state2);
|
|
2728
|
+
fs.appendFileSync(state2.file, item.line);
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2706
2731
|
function applyQueueItemSync(state2, item) {
|
|
2707
2732
|
ensureDirSync(state2);
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2733
|
+
try {
|
|
2734
|
+
writeQueueItemSync(state2, item);
|
|
2735
|
+
return;
|
|
2736
|
+
} catch {
|
|
2737
|
+
}
|
|
2738
|
+
state2.ensuredDir = false;
|
|
2739
|
+
ensureDirSync(state2);
|
|
2740
|
+
try {
|
|
2741
|
+
writeQueueItemSync(state2, item);
|
|
2742
|
+
} catch {
|
|
2743
|
+
state2.writeFailures += 1;
|
|
2744
|
+
}
|
|
2716
2745
|
}
|
|
2717
2746
|
function flushStateSync(state2) {
|
|
2718
2747
|
const inFlight2 = state2.inFlightBatch;
|
|
@@ -2735,6 +2764,8 @@ function createWriterState(file, maxBytes, backupPath) {
|
|
|
2735
2764
|
assertCompatibleWriterOptions(existing, maxBytes, backupPath);
|
|
2736
2765
|
if (!exitFlushers.has(existing.exitFlusher))
|
|
2737
2766
|
registerWriter(existing);
|
|
2767
|
+
if (typeof existing.writeFailures !== "number")
|
|
2768
|
+
existing.writeFailures = 0;
|
|
2738
2769
|
return existing;
|
|
2739
2770
|
}
|
|
2740
2771
|
const state2 = {};
|
|
@@ -2747,6 +2778,7 @@ function createWriterState(file, maxBytes, backupPath) {
|
|
|
2747
2778
|
state2.syncRepairItems = null;
|
|
2748
2779
|
state2.ensuredDir = false;
|
|
2749
2780
|
state2.exitFlusher = () => flushStateSync(state2);
|
|
2781
|
+
state2.writeFailures = 0;
|
|
2750
2782
|
globalState2.writers.set(file, state2);
|
|
2751
2783
|
registerWriter(state2);
|
|
2752
2784
|
return state2;
|
|
@@ -2781,17 +2813,28 @@ function rotateIfNeeded(state2) {
|
|
|
2781
2813
|
} catch {
|
|
2782
2814
|
}
|
|
2783
2815
|
}
|
|
2816
|
+
async function writeQueueItemAsync(state2, item) {
|
|
2817
|
+
if (item.kind === "truncate") {
|
|
2818
|
+
await fs.promises.writeFile(state2.file, "");
|
|
2819
|
+
} else {
|
|
2820
|
+
rotateIfNeeded(state2);
|
|
2821
|
+
await fs.promises.appendFile(state2.file, item.line);
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2784
2824
|
async function applyQueueItemAsync(state2, item) {
|
|
2785
2825
|
await ensureDirAsync(state2);
|
|
2786
2826
|
try {
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
} else {
|
|
2790
|
-
rotateIfNeeded(state2);
|
|
2791
|
-
await fs.promises.appendFile(state2.file, item.line);
|
|
2792
|
-
}
|
|
2827
|
+
await writeQueueItemAsync(state2, item);
|
|
2828
|
+
return;
|
|
2793
2829
|
} catch {
|
|
2794
2830
|
}
|
|
2831
|
+
state2.ensuredDir = false;
|
|
2832
|
+
await ensureDirAsync(state2);
|
|
2833
|
+
try {
|
|
2834
|
+
await writeQueueItemAsync(state2, item);
|
|
2835
|
+
} catch {
|
|
2836
|
+
state2.writeFailures += 1;
|
|
2837
|
+
}
|
|
2795
2838
|
}
|
|
2796
2839
|
async function drainLoop(state2) {
|
|
2797
2840
|
while (state2.queue.length > 0) {
|
|
@@ -2801,14 +2844,24 @@ async function drainLoop(state2) {
|
|
|
2801
2844
|
const pendingEnd = truncateIndex === -1 ? state2.queue.length : truncateIndex;
|
|
2802
2845
|
const pending = item.kind === "truncate" ? [item] : state2.queue.slice(0, pendingEnd);
|
|
2803
2846
|
state2.inFlightBatch = pending;
|
|
2804
|
-
|
|
2847
|
+
const writeBatch = async () => {
|
|
2805
2848
|
if (item.kind === "truncate") {
|
|
2806
2849
|
await fs.promises.writeFile(state2.file, "");
|
|
2807
2850
|
} else {
|
|
2808
2851
|
rotateIfNeeded(state2);
|
|
2809
2852
|
await fs.promises.appendFile(state2.file, pending.map((queued) => queued.line).join(""));
|
|
2810
2853
|
}
|
|
2854
|
+
};
|
|
2855
|
+
try {
|
|
2856
|
+
await writeBatch();
|
|
2811
2857
|
} catch {
|
|
2858
|
+
state2.ensuredDir = false;
|
|
2859
|
+
await ensureDirAsync(state2);
|
|
2860
|
+
try {
|
|
2861
|
+
await writeBatch();
|
|
2862
|
+
} catch {
|
|
2863
|
+
state2.writeFailures += pending.length;
|
|
2864
|
+
}
|
|
2812
2865
|
}
|
|
2813
2866
|
for (const written of pending) {
|
|
2814
2867
|
if (state2.queue[0] !== written)
|
|
@@ -3315,12 +3368,25 @@ function boundedKind(value) {
|
|
|
3315
3368
|
return groups.size < MAX_DISTINCT_KINDS - 1 ? kind : OVERFLOW_KIND;
|
|
3316
3369
|
}
|
|
3317
3370
|
function getDegradationSummary() {
|
|
3318
|
-
|
|
3371
|
+
const summary = [...groups.entries()].map(([kind, group]) => ({
|
|
3319
3372
|
kind,
|
|
3320
3373
|
count: group.count,
|
|
3321
3374
|
droppedCount: group.count - group.entries.length,
|
|
3322
3375
|
latestReasons: group.entries.map((entry) => ({ ...entry }))
|
|
3323
3376
|
}));
|
|
3377
|
+
const sinkFailures = getSinkWriteFailures();
|
|
3378
|
+
if (sinkFailures.length > 0) {
|
|
3379
|
+
summary.push({
|
|
3380
|
+
kind: "log-sink-write-failure",
|
|
3381
|
+
count: sinkFailures.reduce((total, sink) => total + sink.droppedCount, 0),
|
|
3382
|
+
droppedCount: 0,
|
|
3383
|
+
latestReasons: sinkFailures.map((sink) => ({
|
|
3384
|
+
subject: truncateForLedger(sink.file),
|
|
3385
|
+
reason: truncateForLedger(`${sink.droppedCount} dropped write(s) after reopen-retry failed`)
|
|
3386
|
+
}))
|
|
3387
|
+
});
|
|
3388
|
+
}
|
|
3389
|
+
return summary;
|
|
3324
3390
|
}
|
|
3325
3391
|
function debugLedgerFailure(operation, error) {
|
|
3326
3392
|
try {
|
|
@@ -3337,6 +3403,7 @@ function resetDegradationLedger() {
|
|
|
3337
3403
|
onceKeys.clear();
|
|
3338
3404
|
tallies.clear();
|
|
3339
3405
|
ledgerGeneration++;
|
|
3406
|
+
resetSinkWriteFailures();
|
|
3340
3407
|
}
|
|
3341
3408
|
var ENTRIES_PER_KIND, MAX_DISTINCT_KINDS, OVERFLOW_KIND, groups, onceKeys, tallies, ledgerGeneration;
|
|
3342
3409
|
var init_degradation_ledger = __esm({
|
|
@@ -3345,6 +3412,7 @@ var init_degradation_ledger = __esm({
|
|
|
3345
3412
|
init_extension_log();
|
|
3346
3413
|
init_ledger_bounds();
|
|
3347
3414
|
init_latency_logger();
|
|
3415
|
+
init_ndjson_logger();
|
|
3348
3416
|
ENTRIES_PER_KIND = 20;
|
|
3349
3417
|
MAX_DISTINCT_KINDS = 32;
|
|
3350
3418
|
OVERFLOW_KIND = "other";
|
|
@@ -22617,11 +22685,11 @@ function classifyEntry(entry, fullPath, cfg, probeCache, skipCounters) {
|
|
|
22617
22685
|
return { recurseInto: fullPath };
|
|
22618
22686
|
}
|
|
22619
22687
|
if (entry.isFile()) {
|
|
22620
|
-
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
22621
|
-
return {};
|
|
22622
22688
|
const ext2 = path38.extname(entry.name).toLowerCase();
|
|
22623
22689
|
if (!extensions.has(ext2))
|
|
22624
22690
|
return {};
|
|
22691
|
+
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
22692
|
+
return {};
|
|
22625
22693
|
if (isBuildArtifact(fullPath, probeCache)) {
|
|
22626
22694
|
if (skipCounters)
|
|
22627
22695
|
skipCounters.buildArtifactSkips += 1;
|
|
@@ -28510,6 +28578,46 @@ function skipUnlessToolRan(tool, input, fields) {
|
|
|
28510
28578
|
});
|
|
28511
28579
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
28512
28580
|
}
|
|
28581
|
+
function recordParsedNothing(input) {
|
|
28582
|
+
const { tool, status, output, parsedCount } = input;
|
|
28583
|
+
if (parsedCount > 0)
|
|
28584
|
+
return false;
|
|
28585
|
+
if (!status)
|
|
28586
|
+
return false;
|
|
28587
|
+
const text = output ?? "";
|
|
28588
|
+
if (!text.trim())
|
|
28589
|
+
return false;
|
|
28590
|
+
const entries = Object.entries(input.fields ?? {}).filter(([, value]) => value !== void 0 && value !== "");
|
|
28591
|
+
const identity = entries.length ? `${tool} (${entries.map(([key2, value]) => `${key2}=${value}`).join(", ")})` : tool;
|
|
28592
|
+
incrementDegradationCount({
|
|
28593
|
+
kind: "runner-parsed-nothing",
|
|
28594
|
+
subject: tool,
|
|
28595
|
+
reason: truncateForLedger(`${identity} exited ${status} with ${text.length} chars of output but the parser read 0 diagnostics: ${firstOutputLine(text) || "no first line"}`)
|
|
28596
|
+
});
|
|
28597
|
+
return true;
|
|
28598
|
+
}
|
|
28599
|
+
function parseToolRun(tool, input, parse6, options = {}) {
|
|
28600
|
+
const skipped = skipUnlessToolRan(tool, input, options.fields);
|
|
28601
|
+
if (skipped)
|
|
28602
|
+
return { skipped, diagnostics: [], parsedNothing: false };
|
|
28603
|
+
const output = options.parseOutput ?? input.output ?? input.result.stdout ?? "";
|
|
28604
|
+
const diagnostics = [...parse6(output)];
|
|
28605
|
+
const parsedNothing = recordParsedNothing({
|
|
28606
|
+
tool,
|
|
28607
|
+
status: input.result.status ?? null,
|
|
28608
|
+
output,
|
|
28609
|
+
parsedCount: diagnostics.length,
|
|
28610
|
+
fields: options.fields
|
|
28611
|
+
});
|
|
28612
|
+
if (parsedNothing && options.skipWhenParsedNothing) {
|
|
28613
|
+
return {
|
|
28614
|
+
skipped: { status: "skipped", diagnostics: [], semantic: "none" },
|
|
28615
|
+
diagnostics: [],
|
|
28616
|
+
parsedNothing
|
|
28617
|
+
};
|
|
28618
|
+
}
|
|
28619
|
+
return { skipped: null, diagnostics, parsedNothing };
|
|
28620
|
+
}
|
|
28513
28621
|
var init_tool_failure = __esm({
|
|
28514
28622
|
"dist/clients/dispatch/runners/utils/tool-failure.js"() {
|
|
28515
28623
|
"use strict";
|
|
@@ -29413,11 +29521,11 @@ var init_jscpd_client = __esm({
|
|
|
29413
29521
|
}
|
|
29414
29522
|
if (!entry.isFile())
|
|
29415
29523
|
return "skip";
|
|
29416
|
-
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
29417
|
-
return "skip";
|
|
29418
29524
|
if (/\.(ts|tsx|js|jsx|mjs|cjs|py|pyi|java|go|rs|rb|php|swift|kt|kts|dart|lua|scala|c|h|cpp|cc|cxx|hpp|hxx|cs|m|mm)$/.test(entry.name)) {
|
|
29419
29525
|
if (entry.name.endsWith(".d.ts"))
|
|
29420
29526
|
return "skip";
|
|
29527
|
+
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
29528
|
+
return "skip";
|
|
29421
29529
|
return "stop";
|
|
29422
29530
|
}
|
|
29423
29531
|
return "skip";
|
|
@@ -31609,7 +31717,8 @@ function logTreeSitterCacheStats(options) {
|
|
|
31609
31717
|
maxSize: options.stats.maxSize,
|
|
31610
31718
|
totalBytes: options.stats.totalBytes,
|
|
31611
31719
|
totalLines: options.stats.totalLines
|
|
31612
|
-
}
|
|
31720
|
+
},
|
|
31721
|
+
...options.astGrep ? { astGrep: options.astGrep } : {}
|
|
31613
31722
|
}
|
|
31614
31723
|
});
|
|
31615
31724
|
}
|
|
@@ -38909,7 +39018,11 @@ function shouldLogEvent(event) {
|
|
|
38909
39018
|
return LOG_ALLOWED_EDITS;
|
|
38910
39019
|
if (event === "range_snapshot_validation")
|
|
38911
39020
|
return LOG_SNAPSHOT_VALIDATION;
|
|
38912
|
-
return event === "edit_blocked" || event === "edit_warned" || event === "exemption_added" || event === "oldtext_not_found" || event === "oldtext_duplicate" || event === "oldtext_indent_autopatched" || event === "oldtext_trailing_ws_autopatched" || event === "oldtext_escape_autopatched" || event === "edit_range_relocated" || event === "edit_preflight_blocked" || event === "edit_partial_apply" || event === "edit_partial_apply_skipped" || event === "edit_post_edit_pipeline_failed" || event === "edit_batch_summary" || event === "edit_batch_summary_overflow" || event === "touched_lines_missing"
|
|
39021
|
+
return event === "edit_blocked" || event === "edit_warned" || event === "exemption_added" || event === "oldtext_not_found" || event === "oldtext_duplicate" || event === "oldtext_indent_autopatched" || event === "oldtext_trailing_ws_autopatched" || event === "oldtext_escape_autopatched" || event === "edit_range_relocated" || event === "edit_preflight_blocked" || event === "edit_partial_apply" || event === "edit_partial_apply_skipped" || event === "edit_post_edit_pipeline_failed" || event === "edit_batch_summary" || event === "edit_batch_summary_overflow" || event === "touched_lines_missing" || // #1913: read-guard record-cap evictions are rare by construction (only
|
|
39022
|
+
// READ_GUARD_MAX_RECORDS_PER_FILE overflow triggers one), so this trim
|
|
39023
|
+
// record bypasses the per-read verbosity gate — a live eviction
|
|
39024
|
+
// regression must be visible without PI_LENS_READ_GUARD_VERBOSE=1.
|
|
39025
|
+
event === "read_cap_trimmed";
|
|
38913
39026
|
}
|
|
38914
39027
|
function boundTelemetryValue(value, pathName, depth) {
|
|
38915
39028
|
if (typeof value === "string") {
|
|
@@ -39700,11 +39813,11 @@ function getModuleSourceFiles(moduleRoot, maxFiles = 20) {
|
|
|
39700
39813
|
}
|
|
39701
39814
|
if (!entry.isFile())
|
|
39702
39815
|
continue;
|
|
39816
|
+
if (!SOURCE_EXTS.has(path72.extname(entry.name).toLowerCase()))
|
|
39817
|
+
continue;
|
|
39703
39818
|
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
39704
39819
|
continue;
|
|
39705
|
-
|
|
39706
|
-
files2.push(normalizeMapKey(fullPath));
|
|
39707
|
-
}
|
|
39820
|
+
files2.push(normalizeMapKey(fullPath));
|
|
39708
39821
|
}
|
|
39709
39822
|
};
|
|
39710
39823
|
visit2(root, 0);
|
|
@@ -41834,12 +41947,26 @@ var init_bounded_telemetry = __esm({
|
|
|
41834
41947
|
"lsp_client_skipped_broken",
|
|
41835
41948
|
/** #1743 review: the same skip, for a temporarily unavailable command. */
|
|
41836
41949
|
"lsp_client_skipped_unavailable_command",
|
|
41950
|
+
/**
|
|
41951
|
+
* #1934: `getWarmClientForFile` found no live client for a file that has at
|
|
41952
|
+
* least one language server with a resolvable root. Its callers run per
|
|
41953
|
+
* file (the cascade quiet window, read expansion, `hasWarmLSP`), so it is
|
|
41954
|
+
* rising-edge per candidate (server, root) set, with the ledger holding the
|
|
41955
|
+
* exact count.
|
|
41956
|
+
*/
|
|
41957
|
+
"lsp_warm_client_missing",
|
|
41837
41958
|
/**
|
|
41838
41959
|
* #1723: an event-loop block at or above the floor. Not a degradation, so
|
|
41839
41960
|
* no ledger kind; bounded by call cadence (one `turn_end` runs it once per
|
|
41840
41961
|
* turn) rather than by an option here.
|
|
41841
41962
|
*/
|
|
41842
|
-
"loop_block"
|
|
41963
|
+
"loop_block",
|
|
41964
|
+
/**
|
|
41965
|
+
* #1925: a session event skipped because its ctx was invalidated by a
|
|
41966
|
+
* session replacement or reload. A replaced session can drain a whole
|
|
41967
|
+
* queue of them, so it is rising-edge per event name.
|
|
41968
|
+
*/
|
|
41969
|
+
"session_event_stale_ctx_skip"
|
|
41843
41970
|
];
|
|
41844
41971
|
REGISTERED_PHASES = new Set(BOUNDED_TELEMETRY_PHASES);
|
|
41845
41972
|
turnCounts = /* @__PURE__ */ new Map();
|
|
@@ -48819,6 +48946,19 @@ function setupConnectionLifecycle(state2, recentStderr) {
|
|
|
48819
48946
|
});
|
|
48820
48947
|
}
|
|
48821
48948
|
});
|
|
48949
|
+
state2.lspProcess.process.on("close", (code, signal) => {
|
|
48950
|
+
if (state2.shutdownRequested)
|
|
48951
|
+
return;
|
|
48952
|
+
try {
|
|
48953
|
+
const stderrTail = recentStderr(20);
|
|
48954
|
+
incrementDegradationCount({
|
|
48955
|
+
kind: "lsp-server-unexpected-close",
|
|
48956
|
+
subject: state2.serverId,
|
|
48957
|
+
reason: `closed unprompted: code=${code ?? "none"} signal=${signal ?? "none"} stderr=${stderrTail.length > 0 ? `present(${stderrTail.length}b)` : "empty"} root=${state2.root}`
|
|
48958
|
+
});
|
|
48959
|
+
} catch {
|
|
48960
|
+
}
|
|
48961
|
+
});
|
|
48822
48962
|
}
|
|
48823
48963
|
async function clientRequestPullDiagnostics(state2, filePath, budgetMs = PULL_REQUEST_TIMEOUT_MS) {
|
|
48824
48964
|
if (!isClientAlive(state2))
|
|
@@ -49590,13 +49730,58 @@ function armNavLateAnswerTelemetry(args) {
|
|
|
49590
49730
|
}, () => {
|
|
49591
49731
|
});
|
|
49592
49732
|
}
|
|
49733
|
+
function chooseLivenessProbe(state2) {
|
|
49734
|
+
if (state2.operationSupport?.workspaceSymbol === true) {
|
|
49735
|
+
return {
|
|
49736
|
+
method: "workspace/symbol",
|
|
49737
|
+
params: { query: LIVENESS_PING_QUERY }
|
|
49738
|
+
};
|
|
49739
|
+
}
|
|
49740
|
+
const openUri = firstOpenDocumentUri(state2);
|
|
49741
|
+
if (openUri === void 0)
|
|
49742
|
+
return void 0;
|
|
49743
|
+
if (state2.operationSupport?.documentSymbol === true) {
|
|
49744
|
+
return {
|
|
49745
|
+
method: "textDocument/documentSymbol",
|
|
49746
|
+
params: { textDocument: { uri: openUri } }
|
|
49747
|
+
};
|
|
49748
|
+
}
|
|
49749
|
+
if (state2.operationSupport?.hover === true) {
|
|
49750
|
+
return {
|
|
49751
|
+
method: "textDocument/hover",
|
|
49752
|
+
params: {
|
|
49753
|
+
textDocument: { uri: openUri },
|
|
49754
|
+
position: { line: 0, character: 0 }
|
|
49755
|
+
}
|
|
49756
|
+
};
|
|
49757
|
+
}
|
|
49758
|
+
return void 0;
|
|
49759
|
+
}
|
|
49760
|
+
function firstOpenDocumentUri(state2) {
|
|
49761
|
+
for (const normalizedPath of state2.openDocuments) {
|
|
49762
|
+
const uri = state2.openDocumentUris?.get(normalizedPath);
|
|
49763
|
+
if (uri !== void 0)
|
|
49764
|
+
return uri;
|
|
49765
|
+
}
|
|
49766
|
+
return void 0;
|
|
49767
|
+
}
|
|
49593
49768
|
async function clientPingLiveness(state2, timeoutMs = LIVENESS_PING_TIMEOUT_MS) {
|
|
49594
49769
|
if (!isClientAlive(state2))
|
|
49595
49770
|
return false;
|
|
49771
|
+
const probe = chooseLivenessProbe(state2);
|
|
49772
|
+
if (probe === void 0) {
|
|
49773
|
+
try {
|
|
49774
|
+
incrementDegradationCount({
|
|
49775
|
+
kind: "lsp-liveness-probe-unsupported",
|
|
49776
|
+
subject: state2.serverId,
|
|
49777
|
+
reason: "no advertised request method to probe with (no workspaceSymbolProvider, and no open document with documentSymbolProvider or hoverProvider); liveness from process and connection state only"
|
|
49778
|
+
});
|
|
49779
|
+
} catch {
|
|
49780
|
+
}
|
|
49781
|
+
return isClientAlive(state2);
|
|
49782
|
+
}
|
|
49596
49783
|
try {
|
|
49597
|
-
await withTimeout(safeSendRequest(state2.connection,
|
|
49598
|
-
query: LIVENESS_PING_QUERY
|
|
49599
|
-
}), timeoutMs);
|
|
49784
|
+
await withTimeout(safeSendRequest(state2.connection, probe.method, probe.params), timeoutMs);
|
|
49600
49785
|
} catch (err) {
|
|
49601
49786
|
if (err instanceof Error && err.message.startsWith("Timeout after")) {
|
|
49602
49787
|
return false;
|
|
@@ -49872,6 +50057,7 @@ async function createLSPClient(options) {
|
|
|
49872
50057
|
initializationOptions: initialization
|
|
49873
50058
|
}), initializeTimeoutMs);
|
|
49874
50059
|
} catch (err) {
|
|
50060
|
+
state2.shutdownRequested = true;
|
|
49875
50061
|
const pid = lspProcess.pid;
|
|
49876
50062
|
void killProcessTree(lspProcess.process, pid);
|
|
49877
50063
|
void removeLspChild(pid, extractSpawnMarker(lspProcess.args)).catch((err2) => {
|
|
@@ -51533,7 +51719,14 @@ async function collectWorkspaceDiagnosticFiles(root, maxFiles = getMaxWorkspaceD
|
|
|
51533
51719
|
if (ignoreMatcher.isIgnored(full, true))
|
|
51534
51720
|
continue;
|
|
51535
51721
|
await walk2(full);
|
|
51536
|
-
} else if (
|
|
51722
|
+
} else if (
|
|
51723
|
+
// #1974: the getServersForFileWithConfig lookup (an in-memory
|
|
51724
|
+
// extension/pathFilter match against the registered LSP servers) is
|
|
51725
|
+
// cheap relative to isIgnored's per-call minimatch pattern compile,
|
|
51726
|
+
// so it gates first — the same order-independent shape as the four
|
|
51727
|
+
// walkers fixed for #1974.
|
|
51728
|
+
entry.isFile() && getServersForFileWithConfig(full).length > 0 && !ignoreMatcher.isIgnored(full, false)
|
|
51729
|
+
) {
|
|
51537
51730
|
files2.push(full);
|
|
51538
51731
|
}
|
|
51539
51732
|
}
|
|
@@ -51647,6 +51840,21 @@ var init_lsp = __esm({
|
|
|
51647
51840
|
/** Server/root pairs that already emitted unavailable for the current occurrence. */
|
|
51648
51841
|
unavailableLogged = /* @__PURE__ */ new Set();
|
|
51649
51842
|
optionalDisabled = /* @__PURE__ */ new Set();
|
|
51843
|
+
/**
|
|
51844
|
+
* #1934 review F1: what the last COMPLETED `spawnClient` call for a
|
|
51845
|
+
* (server, root) key decided, written by that call at every point it
|
|
51846
|
+
* returns without a client. This is a direct signal, deliberately NOT an
|
|
51847
|
+
* inference from breaker state: the "binary unavailable while installs are
|
|
51848
|
+
* disabled" branch sets a cooldown yet is a POLICY decline by its own
|
|
51849
|
+
* comment, so reading the cooldown mislabels it as a server failure.
|
|
51850
|
+
*
|
|
51851
|
+
* Not a latch, and nothing re-arms it at `session_start`. Every read sits
|
|
51852
|
+
* in the same microtask as the `await` of the spawn promise that just
|
|
51853
|
+
* wrote it, so a stale entry is unreachable: a read is always preceded by
|
|
51854
|
+
* its own attempt's write. Cardinality matches `state.clients` — one entry
|
|
51855
|
+
* per (server, root) — and a successful spawn deletes its entry.
|
|
51856
|
+
*/
|
|
51857
|
+
lastSpawnVerdict = /* @__PURE__ */ new Map();
|
|
51650
51858
|
/** Consecutive failure counts for exponential backoff circuit breaker */
|
|
51651
51859
|
failureCounts = /* @__PURE__ */ new Map();
|
|
51652
51860
|
/**
|
|
@@ -52558,8 +52766,14 @@ var init_lsp = __esm({
|
|
|
52558
52766
|
const withBudget2 = async () => {
|
|
52559
52767
|
if (servers.length === 0)
|
|
52560
52768
|
return void 0;
|
|
52769
|
+
let erroredServerId;
|
|
52561
52770
|
for (const server of servers) {
|
|
52562
|
-
const
|
|
52771
|
+
const acquisition = {
|
|
52772
|
+
outcome: "declined"
|
|
52773
|
+
};
|
|
52774
|
+
const spawned = await this.ensureClientForServer(filePath, server, resolvedRoots, noteSpawnInFlight, (reported) => {
|
|
52775
|
+
acquisition.outcome = reported;
|
|
52776
|
+
});
|
|
52563
52777
|
if (spawned) {
|
|
52564
52778
|
logLatency({
|
|
52565
52779
|
type: "phase",
|
|
@@ -52568,11 +52782,32 @@ var init_lsp = __esm({
|
|
|
52568
52782
|
durationMs: 0,
|
|
52569
52783
|
metadata: {
|
|
52570
52784
|
serverId: server.id,
|
|
52571
|
-
candidateCount: servers.length
|
|
52785
|
+
candidateCount: servers.length,
|
|
52786
|
+
// Emitted RAW, never coerced to a "safe" value: a served
|
|
52787
|
+
// client always reports `warm-reuse` or `cold-spawn`, so a
|
|
52788
|
+
// `declined` here would be a real reporting bug and must be
|
|
52789
|
+
// visible in the log rather than laundered into a lie.
|
|
52790
|
+
outcome: acquisition.outcome
|
|
52572
52791
|
}
|
|
52573
52792
|
});
|
|
52574
52793
|
return spawned;
|
|
52575
52794
|
}
|
|
52795
|
+
if (acquisition.outcome === "spawn-failure") {
|
|
52796
|
+
erroredServerId ??= server.id;
|
|
52797
|
+
}
|
|
52798
|
+
}
|
|
52799
|
+
if (erroredServerId !== void 0) {
|
|
52800
|
+
logLatency({
|
|
52801
|
+
type: "phase",
|
|
52802
|
+
phase: "lsp_client_selected",
|
|
52803
|
+
filePath,
|
|
52804
|
+
durationMs: 0,
|
|
52805
|
+
metadata: {
|
|
52806
|
+
serverId: erroredServerId,
|
|
52807
|
+
candidateCount: servers.length,
|
|
52808
|
+
outcome: "spawn-failure"
|
|
52809
|
+
}
|
|
52810
|
+
});
|
|
52576
52811
|
}
|
|
52577
52812
|
const unavailable = (await Promise.all(servers.map(async (server) => {
|
|
52578
52813
|
const root = await server.root(filePath);
|
|
@@ -52697,6 +52932,7 @@ var init_lsp = __esm({
|
|
|
52697
52932
|
if (this.checkDestroyed())
|
|
52698
52933
|
return void 0;
|
|
52699
52934
|
const servers = getServersForFileWithConfig(filePath);
|
|
52935
|
+
const missed = [];
|
|
52700
52936
|
for (const server of servers) {
|
|
52701
52937
|
const root = await this.resolveServerRoot(server, filePath);
|
|
52702
52938
|
if (!root)
|
|
@@ -52706,6 +52942,21 @@ var init_lsp = __esm({
|
|
|
52706
52942
|
if (existing?.isAlive()) {
|
|
52707
52943
|
return { client: existing, info: server };
|
|
52708
52944
|
}
|
|
52945
|
+
missed.push(key2);
|
|
52946
|
+
}
|
|
52947
|
+
if (missed.length > 0) {
|
|
52948
|
+
emitBounded("lsp_warm_client_missing", missed.join(","), {
|
|
52949
|
+
filePath,
|
|
52950
|
+
durationMs: 0,
|
|
52951
|
+
metadata: {
|
|
52952
|
+
serverIds: missed.map((key2) => key2.slice(0, key2.indexOf(":"))),
|
|
52953
|
+
roots: missed.map((key2) => key2.slice(key2.indexOf(":") + 1))
|
|
52954
|
+
}
|
|
52955
|
+
}, {
|
|
52956
|
+
ledgerKind: "lsp-warm-client-missing",
|
|
52957
|
+
risingEdgePer: "identity",
|
|
52958
|
+
reason: `no warm client for ${missed.join(",")}`
|
|
52959
|
+
});
|
|
52709
52960
|
}
|
|
52710
52961
|
return void 0;
|
|
52711
52962
|
}
|
|
@@ -52881,7 +53132,22 @@ var init_lsp = __esm({
|
|
|
52881
53132
|
}
|
|
52882
53133
|
this.documentDrift.recordSynced(filePath, content, at);
|
|
52883
53134
|
}
|
|
52884
|
-
|
|
53135
|
+
/**
|
|
53136
|
+
* #1934 review F1: record what a `spawnClient` call decided, at the point
|
|
53137
|
+
* it decides it. Called on EVERY path that returns without a client, so
|
|
53138
|
+
* "no verdict" cannot silently mean "failed".
|
|
53139
|
+
*
|
|
53140
|
+
* `"failed"` is a server failure: the spawn or the initialize handshake
|
|
53141
|
+
* went wrong. `"declined"` is policy or lifecycle: host trust refused the
|
|
53142
|
+
* binary, the service shut down mid-spawn, or the binary is absent while
|
|
53143
|
+
* installs are disabled. That last one sets a breaker cooldown but is NOT
|
|
53144
|
+
* a failure, which is exactly why the outcome cannot be inferred from
|
|
53145
|
+
* breaker state.
|
|
53146
|
+
*/
|
|
53147
|
+
noteSpawnVerdict(key2, verdict) {
|
|
53148
|
+
this.lastSpawnVerdict.set(key2, verdict);
|
|
53149
|
+
}
|
|
53150
|
+
async ensureClientForServer(filePath, server, resolvedRoots, onSpawnInFlight, onOutcome) {
|
|
52885
53151
|
const handoff = this.generationHandoff;
|
|
52886
53152
|
if (handoff) {
|
|
52887
53153
|
await handoff;
|
|
@@ -52944,6 +53210,7 @@ var init_lsp = __esm({
|
|
|
52944
53210
|
logSessionStart(`lsp warm-start ${server.id}: reused root=${root} file=${filePath}`);
|
|
52945
53211
|
this.warmStartLogged.add(key2);
|
|
52946
53212
|
}
|
|
53213
|
+
onOutcome?.("warm-reuse");
|
|
52947
53214
|
return { client: existing, info: server };
|
|
52948
53215
|
}
|
|
52949
53216
|
const spawnedAt = this.state.clientSpawnedAt.get(key2);
|
|
@@ -53051,7 +53318,12 @@ var init_lsp = __esm({
|
|
|
53051
53318
|
}
|
|
53052
53319
|
onSpawnInFlight?.(server.id);
|
|
53053
53320
|
try {
|
|
53054
|
-
|
|
53321
|
+
const spawned = await spawnPromise;
|
|
53322
|
+
onOutcome?.(spawned ? "cold-spawn" : this.lastSpawnVerdict.get(key2) === "failed" ? "spawn-failure" : "declined");
|
|
53323
|
+
return spawned;
|
|
53324
|
+
} catch (err) {
|
|
53325
|
+
onOutcome?.("spawn-failure");
|
|
53326
|
+
throw err;
|
|
53055
53327
|
} finally {
|
|
53056
53328
|
if (this.state.inFlight.get(key2) === spawnPromise) {
|
|
53057
53329
|
this.state.inFlight.delete(key2);
|
|
@@ -53069,6 +53341,7 @@ var init_lsp = __esm({
|
|
|
53069
53341
|
async spawnClient(server, root, key2, filePath, allowInstall) {
|
|
53070
53342
|
if (!isLspSpawnAllowedByTrust()) {
|
|
53071
53343
|
logSessionStart(`lsp spawn ${server.id}: refused \u2014 ${projectTrustDenialReason()}`);
|
|
53344
|
+
this.noteSpawnVerdict(key2, "declined");
|
|
53072
53345
|
return void 0;
|
|
53073
53346
|
}
|
|
53074
53347
|
const isOptionalServer = OPTIONAL_LSP_SERVER_IDS.has(server.id);
|
|
@@ -53083,6 +53356,7 @@ var init_lsp = __esm({
|
|
|
53083
53356
|
} catch {
|
|
53084
53357
|
}
|
|
53085
53358
|
logSessionStart(`lsp spawn ${server.id}: aborted (service shut down mid-spawn)`);
|
|
53359
|
+
this.noteSpawnVerdict(key2, "declined");
|
|
53086
53360
|
return void 0;
|
|
53087
53361
|
}
|
|
53088
53362
|
if (!spawned) {
|
|
@@ -53091,6 +53365,7 @@ var init_lsp = __esm({
|
|
|
53091
53365
|
if (!allowInstall) {
|
|
53092
53366
|
logSessionStart(`lsp spawn ${server.id}: unavailable with install disabled; temporary cooldown only`);
|
|
53093
53367
|
this.state.broken.set(key2, Date.now() + BROKEN_BASE_COOLDOWN_MS);
|
|
53368
|
+
this.noteSpawnVerdict(key2, "declined");
|
|
53094
53369
|
return void 0;
|
|
53095
53370
|
}
|
|
53096
53371
|
const uCount = (this.failureCounts.get(key2) ?? 0) + 1;
|
|
@@ -53102,6 +53377,7 @@ var init_lsp = __esm({
|
|
|
53102
53377
|
this.recordBreaker(key2, `permanently disabled after ${uCount} unavailable spawns`);
|
|
53103
53378
|
logSessionStart(`lsp spawn ${server.id}: permanently disabled after ${uCount} failures`);
|
|
53104
53379
|
}
|
|
53380
|
+
this.noteSpawnVerdict(key2, "failed");
|
|
53105
53381
|
return void 0;
|
|
53106
53382
|
}
|
|
53107
53383
|
const override = getServerInitOverride(server.id, filePath);
|
|
@@ -53118,6 +53394,7 @@ var init_lsp = __esm({
|
|
|
53118
53394
|
client.shutdown({ fast: true }).catch(() => {
|
|
53119
53395
|
});
|
|
53120
53396
|
logSessionStart(`lsp spawn ${server.id}: aborted (service shut down mid-initialize)`);
|
|
53397
|
+
this.noteSpawnVerdict(key2, "declined");
|
|
53121
53398
|
return void 0;
|
|
53122
53399
|
}
|
|
53123
53400
|
const wsDiag = typeof client.getWorkspaceDiagnosticsSupport === "function" ? client.getWorkspaceDiagnosticsSupport() : {
|
|
@@ -53127,6 +53404,7 @@ var init_lsp = __esm({
|
|
|
53127
53404
|
};
|
|
53128
53405
|
this.state.clients.set(key2, client);
|
|
53129
53406
|
this.unavailableLogged.delete(key2);
|
|
53407
|
+
this.lastSpawnVerdict.delete(key2);
|
|
53130
53408
|
this.state.clientSpawnedAt.set(key2, Date.now());
|
|
53131
53409
|
this.clientLastUsedAt.set(key2, Date.now());
|
|
53132
53410
|
this.scheduleTypeScriptIdleEviction(key2);
|
|
@@ -53164,6 +53442,7 @@ var init_lsp = __esm({
|
|
|
53164
53442
|
if (isOptionalServer) {
|
|
53165
53443
|
this.optionalDisabled.add(key2);
|
|
53166
53444
|
}
|
|
53445
|
+
this.noteSpawnVerdict(key2, "failed");
|
|
53167
53446
|
return void 0;
|
|
53168
53447
|
}
|
|
53169
53448
|
}
|
|
@@ -55714,6 +55993,7 @@ var init_lsp = __esm({
|
|
|
55714
55993
|
});
|
|
55715
55994
|
this.state.clients.clear();
|
|
55716
55995
|
this.state.broken.clear();
|
|
55996
|
+
this.lastSpawnVerdict.clear();
|
|
55717
55997
|
this.outstandingAuxNotifyWrites.clear();
|
|
55718
55998
|
this.auxNotifyInflight.clear();
|
|
55719
55999
|
this.documentDrift.clear();
|
|
@@ -56933,12 +57213,15 @@ Please read the file again before modifying it.`, absolutePath, "modified");
|
|
|
56933
57213
|
import * as fs72 from "node:fs";
|
|
56934
57214
|
function enforceRecordCapForFile(records) {
|
|
56935
57215
|
if (records.length <= READ_GUARD_MAX_RECORDS_PER_FILE)
|
|
56936
|
-
return
|
|
57216
|
+
return NO_TRIM;
|
|
56937
57217
|
const excess = records.length - READ_GUARD_MAX_RECORDS_PER_FILE;
|
|
56938
57218
|
const evicted = /* @__PURE__ */ new Set();
|
|
57219
|
+
let evictedCreditCount = 0;
|
|
56939
57220
|
for (let i = 0; i < records.length && evicted.size < excess; i++) {
|
|
56940
|
-
if (records[i].searchCredit !== void 0)
|
|
57221
|
+
if (records[i].searchCredit !== void 0) {
|
|
56941
57222
|
evicted.add(i);
|
|
57223
|
+
evictedCreditCount++;
|
|
57224
|
+
}
|
|
56942
57225
|
}
|
|
56943
57226
|
for (let i = 0; i < records.length && evicted.size < excess; i++) {
|
|
56944
57227
|
evicted.add(i);
|
|
@@ -56947,7 +57230,11 @@ function enforceRecordCapForFile(records) {
|
|
|
56947
57230
|
records.length = 0;
|
|
56948
57231
|
for (const record2 of kept)
|
|
56949
57232
|
records.push(record2);
|
|
56950
|
-
return
|
|
57233
|
+
return {
|
|
57234
|
+
evictedCount: excess,
|
|
57235
|
+
evictedCreditCount,
|
|
57236
|
+
evictedGenuineCount: excess - evictedCreditCount
|
|
57237
|
+
};
|
|
56951
57238
|
}
|
|
56952
57239
|
function captureReadContentBinding(filePath, offset, limit) {
|
|
56953
57240
|
try {
|
|
@@ -57090,10 +57377,11 @@ function mapVerdictAction(action) {
|
|
|
57090
57377
|
return "warned";
|
|
57091
57378
|
}
|
|
57092
57379
|
}
|
|
57093
|
-
var READ_GUARD_STATE_VERSION, DEFAULT_CONFIG, OWN_EDIT_STALE_GRACE_MS, READ_HASH_MAX_LINES, READ_BINDING_MAX_BYTES, READ_GUARD_MAX_FILES, READ_GUARD_MAX_RECORDS_PER_FILE, READ_GUARD_MAX_EDITS_PER_FILE, READ_GUARD_MAX_UNCONSUMED_FILES, READ_GUARD_IDLE_EVICT_MS_DEFAULT, currentContentMatchesBinding, RELOCATION_WINDOW_MIN, RELOCATION_WINDOW_PER_EDIT, RELOCATION_WINDOW_MAX, ReadGuard;
|
|
57380
|
+
var READ_GUARD_STATE_VERSION, DEFAULT_CONFIG, OWN_EDIT_STALE_GRACE_MS, READ_HASH_MAX_LINES, READ_BINDING_MAX_BYTES, READ_GUARD_MAX_FILES, READ_GUARD_MAX_RECORDS_PER_FILE, NO_TRIM, READ_GUARD_MAX_EDITS_PER_FILE, READ_GUARD_MAX_UNCONSUMED_FILES, READ_GUARD_IDLE_EVICT_MS_DEFAULT, currentContentMatchesBinding, RELOCATION_WINDOW_MIN, RELOCATION_WINDOW_PER_EDIT, RELOCATION_WINDOW_MAX, ReadGuard;
|
|
57094
57381
|
var init_read_guard = __esm({
|
|
57095
57382
|
"dist/clients/read-guard.js"() {
|
|
57096
57383
|
"use strict";
|
|
57384
|
+
init_degradation_ledger();
|
|
57097
57385
|
init_file_time();
|
|
57098
57386
|
init_diagnostic_binding();
|
|
57099
57387
|
init_path_utils();
|
|
@@ -57114,6 +57402,11 @@ var init_read_guard = __esm({
|
|
|
57114
57402
|
READ_BINDING_MAX_BYTES = 4 * 1024 * 1024;
|
|
57115
57403
|
READ_GUARD_MAX_FILES = 256;
|
|
57116
57404
|
READ_GUARD_MAX_RECORDS_PER_FILE = 128;
|
|
57405
|
+
NO_TRIM = {
|
|
57406
|
+
evictedCount: 0,
|
|
57407
|
+
evictedCreditCount: 0,
|
|
57408
|
+
evictedGenuineCount: 0
|
|
57409
|
+
};
|
|
57117
57410
|
READ_GUARD_MAX_EDITS_PER_FILE = 256;
|
|
57118
57411
|
READ_GUARD_MAX_UNCONSUMED_FILES = 4096;
|
|
57119
57412
|
READ_GUARD_IDLE_EVICT_MS_DEFAULT = 30 * 6e4;
|
|
@@ -57155,6 +57448,8 @@ var init_read_guard = __esm({
|
|
|
57155
57448
|
// happened to the file since. Pruned inside `evictFile` so it never
|
|
57156
57449
|
// outlives the record it points at.
|
|
57157
57450
|
knownPathIndex = /* @__PURE__ */ new Map();
|
|
57451
|
+
/** Running per-file record-cap trim totals for this session (#1913 F1). */
|
|
57452
|
+
trimAccumulators = /* @__PURE__ */ new Map();
|
|
57158
57453
|
sessionId;
|
|
57159
57454
|
sessionStartMs;
|
|
57160
57455
|
constructor(sessionId, config = {}) {
|
|
@@ -57247,7 +57542,7 @@ var init_read_guard = __esm({
|
|
|
57247
57542
|
arr.push(storedRecord);
|
|
57248
57543
|
this.reads.set(storedRecord.filePath, arr);
|
|
57249
57544
|
const rawReadCountForFile = arr.length;
|
|
57250
|
-
const evictedRecordCount = enforceRecordCapForFile(arr);
|
|
57545
|
+
const { evictedCount: evictedRecordCount, evictedCreditCount, evictedGenuineCount } = enforceRecordCapForFile(arr);
|
|
57251
57546
|
this.touchFile(storedRecord.filePath);
|
|
57252
57547
|
this.enforceFileCap();
|
|
57253
57548
|
logReadGuardEvent({
|
|
@@ -57282,6 +57577,39 @@ var init_read_guard = __esm({
|
|
|
57282
57577
|
}
|
|
57283
57578
|
}
|
|
57284
57579
|
});
|
|
57580
|
+
if (evictedRecordCount > 0) {
|
|
57581
|
+
const key2 = storedRecord.filePath;
|
|
57582
|
+
const acc = this.trimAccumulators.get(key2) ?? {
|
|
57583
|
+
totalEvicted: 0,
|
|
57584
|
+
evictedCreditCount: 0,
|
|
57585
|
+
evictedGenuineCount: 0,
|
|
57586
|
+
trimEventCount: 0
|
|
57587
|
+
};
|
|
57588
|
+
acc.totalEvicted += evictedRecordCount;
|
|
57589
|
+
acc.evictedCreditCount += evictedCreditCount;
|
|
57590
|
+
acc.evictedGenuineCount += evictedGenuineCount;
|
|
57591
|
+
acc.trimEventCount += 1;
|
|
57592
|
+
this.trimAccumulators.set(key2, acc);
|
|
57593
|
+
const isRisingEdge = incrementDegradationCount({
|
|
57594
|
+
kind: "read-guard-record-cap-trim",
|
|
57595
|
+
subject: key2,
|
|
57596
|
+
reason: `trim #${acc.trimEventCount}: evicted ${evictedRecordCount} (credit ${evictedCreditCount}, genuine ${evictedGenuineCount})`
|
|
57597
|
+
});
|
|
57598
|
+
if (isRisingEdge) {
|
|
57599
|
+
logReadGuardEvent({
|
|
57600
|
+
event: "read_cap_trimmed",
|
|
57601
|
+
sessionId: this.sessionId,
|
|
57602
|
+
filePath: storedRecord.filePath,
|
|
57603
|
+
metadata: {
|
|
57604
|
+
trimEventCount: acc.trimEventCount,
|
|
57605
|
+
evictedRecordCount: acc.totalEvicted,
|
|
57606
|
+
evictedCreditCount: acc.evictedCreditCount,
|
|
57607
|
+
evictedGenuineCount: acc.evictedGenuineCount,
|
|
57608
|
+
rawReadCountForFile
|
|
57609
|
+
}
|
|
57610
|
+
});
|
|
57611
|
+
}
|
|
57612
|
+
}
|
|
57285
57613
|
this.fileTime.read(storedRecord.filePath);
|
|
57286
57614
|
}
|
|
57287
57615
|
/**
|
|
@@ -57641,6 +57969,18 @@ Re-read the relevant section, then retry the edit using the current line range/c
|
|
|
57641
57969
|
this.touchFile(key2);
|
|
57642
57970
|
return this.reads.get(key2) ?? [];
|
|
57643
57971
|
}
|
|
57972
|
+
/**
|
|
57973
|
+
* Session-lifetime record-cap trim totals for a file (#1913 review F1).
|
|
57974
|
+
* `recordRead` only writes ONE `read_cap_trimmed` read-guard.log line per
|
|
57975
|
+
* file per session (on the first trim), so this is the running-totals
|
|
57976
|
+
* surface for everything after that — the exact split this class already
|
|
57977
|
+
* computes on every trim, not re-derivable from `getReadHistory` alone
|
|
57978
|
+
* (which only shows the SURVIVING records, not what was evicted).
|
|
57979
|
+
*/
|
|
57980
|
+
getTrimStats(filePath) {
|
|
57981
|
+
const stats = this.trimAccumulators.get(this.key(filePath));
|
|
57982
|
+
return stats ? { ...stats } : void 0;
|
|
57983
|
+
}
|
|
57644
57984
|
/**
|
|
57645
57985
|
* Snapshot the read-set for persistence across a session resume (#1041).
|
|
57646
57986
|
* Mirrors widget-state's `exportWidgetState`: the Map is emitted as
|
|
@@ -58437,11 +58777,11 @@ async function collectSourceFilesForWarmup(rootDir, maxFiles = MAX_WARMUP_SOURCE
|
|
|
58437
58777
|
}
|
|
58438
58778
|
stack.push(fullPath);
|
|
58439
58779
|
} else if (entry.isFile()) {
|
|
58440
|
-
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
58441
|
-
continue;
|
|
58442
58780
|
const ext2 = path90.extname(entry.name).toLowerCase();
|
|
58443
58781
|
if (!WARMUP_SOURCE_EXTS.has(ext2))
|
|
58444
58782
|
continue;
|
|
58783
|
+
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
58784
|
+
continue;
|
|
58445
58785
|
matchedSeen += 1;
|
|
58446
58786
|
const bucket = WARMUP_CODE_EXTS.has(ext2) ? codeOut : nonCodeOut;
|
|
58447
58787
|
if (bucket.length < maxFiles)
|
|
@@ -61302,6 +61642,11 @@ function recordOutstandingCascadeTouch(entry) {
|
|
|
61302
61642
|
});
|
|
61303
61643
|
}
|
|
61304
61644
|
}
|
|
61645
|
+
function resetCascadeTierSessionState() {
|
|
61646
|
+
_outstandingTouches.clear();
|
|
61647
|
+
_expiredSinceLastSweep = 0;
|
|
61648
|
+
_evictedSinceLastSweep = 0;
|
|
61649
|
+
}
|
|
61305
61650
|
async function reconcileOutstandingCascadeTouches(lspService) {
|
|
61306
61651
|
const outcomes = [];
|
|
61307
61652
|
pruneExpiredOutstandingTouches(Date.now());
|
|
@@ -62555,6 +62900,16 @@ var init_git_identity = __esm({
|
|
|
62555
62900
|
}
|
|
62556
62901
|
});
|
|
62557
62902
|
|
|
62903
|
+
// dist/clients/review-graph/revision-drift.js
|
|
62904
|
+
function formatReviewGraphRevisionDriftNote(drift) {
|
|
62905
|
+
return `Graph was built at commit ${drift.stampedHead.slice(0, 8)}; HEAD is now ${drift.currentHead.slice(0, 8)}. Results below reflect the earlier revision \u2014 run pilens_rebuild or re-analyze to refresh.`;
|
|
62906
|
+
}
|
|
62907
|
+
var init_revision_drift = __esm({
|
|
62908
|
+
"dist/clients/review-graph/revision-drift.js"() {
|
|
62909
|
+
"use strict";
|
|
62910
|
+
}
|
|
62911
|
+
});
|
|
62912
|
+
|
|
62558
62913
|
// dist/clients/review-graph/symbol-id.js
|
|
62559
62914
|
function buildSymbolId(filePath, name, kind, startLine) {
|
|
62560
62915
|
return `${filePath}:${name}:${kind}:${startLine}`;
|
|
@@ -63190,6 +63545,7 @@ __export(builder_exports, {
|
|
|
63190
63545
|
flushReviewGraphPersist: () => flushReviewGraphPersist,
|
|
63191
63546
|
flushReviewGraphPersistsForExitForTests: () => flushReviewGraphPersistsForExitForTests,
|
|
63192
63547
|
flushReviewGraphPersistsForTests: () => flushReviewGraphPersistsForTests,
|
|
63548
|
+
formatReviewGraphRevisionDriftNote: () => formatReviewGraphRevisionDriftNote,
|
|
63193
63549
|
getCachedReviewGraph: () => getCachedReviewGraph,
|
|
63194
63550
|
getCheckpointOffloadCountForTests: () => getCheckpointOffloadCountForTests,
|
|
63195
63551
|
getGraphBuildInfoForGraph: () => getGraphBuildInfoForGraph,
|
|
@@ -63199,10 +63555,12 @@ __export(builder_exports, {
|
|
|
63199
63555
|
getLastReviewGraphBuildAttempt: () => getLastReviewGraphBuildAttempt,
|
|
63200
63556
|
getReviewGraphCacheIdentity: () => getReviewGraphCacheIdentity,
|
|
63201
63557
|
getReviewGraphMaxFiles: () => getReviewGraphMaxFiles,
|
|
63558
|
+
getReviewGraphRevisionDrift: () => getReviewGraphRevisionDrift,
|
|
63202
63559
|
getReviewGraphSizeSkipVerdict: () => getReviewGraphSizeSkipVerdict,
|
|
63203
63560
|
getReviewGraphWorkerFallbackReasonForTests: () => getReviewGraphWorkerFallbackReasonForTests,
|
|
63204
63561
|
getReviewGraphWorkspaceCacheSnapshot: () => getReviewGraphWorkspaceCacheSnapshot,
|
|
63205
63562
|
graphBuildInfoIsTrustworthy: () => graphBuildInfoIsTrustworthy,
|
|
63563
|
+
isGraphBuildInFlight: () => isGraphBuildInFlight,
|
|
63206
63564
|
isReviewGraphMigrationNeeded: () => isReviewGraphMigrationNeeded,
|
|
63207
63565
|
resetReviewGraphPersistWorkerForTests: () => resetReviewGraphPersistWorkerForTests,
|
|
63208
63566
|
reviewGraphCachePath: () => reviewGraphCachePath,
|
|
@@ -63227,13 +63585,20 @@ function clearWorkspaceGraphTimer(entry) {
|
|
|
63227
63585
|
clearTimeout(entry.idleTimer);
|
|
63228
63586
|
entry.idleTimer = void 0;
|
|
63229
63587
|
}
|
|
63588
|
+
function buildCacheWorkspaceKey(cwd) {
|
|
63589
|
+
return normalizeMapKey(path104.resolve(cwd));
|
|
63590
|
+
}
|
|
63591
|
+
function buildCacheKeyWorkspace(buildKey) {
|
|
63592
|
+
const separator = buildKey.indexOf("|");
|
|
63593
|
+
return separator >= 0 ? buildKey.slice(0, separator) : void 0;
|
|
63594
|
+
}
|
|
63230
63595
|
function evictWorkspaceGraph(key2, entry) {
|
|
63231
63596
|
if (_workspaceGraphCache.get(key2) !== entry)
|
|
63232
63597
|
return;
|
|
63233
63598
|
clearWorkspaceGraphTimer(entry);
|
|
63599
|
+
const buildWorkspace = buildCacheWorkspaceKey(key2);
|
|
63234
63600
|
for (const buildKey of _buildCache.keys()) {
|
|
63235
|
-
|
|
63236
|
-
if (separator >= 0 && normalizeMapKey(buildKey.slice(0, separator)) === key2) {
|
|
63601
|
+
if (buildCacheKeyWorkspace(buildKey) === buildWorkspace) {
|
|
63237
63602
|
_buildCache.delete(buildKey);
|
|
63238
63603
|
}
|
|
63239
63604
|
}
|
|
@@ -63308,8 +63673,9 @@ function clearReviewGraphWorkspaceCache(cwd) {
|
|
|
63308
63673
|
_sizeSkipVerdicts.clear();
|
|
63309
63674
|
} else {
|
|
63310
63675
|
const normalized = normalizeMapKey(cwd);
|
|
63676
|
+
const buildWorkspace = buildCacheWorkspaceKey(cwd);
|
|
63311
63677
|
for (const key2 of _buildCache.keys()) {
|
|
63312
|
-
if (
|
|
63678
|
+
if (buildCacheKeyWorkspace(key2) === buildWorkspace) {
|
|
63313
63679
|
_buildCache.delete(key2);
|
|
63314
63680
|
}
|
|
63315
63681
|
}
|
|
@@ -63415,7 +63781,7 @@ function getCachedReviewGraph(cwd) {
|
|
|
63415
63781
|
return cached.graph;
|
|
63416
63782
|
}
|
|
63417
63783
|
const disk = loadPersistedGraph(cwd, {
|
|
63418
|
-
|
|
63784
|
+
verifyWorktreeIdentity: true,
|
|
63419
63785
|
allowPartial: true
|
|
63420
63786
|
});
|
|
63421
63787
|
if (!disk)
|
|
@@ -63424,10 +63790,23 @@ function getCachedReviewGraph(cwd) {
|
|
|
63424
63790
|
signature: disk.signature,
|
|
63425
63791
|
fileSignatures: disk.fileSignatures,
|
|
63426
63792
|
fileHashes: disk.fileHashes,
|
|
63427
|
-
graph: disk.graph
|
|
63793
|
+
graph: disk.graph,
|
|
63794
|
+
// Durable half of the drift fact. The current-HEAD half is never cached
|
|
63795
|
+
// beside it — see getReviewGraphRevisionDrift (#1961 review F3).
|
|
63796
|
+
...disk.stampedHead ? { snapshotStampedHead: disk.stampedHead } : {}
|
|
63428
63797
|
});
|
|
63429
63798
|
return disk.graph;
|
|
63430
63799
|
}
|
|
63800
|
+
function getReviewGraphRevisionDrift(cwd) {
|
|
63801
|
+
const entry = _workspaceGraphCache.get(normalizeMapKey(cwd));
|
|
63802
|
+
const stampedHead = entry?.snapshotStampedHead;
|
|
63803
|
+
if (!stampedHead)
|
|
63804
|
+
return void 0;
|
|
63805
|
+
const current = resolveGitIdentity(cwd);
|
|
63806
|
+
if (!current || current.headCommit === stampedHead)
|
|
63807
|
+
return void 0;
|
|
63808
|
+
return { stampedHead, currentHead: current.headCommit };
|
|
63809
|
+
}
|
|
63431
63810
|
function makeCtx(filePath, cwd, facts) {
|
|
63432
63811
|
return {
|
|
63433
63812
|
filePath,
|
|
@@ -63724,6 +64103,19 @@ function rebuildIndexes(graph) {
|
|
|
63724
64103
|
graph.edgesByTo.set(edge.to, to);
|
|
63725
64104
|
}
|
|
63726
64105
|
}
|
|
64106
|
+
function logSnapshotReadVerdict(cwd, phase, reason) {
|
|
64107
|
+
const verdict = phase === "snapshot_read_dropped" ? "dropped" : "drifted";
|
|
64108
|
+
const isRisingEdge = incrementDegradationCount({
|
|
64109
|
+
kind: "review-graph-snapshot-read",
|
|
64110
|
+
// Subject keeps BOTH discriminators, so aggregation still answers which
|
|
64111
|
+
// workspace and which verdict after the detailed records stop.
|
|
64112
|
+
subject: `${verdict}:${normalizeMapKey(cwd)}`,
|
|
64113
|
+
reason
|
|
64114
|
+
});
|
|
64115
|
+
if (!isRisingEdge)
|
|
64116
|
+
return;
|
|
64117
|
+
logReviewGraph({ cwd, phase, reason });
|
|
64118
|
+
}
|
|
63727
64119
|
function loadPersistedGraph(cwd, opts) {
|
|
63728
64120
|
const cacheDir = path104.join(getProjectDataDir(cwd), "cache");
|
|
63729
64121
|
const cachePath3 = path104.join(cacheDir, GRAPH_CACHE_FILENAME);
|
|
@@ -63735,11 +64127,17 @@ function loadPersistedGraph(cwd, opts) {
|
|
|
63735
64127
|
return null;
|
|
63736
64128
|
if (data.coverage?.partial && !opts?.allowPartial)
|
|
63737
64129
|
return null;
|
|
63738
|
-
|
|
64130
|
+
let stampedHead;
|
|
64131
|
+
if (opts?.verifyWorktreeIdentity && data.gitStamp) {
|
|
63739
64132
|
const current = resolveGitIdentity(cwd);
|
|
63740
|
-
if (current &&
|
|
64133
|
+
if (current && current.worktreeRoot !== data.gitStamp.worktreeRoot) {
|
|
64134
|
+
logSnapshotReadVerdict(cwd, "snapshot_read_dropped", "worktree_mismatch");
|
|
63741
64135
|
return null;
|
|
63742
64136
|
}
|
|
64137
|
+
if (current && current.headCommit !== data.gitStamp.headCommit) {
|
|
64138
|
+
stampedHead = data.gitStamp.headCommit;
|
|
64139
|
+
logSnapshotReadVerdict(cwd, "snapshot_read_drifted", "head_moved");
|
|
64140
|
+
}
|
|
63743
64141
|
}
|
|
63744
64142
|
const graph = {
|
|
63745
64143
|
version: data.version,
|
|
@@ -63758,7 +64156,8 @@ function loadPersistedGraph(cwd, opts) {
|
|
|
63758
64156
|
signature: data.signature,
|
|
63759
64157
|
fileSignatures: new Map(data.fileSignatures ?? []),
|
|
63760
64158
|
fileHashes: new Map(data.fileHashes ?? []),
|
|
63761
|
-
graph
|
|
64159
|
+
graph,
|
|
64160
|
+
...stampedHead ? { stampedHead } : {}
|
|
63762
64161
|
};
|
|
63763
64162
|
} catch {
|
|
63764
64163
|
return null;
|
|
@@ -64543,11 +64942,11 @@ function loadReviewGraphCheckpoint(cwd) {
|
|
|
64543
64942
|
}
|
|
64544
64943
|
if (data.gitStamp) {
|
|
64545
64944
|
const current = resolveGitIdentity(cwd);
|
|
64546
|
-
if (current &&
|
|
64945
|
+
if (current && current.worktreeRoot !== data.gitStamp.worktreeRoot) {
|
|
64547
64946
|
logReviewGraph({
|
|
64548
64947
|
cwd,
|
|
64549
64948
|
phase: "checkpoint_discarded",
|
|
64550
|
-
reason: "
|
|
64949
|
+
reason: "worktree_mismatch"
|
|
64551
64950
|
});
|
|
64552
64951
|
deleteReviewGraphCheckpoint(cwd);
|
|
64553
64952
|
return null;
|
|
@@ -66038,6 +66437,7 @@ async function _doBuildGraph(cwd, changedFiles, facts, seqHint, buildId) {
|
|
|
66038
66437
|
const graph = resumed?.graph ?? createEmptyGraph();
|
|
66039
66438
|
const filesToExtract = resumed?.remaining ?? filesToBuild;
|
|
66040
66439
|
const treeSitterClient = getSharedTreeSitterClient();
|
|
66440
|
+
treeSitterClient?.ensureTreeCacheCapacity(filesToExtract.length);
|
|
66041
66441
|
const extractionStartedAt = Date.now();
|
|
66042
66442
|
const fileHashes = resumed?.fileHashes ?? /* @__PURE__ */ new Map();
|
|
66043
66443
|
const checkpointEvery = graphCheckpointEveryFiles();
|
|
@@ -66145,8 +66545,14 @@ async function _doBuildGraph(cwd, changedFiles, facts, seqHint, buildId) {
|
|
|
66145
66545
|
facts.setSessionFact("session.reviewGraph", graph);
|
|
66146
66546
|
return graph;
|
|
66147
66547
|
}
|
|
66548
|
+
function buildCacheKey(cwd, changedFiles) {
|
|
66549
|
+
return `${buildCacheWorkspaceKey(cwd)}|${[...changedFiles].sort((a, b) => a.localeCompare(b)).join(",")}`;
|
|
66550
|
+
}
|
|
66551
|
+
function isGraphBuildInFlight(cwd, changedFiles = []) {
|
|
66552
|
+
return _buildCache.has(buildCacheKey(cwd, changedFiles));
|
|
66553
|
+
}
|
|
66148
66554
|
function buildOrUpdateGraph(cwd, changedFiles, facts, seqHint) {
|
|
66149
|
-
const cacheKey =
|
|
66555
|
+
const cacheKey = buildCacheKey(cwd, changedFiles);
|
|
66150
66556
|
const cached = _buildCache.get(cacheKey);
|
|
66151
66557
|
if (cached)
|
|
66152
66558
|
return cached;
|
|
@@ -66212,7 +66618,6 @@ function buildOrUpdateGraph(cwd, changedFiles, facts, seqHint) {
|
|
|
66212
66618
|
}
|
|
66213
66619
|
return graph;
|
|
66214
66620
|
}).catch((err) => {
|
|
66215
|
-
_buildCache.delete(cacheKey);
|
|
66216
66621
|
const reason = err instanceof Error ? err.message : String(err);
|
|
66217
66622
|
recordBuildAttempt(cwd, "failed", reason, buildId);
|
|
66218
66623
|
logReviewGraph({
|
|
@@ -66233,6 +66638,11 @@ function buildOrUpdateGraph(cwd, changedFiles, facts, seqHint) {
|
|
|
66233
66638
|
throw err;
|
|
66234
66639
|
});
|
|
66235
66640
|
_buildCache.set(cacheKey, promise);
|
|
66641
|
+
const release = () => {
|
|
66642
|
+
if (_buildCache.get(cacheKey) === promise)
|
|
66643
|
+
_buildCache.delete(cacheKey);
|
|
66644
|
+
};
|
|
66645
|
+
promise.then(release, release);
|
|
66236
66646
|
return promise;
|
|
66237
66647
|
}
|
|
66238
66648
|
function extractSymbolsAndRefsFromGraph(graph) {
|
|
@@ -66389,7 +66799,9 @@ var init_builder = __esm({
|
|
|
66389
66799
|
init_tree_sitter_shared();
|
|
66390
66800
|
init_tree_sitter_symbol_extractor();
|
|
66391
66801
|
init_tree_sitter_shared();
|
|
66802
|
+
init_degradation_ledger();
|
|
66392
66803
|
init_git_identity();
|
|
66804
|
+
init_revision_drift();
|
|
66393
66805
|
init_symbol_id();
|
|
66394
66806
|
init_shared_extraction_ir();
|
|
66395
66807
|
REVIEW_GRAPH_VERSION = "v8";
|
|
@@ -68003,7 +68415,7 @@ var init_detekt = __esm({
|
|
|
68003
68415
|
init_tool_policy();
|
|
68004
68416
|
init_priorities();
|
|
68005
68417
|
init_runner_helpers();
|
|
68006
|
-
|
|
68418
|
+
init_tool_failure();
|
|
68007
68419
|
detekt = createAvailabilityChecker("detekt", ".bat");
|
|
68008
68420
|
DETEKT_CONFIG_CANDIDATES = [
|
|
68009
68421
|
"detekt.yml",
|
|
@@ -68096,10 +68508,10 @@ var init_detekt = __esm({
|
|
|
68096
68508
|
const absPath = path112.resolve(cwd, ctx.filePath);
|
|
68097
68509
|
const result = await safeSpawnAsync(cmd, ["--input", absPath, "--config", configPath], { cwd, timeout: 6e4 });
|
|
68098
68510
|
const raw = `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
|
68099
|
-
|
|
68100
|
-
|
|
68101
|
-
|
|
68102
|
-
const diagnostics =
|
|
68511
|
+
const run = parseToolRun("detekt", { result, output: raw }, (out) => parseDetektOutput(out, ctx.filePath));
|
|
68512
|
+
if (run.skipped)
|
|
68513
|
+
return run.skipped;
|
|
68514
|
+
const diagnostics = run.diagnostics;
|
|
68103
68515
|
if (diagnostics.length === 0) {
|
|
68104
68516
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
68105
68517
|
}
|
|
@@ -68998,7 +69410,7 @@ var init_hadolint = __esm({
|
|
|
68998
69410
|
init_tool_policy();
|
|
68999
69411
|
init_priorities();
|
|
69000
69412
|
init_runner_helpers();
|
|
69001
|
-
|
|
69413
|
+
init_tool_failure();
|
|
69002
69414
|
hadolint = createAvailabilityChecker("hadolint", ".exe");
|
|
69003
69415
|
hadolintRunner = {
|
|
69004
69416
|
id: "hadolint",
|
|
@@ -69022,11 +69434,10 @@ var init_hadolint = __esm({
|
|
|
69022
69434
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
69023
69435
|
}
|
|
69024
69436
|
const result = await safeSpawnAsync(cmd, ["--format", "json", "--no-fail", path116.resolve(cwd, ctx.filePath)], { cwd });
|
|
69025
|
-
|
|
69026
|
-
|
|
69027
|
-
|
|
69028
|
-
const
|
|
69029
|
-
const diagnostics = parseHadolintOutput(output, ctx.filePath);
|
|
69437
|
+
const run = parseToolRun("hadolint", { result }, (out) => parseHadolintOutput(out, ctx.filePath));
|
|
69438
|
+
if (run.skipped)
|
|
69439
|
+
return run.skipped;
|
|
69440
|
+
const diagnostics = run.diagnostics;
|
|
69030
69441
|
if (diagnostics.length === 0) {
|
|
69031
69442
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
69032
69443
|
}
|
|
@@ -69825,7 +70236,7 @@ var init_htmlhint = __esm({
|
|
|
69825
70236
|
init_tool_policy();
|
|
69826
70237
|
init_priorities();
|
|
69827
70238
|
init_runner_helpers();
|
|
69828
|
-
|
|
70239
|
+
init_tool_failure();
|
|
69829
70240
|
htmlhint = createAvailabilityChecker("htmlhint");
|
|
69830
70241
|
HTMLHINT_RULES = {
|
|
69831
70242
|
"tag-pair": true,
|
|
@@ -69865,10 +70276,10 @@ var init_htmlhint = __esm({
|
|
|
69865
70276
|
path119.resolve(cwd, ctx.filePath)
|
|
69866
70277
|
], { cwd });
|
|
69867
70278
|
const output = result.stdout || result.stderr || "";
|
|
69868
|
-
|
|
69869
|
-
|
|
69870
|
-
|
|
69871
|
-
const diagnostics =
|
|
70279
|
+
const run = parseToolRun("htmlhint", { result, output }, (out) => parseHtmlhintOutput(out, ctx.filePath));
|
|
70280
|
+
if (run.skipped)
|
|
70281
|
+
return run.skipped;
|
|
70282
|
+
const diagnostics = run.diagnostics;
|
|
69872
70283
|
if (diagnostics.length === 0) {
|
|
69873
70284
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
69874
70285
|
}
|
|
@@ -70558,14 +70969,10 @@ var init_markdownlint = __esm({
|
|
|
70558
70969
|
cwd
|
|
70559
70970
|
});
|
|
70560
70971
|
const raw = `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
|
70561
|
-
const
|
|
70562
|
-
|
|
70563
|
-
|
|
70564
|
-
|
|
70565
|
-
});
|
|
70566
|
-
if (skipped)
|
|
70567
|
-
return skipped;
|
|
70568
|
-
const diagnostics = parseMarkdownlintOutput(raw, ctx.filePath);
|
|
70972
|
+
const run = parseToolRun("markdownlint", { result, output: raw, exitCodes: MARKDOWNLINT_EXIT_CODES }, (out) => parseMarkdownlintOutput(out, ctx.filePath));
|
|
70973
|
+
if (run.skipped)
|
|
70974
|
+
return run.skipped;
|
|
70975
|
+
const diagnostics = run.diagnostics;
|
|
70569
70976
|
if (diagnostics.length === 0) {
|
|
70570
70977
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
70571
70978
|
}
|
|
@@ -70637,14 +71044,10 @@ var init_mypy = __esm({
|
|
|
70637
71044
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
70638
71045
|
const result = await safeSpawnAsync(cmd, ["--no-error-summary", "--show-column-numbers", ctx.filePath], { timeout: 3e4, cwd });
|
|
70639
71046
|
const raw = `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
|
70640
|
-
const
|
|
70641
|
-
|
|
70642
|
-
|
|
70643
|
-
|
|
70644
|
-
});
|
|
70645
|
-
if (skipped)
|
|
70646
|
-
return skipped;
|
|
70647
|
-
const diagnostics = parseMypyOutput(raw, ctx.filePath, cwd);
|
|
71047
|
+
const run = parseToolRun("mypy", { result, output: result.stdout, exitCodes: MYPY_EXIT_CODES }, (out) => parseMypyOutput(out, ctx.filePath, cwd), { parseOutput: raw });
|
|
71048
|
+
if (run.skipped)
|
|
71049
|
+
return run.skipped;
|
|
71050
|
+
const diagnostics = run.diagnostics;
|
|
70648
71051
|
if (diagnostics.length === 0) {
|
|
70649
71052
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
70650
71053
|
}
|
|
@@ -70794,9 +71197,6 @@ var init_oxlint = __esm({
|
|
|
70794
71197
|
const result = await safeSpawnAsync(cmd, args, {
|
|
70795
71198
|
timeout: 3e4
|
|
70796
71199
|
});
|
|
70797
|
-
if (result.status === 0) {
|
|
70798
|
-
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
70799
|
-
}
|
|
70800
71200
|
const stdout = result.stdout ?? "";
|
|
70801
71201
|
const stderr = result.stderr ?? "";
|
|
70802
71202
|
let diagnostics = parseOxlintJson(stdout, ctx.filePath);
|
|
@@ -70808,7 +71208,7 @@ var init_oxlint = __esm({
|
|
|
70808
71208
|
}
|
|
70809
71209
|
const hasBlocking = diagnostics.some((d) => d.semantic === "blocking");
|
|
70810
71210
|
return {
|
|
70811
|
-
status: "failed",
|
|
71211
|
+
status: !hasBlocking && result.status === 0 ? "succeeded" : "failed",
|
|
70812
71212
|
diagnostics,
|
|
70813
71213
|
semantic: hasBlocking ? "blocking" : "warning"
|
|
70814
71214
|
};
|
|
@@ -70896,7 +71296,7 @@ function parsePhpstanJson(raw, fallbackPath, cwd) {
|
|
|
70896
71296
|
const diagnostics = [];
|
|
70897
71297
|
for (const [file, fileErrors] of Object.entries(output.files ?? {})) {
|
|
70898
71298
|
const filePath = file && file.trim() ? path126.isAbsolute(file) ? file : path126.resolve(cwd, file) : fallbackPath;
|
|
70899
|
-
for (const err of fileErrors
|
|
71299
|
+
for (const err of fileErrors?.messages ?? []) {
|
|
70900
71300
|
diagnostics.push({
|
|
70901
71301
|
id: `phpstan:${err.line ?? 1}:${err.message.slice(0, 40)}`,
|
|
70902
71302
|
message: err.message,
|
|
@@ -70906,11 +71306,27 @@ function parsePhpstanJson(raw, fallbackPath, cwd) {
|
|
|
70906
71306
|
severity: "error",
|
|
70907
71307
|
semantic: "blocking",
|
|
70908
71308
|
tool: "phpstan",
|
|
70909
|
-
rule: "phpstan",
|
|
71309
|
+
rule: err.identifier || "phpstan",
|
|
70910
71310
|
fixable: false
|
|
70911
71311
|
});
|
|
70912
71312
|
}
|
|
70913
71313
|
}
|
|
71314
|
+
for (const message of output.errors ?? []) {
|
|
71315
|
+
if (typeof message !== "string" || !message.trim())
|
|
71316
|
+
continue;
|
|
71317
|
+
diagnostics.push({
|
|
71318
|
+
id: `phpstan:global:${message.slice(0, 40)}`,
|
|
71319
|
+
message,
|
|
71320
|
+
filePath: fallbackPath,
|
|
71321
|
+
line: 1,
|
|
71322
|
+
column: 1,
|
|
71323
|
+
severity: "error",
|
|
71324
|
+
semantic: "blocking",
|
|
71325
|
+
tool: "phpstan",
|
|
71326
|
+
rule: "phpstan/analysis",
|
|
71327
|
+
fixable: false
|
|
71328
|
+
});
|
|
71329
|
+
}
|
|
70914
71330
|
return diagnostics;
|
|
70915
71331
|
} catch {
|
|
70916
71332
|
return [];
|
|
@@ -70921,7 +71337,7 @@ async function resolvePhpstan(cwd) {
|
|
|
70921
71337
|
return phpstan.getCommand(cwd);
|
|
70922
71338
|
return resolveVendorToolCommand(cwd, "phpstan", ".bat");
|
|
70923
71339
|
}
|
|
70924
|
-
var phpstan, phpstanRunner, phpstan_default;
|
|
71340
|
+
var PHPSTAN_EXIT_CODES, phpstan, phpstanRunner, phpstan_default;
|
|
70925
71341
|
var init_phpstan = __esm({
|
|
70926
71342
|
"dist/clients/dispatch/runners/phpstan.js"() {
|
|
70927
71343
|
"use strict";
|
|
@@ -70929,6 +71345,8 @@ var init_phpstan = __esm({
|
|
|
70929
71345
|
init_tool_policy();
|
|
70930
71346
|
init_priorities();
|
|
70931
71347
|
init_runner_helpers();
|
|
71348
|
+
init_tool_failure();
|
|
71349
|
+
PHPSTAN_EXIT_CODES = { ran: [1] };
|
|
70932
71350
|
phpstan = createAvailabilityChecker("phpstan", ".phar");
|
|
70933
71351
|
phpstanRunner = {
|
|
70934
71352
|
id: "phpstan",
|
|
@@ -70950,13 +71368,10 @@ var init_phpstan = __esm({
|
|
|
70950
71368
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
70951
71369
|
const absPath = path126.resolve(cwd, ctx.filePath);
|
|
70952
71370
|
const result = await safeSpawnAsync(cmd, ["analyse", "--error-format=json", "--no-progress", absPath], { timeout: 3e4, cwd });
|
|
70953
|
-
|
|
70954
|
-
|
|
70955
|
-
|
|
70956
|
-
|
|
70957
|
-
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
70958
|
-
}
|
|
70959
|
-
const diagnostics = parsePhpstanJson(result.stdout ?? "", ctx.filePath, cwd);
|
|
71371
|
+
const run = parseToolRun("phpstan", { result, exitCodes: PHPSTAN_EXIT_CODES }, (out) => parsePhpstanJson(out, ctx.filePath, cwd), { parseOutput: result.stdout ?? "" });
|
|
71372
|
+
if (run.skipped)
|
|
71373
|
+
return run.skipped;
|
|
71374
|
+
const diagnostics = run.diagnostics;
|
|
70960
71375
|
if (diagnostics.length === 0) {
|
|
70961
71376
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
70962
71377
|
}
|
|
@@ -72470,10 +72885,10 @@ var typos, TYPOS_EXIT_CODES, spellcheckRunner, spellcheck_default;
|
|
|
72470
72885
|
var init_spellcheck = __esm({
|
|
72471
72886
|
"dist/clients/dispatch/runners/spellcheck.js"() {
|
|
72472
72887
|
"use strict";
|
|
72473
|
-
init_tool_failure();
|
|
72474
72888
|
init_safe_spawn();
|
|
72475
72889
|
init_priorities();
|
|
72476
72890
|
init_runner_helpers();
|
|
72891
|
+
init_tool_failure();
|
|
72477
72892
|
typos = createAvailabilityChecker("typos", ".exe");
|
|
72478
72893
|
TYPOS_EXIT_CODES = { ran: [2] };
|
|
72479
72894
|
spellcheckRunner = {
|
|
@@ -72491,18 +72906,10 @@ var init_spellcheck = __esm({
|
|
|
72491
72906
|
const result = await safeSpawnAsync(typos.getCommand(ctx.cwd || process.cwd()), args, {
|
|
72492
72907
|
timeout: 15e3
|
|
72493
72908
|
});
|
|
72494
|
-
const
|
|
72495
|
-
|
|
72496
|
-
|
|
72497
|
-
|
|
72498
|
-
if (skipped)
|
|
72499
|
-
return skipped;
|
|
72500
|
-
const hasTypos = result.status === 2 || result.stdout?.trim();
|
|
72501
|
-
if (!hasTypos) {
|
|
72502
|
-
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
72503
|
-
}
|
|
72504
|
-
const raw = result.stdout + result.stderr;
|
|
72505
|
-
const diagnostics = parseTyposOutput(raw, ctx.filePath);
|
|
72909
|
+
const run = parseToolRun("spellcheck", { result, exitCodes: TYPOS_EXIT_CODES }, (out) => parseTyposOutput(out, ctx.filePath), { parseOutput: `${result.stdout ?? ""}${result.stderr ?? ""}` });
|
|
72910
|
+
if (run.skipped)
|
|
72911
|
+
return run.skipped;
|
|
72912
|
+
const diagnostics = run.diagnostics;
|
|
72506
72913
|
if (diagnostics.length === 0) {
|
|
72507
72914
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
72508
72915
|
}
|
|
@@ -72631,21 +73038,19 @@ var init_sqlfluff = __esm({
|
|
|
72631
73038
|
}
|
|
72632
73039
|
if (!cmd)
|
|
72633
73040
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
72634
|
-
const args = ["lint", "--format", "json"
|
|
73041
|
+
const args = ["lint", "--format", "json"];
|
|
72635
73042
|
if (!hasConfig) {
|
|
72636
|
-
args.
|
|
73043
|
+
args.push("--dialect", "ansi");
|
|
72637
73044
|
}
|
|
73045
|
+
args.push(ctx.filePath);
|
|
72638
73046
|
const result = await safeSpawnAsync(cmd, args, {
|
|
72639
73047
|
timeout: 2e4,
|
|
72640
73048
|
cwd
|
|
72641
73049
|
});
|
|
72642
|
-
const
|
|
72643
|
-
|
|
72644
|
-
|
|
72645
|
-
|
|
72646
|
-
if (skipped)
|
|
72647
|
-
return skipped;
|
|
72648
|
-
const diagnostics = parseSqlfluffOutput(result.stdout ?? "", ctx.filePath);
|
|
73050
|
+
const run = parseToolRun("sqlfluff", { result, exitCodes: SQLFLUFF_EXIT_CODES }, (out) => parseSqlfluffOutput(out, ctx.filePath), { parseOutput: result.stdout ?? "" });
|
|
73051
|
+
if (run.skipped)
|
|
73052
|
+
return run.skipped;
|
|
73053
|
+
const diagnostics = run.diagnostics;
|
|
72649
73054
|
if (diagnostics.length === 0) {
|
|
72650
73055
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
72651
73056
|
}
|
|
@@ -72662,6 +73067,13 @@ var init_sqlfluff = __esm({
|
|
|
72662
73067
|
|
|
72663
73068
|
// dist/clients/dispatch/runners/stylelint.js
|
|
72664
73069
|
import * as path132 from "node:path";
|
|
73070
|
+
function stylelintReport(stdout, stderr) {
|
|
73071
|
+
for (const stream of [stdout, stderr]) {
|
|
73072
|
+
if (stream?.trimStart().startsWith("["))
|
|
73073
|
+
return stream;
|
|
73074
|
+
}
|
|
73075
|
+
return "";
|
|
73076
|
+
}
|
|
72665
73077
|
function parseStylelintJson(raw, filePath) {
|
|
72666
73078
|
try {
|
|
72667
73079
|
const results = JSON.parse(raw);
|
|
@@ -72758,14 +73170,11 @@ var init_stylelint = __esm({
|
|
|
72758
73170
|
if (!cmd)
|
|
72759
73171
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
72760
73172
|
const result = await safeSpawnAsync(cmd, ["--formatter", "json", ctx.filePath], { timeout: 2e4, cwd });
|
|
72761
|
-
const
|
|
72762
|
-
|
|
72763
|
-
|
|
72764
|
-
|
|
72765
|
-
|
|
72766
|
-
return skipped;
|
|
72767
|
-
const raw = result.stdout ?? "";
|
|
72768
|
-
const diagnostics = parseStylelintJson(raw, ctx.filePath);
|
|
73173
|
+
const raw = stylelintReport(result.stdout, result.stderr);
|
|
73174
|
+
const run = parseToolRun("stylelint", { result, output: raw, exitCodes: STYLELINT_EXIT_CODES }, (out) => parseStylelintJson(out, ctx.filePath));
|
|
73175
|
+
if (run.skipped)
|
|
73176
|
+
return run.skipped;
|
|
73177
|
+
const diagnostics = run.diagnostics;
|
|
72769
73178
|
if (diagnostics.length === 0) {
|
|
72770
73179
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
72771
73180
|
}
|
|
@@ -72905,11 +73314,10 @@ var init_swiftlint = __esm({
|
|
|
72905
73314
|
if (!cmd)
|
|
72906
73315
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
72907
73316
|
const result = await safeSpawnAsync(cmd, ["--reporter", "json", path133.resolve(cwd, ctx.filePath)], { cwd, timeout: 15e3 });
|
|
72908
|
-
const
|
|
72909
|
-
if (skipped)
|
|
72910
|
-
return skipped;
|
|
72911
|
-
const
|
|
72912
|
-
const diagnostics = parseSwiftLintOutput(raw, ctx.filePath);
|
|
73317
|
+
const run = parseToolRun("swiftlint", { result }, (out) => parseSwiftLintOutput(out, ctx.filePath));
|
|
73318
|
+
if (run.skipped)
|
|
73319
|
+
return run.skipped;
|
|
73320
|
+
const diagnostics = run.diagnostics;
|
|
72913
73321
|
if (diagnostics.length === 0) {
|
|
72914
73322
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
72915
73323
|
}
|
|
@@ -72928,26 +73336,47 @@ var init_swiftlint = __esm({
|
|
|
72928
73336
|
// dist/clients/dispatch/runners/taplo.js
|
|
72929
73337
|
import * as path134 from "node:path";
|
|
72930
73338
|
function parseTaploOutput(raw, filePath) {
|
|
72931
|
-
|
|
72932
|
-
|
|
72933
|
-
|
|
72934
|
-
|
|
72935
|
-
|
|
72936
|
-
|
|
73339
|
+
const diagnostics = [];
|
|
73340
|
+
const lines = (raw ?? "").split(/\r?\n/);
|
|
73341
|
+
for (let i = 0; i < lines.length; i++) {
|
|
73342
|
+
const header = HEADER_PATTERN.exec(lines[i].trimEnd());
|
|
73343
|
+
if (!header)
|
|
73344
|
+
continue;
|
|
73345
|
+
const severityWord = header[1];
|
|
73346
|
+
const summary = header[2].trim();
|
|
73347
|
+
if (!summary)
|
|
73348
|
+
continue;
|
|
73349
|
+
let line = null;
|
|
73350
|
+
let column = 1;
|
|
73351
|
+
for (let j = i + 1; j < Math.min(i + 4, lines.length); j++) {
|
|
73352
|
+
if (!lines[j].includes(LOCATION_LEAD))
|
|
73353
|
+
continue;
|
|
73354
|
+
const location = LOCATION_PATTERN.exec(lines[j].trimEnd());
|
|
73355
|
+
if (!location)
|
|
73356
|
+
continue;
|
|
73357
|
+
line = Number.parseInt(location[1], 10) || 1;
|
|
73358
|
+
column = Number.parseInt(location[2], 10) || 1;
|
|
73359
|
+
break;
|
|
73360
|
+
}
|
|
73361
|
+
if (line === null)
|
|
73362
|
+
continue;
|
|
73363
|
+
const severity = severityWord === "warning" ? "warning" : "error";
|
|
73364
|
+
diagnostics.push({
|
|
73365
|
+
id: `taplo-${severity}-${line}-${column}`,
|
|
73366
|
+
message: summary,
|
|
72937
73367
|
filePath,
|
|
72938
|
-
line
|
|
72939
|
-
column
|
|
72940
|
-
severity
|
|
72941
|
-
semantic: "blocking",
|
|
73368
|
+
line,
|
|
73369
|
+
column,
|
|
73370
|
+
severity,
|
|
73371
|
+
semantic: severity === "error" ? "blocking" : "warning",
|
|
72942
73372
|
tool: "taplo",
|
|
72943
|
-
rule:
|
|
73373
|
+
rule: `taplo/${severity}`,
|
|
72944
73374
|
fixable: false
|
|
72945
|
-
})
|
|
72946
|
-
} catch {
|
|
72947
|
-
return [];
|
|
73375
|
+
});
|
|
72948
73376
|
}
|
|
73377
|
+
return diagnostics;
|
|
72949
73378
|
}
|
|
72950
|
-
var taplo, taploRunner, taplo_default;
|
|
73379
|
+
var taplo, TAPLO_EXIT_CODES, HEADER_PATTERN, LOCATION_LEAD, LOCATION_PATTERN, taploRunner, taplo_default;
|
|
72951
73380
|
var init_taplo = __esm({
|
|
72952
73381
|
"dist/clients/dispatch/runners/taplo.js"() {
|
|
72953
73382
|
"use strict";
|
|
@@ -72956,8 +73385,12 @@ var init_taplo = __esm({
|
|
|
72956
73385
|
init_tool_policy();
|
|
72957
73386
|
init_priorities();
|
|
72958
73387
|
init_runner_helpers();
|
|
72959
|
-
|
|
73388
|
+
init_tool_failure();
|
|
72960
73389
|
taplo = createAvailabilityChecker("taplo", ".exe");
|
|
73390
|
+
TAPLO_EXIT_CODES = { ran: [1] };
|
|
73391
|
+
HEADER_PATTERN = /^\s*(error|warning):(.*)$/;
|
|
73392
|
+
LOCATION_LEAD = "\u250C\u2500";
|
|
73393
|
+
LOCATION_PATTERN = /:(\d+):(\d+)$/;
|
|
72961
73394
|
taploRunner = {
|
|
72962
73395
|
id: "taplo",
|
|
72963
73396
|
appliesTo: ["toml"],
|
|
@@ -72984,11 +73417,12 @@ var init_taplo = __esm({
|
|
|
72984
73417
|
if (!cmd)
|
|
72985
73418
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
72986
73419
|
const absPath = path134.resolve(cwd, ctx.filePath);
|
|
72987
|
-
const result = await safeSpawnAsync(cmd, ["check", "--
|
|
72988
|
-
|
|
72989
|
-
|
|
72990
|
-
|
|
72991
|
-
|
|
73420
|
+
const result = await safeSpawnAsync(cmd, ["check", "--colors", "never", absPath], { cwd, timeout: 15e3 });
|
|
73421
|
+
const raw = result.stderr?.trim() ? result.stderr : result.stdout ?? "";
|
|
73422
|
+
const run = parseToolRun("taplo", { result, output: raw, exitCodes: TAPLO_EXIT_CODES }, (out) => parseTaploOutput(out, ctx.filePath), { skipWhenParsedNothing: true });
|
|
73423
|
+
if (run.skipped)
|
|
73424
|
+
return run.skipped;
|
|
73425
|
+
const diagnostics = run.diagnostics;
|
|
72992
73426
|
if (diagnostics.length === 0) {
|
|
72993
73427
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
72994
73428
|
}
|
|
@@ -73150,9 +73584,9 @@ var init_tflint = __esm({
|
|
|
73150
73584
|
init_safe_spawn();
|
|
73151
73585
|
init_tool_policy();
|
|
73152
73586
|
init_workspace_topology();
|
|
73153
|
-
init_runner_helpers();
|
|
73154
|
-
init_spawn_outcome();
|
|
73155
73587
|
init_priorities();
|
|
73588
|
+
init_runner_helpers();
|
|
73589
|
+
init_tool_failure();
|
|
73156
73590
|
tflint = createAvailabilityChecker("tflint", ".exe");
|
|
73157
73591
|
TFLINT_CONFIG = ".tflint.hcl";
|
|
73158
73592
|
tflintRunner = {
|
|
@@ -73191,10 +73625,10 @@ var init_tflint = __esm({
|
|
|
73191
73625
|
cwd: fileDir,
|
|
73192
73626
|
timeout: 3e4
|
|
73193
73627
|
});
|
|
73194
|
-
|
|
73195
|
-
|
|
73196
|
-
|
|
73197
|
-
const diagnostics =
|
|
73628
|
+
const run = parseToolRun("tflint", { result }, (out) => parseTflintOutput(out, ctx.filePath));
|
|
73629
|
+
if (run.skipped)
|
|
73630
|
+
return run.skipped;
|
|
73631
|
+
const diagnostics = run.diagnostics;
|
|
73198
73632
|
if (diagnostics.length === 0) {
|
|
73199
73633
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
73200
73634
|
}
|
|
@@ -73404,13 +73838,12 @@ function parseValeOutput(raw, filePath) {
|
|
|
73404
73838
|
return diagnostics;
|
|
73405
73839
|
try {
|
|
73406
73840
|
const parsed = JSON.parse(raw);
|
|
73407
|
-
|
|
73408
|
-
if (!files2)
|
|
73841
|
+
if (!parsed || typeof parsed !== "object")
|
|
73409
73842
|
return diagnostics;
|
|
73410
|
-
for (const
|
|
73411
|
-
if (!
|
|
73843
|
+
for (const alerts of Object.values(parsed)) {
|
|
73844
|
+
if (!Array.isArray(alerts))
|
|
73412
73845
|
continue;
|
|
73413
|
-
for (const alert of
|
|
73846
|
+
for (const alert of alerts) {
|
|
73414
73847
|
if (!alert.Message)
|
|
73415
73848
|
continue;
|
|
73416
73849
|
const severityMap = {
|
|
@@ -73425,7 +73858,7 @@ function parseValeOutput(raw, filePath) {
|
|
|
73425
73858
|
message: `[${alert.Check ?? "vale"}] ${alert.Message}`,
|
|
73426
73859
|
filePath,
|
|
73427
73860
|
line: alert.Line ?? 1,
|
|
73428
|
-
column: alert.
|
|
73861
|
+
column: alert.Span?.[0] ?? 1,
|
|
73429
73862
|
severity,
|
|
73430
73863
|
semantic: severity === "error" ? "blocking" : "warning",
|
|
73431
73864
|
tool: "vale",
|
|
@@ -73468,11 +73901,10 @@ var init_vale = __esm({
|
|
|
73468
73901
|
if (!cmd)
|
|
73469
73902
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
73470
73903
|
const result = await safeSpawnAsync(cmd, ["--output", "JSON", ctx.filePath], { cwd, timeout: 15e3 });
|
|
73471
|
-
const
|
|
73472
|
-
if (skipped)
|
|
73473
|
-
return skipped;
|
|
73474
|
-
const
|
|
73475
|
-
const diagnostics = parseValeOutput(raw, ctx.filePath);
|
|
73904
|
+
const run = parseToolRun("vale", { result }, (raw) => parseValeOutput(raw, ctx.filePath));
|
|
73905
|
+
if (run.skipped)
|
|
73906
|
+
return run.skipped;
|
|
73907
|
+
const diagnostics = run.diagnostics;
|
|
73476
73908
|
if (diagnostics.length === 0) {
|
|
73477
73909
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
73478
73910
|
}
|
|
@@ -74194,13 +74626,10 @@ var init_yamllint = __esm({
|
|
|
74194
74626
|
timeout: 15e3
|
|
74195
74627
|
});
|
|
74196
74628
|
const raw = `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
|
74197
|
-
const
|
|
74198
|
-
|
|
74199
|
-
|
|
74200
|
-
|
|
74201
|
-
if (skipped)
|
|
74202
|
-
return skipped;
|
|
74203
|
-
const diagnostics = parseYamllintParsable(raw, ctx.filePath);
|
|
74629
|
+
const run = parseToolRun("yamllint", { result, output: result.stdout }, (out) => parseYamllintParsable(out, ctx.filePath), { parseOutput: raw });
|
|
74630
|
+
if (run.skipped)
|
|
74631
|
+
return run.skipped;
|
|
74632
|
+
const diagnostics = run.diagnostics;
|
|
74204
74633
|
if (diagnostics.length === 0) {
|
|
74205
74634
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
74206
74635
|
}
|
|
@@ -77975,7 +78404,7 @@ function makeSourceCountVisitor(state2, ignoreMatcher, limit, maxEntries) {
|
|
|
77975
78404
|
}
|
|
77976
78405
|
return recurse ? "recurse" : "skip";
|
|
77977
78406
|
}
|
|
77978
|
-
if (entry.isFile() && !ignoreMatcher.isIgnored(fullPath, false)
|
|
78407
|
+
if (entry.isFile() && SOURCE_FILE_PATTERN.test(entry.name) && !ignoreMatcher.isIgnored(fullPath, false)) {
|
|
77979
78408
|
state2.count += 1;
|
|
77980
78409
|
if (state2.count > limit)
|
|
77981
78410
|
return "stop";
|
|
@@ -83501,10 +83930,10 @@ function tokenizeShellCommand(command) {
|
|
|
83501
83930
|
word = "";
|
|
83502
83931
|
atTokenStart = true;
|
|
83503
83932
|
};
|
|
83504
|
-
const flushSegment = () => {
|
|
83933
|
+
const flushSegment = (terminator) => {
|
|
83505
83934
|
flushWord();
|
|
83506
83935
|
if (tokens.length > 0 || unsupported)
|
|
83507
|
-
segments.push({ tokens, unsupported });
|
|
83936
|
+
segments.push({ tokens, unsupported, terminator });
|
|
83508
83937
|
tokens = [];
|
|
83509
83938
|
unsupported = false;
|
|
83510
83939
|
atTokenStart = true;
|
|
@@ -83569,13 +83998,17 @@ function tokenizeShellCommand(command) {
|
|
|
83569
83998
|
}
|
|
83570
83999
|
if (ch === ";" || ch === "\n" || ch === "|" || ch === "&") {
|
|
83571
84000
|
flushWord();
|
|
84001
|
+
let terminator;
|
|
83572
84002
|
if (ch === "|" && next === "|")
|
|
83573
84003
|
i++;
|
|
83574
84004
|
else if (ch === "&" && next === "&")
|
|
83575
84005
|
i++;
|
|
83576
|
-
else if (ch === "|"
|
|
84006
|
+
else if (ch === "|") {
|
|
84007
|
+
unsupported = true;
|
|
84008
|
+
terminator = "pipe";
|
|
84009
|
+
} else if (ch === "&")
|
|
83577
84010
|
unsupported = true;
|
|
83578
|
-
flushSegment();
|
|
84011
|
+
flushSegment(terminator);
|
|
83579
84012
|
continue;
|
|
83580
84013
|
}
|
|
83581
84014
|
if (ch === "<" || ch === ">") {
|
|
@@ -83926,11 +84359,44 @@ function parseGrepLineWithoutFile(line, file) {
|
|
|
83926
84359
|
return void 0;
|
|
83927
84360
|
return { file, startLine: lineNumber, endLine: lineNumber };
|
|
83928
84361
|
}
|
|
84362
|
+
var LINE_DROPPING_TAIL_VERBS = /* @__PURE__ */ new Set(["head", "tail", "uniq"]);
|
|
84363
|
+
function isSedQuitCommand(args) {
|
|
84364
|
+
for (const arg of args) {
|
|
84365
|
+
const token = stripQuotes(arg);
|
|
84366
|
+
if (token.startsWith("-"))
|
|
84367
|
+
continue;
|
|
84368
|
+
if (/(^|[;\n])\s*(\d+|\$)?\s*q\b/.test(token))
|
|
84369
|
+
return true;
|
|
84370
|
+
}
|
|
84371
|
+
return false;
|
|
84372
|
+
}
|
|
84373
|
+
function isLineDroppingTailCommand(tokens) {
|
|
84374
|
+
const verb = path69.basename(stripQuotes(tokens[0] ?? ""));
|
|
84375
|
+
if (LINE_DROPPING_TAIL_VERBS.has(verb))
|
|
84376
|
+
return true;
|
|
84377
|
+
if (verb === "sed")
|
|
84378
|
+
return isSedQuitCommand(tokens.slice(1));
|
|
84379
|
+
return false;
|
|
84380
|
+
}
|
|
84381
|
+
function grepPipesIntoTruncatingTail(segments, index) {
|
|
84382
|
+
if (segments[index]?.terminator !== "pipe")
|
|
84383
|
+
return false;
|
|
84384
|
+
for (let j = index + 1; j < segments.length; j++) {
|
|
84385
|
+
if (isLineDroppingTailCommand(segments[j].tokens))
|
|
84386
|
+
return true;
|
|
84387
|
+
if (segments[j].terminator !== "pipe")
|
|
84388
|
+
return false;
|
|
84389
|
+
}
|
|
84390
|
+
return false;
|
|
84391
|
+
}
|
|
83929
84392
|
function collectGrepCommandFiles(command, cwd) {
|
|
83930
84393
|
const files2 = /* @__PURE__ */ new Set();
|
|
83931
84394
|
let hasLineNumberGrep = false;
|
|
83932
84395
|
let context;
|
|
83933
|
-
|
|
84396
|
+
let truncated = false;
|
|
84397
|
+
const segments = tokenizeShellCommand(command);
|
|
84398
|
+
for (let i = 0; i < segments.length; i++) {
|
|
84399
|
+
const tokens = segments[i].tokens;
|
|
83934
84400
|
const verb = path69.basename(stripQuotes(tokens[0] ?? ""));
|
|
83935
84401
|
if (verb !== "grep" && verb !== "egrep" && verb !== "fgrep")
|
|
83936
84402
|
continue;
|
|
@@ -83945,11 +84411,13 @@ function collectGrepCommandFiles(command, cwd) {
|
|
|
83945
84411
|
} : segmentContext;
|
|
83946
84412
|
for (const file of extractGrepSearchFiles(args, cwd))
|
|
83947
84413
|
files2.add(file);
|
|
84414
|
+
if (grepPipesIntoTruncatingTail(segments, i))
|
|
84415
|
+
truncated = true;
|
|
83948
84416
|
}
|
|
83949
84417
|
return {
|
|
83950
84418
|
hasLineNumberGrep,
|
|
83951
84419
|
files: files2,
|
|
83952
|
-
context: context ?? { before: 0, after: 0 }
|
|
84420
|
+
context: truncated ? { before: 0, after: 0 } : context ?? { before: 0, after: 0 }
|
|
83953
84421
|
};
|
|
83954
84422
|
}
|
|
83955
84423
|
function dedupePushSearchRead(out, seen, loc) {
|
|
@@ -89534,6 +90002,47 @@ var RuntimeCoordinator = class {
|
|
|
89534
90002
|
});
|
|
89535
90003
|
return true;
|
|
89536
90004
|
}
|
|
90005
|
+
/**
|
|
90006
|
+
* #1944: retire a past-EOF demotion after its ONE degraded delivery.
|
|
90007
|
+
*
|
|
90008
|
+
* The past-EOF gate demotes and re-arms, but nothing ever retired the
|
|
90009
|
+
* record, so a blocker whose file shrank past the cited lines re-served on
|
|
90010
|
+
* every turn end for the rest of the session — measured live at 80+
|
|
90011
|
+
* minutes on session 01a0234c. The re-serve is unbounded, not the six
|
|
90012
|
+
* turns the first evidence window suggested.
|
|
90013
|
+
*
|
|
90014
|
+
* It is unbounded because the record cannot resolve itself. The two
|
|
90015
|
+
* clearing events (`clearInlineBlockers` on a later dispatch of the same
|
|
90016
|
+
* path, `retireInlineBlockerOnConfirmedClean` on a fresh clean verdict)
|
|
90017
|
+
* both need the file to be looked at again, and the agent has no reason to
|
|
90018
|
+
* look: the coordinates it was handed do not exist. "Re-run to confirm" is
|
|
90019
|
+
* an instruction this record makes impossible to follow.
|
|
90020
|
+
*
|
|
90021
|
+
* So the delivery surface retires it after serving it once, degraded. That
|
|
90022
|
+
* is a DROP, which #1419's demote-not-drop rule normally forbids; the
|
|
90023
|
+
* exception is narrow and stated here. The finding was already delivered
|
|
90024
|
+
* this turn with its dead coordinates annotated, and what remains is a
|
|
90025
|
+
* message pinned to a line the file does not have. `deadLines` is required
|
|
90026
|
+
* and must be non-empty, so a record stale for any OTHER reason, or
|
|
90027
|
+
* past-EOF with no identified dead line, still stands.
|
|
90028
|
+
*
|
|
90029
|
+
* @returns true when an entry was retired — the caller records it, so the
|
|
90030
|
+
* suppression is never silent (#1432 Gap 1).
|
|
90031
|
+
*/
|
|
90032
|
+
retireDemotedPastEofBlocker(filePath, deadLines) {
|
|
90033
|
+
if (deadLines.length === 0)
|
|
90034
|
+
return false;
|
|
90035
|
+
const key2 = path152.resolve(filePath);
|
|
90036
|
+
const existing = this._pendingInlineBlockers.get(key2);
|
|
90037
|
+
if (!existing)
|
|
90038
|
+
return false;
|
|
90039
|
+
if (!existing.stale)
|
|
90040
|
+
return false;
|
|
90041
|
+
if ((existing.staleReason ?? "past-eof") !== "past-eof")
|
|
90042
|
+
return false;
|
|
90043
|
+
this._pendingInlineBlockers.delete(key2);
|
|
90044
|
+
return true;
|
|
90045
|
+
}
|
|
89537
90046
|
/**
|
|
89538
90047
|
* Retire a file's inline blocker because a FRESH, content-bound diagnostic
|
|
89539
90048
|
* verdict proved it gone (#1561).
|
|
@@ -89926,6 +90435,7 @@ init_language_policy();
|
|
|
89926
90435
|
init_language_profile();
|
|
89927
90436
|
init_latency_logger();
|
|
89928
90437
|
init_log_cleanup();
|
|
90438
|
+
init_cascade_tier();
|
|
89929
90439
|
init_config();
|
|
89930
90440
|
init_workspace_diagnostics_session();
|
|
89931
90441
|
init_server();
|
|
@@ -91079,6 +91589,7 @@ async function handleSessionStart(deps) {
|
|
|
91079
91589
|
resetSmellsSessionState();
|
|
91080
91590
|
resetWorkspaceDiagnosticsCacheSession(sessionStartMs);
|
|
91081
91591
|
knipClient.resetSessionState?.();
|
|
91592
|
+
resetCascadeTierSessionState();
|
|
91082
91593
|
runtime2.resetForSession(sessionStartMs);
|
|
91083
91594
|
logLatency({
|
|
91084
91595
|
type: "phase",
|
|
@@ -91218,6 +91729,32 @@ async function handleSessionStart(deps) {
|
|
|
91218
91729
|
log2(`Active tools: ${quickTools.join(", ")}`);
|
|
91219
91730
|
dbg2(`session_start tools: ${quickTools.join(", ") || "deferred (quick mode)"}`);
|
|
91220
91731
|
dbg2("session_start: quick mode active - skipping slow tool probes, language profiling, preinstall, scans, and error debt baseline");
|
|
91732
|
+
logLatency({
|
|
91733
|
+
type: "phase",
|
|
91734
|
+
phase: "session_start_skipped_steps",
|
|
91735
|
+
filePath: cwd,
|
|
91736
|
+
durationMs: 0,
|
|
91737
|
+
metadata: {
|
|
91738
|
+
mode: startupMode,
|
|
91739
|
+
reason: deps.sessionReason,
|
|
91740
|
+
// #1911 review F3: this `if (quickMode)` branch is an early return —
|
|
91741
|
+
// the whole quick path — so there is no enumerable list of "steps
|
|
91742
|
+
// run vs. skipped" this array could be derived from mechanically. It
|
|
91743
|
+
// is DESCRIPTIVE documentation of what the early return skips,
|
|
91744
|
+
// matching the `dbg()` line above word for word; keep both in sync by
|
|
91745
|
+
// hand if either changes. It also does NOT narrow under
|
|
91746
|
+
// `getFlag("no-lsp")` — quick mode skips the same five steps either
|
|
91747
|
+
// way; the LSP flag instead affects `quickTools` above, a separate
|
|
91748
|
+
// record.
|
|
91749
|
+
steps: [
|
|
91750
|
+
"slow_tool_probes",
|
|
91751
|
+
"language_profiling",
|
|
91752
|
+
"tool_preinstall",
|
|
91753
|
+
"startup_scans",
|
|
91754
|
+
"error_debt_baseline"
|
|
91755
|
+
]
|
|
91756
|
+
}
|
|
91757
|
+
});
|
|
91221
91758
|
const totalDurationMs2 = Date.now() - sessionStartMs;
|
|
91222
91759
|
dbg2(`session_start total: ${totalDurationMs2}ms (interactive path)`);
|
|
91223
91760
|
logLatency({
|
|
@@ -93655,6 +94192,61 @@ ${partial.postEditOutput}`;
|
|
|
93655
94192
|
}
|
|
93656
94193
|
}
|
|
93657
94194
|
|
|
94195
|
+
// dist/clients/session-event-guard.js
|
|
94196
|
+
init_bounded_telemetry();
|
|
94197
|
+
init_session_lifecycle();
|
|
94198
|
+
function isStaleExtensionCtxError(err) {
|
|
94199
|
+
return err instanceof Error && err.message.includes("stale after session replacement or reload");
|
|
94200
|
+
}
|
|
94201
|
+
function recordStaleSkip(eventName, detectedAt) {
|
|
94202
|
+
emitBounded("session_event_stale_ctx_skip", eventName, {
|
|
94203
|
+
durationMs: 0,
|
|
94204
|
+
metadata: { event: eventName, detectedAt }
|
|
94205
|
+
}, {
|
|
94206
|
+
ledgerKind: "extension-ctx-stale",
|
|
94207
|
+
risingEdgePer: "identity",
|
|
94208
|
+
reason: `${eventName} skipped: extension ctx is stale (${detectedAt})`
|
|
94209
|
+
});
|
|
94210
|
+
}
|
|
94211
|
+
function isThenable(value) {
|
|
94212
|
+
return typeof value?.then === "function";
|
|
94213
|
+
}
|
|
94214
|
+
function guardSessionEvent(eventName, handler, onStaleResult, options) {
|
|
94215
|
+
const skip = (event, detectedAt) => {
|
|
94216
|
+
recordStaleSkip(eventName, detectedAt);
|
|
94217
|
+
try {
|
|
94218
|
+
options.dbg?.(`${eventName} skipped: extension ctx is stale after session replacement or reload`);
|
|
94219
|
+
} catch {
|
|
94220
|
+
}
|
|
94221
|
+
return onStaleResult(event);
|
|
94222
|
+
};
|
|
94223
|
+
return (event, ctx) => {
|
|
94224
|
+
if (probeCtxActive(ctx) === false)
|
|
94225
|
+
return skip(event, "pre-dispatch");
|
|
94226
|
+
try {
|
|
94227
|
+
const result = handler(event, ctx);
|
|
94228
|
+
if (isThenable(result)) {
|
|
94229
|
+
return Promise.resolve(result).catch((err) => {
|
|
94230
|
+
if (isStaleExtensionCtxError(err))
|
|
94231
|
+
return skip(event, "mid-handler");
|
|
94232
|
+
throw err;
|
|
94233
|
+
});
|
|
94234
|
+
}
|
|
94235
|
+
return result;
|
|
94236
|
+
} catch (err) {
|
|
94237
|
+
if (isStaleExtensionCtxError(err))
|
|
94238
|
+
return skip(event, "mid-handler");
|
|
94239
|
+
throw err;
|
|
94240
|
+
}
|
|
94241
|
+
};
|
|
94242
|
+
}
|
|
94243
|
+
function wrapSessionEventHandler(eventName, handler, options = {}) {
|
|
94244
|
+
return guardSessionEvent(eventName, handler, () => void 0, options);
|
|
94245
|
+
}
|
|
94246
|
+
function wrapSessionEventHandlerWithResult(eventName, handler, options) {
|
|
94247
|
+
return guardSessionEvent(eventName, handler, options.onStaleResult, options);
|
|
94248
|
+
}
|
|
94249
|
+
|
|
93658
94250
|
// dist/index.js
|
|
93659
94251
|
init_session_lifecycle();
|
|
93660
94252
|
|
|
@@ -94110,7 +94702,7 @@ function sweepInlineBlockerPastEof(runtime2, cwd, options) {
|
|
|
94110
94702
|
total: 0,
|
|
94111
94703
|
checked: 0,
|
|
94112
94704
|
demoted: 0,
|
|
94113
|
-
|
|
94705
|
+
deadLinesByPath: /* @__PURE__ */ new Map()
|
|
94114
94706
|
};
|
|
94115
94707
|
const resync = options?.resync ?? resyncDocumentOnPastEof;
|
|
94116
94708
|
let entries;
|
|
@@ -94141,20 +94733,80 @@ function sweepInlineBlockerPastEof(runtime2, cwd, options) {
|
|
|
94141
94733
|
resync
|
|
94142
94734
|
});
|
|
94143
94735
|
const isPastEof = diagnostics.some((d) => d.stale);
|
|
94736
|
+
if (isPastEof) {
|
|
94737
|
+
counts.deadLinesByPath.set(entry.filePath, diagnostics.filter((d) => d.stale).map((d) => d.line).filter((line) => typeof line === "number"));
|
|
94738
|
+
}
|
|
94144
94739
|
const transitioned = runtime2.setInlineBlockerPastEofStale(entry.filePath, isPastEof);
|
|
94145
94740
|
if (!transitioned)
|
|
94146
94741
|
continue;
|
|
94147
|
-
if (isPastEof)
|
|
94742
|
+
if (isPastEof)
|
|
94148
94743
|
counts.demoted += 1;
|
|
94149
|
-
} else {
|
|
94150
|
-
counts.healed += 1;
|
|
94151
|
-
}
|
|
94152
94744
|
} catch {
|
|
94153
94745
|
}
|
|
94154
94746
|
}
|
|
94155
94747
|
return counts;
|
|
94156
94748
|
}
|
|
94157
94749
|
|
|
94750
|
+
// dist/clients/runtime-turn.js
|
|
94751
|
+
init_degradation_ledger();
|
|
94752
|
+
|
|
94753
|
+
// dist/clients/demoted-finding-render.js
|
|
94754
|
+
var DEAD_LINE_ANNOTATION = "(line no longer exists)";
|
|
94755
|
+
var AUTHORITY_REWRITES = [
|
|
94756
|
+
[
|
|
94757
|
+
/[^\S\n]*(?:🔴|⛔|❌)?[^\S\n]*STOP[^\S\n]*[—–-][^\S\n]*(\d+)[^\S\n]+issue\(s\)[^\S\n]+must be fixed:?/g,
|
|
94758
|
+
"$1 issue(s) were flagged before this file changed; the coordinates below may no longer exist:"
|
|
94759
|
+
],
|
|
94760
|
+
[/(?:🔴|⛔|❌)[^\S\n]*STOP\b[^\S\n]*[—–-]?/g, "Previously flagged \u2014"],
|
|
94761
|
+
[/\bSTOP\b/g, "Previously flagged"],
|
|
94762
|
+
[/\bmust be fixed\b/g, "were flagged"]
|
|
94763
|
+
];
|
|
94764
|
+
var CITED_LINE_RE = /^([^\S\n]*)L(\d+)\b/;
|
|
94765
|
+
function splitBannerRegion(lines) {
|
|
94766
|
+
const firstCitedRow = lines.findIndex((line) => CITED_LINE_RE.test(line));
|
|
94767
|
+
if (firstCitedRow !== -1)
|
|
94768
|
+
return { bannerEnd: firstCitedRow };
|
|
94769
|
+
const firstNonBlank = lines.findIndex((line) => line.trim() !== "");
|
|
94770
|
+
return { bannerEnd: firstNonBlank === -1 ? 0 : firstNonBlank + 1 };
|
|
94771
|
+
}
|
|
94772
|
+
function degradeDemotedFindingBody(summary, options = {}) {
|
|
94773
|
+
const deadLines = new Set(options.deadLines ?? []);
|
|
94774
|
+
let authorityMarkersRemoved = 0;
|
|
94775
|
+
const sourceLines = summary.split("\n");
|
|
94776
|
+
const { bannerEnd } = splitBannerRegion(sourceLines);
|
|
94777
|
+
const degradedLines = sourceLines.map((line, index) => {
|
|
94778
|
+
if (index >= bannerEnd)
|
|
94779
|
+
return line;
|
|
94780
|
+
let rewritten = line;
|
|
94781
|
+
for (const [pattern, replacement] of AUTHORITY_REWRITES) {
|
|
94782
|
+
rewritten = rewritten.replace(pattern, (...args) => {
|
|
94783
|
+
authorityMarkersRemoved += 1;
|
|
94784
|
+
return replacement.replace(/\$(\d)/g, (_, digit) => String(args[Number(digit)] ?? ""));
|
|
94785
|
+
});
|
|
94786
|
+
}
|
|
94787
|
+
return rewritten;
|
|
94788
|
+
});
|
|
94789
|
+
let body = degradedLines.join("\n");
|
|
94790
|
+
const deadLinesAnnotated = [];
|
|
94791
|
+
if (deadLines.size > 0) {
|
|
94792
|
+
body = degradedLines.map((line) => {
|
|
94793
|
+
const hit = CITED_LINE_RE.exec(line);
|
|
94794
|
+
if (!hit)
|
|
94795
|
+
return line;
|
|
94796
|
+
const cited = Number.parseInt(hit[2] ?? "", 10);
|
|
94797
|
+
if (!Number.isFinite(cited) || !deadLines.has(cited))
|
|
94798
|
+
return line;
|
|
94799
|
+
deadLinesAnnotated.push(cited);
|
|
94800
|
+
return `${hit[1] ?? ""}L${cited} ${DEAD_LINE_ANNOTATION}${line.slice(hit[0].length)}`;
|
|
94801
|
+
}).join("\n");
|
|
94802
|
+
}
|
|
94803
|
+
return { body, authorityMarkersRemoved, deadLinesAnnotated };
|
|
94804
|
+
}
|
|
94805
|
+
function formatRetirementNote(deadLines) {
|
|
94806
|
+
const cited = deadLines.length > 0 ? ` (cited ${deadLines.length === 1 ? "line" : "lines"} ${deadLines.join(", ")})` : "";
|
|
94807
|
+
return `Retired after this delivery${cited}: the file no longer has these lines, so this finding cannot be re-confirmed and will not be served again.`;
|
|
94808
|
+
}
|
|
94809
|
+
|
|
94158
94810
|
// dist/clients/runtime-turn.js
|
|
94159
94811
|
init_stale_marker();
|
|
94160
94812
|
init_widget_state();
|
|
@@ -94331,8 +94983,10 @@ async function handleTurnEnd(deps) {
|
|
|
94331
94983
|
metadata: {
|
|
94332
94984
|
total: blockerPastEof.total,
|
|
94333
94985
|
checked: blockerPastEof.checked,
|
|
94334
|
-
demoted: blockerPastEof.demoted
|
|
94335
|
-
|
|
94986
|
+
demoted: blockerPastEof.demoted
|
|
94987
|
+
// #1944 review F3: `healed` is gone. Retirement makes the falling edge
|
|
94988
|
+
// unreachable on this store, so the field could only ever log zero —
|
|
94989
|
+
// see `BlockerPastEofCounts`.
|
|
94336
94990
|
}
|
|
94337
94991
|
});
|
|
94338
94992
|
const blockerFreshnessStart = Date.now();
|
|
@@ -94358,11 +95012,24 @@ async function handleTurnEnd(deps) {
|
|
|
94358
95012
|
}
|
|
94359
95013
|
});
|
|
94360
95014
|
const unresolvedBlockers = runtime2.getInlineBlockersSnapshot();
|
|
95015
|
+
let demotedFindingsRetired = 0;
|
|
94361
95016
|
for (const { filePath: bPath, summary, stale } of unresolvedBlockers) {
|
|
94362
95017
|
const displayPath = toRunnerDisplayPath(cwd, bPath);
|
|
94363
95018
|
if (stale) {
|
|
95019
|
+
const deadLines = blockerPastEof.deadLinesByPath.get(bPath) ?? [];
|
|
95020
|
+
const degraded = degradeDemotedFindingBody(summary, { deadLines });
|
|
95021
|
+
const retired = runtime2.retireDemotedPastEofBlocker(bPath, deadLines);
|
|
95022
|
+
if (retired) {
|
|
95023
|
+
demotedFindingsRetired += 1;
|
|
95024
|
+
incrementDegradationCount({
|
|
95025
|
+
kind: "demoted-finding-retired",
|
|
95026
|
+
subject: `inline-blocker:${displayPath}`,
|
|
95027
|
+
reason: `file shrank past cited line(s) ${deadLines.join(", ")}; retired after one degraded delivery`
|
|
95028
|
+
});
|
|
95029
|
+
}
|
|
94364
95030
|
advisoryParts.push(`${STALE_LINE_MARKER} ${displayPath}:
|
|
94365
|
-
${
|
|
95031
|
+
${degraded.body}` + (retired ? `
|
|
95032
|
+
${formatRetirementNote(deadLines)}` : ""));
|
|
94366
95033
|
} else {
|
|
94367
95034
|
blockerParts.push(`Unresolved from this turn \u2014 ${displayPath}:
|
|
94368
95035
|
${summary}`);
|
|
@@ -95408,6 +96075,9 @@ ${p}`);
|
|
|
95408
96075
|
runtime2.fixedThisTurn.clear();
|
|
95409
96076
|
runtime2.clearActionableWarnings();
|
|
95410
96077
|
runtime2.clearCodeQualityWarnings();
|
|
96078
|
+
if (demotedFindingsRetired > 0) {
|
|
96079
|
+
cacheManager.clearCache("turn-end-findings-last", cwd);
|
|
96080
|
+
}
|
|
95411
96081
|
logLatency({
|
|
95412
96082
|
type: "tool_result",
|
|
95413
96083
|
toolName: "turn_end",
|
|
@@ -95421,7 +96091,12 @@ ${p}`);
|
|
|
95421
96091
|
fileCount: files2.length,
|
|
95422
96092
|
blockerSections: blockerParts.length,
|
|
95423
96093
|
staleSecretSections: staleSecretParts.length,
|
|
95424
|
-
advisorySections: advisoryParts.length
|
|
96094
|
+
advisorySections: advisoryParts.length,
|
|
96095
|
+
// #1944 AC3: an empty advisory section on its own cannot say whether
|
|
96096
|
+
// the turn had nothing to report or dropped something. This counter
|
|
96097
|
+
// answers that from latency.log even when the payload is empty, and
|
|
96098
|
+
// the payload itself carries the retirement note when it is not.
|
|
96099
|
+
demotedFindingsRetired
|
|
95425
96100
|
}
|
|
95426
96101
|
});
|
|
95427
96102
|
resetFormatService2();
|
|
@@ -96651,17 +97326,15 @@ async function scanFileMajorRules(cwd, files2, signal) {
|
|
|
96651
97326
|
// subtract its share so this metric stays comparable to the historical
|
|
96652
97327
|
// phase-major scans.
|
|
96653
97328
|
durationMs: Date.now() - startedAt - astGrepDurationMs,
|
|
96654
|
-
stats
|
|
96655
|
-
|
|
96656
|
-
|
|
96657
|
-
|
|
96658
|
-
|
|
96659
|
-
|
|
96660
|
-
|
|
96661
|
-
|
|
96662
|
-
fileCount: astGrepFilesScanned
|
|
96663
|
-
durationMs: astGrepDurationMs,
|
|
96664
|
-
stats
|
|
97329
|
+
stats,
|
|
97330
|
+
// #1935 review: ast-grep's own cost is often a scan's most expensive
|
|
97331
|
+
// phase (production evidence: 13168ms over 86 files, the single
|
|
97332
|
+
// biggest contributor). Its duration is subtracted above so it stays
|
|
97333
|
+
// comparable to the historical phase-major scans; carry it here too
|
|
97334
|
+
// so it stays visible SOMEWHERE instead of disappearing when the
|
|
97335
|
+
// vacuous `project_diagnostics_ast_grep_scan` cache_stats record
|
|
97336
|
+
// (below) was removed.
|
|
97337
|
+
astGrep: { durationMs: astGrepDurationMs, fileCount: astGrepFilesScanned }
|
|
96665
97338
|
});
|
|
96666
97339
|
});
|
|
96667
97340
|
return { treeSitter, factRules, astGrep, filesScanned, wasmAborted };
|
|
@@ -97999,10 +98672,14 @@ async function moduleReport(file, cwd, options) {
|
|
|
97999
98672
|
let graph;
|
|
98000
98673
|
let graphFileCap;
|
|
98001
98674
|
let callGraphIdentity;
|
|
98675
|
+
let revisionDriftNote;
|
|
98002
98676
|
try {
|
|
98003
|
-
const { getCachedReviewGraph: getCachedReviewGraph2, getReviewGraphCacheIdentity: getReviewGraphCacheIdentity2, getReviewGraphSizeSkipVerdict: getReviewGraphSizeSkipVerdict2 } = await Promise.resolve().then(() => (init_builder(), builder_exports));
|
|
98677
|
+
const { getCachedReviewGraph: getCachedReviewGraph2, getReviewGraphCacheIdentity: getReviewGraphCacheIdentity2, getReviewGraphSizeSkipVerdict: getReviewGraphSizeSkipVerdict2, getReviewGraphRevisionDrift: getReviewGraphRevisionDrift2, formatReviewGraphRevisionDriftNote: formatReviewGraphRevisionDriftNote2 } = await Promise.resolve().then(() => (init_builder(), builder_exports));
|
|
98004
98678
|
graph = getCachedReviewGraph2(cwd);
|
|
98005
98679
|
graphFileCap = getReviewGraphSizeSkipVerdict2(cwd)?.maxFileCount;
|
|
98680
|
+
const drift = graph ? getReviewGraphRevisionDrift2(cwd) : void 0;
|
|
98681
|
+
if (drift)
|
|
98682
|
+
revisionDriftNote = formatReviewGraphRevisionDriftNote2(drift);
|
|
98006
98683
|
callGraphIdentity = graph ? (() => {
|
|
98007
98684
|
const identity = getReviewGraphCacheIdentity2(cwd, graph);
|
|
98008
98685
|
return identity ? {
|
|
@@ -98021,6 +98698,8 @@ async function moduleReport(file, cwd, options) {
|
|
|
98021
98698
|
const api = topLevel.filter((entry) => entry.exported);
|
|
98022
98699
|
const internal = topLevel.filter((entry) => !entry.exported);
|
|
98023
98700
|
const warnings = [...extractionWarnings ?? []];
|
|
98701
|
+
if (revisionDriftNote)
|
|
98702
|
+
warnings.push(revisionDriftNote);
|
|
98024
98703
|
if (callbackError) {
|
|
98025
98704
|
warnings.push(`Failed to extract callbacks: ${callbackError}`);
|
|
98026
98705
|
logLatency({
|
|
@@ -98639,6 +99318,7 @@ async function readEnclosing(file, line, cwd, options) {
|
|
|
98639
99318
|
// dist/clients/project-report.js
|
|
98640
99319
|
init_path_utils();
|
|
98641
99320
|
init_project_snapshot();
|
|
99321
|
+
init_revision_drift();
|
|
98642
99322
|
import * as path179 from "node:path";
|
|
98643
99323
|
var DEFAULT_LIMIT = 10;
|
|
98644
99324
|
var STALE_THRESHOLD_MS = 15 * 6e4;
|
|
@@ -98691,7 +99371,7 @@ function buildFileDegrees(graph) {
|
|
|
98691
99371
|
}
|
|
98692
99372
|
return { fanIn, fanOut };
|
|
98693
99373
|
}
|
|
98694
|
-
function computeTrust(graph, cwd) {
|
|
99374
|
+
function computeTrust(graph, cwd, drift) {
|
|
98695
99375
|
const filesCovered = graph.fileNodes.size;
|
|
98696
99376
|
const snapshot = loadProjectSnapshotWithoutWordIndex(cwd);
|
|
98697
99377
|
const snapshotFileCount = snapshot ? Object.keys(snapshot.files).length : 0;
|
|
@@ -98728,6 +99408,8 @@ function computeTrust(graph, cwd) {
|
|
|
98728
99408
|
const stale = Number.isFinite(ageMs) && ageMs > STALE_THRESHOLD_MS;
|
|
98729
99409
|
const lowCoverage = coverage < LOW_COVERAGE_THRESHOLD || graph.persistCoverage?.partial === true;
|
|
98730
99410
|
const notes = [];
|
|
99411
|
+
if (drift)
|
|
99412
|
+
notes.push(formatReviewGraphRevisionDriftNote(drift));
|
|
98731
99413
|
if (stale) {
|
|
98732
99414
|
const ageMin = Math.round(ageMs / 6e4);
|
|
98733
99415
|
notes.push(`Graph is stale: built ${ageMin}m ago. Sections below may miss recent edits \u2014 run pilens_rebuild or re-analyze to refresh.`);
|
|
@@ -98759,6 +99441,7 @@ function computeTrust(graph, cwd) {
|
|
|
98759
99441
|
sampleSize
|
|
98760
99442
|
},
|
|
98761
99443
|
stale,
|
|
99444
|
+
...drift ? { revisionDrift: drift } : {},
|
|
98762
99445
|
lowCoverage,
|
|
98763
99446
|
persistCoverage: graph.persistCoverage?.partial ? graph.persistCoverage : void 0,
|
|
98764
99447
|
notes
|
|
@@ -99016,28 +99699,22 @@ function computeDeadWeight(graph, degrees, entryPointFiles, cwd, limit) {
|
|
|
99016
99699
|
};
|
|
99017
99700
|
}
|
|
99018
99701
|
var inFlightGraphBuilds = /* @__PURE__ */ new Set();
|
|
99019
|
-
function triggerBackgroundGraphBuild(cwd) {
|
|
99702
|
+
function triggerBackgroundGraphBuild(cwd, deps) {
|
|
99020
99703
|
const key2 = normalizeMapKey(path179.resolve(cwd));
|
|
99021
99704
|
if (inFlightGraphBuilds.has(key2))
|
|
99022
|
-
return
|
|
99705
|
+
return "already_running";
|
|
99706
|
+
const deduped = deps.isGraphBuildInFlight(key2, []);
|
|
99023
99707
|
inFlightGraphBuilds.add(key2);
|
|
99024
|
-
|
|
99025
|
-
|
|
99026
|
-
|
|
99027
|
-
|
|
99028
|
-
await buildOrUpdateGraph3(key2, [], new FactStore2());
|
|
99029
|
-
} catch {
|
|
99030
|
-
} finally {
|
|
99031
|
-
inFlightGraphBuilds.delete(key2);
|
|
99032
|
-
}
|
|
99033
|
-
})();
|
|
99034
|
-
return true;
|
|
99708
|
+
const build2 = deps.buildOrUpdateGraph(key2, [], new deps.FactStore()).catch(() => {
|
|
99709
|
+
});
|
|
99710
|
+
void build2.finally(() => inFlightGraphBuilds.delete(key2));
|
|
99711
|
+
return deduped ? "already_running" : "started";
|
|
99035
99712
|
}
|
|
99036
99713
|
async function projectReport(cwd, options) {
|
|
99037
99714
|
const limit = clampLimit(options?.limit);
|
|
99038
99715
|
const focusTerms = normalizeFocus2(options?.focus);
|
|
99039
99716
|
const view = options?.view;
|
|
99040
|
-
const { getCachedReviewGraph: getCachedReviewGraph2, getReviewGraphSizeSkipVerdict: getReviewGraphSizeSkipVerdict2, getLastReviewGraphBuildAttempt: getLastReviewGraphBuildAttempt2 } = await Promise.resolve().then(() => (init_builder(), builder_exports));
|
|
99717
|
+
const { getCachedReviewGraph: getCachedReviewGraph2, getReviewGraphSizeSkipVerdict: getReviewGraphSizeSkipVerdict2, getLastReviewGraphBuildAttempt: getLastReviewGraphBuildAttempt2, buildOrUpdateGraph: buildOrUpdateGraph3, isGraphBuildInFlight: isGraphBuildInFlight2, getReviewGraphRevisionDrift: getReviewGraphRevisionDrift2 } = await Promise.resolve().then(() => (init_builder(), builder_exports));
|
|
99041
99718
|
let graph;
|
|
99042
99719
|
try {
|
|
99043
99720
|
graph = getCachedReviewGraph2(cwd);
|
|
@@ -99061,17 +99738,25 @@ async function projectReport(cwd, options) {
|
|
|
99061
99738
|
};
|
|
99062
99739
|
}
|
|
99063
99740
|
const previousAttempt = getLastReviewGraphBuildAttempt2(cwd);
|
|
99064
|
-
const
|
|
99065
|
-
const
|
|
99741
|
+
const { FactStore: FactStore2 } = await Promise.resolve().then(() => (init_fact_store(), fact_store_exports));
|
|
99742
|
+
const trigger = triggerBackgroundGraphBuild(cwd, {
|
|
99743
|
+
buildOrUpdateGraph: buildOrUpdateGraph3,
|
|
99744
|
+
isGraphBuildInFlight: isGraphBuildInFlight2,
|
|
99745
|
+
FactStore: FactStore2
|
|
99746
|
+
});
|
|
99747
|
+
const started = trigger === "started";
|
|
99748
|
+
const lastBuildAttempt2 = started ? getLastReviewGraphBuildAttempt2(cwd) ?? previousAttempt : previousAttempt;
|
|
99749
|
+
const terminal = previousAttempt?.outcome === "failed" || previousAttempt?.outcome === "skipped";
|
|
99750
|
+
const cause = terminal ? `Review graph unavailable: ${previousAttempt?.reason ?? previousAttempt?.outcome}. ` : "";
|
|
99066
99751
|
return {
|
|
99067
99752
|
available: false,
|
|
99068
|
-
hint:
|
|
99753
|
+
hint: started ? terminal ? `${cause}A retry was started.` : "No review graph cached for this workspace yet \u2014 a build was kicked off in the background; retry this call shortly." : `${cause}A build is already running for this workspace; retry this call shortly.`,
|
|
99069
99754
|
...lastBuildAttempt2 ? { lastBuildAttempt: lastBuildAttempt2 } : {},
|
|
99070
99755
|
...view ? { view } : {}
|
|
99071
99756
|
};
|
|
99072
99757
|
}
|
|
99073
99758
|
const degrees = buildFileDegrees(graph);
|
|
99074
|
-
const trust = computeTrust(graph, cwd);
|
|
99759
|
+
const trust = computeTrust(graph, cwd, getReviewGraphRevisionDrift2(cwd));
|
|
99075
99760
|
const hubs = await computeHubs(graph, degrees, cwd, limit, focusTerms);
|
|
99076
99761
|
const { entryPoints, entryPointFiles } = computeEntryPoints(graph, degrees, cwd, limit, focusTerms);
|
|
99077
99762
|
const subsystems = computeSubsystems(graph, cwd, limit);
|
|
@@ -99507,7 +100192,7 @@ function createLensDiagnosticsTool(cacheManager, getCwd, getLspService = getLSPS
|
|
|
99507
100192
|
};
|
|
99508
100193
|
}
|
|
99509
100194
|
function formatProjectDeltaDiagnostic(diagnostic, stale) {
|
|
99510
|
-
const marker = diagnostic.semantic === "blocking" || diagnostic.severity === "error" ? "\u{1F534}" : "\u2139";
|
|
100195
|
+
const marker = stale ? "\u25CB" : diagnostic.semantic === "blocking" || diagnostic.severity === "error" ? "\u{1F534}" : "\u2139";
|
|
99511
100196
|
const rule = diagnostic.rule ?? diagnostic.code ?? diagnostic.runner;
|
|
99512
100197
|
const where = stale ? STALE_LINE_MARKER : `L${diagnostic.line ?? "?"}`;
|
|
99513
100198
|
return ` ${marker} ${where} ${rule} ${diagnostic.message}`;
|
|
@@ -104856,6 +105541,7 @@ function recordToolSetMutation(mutation) {
|
|
|
104856
105541
|
}
|
|
104857
105542
|
|
|
104858
105543
|
// dist/clients/cache-observability.js
|
|
105544
|
+
init_env_utils();
|
|
104859
105545
|
init_latency_logger();
|
|
104860
105546
|
import { createHash as createHash15 } from "node:crypto";
|
|
104861
105547
|
var PROCESS_TURN_SCOPE = "process-global-runtime";
|
|
@@ -104866,6 +105552,93 @@ var MAX_REPORTED_MESSAGES = 1e4;
|
|
|
104866
105552
|
var MAX_INJECTED_CHARS = 16384;
|
|
104867
105553
|
var MAX_INJECTED_BYTES = 65536;
|
|
104868
105554
|
var contextObservationCounter = 0;
|
|
105555
|
+
var CHARS_PER_ESTIMATED_TOKEN = 4;
|
|
105556
|
+
var DEFAULT_PROVIDER_CACHE_TTL_MS = 6e4;
|
|
105557
|
+
var _providerCacheTtl = lazyEnvNumber("PI_LENS_PROVIDER_CACHE_TTL_MS", DEFAULT_PROVIDER_CACHE_TTL_MS);
|
|
105558
|
+
var getProviderCacheTtlMs = _providerCacheTtl.get;
|
|
105559
|
+
var _resetProviderCacheTtlForTests = _providerCacheTtl._resetForTests;
|
|
105560
|
+
var LOW_CACHE_READ_RATIO = 0.5;
|
|
105561
|
+
var PARTIAL_EVICTION_INPUT_FACTOR = 4;
|
|
105562
|
+
var PARTIAL_EVICTION_MIN_FRESH_TOKENS = 512;
|
|
105563
|
+
var MAX_ATTRIBUTION_CHARS = 262144;
|
|
105564
|
+
var MAX_ATTRIBUTION_BYTES = 1048576;
|
|
105565
|
+
var attributionBySession = /* @__PURE__ */ new Map();
|
|
105566
|
+
function newAttributionState() {
|
|
105567
|
+
return {
|
|
105568
|
+
prefixBrokeSinceLastUsage: false,
|
|
105569
|
+
injectedCharsSinceLastUsage: 0,
|
|
105570
|
+
newTranscriptCharsSinceLastUsage: 0,
|
|
105571
|
+
attributionCharsCapped: false
|
|
105572
|
+
};
|
|
105573
|
+
}
|
|
105574
|
+
function attributionFor(key2) {
|
|
105575
|
+
const existing = attributionBySession.get(key2);
|
|
105576
|
+
const state2 = existing ?? newAttributionState();
|
|
105577
|
+
attributionBySession.delete(key2);
|
|
105578
|
+
attributionBySession.set(key2, state2);
|
|
105579
|
+
while (attributionBySession.size > MAX_TRACKED_SESSIONS) {
|
|
105580
|
+
const oldest = attributionBySession.keys().next().value;
|
|
105581
|
+
if (oldest === void 0)
|
|
105582
|
+
break;
|
|
105583
|
+
attributionBySession.delete(oldest);
|
|
105584
|
+
}
|
|
105585
|
+
return state2;
|
|
105586
|
+
}
|
|
105587
|
+
function recordContextAttribution(key2, existingMessages, injectedSize) {
|
|
105588
|
+
const state2 = attributionFor(key2);
|
|
105589
|
+
const baseline = Math.min(state2.lastObservedMessageCount ?? existingMessages.length, existingMessages.length);
|
|
105590
|
+
const grown = measureTranscriptGrowth(existingMessages.slice(baseline));
|
|
105591
|
+
state2.injectedCharsSinceLastUsage = Math.min(MAX_ATTRIBUTION_CHARS, state2.injectedCharsSinceLastUsage + injectedSize.chars);
|
|
105592
|
+
state2.newTranscriptCharsSinceLastUsage = Math.min(MAX_ATTRIBUTION_CHARS, state2.newTranscriptCharsSinceLastUsage + grown.chars);
|
|
105593
|
+
if (injectedSize.capped || grown.capped || state2.injectedCharsSinceLastUsage >= MAX_ATTRIBUTION_CHARS || state2.newTranscriptCharsSinceLastUsage >= MAX_ATTRIBUTION_CHARS) {
|
|
105594
|
+
state2.attributionCharsCapped = true;
|
|
105595
|
+
}
|
|
105596
|
+
state2.lastObservedMessageCount = existingMessages.length;
|
|
105597
|
+
state2.lastContextAtMs = Date.now();
|
|
105598
|
+
}
|
|
105599
|
+
function resolveInterTurnGap(state2, nowMs) {
|
|
105600
|
+
if (state2.lastUsageAtMs === void 0) {
|
|
105601
|
+
return { gapMs: null, basis: "no-prior-turn" };
|
|
105602
|
+
}
|
|
105603
|
+
if (state2.lastContextAtMs !== void 0) {
|
|
105604
|
+
return {
|
|
105605
|
+
gapMs: Math.max(0, state2.lastContextAtMs - state2.lastUsageAtMs),
|
|
105606
|
+
basis: "request-time"
|
|
105607
|
+
};
|
|
105608
|
+
}
|
|
105609
|
+
return {
|
|
105610
|
+
gapMs: Math.max(0, nowMs - state2.lastUsageAtMs),
|
|
105611
|
+
basis: "message-end-fallback"
|
|
105612
|
+
};
|
|
105613
|
+
}
|
|
105614
|
+
function estimateTokens2(chars) {
|
|
105615
|
+
return Math.ceil(chars / CHARS_PER_ESTIMATED_TOKEN);
|
|
105616
|
+
}
|
|
105617
|
+
function classifyCacheMiss(args) {
|
|
105618
|
+
const { cacheRead, priorCacheRead } = args;
|
|
105619
|
+
if (typeof cacheRead !== "number" || !Number.isFinite(cacheRead))
|
|
105620
|
+
return null;
|
|
105621
|
+
if (typeof priorCacheRead !== "number" || !Number.isFinite(priorCacheRead)) {
|
|
105622
|
+
return null;
|
|
105623
|
+
}
|
|
105624
|
+
let kind;
|
|
105625
|
+
if (cacheRead === 0) {
|
|
105626
|
+
kind = "zero-read";
|
|
105627
|
+
} else if (priorCacheRead > 0 && cacheRead < priorCacheRead * LOW_CACHE_READ_RATIO) {
|
|
105628
|
+
kind = "low-read";
|
|
105629
|
+
} else {
|
|
105630
|
+
return null;
|
|
105631
|
+
}
|
|
105632
|
+
if (args.prefixBroke)
|
|
105633
|
+
return { kind, cause: "prefix-broke" };
|
|
105634
|
+
if (args.interTurnGapMs !== null && args.interTurnGapMs >= args.ttlMs) {
|
|
105635
|
+
return { kind, cause: "ttl-expired" };
|
|
105636
|
+
}
|
|
105637
|
+
if (kind === "low-read" && !args.attributionCharsCapped && args.input > Math.max(PARTIAL_EVICTION_MIN_FRESH_TOKENS, args.estimatedNewTokens * PARTIAL_EVICTION_INPUT_FACTOR)) {
|
|
105638
|
+
return { kind, cause: "partial-eviction" };
|
|
105639
|
+
}
|
|
105640
|
+
return { kind, cause: "unknown" };
|
|
105641
|
+
}
|
|
104869
105642
|
function boundedHashScalar(value, state2) {
|
|
104870
105643
|
if (value === null)
|
|
104871
105644
|
return "null";
|
|
@@ -104938,87 +105711,78 @@ function hashMessageSequence(messages) {
|
|
|
104938
105711
|
contentTruncated: state2.contentTruncated
|
|
104939
105712
|
};
|
|
104940
105713
|
}
|
|
104941
|
-
|
|
105714
|
+
var INJECTED_LIMITS = {
|
|
105715
|
+
maxChars: MAX_INJECTED_CHARS,
|
|
105716
|
+
maxBytes: MAX_INJECTED_BYTES
|
|
105717
|
+
};
|
|
105718
|
+
var TRANSCRIPT_LIMITS = {
|
|
105719
|
+
maxChars: MAX_ATTRIBUTION_CHARS,
|
|
105720
|
+
maxBytes: MAX_ATTRIBUTION_BYTES
|
|
105721
|
+
};
|
|
105722
|
+
function messageTextSize(content, limits) {
|
|
104942
105723
|
if (typeof content === "string") {
|
|
104943
|
-
const chars = Math.min(content.length,
|
|
105724
|
+
const chars = Math.min(content.length, limits.maxChars);
|
|
104944
105725
|
return {
|
|
104945
105726
|
chars,
|
|
104946
|
-
bytes: Math.min(Buffer.byteLength(content.slice(0, chars), "utf8"),
|
|
105727
|
+
bytes: Math.min(Buffer.byteLength(content.slice(0, chars), "utf8"), limits.maxBytes)
|
|
104947
105728
|
};
|
|
104948
105729
|
}
|
|
104949
105730
|
const bounded = boundedHashValue(content);
|
|
104950
105731
|
return {
|
|
104951
|
-
chars: Math.min(bounded.length,
|
|
104952
|
-
bytes: Math.min(Buffer.byteLength(bounded.slice(0,
|
|
105732
|
+
chars: Math.min(bounded.length, limits.maxChars),
|
|
105733
|
+
bytes: Math.min(Buffer.byteLength(bounded.slice(0, limits.maxChars), "utf8"), limits.maxBytes)
|
|
104953
105734
|
};
|
|
104954
105735
|
}
|
|
104955
|
-
function
|
|
105736
|
+
function measureMessages(messages, limits) {
|
|
104956
105737
|
let chars = 0;
|
|
104957
105738
|
let bytes = 0;
|
|
104958
105739
|
const measuredCount = Math.min(messages.length, MAX_REPORTED_MESSAGES);
|
|
104959
105740
|
for (let i = 0; i < measuredCount; i++) {
|
|
104960
105741
|
const message = messages[i];
|
|
104961
|
-
const size = messageTextSize(message?.content);
|
|
104962
|
-
chars = Math.min(
|
|
104963
|
-
bytes = Math.min(
|
|
104964
|
-
if (chars ===
|
|
105742
|
+
const size = messageTextSize(message?.content, limits);
|
|
105743
|
+
chars = Math.min(limits.maxChars, chars + size.chars);
|
|
105744
|
+
bytes = Math.min(limits.maxBytes, bytes + size.bytes);
|
|
105745
|
+
if (chars === limits.maxChars || bytes === limits.maxBytes)
|
|
104965
105746
|
break;
|
|
104966
105747
|
}
|
|
104967
105748
|
return {
|
|
104968
105749
|
chars,
|
|
104969
105750
|
bytes,
|
|
104970
|
-
capped: chars >=
|
|
105751
|
+
capped: chars >= limits.maxChars || bytes >= limits.maxBytes
|
|
104971
105752
|
};
|
|
104972
105753
|
}
|
|
104973
|
-
function
|
|
104974
|
-
return
|
|
104975
|
-
}
|
|
104976
|
-
function prefixLengthForPlacement(placement, messageCount) {
|
|
104977
|
-
if (placement === "insert-before-final") {
|
|
104978
|
-
return Math.max(0, messageCount - 1);
|
|
104979
|
-
}
|
|
104980
|
-
if (placement === "prepend")
|
|
104981
|
-
return 0;
|
|
104982
|
-
return messageCount;
|
|
104983
|
-
}
|
|
104984
|
-
function resolvePrefixObservation(truncated, observation) {
|
|
104985
|
-
if (truncated)
|
|
104986
|
-
return "unknown";
|
|
104987
|
-
return observation ?? "empty";
|
|
105754
|
+
function measureInjectedMessages(messages) {
|
|
105755
|
+
return measureMessages(messages, INJECTED_LIMITS);
|
|
104988
105756
|
}
|
|
104989
|
-
function
|
|
104990
|
-
|
|
104991
|
-
return true;
|
|
104992
|
-
if (observation === "empty" || observation === "unknown")
|
|
104993
|
-
return null;
|
|
104994
|
-
return false;
|
|
105757
|
+
function measureTranscriptGrowth(messages) {
|
|
105758
|
+
return measureMessages(messages, TRANSCRIPT_LIMITS);
|
|
104995
105759
|
}
|
|
104996
|
-
function
|
|
104997
|
-
|
|
104998
|
-
return "unknown";
|
|
104999
|
-
return before !== after ? "changed" : "unchanged";
|
|
105760
|
+
function sessionKey(sessionId) {
|
|
105761
|
+
return sessionId?.trim() ? sessionId.trim() : NO_SESSION_KEY;
|
|
105000
105762
|
}
|
|
105001
105763
|
function observeCacheContext(args) {
|
|
105002
105764
|
try {
|
|
105003
105765
|
const existingMessages = args.existingMessages ?? [];
|
|
105004
105766
|
const resultMessages = args.resultMessages ?? existingMessages;
|
|
105005
|
-
const
|
|
105767
|
+
const injectionSlices = (args.injectionSlices ?? []).filter((slice) => slice.messages.length > 0);
|
|
105768
|
+
const injectedMessages = injectionSlices.flatMap((slice) => slice.messages);
|
|
105006
105769
|
const placement = args.placement ?? "none";
|
|
105007
105770
|
const beforeSequence = hashMessageSequence(existingMessages);
|
|
105008
105771
|
const afterSequence = hashMessageSequence(resultMessages);
|
|
105009
|
-
const beforePrefixLength = prefixLengthForPlacement(placement, existingMessages.length);
|
|
105010
|
-
const afterPrefixLength = Math.min(beforePrefixLength, resultMessages.length);
|
|
105011
|
-
const beforePrefix = hashMessageSequence(existingMessages.slice(0, beforePrefixLength));
|
|
105012
|
-
const afterPrefix = hashMessageSequence(resultMessages.slice(0, afterPrefixLength));
|
|
105013
|
-
const beforeFirstSequence = existingMessages.length ? hashMessageSequence([existingMessages[0]]) : void 0;
|
|
105014
|
-
const afterFirstSequence = resultMessages.length ? hashMessageSequence([resultMessages[0]]) : void 0;
|
|
105015
|
-
const beforeFirst = beforeFirstSequence?.hash ?? null;
|
|
105016
|
-
const afterFirst = afterFirstSequence?.hash ?? null;
|
|
105017
|
-
const firstMessageHashTruncated = beforeFirstSequence?.truncated === true || beforeFirstSequence?.contentTruncated === true || afterFirstSequence?.truncated === true || afterFirstSequence?.contentTruncated === true;
|
|
105018
|
-
const prefixHashTruncated = beforePrefix.truncated || afterPrefix.truncated || beforePrefix.contentTruncated || afterPrefix.contentTruncated;
|
|
105019
|
-
const prefixObservation = resolvePrefixObservation(prefixHashTruncated, args.prefixObservation);
|
|
105020
105772
|
const sizes = measureInjectedMessages(injectedMessages);
|
|
105773
|
+
const sourceBreakdown = injectionSlices.map((slice) => {
|
|
105774
|
+
const sliceSize = measureInjectedMessages(slice.messages);
|
|
105775
|
+
return {
|
|
105776
|
+
source: slice.source,
|
|
105777
|
+
messageCount: Math.min(slice.messages.length, MAX_REPORTED_MESSAGES),
|
|
105778
|
+
chars: sliceSize.chars,
|
|
105779
|
+
bytes: sliceSize.bytes,
|
|
105780
|
+
estimatedTokens: estimateTokens2(sliceSize.chars),
|
|
105781
|
+
countsCapped: sliceSize.capped
|
|
105782
|
+
};
|
|
105783
|
+
});
|
|
105021
105784
|
const messageCountCapped = existingMessages.length > MAX_REPORTED_MESSAGES || resultMessages.length > MAX_REPORTED_MESSAGES;
|
|
105785
|
+
recordContextAttribution(sessionKey(args.sessionId), existingMessages, sizes);
|
|
105022
105786
|
logLatency({
|
|
105023
105787
|
type: "phase",
|
|
105024
105788
|
filePath: "<pi-lens>",
|
|
@@ -105032,34 +105796,25 @@ function observeCacheContext(args) {
|
|
|
105032
105796
|
sessionRole: args.sessionRole,
|
|
105033
105797
|
...args.sessionRole === "concurrent-secondary" ? { turnScope: SECONDARY_TURN_SCOPE } : { turnIndex: args.turnIndex, turnScope: PROCESS_TURN_SCOPE },
|
|
105034
105798
|
injectionEnabled: args.injectionEnabled,
|
|
105035
|
-
injectionSources:
|
|
105799
|
+
injectionSources: sourceBreakdown.map((entry) => entry.source),
|
|
105800
|
+
injectionSourceBreakdown: sourceBreakdown,
|
|
105801
|
+
injectionOccurred: injectedMessages.length > 0,
|
|
105036
105802
|
injectedMessageCount: Math.min(injectedMessages.length, MAX_REPORTED_MESSAGES),
|
|
105037
105803
|
injectedMessageCountCapped: injectedMessages.length > MAX_REPORTED_MESSAGES,
|
|
105038
105804
|
injectedChars: sizes.chars,
|
|
105039
105805
|
injectedBytes: sizes.bytes,
|
|
105806
|
+
injectedEstimatedTokens: estimateTokens2(sizes.chars),
|
|
105807
|
+
injectedTokenBasis: "chars-per-token-4-estimate-not-provider-measured",
|
|
105040
105808
|
injectedCountsCapped: sizes.capped,
|
|
105041
105809
|
existingMessageCount: Math.min(existingMessages.length, MAX_REPORTED_MESSAGES),
|
|
105042
105810
|
resultMessageCount: Math.min(resultMessages.length, MAX_REPORTED_MESSAGES),
|
|
105043
105811
|
messageCountCapped,
|
|
105044
105812
|
placement,
|
|
105045
|
-
prefixObservation,
|
|
105046
|
-
prefixObservationUnknown: prefixObservation === "unknown",
|
|
105047
|
-
prefixBaseline: prefixBaselineForObservation(prefixObservation),
|
|
105048
|
-
firstMessageChanged: firstMessageHashTruncated ? null : beforeFirst !== afterFirst,
|
|
105049
|
-
firstMessageChange: firstMessageChangeFor(firstMessageHashTruncated, beforeFirst, afterFirst),
|
|
105050
|
-
firstMessageHashTruncated,
|
|
105051
|
-
beforeFirstMessageHash: beforeFirst,
|
|
105052
|
-
afterFirstMessageHash: afterFirst,
|
|
105053
105813
|
beforeSequenceHash: beforeSequence.hash,
|
|
105054
105814
|
afterSequenceHash: afterSequence.hash,
|
|
105055
|
-
beforePrefixHash: beforePrefix.hash,
|
|
105056
|
-
afterPrefixHash: afterPrefix.hash,
|
|
105057
105815
|
sequenceHashTruncated: beforeSequence.truncated || afterSequence.truncated || beforeSequence.contentTruncated || afterSequence.contentTruncated,
|
|
105058
105816
|
sequenceMessageCountTruncated: beforeSequence.truncated || afterSequence.truncated,
|
|
105059
|
-
sequenceContentHashTruncated: beforeSequence.contentTruncated || afterSequence.contentTruncated
|
|
105060
|
-
prefixHashTruncated,
|
|
105061
|
-
prefixMessageCountTruncated: beforePrefix.truncated || afterPrefix.truncated,
|
|
105062
|
-
prefixContentHashTruncated: beforePrefix.contentTruncated || afterPrefix.contentTruncated
|
|
105817
|
+
sequenceContentHashTruncated: beforeSequence.contentTruncated || afterSequence.contentTruncated
|
|
105063
105818
|
}
|
|
105064
105819
|
});
|
|
105065
105820
|
} catch (err) {
|
|
@@ -105077,6 +105832,34 @@ function logCacheUsage(message, dbg2, context) {
|
|
|
105077
105832
|
if (!usage || typeof usage !== "object")
|
|
105078
105833
|
return;
|
|
105079
105834
|
const u = usage;
|
|
105835
|
+
const attributionKey = sessionKey(context?.sessionId);
|
|
105836
|
+
const state2 = attributionFor(attributionKey);
|
|
105837
|
+
const nowMs = Date.now();
|
|
105838
|
+
const gap = resolveInterTurnGap(state2, nowMs);
|
|
105839
|
+
const interTurnGapMs = gap.gapMs;
|
|
105840
|
+
const ttlMs = getProviderCacheTtlMs();
|
|
105841
|
+
const estimatedNewTokens = estimateTokens2(state2.injectedCharsSinceLastUsage + state2.newTranscriptCharsSinceLastUsage);
|
|
105842
|
+
const verdict = classifyCacheMiss({
|
|
105843
|
+
cacheRead: u.cacheRead,
|
|
105844
|
+
input: typeof u.input === "number" ? u.input : 0,
|
|
105845
|
+
priorCacheRead: state2.lastCacheRead,
|
|
105846
|
+
interTurnGapMs,
|
|
105847
|
+
ttlMs,
|
|
105848
|
+
prefixBroke: state2.prefixBrokeSinceLastUsage,
|
|
105849
|
+
estimatedNewTokens,
|
|
105850
|
+
attributionCharsCapped: state2.attributionCharsCapped
|
|
105851
|
+
});
|
|
105852
|
+
const priorCacheRead = typeof state2.lastCacheRead === "number" ? state2.lastCacheRead : null;
|
|
105853
|
+
const injectedCharsSinceLastTurn = state2.injectedCharsSinceLastUsage;
|
|
105854
|
+
const newTranscriptCharsSinceLastTurn = state2.newTranscriptCharsSinceLastUsage;
|
|
105855
|
+
const attributionCharsCapped = state2.attributionCharsCapped;
|
|
105856
|
+
state2.lastUsageAtMs = nowMs;
|
|
105857
|
+
state2.lastCacheRead = typeof u.cacheRead === "number" && Number.isFinite(u.cacheRead) ? u.cacheRead : void 0;
|
|
105858
|
+
state2.prefixBrokeSinceLastUsage = false;
|
|
105859
|
+
state2.injectedCharsSinceLastUsage = 0;
|
|
105860
|
+
state2.newTranscriptCharsSinceLastUsage = 0;
|
|
105861
|
+
state2.attributionCharsCapped = false;
|
|
105862
|
+
state2.lastContextAtMs = void 0;
|
|
105080
105863
|
logLatency({
|
|
105081
105864
|
type: "phase",
|
|
105082
105865
|
filePath: "<pi-lens>",
|
|
@@ -105091,6 +105874,20 @@ function logCacheUsage(message, dbg2, context) {
|
|
|
105091
105874
|
output: u.output,
|
|
105092
105875
|
// `Usage.cost` is a breakdown object; the total is the headline number.
|
|
105093
105876
|
cost: u.cost?.total,
|
|
105877
|
+
// Idle milliseconds before this turn's request, or null for the first
|
|
105878
|
+
// record in the session. This is the field the 2026-08-21
|
|
105879
|
+
// investigation had to reconstruct by hand-joining timestamps.
|
|
105880
|
+
interTurnGapMs,
|
|
105881
|
+
gapBasis: gap.basis,
|
|
105882
|
+
// null means "nothing to explain", not "cause unknown"; `unknown` is
|
|
105883
|
+
// the explicit no-local-explanation verdict.
|
|
105884
|
+
cacheMissCause: verdict?.cause ?? null,
|
|
105885
|
+
cacheMissKind: verdict?.kind ?? null,
|
|
105886
|
+
cacheTtlThresholdMs: ttlMs,
|
|
105887
|
+
priorCacheRead,
|
|
105888
|
+
injectedCharsSinceLastTurn,
|
|
105889
|
+
newTranscriptCharsSinceLastTurn,
|
|
105890
|
+
attributionCharsCapped,
|
|
105094
105891
|
...context ? {
|
|
105095
105892
|
// MessageEndEvent has no request/context id in the host API. These
|
|
105096
105893
|
// fields permit session correlation without inventing an exact
|
|
@@ -105158,6 +105955,7 @@ function observeCachePrefix(messages, turnIndex, sessionId, sessionRole, dbg2) {
|
|
|
105158
105955
|
return "baseline";
|
|
105159
105956
|
}
|
|
105160
105957
|
if (currentHash !== previousHash) {
|
|
105958
|
+
attributionFor(key2).prefixBrokeSinceLastUsage = true;
|
|
105161
105959
|
logLatency({
|
|
105162
105960
|
type: "phase",
|
|
105163
105961
|
filePath: "<pi-lens>",
|
|
@@ -105182,6 +105980,7 @@ function observeCachePrefix(messages, turnIndex, sessionId, sessionRole, dbg2) {
|
|
|
105182
105980
|
function clearCachePrefixSession(sessionId) {
|
|
105183
105981
|
const key2 = sessionKey(sessionId);
|
|
105184
105982
|
prefixHashBySession.delete(key2);
|
|
105983
|
+
attributionBySession.delete(key2);
|
|
105185
105984
|
}
|
|
105186
105985
|
|
|
105187
105986
|
// dist/clients/startup-timing.js
|
|
@@ -105478,9 +106277,6 @@ logLatency({
|
|
|
105478
106277
|
});
|
|
105479
106278
|
function log(_msg) {
|
|
105480
106279
|
}
|
|
105481
|
-
function isStaleExtensionCtxError(err) {
|
|
105482
|
-
return err instanceof Error && err.message.includes("stale after session replacement or reload");
|
|
105483
|
-
}
|
|
105484
106280
|
var runtime = new RuntimeCoordinator();
|
|
105485
106281
|
var _readBridgeRegistered = false;
|
|
105486
106282
|
var _readBridgeGetFlag;
|
|
@@ -106139,7 +106935,7 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106139
106935
|
skillPaths: [skillsDir]
|
|
106140
106936
|
};
|
|
106141
106937
|
});
|
|
106142
|
-
pi.on("session_start", async (event, ctx) => {
|
|
106938
|
+
pi.on("session_start", wrapSessionEventHandler("session_start", async (event, ctx) => {
|
|
106143
106939
|
const sessionStartMonotonicAt = performance4.now();
|
|
106144
106940
|
resetVerifiedPathAttributionGuessCount();
|
|
106145
106941
|
warmDispatchAtSessionStart();
|
|
@@ -106314,10 +107110,12 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106314
107110
|
mountLensWidget(ctx.ui, readExtensionMode(ctx));
|
|
106315
107111
|
}
|
|
106316
107112
|
} catch (sessionErr) {
|
|
107113
|
+
if (isStaleExtensionCtxError(sessionErr))
|
|
107114
|
+
throw sessionErr;
|
|
106317
107115
|
dbg(`session_start crashed: ${sessionErr}`);
|
|
106318
107116
|
dbg(`session_start crash stack: ${sessionErr.stack}`);
|
|
106319
107117
|
}
|
|
106320
|
-
});
|
|
107118
|
+
}, { dbg }));
|
|
106321
107119
|
pi.on("session_before_fork", () => {
|
|
106322
107120
|
try {
|
|
106323
107121
|
pendingForkSnapshot = exportWidgetState();
|
|
@@ -106341,7 +107139,7 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106341
107139
|
resetLSPService
|
|
106342
107140
|
});
|
|
106343
107141
|
});
|
|
106344
|
-
|
|
107142
|
+
const onToolResult = async (event, ctx) => {
|
|
106345
107143
|
rememberOwnEventCtx(ctx);
|
|
106346
107144
|
if (!lensEnabled)
|
|
106347
107145
|
return;
|
|
@@ -106382,8 +107180,9 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106382
107180
|
} finally {
|
|
106383
107181
|
setAmbientAbortSignal(void 0);
|
|
106384
107182
|
}
|
|
106385
|
-
}
|
|
106386
|
-
pi.on("
|
|
107183
|
+
};
|
|
107184
|
+
pi.on("tool_result", wrapSessionEventHandler("tool_result", onToolResult, { dbg }));
|
|
107185
|
+
const onTurnStart = (_event, ctx) => {
|
|
106387
107186
|
rememberOwnEventCtx(ctx);
|
|
106388
107187
|
adoptProjectTrustFromPorts(hostPorts);
|
|
106389
107188
|
if (lensWidgetVisible && ctx?.ui && (mountedLensWidgetUi === void 0 || mountedLensWidgetUi !== ctx.ui)) {
|
|
@@ -106400,7 +107199,8 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106400
107199
|
}).catch((err) => {
|
|
106401
107200
|
dbg(`turn_start: cross-process nudge read failed: ${err}`);
|
|
106402
107201
|
});
|
|
106403
|
-
}
|
|
107202
|
+
};
|
|
107203
|
+
pi.on("turn_start", wrapSessionEventHandler("turn_start", onTurnStart, { dbg }));
|
|
106404
107204
|
async function runDeferredMutationDrain(ctx) {
|
|
106405
107205
|
const currentSessionId = getStableSessionId(ctx);
|
|
106406
107206
|
const emission = classifyCurrentSessionEmission(ctx, currentSessionId);
|
|
@@ -106434,25 +107234,28 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106434
107234
|
updateLspStatus(ctx.ui.setStatus, ctx.ui.theme);
|
|
106435
107235
|
}
|
|
106436
107236
|
}
|
|
106437
|
-
|
|
107237
|
+
const onAgentEnd = async (_event, ctx) => {
|
|
106438
107238
|
if (!lensEnabled)
|
|
106439
107239
|
return;
|
|
106440
|
-
setAmbientAbortSignal(ctx?.signal);
|
|
106441
107240
|
try {
|
|
107241
|
+
setAmbientAbortSignal(ctx?.signal);
|
|
106442
107242
|
await flushDebouncedToolResults();
|
|
106443
107243
|
ctx.ui && updateLspStatus(ctx.ui.setStatus, ctx.ui.theme);
|
|
106444
107244
|
} catch (agentEndErr) {
|
|
107245
|
+
if (isStaleExtensionCtxError(agentEndErr))
|
|
107246
|
+
throw agentEndErr;
|
|
106445
107247
|
dbg(`agent_end crashed: ${agentEndErr}`);
|
|
106446
107248
|
dbg(`agent_end crash stack: ${agentEndErr.stack}`);
|
|
106447
107249
|
} finally {
|
|
106448
107250
|
setAmbientAbortSignal(void 0);
|
|
106449
107251
|
}
|
|
106450
|
-
}
|
|
106451
|
-
pi.on("
|
|
107252
|
+
};
|
|
107253
|
+
pi.on("agent_end", wrapSessionEventHandler("agent_end", onAgentEnd, { dbg }));
|
|
107254
|
+
const onTurnEnd = async (_event, ctx) => {
|
|
106452
107255
|
if (!lensEnabled)
|
|
106453
107256
|
return;
|
|
106454
|
-
setAmbientAbortSignal(ctx?.signal);
|
|
106455
107257
|
try {
|
|
107258
|
+
setAmbientAbortSignal(ctx?.signal);
|
|
106456
107259
|
const repaintLspStatus = captureLspStatusRepaint(ctx);
|
|
106457
107260
|
const elStats = getEventLoopStats();
|
|
106458
107261
|
const loopMaxMs = elStats?.maxMs ?? 0;
|
|
@@ -106551,12 +107354,15 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106551
107354
|
);
|
|
106552
107355
|
}
|
|
106553
107356
|
} catch (turnEndErr) {
|
|
107357
|
+
if (isStaleExtensionCtxError(turnEndErr))
|
|
107358
|
+
throw turnEndErr;
|
|
106554
107359
|
dbg(`turn_end crashed: ${turnEndErr}`);
|
|
106555
107360
|
dbg(`turn_end crash stack: ${turnEndErr.stack}`);
|
|
106556
107361
|
} finally {
|
|
106557
107362
|
setAmbientAbortSignal(void 0);
|
|
106558
107363
|
}
|
|
106559
|
-
}
|
|
107364
|
+
};
|
|
107365
|
+
pi.on("turn_end", wrapSessionEventHandler("turn_end", onTurnEnd, { dbg }));
|
|
106560
107366
|
registerBuiltinQuietWindowTasks(() => runtime);
|
|
106561
107367
|
registerCascadeTierReconcileTask(() => getLSPService(), {
|
|
106562
107368
|
onResolvedFound: ({ filePath, diagnostics }) => {
|
|
@@ -106644,27 +107450,36 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106644
107450
|
});
|
|
106645
107451
|
});
|
|
106646
107452
|
}
|
|
106647
|
-
|
|
106648
|
-
|
|
106649
|
-
|
|
106650
|
-
|
|
107453
|
+
const onAgentSettled = async (_event, ctx) => {
|
|
107454
|
+
if (!lensEnabled)
|
|
107455
|
+
return;
|
|
107456
|
+
try {
|
|
106651
107457
|
setAmbientAbortSignal(ctx?.signal);
|
|
106652
107458
|
try {
|
|
106653
107459
|
await runDeferredMutationDrain(ctx);
|
|
106654
107460
|
} catch (drainErr) {
|
|
107461
|
+
if (isStaleExtensionCtxError(drainErr))
|
|
107462
|
+
throw drainErr;
|
|
106655
107463
|
dbg(`agent_settled deferred_mutation_drain crashed: ${drainErr}`);
|
|
106656
107464
|
} finally {
|
|
106657
107465
|
setAmbientAbortSignal(void 0);
|
|
106658
107466
|
}
|
|
107467
|
+
const cwd = ctx?.cwd;
|
|
106659
107468
|
void runQuietWindow({
|
|
106660
107469
|
runtime,
|
|
106661
107470
|
dbg,
|
|
106662
|
-
cwd
|
|
107471
|
+
cwd
|
|
106663
107472
|
}).catch((err) => {
|
|
106664
107473
|
dbg(`quiet_window crashed: ${err}`);
|
|
106665
107474
|
});
|
|
106666
107475
|
dumpActiveHandles("agent_settled");
|
|
106667
|
-
})
|
|
107476
|
+
} catch (settledErr) {
|
|
107477
|
+
setAmbientAbortSignal(void 0);
|
|
107478
|
+
throw settledErr;
|
|
107479
|
+
}
|
|
107480
|
+
};
|
|
107481
|
+
try {
|
|
107482
|
+
pi.on("agent_settled", wrapSessionEventHandler("agent_settled", onAgentSettled, { dbg }));
|
|
106668
107483
|
} catch (registerErr) {
|
|
106669
107484
|
dbg(`agent_settled registration failed (older pi host?): ${registerErr}`);
|
|
106670
107485
|
}
|
|
@@ -106719,89 +107534,105 @@ ${degradations.map((group) => ` ${group.kind}: ${group.count} (${group.latestRe
|
|
|
106719
107534
|
return true;
|
|
106720
107535
|
return !msg.content.some((block) => typeof block === "object" && block !== null && block.type === "tool_result");
|
|
106721
107536
|
};
|
|
106722
|
-
pi.on(
|
|
106723
|
-
|
|
106724
|
-
|
|
106725
|
-
|
|
106726
|
-
|
|
106727
|
-
|
|
106728
|
-
|
|
106729
|
-
|
|
106730
|
-
|
|
106731
|
-
|
|
106732
|
-
|
|
106733
|
-
|
|
106734
|
-
|
|
106735
|
-
|
|
106736
|
-
|
|
106737
|
-
|
|
106738
|
-
|
|
106739
|
-
|
|
106740
|
-
|
|
106741
|
-
|
|
106742
|
-
|
|
106743
|
-
|
|
106744
|
-
|
|
106745
|
-
|
|
106746
|
-
|
|
106747
|
-
|
|
106748
|
-
|
|
106749
|
-
|
|
106750
|
-
|
|
106751
|
-
|
|
106752
|
-
}
|
|
106753
|
-
|
|
106754
|
-
|
|
106755
|
-
|
|
106756
|
-
|
|
106757
|
-
|
|
106758
|
-
|
|
106759
|
-
|
|
106760
|
-
|
|
106761
|
-
|
|
106762
|
-
|
|
106763
|
-
|
|
106764
|
-
|
|
106765
|
-
|
|
106766
|
-
|
|
106767
|
-
|
|
106768
|
-
|
|
106769
|
-
|
|
106770
|
-
|
|
106771
|
-
|
|
106772
|
-
|
|
106773
|
-
|
|
106774
|
-
|
|
106775
|
-
|
|
106776
|
-
|
|
106777
|
-
|
|
106778
|
-
|
|
106779
|
-
|
|
107537
|
+
pi.on(
|
|
107538
|
+
"context",
|
|
107539
|
+
// #1929: `context` is reachable with a ctx the SDK already invalidated,
|
|
107540
|
+
// exactly like the five handlers #1925 wrapped. It could not use the void
|
|
107541
|
+
// wrapper because the host CONSUMES its return value on the live path, so
|
|
107542
|
+
// it uses the value-returning variant and states its own stale-path answer
|
|
107543
|
+
// below. Before this, a stale ctx surfaced as `context event error: …`,
|
|
107544
|
+
// indistinguishable from a real handler bug, and counted nothing.
|
|
107545
|
+
wrapSessionEventHandlerWithResult("context", async (event, ctx) => {
|
|
107546
|
+
const existingMessages = event?.messages ?? [];
|
|
107547
|
+
const prefixSessionId = getStableSessionId(ctx);
|
|
107548
|
+
const sessionRole = classifyCurrentSessionEmission(ctx, prefixSessionId);
|
|
107549
|
+
observeCachePrefix(existingMessages, runtime.turnIndex, prefixSessionId, sessionRole, dbg);
|
|
107550
|
+
const effectiveInjectionEnabled = lensEnabled && contextInjectionEnabled;
|
|
107551
|
+
let telemetryLogged = false;
|
|
107552
|
+
const logContextObservation = (resultMessages, placement, injectionSlices) => {
|
|
107553
|
+
if (telemetryLogged)
|
|
107554
|
+
return;
|
|
107555
|
+
telemetryLogged = true;
|
|
107556
|
+
observeCacheContext({
|
|
107557
|
+
existingMessages,
|
|
107558
|
+
resultMessages,
|
|
107559
|
+
sessionId: prefixSessionId,
|
|
107560
|
+
sessionRole,
|
|
107561
|
+
turnIndex: runtime.turnIndex,
|
|
107562
|
+
injectionEnabled: effectiveInjectionEnabled,
|
|
107563
|
+
injectionSlices,
|
|
107564
|
+
placement,
|
|
107565
|
+
dbg
|
|
107566
|
+
});
|
|
107567
|
+
};
|
|
107568
|
+
try {
|
|
107569
|
+
const cwd = ctx.cwd ?? process.cwd();
|
|
107570
|
+
if (!effectiveInjectionEnabled) {
|
|
107571
|
+
logContextObservation(existingMessages, "none", []);
|
|
107572
|
+
return;
|
|
107573
|
+
}
|
|
107574
|
+
const turnEndFindings = consumeTurnEndFindings(cacheManager, cwd, runtime);
|
|
107575
|
+
const sessionGuidance = consumeSessionStartGuidance(cacheManager, cwd);
|
|
107576
|
+
const testFindings = consumeTestFindings(cacheManager, cwd, runtime);
|
|
107577
|
+
const agentNudge = consumeAgentNudge(dbg);
|
|
107578
|
+
const sourceMessages = [
|
|
107579
|
+
{
|
|
107580
|
+
source: "session-guidance",
|
|
107581
|
+
messages: sessionGuidance?.messages ?? []
|
|
107582
|
+
},
|
|
107583
|
+
{
|
|
107584
|
+
source: "turn-findings",
|
|
107585
|
+
messages: turnEndFindings?.messages ?? []
|
|
107586
|
+
},
|
|
107587
|
+
{
|
|
107588
|
+
source: "test-findings",
|
|
107589
|
+
messages: testFindings?.messages ?? []
|
|
107590
|
+
},
|
|
107591
|
+
{
|
|
107592
|
+
source: "agent-nudge",
|
|
107593
|
+
messages: agentNudge?.messages ?? []
|
|
107594
|
+
}
|
|
107595
|
+
].filter((source) => source.messages.length > 0);
|
|
107596
|
+
const injectedMessages = sourceMessages.flatMap((source) => source.messages);
|
|
107597
|
+
if (injectedMessages.length === 0) {
|
|
107598
|
+
logContextObservation(existingMessages, "none", []);
|
|
107599
|
+
return;
|
|
107600
|
+
}
|
|
107601
|
+
if (existingMessages.length === 0) {
|
|
107602
|
+
const resultMessages2 = [...injectedMessages];
|
|
107603
|
+
logContextObservation(resultMessages2, "prepend", sourceMessages);
|
|
107604
|
+
return { messages: resultMessages2 };
|
|
107605
|
+
}
|
|
107606
|
+
const lastMessage = existingMessages[existingMessages.length - 1];
|
|
107607
|
+
if (!isPlainUserPrompt(lastMessage)) {
|
|
107608
|
+
const resultMessages2 = [...existingMessages, ...injectedMessages];
|
|
107609
|
+
logContextObservation(resultMessages2, "append", sourceMessages);
|
|
107610
|
+
return { messages: resultMessages2 };
|
|
107611
|
+
}
|
|
107612
|
+
const resultMessages = [
|
|
107613
|
+
...existingMessages.slice(0, -1),
|
|
107614
|
+
...injectedMessages,
|
|
107615
|
+
lastMessage
|
|
107616
|
+
];
|
|
107617
|
+
logContextObservation(resultMessages, "insert-before-final", sourceMessages);
|
|
107618
|
+
return { messages: resultMessages };
|
|
107619
|
+
} catch (err) {
|
|
107620
|
+
if (isStaleExtensionCtxError(err))
|
|
107621
|
+
throw err;
|
|
107622
|
+
if (!telemetryLogged)
|
|
107623
|
+
logContextObservation(existingMessages, "none", []);
|
|
107624
|
+
dbg(`context event error: ${err}`);
|
|
106780
107625
|
}
|
|
106781
|
-
|
|
106782
|
-
|
|
106783
|
-
|
|
106784
|
-
|
|
106785
|
-
|
|
106786
|
-
|
|
106787
|
-
|
|
106788
|
-
|
|
106789
|
-
|
|
106790
|
-
|
|
106791
|
-
}
|
|
106792
|
-
const resultMessages = [
|
|
106793
|
-
...existingMessages.slice(0, -1),
|
|
106794
|
-
...injectedMessages,
|
|
106795
|
-
lastMessage
|
|
106796
|
-
];
|
|
106797
|
-
logContextObservation(resultMessages, "insert-before-final", injectionSources, injectedMessages);
|
|
106798
|
-
return { messages: resultMessages };
|
|
106799
|
-
} catch (err) {
|
|
106800
|
-
if (!telemetryLogged)
|
|
106801
|
-
logContextObservation(existingMessages, "none", [], []);
|
|
106802
|
-
dbg(`context event error: ${err}`);
|
|
106803
|
-
}
|
|
106804
|
-
});
|
|
107626
|
+
}, {
|
|
107627
|
+
dbg,
|
|
107628
|
+
// #1929: a dead ctx means pi-lens contributes NOTHING to this
|
|
107629
|
+
// request. `undefined` is that answer, and is what the four
|
|
107630
|
+
// non-injecting paths above already return, so the host keeps its
|
|
107631
|
+
// own message list byte-for-byte. Never a half-built injection: the
|
|
107632
|
+
// consume* calls that feed one have side effects and may not have run.
|
|
107633
|
+
onStaleResult: () => void 0
|
|
107634
|
+
})
|
|
107635
|
+
);
|
|
106805
107636
|
}
|
|
106806
107637
|
function index_default(pi) {
|
|
106807
107638
|
return runInConsoleCaptureWindow(() => activateExtension(pi));
|