@mrclrchtr/supi-code-intelligence 6.2.0 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +2 -0
  2. package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  3. package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  4. package/node_modules/@mrclrchtr/supi-lsp/README.md +2 -0
  5. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  6. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  7. package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/README.md +52 -0
  8. package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/index.js +785 -129
  9. package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/legacy.js +660 -98
  10. package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/package.json +10 -4
  11. package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -3
  12. package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +16 -2
  13. package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sentinels.ts +4 -32
  14. package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sources.ts +108 -0
  15. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-process-crash-report.ts +106 -0
  16. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +4 -4
  17. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +513 -113
  18. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +43 -15
  19. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +40 -33
  20. package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +36 -6
  21. package/node_modules/@mrclrchtr/supi-lsp/src/summary.ts +1 -1
  22. package/node_modules/@mrclrchtr/supi-lsp/src/workspace-path-policy.ts +18 -9
  23. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  24. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  25. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/README.md +29 -1
  26. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.cjs +99 -19
  27. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.cjs.map +4 -4
  28. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.js +94 -18
  29. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.js.map +4 -4
  30. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm +0 -0
  31. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm.map +14 -14
  32. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/package.json +13 -8
  33. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.cjs +97 -19
  34. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.cjs.map +4 -4
  35. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.cts +28 -8
  36. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.cts.map +1 -1
  37. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.ts +28 -8
  38. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.ts.map +1 -1
  39. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.js +92 -18
  40. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.js.map +4 -4
  41. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm +0 -0
  42. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm.map +17 -17
  43. package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +7 -4
  44. package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/kotlin/tree-sitter-kotlin.wasm +0 -0
  45. package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/kotlin/tree-sitter-kotlin.wasm.json +2 -2
  46. package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/sql/tree-sitter-sql.wasm +0 -0
  47. package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/sql/tree-sitter-sql.wasm.json +2 -2
  48. package/package.json +5 -5
  49. package/src/session/health-refresh.ts +19 -12
  50. package/src/session/health-types.ts +8 -3
  51. package/src/session/health-workflow.ts +7 -3
  52. package/src/session/session.ts +12 -5
  53. package/src/substrate/lsp/maintenance.ts +53 -47
  54. package/src/substrate/lsp/settings.ts +2 -1
  55. package/src/substrate/lsp/source-tracking.ts +247 -0
  56. package/src/tool/code_find/guidance.ts +3 -3
  57. package/src/tool/code_graph/guidance.ts +2 -2
  58. package/src/tool/code_health/guidance.ts +3 -3
  59. package/src/tool/code_health/markdown.ts +21 -5
  60. package/src/tool/code_health/refresh-outcome.ts +48 -7
  61. package/src/tool/code_health/refresh-status.ts +83 -16
  62. package/src/tool/code_health/tui.ts +4 -0
  63. package/src/tool/code_inspect/guidance.ts +5 -3
  64. package/src/tool/code_orientation/guidance.ts +3 -4
  65. package/src/tool/code_refactor_apply/guidance.ts +1 -1
  66. package/src/tool/code_refactor_plan/guidance.ts +3 -5
  67. package/src/tool/code_resolve/guidance.ts +3 -3
  68. package/src/tool/guidance.ts +11 -9
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-tree-sitter",
3
- "version": "6.2.0",
3
+ "version": "6.4.0",
4
4
  "description": "Structural AST analysis for SuPi code intelligence",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -30,13 +30,14 @@
30
30
  "src/**/*.mjs",
31
31
  "src/**/*.json",
32
32
  "resources",
33
+ "!resources/**/.supi-wasm-*",
33
34
  "!__tests__"
34
35
  ],
35
36
  "dependencies": {
36
37
  "jiti": "^2.7.0",
37
- "web-tree-sitter": "^0.26.8",
38
- "@mrclrchtr/supi-code-runtime": "6.2.0",
39
- "@mrclrchtr/supi-core": "6.2.0"
38
+ "web-tree-sitter": "^0.27.0",
39
+ "@mrclrchtr/supi-code-runtime": "6.4.0",
40
+ "@mrclrchtr/supi-core": "6.4.0"
40
41
  },
41
42
  "bundledDependencies": [
42
43
  "@mrclrchtr/supi-code-runtime",
@@ -53,6 +54,8 @@
53
54
  "bench:structural": "vitest bench __tests__/benchmark/structural-baseline.bench.ts --run",
54
55
  "vendor:wasm": "node scripts/vendor-wasm.mjs",
55
56
  "check:wasm": "node scripts/vendor-wasm.mjs --check",
57
+ "check:all-wasm": "node scripts/check-all-wasm.mjs",
58
+ "generate:all-wasm": "node scripts/generate-all-wasm.mjs",
56
59
  "generate:kotlin-wasm": "node scripts/generate-kotlin-wasm.mjs",
57
60
  "check:kotlin-wasm": "node scripts/generate-kotlin-wasm.mjs --check",
58
61
  "generate:sql-wasm": "node scripts/generate-sql-wasm.mjs",
@@ -6,7 +6,7 @@
6
6
  "releaseAsset": "https://github.com/fwcd/tree-sitter-kotlin/releases/download/0.3.8/tree-sitter-kotlin.wasm"
7
7
  },
8
8
  "generatedWith": {
9
- "treeSitterCli": "0.26.13"
9
+ "treeSitterCli": "0.27.0"
10
10
  },
11
- "sha256": "e08447e36ad5d86f39f91f13defce0636aea1490b8d65dafde6fa72649422061"
11
+ "sha256": "7f522f2e3ef633735b3e2bdea165071b5ad0a99d6201e84acab49017590f812a"
12
12
  }
@@ -5,9 +5,9 @@
5
5
  "repository": "https://github.com/derekstride/tree-sitter-sql"
6
6
  },
7
7
  "generatedWith": {
8
- "treeSitterCli": "0.26.13"
8
+ "treeSitterCli": "0.27.0"
9
9
  },
10
- "sha256": "9b93a15dc3eade66df4347731f2687b939daf987c8382660d6118e863604ab09",
10
+ "sha256": "e03fb5079e88cfe0807056c284fd2b0589cee35df9bbb3d07e72f2f4178de8de",
11
11
  "trust": {
12
12
  "note": "The @derekstride/tree-sitter-sql npm package is a devDependency only. It is never resolved at runtime; the vendored WASM above is the sole runtime artifact. This workspace explicitly disables the package's npx-based install script via pnpm allowBuilds. The WASM was built locally from the installed package source. See scripts/generate-sql-wasm.mjs for the rebuild procedure.",
13
13
  "alternativesConsidered": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-code-intelligence",
3
- "version": "6.2.0",
3
+ "version": "6.4.0",
4
4
  "description": "LSP and AST navigation, search, diagnostics, and refactoring",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,10 +35,10 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "yaml": "^2.9.0",
38
- "@mrclrchtr/supi-code-runtime": "6.2.0",
39
- "@mrclrchtr/supi-tree-sitter": "6.2.0",
40
- "@mrclrchtr/supi-lsp": "6.2.0",
41
- "@mrclrchtr/supi-core": "6.2.0"
38
+ "@mrclrchtr/supi-lsp": "6.4.0",
39
+ "@mrclrchtr/supi-tree-sitter": "6.4.0",
40
+ "@mrclrchtr/supi-code-runtime": "6.4.0",
41
+ "@mrclrchtr/supi-core": "6.4.0"
42
42
  },
43
43
  "bundledDependencies": [
44
44
  "@mrclrchtr/supi-code-runtime",
@@ -3,13 +3,14 @@ import {
3
3
  isCodeRequestInterruption,
4
4
  } from "@mrclrchtr/supi-code-runtime/api";
5
5
  import {
6
- emptyProcessCrashRecoverySummary,
6
+ emptyProcessCrashRecoveryReport,
7
7
  type WorkspaceDiagnosticReport,
8
8
  type WorkspaceLspRuntime,
9
9
  } from "@mrclrchtr/supi-lsp/api";
10
10
  import { recoverDiagnosticRuntime } from "../analysis/health/recovery.ts";
11
11
  import { mergeDiagnosticEvidence } from "../diagnostics/evidence.ts";
12
12
  import { refreshFileLspMaintenance, refreshLspMaintenance } from "../substrate/lsp/maintenance.ts";
13
+ import type { LspMaintenanceState } from "../substrate/lsp/source-tracking.ts";
13
14
  import type {
14
15
  HealthDiagnosticScope,
15
16
  HealthFileReadiness,
@@ -21,13 +22,15 @@ interface HealthRefreshAttemptOptions {
21
22
  readonly diagnosticsScope: HealthDiagnosticScope;
22
23
  readonly attemptedAt: number;
23
24
  readonly cwd: string;
24
- readonly sentinelSnapshot: Map<string, number>;
25
+ readonly maintenanceState: LspMaintenanceState;
25
26
  readonly control?: CodeRequestControl;
26
27
  readonly reportRecoveryProgress?: () => void;
27
28
  }
28
29
 
29
30
  export interface HealthRefreshCollection {
30
31
  readonly attempt: HealthRefreshAttempt;
32
+ /** Next typed maintenance state, committed only after the attempt returns. */
33
+ readonly maintenanceState: LspMaintenanceState;
31
34
  /** Final report from the runtime, retained only for the current workflow. */
32
35
  readonly diagnosticReport?: WorkspaceDiagnosticReport;
33
36
  }
@@ -49,11 +52,10 @@ async function collectFileRefreshAttempt(
49
52
  const maintenance = await refreshFileLspMaintenance({
50
53
  runtime: options.runtime,
51
54
  cwd: options.cwd,
52
- sentinelSnapshot: options.sentinelSnapshot,
55
+ maintenanceState: options.maintenanceState,
53
56
  filePath: scope.path,
54
57
  control: options.control,
55
58
  });
56
- updateSentinelSnapshot(options.sentinelSnapshot, maintenance.snapshot);
57
59
  const readiness = await options.runtime.waitUntilReadyForFile(
58
60
  scope.path,
59
61
  undefined,
@@ -62,6 +64,7 @@ async function collectFileRefreshAttempt(
62
64
  const fileReadiness: HealthFileReadiness =
63
65
  readiness.kind === "ready" ? "ready" : readiness.kind === "timeout" ? "pending" : "unavailable";
64
66
  return {
67
+ maintenanceState: maintenance.maintenanceState,
65
68
  attempt: {
66
69
  kind: "completed",
67
70
  attemptedAt: options.attemptedAt,
@@ -71,7 +74,7 @@ async function collectFileRefreshAttempt(
71
74
  attemptedActiveClients: readiness.kind === "ready" ? 1 : 0,
72
75
  fileReadiness,
73
76
  restartedClients: 0,
74
- processCrashRecovery: readiness.processCrashRecovery ?? emptyProcessCrashRecoverySummary(),
77
+ processCrashRecovery: readiness.processCrashRecovery ?? emptyProcessCrashRecoveryReport(),
75
78
  staleAssessment: {
76
79
  scope: "file",
77
80
  suspected: null,
@@ -90,16 +93,16 @@ async function collectWorkspaceRefreshAttempt(
90
93
  const maintenance = await refreshLspMaintenance(
91
94
  options.runtime,
92
95
  options.cwd,
93
- options.sentinelSnapshot,
96
+ options.maintenanceState,
94
97
  {
95
98
  control: options.control,
96
99
  scope: workspaceScope?.filter ?? null,
97
100
  trackSources: workspaceScope !== null,
98
101
  },
99
102
  );
100
- updateSentinelSnapshot(options.sentinelSnapshot, maintenance.snapshot);
101
103
  if (maintenance.failureReason) {
102
104
  return {
105
+ maintenanceState: maintenance.maintenanceState,
103
106
  attempt: {
104
107
  kind: "failed",
105
108
  attemptedAt: options.attemptedAt,
@@ -107,6 +110,8 @@ async function collectWorkspaceRefreshAttempt(
107
110
  requestedDiagnosticScope: options.diagnosticsScope,
108
111
  operationScope: "workspace-runtime",
109
112
  diagnosticEvidence: maintenance.diagnosticEvidence,
113
+ processCrashRecovery: emptyProcessCrashRecoveryReport(),
114
+ ...(maintenance.sourceTracking ? { sourceTracking: maintenance.sourceTracking } : {}),
110
115
  reason: maintenance.failureReason,
111
116
  },
112
117
  };
@@ -132,6 +137,7 @@ async function collectWorkspaceRefreshAttempt(
132
137
  );
133
138
  if (recovery.refreshFailureReason) {
134
139
  return {
140
+ maintenanceState: maintenance.maintenanceState,
135
141
  attempt: {
136
142
  kind: "failed",
137
143
  attemptedAt: options.attemptedAt,
@@ -148,12 +154,14 @@ async function collectWorkspaceRefreshAttempt(
148
154
  },
149
155
  diagnosticEvidence,
150
156
  processCrashRecovery: recovery.processCrashRecovery,
157
+ ...(maintenance.sourceTracking ? { sourceTracking: maintenance.sourceTracking } : {}),
151
158
  reason: recovery.refreshFailureReason,
152
159
  },
153
160
  diagnosticReport: recovery.diagnosticReport,
154
161
  };
155
162
  }
156
163
  return {
164
+ maintenanceState: maintenance.maintenanceState,
157
165
  attempt: {
158
166
  kind: "completed",
159
167
  attemptedAt: options.attemptedAt,
@@ -164,6 +172,7 @@ async function collectWorkspaceRefreshAttempt(
164
172
  restartedClients: recovery.restartedClients,
165
173
  processCrashRecovery: recovery.processCrashRecovery,
166
174
  diagnosticEvidence,
175
+ ...(maintenance.sourceTracking ? { sourceTracking: maintenance.sourceTracking } : {}),
167
176
  staleAssessment: {
168
177
  scope: "workspace",
169
178
  suspected: recovery.staleAssessment.suspected,
@@ -178,6 +187,7 @@ async function collectWorkspaceRefreshAttempt(
178
187
  // recorded failed attempt.
179
188
  if (isCodeRequestInterruption(error, options.control)) throw error;
180
189
  return {
190
+ maintenanceState: maintenance.maintenanceState,
181
191
  attempt: {
182
192
  kind: "failed",
183
193
  attemptedAt: options.attemptedAt,
@@ -185,17 +195,14 @@ async function collectWorkspaceRefreshAttempt(
185
195
  requestedDiagnosticScope: options.diagnosticsScope,
186
196
  operationScope: "workspace-runtime",
187
197
  diagnosticEvidence: maintenance.diagnosticEvidence,
198
+ processCrashRecovery: emptyProcessCrashRecoveryReport(),
199
+ ...(maintenance.sourceTracking ? { sourceTracking: maintenance.sourceTracking } : {}),
188
200
  reason: errorMessage(error),
189
201
  },
190
202
  };
191
203
  }
192
204
  }
193
205
 
194
- function updateSentinelSnapshot(target: Map<string, number>, next: Map<string, number>): void {
195
- target.clear();
196
- for (const [key, value] of next) target.set(key, value);
197
- }
198
-
199
206
  function errorMessage(error: unknown): string {
200
207
  return error instanceof Error && error.message ? error.message : "Diagnostic refresh failed.";
201
208
  }
@@ -1,11 +1,12 @@
1
1
  import type {
2
2
  DiagnosticEvidenceSummary,
3
3
  FileScopeDecision,
4
- ProcessCrashRecoverySummary,
4
+ ProcessCrashRecoveryReport,
5
5
  ProjectServerInfo,
6
6
  ProjectServerStatusReason,
7
7
  } from "@mrclrchtr/supi-lsp/api";
8
8
  import type { CapabilityWarningReport } from "../analysis/capability/capability-warnings.ts";
9
+ import type { SourceTrackingReport } from "../substrate/lsp/source-tracking.ts";
9
10
 
10
11
  export type HealthSection = "diagnostics" | "servers";
11
12
 
@@ -112,8 +113,10 @@ interface CompletedHealthRefreshAttempt {
112
113
  /** Clients restarted by stale-diagnostic recovery. */
113
114
  readonly restartedClients: number;
114
115
  /** Separate outcome for process-crash route recovery. */
115
- readonly processCrashRecovery: ProcessCrashRecoverySummary;
116
+ readonly processCrashRecovery: ProcessCrashRecoveryReport;
116
117
  readonly staleAssessment: HealthStaleAssessment;
118
+ /** Source discovery and bounded tracking facts for broad refreshes. */
119
+ readonly sourceTracking?: SourceTrackingReport;
117
120
  }
118
121
 
119
122
  /** A diagnostic refresh attempt against an explicit LSP runtime scope. */
@@ -143,7 +146,9 @@ export type HealthRefreshAttempt =
143
146
  /** Evidence collected before the operation failed, when available. */
144
147
  readonly diagnosticEvidence?: DiagnosticEvidenceSummary;
145
148
  /** Process-crash outcome, when the recovery pass returned one. */
146
- readonly processCrashRecovery?: ProcessCrashRecoverySummary;
149
+ readonly processCrashRecovery?: ProcessCrashRecoveryReport;
150
+ /** Source discovery and bounded tracking facts for broad refreshes. */
151
+ readonly sourceTracking?: SourceTrackingReport;
147
152
  /** File readiness outcome, when a file-scoped attempt failed. */
148
153
  readonly fileReadiness?: HealthFileReadiness;
149
154
  readonly reason: string;
@@ -21,6 +21,7 @@ import { describeStructuralState } from "../analysis/health/recovery.ts";
21
21
  import { collectServers } from "../analysis/health/signals.ts";
22
22
  import { SEMANTIC_READINESS_TIMEOUT_REASON } from "../analysis/readiness.ts";
23
23
  import { resolveScope } from "../analysis/search/paths.ts";
24
+ import type { LspMaintenanceState } from "../substrate/lsp/source-tracking.ts";
24
25
  import type { CapabilityAdapter } from "./capability-adapter.ts";
25
26
  import { collectHealthRefreshAttempt } from "./health-refresh.ts";
26
27
  import type {
@@ -45,8 +46,10 @@ export interface HealthWorkflowDeps {
45
46
  readonly lspController: LspRuntimeController | null;
46
47
  readonly lastRefreshAttempt: HealthRefreshAttempt | null;
47
48
  readonly trackRefreshAttempt: (attempt: HealthRefreshAttempt) => void;
48
- /** Workspace sentinel snapshot for change detection. */
49
- readonly sentinelSnapshot: Map<string, number>;
49
+ /** Typed sentinel, source-baseline, and created-source queue state. */
50
+ readonly maintenanceState: LspMaintenanceState;
51
+ /** Commit maintenance state only after a health attempt completes. */
52
+ readonly updateMaintenanceState: (state: LspMaintenanceState) => void;
50
53
  }
51
54
 
52
55
  /** Collect health facts without rendering a public result. */
@@ -282,7 +285,7 @@ async function collectRefreshState(
282
285
  diagnosticsScope,
283
286
  attemptedAt,
284
287
  cwd: options.deps.cwd,
285
- sentinelSnapshot: options.deps.sentinelSnapshot,
288
+ maintenanceState: options.deps.maintenanceState,
286
289
  control: options.control,
287
290
  reportRecoveryProgress: () =>
288
291
  reportProgress(options.control, {
@@ -291,6 +294,7 @@ async function collectRefreshState(
291
294
  message: "Refreshing diagnostics and recovery state",
292
295
  }),
293
296
  });
297
+ deps.updateMaintenanceState(attempt.maintenanceState);
294
298
  deps.trackRefreshAttempt(attempt.attempt);
295
299
  return attempt;
296
300
  } catch (error) {
@@ -20,6 +20,10 @@ import { realpathSync } from "node:fs";
20
20
  import * as path from "node:path";
21
21
  import type { SessionEntry } from "@earendil-works/pi-coding-agent";
22
22
  import type { LspRuntimeController } from "@mrclrchtr/supi-lsp/api";
23
+ import {
24
+ createLspMaintenanceState,
25
+ type LspMaintenanceState,
26
+ } from "../substrate/lsp/source-tracking.ts";
23
27
  import { type CapabilityAdapter, WorkspaceCapabilityAdapter } from "./capability-adapter.ts";
24
28
  import type { FindWorkflowInput, FindWorkflowOutcome } from "./find-types.ts";
25
29
  import { runFindWorkflow } from "./find-workflow.ts";
@@ -162,8 +166,8 @@ export class WorkspaceCodeIntelligenceSession {
162
166
  */
163
167
  #lspController: LspRuntimeController | null = null;
164
168
 
165
- /** Workspace sentinel snapshot for change detection across explicit queries. */
166
- #sentinelSnapshot: Map<string, number> = new Map();
169
+ /** Typed sentinel, source-baseline, and created-source queue state. */
170
+ #maintenanceState: LspMaintenanceState = createLspMaintenanceState();
167
171
 
168
172
  /** Whether the project owning this session is trusted for config loading. */
169
173
  #projectTrusted = false;
@@ -196,7 +200,7 @@ export class WorkspaceCodeIntelligenceSession {
196
200
  * Called by the extension entry point after LSP initialization.
197
201
  */
198
202
  seedSentinelSnapshot(snapshot: Map<string, number>): void {
199
- this.#sentinelSnapshot = snapshot;
203
+ this.#maintenanceState = createLspMaintenanceState(snapshot);
200
204
  }
201
205
 
202
206
  /** Restore overview state from the active session branch. */
@@ -283,7 +287,10 @@ export class WorkspaceCodeIntelligenceSession {
283
287
  trackRefreshAttempt: (attempt) => {
284
288
  this.#lastHealthRefreshAttempt = attempt;
285
289
  },
286
- sentinelSnapshot: this.#sentinelSnapshot,
290
+ maintenanceState: this.#maintenanceState,
291
+ updateMaintenanceState: (state) => {
292
+ this.#maintenanceState = state;
293
+ },
287
294
  },
288
295
  control,
289
296
  );
@@ -429,7 +436,7 @@ export class WorkspaceCodeIntelligenceSession {
429
436
  this.#workflowTargets.clear();
430
437
  this.#surfacedInstructionDirs.clear();
431
438
  this.#nativeInstructionPaths.clear();
432
- this.#sentinelSnapshot.clear();
439
+ this.#maintenanceState = createLspMaintenanceState();
433
440
  this.#lspController = null;
434
441
  this.#projectTrusted = false;
435
442
  }
@@ -13,7 +13,6 @@ import {
13
13
  isCodeRequestInterruption,
14
14
  throwIfCodeRequestInterrupted,
15
15
  } from "@mrclrchtr/supi-code-runtime/api";
16
- import { isWithinOrEqual } from "@mrclrchtr/supi-core/api";
17
16
  import { uriToFile } from "@mrclrchtr/supi-core/path";
18
17
  import type { DiagnosticEvidenceSummary } from "@mrclrchtr/supi-lsp/api";
19
18
  import {
@@ -27,6 +26,12 @@ import {
27
26
  type WorkspaceLspRuntime,
28
27
  } from "@mrclrchtr/supi-lsp/api";
29
28
  import { mergeDiagnosticEvidence } from "../../diagnostics/evidence.ts";
29
+ import {
30
+ type LspMaintenanceState,
31
+ type SourceTrackingReport,
32
+ trackCreatedSources,
33
+ withSentinelSnapshot,
34
+ } from "./source-tracking.ts";
30
35
 
31
36
  /** Options shared by the workspace and file-scoped maintenance passes. */
32
37
  export interface LspMaintenanceOptions {
@@ -36,11 +41,7 @@ export interface LspMaintenanceOptions {
36
41
  * tracks created files inside this prefix; null disables the scope bound.
37
42
  */
38
43
  scope?: string | null;
39
- /**
40
- * Track files created since the last refresh so the following refresh pull
41
- * includes them. Only the workspace-runtime path sets this; the snapshot is
42
- * still widened on file-scoped passes so later diffs stay correct.
43
- */
44
+ /** Track source additions only for a broad tracked-file refresh. */
44
45
  trackSources?: boolean;
45
46
  }
46
47
 
@@ -52,10 +53,11 @@ export interface LspMaintenanceOptions {
52
53
  export async function refreshLspMaintenance(
53
54
  runtime: WorkspaceLspRuntime,
54
55
  cwd: string,
55
- sentinelSnapshot: Map<string, number>,
56
+ maintenanceState: LspMaintenanceState,
56
57
  options: LspMaintenanceOptions = {},
57
58
  ): Promise<WorkspaceLspMaintenanceResult> {
58
- const { snapshot } = await synchronizeSentinels(runtime, sentinelSnapshot, options);
59
+ const synchronized = await synchronizeSentinels(runtime, cwd, maintenanceState, options);
60
+ const { snapshot, nextState, sourceTracking } = synchronized;
59
61
  let diagnosticEvidence = emptyEvidence();
60
62
  let failureReason: string | undefined;
61
63
 
@@ -80,15 +82,21 @@ export async function refreshLspMaintenance(
80
82
 
81
83
  return {
82
84
  snapshot,
85
+ maintenanceState: nextState,
83
86
  diagnosticEvidence,
87
+ ...(sourceTracking ? { sourceTracking } : {}),
84
88
  ...(failureReason ? { failureReason } : {}),
85
89
  };
86
90
  }
87
91
 
88
92
  /** Sentinel state and diagnostic evidence retained from one workspace pass. */
89
93
  export interface WorkspaceLspMaintenanceResult {
94
+ /** The next typed maintenance state for the session. */
95
+ maintenanceState: LspMaintenanceState;
90
96
  /** The next sentinel snapshot for the session-owned maintenance state. */
91
97
  snapshot: Map<string, number>;
98
+ /** Source discovery and bounded tracking facts for broad refreshes. */
99
+ sourceTracking?: SourceTrackingReport;
92
100
  /** Evidence from every diagnostic refresh performed by this pass. */
93
101
  diagnosticEvidence: DiagnosticEvidenceSummary;
94
102
  /** Failure from the first workspace refresh, when no fresh pass completed. */
@@ -97,6 +105,8 @@ export interface WorkspaceLspMaintenanceResult {
97
105
 
98
106
  /** Sentinel state and stale-file facts from one file-scoped pass. */
99
107
  export interface FileLspMaintenanceResult {
108
+ /** The next typed maintenance state for the session. */
109
+ maintenanceState: LspMaintenanceState;
100
110
  /** The next sentinel snapshot for the session-owned maintenance state. */
101
111
  snapshot: Map<string, number>;
102
112
  /** Number of stale files that matched the requested file. */
@@ -107,14 +117,14 @@ export interface FileLspMaintenanceResult {
107
117
  export async function refreshFileLspMaintenance(options: {
108
118
  runtime: WorkspaceLspRuntime;
109
119
  cwd: string;
110
- sentinelSnapshot: Map<string, number>;
120
+ maintenanceState: LspMaintenanceState;
111
121
  filePath: string;
112
122
  control?: CodeRequestControl;
113
123
  }): Promise<FileLspMaintenanceResult> {
114
- const { runtime, cwd, sentinelSnapshot, filePath, control } = options;
124
+ const { runtime, cwd, maintenanceState, filePath, control } = options;
115
125
  // A cancelled caller stops before any maintenance work starts.
116
126
  throwIfCodeRequestInterrupted(control);
117
- const { snapshot } = await synchronizeSentinels(runtime, sentinelSnapshot);
127
+ const { snapshot, nextState } = await synchronizeSentinels(runtime, cwd, maintenanceState);
118
128
  const target = nodePath.resolve(filePath);
119
129
  const stale = confirmedOutstandingDiagnostics(runtime, cwd).some(
120
130
  (entry) =>
@@ -132,38 +142,51 @@ export async function refreshFileLspMaintenance(options: {
132
142
  runtime.pruneMissingFiles();
133
143
  throwIfCodeRequestInterrupted(control);
134
144
 
135
- return { snapshot, matchedStaleFileCount: stale ? 1 : 0 };
145
+ return {
146
+ snapshot,
147
+ maintenanceState: nextState,
148
+ matchedStaleFileCount: stale ? 1 : 0,
149
+ };
136
150
  }
137
151
 
138
152
  /**
139
- * Sync the widened workspace snapshot, forward sentinel changes, and track
140
- * source files newly created since the last pass.
153
+ * Sync sentinel state and, only for broad refreshes, process source additions.
141
154
  *
142
- * The snapshot is widened to every regular file on every pass so later diffs
143
- * see genuine creations. Only sentinel-file events are forwarded as workspace
144
- * changes (config semantics unchanged); created source files are tracked only
145
- * on the workspace-runtime path and only once the snapshot was primed by an
146
- * earlier pass — the first pass establishes the baseline and cannot tell a
147
- * just-created file from a long-existing one.
155
+ * Sentinel state and source state use separate baselines. A complete source
156
+ * inventory establishes the first baseline without treating existing files as
157
+ * created. Limited inventories leave the previous source state unchanged.
148
158
  */
149
159
  async function synchronizeSentinels(
150
160
  runtime: WorkspaceLspRuntime,
151
- sentinelSnapshot: Map<string, number>,
161
+ cwd: string,
162
+ maintenanceState: LspMaintenanceState,
152
163
  options: LspMaintenanceOptions = {},
153
- ) {
154
- const primed = sentinelSnapshot.size > 0;
155
- const state = runtime.syncWorkspaceSentinelSnapshot(sentinelSnapshot, {
156
- includeSourceFiles: true,
157
- });
158
-
164
+ ): Promise<{
165
+ snapshot: Map<string, number>;
166
+ nextState: LspMaintenanceState;
167
+ sourceTracking?: SourceTrackingReport;
168
+ }> {
169
+ const state = runtime.syncWorkspaceSentinelSnapshot(maintenanceState.sentinelSnapshot);
159
170
  invalidateChangedProjectConfigs(state.changes);
160
171
  if (state.changes.length > 0) runtime.noteWorkspaceChanges(state.changes);
161
172
 
162
- if (options.trackSources && primed) {
163
- await trackCreatedSourceFiles(runtime, state.sourceChanges, options.scope);
173
+ const nextSentinelState = withSentinelSnapshot(maintenanceState, state.snapshot);
174
+ if (!options.trackSources) {
175
+ return { snapshot: state.snapshot, nextState: nextSentinelState };
164
176
  }
165
177
 
166
- return state;
178
+ const sourceResult = await trackCreatedSources({
179
+ runtime,
180
+ cwd,
181
+ state: nextSentinelState,
182
+ scope: options.scope,
183
+ control: options.control,
184
+ });
185
+ return {
186
+ snapshot: state.snapshot,
187
+ nextState: sourceResult.state,
188
+ sourceTracking: sourceResult.report,
189
+ };
167
190
  }
168
191
 
169
192
  /** Invalidate cached tsconfig scope parses only for config files that changed. */
@@ -181,23 +204,6 @@ function invalidateChangedProjectConfigs(changes: readonly FileEvent[]): void {
181
204
  }
182
205
  }
183
206
 
184
- /** Track source files newly created since the last pass, within the scope bound. */
185
- async function trackCreatedSourceFiles(
186
- runtime: WorkspaceLspRuntime,
187
- sourceChanges: readonly FileEvent[],
188
- scope: string | null | undefined,
189
- ): Promise<void> {
190
- for (const change of sourceChanges) {
191
- if (change.type !== FileChangeType.Created) continue;
192
- const filePath = uriToFile(change.uri);
193
- if (scope && !isWithinOrEqual(scope, filePath)) continue;
194
- if (!runtime.isSupportedSourceFile(filePath)) continue;
195
- // Best-effort: a file no client can serve stays untracked and is
196
- // simply absent from evidence until a later explicit request.
197
- await runtime.trackFile(filePath);
198
- }
199
- }
200
-
201
207
  /** Return only diagnostics whose document evidence is confirmed. */
202
208
  function confirmedOutstandingDiagnostics(runtime: WorkspaceLspRuntime, cwd: string) {
203
209
  const outstanding = runtime.getOutstandingDiagnostics(1);
@@ -150,7 +150,8 @@ export function registerLspSettings(pi: ExtensionAPI): void {
150
150
  kind: "stringList" as const,
151
151
  key: "exclude",
152
152
  label: "Exclude Patterns",
153
- description: "Gitignore patterns for automatic LSP workspace work (comma-separated)",
153
+ description:
154
+ "Comma-separated gitignore patterns for automatic LSP workspace work. Exact file requests stay available.",
154
155
  },
155
156
  {
156
157
  kind: "custom" as const,