knodin 0.7.5 → 0.7.6

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 (105) hide show
  1. package/README.md +4 -1
  2. package/dist/bin/cli.js +108 -1859
  3. package/dist/bin/launcher.js +3 -10
  4. package/dist/chunks/chunk-DMQAGX77.js +654 -0
  5. package/dist/chunks/chunk-F4Z3Z766.js +4 -0
  6. package/dist/chunks/chunk-SIJAQVSX.js +3 -0
  7. package/dist/chunks/chunk-X6M4HUUE.js +2 -0
  8. package/dist/chunks/chunk-YPRMY2LP.js +8 -0
  9. package/dist/chunks/pure-compression-cli-4TA2TQD5.js +5 -0
  10. package/dist/chunks/server-7EDF4CBY.js +14 -0
  11. package/dist/chunks/structural-fast-path-KD5KQSPX.js +4 -0
  12. package/dist/src/init-progress-worker.js +2 -106
  13. package/dist/src/repair-progress-worker.js +2 -120
  14. package/docs/INSTALLATION.md +17 -1
  15. package/docs/releases/0.7.6.md +25 -0
  16. package/package.json +1 -111
  17. package/dist/src/agent-integration.js +0 -238
  18. package/dist/src/artifact-refresh.js +0 -81
  19. package/dist/src/cli-args.js +0 -274
  20. package/dist/src/cli-model.js +0 -358
  21. package/dist/src/codeflow-replay.js +0 -80
  22. package/dist/src/compact-structural.js +0 -96
  23. package/dist/src/competitive-cold-mcp.js +0 -40
  24. package/dist/src/competitive-constraints.js +0 -20
  25. package/dist/src/competitive-manifest.js +0 -411
  26. package/dist/src/competitive-measurement.js +0 -183
  27. package/dist/src/competitive-runner.js +0 -487
  28. package/dist/src/competitive-sandbox.js +0 -108
  29. package/dist/src/context-export.js +0 -422
  30. package/dist/src/context.js +0 -102
  31. package/dist/src/diagnostics.js +0 -449
  32. package/dist/src/docs-sections.js +0 -141
  33. package/dist/src/doctor.js +0 -380
  34. package/dist/src/engine/ann-hnsw.js +0 -271
  35. package/dist/src/engine/embeddings.js +0 -193
  36. package/dist/src/engine/file-walker.js +0 -43
  37. package/dist/src/engine/git-history.js +0 -289
  38. package/dist/src/engine/index.js +0 -13377
  39. package/dist/src/engine/perf.js +0 -115
  40. package/dist/src/engine/prune.js +0 -112
  41. package/dist/src/engine/scip-import.js +0 -408
  42. package/dist/src/engine/source-policy.js +0 -69
  43. package/dist/src/engine/sqlite.js +0 -71
  44. package/dist/src/engine/symbol-delete.js +0 -58
  45. package/dist/src/execution-profile.js +0 -203
  46. package/dist/src/failure-diagnosis.js +0 -649
  47. package/dist/src/fleet.js +0 -7
  48. package/dist/src/git-executable.js +0 -31
  49. package/dist/src/graph-query-health.js +0 -115
  50. package/dist/src/hook-manager-integration.js +0 -156
  51. package/dist/src/index-activity.js +0 -125
  52. package/dist/src/init-progress.js +0 -155
  53. package/dist/src/init.js +0 -1254
  54. package/dist/src/lifecycle-health.js +0 -250
  55. package/dist/src/lsp-readonly.js +0 -217
  56. package/dist/src/output-compression.js +0 -629
  57. package/dist/src/output-telemetry.js +0 -363
  58. package/dist/src/pr-triage.js +0 -638
  59. package/dist/src/progressive-evidence.js +0 -473
  60. package/dist/src/pure-compression-cli.js +0 -101
  61. package/dist/src/relationship-adapters.js +0 -370
  62. package/dist/src/release-attestation.js +0 -533
  63. package/dist/src/release-preflight.js +0 -510
  64. package/dist/src/repair-progress.js +0 -262
  65. package/dist/src/repository-init-process.js +0 -173
  66. package/dist/src/repository-management.js +0 -1231
  67. package/dist/src/response-budget.js +0 -194
  68. package/dist/src/server.js +0 -172
  69. package/dist/src/structural-fast-path.js +0 -338
  70. package/dist/src/structural-snapshot.js +0 -33
  71. package/dist/src/system-config.js +0 -615
  72. package/dist/src/terminal-help.js +0 -83
  73. package/dist/src/tools/knodin-tools.js +0 -1529
  74. package/dist/src/update-ceremony.js +0 -158
  75. package/dist/src/update-policy.js +0 -944
  76. package/dist/src/update-trust.js +0 -503
  77. package/dist/src/version.js +0 -13
  78. package/dist/src/visualization.js +0 -162
  79. package/dist/src/wait-for-fresh.js +0 -98
  80. package/dist/src/worktree-lifecycle.js +0 -231
  81. package/docs/CONTAINED-EXECUTION.md +0 -77
  82. package/docs/DIAGNOSTICS.md +0 -45
  83. package/docs/GIT-HISTORY-REVIEW.md +0 -39
  84. package/docs/PROGRESSIVE-EVIDENCE.md +0 -37
  85. package/docs/PT-ACCESS-RECOMMENDATION.md +0 -91
  86. package/docs/RELEASE-0.3-EVIDENCE.md +0 -73
  87. package/docs/SCIP-IMPORT.md +0 -57
  88. package/docs/SIGNED-UPDATES.md +0 -151
  89. package/docs/TELEMETRY.md +0 -46
  90. package/docs/assets/knodin-favicon.svg +0 -4
  91. package/docs/releases/0.3.0.md +0 -46
  92. package/docs/releases/0.4.0.md +0 -68
  93. package/docs/releases/0.4.1.md +0 -28
  94. package/docs/releases/0.4.2.md +0 -27
  95. package/docs/releases/0.4.3.md +0 -23
  96. package/docs/releases/0.5.0.md +0 -29
  97. package/docs/releases/0.5.1.md +0 -17
  98. package/docs/releases/0.6.0.md +0 -18
  99. package/docs/releases/0.7.0.md +0 -24
  100. package/docs/releases/0.7.1.md +0 -21
  101. package/docs/releases/0.7.2.md +0 -21
  102. package/docs/releases/0.7.3.md +0 -23
  103. package/docs/releases/0.7.4.md +0 -17
  104. package/docs/releases/0.7.5.md +0 -20
  105. package/schemas/release-attestation-v1.schema.json +0 -210
@@ -1,338 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { contentFingerprint, readStructuralSnapshot, } from "./structural-snapshot.js";
4
- function exactFile(repo, file) {
5
- try {
6
- return (contentFingerprint(fs.readFileSync(path.resolve(repo, file.path))) === file.contentFingerprint);
7
- }
8
- catch {
9
- return false;
10
- }
11
- }
12
- const DIRECT_FILE_EXTENSIONS = new Set([
13
- ".cjs",
14
- ".cs",
15
- ".cts",
16
- ".go",
17
- ".java",
18
- ".js",
19
- ".jsx",
20
- ".mjs",
21
- ".mts",
22
- ".py",
23
- ".rs",
24
- ".ts",
25
- ".tsx",
26
- ]);
27
- function lexicalEndLine(lines, startIndex, python) {
28
- if (python) {
29
- const indent = /^\s*/.exec(lines[startIndex])?.[0].length ?? 0;
30
- let end = startIndex + 1;
31
- for (let index = startIndex + 1; index < lines.length; index++) {
32
- const line = lines[index];
33
- if (line.trim() && (/^\s*/.exec(line)?.[0].length ?? 0) <= indent)
34
- break;
35
- end = index + 1;
36
- }
37
- return end;
38
- }
39
- let depth = 0;
40
- let opened = false;
41
- for (let index = startIndex; index < lines.length; index++) {
42
- for (const character of lines[index]) {
43
- if (character === "{") {
44
- opened = true;
45
- depth++;
46
- }
47
- else if (character === "}")
48
- depth--;
49
- }
50
- if (opened && depth <= 0)
51
- return index + 1;
52
- if (!opened && /[;}]\s*$/.test(lines[index]))
53
- return index + 1;
54
- }
55
- return startIndex + 1;
56
- }
57
- function genericFunctionSymbol(line) {
58
- const opening = line.indexOf("(");
59
- if (opening <= 0)
60
- return null;
61
- let depth = 0;
62
- let closing = -1;
63
- for (let index = opening; index < line.length; index += 1) {
64
- if (line[index] === "(")
65
- depth += 1;
66
- if (line[index] !== ")")
67
- continue;
68
- depth -= 1;
69
- if (depth === 0) {
70
- closing = index;
71
- break;
72
- }
73
- }
74
- if (closing < 0)
75
- return null;
76
- const suffix = line.slice(closing + 1).trimStart();
77
- if (!suffix.startsWith("{") && !suffix.startsWith("=>"))
78
- return null;
79
- const prefix = line.slice(0, opening).trim();
80
- if (/[=;{}()]/.test(prefix))
81
- return null;
82
- const tokens = prefix.split(/\s+/);
83
- const symbol = tokens.at(-1) ?? "";
84
- return tokens.length >= 2 && /^[A-Za-z_$][\w$]*$/.test(symbol) ? symbol : null;
85
- }
86
- function firstPatternSymbol(line, patterns) {
87
- for (const { kind, expression } of patterns) {
88
- const match = expression.exec(line);
89
- if (match)
90
- return { kind, symbol: match[1] };
91
- }
92
- return null;
93
- }
94
- function directSymbols(filePath, content) {
95
- const extension = path.extname(filePath).toLowerCase();
96
- const python = extension === ".py";
97
- const lines = content.split(/\r?\n/);
98
- const symbols = [];
99
- const patterns = python
100
- ? [
101
- { kind: "class", expression: /^\s*class\s+([A-Za-z_$][\w$]*)\b/ },
102
- { kind: "function", expression: /^\s*(?:async\s+)?def\s+([A-Za-z_$][\w$]*)\s*\(/ },
103
- ]
104
- : [
105
- {
106
- kind: "class",
107
- expression: /^\s*(?:(?:export|public|private|protected|internal|abstract|final|sealed|static)\s+)*(?:class|interface|enum|struct|trait|record|type)\s+([A-Za-z_$][\w$]*)\b/,
108
- },
109
- {
110
- kind: "function",
111
- expression: /^\s*(?:(?:export|public|private|protected|internal|async|static|final|pub(?:\([^)]*\))?)\s+)*(?:func|fn|function)\s+([A-Za-z_$][\w$]*)\s*\(/,
112
- },
113
- {
114
- kind: "function",
115
- expression: /^\s*(?:(?:export|const|let|var|public|private|protected|static|readonly)\s+)*([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>/,
116
- },
117
- ];
118
- for (const [index, line] of lines.entries()) {
119
- let found = firstPatternSymbol(line, patterns);
120
- if (!found && !python) {
121
- const symbol = genericFunctionSymbol(line);
122
- if (symbol)
123
- found = { kind: "function", symbol };
124
- }
125
- if (found) {
126
- const { kind, symbol } = found;
127
- const visibility = line.match(/\b(public|private|protected|internal)\b/)?.[1] ??
128
- (python && symbol.startsWith("_") ? "private" : "default");
129
- symbols.push({
130
- identity: null,
131
- symbol,
132
- kind,
133
- line: index + 1,
134
- endLine: lexicalEndLine(lines, index, python),
135
- signature: line
136
- .trim()
137
- .split(/\s*(?:\{|=>)\s*/, 1)[0]
138
- .slice(0, 500),
139
- visibility,
140
- exported: /\bexport\b/.test(line) || /\bpub\b/.test(line),
141
- evidenceQuality: "lexical-structural-fallback",
142
- });
143
- }
144
- }
145
- return symbols;
146
- }
147
- function directFile(repo, filePath) {
148
- if (!DIRECT_FILE_EXTENSIONS.has(path.extname(filePath).toLowerCase()))
149
- return null;
150
- const root = fs.realpathSync(repo);
151
- const absolute = path.resolve(root, filePath);
152
- let real;
153
- try {
154
- real = fs.realpathSync(absolute);
155
- }
156
- catch {
157
- return null;
158
- }
159
- const relative = path.relative(root, real);
160
- if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))
161
- return null;
162
- const content = fs.readFileSync(real, "utf8");
163
- return {
164
- path: relative.split(path.sep).join("/"),
165
- sizeBytes: Buffer.byteLength(content),
166
- mtimeMs: fs.statSync(real).mtimeMs,
167
- contentFingerprint: contentFingerprint(content),
168
- symbols: directSymbols(filePath, content),
169
- };
170
- }
171
- export function runStructuralFastPath(repo, pattern, target, limit = 100) {
172
- const snapshot = readStructuralSnapshot(repo);
173
- if (!snapshot && pattern !== "file_summary")
174
- return null;
175
- let matching = (snapshot?.files ?? []).filter((file) => !target || file.path.includes(target));
176
- if (pattern === "file_summary") {
177
- const indexed = matching.find((file) => file.path === target);
178
- if (!indexed || !exactFile(repo, indexed)) {
179
- const direct = directFile(repo, target);
180
- if (!direct)
181
- return null;
182
- matching = [direct];
183
- }
184
- }
185
- else if (pattern === "batch_outline") {
186
- matching = matching.flatMap((file) => {
187
- if (exactFile(repo, file))
188
- return [file];
189
- const direct = directFile(repo, file.path);
190
- return direct ? [direct] : [];
191
- });
192
- }
193
- let rows = [];
194
- let fingerprint;
195
- let fresh = false;
196
- if (pattern === "project_overview") {
197
- fresh = matching.every((file) => {
198
- try {
199
- const stat = fs.statSync(path.resolve(repo, file.path));
200
- return stat.size === file.sizeBytes && stat.mtimeMs === file.mtimeMs;
201
- }
202
- catch {
203
- return false;
204
- }
205
- });
206
- const directories = new Map();
207
- for (const file of matching) {
208
- const directory = file.path.includes("/") ? file.path.split("/", 1)[0] : ".";
209
- const value = directories.get(directory) ?? { fileCount: 0, sizeBytes: 0 };
210
- value.fileCount += 1;
211
- value.sizeBytes += file.sizeBytes;
212
- directories.set(directory, value);
213
- }
214
- rows = [...directories]
215
- .sort(([a], [b]) => a.localeCompare(b))
216
- .map(([symbol, value]) => ({ symbol, kind: "directory", ...value }));
217
- fingerprint = contentFingerprint(JSON.stringify(matching.map(({ path: file, contentFingerprint: hash }) => [file, hash])));
218
- }
219
- else {
220
- const files = pattern === "file_summary" ? matching.filter((file) => file.path === target) : matching;
221
- fresh = files.length > 0 && files.every((file) => exactFile(repo, file));
222
- fingerprint =
223
- files.length === 1
224
- ? files[0].contentFingerprint
225
- : contentFingerprint(JSON.stringify(files.map((file) => [file.path, file.contentFingerprint])));
226
- rows = files.flatMap((file) => file.symbols.map((symbol) => ({ ...symbol, file: file.path })));
227
- }
228
- const selected = rows.slice(0, limit);
229
- return {
230
- pattern,
231
- target,
232
- count: selected.length,
233
- results: selected,
234
- ...(rows.length > selected.length ? { hasMore: true } : {}),
235
- staleness: fresh ? "fresh" : "unknown",
236
- graphEnriched: false,
237
- evidence: {
238
- ...(pattern === "file_summary" ? { path: target } : {}),
239
- contentFingerprint: fingerprint,
240
- evidenceQuality: matching.some((file) => file.symbols.some((symbol) => symbol.evidenceQuality === "lexical-structural-fallback"))
241
- ? "direct-lexical-parser"
242
- : "indexed-structural-snapshot",
243
- uniqueness: pattern === "project_overview" ? "not-applicable" : "file-scoped-only",
244
- evidenceGeneratedAt: snapshot?.generatedAt ?? new Date().toISOString(),
245
- },
246
- upgrade: pattern === "file_summary"
247
- ? { operation: "explain", target }
248
- : pattern === "project_overview"
249
- ? { operation: "query", pattern: "architecture_overview", target: "" }
250
- : { operation: "query", pattern: "impact", target },
251
- };
252
- }
253
- export function runExactSymbolFastPath(repo, symbol, filePath) {
254
- const snapshot = readStructuralSnapshot(repo);
255
- const indexed = snapshot?.files.find((candidate) => candidate.path === filePath);
256
- const file = indexed && exactFile(repo, indexed) ? indexed : directFile(repo, filePath);
257
- if (!file)
258
- return null;
259
- const matches = file.symbols.filter((candidate) => candidate.symbol === symbol);
260
- if (matches.length === 0)
261
- return null;
262
- const fresh = exactFile(repo, file);
263
- const evidence = {
264
- path: filePath,
265
- contentFingerprint: file.contentFingerprint,
266
- evidenceQuality: file.symbols.some((candidate) => candidate.evidenceQuality === "lexical-structural-fallback")
267
- ? "direct-lexical-parser"
268
- : "indexed-structural-snapshot",
269
- uniqueness: "file-scoped-only",
270
- evidenceGeneratedAt: snapshot?.generatedAt ?? new Date().toISOString(),
271
- };
272
- if (matches.length > 1) {
273
- return {
274
- symbol,
275
- file: filePath,
276
- ambiguity: {
277
- candidates: matches.map((match) => ({
278
- identity: match.identity ?? "",
279
- file: filePath,
280
- kind: match.kind,
281
- line: match.line,
282
- })),
283
- },
284
- staleness: fresh ? "fresh" : "unknown",
285
- graphEnriched: false,
286
- evidence,
287
- upgrade: { operation: "explain", target: symbol },
288
- };
289
- }
290
- const match = matches[0];
291
- const lines = fs.readFileSync(path.resolve(repo, filePath), "utf8").split(/\r?\n/);
292
- const source = fresh
293
- ? lines
294
- .slice(match.line - 1, match.endLine)
295
- .map((line, offset) => `${match.line + offset}: ${line}`)
296
- .join("\n")
297
- : undefined;
298
- return {
299
- symbol,
300
- ...(match.identity ? { identity: match.identity } : {}),
301
- file: filePath,
302
- ...(source ? { source } : {}),
303
- staleness: fresh ? "fresh" : "unknown",
304
- graphEnriched: false,
305
- evidence,
306
- upgrade: { operation: "explain", target: symbol },
307
- };
308
- }
309
- export function tryStructuralFastPath(argv, cwd = process.cwd()) {
310
- const valueAfter = (flag) => {
311
- const index = argv.indexOf(flag);
312
- return index >= 0
313
- ? argv[index + 1]
314
- : argv.find((value) => value.startsWith(`${flag}=`))?.slice(flag.length + 1);
315
- };
316
- if (argv[0] === "explain" && argv[1] && valueAfter("--file")) {
317
- const repo = path.resolve(valueAfter("--repo") ?? cwd);
318
- const result = runExactSymbolFastPath(repo, argv[1], valueAfter("--file"));
319
- if (!result)
320
- return false;
321
- process.stdout.write(`${JSON.stringify(result)}\n`);
322
- return true;
323
- }
324
- if (argv[0] !== "query" ||
325
- !["file_summary", "batch_outline", "project_overview"].includes(argv[1] ?? ""))
326
- return false;
327
- const pattern = argv[1];
328
- const repo = path.resolve(valueAfter("--repo") ?? cwd);
329
- const target = pattern === "project_overview" ? "" : (argv[2] ?? "");
330
- const limit = Number(valueAfter("--limit") ?? 100);
331
- if (!target && pattern !== "project_overview")
332
- return false;
333
- const result = runStructuralFastPath(repo, pattern, target, Number.isInteger(limit) && limit > 0 ? limit : 100);
334
- if (!result)
335
- return false;
336
- process.stdout.write(`${JSON.stringify(result)}\n`);
337
- return true;
338
- }
@@ -1,33 +0,0 @@
1
- import crypto from "node:crypto";
2
- import fs from "node:fs";
3
- import path from "node:path";
4
- export const STRUCTURAL_SNAPSHOT_VERSION = 1;
5
- export function contentFingerprint(content) {
6
- return `sha256:${crypto.createHash("sha256").update(content).digest("hex")}`;
7
- }
8
- export function structuralSnapshotPath(repo) {
9
- return path.join(path.resolve(repo), ".knodin", "structural-v1.json");
10
- }
11
- export function writeStructuralSnapshot(repo, files) {
12
- const destination = structuralSnapshotPath(repo);
13
- fs.mkdirSync(path.dirname(destination), { recursive: true });
14
- const snapshot = {
15
- schemaVersion: STRUCTURAL_SNAPSHOT_VERSION,
16
- generatedAt: new Date().toISOString(),
17
- files: [...files].sort((left, right) => left.path.localeCompare(right.path)),
18
- };
19
- const temporary = `${destination}.${process.pid}.tmp`;
20
- fs.writeFileSync(temporary, `${JSON.stringify(snapshot)}\n`, { mode: 0o600 });
21
- fs.renameSync(temporary, destination);
22
- }
23
- export function readStructuralSnapshot(repo) {
24
- try {
25
- const parsed = JSON.parse(fs.readFileSync(structuralSnapshotPath(repo), "utf8"));
26
- return parsed?.schemaVersion === STRUCTURAL_SNAPSHOT_VERSION && Array.isArray(parsed.files)
27
- ? parsed
28
- : null;
29
- }
30
- catch {
31
- return null;
32
- }
33
- }