knodin 0.7.4 → 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 (104) 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 -110
  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 -73
  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/schemas/release-attestation-v1.schema.json +0 -210
@@ -1,262 +0,0 @@
1
- const DEFAULT_PROGRESS_INTERVAL_MS = 30_000;
2
- const TTY_THROTTLE_MS = 100;
3
- const CLEAR_TTY_LINE = "\r\x1b[2K";
4
- const TERMINAL_PHASES = new Set(["completed", "cancelled", "failed"]);
5
- const RESPONSE_BUDGET_FLAGS = new Set(["--bytes", "--tokens", "--items"]);
6
- function parseDuration(value) {
7
- const match = /^(\d+(?:\.\d+)?)(ms|s|m)$/.exec(value.trim());
8
- if (!match) {
9
- throw new Error("knodin repair: --progress-interval must be a positive duration such as 750ms, 30s, or 2m");
10
- }
11
- const amount = Number(match[1]);
12
- const multiplier = match[2] === "ms" ? 1 : match[2] === "s" ? 1_000 : 60_000;
13
- const milliseconds = amount * multiplier;
14
- if (!Number.isFinite(milliseconds) || milliseconds <= 0) {
15
- throw new Error("knodin repair: --progress-interval must be a positive duration");
16
- }
17
- return milliseconds;
18
- }
19
- export function parseRepairCliArgs(args) {
20
- let progress = "auto";
21
- let progressExplicit = false;
22
- let progressIntervalMs = DEFAULT_PROGRESS_INTERVAL_MS;
23
- let json = false;
24
- let jsonl = false;
25
- let plan = false;
26
- const seen = new Set();
27
- const markSeen = (flag) => {
28
- if (seen.has(flag))
29
- throw new Error(`knodin repair: repeated ${flag} argument`);
30
- seen.add(flag);
31
- };
32
- const consumeValue = (flag, index) => {
33
- const value = args[index + 1];
34
- if (!value || value.startsWith("--"))
35
- throw new Error(`knodin repair: ${flag} requires a value`);
36
- return value;
37
- };
38
- for (let index = 0; index < args.length; index++) {
39
- const argument = args[index];
40
- if (argument === "--plan") {
41
- markSeen(argument);
42
- plan = true;
43
- continue;
44
- }
45
- if (argument === "--json" || argument === "--jsonl") {
46
- markSeen(argument);
47
- if (argument === "--json")
48
- json = true;
49
- else
50
- jsonl = true;
51
- continue;
52
- }
53
- if (argument === "--progress" || argument.startsWith("--progress=")) {
54
- markSeen("--progress");
55
- const value = argument === "--progress"
56
- ? consumeValue("--progress", index++)
57
- : argument.slice("--progress=".length);
58
- if (!value)
59
- throw new Error("knodin repair: --progress requires a value");
60
- if (!["auto", "tty", "plain", "none"].includes(value)) {
61
- throw new Error("knodin repair: --progress must be auto, tty, plain, or none");
62
- }
63
- progress = value;
64
- progressExplicit = true;
65
- continue;
66
- }
67
- if (argument === "--progress-interval" || argument.startsWith("--progress-interval=")) {
68
- markSeen("--progress-interval");
69
- const value = argument === "--progress-interval"
70
- ? consumeValue("--progress-interval", index++)
71
- : argument.slice("--progress-interval=".length);
72
- if (!value)
73
- throw new Error("knodin repair: --progress-interval requires a value");
74
- progressIntervalMs = parseDuration(value);
75
- continue;
76
- }
77
- if (RESPONSE_BUDGET_FLAGS.has(argument)) {
78
- markSeen(argument);
79
- consumeValue(argument, index++);
80
- continue;
81
- }
82
- if (argument.startsWith("--")) {
83
- throw new Error(`knodin repair: unknown argument ${argument}`);
84
- }
85
- throw new Error(`knodin repair: unexpected positional argument ${argument}`);
86
- }
87
- if (json && jsonl)
88
- throw new Error("knodin repair: --json and --jsonl are mutually exclusive");
89
- return {
90
- progress,
91
- progressExplicit,
92
- progressIntervalMs,
93
- output: jsonl ? "jsonl" : json ? "json" : "human",
94
- plan,
95
- };
96
- }
97
- export function createRepairPlan(health) {
98
- const staleRecords = health.missing.records.filter((record) => /^(indexed file no longer exists|indexed file is no longer eligible): /.test(record));
99
- const damagedSnapshots = health.missing.records.filter((record) => record.startsWith("indexed snapshot differs from disk: "));
100
- const incompletePostProcessing = health.missing.records.filter((record) => record.includes("post-processing is incomplete"));
101
- const fileReconciliations = new Set([
102
- ...health.missing.files,
103
- ...staleRecords.map((record) => record.slice(record.indexOf(": ") + 2)),
104
- ...damagedSnapshots.map((record) => record.slice(record.indexOf(": ") + 2)),
105
- ]);
106
- const orphanGroups = Object.values(health.orphaned).filter((count) => count > 0).length;
107
- return {
108
- schemaVersion: 1,
109
- mutating: false,
110
- healthFindings: {
111
- missingFiles: health.missing.files.length,
112
- damagedSnapshots: damagedSnapshots.length,
113
- staleOrIneligibleRecords: staleRecords.length,
114
- orphanedEmbeddings: health.orphaned.embeddings,
115
- orphanedReferences: health.orphaned.references,
116
- orphanedDependencies: health.orphaned.dependencies,
117
- incompletePostProcessing: incompletePostProcessing.length,
118
- total: health.missing.files.length +
119
- health.missing.records.length +
120
- Object.values(health.orphaned).reduce((sum, count) => sum + count, 0),
121
- },
122
- operations: {
123
- fileReconciliations: fileReconciliations.size,
124
- removals: staleRecords.length,
125
- identityPasses: fileReconciliations.size > 0 ? 1 : 0,
126
- embeddingCandidates: fileReconciliations.size,
127
- orphanCleanupGroups: orphanGroups,
128
- verification: 1,
129
- total: fileReconciliations.size +
130
- staleRecords.length +
131
- (fileReconciliations.size > 0 ? 1 : 0) +
132
- fileReconciliations.size +
133
- orphanGroups +
134
- 1,
135
- },
136
- explanation: "Health findings count observed problems; operations count bounded repair actions, so the totals need not match one-to-one.",
137
- health,
138
- };
139
- }
140
- export function resolveRepairProgressMode(options, environment, stderrIsTTY) {
141
- if (options.output === "jsonl")
142
- return "jsonl";
143
- if (options.output === "json" && !options.progressExplicit)
144
- return "none";
145
- if (options.progress !== "auto")
146
- return options.progress;
147
- const ci = environment.CI;
148
- const runsInCi = ci !== undefined && ci !== "" && ci !== "0" && ci.toLowerCase() !== "false";
149
- return stderrIsTTY && !runsInCi && environment.TERM?.toLowerCase() !== "dumb" ? "tty" : "plain";
150
- }
151
- export function formatRepairProgress(event) {
152
- const total = event.phaseTotal === undefined
153
- ? `${event.phaseCompleted}`
154
- : `${event.phaseCompleted}/${event.phaseTotal}`;
155
- const location = [event.currentFamily, event.currentPath].filter(Boolean).join(" ");
156
- const suffix = location ? ` — ${location}` : "";
157
- return `[repair:${event.phase}] ${total} ${event.message}${suffix}`;
158
- }
159
- export function createRepairProgressRenderer(options) {
160
- const now = options.now ?? Date.now;
161
- const schedule = options.setTimeout ??
162
- ((callback, intervalMs) => setTimeout(callback, intervalMs));
163
- const unschedule = options.clearTimeout ?? ((handle) => clearTimeout(handle));
164
- let heartbeatHandle;
165
- let started = false;
166
- let stopped = false;
167
- let ttyHasLine = false;
168
- let lastWriteAt = Number.NEGATIVE_INFINITY;
169
- let lastEvent;
170
- let lastPhase;
171
- let lastPercentBucket = -1;
172
- const scheduleHeartbeat = () => {
173
- if (options.mode !== "plain" && options.mode !== "tty")
174
- return;
175
- if (heartbeatHandle !== undefined)
176
- unschedule(heartbeatHandle);
177
- const heartbeatDelay = options.mode === "tty" ? Math.max(options.intervalMs, TTY_THROTTLE_MS) : options.intervalMs;
178
- heartbeatHandle = schedule(() => {
179
- heartbeatHandle = undefined;
180
- if (stopped)
181
- return;
182
- if (lastEvent) {
183
- if (options.mode === "plain")
184
- writePlain(`${formatRepairProgress(lastEvent)} (heartbeat)`);
185
- else
186
- writeTty(`${formatRepairProgress(lastEvent)} (heartbeat)`);
187
- }
188
- scheduleHeartbeat();
189
- }, heartbeatDelay);
190
- if (typeof heartbeatHandle === "object" &&
191
- heartbeatHandle !== null &&
192
- "unref" in heartbeatHandle) {
193
- heartbeatHandle.unref();
194
- }
195
- };
196
- const writePlain = (line) => {
197
- options.stderr.write(`${line}\n`);
198
- lastWriteAt = now();
199
- scheduleHeartbeat();
200
- };
201
- const writeTty = (line) => {
202
- options.stderr.write(`${CLEAR_TTY_LINE}${line}`);
203
- ttyHasLine = true;
204
- lastWriteAt = now();
205
- scheduleHeartbeat();
206
- };
207
- return {
208
- start() {
209
- if (started || stopped)
210
- return;
211
- started = true;
212
- if (options.mode === "tty")
213
- writeTty("Starting repair…");
214
- else if (options.mode === "plain")
215
- writePlain("[repair] Starting repair");
216
- },
217
- onProgress(event) {
218
- if (stopped)
219
- return;
220
- if (!started)
221
- this.start();
222
- lastEvent = event;
223
- if (options.mode === "none")
224
- return;
225
- if (options.mode === "jsonl") {
226
- options.stdout.write(serializeRepairJsonlRecord("progress", event));
227
- return;
228
- }
229
- if (options.mode === "tty") {
230
- if (now() - lastWriteAt < TTY_THROTTLE_MS && !TERMINAL_PHASES.has(event.phase))
231
- return;
232
- writeTty(formatRepairProgress(event));
233
- return;
234
- }
235
- const phaseChanged = event.phase !== lastPhase;
236
- const percentage = event.phaseTotal && event.phaseTotal > 0
237
- ? Math.floor((event.phaseCompleted / event.phaseTotal) * 100)
238
- : undefined;
239
- const percentBucket = percentage === undefined ? -1 : Math.floor(percentage / 5);
240
- if (phaseChanged || percentBucket > lastPercentBucket) {
241
- writePlain(formatRepairProgress(event));
242
- if (phaseChanged)
243
- lastPercentBucket = percentBucket;
244
- else
245
- lastPercentBucket = Math.max(lastPercentBucket, percentBucket);
246
- lastPhase = event.phase;
247
- }
248
- },
249
- stop() {
250
- if (stopped)
251
- return;
252
- stopped = true;
253
- if (heartbeatHandle !== undefined)
254
- unschedule(heartbeatHandle);
255
- if (options.mode === "tty" && ttyHasLine)
256
- options.stderr.write("\n");
257
- },
258
- };
259
- }
260
- export function serializeRepairJsonlRecord(type, value) {
261
- return `${JSON.stringify(type === "progress" ? { type, event: value } : { type, result: value })}\n`;
262
- }
@@ -1,173 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import process from "node:process";
3
- export const DEFAULT_REPOSITORY_INIT_MEMORY_LIMIT_BYTES = 768 * 1024 * 1024;
4
- const MAX_DIAGNOSTIC_BYTES = 64 * 1024;
5
- const TERMINATION_GRACE_MS = 1_000;
6
- const RSS_POLL_MS = 250;
7
- function boundedAppend(current, chunk) {
8
- if (current.length >= MAX_DIAGNOSTIC_BYTES)
9
- return current;
10
- return `${current}${chunk.toString("utf-8")}`.slice(0, MAX_DIAGNOSTIC_BYTES);
11
- }
12
- function terminateProcessTree(pid) {
13
- if (!Number.isSafeInteger(pid) || pid <= 1)
14
- return;
15
- try {
16
- process.kill(process.platform === "win32" ? pid : -pid, "SIGTERM");
17
- }
18
- catch {
19
- // The worker may have exited between observation and termination.
20
- }
21
- }
22
- function forceTerminateProcessTree(pid) {
23
- if (!Number.isSafeInteger(pid) || pid <= 1)
24
- return;
25
- try {
26
- process.kill(process.platform === "win32" ? pid : -pid, "SIGKILL");
27
- }
28
- catch {
29
- // Already terminated.
30
- }
31
- }
32
- function isWorkerMessage(value) {
33
- if (!value || typeof value !== "object")
34
- return false;
35
- const record = value;
36
- const result = record.result;
37
- return ((record.type === "rss" &&
38
- Number.isSafeInteger(record.rssBytes) &&
39
- Number(record.rssBytes) >= 0) ||
40
- (record.type === "result" &&
41
- Boolean(result) &&
42
- typeof result?.repository === "string" &&
43
- typeof result.message === "string" &&
44
- ["initialized", "updated", "already-current", "skipped", "failed"].includes(String(result.status))));
45
- }
46
- /**
47
- * Initialize one repository in a disposable process. The parent observes RSS
48
- * heartbeats, kills the whole process group on a ceiling breach, and converts
49
- * every worker failure into a repository-scoped result so the portfolio can
50
- * continue.
51
- */
52
- export async function runRepositoryInitializationProcess(options) {
53
- const memoryLimitBytes = options.memoryLimitBytes ?? DEFAULT_REPOSITORY_INIT_MEMORY_LIMIT_BYTES;
54
- if (!Number.isSafeInteger(memoryLimitBytes) || memoryLimitBytes < 128 * 1024 * 1024)
55
- throw new Error("repository init memory limit must be an integer of at least 128 MiB");
56
- if (options.command.length === 0 || !options.command[0])
57
- throw new Error("repository init worker command is empty");
58
- return await new Promise((resolve) => {
59
- let stderr = "";
60
- let peakRssBytes = 0;
61
- let result;
62
- let exceeded = false;
63
- let timedOut = false;
64
- let settled = false;
65
- let rssPollRunning = false;
66
- const child = spawn(options.command[0], [...options.command.slice(1), "__repository-init-worker", options.repository], {
67
- cwd: options.repository,
68
- detached: process.platform !== "win32",
69
- env: {
70
- ...process.env,
71
- KNODIN_INTERNAL_INIT_MEMORY_LIMIT_BYTES: String(memoryLimitBytes),
72
- },
73
- stdio: ["ignore", "ignore", "pipe", "ipc"],
74
- });
75
- child.stderr?.on("data", (chunk) => {
76
- stderr = boundedAppend(stderr, chunk);
77
- });
78
- const observeRss = (rssBytes) => {
79
- peakRssBytes = Math.max(peakRssBytes, rssBytes);
80
- if (rssBytes <= memoryLimitBytes || exceeded)
81
- return;
82
- exceeded = true;
83
- const pid = child.pid ?? 0;
84
- terminateProcessTree(pid);
85
- setTimeout(() => forceTerminateProcessTree(pid), TERMINATION_GRACE_MS).unref();
86
- };
87
- child.on("message", (message) => {
88
- if (!isWorkerMessage(message))
89
- return;
90
- if (message.type === "result") {
91
- result = message.result;
92
- return;
93
- }
94
- observeRss(message.rssBytes);
95
- });
96
- const rssPoll = setInterval(() => {
97
- const pid = child.pid;
98
- if (process.platform === "win32" || !pid || rssPollRunning || settled)
99
- return;
100
- rssPollRunning = true;
101
- const probe = spawn("/bin/ps", ["-o", "rss=", "-p", String(pid)], {
102
- stdio: ["ignore", "pipe", "ignore"],
103
- });
104
- let output = "";
105
- probe.stdout?.on("data", (chunk) => {
106
- output = boundedAppend(output, chunk);
107
- });
108
- probe.on("close", () => {
109
- rssPollRunning = false;
110
- if (settled)
111
- return;
112
- const rssKiB = Number.parseInt(output.trim(), 10);
113
- if (Number.isSafeInteger(rssKiB) && rssKiB >= 0)
114
- observeRss(rssKiB * 1024);
115
- });
116
- probe.on("error", () => {
117
- rssPollRunning = false;
118
- });
119
- }, RSS_POLL_MS);
120
- rssPoll.unref();
121
- child.on("error", (error) => {
122
- stderr = boundedAppend(stderr, Buffer.from(error.message));
123
- });
124
- const timeout = setTimeout(() => {
125
- timedOut = true;
126
- const pid = child.pid ?? 0;
127
- terminateProcessTree(pid);
128
- setTimeout(() => forceTerminateProcessTree(pid), TERMINATION_GRACE_MS).unref();
129
- }, options.timeoutMs ?? 30 * 60_000);
130
- timeout.unref();
131
- child.on("close", (code, signal) => {
132
- if (settled)
133
- return;
134
- settled = true;
135
- clearTimeout(timeout);
136
- clearInterval(rssPoll);
137
- if (exceeded) {
138
- resolve({
139
- repository: options.repository,
140
- status: "failed",
141
- message: `memory ceiling exceeded (${peakRssBytes} > ${memoryLimitBytes} bytes); worker terminated`,
142
- peakRssBytes,
143
- memoryLimitBytes,
144
- });
145
- return;
146
- }
147
- if (timedOut) {
148
- resolve({
149
- repository: options.repository,
150
- status: "failed",
151
- message: "isolated initialization timed out; worker process tree terminated",
152
- peakRssBytes,
153
- memoryLimitBytes,
154
- });
155
- return;
156
- }
157
- if (result) {
158
- resolve({ ...result, repository: options.repository, peakRssBytes, memoryLimitBytes });
159
- return;
160
- }
161
- const diagnostic = stderr.trim().replace(/\s+/g, " ");
162
- const outcome = signal ? `signal ${signal}` : `exit ${code ?? "unknown"}`;
163
- const detail = diagnostic ? `: ${diagnostic}` : "";
164
- resolve({
165
- repository: options.repository,
166
- status: "failed",
167
- message: `isolated initialization failed (${outcome})${detail}`,
168
- peakRssBytes,
169
- memoryLimitBytes,
170
- });
171
- });
172
- });
173
- }