sift-light 1.0.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 (145) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/CONTRIBUTING.md +19 -0
  3. package/LICENSE +661 -0
  4. package/README.md +177 -0
  5. package/README.zh-CN.md +177 -0
  6. package/SECURITY.md +25 -0
  7. package/package.json +142 -0
  8. package/plugins/sift-light/.claude-plugin/plugin.json +10 -0
  9. package/plugins/sift-light/.codex-plugin/plugin.json +20 -0
  10. package/plugins/sift-light/.mcp.json +24 -0
  11. package/plugins/sift-light/LICENSE +661 -0
  12. package/plugins/sift-light/concept-worker.mjs +567 -0
  13. package/plugins/sift-light/hooks/THIRD_PARTY_NOTICES.txt +70 -0
  14. package/plugins/sift-light/hooks/hooks.json +16 -0
  15. package/plugins/sift-light/hooks/search-policy.mjs +4113 -0
  16. package/plugins/sift-light/hooks/tree-sitter-bash.wasm +0 -0
  17. package/plugins/sift-light/hooks/tree-sitter-powershell.wasm +0 -0
  18. package/plugins/sift-light/hooks/tree-sitter.wasm +0 -0
  19. package/plugins/sift-light/kimi.plugin.json +36 -0
  20. package/plugins/sift-light/mcp-server.mjs +1 -0
  21. package/plugins/sift-light/omp-extension.mjs +20914 -0
  22. package/plugins/sift-light/package.json +11 -0
  23. package/plugins/sift-light/syntax-worker.mjs +280 -0
  24. package/plugins/sift-light/syntax-worker.toml +2 -0
  25. package/src/analysis-evidence.ts +43 -0
  26. package/src/analysis-limits.ts +27 -0
  27. package/src/analysis-store.ts +559 -0
  28. package/src/analysis-term-pages.ts +73 -0
  29. package/src/analysis-types.ts +162 -0
  30. package/src/audit-search.ts +391 -0
  31. package/src/capped-lines.ts +112 -0
  32. package/src/concept-embedding-cache.ts +186 -0
  33. package/src/concept-inference.ts +218 -0
  34. package/src/concept-model.ts +96 -0
  35. package/src/concept-search.ts +577 -0
  36. package/src/concept-setup.ts +75 -0
  37. package/src/concept-source-generation.ts +268 -0
  38. package/src/concept-worker.mjs +567 -0
  39. package/src/concept-worker.ts +210 -0
  40. package/src/config-reader.ts +283 -0
  41. package/src/config.ts +37 -0
  42. package/src/context-budget.ts +26 -0
  43. package/src/discovery-errors.ts +2 -0
  44. package/src/errors.ts +95 -0
  45. package/src/evidence-candidates.ts +344 -0
  46. package/src/evidence-ranking.ts +48 -0
  47. package/src/evidence-service.ts +1047 -0
  48. package/src/evidence-validation.ts +466 -0
  49. package/src/evidence-validity.ts +33 -0
  50. package/src/excerpt.ts +53 -0
  51. package/src/file-discovery.ts +150 -0
  52. package/src/file-metadata-filter.ts +46 -0
  53. package/src/format.ts +407 -0
  54. package/src/git-diff.ts +195 -0
  55. package/src/git-process.ts +189 -0
  56. package/src/git-repository.ts +367 -0
  57. package/src/git-source.ts +385 -0
  58. package/src/historical-paths.ts +205 -0
  59. package/src/hybrid-search.ts +340 -0
  60. package/src/import-model.ts +611 -0
  61. package/src/import-navigation.ts +100 -0
  62. package/src/import-resolution.ts +240 -0
  63. package/src/index.ts +97 -0
  64. package/src/inspect-batch.ts +265 -0
  65. package/src/inspect.ts +271 -0
  66. package/src/language-capabilities.ts +157 -0
  67. package/src/language-capability-definitions.ts +204 -0
  68. package/src/literal-search.ts +25 -0
  69. package/src/mcp-cli.ts +21 -0
  70. package/src/mcp-model-output.ts +120 -0
  71. package/src/mcp-output.ts +9 -0
  72. package/src/mcp-semantic-judge.ts +39 -0
  73. package/src/mcp-server.mjs +14064 -0
  74. package/src/mcp-server.ts +157 -0
  75. package/src/mcp-stdio.ts +114 -0
  76. package/src/mcp.ts +631 -0
  77. package/src/model-error.ts +120 -0
  78. package/src/multi-term-search.ts +122 -0
  79. package/src/omp-index.ts +277 -0
  80. package/src/omp-marketplace-entry.ts +7 -0
  81. package/src/operation-lifecycle.ts +413 -0
  82. package/src/operation-output.ts +100 -0
  83. package/src/owned-parallel.ts +22 -0
  84. package/src/owned-process.ts +102 -0
  85. package/src/owned-task-queue.ts +38 -0
  86. package/src/package-version.ts +3 -0
  87. package/src/path-policy.ts +203 -0
  88. package/src/pi-search-policy.ts +33 -0
  89. package/src/prompt-guidelines.ts +54 -0
  90. package/src/python-outline.ts +231 -0
  91. package/src/record-value.ts +3 -0
  92. package/src/redaction.ts +95 -0
  93. package/src/request-contract-catalog.ts +215 -0
  94. package/src/request-contract-error.ts +96 -0
  95. package/src/request-contract.ts +481 -0
  96. package/src/request.ts +132 -0
  97. package/src/result-statistics.ts +178 -0
  98. package/src/rg.ts +574 -0
  99. package/src/ripgrep-diagnostics.ts +122 -0
  100. package/src/ripgrep-executable.ts +43 -0
  101. package/src/runtime.ts +53 -0
  102. package/src/scan-revisions.ts +148 -0
  103. package/src/script-runtime.ts +11 -0
  104. package/src/search-policy-commands.ts +170 -0
  105. package/src/search-policy-hook.ts +61 -0
  106. package/src/search-policy-recovery.ts +388 -0
  107. package/src/search-policy-shell.ts +280 -0
  108. package/src/search-policy.ts +102 -0
  109. package/src/search-retention.ts +77 -0
  110. package/src/semantic-judge-batches.ts +135 -0
  111. package/src/semantic-judge.ts +519 -0
  112. package/src/service.ts +945 -0
  113. package/src/session-summary.ts +100 -0
  114. package/src/snapshot-store.ts +203 -0
  115. package/src/source-access.ts +288 -0
  116. package/src/source-continuations.ts +168 -0
  117. package/src/source-document.ts +277 -0
  118. package/src/source-inspection.ts +731 -0
  119. package/src/source-pages.ts +112 -0
  120. package/src/source.ts +286 -0
  121. package/src/structural-search.ts +125 -0
  122. package/src/structure.ts +259 -0
  123. package/src/summary-previews.ts +96 -0
  124. package/src/summary.ts +79 -0
  125. package/src/syntax-facts.ts +464 -0
  126. package/src/syntax-fields.ts +161 -0
  127. package/src/syntax-search.ts +361 -0
  128. package/src/syntax-tree.ts +30 -0
  129. package/src/syntax-types.ts +72 -0
  130. package/src/syntax-worker.mjs +280 -0
  131. package/src/syntax-worker.toml +2 -0
  132. package/src/syntax-worker.ts +143 -0
  133. package/src/syntax.ts +259 -0
  134. package/src/test-navigation-facts.ts +261 -0
  135. package/src/test-navigation.ts +543 -0
  136. package/src/tool-schema.ts +321 -0
  137. package/src/tui/dashboard.ts +107 -0
  138. package/src/tui/layout.ts +291 -0
  139. package/src/tui/palette.ts +73 -0
  140. package/src/tui/presentation.ts +240 -0
  141. package/src/tui/renderers.ts +106 -0
  142. package/src/types.ts +368 -0
  143. package/src/validation-output.ts +148 -0
  144. package/src/validation-types.ts +48 -0
  145. package/src/workspace-files.ts +142 -0
@@ -0,0 +1,268 @@
1
+ import { SiftLightError } from "./errors.js";
2
+ import { createHash } from "node:crypto";
3
+ import { MAX_STRUCTURE_FILES } from "./analysis-limits.js";
4
+ import { SourceAccess, SourceBudgetError } from "./source-access.js";
5
+ import {
6
+ SourceDocumentError,
7
+ type SourceDocument,
8
+ type SourceReference,
9
+ } from "./source-document.js";
10
+ import { listWorkspaceFiles, type WorkspaceFileList } from "./workspace-files.js";
11
+
12
+ export interface ConceptSourceFilters {
13
+ path?: string;
14
+ glob: string[];
15
+ exclude: string[];
16
+ hidden: boolean;
17
+ }
18
+
19
+ export interface ConceptSourceInventoryEntry {
20
+ path: string;
21
+ status: "admitted" | "empty" | "binary" | "unavailable";
22
+ reference?: SourceReference;
23
+ contentHash?: string;
24
+ reason?: string;
25
+ }
26
+
27
+ export interface ConceptSourceSummary {
28
+ inventoryHash: string;
29
+ verification: "verified-during-interval" | "unverified";
30
+ startedAt: number;
31
+ verifiedAt?: number;
32
+ filesEnumerated: number;
33
+ filesAdmitted: number;
34
+ filesSkippedEmpty: number;
35
+ filesSkippedBinary: number;
36
+ filesUnavailable: number;
37
+ batches: number;
38
+ batchFileLimit: number;
39
+ fileLimit: number;
40
+ }
41
+
42
+ export interface ConceptSourceGeneration {
43
+ readonly cwd: string;
44
+ readonly filters: ConceptSourceFilters;
45
+ readonly files: WorkspaceFileList;
46
+ readonly inventory: readonly ConceptSourceInventoryEntry[];
47
+ readonly documents: readonly SourceDocument[];
48
+ readonly partial: boolean;
49
+ readonly reasons: readonly string[];
50
+ readonly filesSkippedEmpty: number;
51
+ readonly filesSkippedBinary: number;
52
+ readonly filesUnavailable: number;
53
+ readonly filesAdmitted: number;
54
+ readonly batches: number;
55
+ readonly batchFileLimit: number;
56
+ readonly fileLimit: number;
57
+ readonly startedAt: number;
58
+ readonly inventoryHash: string;
59
+ verifiedAt?: number;
60
+ }
61
+
62
+ export class ConceptSourceChangedError extends SiftLightError {
63
+ constructor(message = "Concept source changed while evidence was being computed") {
64
+ super(message);
65
+ this.name = "ConceptSourceChangedError";
66
+ }
67
+ }
68
+
69
+ function isSourceMissing(error: unknown): boolean {
70
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
71
+ }
72
+
73
+ function options(filters: ConceptSourceFilters): {
74
+ path?: string;
75
+ glob: string[];
76
+ exclude: string[];
77
+ hidden: boolean;
78
+ } {
79
+ return {
80
+ ...(filters.path ? { path: filters.path } : {}),
81
+ glob: filters.glob,
82
+ exclude: filters.exclude,
83
+ hidden: filters.hidden,
84
+ };
85
+ }
86
+
87
+ export async function createConceptSourceGeneration(
88
+ access: SourceAccess,
89
+ filters: ConceptSourceFilters,
90
+ providedFiles?: WorkspaceFileList,
91
+ ): Promise<ConceptSourceGeneration> {
92
+ const files =
93
+ providedFiles ?? (await listWorkspaceFiles(access.cwd, access.signal, options(filters)));
94
+ const startedAt = Date.now();
95
+ const inventory: ConceptSourceInventoryEntry[] = [];
96
+ const documents: SourceDocument[] = [];
97
+ const reasons = [...files.reasons];
98
+ let filesSkippedEmpty = 0;
99
+ let filesSkippedBinary = 0;
100
+ let filesUnavailable = 0;
101
+ let budgetError: SourceBudgetError | undefined;
102
+ for (const path of files.paths) {
103
+ if (budgetError) {
104
+ inventory.push({ path, status: "unavailable", reason: budgetError.message });
105
+ filesUnavailable += 1;
106
+ continue;
107
+ }
108
+ try {
109
+ // oxlint-disable-next-line no-await-in-loop -- SourceAccess serializes a bounded source budget.
110
+ const document = await access.load(path);
111
+ if (document.bytes.includes(0)) {
112
+ inventory.push({
113
+ path,
114
+ status: "binary",
115
+ reference: document.reference,
116
+ ...(document.reference.origin.kind === "worktree"
117
+ ? { contentHash: document.reference.origin.contentHash }
118
+ : {}),
119
+ reason: "Binary source contains NUL bytes",
120
+ });
121
+ filesSkippedBinary += 1;
122
+ continue;
123
+ }
124
+ if (!document.utf8) throw new SourceDocumentError("encoding", "Not lossless UTF-8");
125
+ if (!document.text.trim()) {
126
+ inventory.push({
127
+ path,
128
+ status: "empty",
129
+ reference: document.reference,
130
+ ...(document.reference.origin.kind === "worktree"
131
+ ? { contentHash: document.reference.origin.contentHash }
132
+ : {}),
133
+ });
134
+ filesSkippedEmpty += 1;
135
+ continue;
136
+ }
137
+ inventory.push({
138
+ path,
139
+ status: "admitted",
140
+ reference: document.reference,
141
+ ...(document.reference.origin.kind === "worktree"
142
+ ? { contentHash: document.reference.origin.contentHash }
143
+ : {}),
144
+ });
145
+ documents.push(document);
146
+ } catch (error) {
147
+ if (isSourceMissing(error))
148
+ throw new ConceptSourceChangedError(`${path}: source disappeared while reading`);
149
+ if (error instanceof SourceBudgetError) {
150
+ budgetError = error;
151
+ reasons.push(error.message);
152
+ inventory.push({ path, status: "unavailable", reason: error.message });
153
+ filesUnavailable += 1;
154
+ continue;
155
+ }
156
+ if (!(error instanceof SourceDocumentError)) throw error;
157
+ if (error.reason === "source-changed")
158
+ throw new ConceptSourceChangedError(`${path}: ${error.message}`);
159
+ inventory.push({ path, status: "unavailable", reason: error.message });
160
+ filesUnavailable += 1;
161
+ reasons.push(`${path}: ${error.message}`);
162
+ }
163
+ }
164
+ const inventoryHash = createHash("sha256")
165
+ .update(JSON.stringify(inventory))
166
+ .digest("hex")
167
+ .slice(0, 32);
168
+ return {
169
+ cwd: access.cwd,
170
+ filters: {
171
+ ...(filters.path ? { path: filters.path } : {}),
172
+ glob: [...filters.glob],
173
+ exclude: [...filters.exclude],
174
+ hidden: filters.hidden,
175
+ },
176
+ files,
177
+ inventory,
178
+ documents,
179
+ partial: files.partial || filesUnavailable > 0,
180
+ reasons,
181
+ filesSkippedEmpty,
182
+ filesSkippedBinary,
183
+ filesUnavailable,
184
+ filesAdmitted: documents.length,
185
+ batches: 1,
186
+ batchFileLimit: access.maxFiles,
187
+ fileLimit: access.maxFiles,
188
+ startedAt,
189
+ inventoryHash,
190
+ };
191
+ }
192
+
193
+ export function conceptSourceSummary(generation: ConceptSourceGeneration): ConceptSourceSummary {
194
+ return {
195
+ inventoryHash: generation.inventoryHash,
196
+ verification: generation.verifiedAt === undefined ? "unverified" : "verified-during-interval",
197
+ startedAt: generation.startedAt,
198
+ ...(generation.verifiedAt === undefined ? {} : { verifiedAt: generation.verifiedAt }),
199
+ filesEnumerated: generation.files.paths.length,
200
+ filesAdmitted: generation.filesAdmitted,
201
+ filesSkippedEmpty: generation.filesSkippedEmpty,
202
+ filesSkippedBinary: generation.filesSkippedBinary,
203
+ filesUnavailable: generation.filesUnavailable,
204
+ batches: generation.batches,
205
+ batchFileLimit: generation.batchFileLimit,
206
+ fileLimit: generation.fileLimit,
207
+ };
208
+ }
209
+
210
+ function samePathSet(left: readonly string[], right: readonly string[]): boolean {
211
+ if (left.length !== right.length) return false;
212
+ return left.every((path, index) => path === right[index]);
213
+ }
214
+
215
+ /** Re-enumerate and reread the exact admitted generation before publishing evidence. */
216
+ export async function verifyConceptSourceGeneration(
217
+ generation: ConceptSourceGeneration,
218
+ access: SourceAccess,
219
+ ): Promise<void> {
220
+ const current = await listWorkspaceFiles(access.cwd, access.signal, {
221
+ ...options(generation.filters),
222
+ maxFiles: generation.fileLimit,
223
+ });
224
+ if (
225
+ current.coverageIssue !== undefined &&
226
+ current.coverageIssue !== generation.files.coverageIssue
227
+ ) {
228
+ throw new SiftLightError(current.reasons.join("; "));
229
+ }
230
+ if (
231
+ current.partial !== generation.files.partial ||
232
+ !samePathSet(current.paths, generation.files.paths)
233
+ ) {
234
+ throw new ConceptSourceChangedError(
235
+ "Concept source inventory changed while evidence was being computed",
236
+ );
237
+ }
238
+ let verificationAccess = access.batch(Math.min(generation.batchFileLimit, MAX_STRUCTURE_FILES));
239
+ let verifiedInBatch = 0;
240
+ for (const entry of generation.inventory) {
241
+ if (!entry.reference) continue;
242
+ if (verifiedInBatch >= verificationAccess.maxFiles) {
243
+ verificationAccess = access.batch(Math.min(generation.batchFileLimit, MAX_STRUCTURE_FILES));
244
+ verifiedInBatch = 0;
245
+ }
246
+ try {
247
+ // oxlint-disable-next-line no-await-in-loop -- every admitted file must be version-checked.
248
+ const document = await verificationAccess.refresh(entry.path, entry.reference);
249
+ verifiedInBatch += 1;
250
+ const hash =
251
+ document.reference.origin.kind === "worktree"
252
+ ? document.reference.origin.contentHash
253
+ : undefined;
254
+ if (entry.contentHash !== hash)
255
+ throw new ConceptSourceChangedError(`${entry.path}: source content changed`);
256
+ } catch (error) {
257
+ if (error instanceof ConceptSourceChangedError) throw error;
258
+ if (isSourceMissing(error))
259
+ throw new ConceptSourceChangedError(
260
+ `${entry.path}: source disappeared during verification`,
261
+ );
262
+ if (error instanceof SourceDocumentError)
263
+ throw new ConceptSourceChangedError(`${entry.path}: ${error.message}`);
264
+ throw error;
265
+ }
266
+ }
267
+ generation.verifiedAt = Date.now();
268
+ }