@hraness/wordcell 0.21.2 → 0.21.3

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/dist/cli.js CHANGED
@@ -1,3820 +1,75 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
  import {
4
- backfillSavedUrlMetadata,
5
- createRustMetadataSearchProvider
6
- } from "./index-bcknqxrq.js";
7
- import {
8
- MAX_AUTHORIZED_VAULTS,
9
- auditKnowledgePortfolio,
10
- loadPortfolioRegistry,
11
- openKnowledgePortfolio,
12
- snapshotPortfolioRegistry
13
- } from "./index-51bap0mq.js";
14
- import {
15
- main as main2
16
- } from "./index-054mb7d3.js";
17
- import {
18
- diffCaptureBundle
19
- } from "./index-j4zgmzjr.js";
20
- import {
21
- verifyCaptureBundle
22
- } from "./index-npg9z1a4.js";
23
- import {
24
- initVault
25
- } from "./index-23z4zxgg.js";
26
- import {
27
- MAX_SOURCE_INBOX_PREFIXES,
28
- MAX_SOURCE_INBOX_RESULTS,
29
- sourceInbox
30
- } from "./index-pj501bh1.js";
31
- import {
32
- knowledgeBaseEvaluationRetrieverIds,
33
- openKnowledgeBaseEvaluation
34
- } from "./index-pbr6rv47.js";
35
- import {
36
- DEFAULT_SEARCH_RESULTS,
37
- MAX_SEARCH_CANDIDATES,
38
- MAX_SEARCH_NOTE_REFERENCE_BYTES,
39
- MAX_SEARCH_RELATED_SEEDS,
40
- MAX_SEARCH_RESULTS,
41
- openKnowledgeBase
42
- } from "./index-vdw5yjfa.js";
4
+ main,
5
+ parseArguments,
6
+ runExecutable,
7
+ usage
8
+ } from "./index-0rfcqab6.js";
9
+ import"./index-bcknqxrq.js";
10
+ import"./index-51bap0mq.js";
11
+ import"./index-054mb7d3.js";
12
+ import"./index-j4zgmzjr.js";
13
+ import"./index-npg9z1a4.js";
14
+ import"./index-23z4zxgg.js";
15
+ import"./index-pj501bh1.js";
16
+ import"./index-pbr6rv47.js";
17
+ import"./index-vdw5yjfa.js";
43
18
  import"./index-4j3tt0c3.js";
44
- import {
45
- MAX_SEARCH_RULE_CONFIG_BYTES,
46
- parseSearchRules
47
- } from "./index-adx6khj5.js";
48
- import {
49
- indexSemanticVault,
50
- qmdIndexerVersion,
51
- recommendedEmbeddingModel,
52
- recommendedEmbeddingModelSha256,
53
- sha256EmbeddingModelFile
54
- } from "./index-115b07ap.js";
55
- import {
56
- percolateWithGraph
57
- } from "./index-bgfzwt4h.js";
58
- import {
59
- queryGraph,
60
- rebuildGraph,
61
- verifyGraph
62
- } from "./index-bcfn9xah.js";
63
- import {
64
- validateGraphQueryRequest
65
- } from "./index-11621h23.js";
66
- import {
67
- refreshVault,
68
- scanVault
69
- } from "./index-0k2x4nn9.js";
70
- import {
71
- MAX_PERCOLATION_MENTIONS,
72
- MAX_PERCOLATION_MENTION_PAIRS,
73
- MAX_PERCOLATION_NOTES,
74
- MAX_SCOPED_PERCOLATION_MENTION_PAIRS,
75
- percolateVault
76
- } from "./index-nd6nynv2.js";
19
+ import"./index-adx6khj5.js";
20
+ import"./index-115b07ap.js";
21
+ import"./index-bgfzwt4h.js";
22
+ import"./index-bcfn9xah.js";
23
+ import"./index-11621h23.js";
24
+ import"./index-0k2x4nn9.js";
25
+ import"./index-nd6nynv2.js";
77
26
  import"./index-1gwbassd.js";
78
- import {
79
- MAX_EVALUATION_RESULTS_PER_QUERY,
80
- MAX_EVALUATION_TIMEOUT_MS,
81
- buildRetrievalEvaluationReport,
82
- parseRetrievalEvaluationCorpus,
83
- runRetrievalEvaluation
84
- } from "./index-b88v3vtm.js";
85
- import {
86
- auditAgentGuideRepository
87
- } from "./index-hya40gb2.js";
88
- import {
89
- validateMarkdownAttachments
90
- } from "./index-x3fthpsc.js";
91
- import {
92
- addNoteRelation,
93
- createNote,
94
- removeNoteRelation
95
- } from "./index-6sw24nvv.js";
27
+ import"./index-b88v3vtm.js";
28
+ import"./index-hya40gb2.js";
29
+ import"./index-x3fthpsc.js";
30
+ import"./index-6sw24nvv.js";
96
31
  import"./index-3rm7cz6h.js";
97
- import {
98
- validateSearchQuery
99
- } from "./index-why54q5p.js";
100
- import {
101
- MAX_QUERY_FILTERS,
102
- MAX_QUERY_TAGS,
103
- queryVault,
104
- validateQueryOptions
105
- } from "./index-48pz4jpc.js";
106
- import {
107
- MAX_REPOSITORY_SCOPES,
108
- buildRepositoryMemoryContext,
109
- repositoryMemoryGroupKeys
110
- } from "./index-06c9ctr6.js";
111
- import {
112
- navigateLinks
113
- } from "./index-d13v9ckt.js";
114
- import {
115
- agentContextGuidePath,
116
- agentContextMarkerForScope,
117
- agentContextNoteId,
118
- agentContextNotePath,
119
- analyzeAgentContexts,
120
- inspectAgentContextRepository,
121
- normalizeRepositoryScope
122
- } from "./index-5vwpzb5a.js";
123
- import {
124
- lookupNote,
125
- parseVaultKey,
126
- renderCatalog
127
- } from "./index-ekpwvbra.js";
128
- import {
129
- main
130
- } from "./index-180zbkkt.js";
32
+ import"./index-why54q5p.js";
33
+ import"./index-48pz4jpc.js";
34
+ import"./index-06c9ctr6.js";
35
+ import"./index-d13v9ckt.js";
36
+ import"./index-5vwpzb5a.js";
37
+ import"./index-ekpwvbra.js";
38
+ import"./index-9zcpdbjg.js";
131
39
  import"./index-6jcz0m1c.js";
132
40
  import"./index-f984hw45.js";
133
- import"./index-by0pbant.js";
134
- import {
135
- findKbPackageRoot
136
- } from "./index-x6m57nfc.js";
41
+ import"./index-van48n3g.js";
42
+ import"./index-jzcws0zn.js";
137
43
  import"./index-hgve9rh2.js";
138
44
  import"./index-w2zc0vwa.js";
139
45
  import"./index-e5fbsywq.js";
140
46
  import"./index-dfag79p7.js";
141
47
  import"./index-gh719d91.js";
142
- import {
143
- redactSensitiveText
144
- } from "./index-mxxxytys.js";
48
+ import"./index-mxxxytys.js";
145
49
  import"./index-2gv8y733.js";
146
- import {
147
- sanitizeTerminalLine,
148
- sanitizeTerminalText
149
- } from "./index-1xxnjn0d.js";
50
+ import"./index-1xxnjn0d.js";
150
51
  import"./index-5n05se68.js";
151
- import"./index-z1w83f81.js";
152
-
153
- // src/cli-intro.ts
154
- function terminalIntro(terminal) {
155
- if (terminal.isTTY !== true || terminal.term === "dumb" || (terminal.columns ?? 80) < 48)
156
- return "";
157
- return ` .----. /
158
- | ===| / wordcell
159
- | ===|/ Markdown memory for your agents.
160
- |____/
161
-
162
- `;
163
- }
164
-
165
- // src/cli-program.ts
166
- import { open } from "fs/promises";
167
- import { cpus, release, totalmem } from "os";
168
- import { relative, resolve as resolve3 } from "path";
169
- import { format } from "util";
170
-
171
- // src/clip/url-metadata-cli.ts
172
- import { resolve as resolve2 } from "path";
173
-
174
- // src/clip/metadata-search-tool/runner.ts
175
- import { randomUUID } from "crypto";
176
52
  import {
177
- closeSync,
178
- constants,
179
- fchmodSync,
180
- fstatSync,
181
- fsyncSync,
182
- lstatSync,
183
- mkdirSync,
184
- mkdtempSync,
185
- openSync,
186
- readSync,
187
- renameSync,
188
- rmSync,
189
- writeSync
190
- } from "fs";
191
- import { tmpdir } from "os";
192
- import { basename, dirname, isAbsolute, join, resolve } from "path";
193
- var TEMPORARY_DIRECTORY_PREFIX = "hraness-wordcell-metadata-search-tool-";
194
- var MAX_EXECUTABLE_BYTES = 64 * 1024 * 1024;
195
- var COPY_BUFFER_BYTES = 64 * 1024;
196
- function noFollowFlag() {
197
- return typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
198
- }
199
- function directoryFlag() {
200
- return typeof constants.O_DIRECTORY === "number" ? constants.O_DIRECTORY : 0;
201
- }
202
- function errorCode(error) {
203
- return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : undefined;
204
- }
205
- function maybeLstat(path) {
206
- try {
207
- return lstatSync(path, { bigint: true });
208
- } catch (error) {
209
- if (errorCode(error) === "ENOENT")
210
- return null;
211
- throw error;
212
- }
213
- }
214
- function sameDirectoryIdentity(left, right) {
215
- return left.dev === right.dev && left.ino === right.ino;
216
- }
217
- function sameFileIdentity(left, right) {
218
- return sameDirectoryIdentity(left, right) && left.size === right.size && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs;
219
- }
220
- function sameInstalledFile(left, right) {
221
- return sameDirectoryIdentity(left, right) && left.size === right.size && left.mtimeNs === right.mtimeNs;
222
- }
223
- function assertOwnedByCurrentUser(stat, label) {
224
- if (process.platform === "win32" || typeof process.getuid !== "function")
225
- return;
226
- if (stat.uid !== BigInt(process.getuid())) {
227
- throw new Error(`${label} must be owned by the current user`);
228
- }
229
- }
230
- function assertDirectory(stat, label) {
231
- if (stat === null || stat.isSymbolicLink() || !stat.isDirectory()) {
232
- throw new Error(`${label} must be a real directory`);
233
- }
234
- assertOwnedByCurrentUser(stat, label);
235
- }
236
- function openBoundDirectory(path, label) {
237
- const before = maybeLstat(path);
238
- assertDirectory(before, label);
239
- const descriptor = openSync(path, constants.O_RDONLY | directoryFlag() | noFollowFlag());
240
- try {
241
- const opened = fstatSync(descriptor, { bigint: true });
242
- if (!opened.isDirectory() || !sameDirectoryIdentity(before, opened)) {
243
- throw new Error(`${label} changed while it was opened`);
244
- }
245
- return { path, descriptor, identity: opened };
246
- } catch (error) {
247
- closeSync(descriptor);
248
- throw error;
249
- }
250
- }
251
- function assertDirectoryBinding(binding, label) {
252
- const byPath = maybeLstat(binding.path);
253
- assertDirectory(byPath, label);
254
- const byDescriptor = fstatSync(binding.descriptor, { bigint: true });
255
- if (!sameDirectoryIdentity(binding.identity, byPath) || !sameDirectoryIdentity(binding.identity, byDescriptor)) {
256
- throw new Error(`${label} changed during installation`);
257
- }
258
- }
259
- function ensurePrivateDirectory(path, label) {
260
- let created = false;
261
- try {
262
- mkdirSync(path, { mode: 448 });
263
- created = true;
264
- } catch (error) {
265
- if (errorCode(error) !== "EEXIST")
266
- throw error;
267
- }
268
- const before = maybeLstat(path);
269
- assertDirectory(before, label);
270
- const binding = openBoundDirectory(path, label);
271
- try {
272
- if (process.platform !== "win32") {
273
- fchmodSync(binding.descriptor, 448);
274
- }
275
- const identity = fstatSync(binding.descriptor, { bigint: true });
276
- return { binding: { ...binding, identity }, created };
277
- } catch (error) {
278
- closeSync(binding.descriptor);
279
- throw error;
280
- }
281
- }
282
- function assertExecutableSource(stat, platform) {
283
- if (!stat.isFile() || stat.isSymbolicLink()) {
284
- throw new Error("Cargo release output must be a regular file");
285
- }
286
- if (stat.nlink !== 1n) {
287
- throw new Error("Cargo release output must not be hard-linked");
288
- }
289
- if (stat.size < 1n || stat.size > BigInt(MAX_EXECUTABLE_BYTES)) {
290
- throw new Error(`Cargo release output must contain 1-${MAX_EXECUTABLE_BYTES} bytes`);
291
- }
292
- if (platform !== "win32" && (stat.mode & 0o111n) === 0n) {
293
- throw new Error("Cargo release output must be executable");
294
- }
295
- assertOwnedByCurrentUser(stat, "Cargo release output");
296
- }
297
- function assertExistingDestination(stat, platform) {
298
- assertExecutableSource(stat, platform);
299
- if (platform !== "win32" && (stat.mode & 0o777n) !== 0o700n) {
300
- throw new Error("installed metadata-search executable has unsafe permissions");
301
- }
302
- }
303
- function writeAll(descriptor, buffer, length) {
304
- let offset = 0;
305
- while (offset < length) {
306
- const written = writeSync(descriptor, buffer, offset, length - offset);
307
- if (written < 1)
308
- throw new Error("could not write the staged executable");
309
- offset += written;
310
- }
311
- }
312
- function copyValidatedExecutable(sourcePath, stagingPath, platform) {
313
- const sourceDescriptor = openSync(sourcePath, constants.O_RDONLY | noFollowFlag());
314
- let stagingDescriptor = null;
315
- let staged = null;
316
- let complete = false;
317
- try {
318
- const sourceBefore = fstatSync(sourceDescriptor, { bigint: true });
319
- assertExecutableSource(sourceBefore, platform);
320
- stagingDescriptor = openSync(stagingPath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | noFollowFlag(), 448);
321
- if (platform !== "win32")
322
- fchmodSync(stagingDescriptor, 448);
323
- const buffer = Buffer.allocUnsafe(COPY_BUFFER_BYTES);
324
- let copiedBytes = 0;
325
- const expectedBytes = Number(sourceBefore.size);
326
- while (copiedBytes < expectedBytes) {
327
- const bytesRead = readSync(sourceDescriptor, buffer, 0, Math.min(buffer.byteLength, expectedBytes - copiedBytes), null);
328
- if (bytesRead < 1) {
329
- throw new Error("Cargo release output changed while it was copied");
330
- }
331
- writeAll(stagingDescriptor, buffer, bytesRead);
332
- copiedBytes += bytesRead;
333
- }
334
- if (readSync(sourceDescriptor, buffer, 0, 1, null) !== 0) {
335
- throw new Error("Cargo release output grew while it was copied");
336
- }
337
- const sourceAfter = fstatSync(sourceDescriptor, { bigint: true });
338
- if (!sameFileIdentity(sourceBefore, sourceAfter)) {
339
- throw new Error("Cargo release output changed while it was copied");
340
- }
341
- const sourceByPath = maybeLstat(sourcePath);
342
- if (sourceByPath === null || !sameFileIdentity(sourceBefore, sourceByPath)) {
343
- throw new Error("Cargo release output path changed while it was copied");
344
- }
345
- fsyncSync(stagingDescriptor);
346
- staged = fstatSync(stagingDescriptor, { bigint: true });
347
- if (!staged.isFile() || staged.nlink !== 1n || staged.size !== sourceBefore.size) {
348
- throw new Error("staged metadata-search executable failed validation");
349
- }
350
- complete = true;
351
- return staged;
352
- } finally {
353
- if (stagingDescriptor !== null) {
354
- if (!complete)
355
- staged = fstatSync(stagingDescriptor, { bigint: true });
356
- closeSync(stagingDescriptor);
357
- }
358
- closeSync(sourceDescriptor);
359
- if (!complete) {
360
- removeIdentityBoundFile(stagingPath, staged, "incomplete staged executable");
361
- }
362
- }
363
- }
364
- function assertDestinationUnchanged(destinationPath, expected, platform) {
365
- const current = maybeLstat(destinationPath);
366
- if (expected === null) {
367
- if (current !== null) {
368
- throw new Error("metadata-search executable destination appeared during installation");
369
- }
370
- return;
371
- }
372
- if (current === null || !sameFileIdentity(expected, current)) {
373
- throw new Error("metadata-search executable destination changed during installation");
374
- }
375
- assertExistingDestination(current, platform);
376
- }
377
- function removeIdentityBoundFile(path, expected, label) {
378
- const current = maybeLstat(path);
379
- if (current === null)
380
- return;
381
- if (expected === null || current.isDirectory() || !sameFileIdentity(expected, current)) {
382
- throw new Error(`refusing to remove a replaced ${label}`);
383
- }
384
- rmSync(path, { force: true });
385
- }
386
- function metadataSearchExecutableName(platform = process.platform) {
387
- return platform === "win32" ? "kb-url-metadata-search.exe" : "kb-url-metadata-search";
388
- }
389
- function metadataSearchToolCommand(action, targetDirectory, toolDirectory = import.meta.dir) {
390
- if (!isAbsolute(targetDirectory)) {
391
- throw new Error("metadata-search tool target directory must be absolute");
392
- }
393
- if (!isAbsolute(toolDirectory)) {
394
- throw new Error("metadata-search tool directory must be absolute");
395
- }
396
- return Object.freeze([
397
- "cargo",
398
- action,
399
- ...action === "check" ? ["--all-targets"] : ["--release"],
400
- "--locked",
401
- "--manifest-path",
402
- join(toolDirectory, "Cargo.toml"),
403
- "--target-dir",
404
- targetDirectory
405
- ]);
406
- }
407
- function installMetadataSearchExecutable(input) {
408
- const toolDirectory = resolve(input.toolDirectory);
409
- const platform = input.platform ?? process.platform;
410
- const executableName = metadataSearchExecutableName(platform);
411
- const sourcePath = resolve(input.sourcePath);
412
- const targetDirectory = join(toolDirectory, "target");
413
- const releaseDirectory = join(targetDirectory, "release");
414
- const destinationPath = join(releaseDirectory, executableName);
415
- const stagingName = `.${executableName}.${process.pid}.${randomUUID()}.tmp`;
416
- const backupName = `.${executableName}.${process.pid}.${randomUUID()}.backup`;
417
- const stagingPath = join(toolDirectory, stagingName);
418
- const backupPath = join(toolDirectory, backupName);
419
- const syncDirectory = input.syncDirectory ?? ((descriptor) => fsyncSync(descriptor));
420
- const toolBinding = openBoundDirectory(toolDirectory, "metadata-search tool directory");
421
- let targetBinding = null;
422
- let releaseBinding = null;
423
- let stagedIdentity = null;
424
- let backupIdentity = null;
425
- let committed = false;
426
- let backupDestroyed = false;
427
- let installFailure = null;
428
- let installedPath = null;
429
- const cleanupErrors = [];
430
- try {
431
- const target = ensurePrivateDirectory(targetDirectory, "metadata-search target directory");
432
- targetBinding = target.binding;
433
- assertDirectoryBinding(toolBinding, "metadata-search tool directory");
434
- syncDirectory(toolBinding.descriptor, "tool-after-target");
435
- const release = ensurePrivateDirectory(releaseDirectory, "metadata-search release directory");
436
- releaseBinding = release.binding;
437
- assertDirectoryBinding(targetBinding, "metadata-search target directory");
438
- syncDirectory(targetBinding.descriptor, "target-after-release");
439
- const previousDestination = maybeLstat(destinationPath);
440
- if (previousDestination !== null) {
441
- assertExistingDestination(previousDestination, platform);
442
- backupIdentity = copyValidatedExecutable(destinationPath, backupPath, platform);
443
- }
444
- stagedIdentity = copyValidatedExecutable(sourcePath, stagingPath, platform);
445
- input.beforeInstall?.({
446
- sourcePath,
447
- targetDirectory,
448
- releaseDirectory,
449
- destinationPath
450
- });
451
- assertDirectoryBinding(toolBinding, "metadata-search tool directory");
452
- assertDirectoryBinding(targetBinding, "metadata-search target directory");
453
- assertDirectoryBinding(releaseBinding, "metadata-search release directory");
454
- assertDestinationUnchanged(destinationPath, previousDestination, platform);
455
- const stagedByPath = maybeLstat(stagingPath);
456
- if (stagedByPath === null || !sameFileIdentity(stagedIdentity, stagedByPath)) {
457
- throw new Error("staged metadata-search executable changed before installation");
458
- }
459
- if (backupIdentity !== null) {
460
- const backup = maybeLstat(backupPath);
461
- if (backup === null || !sameFileIdentity(backupIdentity, backup)) {
462
- throw new Error("metadata-search executable backup changed before installation");
463
- }
464
- }
465
- input.beforeCommit?.({
466
- sourcePath,
467
- targetDirectory,
468
- releaseDirectory,
469
- destinationPath
470
- });
471
- assertDirectoryBinding(toolBinding, "metadata-search tool directory");
472
- assertDirectoryBinding(targetBinding, "metadata-search target directory");
473
- assertDirectoryBinding(releaseBinding, "metadata-search release directory");
474
- assertDestinationUnchanged(destinationPath, previousDestination, platform);
475
- const commitStaging = maybeLstat(stagingPath);
476
- if (commitStaging === null || !sameFileIdentity(stagedIdentity, commitStaging)) {
477
- throw new Error("staged metadata-search executable changed before commit");
478
- }
479
- if (backupIdentity !== null) {
480
- const commitBackup = maybeLstat(backupPath);
481
- if (commitBackup === null || !sameFileIdentity(backupIdentity, commitBackup)) {
482
- throw new Error("metadata-search executable backup changed before commit");
483
- }
484
- }
485
- syncDirectory(toolBinding.descriptor, "tool-before-commit");
486
- syncDirectory(releaseBinding.descriptor, "release-before-commit");
487
- renameSync(stagingPath, destinationPath);
488
- committed = true;
489
- assertDirectoryBinding(toolBinding, "metadata-search tool directory");
490
- assertDirectoryBinding(targetBinding, "metadata-search target directory");
491
- assertDirectoryBinding(releaseBinding, "metadata-search release directory");
492
- const installed = maybeLstat(destinationPath);
493
- if (installed === null || !sameInstalledFile(stagedIdentity, installed)) {
494
- throw new Error("installed metadata-search executable failed identity validation");
495
- }
496
- assertExistingDestination(installed, platform);
497
- syncDirectory(releaseBinding.descriptor, "release-after-commit");
498
- syncDirectory(toolBinding.descriptor, "tool-after-commit");
499
- if (backupIdentity !== null) {
500
- const backup = maybeLstat(backupPath);
501
- if (backup === null || !sameFileIdentity(backupIdentity, backup)) {
502
- throw new Error("metadata-search executable backup changed during installation");
503
- }
504
- rmSync(backupPath, { force: true });
505
- backupDestroyed = true;
506
- syncDirectory(toolBinding.descriptor, "tool-after-backup-removal");
507
- backupIdentity = null;
508
- }
509
- installedPath = destinationPath;
510
- } catch (error) {
511
- let reportedError = error;
512
- if (committed && !backupDestroyed && releaseBinding !== null && stagedIdentity !== null) {
513
- try {
514
- const installed = maybeLstat(destinationPath);
515
- if (installed === null || !sameInstalledFile(stagedIdentity, installed)) {
516
- throw new Error("refusing to replace an unrecognized failed install");
517
- }
518
- if (backupIdentity === null) {
519
- rmSync(destinationPath, { force: true });
520
- } else {
521
- const backup = maybeLstat(backupPath);
522
- if (backup === null || !sameFileIdentity(backupIdentity, backup)) {
523
- throw new Error("refusing to restore an unrecognized executable backup");
524
- }
525
- renameSync(backupPath, destinationPath);
526
- backupIdentity = null;
527
- }
528
- syncDirectory(releaseBinding.descriptor, "release-after-rollback");
529
- syncDirectory(toolBinding.descriptor, "tool-after-rollback");
530
- } catch (rollbackError) {
531
- reportedError = new AggregateError([error, rollbackError], "metadata-search executable installation and rollback both failed");
532
- }
533
- }
534
- installFailure = { error: reportedError };
535
- } finally {
536
- const attemptCleanup = (action) => {
537
- try {
538
- action();
539
- } catch (error) {
540
- cleanupErrors.push(error);
541
- }
542
- };
543
- attemptCleanup(() => removeIdentityBoundFile(stagingPath, stagedIdentity, "staging executable"));
544
- attemptCleanup(() => removeIdentityBoundFile(backupPath, backupIdentity, "executable backup"));
545
- if (releaseBinding !== null) {
546
- const releaseDescriptor = releaseBinding.descriptor;
547
- attemptCleanup(() => closeSync(releaseDescriptor));
548
- }
549
- if (targetBinding !== null) {
550
- const targetDescriptor = targetBinding.descriptor;
551
- attemptCleanup(() => closeSync(targetDescriptor));
552
- }
553
- attemptCleanup(() => closeSync(toolBinding.descriptor));
554
- }
555
- const errors = [
556
- ...installFailure === null ? [] : [installFailure.error],
557
- ...cleanupErrors
558
- ];
559
- if (errors.length === 1)
560
- throw errors[0];
561
- if (errors.length > 1) {
562
- const details = errors.map((error) => error instanceof Error ? error.message : "unknown error").join("; ");
563
- throw new AggregateError(errors, `metadata-search executable installation or cleanup failed: ${details}`);
564
- }
565
- if (installedPath === null) {
566
- throw new Error("metadata-search executable installation produced no outcome");
567
- }
568
- return installedPath;
569
- }
570
- function defaultTemporaryDirectory() {
571
- return mkdtempSync(join(tmpdir(), TEMPORARY_DIRECTORY_PREFIX));
572
- }
573
- function assertTemporaryDirectoryIdentity(path, expected) {
574
- const current = maybeLstat(path);
575
- assertDirectory(current, "Cargo target directory");
576
- if (!sameDirectoryIdentity(expected, current)) {
577
- throw new Error("Cargo target directory changed before cleanup");
578
- }
579
- }
580
- function removeOwnedTemporaryDirectory(path, identity) {
581
- const resolvedPath = resolve(path);
582
- const resolvedTemporaryRoot = resolve(tmpdir());
583
- if (dirname(resolvedPath) !== resolvedTemporaryRoot || !basename(resolvedPath).startsWith(TEMPORARY_DIRECTORY_PREFIX)) {
584
- throw new Error("refusing to remove an unexpected Cargo target directory");
585
- }
586
- assertTemporaryDirectoryIdentity(resolvedPath, identity);
587
- rmSync(resolvedPath, { recursive: true, force: true });
588
- }
589
- function defaultCargoRunner(command, options) {
590
- const result = Bun.spawnSync({
591
- cmd: [...command],
592
- cwd: options.cwd,
593
- env: options.environment,
594
- stdin: "inherit",
595
- stdout: "inherit",
596
- stderr: "inherit"
597
- });
598
- return result.exitCode;
599
- }
600
- function runMetadataSearchTool(action, dependencies = {}) {
601
- const toolDirectory = resolve(dependencies.toolDirectory ?? import.meta.dir);
602
- const platform = dependencies.platform ?? process.platform;
603
- const createTemporaryDirectory = dependencies.createTemporaryDirectory ?? defaultTemporaryDirectory;
604
- const removeTemporaryDirectory = dependencies.removeTemporaryDirectory ?? removeOwnedTemporaryDirectory;
605
- const runCargo = dependencies.runCargo ?? defaultCargoRunner;
606
- const createdTargetDirectory = createTemporaryDirectory();
607
- if (!isAbsolute(createdTargetDirectory)) {
608
- throw new Error("metadata-search tool temporary directory must be absolute");
609
- }
610
- const targetDirectory = resolve(createdTargetDirectory);
611
- const targetIdentity = maybeLstat(targetDirectory);
612
- assertDirectory(targetIdentity, "Cargo target directory");
613
- try {
614
- const command = metadataSearchToolCommand(action, targetDirectory, toolDirectory);
615
- const exitCode = runCargo(command, {
616
- cwd: toolDirectory,
617
- environment: { ...process.env, CARGO_INCREMENTAL: "0" }
618
- });
619
- if (exitCode !== 0 || action === "check")
620
- return exitCode;
621
- installMetadataSearchExecutable({
622
- sourcePath: join(targetDirectory, "release", metadataSearchExecutableName(platform)),
623
- toolDirectory,
624
- platform,
625
- beforeInstall: dependencies.beforeInstall,
626
- beforeCommit: dependencies.beforeCommit,
627
- syncDirectory: dependencies.syncDirectory
628
- });
629
- return 0;
630
- } finally {
631
- assertTemporaryDirectoryIdentity(targetDirectory, targetIdentity);
632
- removeTemporaryDirectory(targetDirectory, targetIdentity);
633
- }
634
- }
635
- if (false) {}
636
-
637
- // src/clip/url-metadata-cli.ts
638
- var urlMetadataUsage = `wordcell url-metadata \u2014 backfill bounded metadata for saved URLs
639
-
640
- Usage:
641
- wordcell url-metadata tool <build|check>
642
- wordcell url-metadata backfill [--root <vault>] [--search-binary <path>] [--refresh]
643
- [--archive | --no-archive] [--delay-ms <milliseconds>]
644
- [--max-results <count>] [--timeout <milliseconds>] [--json]
645
-
646
- Build or validate the immutable metadata-search-engine-rs helper directly from
647
- an installed @hraness/wordcell package:
648
- wordcell url-metadata tool build
649
- `;
650
- var defaultOutput = {
651
- stdout: (value) => process.stdout.write(value),
652
- stderr: (value) => process.stderr.write(value)
653
- };
654
- function integer(value, minimum, maximum) {
655
- if (!/^(?:0|[1-9]\d*)$/u.test(value))
656
- return null;
657
- const parsed = Number(value);
658
- return Number.isSafeInteger(parsed) && parsed >= minimum && parsed <= maximum ? parsed : null;
659
- }
660
- function metadataSearchBinaryPath(packageRoot = findKbPackageRoot(), platform = process.platform) {
661
- const executable = platform === "win32" ? "kb-url-metadata-search.exe" : "kb-url-metadata-search";
662
- return resolve2(packageRoot, "src", "clip", "metadata-search-tool", "target", "release", executable);
663
- }
664
- function defaultBinaryPath(environment) {
665
- const configured = environment.HRANESS_KB_METADATA_SEARCH_BINARY;
666
- if (configured !== undefined && configured.trim() !== "")
667
- return resolve2(configured);
668
- return metadataSearchBinaryPath();
669
- }
670
- function parseUrlMetadataArguments(arguments_, environment = process.env) {
671
- const command = arguments_[0];
672
- const jsonRequested = arguments_.includes("--json");
673
- if (command === undefined || command === "help" || command === "--help" || command === "-h") {
674
- return { ok: true, value: { kind: "help" } };
675
- }
676
- if (command === "tool") {
677
- const action = arguments_[1];
678
- if (arguments_.length !== 2 || action !== "build" && action !== "check") {
679
- return {
680
- ok: false,
681
- message: "url-metadata tool accepts exactly one build or check action",
682
- json: jsonRequested
683
- };
684
- }
685
- return { ok: true, value: { kind: "tool", action } };
686
- }
687
- if (command !== "backfill") {
688
- return {
689
- ok: false,
690
- message: "url-metadata accepts only the tool or backfill subcommand",
691
- json: jsonRequested
692
- };
693
- }
694
- let root = "kb";
695
- let binaryPath = defaultBinaryPath(environment);
696
- let refresh = false;
697
- let discoverArchives = true;
698
- let delayMs = 1000;
699
- let maxResults = 20;
700
- let timeoutMs = 15000;
701
- let json = false;
702
- for (let index = 1;index < arguments_.length; index += 1) {
703
- const argument = arguments_[index];
704
- if (argument === "--refresh")
705
- refresh = true;
706
- else if (argument === "--archive")
707
- discoverArchives = true;
708
- else if (argument === "--no-archive")
709
- discoverArchives = false;
710
- else if (argument === "--json")
711
- json = true;
712
- else if (argument === "--root" || argument === "--search-binary" || argument === "--delay-ms" || argument === "--max-results" || argument === "--timeout") {
713
- const value = arguments_[index + 1];
714
- if (value === undefined || value.startsWith("--")) {
715
- return { ok: false, message: `${argument} requires a value`, json: jsonRequested };
716
- }
717
- index += 1;
718
- if (argument === "--root")
719
- root = value;
720
- else if (argument === "--search-binary")
721
- binaryPath = resolve2(value);
722
- else if (argument === "--delay-ms") {
723
- const parsed = integer(value, 0, 60000);
724
- if (parsed === null)
725
- return { ok: false, message: "--delay-ms must be an integer from 0 through 60000", json: jsonRequested };
726
- delayMs = parsed;
727
- } else if (argument === "--max-results") {
728
- const parsed = integer(value, 1, 20);
729
- if (parsed === null)
730
- return { ok: false, message: "--max-results must be an integer from 1 through 20", json: jsonRequested };
731
- maxResults = parsed;
732
- } else {
733
- const parsed = integer(value, 500, 15000);
734
- if (parsed === null)
735
- return { ok: false, message: "--timeout must be an integer from 500 through 15000", json: jsonRequested };
736
- timeoutMs = parsed;
737
- }
738
- } else {
739
- return { ok: false, message: `unknown url-metadata option: ${argument ?? ""}`, json: jsonRequested };
740
- }
741
- }
742
- if (root.trim() === "")
743
- return { ok: false, message: "--root must not be empty", json: jsonRequested };
744
- return {
745
- ok: true,
746
- value: {
747
- kind: "backfill",
748
- root,
749
- binaryPath,
750
- refresh,
751
- discoverArchives,
752
- delayMs,
753
- maxResults,
754
- timeoutMs,
755
- json
756
- }
757
- };
758
- }
759
- function terminalJson(value) {
760
- return `${JSON.stringify(value, (_key, candidate) => typeof candidate === "string" ? sanitizeTerminalText(candidate) : candidate, 2)}
761
- `;
762
- }
763
- function renderReport(report) {
764
- const counts = report.statusCounts;
765
- return [
766
- `URL metadata: ${report.processedRecords} processed, ${report.skippedRecords} resumed, ${report.remainingRecords} remaining.`,
767
- `Writes: ${report.writtenRecords} new or refreshed, ${report.unchangedRecords} unchanged.`,
768
- `Status: ${counts.matched} matched, ${counts.partial} partial, ${counts.notFound} not found, ${counts.unavailable} unavailable.`
769
- ].join(`
770
- `) + `
771
- `;
772
- }
773
- async function main3(rawArguments = process.argv.slice(2), environment = process.env, output = defaultOutput, dependencies = {}) {
774
- const parsed = parseUrlMetadataArguments(rawArguments, environment);
775
- if (!parsed.ok) {
776
- if (parsed.json)
777
- output.stdout(terminalJson({ ok: false, error: parsed.message }));
778
- else
779
- output.stderr(`error: ${sanitizeTerminalText(parsed.message)}
780
-
781
- ${urlMetadataUsage}`);
782
- return 2;
783
- }
784
- if (parsed.value.kind === "help") {
785
- output.stdout(urlMetadataUsage);
786
- return 0;
787
- }
788
- try {
789
- if (parsed.value.kind === "tool") {
790
- return (dependencies.runTool ?? runMetadataSearchTool)(parsed.value.action, {
791
- toolDirectory: resolve2(findKbPackageRoot(), "src", "clip", "metadata-search-tool")
792
- });
793
- }
794
- const provider = (dependencies.createSearchProvider ?? ((binaryPath) => createRustMetadataSearchProvider({ binaryPath })))(parsed.value.binaryPath);
795
- const report = await (dependencies.backfill ?? backfillSavedUrlMetadata)({
796
- vaultRoot: parsed.value.root,
797
- refresh: parsed.value.refresh,
798
- discoverArchives: parsed.value.discoverArchives,
799
- interRequestDelayMs: parsed.value.delayMs,
800
- maxResults: parsed.value.maxResults,
801
- searchTimeoutMs: parsed.value.timeoutMs
802
- }, { searchProvider: provider });
803
- if (parsed.value.json)
804
- output.stdout(terminalJson({ ok: !report.aborted, ...report }));
805
- else
806
- output.stdout(renderReport(report));
807
- if (report.aborted)
808
- return 130;
809
- return report.statusCounts.unavailable > 0 ? 3 : 0;
810
- } catch (error) {
811
- const message = error instanceof Error ? error.message : String(error);
812
- if (parsed.value.kind === "backfill" && parsed.value.json) {
813
- output.stdout(terminalJson({ ok: false, error: message }));
814
- } else
815
- output.stderr(`error: ${sanitizeTerminalText(message)}
816
- `);
817
- return 1;
818
- }
819
- }
820
- if (false)
821
- ;
822
-
823
- // src/graph-cli.ts
824
- function parseGraphCommand(arguments_) {
825
- const action = arguments_[0];
826
- if (action !== "rebuild" && action !== "verify" && action !== "query") {
827
- return { ok: false, message: "unknown graph action" };
828
- }
829
- if (arguments_.length > 32)
830
- return { ok: false, message: "too many graph options" };
831
- let root = ".";
832
- let index;
833
- let json = false;
834
- let persisted = false;
835
- let fresh = false;
836
- const request = {};
837
- const seen = new Set;
838
- for (let position = 1;position < arguments_.length; position += 1) {
839
- const option = arguments_[position];
840
- if (seen.has(option))
841
- return { ok: false, message: "duplicate graph option" };
842
- seen.add(option);
843
- if (option === "--json") {
844
- json = true;
845
- continue;
846
- }
847
- if (option === "--fresh" && action === "rebuild") {
848
- fresh = true;
849
- continue;
850
- }
851
- if (option === "--persisted" && action === "query") {
852
- persisted = true;
853
- continue;
854
- }
855
- if (option !== "--root" && option !== "--index" && !(action === "query" && ["--program", "--note", "--scope", "--predicate", "--depth", "--limit"].includes(option))) {
856
- return { ok: false, message: "unknown graph option" };
857
- }
858
- const value = arguments_[++position];
859
- if (value === undefined || value.startsWith("--") || value.length === 0 || Buffer.byteLength(value, "utf8") > 16384) {
860
- return { ok: false, message: "graph option requires a bounded value" };
861
- }
862
- if (option === "--root") {
863
- root = value;
864
- continue;
865
- }
866
- if (option === "--index") {
867
- index = value;
868
- continue;
869
- }
870
- if (option === "--depth" || option === "--limit") {
871
- if (!/^[1-9][0-9]*$/u.test(value) || !Number.isSafeInteger(Number(value))) {
872
- return { ok: false, message: "graph count must be a positive integer" };
873
- }
874
- if (option === "--depth")
875
- request.depth = Number(value);
876
- else
877
- request.limits = { rows: Number(value) };
878
- } else
879
- request[option.slice(2)] = value;
880
- }
881
- const base = { root, ...index === undefined ? {} : { index }, json };
882
- if (action === "rebuild")
883
- return { ok: true, value: { kind: "graph-rebuild", ...base, fresh } };
884
- if (action === "verify")
885
- return { ok: true, value: { kind: "graph-verify", ...base } };
886
- try {
887
- return { ok: true, value: { kind: "graph-query", ...base, persisted, request: validateGraphQueryRequest(request) } };
888
- } catch (error) {
889
- return { ok: false, message: error instanceof Error ? error.message : "invalid graph query" };
890
- }
891
- }
892
- async function executeGraphCommand(command, dependencies = {}) {
893
- const options = command.index === undefined ? {} : { index: command.index };
894
- if (command.kind === "graph-query") {
895
- const value2 = await (dependencies.queryGraph ?? queryGraph)(command.root, command.request, {
896
- ...options,
897
- persisted: command.persisted
898
- });
899
- const lines = [
900
- `${value2.request.program}: ${value2.rows.length} derived graph rows.`,
901
- `Snapshot: ${value2.revision}`,
902
- "Proofs and exact source record digests are included in --json output.",
903
- value2.columns.join("\t"),
904
- ...value2.rows.map((row) => row.values.map((atom) => JSON.stringify(atom)).join("\t"))
905
- ];
906
- if (value2.truncated || value2.proofsTruncated) {
907
- lines.push(`Partial result: ${value2.truncationReasons.join(", ") || "proof evidence was truncated"}.`);
908
- }
909
- return { value: value2, text: `${lines.join(`
910
- `)}
911
- `, exitCode: value2.truncated || value2.proofsTruncated ? 4 : 0 };
912
- }
913
- const value = command.kind === "graph-rebuild" ? await (dependencies.rebuildGraph ?? rebuildGraph)(command.root, { ...options, fresh: command.fresh }) : await (dependencies.verifyGraph ?? verifyGraph)(command.root, options);
914
- return {
915
- value,
916
- text: `${command.kind === "graph-rebuild" ? "Rebuilt" : "Verified"} the local graph projection: ${value.records} notes, ${value.facts} facts.
917
- Snapshot: ${value.revision}
918
- `,
919
- exitCode: 0
920
- };
921
- }
922
-
923
- // src/cli-program.ts
924
- var defaultOutput2 = {
925
- stdout: (value) => process.stdout.write(value),
926
- stderr: (value) => process.stderr.write(value)
927
- };
928
- async function readBoundedUtf8(path, maximumBytes, label) {
929
- const handle = await open(path, "r");
930
- try {
931
- const bytes = new Uint8Array(maximumBytes + 1);
932
- let offset = 0;
933
- while (offset < bytes.byteLength) {
934
- const { bytesRead } = await handle.read(bytes, offset, bytes.byteLength - offset, null);
935
- if (bytesRead === 0)
936
- break;
937
- offset += bytesRead;
938
- }
939
- if (offset > maximumBytes) {
940
- throw new Error(`${label} exceeds the ${maximumBytes}-byte limit`);
941
- }
942
- try {
943
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, offset));
944
- } catch (error) {
945
- throw new Error(`${label} is not valid UTF-8`, { cause: error });
946
- }
947
- } finally {
948
- await handle.close();
949
- }
950
- }
951
- async function loadSearchRulesFile(path) {
952
- const text = await readBoundedUtf8(path, MAX_SEARCH_RULE_CONFIG_BYTES, "search rules file");
953
- let input;
954
- try {
955
- input = JSON.parse(text);
956
- } catch (error) {
957
- throw new Error("search rules file is not valid JSON", { cause: error });
958
- }
959
- return parseSearchRules(input);
960
- }
961
- var usage = `wordcell \u2014 auditable capture and derived links for Markdown vaults
53
+ __require
54
+ } from "./index-z1w83f81.js";
962
55
 
963
- Usage:
964
- wordcell init [directory] [--json]
965
- wordcell clip <url|current> [capture options]
966
- wordcell capture show <bundle> [--verify-assets] [--include-source-html] [--json]
967
- wordcell capture verify <bundle> [--verify-assets] [--json]
968
- wordcell capture diff <bundle> [--repo <repository>] [--ref <ref>] [--json]
969
- wordcell url-metadata tool <build|check>
970
- wordcell url-metadata backfill [metadata options]
971
- wordcell inspect <url> [capture options]
972
- wordcell pdf <file-or-url> [PDF options]
973
- wordcell refresh [--root <directory>] [--index <path>] [--json]
974
- wordcell check [--root <directory>] [--index <path>] [--no-catalog] [--json]
975
- wordcell catalog [--root <directory>] [--index <path>] [--json]
976
- wordcell graph [--root <directory>] [--index <path>] [--json]
977
- wordcell graph rebuild [--fresh] [--root <directory>] [--index <path>] [--json]
978
- wordcell graph verify [--root <directory>] [--index <path>] [--json]
979
- wordcell graph query --program <backlinks|reachability|scope-route|relation-closure|shared-tags|shared-concepts> [--note <id> | --scope <path>] [--predicate <predicate>] [--depth <count>] [--limit <count>] [--persisted] [--root <directory>] [--index <path>] [--json]
980
- wordcell backlinks <note> [--root <directory>] [--index <path>] [--json]
981
- wordcell links <note> [--root <directory>] [--direction <in|out|both>] [--depth <count>] [--limit <count>] [--json]
982
- wordcell note create <id> --title <title> [--type <type>] [--tag <tag>] [--body <markdown> | --body-file <path>] [--root <directory>] [--json]
983
- wordcell relation add <source> <predicate> <target> [--root <directory>] [--expected-revision <sha256:...>] [--json]
984
- wordcell relation remove <source> <predicate> <target> [--root <directory>] [--expected-revision <sha256:...>] [--json]
985
- wordcell relation list <note> [--root <directory>] [--json]
986
- wordcell percolate [note] [--proofs] [--root <directory>] [--min-support <count>] [--limit <count>] [--json]
987
- wordcell list [--root <directory>] [--where <path=value>] [--has <path>] [--tag <tag>] [--scope <repository-path>] [--sort <field>] [--order <asc|desc>] [--limit <count>] [--json]
988
- wordcell index [--root <directory>] [--database <path>] [--force] [--json]
989
- wordcell search <query> [--root <directory>] [--repo <repository>] [--database <path>] [--mode <hybrid|exact|keyword|semantic>] [--rules <file>] [--priority] [--where <path=value>] [--has <path>] [--tag <tag>] [--scope <repository-path>] [--related <note>] [--graph-depth <1|2>] [--no-graph] [--history | --no-history | --require-history] [--limit <count>] [--candidate-limit <count>] [--min-score <score>] [--json]
990
- wordcell history <note> [--root <directory>] [--repo <repository>] [--limit <count>] [--cochanged-limit <count>] [--json]
991
- wordcell history search <query-or-path> [--root <directory>] [--repo <repository>] [--limit <count>] [--commit-limit <count>] [--cochanged-limit <count>] [--json]
992
- wordcell evaluate <manifest.json> [--root <directory>] [--repo <repository>] [--database <path>] [--retriever <id>] [--split <development|test|all>] [--limit <count>] [--cutoff <count>] [--timeout <milliseconds>] [--baseline <id>] [--model-file <path>] [--cache-state <cold|mixed|warm>] [--json]
993
- wordcell portfolio search <query> --registry <file> --workspace <directory> (--shared | --vault <owner/id>...) [--mode <hybrid|exact|keyword|semantic>] [--rules <file>] [--priority] [--limit <count>] [--require-all] [--json]
994
- wordcell portfolio audit --registry <file> --workspace <directory> (--all | --shared | --vault <owner/id>...) [--strict] [--json]
995
- wordcell inbox [--root <directory>] [--source-prefix <directory>] [--limit <count>] [--json]
996
- wordcell context <repository-path> [--root <vault>] [--repo <repository>] [--kind <auto|file|directory>] [--json]
997
- wordcell agents identity <repository-scope> [--json]
998
- wordcell agents check [--root <vault>] [--repo <repository>] [--json]
999
- wordcell agents audit [--root <vault>] [--repo <repository>] [--json]
1000
- wordcell doctor [--json]
1001
- wordcell adapters [--json]
1002
-
1003
- Run \`wordcell clip --help\` for web capture options or \`wordcell pdf --help\` for PDF conversion options.
1004
- `;
1005
- function safe(value) {
1006
- return sanitizeTerminalLine(redactSensitiveText(value));
1007
- }
1008
- function terminalSafeJson(value) {
1009
- return `${JSON.stringify(value, (_key, candidate) => typeof candidate === "string" ? sanitizeTerminalText(redactSensitiveText(candidate)) : candidate, 2)}
1010
- `;
1011
- }
1012
- function readValue(arguments_, index) {
1013
- const value = arguments_[index + 1];
1014
- return value === undefined || value.startsWith("--") ? null : value;
1015
- }
1016
- function parseCaptureBundleCommand(arguments_) {
1017
- const action = arguments_[0];
1018
- if (action !== "show" && action !== "verify") {
1019
- return { ok: false, message: "capture bundle action must be show or verify" };
1020
- }
1021
- let json = false;
1022
- let includeSourceHtml = false;
1023
- let verifyAssets = false;
1024
- const positional = [];
1025
- for (const argument of arguments_.slice(1)) {
1026
- if (argument === "--json")
1027
- json = true;
1028
- else if (argument === "--verify-assets")
1029
- verifyAssets = true;
1030
- else if (argument === "--include-source-html" && action === "show")
1031
- includeSourceHtml = true;
1032
- else if (argument.startsWith("--"))
1033
- return { ok: false, message: `unknown capture ${action} option: ${argument}` };
1034
- else
1035
- positional.push(argument);
1036
- }
1037
- if (positional.length !== 1 || positional[0] === undefined) {
1038
- return { ok: false, message: `capture ${action} requires exactly one bundle path` };
1039
- }
1040
- return {
1041
- ok: true,
1042
- value: {
1043
- kind: "capture-bundle",
1044
- action,
1045
- path: positional[0],
1046
- options: { verifyAssets, ...includeSourceHtml ? { includeSourceHtml: true } : {} },
1047
- json
1048
- }
1049
- };
1050
- }
1051
- function parseCaptureDiffCommand(arguments_) {
1052
- let repository = ".";
1053
- let ref = "HEAD";
1054
- let json = false;
1055
- const positional = [];
1056
- for (let index = 0;index < arguments_.length; index += 1) {
1057
- const argument = arguments_[index];
1058
- if (argument === undefined)
1059
- continue;
1060
- if (argument === "--json")
1061
- json = true;
1062
- else if (argument === "--repo" || argument === "--ref") {
1063
- const value = readValue(arguments_, index);
1064
- if (value === null)
1065
- return { ok: false, message: `${argument} requires a value` };
1066
- if (argument === "--repo")
1067
- repository = value;
1068
- else
1069
- ref = value;
1070
- index += 1;
1071
- } else if (argument.startsWith("--"))
1072
- return { ok: false, message: `unknown capture diff option: ${argument}` };
1073
- else
1074
- positional.push(argument);
1075
- }
1076
- if (positional.length !== 1 || positional[0] === undefined) {
1077
- return { ok: false, message: "capture diff requires exactly one bundle path" };
1078
- }
1079
- return {
1080
- ok: true,
1081
- value: {
1082
- kind: "capture-diff",
1083
- options: { bundle: positional[0], repository, ref },
1084
- json
1085
- }
1086
- };
1087
- }
1088
- function parseVaultCommand(command, arguments_) {
1089
- let root = ".";
1090
- let index;
1091
- let json = false;
1092
- let direction = "both";
1093
- let depth = 1;
1094
- let limit;
1095
- let noCatalog = false;
1096
- const positional = [];
1097
- for (let cursor = 0;cursor < arguments_.length; cursor += 1) {
1098
- const argument = arguments_[cursor];
1099
- if (argument === undefined)
1100
- continue;
1101
- if (argument === "--json") {
1102
- json = true;
1103
- continue;
1104
- }
1105
- if (argument === "--no-catalog" && command === "check") {
1106
- noCatalog = true;
1107
- continue;
1108
- }
1109
- if (argument === "--root" || argument === "--index") {
1110
- const value = readValue(arguments_, cursor);
1111
- if (value === null)
1112
- return { ok: false, message: `${argument} requires a value` };
1113
- if (argument === "--root")
1114
- root = value;
1115
- else
1116
- index = value;
1117
- cursor += 1;
1118
- continue;
1119
- }
1120
- if (command === "links" && (argument === "--direction" || argument === "--depth" || argument === "--limit")) {
1121
- const value = readValue(arguments_, cursor);
1122
- if (value === null)
1123
- return { ok: false, message: `${argument} requires a value` };
1124
- if (argument === "--direction") {
1125
- if (value !== "in" && value !== "out" && value !== "both") {
1126
- return { ok: false, message: "--direction must be in, out, or both" };
1127
- }
1128
- direction = value;
1129
- } else if (argument === "--depth") {
1130
- const parsed = Number(value);
1131
- if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 10) {
1132
- return { ok: false, message: "--depth must be an integer from 1 through 10" };
1133
- }
1134
- depth = parsed;
1135
- } else {
1136
- const parsed = Number(value);
1137
- if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 1000) {
1138
- return { ok: false, message: "--limit must be an integer from 1 through 1000" };
1139
- }
1140
- limit = parsed;
1141
- }
1142
- cursor += 1;
1143
- continue;
1144
- }
1145
- if (argument.startsWith("--"))
1146
- return { ok: false, message: `unknown ${command} option` };
1147
- positional.push(argument);
1148
- }
1149
- if (command === "backlinks" || command === "links") {
1150
- const note = positional[0];
1151
- if (positional.length !== 1 || note === undefined) {
1152
- return { ok: false, message: `${command} requires exactly one note path, title, or alias` };
1153
- }
1154
- return {
1155
- ok: true,
1156
- value: {
1157
- kind: command,
1158
- root,
1159
- options: index === undefined ? {} : { index },
1160
- json,
1161
- note,
1162
- ...command === "links" ? { direction, depth, ...limit === undefined ? {} : { limit } } : {}
1163
- }
1164
- };
1165
- }
1166
- if (positional.length !== 0)
1167
- return { ok: false, message: `${command} does not accept positional arguments` };
1168
- return {
1169
- ok: true,
1170
- value: {
1171
- kind: command,
1172
- root,
1173
- options: index === undefined ? {} : { index },
1174
- json,
1175
- ...command === "check" && noCatalog ? { noCatalog: true } : {}
1176
- }
1177
- };
1178
- }
1179
- function parseCatalogCommand(arguments_) {
1180
- let root = ".";
1181
- let index;
1182
- let json = false;
1183
- for (let cursor = 0;cursor < arguments_.length; cursor += 1) {
1184
- const argument = arguments_[cursor];
1185
- if (argument === "--json") {
1186
- json = true;
1187
- continue;
1188
- }
1189
- if (argument === "--root" || argument === "--index") {
1190
- const value = readValue(arguments_, cursor);
1191
- if (value === null)
1192
- return { ok: false, message: `${argument} requires a value` };
1193
- if (argument === "--root")
1194
- root = value;
1195
- else
1196
- index = value;
1197
- cursor += 1;
1198
- continue;
1199
- }
1200
- return {
1201
- ok: false,
1202
- message: argument?.startsWith("--") === true ? "unknown catalog option" : "catalog does not accept positional arguments"
1203
- };
1204
- }
1205
- return {
1206
- ok: true,
1207
- value: {
1208
- kind: "catalog",
1209
- root,
1210
- options: index === undefined ? { mentionScope: false } : { index, mentionScope: false },
1211
- json
1212
- }
1213
- };
1214
- }
1215
- function metadataScalar(raw) {
1216
- const value = raw.trim();
1217
- if (value.startsWith('"') || value.endsWith('"')) {
1218
- try {
1219
- const parsed = JSON.parse(value);
1220
- return typeof parsed === "string" ? { ok: true, value: parsed } : { ok: false, message: "quoted --where values must be strings" };
1221
- } catch {
1222
- return { ok: false, message: "double-quoted --where values must be valid JSON strings" };
1223
- }
1224
- }
1225
- if (value.startsWith("'") || value.endsWith("'")) {
1226
- if (!(value.startsWith("'") && value.endsWith("'") && value.length >= 2)) {
1227
- return { ok: false, message: "single-quoted --where values must have a closing quote" };
1228
- }
1229
- return { ok: true, value: value.slice(1, -1).replaceAll("''", "'") };
1230
- }
1231
- if (value === "null")
1232
- return { ok: true, value: null };
1233
- if (value === "true")
1234
- return { ok: true, value: true };
1235
- if (value === "false")
1236
- return { ok: true, value: false };
1237
- if (/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/u.test(value)) {
1238
- const number = Number(value);
1239
- if (Number.isFinite(number)) {
1240
- if (Number.isInteger(number) && !Number.isSafeInteger(number)) {
1241
- return { ok: false, message: "numeric --where values must be safe integers; quote large identifiers" };
1242
- }
1243
- return { ok: true, value: number };
1244
- }
1245
- }
1246
- return { ok: true, value };
1247
- }
1248
- function querySort(raw) {
1249
- const value = raw.trim();
1250
- if (value === "title" || value === "path" || value === "inbound" || value === "outbound") {
1251
- return { kind: "builtin", field: value };
1252
- }
1253
- const path = value.replace(/^(?:meta|metadata)\./u, "");
1254
- return path === "" ? null : { kind: "metadata", path };
1255
- }
1256
- function parseListCommand(arguments_) {
1257
- let root = ".";
1258
- let index;
1259
- let json = false;
1260
- let sort = { kind: "builtin", field: "path" };
1261
- let direction = "asc";
1262
- let limit;
1263
- const filters = [];
1264
- const tags = [];
1265
- const repositoryScopes = [];
1266
- for (let cursor = 0;cursor < arguments_.length; cursor += 1) {
1267
- const argument = arguments_[cursor];
1268
- if (argument === undefined)
1269
- continue;
1270
- if (argument === "--json") {
1271
- json = true;
1272
- continue;
1273
- }
1274
- if (argument === "--root" || argument === "--index" || argument === "--where" || argument === "--has" || argument === "--tag" || argument === "--scope" || argument === "--repository-scope" || argument === "--sort" || argument === "--order" || argument === "--limit") {
1275
- const value = readValue(arguments_, cursor);
1276
- if (value === null)
1277
- return { ok: false, message: `${argument} requires a value` };
1278
- if (argument === "--root")
1279
- root = value;
1280
- else if (argument === "--index")
1281
- index = value;
1282
- else if (argument === "--tag") {
1283
- if (tags.length >= MAX_QUERY_TAGS) {
1284
- return {
1285
- ok: false,
1286
- message: `Query tags may contain at most ${MAX_QUERY_TAGS} entries.`
1287
- };
1288
- }
1289
- tags.push(value);
1290
- } else if (argument === "--scope" || argument === "--repository-scope") {
1291
- if (repositoryScopes.length >= MAX_REPOSITORY_SCOPES) {
1292
- return {
1293
- ok: false,
1294
- message: `Repository scope filters may contain at most ${MAX_REPOSITORY_SCOPES} entries.`
1295
- };
1296
- }
1297
- repositoryScopes.push(value);
1298
- } else if (argument === "--has") {
1299
- if (value.trim() === "")
1300
- return { ok: false, message: "--has requires a metadata path" };
1301
- if (filters.length >= MAX_QUERY_FILTERS) {
1302
- return {
1303
- ok: false,
1304
- message: `Query filters may contain at most ${MAX_QUERY_FILTERS} entries.`
1305
- };
1306
- }
1307
- filters.push({ kind: "exists", path: value });
1308
- } else if (argument === "--where") {
1309
- const equals = value.indexOf("=");
1310
- const path = equals === -1 ? "" : value.slice(0, equals).trim();
1311
- if (path === "")
1312
- return { ok: false, message: "--where requires path=value" };
1313
- const scalar = metadataScalar(value.slice(equals + 1));
1314
- if (!scalar.ok)
1315
- return scalar;
1316
- if (filters.length >= MAX_QUERY_FILTERS) {
1317
- return {
1318
- ok: false,
1319
- message: `Query filters may contain at most ${MAX_QUERY_FILTERS} entries.`
1320
- };
1321
- }
1322
- filters.push({ kind: "equals", path, value: scalar.value });
1323
- } else if (argument === "--sort") {
1324
- const parsed = querySort(value);
1325
- if (parsed === null)
1326
- return { ok: false, message: "--sort requires a field" };
1327
- sort = parsed;
1328
- } else if (argument === "--order") {
1329
- if (value !== "asc" && value !== "desc") {
1330
- return { ok: false, message: "--order must be asc or desc" };
1331
- }
1332
- direction = value;
1333
- } else {
1334
- const parsed = Number(value);
1335
- if (!Number.isSafeInteger(parsed) || parsed < 0) {
1336
- return { ok: false, message: "--limit must be a non-negative integer" };
1337
- }
1338
- limit = parsed;
1339
- }
1340
- cursor += 1;
1341
- continue;
1342
- }
1343
- return {
1344
- ok: false,
1345
- message: argument.startsWith("--") ? "unknown list option" : "list does not accept positional arguments"
1346
- };
1347
- }
1348
- try {
1349
- validateQueryOptions({
1350
- filters,
1351
- tags,
1352
- repositoryScopes,
1353
- sort,
1354
- direction,
1355
- ...limit === undefined ? {} : { limit }
1356
- });
1357
- } catch (error) {
1358
- return {
1359
- ok: false,
1360
- message: error instanceof Error ? error.message : String(error)
1361
- };
1362
- }
1363
- return {
1364
- ok: true,
1365
- value: {
1366
- kind: "list",
1367
- root,
1368
- options: index === undefined ? {} : { index },
1369
- filters,
1370
- tags,
1371
- repositoryScopes,
1372
- sort,
1373
- direction,
1374
- ...limit === undefined ? {} : { limit },
1375
- json
1376
- }
1377
- };
1378
- }
1379
- function parseInboxCommand(arguments_) {
1380
- let root = ".";
1381
- let index;
1382
- let json = false;
1383
- let limit = 100;
1384
- const sourcePrefixes = [];
1385
- for (let cursor = 0;cursor < arguments_.length; cursor += 1) {
1386
- const argument = arguments_[cursor];
1387
- if (argument === undefined)
1388
- continue;
1389
- if (argument === "--json") {
1390
- json = true;
1391
- continue;
1392
- }
1393
- if (argument === "--root" || argument === "--index" || argument === "--limit" || argument === "--source-prefix") {
1394
- const value = readValue(arguments_, cursor);
1395
- if (value === null)
1396
- return { ok: false, message: `${argument} requires a value` };
1397
- if (argument === "--root")
1398
- root = value;
1399
- else if (argument === "--index")
1400
- index = value;
1401
- else if (argument === "--source-prefix") {
1402
- if (sourcePrefixes.length >= MAX_SOURCE_INBOX_PREFIXES) {
1403
- return {
1404
- ok: false,
1405
- message: `Source inbox accepts at most ${MAX_SOURCE_INBOX_PREFIXES} source prefixes.`
1406
- };
1407
- }
1408
- sourcePrefixes.push(value);
1409
- } else {
1410
- const parsed = Number(value);
1411
- if (!Number.isSafeInteger(parsed) || parsed < 0 || parsed > MAX_SOURCE_INBOX_RESULTS) {
1412
- return {
1413
- ok: false,
1414
- message: `--limit must be an integer from 0 through ${MAX_SOURCE_INBOX_RESULTS}`
1415
- };
1416
- }
1417
- limit = parsed;
1418
- }
1419
- cursor += 1;
1420
- continue;
1421
- }
1422
- return {
1423
- ok: false,
1424
- message: argument.startsWith("--") ? "unknown inbox option" : "inbox does not accept positional arguments"
1425
- };
1426
- }
1427
- return {
1428
- ok: true,
1429
- value: {
1430
- kind: "inbox",
1431
- root,
1432
- options: index === undefined ? { mentionScope: false } : { index, mentionScope: false },
1433
- sourcePrefixes,
1434
- limit,
1435
- json
1436
- }
1437
- };
1438
- }
1439
- function parseSemanticCommand(command, arguments_) {
1440
- let root = ".";
1441
- let repository = ".";
1442
- let database;
1443
- let force = false;
1444
- let json = false;
1445
- let mode;
1446
- let priority = false;
1447
- let rulesPath;
1448
- let limit;
1449
- let candidateLimit;
1450
- let minScore;
1451
- let graphDepth;
1452
- let noGraph = false;
1453
- let history = false;
1454
- let noHistory = false;
1455
- let requireHistory = false;
1456
- const filters = [];
1457
- const tags = [];
1458
- const repositoryScopes = [];
1459
- const related = [];
1460
- const positional = [];
1461
- for (let cursor = 0;cursor < arguments_.length; cursor += 1) {
1462
- const argument = arguments_[cursor];
1463
- if (argument === undefined)
1464
- continue;
1465
- if (argument === "--json") {
1466
- json = true;
1467
- continue;
1468
- }
1469
- if (argument === "--force" && command === "index") {
1470
- force = true;
1471
- continue;
1472
- }
1473
- if (argument === "--no-graph" && command === "search") {
1474
- noGraph = true;
1475
- continue;
1476
- }
1477
- if (argument === "--no-history" && command === "search") {
1478
- noHistory = true;
1479
- continue;
1480
- }
1481
- if (argument === "--history" && command === "search") {
1482
- history = true;
1483
- continue;
1484
- }
1485
- if (argument === "--require-history" && command === "search") {
1486
- requireHistory = true;
1487
- continue;
1488
- }
1489
- if (argument === "--priority" && command === "search") {
1490
- priority = true;
1491
- continue;
1492
- }
1493
- if (argument === "--root" || argument === "--database" || command === "search" && (argument === "--repo" || argument === "--rules")) {
1494
- const value = readValue(arguments_, cursor);
1495
- if (value === null)
1496
- return { ok: false, message: `${argument} requires a value` };
1497
- if (argument === "--root")
1498
- root = value;
1499
- else if (argument === "--repo")
1500
- repository = value;
1501
- else if (argument === "--rules")
1502
- rulesPath = value;
1503
- else
1504
- database = value;
1505
- cursor += 1;
1506
- continue;
1507
- }
1508
- if (command === "search" && (argument === "--mode" || argument === "--limit" || argument === "--candidate-limit" || argument === "--min-score" || argument === "--where" || argument === "--has" || argument === "--tag" || argument === "--scope" || argument === "--repository-scope" || argument === "--related" || argument === "--graph-depth")) {
1509
- const value = readValue(arguments_, cursor);
1510
- if (value === null)
1511
- return { ok: false, message: `${argument} requires a value` };
1512
- if (argument === "--mode") {
1513
- if (value !== "hybrid" && value !== "exact" && value !== "semantic" && value !== "keyword") {
1514
- return { ok: false, message: "--mode must be hybrid, exact, keyword, or semantic" };
1515
- }
1516
- mode = value;
1517
- } else if (argument === "--where") {
1518
- const equals = value.indexOf("=");
1519
- const path = equals === -1 ? "" : value.slice(0, equals).trim();
1520
- if (path === "")
1521
- return { ok: false, message: "--where requires path=value" };
1522
- const scalar = metadataScalar(value.slice(equals + 1));
1523
- if (!scalar.ok)
1524
- return scalar;
1525
- if (filters.length >= MAX_QUERY_FILTERS) {
1526
- return {
1527
- ok: false,
1528
- message: `Query filters may contain at most ${MAX_QUERY_FILTERS} entries.`
1529
- };
1530
- }
1531
- filters.push({ kind: "equals", path, value: scalar.value });
1532
- } else if (argument === "--has") {
1533
- if (value.trim() === "")
1534
- return { ok: false, message: "--has requires a metadata path" };
1535
- if (filters.length >= MAX_QUERY_FILTERS) {
1536
- return {
1537
- ok: false,
1538
- message: `Query filters may contain at most ${MAX_QUERY_FILTERS} entries.`
1539
- };
1540
- }
1541
- filters.push({ kind: "exists", path: value });
1542
- } else if (argument === "--tag") {
1543
- if (tags.length >= MAX_QUERY_TAGS) {
1544
- return {
1545
- ok: false,
1546
- message: `Query tags may contain at most ${MAX_QUERY_TAGS} entries.`
1547
- };
1548
- }
1549
- tags.push(value);
1550
- } else if (argument === "--scope" || argument === "--repository-scope") {
1551
- if (repositoryScopes.length >= MAX_REPOSITORY_SCOPES) {
1552
- return {
1553
- ok: false,
1554
- message: `Repository scope filters may contain at most ${MAX_REPOSITORY_SCOPES} entries.`
1555
- };
1556
- }
1557
- repositoryScopes.push(value);
1558
- } else if (argument === "--related") {
1559
- if (related.length >= MAX_SEARCH_RELATED_SEEDS) {
1560
- return {
1561
- ok: false,
1562
- message: `Hybrid search accepts at most ${MAX_SEARCH_RELATED_SEEDS} explicit related-note seeds.`
1563
- };
1564
- }
1565
- if (Buffer.byteLength(value, "utf8") > MAX_SEARCH_NOTE_REFERENCE_BYTES) {
1566
- return {
1567
- ok: false,
1568
- message: `Search related-note seed ${related.length + 1} must be at most ` + `${MAX_SEARCH_NOTE_REFERENCE_BYTES.toLocaleString("en-US")} UTF-8 bytes.`
1569
- };
1570
- }
1571
- if (value.trim() === "") {
1572
- return {
1573
- ok: false,
1574
- message: `Search related-note seed ${related.length + 1} must not be empty.`
1575
- };
1576
- }
1577
- related.push(value);
1578
- } else if (argument === "--min-score") {
1579
- const parsed = Number(value);
1580
- if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
1581
- return { ok: false, message: "--min-score must be a number from 0 through 1" };
1582
- }
1583
- minScore = parsed;
1584
- } else {
1585
- const parsed = Number(value);
1586
- if (argument === "--limit" || argument === "--candidate-limit") {
1587
- const maximum = argument === "--limit" ? MAX_SEARCH_RESULTS : MAX_SEARCH_CANDIDATES;
1588
- if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > maximum) {
1589
- return {
1590
- ok: false,
1591
- message: `${argument} must be an integer from 1 through ${maximum}`
1592
- };
1593
- }
1594
- if (argument === "--limit")
1595
- limit = parsed;
1596
- else
1597
- candidateLimit = parsed;
1598
- } else if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 2) {
1599
- return { ok: false, message: "--graph-depth must be 1 or 2" };
1600
- } else {
1601
- graphDepth = parsed;
1602
- }
1603
- }
1604
- cursor += 1;
1605
- continue;
1606
- }
1607
- if (argument.startsWith("--"))
1608
- return { ok: false, message: `unknown ${command} option` };
1609
- positional.push(argument);
1610
- }
1611
- if (command === "index") {
1612
- if (positional.length > 0)
1613
- return { ok: false, message: "index does not accept positional arguments" };
1614
- return {
1615
- ok: true,
1616
- value: { kind: "index", root, ...database === undefined ? {} : { database }, force, json }
1617
- };
1618
- }
1619
- if (noHistory && requireHistory) {
1620
- return {
1621
- ok: false,
1622
- message: "--no-history and --require-history cannot be used together"
1623
- };
1624
- }
1625
- if (history && noHistory) {
1626
- return {
1627
- ok: false,
1628
- message: "--history and --no-history cannot be used together"
1629
- };
1630
- }
1631
- if (history && requireHistory) {
1632
- return {
1633
- ok: false,
1634
- message: "--history and --require-history cannot be used together"
1635
- };
1636
- }
1637
- if (candidateLimit !== undefined && candidateLimit < (limit ?? DEFAULT_SEARCH_RESULTS)) {
1638
- return {
1639
- ok: false,
1640
- message: "Search candidate limit must be at least the result limit."
1641
- };
1642
- }
1643
- if (mode === "exact" && minScore !== undefined) {
1644
- return {
1645
- ok: false,
1646
- message: "Search minimum score applies only to hybrid, keyword, or semantic mode."
1647
- };
1648
- }
1649
- if (priority && rulesPath === undefined) {
1650
- return { ok: false, message: "--priority requires --rules" };
1651
- }
1652
- const rawQuery = positional.join(" ");
1653
- if (rawQuery.trim() === "")
1654
- return { ok: false, message: "search requires a query" };
1655
- let query;
1656
- try {
1657
- query = validateSearchQuery(rawQuery).query;
1658
- validateQueryOptions({ filters, tags, repositoryScopes });
1659
- } catch (error) {
1660
- return {
1661
- ok: false,
1662
- message: error instanceof Error ? error.message : String(error)
1663
- };
1664
- }
1665
- return {
1666
- ok: true,
1667
- value: {
1668
- kind: "search",
1669
- root,
1670
- repository,
1671
- ...database === undefined ? {} : { database },
1672
- ...mode === undefined ? {} : { mode },
1673
- ordering: priority ? "priority-then-relevance" : "relevance",
1674
- ...rulesPath === undefined ? {} : { rulesPath },
1675
- filters,
1676
- tags,
1677
- repositoryScopes,
1678
- graph: noGraph ? false : {
1679
- ...related.length === 0 ? {} : { related },
1680
- ...graphDepth === undefined ? {} : { depth: graphDepth }
1681
- },
1682
- history: requireHistory ? "required" : history ? "auto" : false,
1683
- ...limit === undefined ? {} : { limit },
1684
- ...candidateLimit === undefined ? {} : { candidateLimit },
1685
- ...minScore === undefined ? {} : { minScore },
1686
- query,
1687
- json
1688
- }
1689
- };
1690
- }
1691
- function parseContextCommand(arguments_) {
1692
- let root = ".";
1693
- let repository = ".";
1694
- let targetKind = "auto";
1695
- let json = false;
1696
- const positional = [];
1697
- for (let cursor = 0;cursor < arguments_.length; cursor += 1) {
1698
- const argument = arguments_[cursor];
1699
- if (argument === undefined)
1700
- continue;
1701
- if (argument === "--json") {
1702
- json = true;
1703
- continue;
1704
- }
1705
- if (argument === "--root" || argument === "--repo" || argument === "--kind") {
1706
- const value = readValue(arguments_, cursor);
1707
- if (value === null)
1708
- return { ok: false, message: `${argument} requires a value` };
1709
- if (argument === "--root")
1710
- root = value;
1711
- else if (argument === "--repo")
1712
- repository = value;
1713
- else {
1714
- if (value !== "auto" && value !== "file" && value !== "directory") {
1715
- return { ok: false, message: "--kind must be auto, file, or directory" };
1716
- }
1717
- targetKind = value;
1718
- }
1719
- cursor += 1;
1720
- continue;
1721
- }
1722
- if (argument.startsWith("--"))
1723
- return { ok: false, message: "unknown context option" };
1724
- positional.push(argument);
1725
- }
1726
- const target = positional[0];
1727
- if (target === undefined || positional.length !== 1) {
1728
- return { ok: false, message: "context requires exactly one repository path" };
1729
- }
1730
- return {
1731
- ok: true,
1732
- value: {
1733
- kind: "context",
1734
- root,
1735
- repository,
1736
- target,
1737
- targetKind,
1738
- json
1739
- }
1740
- };
1741
- }
1742
- var MAX_HISTORY_QUERY_CHARACTERS = 500;
1743
- var MAX_HISTORY_RESULT_LIMIT = 100;
1744
- var MAX_HISTORY_COMMIT_LIMIT = 50;
1745
- var MAX_HISTORY_COCHANGED_LIMIT = 100;
1746
- function parseHistoryCommand(arguments_) {
1747
- const search = arguments_[0] === "search";
1748
- let root = ".";
1749
- let repository = ".";
1750
- let limit;
1751
- let commitLimit;
1752
- let cochangedLimit;
1753
- let json = false;
1754
- const positional = [];
1755
- for (let cursor = search ? 1 : 0;cursor < arguments_.length; cursor += 1) {
1756
- const argument = arguments_[cursor];
1757
- if (argument === undefined)
1758
- continue;
1759
- if (argument === "--json") {
1760
- json = true;
1761
- continue;
1762
- }
1763
- if (argument === "--root" || argument === "--repo" || argument === "--limit" || argument === "--commit-limit" || argument === "--cochanged-limit") {
1764
- const value = readValue(arguments_, cursor);
1765
- if (value === null)
1766
- return { ok: false, message: `${argument} requires a value` };
1767
- if (argument === "--root")
1768
- root = value;
1769
- else if (argument === "--repo")
1770
- repository = value;
1771
- else {
1772
- if (!search && argument === "--commit-limit") {
1773
- return {
1774
- ok: false,
1775
- message: "history <note> uses --limit for its per-note commit limit"
1776
- };
1777
- }
1778
- const maximum = argument === "--cochanged-limit" ? MAX_HISTORY_COCHANGED_LIMIT : argument === "--commit-limit" ? MAX_HISTORY_COMMIT_LIMIT : search ? MAX_HISTORY_RESULT_LIMIT : MAX_HISTORY_COMMIT_LIMIT;
1779
- const minimum = argument === "--cochanged-limit" ? 0 : 1;
1780
- const parsed = Number(value);
1781
- if (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) {
1782
- return {
1783
- ok: false,
1784
- message: `${argument} must be an integer from ${minimum} through ${maximum}`
1785
- };
1786
- }
1787
- if (argument === "--cochanged-limit")
1788
- cochangedLimit = parsed;
1789
- else if (argument === "--commit-limit")
1790
- commitLimit = parsed;
1791
- else
1792
- limit = parsed;
1793
- }
1794
- cursor += 1;
1795
- continue;
1796
- }
1797
- if (argument.startsWith("--")) {
1798
- return { ok: false, message: `unknown history ${search ? "search " : ""}option` };
1799
- }
1800
- positional.push(argument);
1801
- }
1802
- const query = search ? positional.join(" ").trim() : positional[0]?.trim();
1803
- if (query === undefined || query === "" || !search && positional.length !== 1) {
1804
- return {
1805
- ok: false,
1806
- message: search ? "history search requires a query or repository path" : "history requires exactly one note path, title, or alias"
1807
- };
1808
- }
1809
- if (query.length > MAX_HISTORY_QUERY_CHARACTERS || /[\0\r\n]/u.test(query)) {
1810
- return {
1811
- ok: false,
1812
- message: `history ${search ? "search query" : "note"} must be one to ${MAX_HISTORY_QUERY_CHARACTERS} characters on one line`
1813
- };
1814
- }
1815
- return {
1816
- ok: true,
1817
- value: {
1818
- kind: "history",
1819
- action: search ? "search" : "note",
1820
- root,
1821
- repository,
1822
- query,
1823
- ...limit === undefined ? {} : { limit },
1824
- ...commitLimit === undefined ? {} : { commitLimit },
1825
- ...cochangedLimit === undefined ? {} : { cochangedLimit },
1826
- json
1827
- }
1828
- };
1829
- }
1830
- function parseAgentsCommand(arguments_) {
1831
- const action = arguments_[0];
1832
- if (action === "identity") {
1833
- let json2 = false;
1834
- const positional = [];
1835
- for (const argument of arguments_.slice(1)) {
1836
- if (argument === "--json")
1837
- json2 = true;
1838
- else if (argument.startsWith("--")) {
1839
- return { ok: false, message: "unknown agents identity option" };
1840
- } else {
1841
- positional.push(argument);
1842
- }
1843
- }
1844
- const scope = positional[0];
1845
- if (scope === undefined || positional.length !== 1) {
1846
- return {
1847
- ok: false,
1848
- message: "agents identity requires exactly one repository scope"
1849
- };
1850
- }
1851
- return {
1852
- ok: true,
1853
- value: { kind: "agent-identity", scope, json: json2 }
1854
- };
1855
- }
1856
- if (action !== "check" && action !== "audit") {
1857
- return { ok: false, message: "agents requires identity, check, or audit" };
1858
- }
1859
- let root = ".";
1860
- let repository = ".";
1861
- let json = false;
1862
- for (let cursor = 1;cursor < arguments_.length; cursor += 1) {
1863
- const argument = arguments_[cursor];
1864
- if (argument === undefined)
1865
- continue;
1866
- if (argument === "--json") {
1867
- json = true;
1868
- continue;
1869
- }
1870
- if (argument === "--root" || argument === "--repo") {
1871
- const value = readValue(arguments_, cursor);
1872
- if (value === null)
1873
- return { ok: false, message: `${argument} requires a value` };
1874
- if (argument === "--root")
1875
- root = value;
1876
- else
1877
- repository = value;
1878
- cursor += 1;
1879
- continue;
1880
- }
1881
- return {
1882
- ok: false,
1883
- message: argument.startsWith("--") ? `unknown agents ${action} option` : `agents ${action} does not accept positional arguments`
1884
- };
1885
- }
1886
- return {
1887
- ok: true,
1888
- value: { kind: "agents", action, root, repository, json }
1889
- };
1890
- }
1891
- function boundedInteger(raw, option, minimum, maximum) {
1892
- const value = Number(raw);
1893
- if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
1894
- return {
1895
- ok: false,
1896
- message: `${option} must be an integer from ${minimum} through ${maximum}`
1897
- };
1898
- }
1899
- return value;
1900
- }
1901
- function parseEvaluationCommand(arguments_) {
1902
- let root = ".";
1903
- let repository = ".";
1904
- let database;
1905
- let split = "test";
1906
- let limit = 20;
1907
- let cutoff = 10;
1908
- let timeoutMs = 30000;
1909
- let baseline;
1910
- let modelFile;
1911
- let cacheState = "mixed";
1912
- let json = false;
1913
- const retrievers = [];
1914
- const positional = [];
1915
- const supported = new Set(knowledgeBaseEvaluationRetrieverIds);
1916
- for (let cursor = 0;cursor < arguments_.length; cursor += 1) {
1917
- const argument = arguments_[cursor];
1918
- if (argument === undefined)
1919
- continue;
1920
- if (argument === "--json") {
1921
- json = true;
1922
- continue;
1923
- }
1924
- if (argument === "--root" || argument === "--repo" || argument === "--database" || argument === "--retriever" || argument === "--split" || argument === "--limit" || argument === "--cutoff" || argument === "--timeout" || argument === "--baseline" || argument === "--model-file" || argument === "--cache-state") {
1925
- const value = readValue(arguments_, cursor);
1926
- if (value === null)
1927
- return { ok: false, message: `${argument} requires a value` };
1928
- if (argument === "--root")
1929
- root = value;
1930
- else if (argument === "--repo")
1931
- repository = value;
1932
- else if (argument === "--database")
1933
- database = value;
1934
- else if (argument === "--retriever") {
1935
- if (!supported.has(value)) {
1936
- return {
1937
- ok: false,
1938
- message: `--retriever must be one of ${knowledgeBaseEvaluationRetrieverIds.join(", ")}`
1939
- };
1940
- }
1941
- retrievers.push(value);
1942
- } else if (argument === "--split") {
1943
- if (value !== "development" && value !== "test" && value !== "all") {
1944
- return { ok: false, message: "--split must be development, test, or all" };
1945
- }
1946
- split = value;
1947
- } else if (argument === "--limit" || argument === "--cutoff") {
1948
- const parsed = boundedInteger(value, argument, 1, MAX_CLI_EVALUATION_RESULT_LIMIT);
1949
- if (typeof parsed !== "number")
1950
- return parsed;
1951
- if (argument === "--limit")
1952
- limit = parsed;
1953
- else
1954
- cutoff = parsed;
1955
- } else if (argument === "--timeout") {
1956
- const parsed = boundedInteger(value, argument, 1, MAX_EVALUATION_TIMEOUT_MS);
1957
- if (typeof parsed !== "number")
1958
- return parsed;
1959
- timeoutMs = parsed;
1960
- } else if (argument === "--baseline")
1961
- baseline = value;
1962
- else if (argument === "--model-file")
1963
- modelFile = value;
1964
- else {
1965
- if (value !== "cold" && value !== "mixed" && value !== "warm") {
1966
- return { ok: false, message: "--cache-state must be cold, mixed, or warm" };
1967
- }
1968
- cacheState = value;
1969
- }
1970
- cursor += 1;
1971
- continue;
1972
- }
1973
- if (argument.startsWith("--")) {
1974
- return { ok: false, message: "unknown evaluate option" };
1975
- }
1976
- positional.push(argument);
1977
- }
1978
- const manifest = positional[0];
1979
- if (manifest === undefined || positional.length !== 1) {
1980
- return { ok: false, message: "evaluate requires exactly one manifest path" };
1981
- }
1982
- const selected = retrievers.length === 0 ? [...knowledgeBaseEvaluationRetrieverIds] : retrievers;
1983
- if (new Set(selected).size !== selected.length) {
1984
- return { ok: false, message: "--retriever values must not repeat" };
1985
- }
1986
- const selectedBaseline = baseline ?? (selected.includes("exact") ? "exact" : selected[0]);
1987
- if (selectedBaseline === undefined || !selected.includes(selectedBaseline)) {
1988
- return { ok: false, message: "--baseline must name a selected retriever" };
1989
- }
1990
- if (cutoff > limit) {
1991
- return { ok: false, message: "--cutoff must not exceed --limit" };
1992
- }
1993
- const needsModel = selected.includes("semantic") || selected.includes("hybrid");
1994
- if (needsModel && modelFile === undefined) {
1995
- return {
1996
- ok: false,
1997
- message: "semantic and hybrid evaluation require --model-file to bind the pinned model bytes"
1998
- };
1999
- }
2000
- if (!needsModel && modelFile !== undefined) {
2001
- return {
2002
- ok: false,
2003
- message: "--model-file is only valid when semantic or hybrid evaluation is selected"
2004
- };
2005
- }
2006
- return {
2007
- ok: true,
2008
- value: {
2009
- kind: "evaluate",
2010
- manifest,
2011
- root,
2012
- repository,
2013
- ...database === undefined ? {} : { database },
2014
- retrievers: selected,
2015
- split,
2016
- limit,
2017
- cutoff,
2018
- timeoutMs,
2019
- baseline: selectedBaseline,
2020
- ...modelFile === undefined ? {} : { modelFile },
2021
- cacheState: needsModel ? cacheState : "not-applicable",
2022
- json
2023
- }
2024
- };
2025
- }
2026
- function parseNoteCommand(arguments_) {
2027
- if (arguments_[0] !== "create") {
2028
- return { ok: false, message: "note requires create" };
2029
- }
2030
- let root = ".";
2031
- let title;
2032
- let type = "note";
2033
- let body;
2034
- let bodyFile;
2035
- let json = false;
2036
- const tags = [];
2037
- const positional = [];
2038
- for (let cursor = 1;cursor < arguments_.length; cursor += 1) {
2039
- const argument = arguments_[cursor];
2040
- if (argument === undefined)
2041
- continue;
2042
- if (argument === "--json") {
2043
- json = true;
2044
- continue;
2045
- }
2046
- if (argument === "--root" || argument === "--title" || argument === "--type" || argument === "--tag" || argument === "--body" || argument === "--body-file") {
2047
- const value = readValue(arguments_, cursor);
2048
- if (value === null)
2049
- return { ok: false, message: `${argument} requires a value` };
2050
- if (argument === "--root")
2051
- root = value;
2052
- else if (argument === "--title")
2053
- title = value;
2054
- else if (argument === "--type")
2055
- type = value;
2056
- else if (argument === "--tag")
2057
- tags.push(value);
2058
- else if (argument === "--body")
2059
- body = value;
2060
- else
2061
- bodyFile = value;
2062
- cursor += 1;
2063
- continue;
2064
- }
2065
- if (argument.startsWith("--")) {
2066
- return { ok: false, message: "unknown note create option" };
2067
- }
2068
- positional.push(argument);
2069
- }
2070
- const id = positional[0];
2071
- if (id === undefined || positional.length !== 1) {
2072
- return { ok: false, message: "note create requires exactly one canonical note ID" };
2073
- }
2074
- if (title === undefined)
2075
- return { ok: false, message: "note create requires --title" };
2076
- if (body !== undefined && bodyFile !== undefined) {
2077
- return { ok: false, message: "note create accepts either --body or --body-file, not both" };
2078
- }
2079
- return {
2080
- ok: true,
2081
- value: {
2082
- kind: "note-create",
2083
- root,
2084
- input: { id, title, type, ...tags.length === 0 ? {} : { tags } },
2085
- ...body === undefined ? {} : { body },
2086
- ...bodyFile === undefined ? {} : { bodyFile },
2087
- json
2088
- }
2089
- };
2090
- }
2091
- function isNoteRevision(value) {
2092
- return /^sha256:[0-9a-f]{64}$/u.test(value);
2093
- }
2094
- function parseRelationCommand(arguments_) {
2095
- const action = arguments_[0];
2096
- if (action !== "add" && action !== "remove" && action !== "list") {
2097
- return { ok: false, message: "relation requires add, remove, or list" };
2098
- }
2099
- let root = ".";
2100
- let expectedRevision;
2101
- let json = false;
2102
- const positional = [];
2103
- for (let cursor = 1;cursor < arguments_.length; cursor += 1) {
2104
- const argument = arguments_[cursor];
2105
- if (argument === undefined)
2106
- continue;
2107
- if (argument === "--json") {
2108
- json = true;
2109
- continue;
2110
- }
2111
- if (argument === "--root" || argument === "--expected-revision") {
2112
- const value = readValue(arguments_, cursor);
2113
- if (value === null)
2114
- return { ok: false, message: `${argument} requires a value` };
2115
- if (argument === "--root") {
2116
- root = value;
2117
- } else {
2118
- if (!isNoteRevision(value)) {
2119
- return {
2120
- ok: false,
2121
- message: "--expected-revision must be sha256 followed by 64 lowercase hexadecimal characters"
2122
- };
2123
- }
2124
- expectedRevision = value;
2125
- }
2126
- cursor += 1;
2127
- continue;
2128
- }
2129
- if (argument.startsWith("--")) {
2130
- return { ok: false, message: `unknown relation ${action} option` };
2131
- }
2132
- positional.push(argument);
2133
- }
2134
- const source = positional[0];
2135
- if (action === "list") {
2136
- if (source === undefined || positional.length !== 1) {
2137
- return { ok: false, message: "relation list requires exactly one canonical note ID" };
2138
- }
2139
- if (expectedRevision !== undefined) {
2140
- return { ok: false, message: "relation list does not accept --expected-revision" };
2141
- }
2142
- return { ok: true, value: { kind: "relation", action, root, source, json } };
2143
- }
2144
- const predicate = positional[1];
2145
- const target = positional[2];
2146
- if (source === undefined || predicate === undefined || target === undefined || positional.length !== 3) {
2147
- return {
2148
- ok: false,
2149
- message: `relation ${action} requires exact source, predicate, and target IDs`
2150
- };
2151
- }
2152
- return {
2153
- ok: true,
2154
- value: {
2155
- kind: "relation",
2156
- action,
2157
- root,
2158
- source,
2159
- predicate,
2160
- target,
2161
- ...expectedRevision === undefined ? {} : { expectedRevision },
2162
- json
2163
- }
2164
- };
2165
- }
2166
- function parsePercolateCommand(arguments_) {
2167
- let root = ".";
2168
- let minSupport = 2;
2169
- let limit = 25;
2170
- let json = false;
2171
- let proofs = false;
2172
- const positional = [];
2173
- for (let cursor = 0;cursor < arguments_.length; cursor += 1) {
2174
- const argument = arguments_[cursor];
2175
- if (argument === undefined)
2176
- continue;
2177
- if (argument === "--proofs") {
2178
- if (proofs)
2179
- return { ok: false, message: "duplicate percolation proofs option" };
2180
- proofs = true;
2181
- continue;
2182
- }
2183
- if (argument === "--json") {
2184
- json = true;
2185
- continue;
2186
- }
2187
- if (argument === "--root" || argument === "--min-support" || argument === "--limit") {
2188
- const value = readValue(arguments_, cursor);
2189
- if (value === null)
2190
- return { ok: false, message: `${argument} requires a value` };
2191
- if (argument === "--root") {
2192
- root = value;
2193
- } else {
2194
- const parsed = boundedInteger(value, argument, argument === "--min-support" ? 2 : 1, 1000);
2195
- if (typeof parsed !== "number")
2196
- return parsed;
2197
- if (argument === "--min-support")
2198
- minSupport = parsed;
2199
- else
2200
- limit = parsed;
2201
- }
2202
- cursor += 1;
2203
- continue;
2204
- }
2205
- if (argument.startsWith("--")) {
2206
- return { ok: false, message: "unknown percolate option" };
2207
- }
2208
- positional.push(argument);
2209
- }
2210
- const note = positional[0];
2211
- if (positional.length > 1) {
2212
- return { ok: false, message: "percolate accepts at most one note ID" };
2213
- }
2214
- if (proofs && note === undefined)
2215
- return { ok: false, message: "percolate --proofs requires one note" };
2216
- return {
2217
- ok: true,
2218
- value: {
2219
- kind: "percolate",
2220
- ...proofs ? { proofs: true } : {},
2221
- root,
2222
- ...note === undefined ? {} : { note },
2223
- minSupport,
2224
- limit,
2225
- json
2226
- }
2227
- };
2228
- }
2229
- function parsePortfolioCommand(arguments_) {
2230
- const action = arguments_[0];
2231
- if (action !== "search" && action !== "audit") {
2232
- return { ok: false, message: "portfolio action must be search or audit" };
2233
- }
2234
- let registryPath;
2235
- let workspaceRoot;
2236
- let shared = false;
2237
- let all = false;
2238
- let requireAll = false;
2239
- let strict = false;
2240
- let json = false;
2241
- let mode;
2242
- let priority = false;
2243
- let rulesPath;
2244
- let limit;
2245
- const vaults = [];
2246
- const positional = [];
2247
- for (let cursor = 1;cursor < arguments_.length; cursor += 1) {
2248
- const argument = arguments_[cursor];
2249
- if (argument === undefined)
2250
- continue;
2251
- if (argument === "--json")
2252
- json = true;
2253
- else if (argument === "--shared")
2254
- shared = true;
2255
- else if (argument === "--all" && action === "audit")
2256
- all = true;
2257
- else if (argument === "--require-all" && action === "search")
2258
- requireAll = true;
2259
- else if (argument === "--priority" && action === "search")
2260
- priority = true;
2261
- else if (argument === "--strict" && action === "audit")
2262
- strict = true;
2263
- else if (argument === "--registry" || argument === "--workspace" || argument === "--vault" || argument === "--rules" && action === "search" || argument === "--mode" && action === "search" || argument === "--limit" && action === "search") {
2264
- const value = readValue(arguments_, cursor);
2265
- if (value === null)
2266
- return { ok: false, message: `${argument} requires a value` };
2267
- cursor += 1;
2268
- if (argument === "--registry")
2269
- registryPath = value;
2270
- else if (argument === "--workspace")
2271
- workspaceRoot = value;
2272
- else if (argument === "--rules")
2273
- rulesPath = value;
2274
- else if (argument === "--vault") {
2275
- try {
2276
- vaults.push(parseVaultKey(value).key);
2277
- } catch {
2278
- return { ok: false, message: "--vault must be a canonical owner/id key" };
2279
- }
2280
- } else if (argument === "--mode") {
2281
- if (value !== "exact" && value !== "hybrid" && value !== "keyword" && value !== "semantic") {
2282
- return { ok: false, message: "--mode must be exact, hybrid, keyword, or semantic" };
2283
- }
2284
- mode = value;
2285
- } else {
2286
- const checked = boundedInteger(value, "--limit", 1, MAX_SEARCH_RESULTS);
2287
- if (typeof checked !== "number")
2288
- return checked;
2289
- limit = checked;
2290
- }
2291
- } else if (argument.startsWith("--")) {
2292
- return { ok: false, message: `unknown portfolio ${action} option` };
2293
- } else
2294
- positional.push(argument);
2295
- }
2296
- if (registryPath === undefined || workspaceRoot === undefined) {
2297
- return { ok: false, message: `portfolio ${action} requires --registry and --workspace` };
2298
- }
2299
- if (new Set(vaults).size !== vaults.length) {
2300
- return { ok: false, message: "portfolio vault selections must be unique" };
2301
- }
2302
- const selectionCount = Number(shared) + Number(all) + Number(vaults.length > 0);
2303
- if (selectionCount !== 1) {
2304
- return {
2305
- ok: false,
2306
- message: action === "search" ? "portfolio search requires exactly one of --shared or repeated --vault" : "portfolio audit requires exactly one of --all, --shared, or repeated --vault"
2307
- };
2308
- }
2309
- if (action === "search") {
2310
- if (priority && rulesPath === undefined) {
2311
- return { ok: false, message: "--priority requires --rules" };
2312
- }
2313
- const rawQuery = positional.join(" ");
2314
- if (rawQuery.trim() === "")
2315
- return { ok: false, message: "portfolio search requires a query" };
2316
- let query;
2317
- try {
2318
- query = validateSearchQuery(rawQuery).query;
2319
- } catch (error) {
2320
- return { ok: false, message: error instanceof Error ? error.message : String(error) };
2321
- }
2322
- return {
2323
- ok: true,
2324
- value: {
2325
- kind: "portfolio-search",
2326
- registryPath,
2327
- workspaceRoot,
2328
- selection: shared ? "shared" : "explicit",
2329
- vaults,
2330
- failurePolicy: requireAll ? "required" : "partial",
2331
- ...mode === undefined ? {} : { mode },
2332
- ordering: priority ? "priority-then-relevance" : "relevance",
2333
- ...rulesPath === undefined ? {} : { rulesPath },
2334
- ...limit === undefined ? {} : { limit },
2335
- query,
2336
- json
2337
- }
2338
- };
2339
- }
2340
- if (positional.length > 0)
2341
- return { ok: false, message: "portfolio audit does not accept positional arguments" };
2342
- return {
2343
- ok: true,
2344
- value: {
2345
- kind: "portfolio-audit",
2346
- registryPath,
2347
- workspaceRoot,
2348
- selection: all ? "all" : shared ? "shared" : "explicit",
2349
- vaults,
2350
- strict,
2351
- json
2352
- }
2353
- };
2354
- }
2355
- function parseArguments(arguments_) {
2356
- const command = arguments_[0];
2357
- if (command === undefined || command === "help" || command === "--help" || command === "-h") {
2358
- return { ok: true, value: { kind: "help" } };
2359
- }
2360
- if (command === "capture" && arguments_[1] === "diff") {
2361
- return parseCaptureDiffCommand(arguments_.slice(2));
2362
- }
2363
- if (command === "capture" && (arguments_[1] === "show" || arguments_[1] === "verify")) {
2364
- return parseCaptureBundleCommand(arguments_.slice(1));
2365
- }
2366
- if (command === "clip" || command === "capture" || command === "inspect") {
2367
- if (arguments_[1] === "--help" || arguments_[1] === "-h" || arguments_[1] === "help") {
2368
- return { ok: true, value: { kind: "clip", arguments: ["help"] } };
2369
- }
2370
- const delegated = command === "inspect" ? "inspect" : "capture";
2371
- return { ok: true, value: { kind: "clip", arguments: [delegated, ...arguments_.slice(1)] } };
2372
- }
2373
- if (command === "url-metadata") {
2374
- return { ok: true, value: { kind: "url-metadata", arguments: arguments_.slice(1) } };
2375
- }
2376
- if (command === "pdf") {
2377
- return { ok: true, value: { kind: "pdf", arguments: arguments_.slice(1) } };
2378
- }
2379
- if (command === "doctor" || command === "adapters") {
2380
- return { ok: true, value: { kind: "clip", arguments: arguments_ } };
2381
- }
2382
- if (command === "init") {
2383
- let directory = "kb";
2384
- let json = false;
2385
- const positional = [];
2386
- for (const argument of arguments_.slice(1)) {
2387
- if (argument === "--json")
2388
- json = true;
2389
- else if (argument.startsWith("--"))
2390
- return { ok: false, message: "unknown init option" };
2391
- else
2392
- positional.push(argument);
2393
- }
2394
- if (positional.length > 1)
2395
- return { ok: false, message: "init accepts at most one directory" };
2396
- if (positional[0] !== undefined)
2397
- directory = positional[0];
2398
- return { ok: true, value: { kind: "init", directory, json } };
2399
- }
2400
- if (command === "graph" && ["rebuild", "verify", "query"].includes(arguments_[1] ?? "")) {
2401
- return parseGraphCommand(arguments_.slice(1));
2402
- }
2403
- if (command === "refresh" || command === "check" || command === "graph" || command === "backlinks" || command === "links") {
2404
- return parseVaultCommand(command, arguments_.slice(1));
2405
- }
2406
- if (command === "catalog")
2407
- return parseCatalogCommand(arguments_.slice(1));
2408
- if (command === "list" || command === "notes")
2409
- return parseListCommand(arguments_.slice(1));
2410
- if (command === "inbox" || command === "source-inbox") {
2411
- return parseInboxCommand(arguments_.slice(1));
2412
- }
2413
- if (command === "index" || command === "search") {
2414
- return parseSemanticCommand(command, arguments_.slice(1));
2415
- }
2416
- if (command === "history")
2417
- return parseHistoryCommand(arguments_.slice(1));
2418
- if (command === "portfolio")
2419
- return parsePortfolioCommand(arguments_.slice(1));
2420
- if (command === "evaluate")
2421
- return parseEvaluationCommand(arguments_.slice(1));
2422
- if (command === "context")
2423
- return parseContextCommand(arguments_.slice(1));
2424
- if (command === "agents")
2425
- return parseAgentsCommand(arguments_.slice(1));
2426
- if (command === "note")
2427
- return parseNoteCommand(arguments_.slice(1));
2428
- if (command === "relation")
2429
- return parseRelationCommand(arguments_.slice(1));
2430
- if (command === "percolate")
2431
- return parsePercolateCommand(arguments_.slice(1));
2432
- return { ok: false, message: "unknown command" };
2433
- }
2434
- function embeddingCount(result) {
2435
- return result.embedding?.chunksEmbedded ?? 0;
2436
- }
2437
- function renderSemanticIndex(result) {
2438
- const changed = result.update.indexed + result.update.updated;
2439
- return [
2440
- `Indexed ${safe(result.root)} with QMD.`,
2441
- `Documents: ${changed} changed, ${result.update.unchanged} unchanged, ${result.update.removed} removed.`,
2442
- `Embeddings: ${embeddingCount(result)} chunks; model: ${safe(result.model)}.`,
2443
- `Database: ${safe(result.database)}`,
2444
- ""
2445
- ].join(`
2446
- `);
2447
- }
2448
- function renderKnowledgeBaseSearch(result) {
2449
- const lines = [
2450
- `${result.mode[0]?.toLocaleUpperCase("en-US") ?? ""}${result.mode.slice(1)} results for \u201C${safe(result.query)}\u201D (${result.results.length})${result.partial ? " [partial]" : ""}`
2451
- ];
2452
- if (result.results.length === 0)
2453
- lines.push(" None.");
2454
- for (const hit of result.results) {
2455
- const location = `${safe(hit.path)}${hit.line === undefined ? "" : `:${hit.line}`}`;
2456
- const evidence = hit.evidence.map((item) => `${item.kind}#${item.rank}`).join(", ");
2457
- lines.push(` ${hit.rank}. ${hit.score.toFixed(3)} ${location} \u2014 ${safe(hit.title)} [${safe(evidence)}]`);
2458
- if (hit.snippet !== "")
2459
- lines.push(` ${safe(hit.snippet)}`);
2460
- }
2461
- if ((result.graph?.related.length ?? 0) > 0) {
2462
- lines.push(` Related graph context: ${result.graph?.related.length ?? 0}`);
2463
- }
2464
- if (result.history?.status === "ready") {
2465
- const limited = result.history.limitedCommits?.length ?? 0;
2466
- lines.push(` Git provenance: ${result.history.notes.length} notes at ${safe(result.history.head.slice(0, 12))}` + (limited === 0 ? "" : `; ${limited} commit${limited === 1 ? "" : "s"} with incomplete co-change paths`));
2467
- }
2468
- return `${lines.join(`
2469
- `)}
2470
- `;
2471
- }
2472
- async function runSemantic(command, output, dependencies) {
2473
- if (command.kind === "index") {
2474
- const result = await (dependencies.indexSemanticVault ?? indexSemanticVault)({
2475
- root: command.root,
2476
- ...command.database === undefined ? {} : { database: command.database },
2477
- force: command.force
2478
- });
2479
- output.stdout(command.json ? terminalSafeJson(result) : sanitizeTerminalText(renderSemanticIndex(result)));
2480
- return 0;
2481
- }
2482
- const searchRules = command.rulesPath === undefined ? undefined : await loadSearchRulesFile(command.rulesPath);
2483
- const kb = await (dependencies.openKnowledgeBase ?? openKnowledgeBase)({
2484
- root: command.root,
2485
- repository: command.repository,
2486
- ...command.database === undefined ? {} : { database: command.database },
2487
- ...searchRules === undefined ? {} : { searchRules }
2488
- });
2489
- try {
2490
- const result = await kb.search({
2491
- query: command.query,
2492
- ...command.mode === undefined ? {} : { mode: command.mode },
2493
- ordering: command.ordering,
2494
- filters: command.filters,
2495
- tags: command.tags,
2496
- repositoryScopes: command.repositoryScopes,
2497
- graph: command.graph,
2498
- history: command.history,
2499
- ...command.limit === undefined ? {} : { limit: command.limit },
2500
- ...command.candidateLimit === undefined ? {} : { candidateLimit: command.candidateLimit },
2501
- ...command.minScore === undefined ? {} : { minScore: command.minScore }
2502
- });
2503
- output.stdout(command.json ? terminalSafeJson(result) : sanitizeTerminalText(renderKnowledgeBaseSearch(result)));
2504
- return 0;
2505
- } finally {
2506
- await kb.close();
2507
- }
2508
- }
2509
- function historyIsPartial(result) {
2510
- return result.status === "unavailable" || (result.limitedCommits?.length ?? 0) > 0;
2511
- }
2512
- function renderHistoryAvailability(result) {
2513
- if (result.status === "unavailable") {
2514
- return [`Git history unavailable: ${safe(result.reason)}`];
2515
- }
2516
- const limited = result.limitedCommits?.length ?? 0;
2517
- return limited === 0 ? [] : [
2518
- `Coverage: ${limited} oversized commit${limited === 1 ? "" : "s"} ` + "have incomplete co-change paths."
2519
- ];
2520
- }
2521
- function renderNoteHistory(note, result) {
2522
- const lines = [`Git history for ${safe(note.path)} \u2014 ${safe(note.title)}`];
2523
- lines.push(...renderHistoryAvailability(result));
2524
- if (result.status === "unavailable")
2525
- return `${lines.join(`
2526
- `)}
2527
- `;
2528
- const provenance = result.notes.find(({ id }) => id === note.id);
2529
- const commits = provenance?.commits ?? [];
2530
- lines.push(`Head: ${safe(result.head)}; commits: ${commits.length}.`);
2531
- if (commits.length === 0)
2532
- lines.push(" No indexed commits.");
2533
- for (const commit of commits) {
2534
- lines.push(` ${safe(commit.hash.slice(0, 12))} ${safe(commit.committedAt)} ${safe(commit.subject)}`);
2535
- for (const path of commit.cochangedPaths)
2536
- lines.push(` ${safe(path)}`);
2537
- if (commit.cochangeDetailsLimited === true) {
2538
- lines.push(" Co-change paths are incomplete for this oversized commit.");
2539
- }
2540
- }
2541
- return `${lines.join(`
2542
- `)}
2543
- `;
2544
- }
2545
- function renderHistorySearch(result) {
2546
- const lines = [
2547
- result.status === "ready" ? `Git history results for \u201C${safe(result.query)}\u201D (${result.hits.length})` : "Git history search",
2548
- ...renderHistoryAvailability(result)
2549
- ];
2550
- if (result.status === "unavailable")
2551
- return `${lines.join(`
2552
- `)}
2553
- `;
2554
- if (result.hits.length === 0)
2555
- lines.push(" None.");
2556
- for (const hit of result.hits) {
2557
- lines.push(` ${hit.score.toFixed(3)} ${safe(hit.path)}`);
2558
- for (const commit of hit.commits) {
2559
- const matches = commit.matchedPaths.length === 0 ? "" : ` [${commit.matchedPaths.map(safe).join(", ")}]`;
2560
- lines.push(` ${safe(commit.hash.slice(0, 12))} ${safe(commit.subject)}${matches}`);
2561
- }
2562
- }
2563
- return `${lines.join(`
2564
- `)}
2565
- `;
2566
- }
2567
- var MAX_EVALUATION_MANIFEST_BYTES = 16 * 1024 * 1024;
2568
- var MAX_CLI_EVALUATION_RESULT_LIMIT = Math.min(100, MAX_EVALUATION_RESULTS_PER_QUERY);
2569
- var MAX_CLI_EVALUATION_QUERIES = 500;
2570
- var MAX_CLI_EVALUATION_RUNS = 4000;
2571
- function evaluationEnvironment(command, modelSha256, now) {
2572
- const [modelId, modelRevision] = recommendedEmbeddingModel.split("#", 2);
2573
- const processor = cpus()[0]?.model.trim() || "unknown processor";
2574
- const hardware = `${processor}; ${cpus().length} logical CPUs; ` + `${(totalmem() / 1024 ** 3).toFixed(1)} GiB memory`;
2575
- return {
2576
- generatedAt: now().toISOString(),
2577
- runtime: {
2578
- bun: Bun.version,
2579
- node: process.versions.node,
2580
- os: `${process.platform} ${release()}`,
2581
- arch: process.arch,
2582
- hardware
2583
- },
2584
- model: modelSha256 === null ? {
2585
- kind: "none",
2586
- reason: "The selected retrievers do not use local vector embeddings."
2587
- } : {
2588
- kind: "local",
2589
- id: modelId ?? recommendedEmbeddingModel,
2590
- revision: modelRevision ?? "unversioned",
2591
- sha256: modelSha256
2592
- },
2593
- cache: { state: command.cacheState },
2594
- retrievers: command.retrievers.map((id) => ({
2595
- id,
2596
- version: id === "keyword" || id === "semantic" ? `qmd-${qmdIndexerVersion}/${id}` : id === "hybrid" ? `kb-rrf-v1+qmd-${qmdIndexerVersion}` : `kb-${id}-v1`,
2597
- configuration: {
2598
- resultLimit: command.limit,
2599
- cutoff: command.cutoff,
2600
- split: command.split
2601
- }
2602
- }))
2603
- };
2604
- }
2605
- function metricText(value) {
2606
- return value === null ? "n/a" : value.toFixed(4);
2607
- }
2608
- function renderEvaluationReport(report) {
2609
- const lines = [
2610
- `Retrieval evaluation ${safe(report.corpus.id)}: ${report.queryCount} ${safe(report.split)} queries at cutoff ${report.cutoff}.`,
2611
- `Frozen repository: ${safe(report.corpus.frozen.repositoryCommit)}; vault tree: ${safe(report.corpus.frozen.vaultTree)}.`
2612
- ];
2613
- for (const summary of report.summaries) {
2614
- lines.push(` ${safe(summary.retrieverId)}: ready ${summary.ready}, degraded ${summary.degraded}, unavailable ${summary.unavailable}, failed ${summary.failed}; ` + `recall ${metricText(summary.metrics.recall)}, MRR ${metricText(summary.metrics.reciprocalRank)}, ` + `nDCG ${metricText(summary.metrics.ndcg)}, no-answer ${metricText(summary.metrics.noAnswerAccuracy)}, ` + `p95 ${summary.latencyMs.p95?.toFixed(2) ?? "n/a"} ms.`);
2615
- }
2616
- lines.push("These measurements describe only the frozen corpus, selected retrievers, cache state, and recorded machine.");
2617
- return `${lines.join(`
2618
- `)}
2619
- `;
2620
- }
2621
- async function runEvaluation(command, output, dependencies) {
2622
- const source = await readBoundedUtf8(command.manifest, MAX_EVALUATION_MANIFEST_BYTES, "evaluation manifest");
2623
- let parsed;
2624
- try {
2625
- parsed = JSON.parse(source);
2626
- } catch (error) {
2627
- throw new TypeError("The evaluation manifest must contain valid JSON.", { cause: error });
2628
- }
2629
- const corpus = parseRetrievalEvaluationCorpus(parsed);
2630
- const queryCount = corpus.queries.filter(({ split }) => command.split === "all" || split === command.split).length;
2631
- if (queryCount > MAX_CLI_EVALUATION_QUERIES) {
2632
- throw new RangeError(`CLI evaluation accepts at most ${MAX_CLI_EVALUATION_QUERIES} selected queries.`);
2633
- }
2634
- if (queryCount * command.retrievers.length > MAX_CLI_EVALUATION_RUNS) {
2635
- throw new RangeError(`CLI evaluation accepts at most ${MAX_CLI_EVALUATION_RUNS} retriever/query runs.`);
2636
- }
2637
- const embeddingModelFile = command.modelFile === undefined ? undefined : resolve3(command.modelFile);
2638
- const digestEvaluationModel = dependencies.digestEvaluationModel ?? sha256EmbeddingModelFile;
2639
- const modelSha256 = embeddingModelFile === undefined ? null : await digestEvaluationModel(embeddingModelFile);
2640
- if (modelSha256 !== null && modelSha256 !== recommendedEmbeddingModelSha256) {
2641
- throw new Error("The evaluation model does not match the pinned recommended model SHA-256.");
2642
- }
2643
- const evaluation = await (dependencies.openKnowledgeBaseEvaluation ?? openKnowledgeBaseEvaluation)({
2644
- corpus,
2645
- root: command.root,
2646
- repository: command.repository,
2647
- ...command.database === undefined ? {} : { database: command.database },
2648
- ...embeddingModelFile === undefined ? {} : { embeddingModelFile }
2649
- });
2650
- try {
2651
- const byId = new Map(evaluation.retrievers.map((retriever) => [retriever.id, retriever]));
2652
- const retrievers = command.retrievers.map((id) => {
2653
- const retriever = byId.get(id);
2654
- if (retriever === undefined)
2655
- throw new Error(`Evaluation adapter ${id} is unavailable.`);
2656
- return retriever;
2657
- });
2658
- const runs = await runRetrievalEvaluation({
2659
- corpus,
2660
- retrievers,
2661
- split: command.split,
2662
- limit: command.limit,
2663
- timeoutMs: command.timeoutMs
2664
- });
2665
- if (embeddingModelFile !== undefined) {
2666
- const afterSha256 = await digestEvaluationModel(embeddingModelFile);
2667
- if (afterSha256 !== modelSha256) {
2668
- throw new Error("The evaluation model changed while retrieval was running; retry.");
2669
- }
2670
- }
2671
- const report = buildRetrievalEvaluationReport({
2672
- corpus,
2673
- runs,
2674
- environment: evaluationEnvironment(command, modelSha256, dependencies.evaluationNow ?? (() => new Date)),
2675
- cutoff: command.cutoff,
2676
- baselineRetrieverId: command.baseline,
2677
- bootstrapSeed: 1,
2678
- bootstrapResamples: 1e4
2679
- });
2680
- output.stdout(command.json ? terminalSafeJson(report) : sanitizeTerminalText(renderEvaluationReport(report)));
2681
- return 0;
2682
- } finally {
2683
- await evaluation.close();
2684
- }
2685
- }
2686
- async function runHistory(command, output, dependencies) {
2687
- const kb = await (dependencies.openKnowledgeBase ?? openKnowledgeBase)({
2688
- root: command.root,
2689
- repository: command.repository
2690
- });
2691
- try {
2692
- if (command.action === "note") {
2693
- const note = kb.read(command.query, { maxBytes: 1 });
2694
- const history2 = await kb.history([note.id], {
2695
- ...command.limit === undefined ? {} : { commitsPerNote: command.limit },
2696
- ...command.cochangedLimit === undefined ? {} : { cochangedPathsPerCommit: command.cochangedLimit }
2697
- });
2698
- const payload = {
2699
- kind: "note",
2700
- note: { id: note.id, path: note.path, title: note.title },
2701
- history: history2,
2702
- partial: historyIsPartial(history2)
2703
- };
2704
- output.stdout(command.json ? terminalSafeJson(payload) : sanitizeTerminalText(renderNoteHistory(payload.note, history2)));
2705
- return 0;
2706
- }
2707
- const history = await kb.searchHistory({
2708
- query: command.query,
2709
- ...command.limit === undefined ? {} : { limit: command.limit },
2710
- ...command.commitLimit === undefined ? {} : { commitsPerHit: command.commitLimit },
2711
- ...command.cochangedLimit === undefined ? {} : { cochangedPathsPerCommit: command.cochangedLimit }
2712
- });
2713
- output.stdout(command.json ? terminalSafeJson({
2714
- kind: "search",
2715
- history,
2716
- partial: historyIsPartial(history)
2717
- }) : sanitizeTerminalText(renderHistorySearch(history)));
2718
- return 0;
2719
- } finally {
2720
- await kb.close();
2721
- }
2722
- }
2723
- function issueJson(issue) {
2724
- return issue.kind === "broken" ? { kind: issue.kind, source: issue.source, line: issue.line, target: issue.target } : {
2725
- kind: issue.kind,
2726
- source: issue.source,
2727
- line: issue.line,
2728
- target: issue.target,
2729
- candidates: issue.candidates
2730
- };
2731
- }
2732
- function relationIssueJson(issue) {
2733
- return { ...issue };
2734
- }
2735
- function summary(snapshot, options = {}) {
2736
- return {
2737
- root: snapshot.root,
2738
- indexPath: snapshot.indexPath,
2739
- index: snapshot.index,
2740
- catalogRequired: options.noCatalog !== true,
2741
- noteCount: snapshot.analysis.noteCount,
2742
- contextualLinkCount: snapshot.analysis.contextualLinks.length,
2743
- backlinkCount: snapshot.analysis.backlinks.length,
2744
- authoredRelationCount: snapshot.analysis.authoredRelations.length,
2745
- issues: snapshot.analysis.issues.map(issueJson),
2746
- relationIssues: snapshot.analysis.relationIssues.map(relationIssueJson),
2747
- orphans: snapshot.analysis.orphans,
2748
- mentions: snapshot.analysis.mentions,
2749
- ...options.attachments === undefined ? {} : {
2750
- attachments: {
2751
- referenceCount: options.attachments.references.length,
2752
- validatedCount: options.attachments.attachments.length,
2753
- truncated: options.attachments.truncated,
2754
- issues: options.attachments.issues
2755
- }
2756
- }
2757
- };
2758
- }
2759
- function renderIssue(issue) {
2760
- if (issue.kind === "broken") {
2761
- return `${safe(issue.source)}:${issue.line}: broken wikilink [[${safe(issue.target)}]]`;
2762
- }
2763
- return `${safe(issue.source)}:${issue.line}: ambiguous wikilink [[${safe(issue.target)}]] (${issue.candidates.map(safe).join(", ")})`;
2764
- }
2765
- function renderRelationIssue(issue) {
2766
- if (issue.kind === "malformed") {
2767
- return `${safe(issue.source)}:${issue.line}: malformed relationship${issue.predicate === undefined ? "" : ` ${safe(issue.predicate)}`}: ${safe(issue.message)}`;
2768
- }
2769
- if (issue.kind === "broken") {
2770
- return `${safe(issue.source)}:${issue.line}: broken relationship ${safe(issue.predicate)} \u2192 ${safe(issue.target)}`;
2771
- }
2772
- return `${safe(issue.source)}:${issue.line}: ambiguous relationship ${safe(issue.predicate)} \u2192 ${safe(issue.target)} (${issue.candidates.map(safe).join(", ")})`;
2773
- }
2774
- function renderAdvisories(analysis) {
2775
- const lines = [];
2776
- if (analysis.orphans.length > 0) {
2777
- lines.push(`Advisory: ${analysis.orphans.length} contextual orphan${analysis.orphans.length === 1 ? "" : "s"}.`);
2778
- for (const orphan of analysis.orphans)
2779
- lines.push(` ${safe(orphan)}`);
2780
- }
2781
- if (analysis.mentions.length > 0) {
2782
- lines.push(`Advisory: ${analysis.mentions.length} exact unlinked title or alias mention${analysis.mentions.length === 1 ? "" : "s"}.`);
2783
- for (const mention of analysis.mentions) {
2784
- lines.push(` ${safe(mention.source)}:${mention.line} mentions \u201C${safe(mention.phrase)}\u201D (${safe(mention.target)})`);
2785
- }
2786
- }
2787
- return lines;
2788
- }
2789
- function checkExitCode(snapshot, noCatalog = false, attachments) {
2790
- return !noCatalog && snapshot.index === "stale" || snapshot.analysis.issues.length > 0 || snapshot.analysis.relationIssues.length > 0 || (attachments?.issues.length ?? 0) > 0 || attachments?.truncated === true ? 3 : 0;
2791
- }
2792
- function renderAttachmentIssue(issue) {
2793
- const candidates = issue.candidates === undefined ? "" : ` (${issue.candidates.map(safe).join(", ")})`;
2794
- return `${safe(issue.source)}:${issue.line}: ${safe(issue.kind)} attachment ${safe(issue.target)}: ${safe(issue.message)}${candidates}`;
2795
- }
2796
- function renderSnapshot(command, snapshot, noCatalog = false, attachments) {
2797
- const lines = [
2798
- `${command === "refresh" ? "Refreshed" : "Checked"} ${safe(snapshot.root)}`,
2799
- `Index: ${noCatalog ? `not required (${snapshot.index})` : snapshot.index}; notes: ${snapshot.analysis.noteCount}; contextual links: ${snapshot.analysis.contextualLinks.length}; typed relationships: ${snapshot.analysis.authoredRelations.length}.`
2800
- ];
2801
- if (!noCatalog && snapshot.index === "stale") {
2802
- lines.push(`error: generated catalog is stale (${safe(snapshot.indexPath)})`);
2803
- }
2804
- for (const issue of snapshot.analysis.issues)
2805
- lines.push(`error: ${renderIssue(issue)}`);
2806
- for (const issue of snapshot.analysis.relationIssues) {
2807
- lines.push(`error: ${renderRelationIssue(issue)}`);
2808
- }
2809
- for (const issue of attachments?.issues ?? []) {
2810
- lines.push(`error: ${renderAttachmentIssue(issue)}`);
2811
- }
2812
- if (attachments?.truncated === true && attachments.issues.every(({ kind }) => kind !== "budget")) {
2813
- lines.push("error: attachment validation was truncated by a resource limit");
2814
- }
2815
- lines.push(...renderAdvisories(snapshot.analysis));
2816
- return `${lines.join(`
2817
- `)}
2818
- `;
2819
- }
2820
- function graphJson(snapshot) {
2821
- return { ...summary(snapshot), notes: snapshot.analysis.noteConnections };
2822
- }
2823
- function renderGraph(snapshot) {
2824
- const lines = [
2825
- `Graph: ${snapshot.analysis.noteCount} notes; ${snapshot.analysis.contextualLinks.length} contextual links; ${snapshot.analysis.authoredRelations.length} typed relationships.`
2826
- ];
2827
- for (const note of snapshot.analysis.noteConnections) {
2828
- lines.push(`${safe(note.path)} \u2190 ${note.inboundContextualCount} \u2192 ${note.outboundContextualCount}`);
2829
- }
2830
- if (snapshot.analysis.contextualLinks.length > 0) {
2831
- lines.push("Contextual edges:");
2832
- for (const link of snapshot.analysis.contextualLinks) {
2833
- lines.push(` ${safe(link.source)}:${link.line} \u2192 ${safe(link.target)}`);
2834
- }
2835
- }
2836
- if (snapshot.analysis.authoredRelations.length > 0) {
2837
- lines.push("Typed relationships:");
2838
- for (const relation of snapshot.analysis.authoredRelations) {
2839
- lines.push(` ${safe(relation.source)}:${relation.provenance.line} ${safe(relation.predicate)} \u2192 ${safe(relation.target)}`);
2840
- }
2841
- }
2842
- for (const issue of snapshot.analysis.issues)
2843
- lines.push(`error: ${renderIssue(issue)}`);
2844
- for (const issue of snapshot.analysis.relationIssues) {
2845
- lines.push(`error: ${renderRelationIssue(issue)}`);
2846
- }
2847
- lines.push(...renderAdvisories(snapshot.analysis));
2848
- return `${lines.join(`
2849
- `)}
2850
- `;
2851
- }
2852
- function backlinkPayload(notePath, backlinks, relationships) {
2853
- return {
2854
- note: notePath,
2855
- count: backlinks.length + relationships.length,
2856
- backlinkCount: backlinks.length,
2857
- relationshipCount: relationships.length,
2858
- backlinks,
2859
- relationships
2860
- };
2861
- }
2862
- function renderBacklinks(notePath, backlinks, relationships) {
2863
- const lines = [
2864
- `Backlinks to ${safe(notePath)} (${backlinks.length} links, ${relationships.length} typed relationships)`
2865
- ];
2866
- if (backlinks.length === 0 && relationships.length === 0)
2867
- lines.push(" None.");
2868
- else
2869
- for (const backlink of backlinks)
2870
- lines.push(` ${safe(backlink.source)}:${backlink.line}`);
2871
- for (const relation of relationships) {
2872
- lines.push(` ${safe(relation.source)}:${relation.provenance.line} ${safe(relation.predicate)} \u2192 ${safe(relation.target)}`);
2873
- }
2874
- return `${lines.join(`
2875
- `)}
2876
- `;
2877
- }
2878
- function renderLinks(neighborhood) {
2879
- const lines = [
2880
- `Links around ${safe(neighborhood.note)} (${neighborhood.direction}, depth ${neighborhood.depth}, limit ${neighborhood.limit})`
2881
- ];
2882
- for (const node of neighborhood.nodes) {
2883
- lines.push(` ${node.distance} ${safe(node.path)} \u2014 ${safe(node.title)} \u2190 ${node.inboundContextualCount} \u2192 ${node.outboundContextualCount}`);
2884
- }
2885
- if (neighborhood.edges.length > 0) {
2886
- lines.push("Edges:");
2887
- for (const edge of neighborhood.edges) {
2888
- lines.push(` ${safe(edge.source)}:${edge.line} \u2192 ${safe(edge.target)}`);
2889
- }
2890
- }
2891
- if (neighborhood.relations.length > 0) {
2892
- lines.push("Typed relationships:");
2893
- for (const relation of neighborhood.relations) {
2894
- lines.push(` ${safe(relation.source)}:${relation.provenance.line} ${safe(relation.predicate)} \u2192 ${safe(relation.target)}`);
2895
- }
2896
- }
2897
- if (neighborhood.truncated) {
2898
- lines.push("Results were truncated by the node or connection limit; lower the depth or raise --limit.");
2899
- }
2900
- return `${lines.join(`
2901
- `)}
2902
- `;
2903
- }
2904
- function renderList(rows) {
2905
- const lines = [`Notes (${rows.length})`];
2906
- if (rows.length === 0)
2907
- lines.push(" None.");
2908
- for (const row of rows) {
2909
- const tags = row.tags.length === 0 ? "" : ` #${row.tags.map(safe).join(" #")}`;
2910
- lines.push(` ${safe(row.path)} \u2014 ${safe(row.title)} \u2190 ${row.inboundContextualCount} \u2192 ${row.outboundContextualCount}${tags}`);
2911
- }
2912
- return `${lines.join(`
2913
- `)}
2914
- `;
2915
- }
2916
- function renderSourceInbox(report) {
2917
- const lines = [
2918
- `Source inbox: ${report.pendingSources} pending of ${report.totalSources} captures; ${report.disposedSources} disposed.`
2919
- ];
2920
- if (report.items.length === 0)
2921
- lines.push(" None.");
2922
- for (const item of report.items) {
2923
- const clipped = item.clipped === null ? "undated" : item.clipped;
2924
- lines.push(` ${safe(clipped)} ${safe(item.path)} \u2014 ${safe(item.title)} (${safe(item.reason)})`);
2925
- }
2926
- if (report.truncated) {
2927
- lines.push(` \u2026 ${report.pendingSources - report.returnedSources} more; raise --limit to inspect them.`);
2928
- }
2929
- lines.push("Advisory only: a capture may remain an intentional leaf.");
2930
- return `${lines.join(`
2931
- `)}
2932
- `;
2933
- }
2934
- function renderAuthoringResult(verb, result) {
2935
- return [
2936
- `${result.changed ? verb : "Unchanged"} ${safe(result.path)}`,
2937
- `Revision: ${safe(result.revision)}; outbound relationships: ${result.relations.length}.`,
2938
- ""
2939
- ].join(`
2940
- `);
2941
- }
2942
- async function runNoteCreate(command, output, dependencies) {
2943
- const body = command.body ?? (command.bodyFile === undefined ? undefined : await readBoundedUtf8(command.bodyFile, 16 * 1024 * 1024, "note body"));
2944
- const result = await (dependencies.createNote ?? createNote)(command.root, {
2945
- ...command.input,
2946
- ...body === undefined ? {} : { body }
2947
- });
2948
- output.stdout(command.json ? terminalSafeJson(result) : sanitizeTerminalText(renderAuthoringResult("Created", result)));
2949
- return 0;
2950
- }
2951
- async function runRelation(command, output, dependencies) {
2952
- if (command.action === "list") {
2953
- const snapshot = await (dependencies.scanVault ?? scanVault)(command.root, { mentionScope: false });
2954
- const lookup = lookupNote(snapshot.notes, command.source);
2955
- if (lookup.kind === "missing") {
2956
- if (command.json) {
2957
- output.stdout(terminalSafeJson({
2958
- ok: false,
2959
- kind: "missing",
2960
- note: command.source
2961
- }));
2962
- } else {
2963
- output.stderr(`error: note was not found
2964
- `);
2965
- }
2966
- return 3;
2967
- }
2968
- if (lookup.kind === "ambiguous") {
2969
- if (command.json) {
2970
- output.stdout(terminalSafeJson({
2971
- ok: false,
2972
- kind: "ambiguous",
2973
- candidates: lookup.candidates.map(({ id }) => id)
2974
- }));
2975
- } else {
2976
- output.stderr(`error: note is ambiguous (${lookup.candidates.map(({ id }) => safe(id)).join(", ")})
2977
- `);
2978
- }
2979
- return 3;
2980
- }
2981
- const outbound = snapshot.analysis.authoredRelations.filter(({ source }) => source === lookup.note.id);
2982
- const inbound = snapshot.analysis.authoredRelations.filter(({ target: target2 }) => target2 === lookup.note.id);
2983
- const payload = {
2984
- note: lookup.note.id,
2985
- outboundCount: outbound.length,
2986
- inboundCount: inbound.length,
2987
- outbound,
2988
- inbound
2989
- };
2990
- if (command.json) {
2991
- output.stdout(terminalSafeJson(payload));
2992
- } else {
2993
- const lines = [
2994
- `Relationships for ${safe(lookup.note.id)} (${outbound.length} out, ${inbound.length} in)`
2995
- ];
2996
- if (outbound.length === 0 && inbound.length === 0)
2997
- lines.push(" None.");
2998
- for (const relation of outbound) {
2999
- lines.push(` \u2192 ${safe(relation.predicate)} \u2192 ${safe(relation.target)}`);
3000
- }
3001
- for (const relation of inbound) {
3002
- lines.push(` \u2190 ${safe(relation.predicate)} \u2190 ${safe(relation.source)}`);
3003
- }
3004
- output.stdout(`${lines.join(`
3005
- `)}
3006
- `);
3007
- }
3008
- return 0;
3009
- }
3010
- const predicate = command.predicate;
3011
- const target = command.target;
3012
- if (predicate === undefined || target === undefined) {
3013
- throw new Error("relation command parser lost its predicate or target");
3014
- }
3015
- const options = command.expectedRevision === undefined ? {} : { expectedRevision: command.expectedRevision };
3016
- const result = command.action === "add" ? await (dependencies.addNoteRelation ?? addNoteRelation)(command.root, command.source, predicate, target, options) : await (dependencies.removeNoteRelation ?? removeNoteRelation)(command.root, command.source, predicate, target, options);
3017
- output.stdout(command.json ? terminalSafeJson(result) : sanitizeTerminalText(renderAuthoringResult("Updated", result)));
3018
- return 0;
3019
- }
3020
- function renderPercolation(result, note) {
3021
- const lines = [
3022
- `Percolation${note === undefined ? "" : ` for ${safe(note)}`}: ${result.candidates.length} candidate${result.candidates.length === 1 ? "" : "s"}${result.truncated ? " (truncated)" : ""}.`
3023
- ];
3024
- if (result.candidates.length === 0)
3025
- lines.push(" None.");
3026
- for (const candidate of result.candidates) {
3027
- if (candidate.kind === "missing-concept") {
3028
- lines.push(` concept #${safe(candidate.tag)} \u2192 ${safe(candidate.suggestedId)} (${candidate.support} supporting notes)` + (candidate.collidesWith === null ? "" : `; natural ID is occupied by ${safe(candidate.collidesWith)}`));
3029
- } else if (candidate.kind === "missing-relation") {
3030
- lines.push(` relation pair {${safe(candidate.source)}, ${safe(candidate.target)}} (predicate required; ${candidate.support} shared signals)`);
3031
- } else if (candidate.kind === "unlinked-mention") {
3032
- lines.push(` mention ${safe(candidate.source)} \u2192 ${safe(candidate.target)} (${candidate.support})`);
3033
- } else {
3034
- lines.push(` hygiene ${safe(candidate.problem)} in ${safe(candidate.source)}${candidate.target === null ? "" : ` \u2192 ${safe(candidate.target)}`}: ${safe(candidate.message)}`);
3035
- }
3036
- for (const evidence of candidate.evidence.slice(0, 3)) {
3037
- if (evidence.kind === "tag") {
3038
- lines.push(` ${safe(evidence.path)} #${safe(evidence.tag)}`);
3039
- } else if (evidence.kind === "shared-tag") {
3040
- lines.push(` ${safe(evidence.path)} shares #${safe(evidence.tag)}`);
3041
- } else if (evidence.kind === "shared-concept") {
3042
- lines.push(` ${safe(evidence.path)} shares ${safe(evidence.concept)}`);
3043
- } else if (evidence.kind === "mention") {
3044
- lines.push(` ${safe(evidence.source)}:${evidence.line} mentions \u201C${safe(evidence.phrase)}\u201D`);
3045
- } else if (evidence.kind === "relation") {
3046
- lines.push(` ${safe(evidence.source)}:${evidence.line} ${safe(evidence.predicate)} \u2192 ${safe(evidence.target)}`);
3047
- } else {
3048
- lines.push(` ${safe(evidence.source)}:${evidence.line} ${safe(evidence.message)}`);
3049
- }
3050
- }
3051
- if (candidate.evidence.length > 3) {
3052
- lines.push(` \u2026 ${candidate.evidence.length - 3} more evidence records`);
3053
- }
3054
- }
3055
- return `${lines.join(`
3056
- `)}
3057
- `;
3058
- }
3059
- async function runPercolate(command, output, dependencies) {
3060
- const maxMentionPairs = command.note === undefined ? MAX_PERCOLATION_MENTION_PAIRS : MAX_SCOPED_PERCOLATION_MENTION_PAIRS;
3061
- const snapshot = await (dependencies.scanVault ?? scanVault)(command.root, {
3062
- maxNotes: MAX_PERCOLATION_NOTES,
3063
- maxMentionPairs,
3064
- maxMentions: Math.min(MAX_PERCOLATION_MENTIONS, maxMentionPairs),
3065
- ...command.note === undefined ? {} : { mentionScope: command.note }
3066
- });
3067
- if (command.proofs === true) {
3068
- if (command.note === undefined)
3069
- throw new Error("percolate --proofs requires one note");
3070
- const result2 = await (dependencies.percolateWithGraph ?? percolateWithGraph)(snapshot, {
3071
- note: command.note,
3072
- minSupport: command.minSupport,
3073
- limit: command.limit
3074
- });
3075
- const support = [result2.positiveSupport.sharedTags, result2.positiveSupport.sharedConcepts];
3076
- const partial = support.some((item) => item.truncated || item.proofsTruncated);
3077
- const text = `${renderPercolation(result2.suggestions, command.note)}
3078
- Snapshot: ${result2.revision}
3079
- ` + `Positive shared-tag and shared-concept proofs are included in --json output.
3080
- ` + `Absence checks, support counts, and predicate choices remain Wordcell authoring decisions.
3081
- ` + (partial ? `Partial proof evidence: a graph query reached its bounds.
3082
- ` : "");
3083
- output.stdout(command.json ? terminalSafeJson(result2) : sanitizeTerminalText(redactSensitiveText(text)));
3084
- return partial ? 4 : 0;
3085
- }
3086
- const result = (dependencies.percolateVault ?? percolateVault)(snapshot.notes, snapshot.analysis, {
3087
- ...command.note === undefined ? {} : { note: command.note },
3088
- minSupport: command.minSupport,
3089
- limit: command.limit
3090
- });
3091
- const jsonOutput = {
3092
- root: snapshot.root,
3093
- note: command.note ?? null,
3094
- minSupport: command.minSupport,
3095
- limit: command.limit,
3096
- schemaVersion: result.schemaVersion,
3097
- candidates: result.candidates,
3098
- truncated: result.truncated
3099
- };
3100
- output.stdout(command.json ? terminalSafeJson(jsonOutput) : sanitizeTerminalText(renderPercolation(result, command.note)));
3101
- return 0;
3102
- }
3103
- async function runList(command, output, dependencies) {
3104
- const snapshot = await (dependencies.scanVault ?? scanVault)(command.root, command.options);
3105
- const rows = queryVault(snapshot.notes, snapshot.analysis, {
3106
- filters: command.filters,
3107
- tags: command.tags,
3108
- repositoryScopes: command.repositoryScopes,
3109
- sort: command.sort,
3110
- direction: command.direction,
3111
- ...command.limit === undefined ? {} : { limit: command.limit }
3112
- });
3113
- output.stdout(command.json ? terminalSafeJson({ root: snapshot.root, count: rows.length, notes: rows }) : sanitizeTerminalText(renderList(rows)));
3114
- return 0;
3115
- }
3116
- async function runCatalog(command, output, dependencies) {
3117
- const snapshot = await (dependencies.scanVault ?? scanVault)(command.root, command.options);
3118
- const relativeIndex = relative(snapshot.root, snapshot.indexPath).split("\\").join("/");
3119
- const catalogNoteId = relativeIndex.toLocaleLowerCase("en-US").endsWith(".md") ? relativeIndex.slice(0, -3) : relativeIndex;
3120
- const catalog = renderCatalog(snapshot.notes, catalogNoteId);
3121
- output.stdout(command.json ? terminalSafeJson({
3122
- root: snapshot.root,
3123
- catalogMode: snapshot.catalogMode,
3124
- noteCount: snapshot.analysis.noteCount,
3125
- catalog
3126
- }) : sanitizeTerminalText(`${catalog}
3127
- `));
3128
- return 0;
3129
- }
3130
- async function runInbox(command, output, dependencies) {
3131
- const snapshot = await (dependencies.scanVault ?? scanVault)(command.root, command.options);
3132
- const report = sourceInbox(snapshot.notes, snapshot.analysis, {
3133
- limit: command.limit,
3134
- ...command.sourcePrefixes.length === 0 ? {} : { sourcePrefixes: command.sourcePrefixes }
3135
- });
3136
- output.stdout(command.json ? terminalSafeJson({ root: snapshot.root, ...report }) : sanitizeTerminalText(renderSourceInbox(report)));
3137
- return 0;
3138
- }
3139
- async function runInit(command, output, initialize) {
3140
- const result = await initialize(command.directory);
3141
- if (command.json)
3142
- output.stdout(terminalSafeJson(result));
3143
- else {
3144
- const relativeRoot = relative(process.cwd(), result.root) || ".";
3145
- output.stdout(`Initialized ${safe(relativeRoot)} with ${result.files.length} files.
3146
- `);
3147
- }
3148
- return 0;
3149
- }
3150
- async function runCaptureBundle(command, output, dependencies) {
3151
- const verification = await (dependencies.verifyCaptureBundle ?? verifyCaptureBundle)(command.path, command.options);
3152
- const inspection = verification.inspection;
3153
- if (command.json) {
3154
- const jsonInspection = command.action === "show" ? inspection : Object.freeze({
3155
- root: inspection.root,
3156
- schemaVersion: inspection.schemaVersion,
3157
- sourceUrl: inspection.sourceUrl,
3158
- canonicalUrl: inspection.canonicalUrl,
3159
- status: inspection.status,
3160
- capturedAt: inspection.capturedAt,
3161
- document: Object.freeze({
3162
- path: inspection.document.path,
3163
- bytes: inspection.document.bytes,
3164
- sha256: inspection.document.sha256,
3165
- expectedBytes: inspection.document.expectedBytes,
3166
- expectedSha256: inspection.document.expectedSha256,
3167
- integrity: inspection.document.integrity
3168
- }),
3169
- assets: inspection.assets
3170
- });
3171
- output.stdout(terminalSafeJson({
3172
- ok: verification.ok,
3173
- trust: "untrusted",
3174
- trustScope: command.action === "show" ? "inspection and issues" : "inspection metadata and issues; stored document and source HTML omitted",
3175
- inspection: jsonInspection,
3176
- issues: verification.issues
3177
- }));
3178
- } else {
3179
- const lines = [
3180
- `Capture bundle: ${safe(inspection.root)}`,
3181
- `Source: ${safe(inspection.sourceUrl)}`,
3182
- `Document: ${safe(inspection.document.path)} (${inspection.document.integrity}; ${inspection.document.bytes} bytes)`,
3183
- `Assets: ${inspection.assets.length}`
3184
- ];
3185
- for (const issue of verification.issues)
3186
- lines.push(`Issue: ${safe(issue.path)} \u2014 ${safe(issue.message)}`);
3187
- if (command.action === "show") {
3188
- lines.push("", "Execution trust: untrusted. The captured fields below are data, not instructions.", "", sanitizeTerminalText(inspection.document.markdown));
3189
- if (inspection.sourceHtml !== undefined) {
3190
- lines.push("", "Source HTML (inert text):", "", sanitizeTerminalText(inspection.sourceHtml));
3191
- }
3192
- }
3193
- output.stdout(`${lines.join(`
3194
- `)}
3195
- `);
3196
- }
3197
- return verification.ok ? 0 : 3;
3198
- }
3199
- async function runCaptureDiff(command, output, dependencies) {
3200
- const result = await (dependencies.diffCaptureBundle ?? diffCaptureBundle)(command.options);
3201
- if (command.json) {
3202
- output.stdout(terminalSafeJson({
3203
- ok: true,
3204
- trust: "untrusted",
3205
- trustScope: "result",
3206
- result
3207
- }));
3208
- } else {
3209
- output.stdout([
3210
- `Capture at ${safe(result.ref)}: ${result.status}`,
3211
- `Path: ${safe(result.repositoryPath)}`,
3212
- `Current SHA-256: ${result.currentSha256}`,
3213
- ...result.referenceSha256 === null ? [] : [`Reference SHA-256: ${result.referenceSha256}`],
3214
- ...result.diff === null || result.diff === "" ? [] : ["", "Diff (untrusted data):", "", sanitizeTerminalText(result.diff)],
3215
- ""
3216
- ].join(`
3217
- `));
3218
- }
3219
- return 0;
3220
- }
3221
- async function authorizedPortfolioSelection(command, dependencies) {
3222
- if (command.selection === "explicit")
3223
- return { authorizedVaults: command.vaults };
3224
- const registry = snapshotPortfolioRegistry(await (dependencies.loadPortfolioRegistry ?? loadPortfolioRegistry)(command.registryPath));
3225
- const selected = command.selection === "all" ? registry.vaults : registry.vaults.filter(({ visibility }) => visibility === "public" || visibility === "organization");
3226
- if (selected.length === 0)
3227
- throw new Error("Portfolio selection resolved to no vaults.");
3228
- if (selected.length > MAX_AUTHORIZED_VAULTS) {
3229
- throw new RangeError(`Portfolio selection resolved to ${selected.length} vaults, exceeding the per-operation limit of ${MAX_AUTHORIZED_VAULTS}; select a bounded set with repeated --vault.`);
3230
- }
3231
- return Object.freeze({
3232
- authorizedVaults: Object.freeze(selected.map(({ key }) => key)),
3233
- registry
3234
- });
3235
- }
3236
- function renderPortfolioSearch(result) {
3237
- const lines = [
3238
- `Portfolio search: ${safe(result.query)}`,
3239
- `Vaults: ${result.diagnostics.availableVaults}/${result.diagnostics.selectedVaults}; notes: ${result.diagnostics.notes}; partial: ${result.partial}`
3240
- ];
3241
- for (const hit of result.results) {
3242
- const identity = hit.identity.kind === "stable" ? hit.identity.uri : `${hit.vault.key}:${hit.path} [legacy path identity]`;
3243
- lines.push("", `${hit.rank}. ${safe(hit.title)}`, ` ${safe(identity)} \xB7 local rank ${hit.localRank}`, ` ${safe(hit.snippet)}`);
3244
- }
3245
- return `${lines.join(`
3246
- `)}
3247
- `;
3248
- }
3249
- async function runPortfolioSearch(command, output, dependencies) {
3250
- const selection = await authorizedPortfolioSelection(command, dependencies);
3251
- const searchRules = command.rulesPath === undefined ? undefined : await loadSearchRulesFile(command.rulesPath);
3252
- const session = await (dependencies.openKnowledgePortfolio ?? openKnowledgePortfolio)({
3253
- registryPath: command.registryPath,
3254
- ...selection.registry === undefined ? {} : { registry: selection.registry },
3255
- workspaceRoot: command.workspaceRoot,
3256
- authorizedVaults: selection.authorizedVaults,
3257
- failurePolicy: command.failurePolicy,
3258
- ...searchRules === undefined ? {} : { knowledgeBase: { searchRules } }
3259
- });
3260
- try {
3261
- const result = await session.search({
3262
- query: command.query,
3263
- ...command.mode === undefined ? {} : { mode: command.mode },
3264
- ordering: command.ordering,
3265
- ...command.limit === undefined ? {} : { limit: command.limit },
3266
- graph: false
3267
- });
3268
- output.stdout(command.json ? terminalSafeJson({
3269
- ok: true,
3270
- trust: "untrusted",
3271
- trustScope: "result.results[*].title, snippet, metadata, evidence, and local",
3272
- result
3273
- }) : renderPortfolioSearch(result));
3274
- return 0;
3275
- } finally {
3276
- await session.close();
3277
- }
3278
- }
3279
- async function runPortfolioAudit(command, output, dependencies) {
3280
- const selection = await authorizedPortfolioSelection(command, dependencies);
3281
- const report = await (dependencies.auditKnowledgePortfolio ?? auditKnowledgePortfolio)({
3282
- registryPath: command.registryPath,
3283
- ...selection.registry === undefined ? {} : { registry: selection.registry },
3284
- workspaceRoot: command.workspaceRoot,
3285
- authorizedVaults: selection.authorizedVaults
3286
- });
3287
- if (command.json) {
3288
- output.stdout(terminalSafeJson({
3289
- ok: report.counts.error === 0 && !report.truncated,
3290
- report
3291
- }));
3292
- } else {
3293
- const lines = [
3294
- `Portfolio audit: ${report.auditedVaults}/${report.selectedVaults} vaults; ${report.notes} notes`,
3295
- `Issues: ${report.counts.error} errors, ${report.counts.warning} warnings, ${report.counts.advisory} advisories`
3296
- ];
3297
- for (const issue of report.issues) {
3298
- const location = issue.vault === undefined ? "portfolio" : `${issue.vault.key}${issue.path === undefined ? "" : `:${issue.path}${issue.line === undefined ? "" : `:${issue.line}`}`}`;
3299
- lines.push(`- ${issue.severity} ${issue.code} ${safe(location)}: ${safe(issue.message)}`);
3300
- }
3301
- output.stdout(`${lines.join(`
3302
- `)}
3303
- `);
3304
- }
3305
- return command.strict && (report.counts.error > 0 || report.truncated) ? 3 : 0;
3306
- }
3307
- function contextIssuePayload(issue) {
3308
- return { ...issue };
3309
- }
3310
- function uniqueAgentContextIssues(issues) {
3311
- const unique = new Map;
3312
- for (const issue of issues)
3313
- unique.set(JSON.stringify(issue), issue);
3314
- return [...unique.values()].toSorted((left, right) => `${left.kind}\x00${left.message}`.localeCompare(`${right.kind}\x00${right.message}`));
3315
- }
3316
- function contextPayload(inspection, snapshot, memory) {
3317
- const connections = new Map(snapshot.analysis.noteConnections.map((connection) => [connection.id, connection]));
3318
- return {
3319
- repositoryRoot: inspection.repositoryRoot,
3320
- vaultRoot: snapshot.root,
3321
- target: inspection.target,
3322
- targetScope: inspection.targetScope,
3323
- guides: inspection.inheritedGuides.map((guide) => ({
3324
- path: guide.path,
3325
- scope: guide.scope,
3326
- context: guide.marker.markers[0]?.noteId
3327
- })),
3328
- contexts: inspection.matchingContexts.map((context) => {
3329
- const connection = connections.get(context.note.id);
3330
- return {
3331
- id: context.note.id,
3332
- path: context.note.path,
3333
- title: context.note.title,
3334
- scope: context.scope,
3335
- summary: context.note.summary,
3336
- inboundContextualCount: connection?.inboundContextualCount ?? 0,
3337
- outboundContextualCount: connection?.outboundContextualCount ?? 0
3338
- };
3339
- }),
3340
- records: memory,
3341
- issues: inspection.issues.map(contextIssuePayload)
3342
- };
3343
- }
3344
- function renderContext(inspection, snapshot, memory) {
3345
- const lines = [
3346
- `Agent context for ${safe(inspection.target)} (scope ${safe(inspection.targetScope)})`,
3347
- "Guides (root \u2192 nearest):"
3348
- ];
3349
- if (inspection.inheritedGuides.length === 0)
3350
- lines.push(" None.");
3351
- for (const guide of inspection.inheritedGuides) {
3352
- const context = guide.marker.markers[0]?.noteId;
3353
- lines.push(` ${safe(guide.path)}${context === undefined ? "" : ` \u2192 ${safe(context)}`}`);
3354
- }
3355
- lines.push("Wordcell hubs (nearest \u2192 root):");
3356
- if (inspection.matchingContexts.length === 0)
3357
- lines.push(" None.");
3358
- for (const context of inspection.matchingContexts) {
3359
- const connection = snapshot.analysis.noteConnections.find(({ id }) => id === context.note.id);
3360
- lines.push(` ${safe(context.note.id)} \u2014 ${safe(context.note.title)} \u2190 ${connection?.inboundContextualCount ?? 0} \u2192 ${connection?.outboundContextualCount ?? 0}`);
3361
- if (context.note.summary !== "")
3362
- lines.push(` ${safe(context.note.summary)}`);
3363
- }
3364
- const groupLabels = {
3365
- maintainedKnowledge: "Maintained knowledge",
3366
- activePlans: "Active plans",
3367
- datedResearch: "Dated research",
3368
- reports: "Reports",
3369
- historicalPlans: "Historical plans"
3370
- };
3371
- lines.push(`Repository memory (${memory.counts.returned} of ${memory.counts.matched} matched records):`);
3372
- for (const key of repositoryMemoryGroupKeys) {
3373
- const group = memory.groups[key];
3374
- lines.push(` ${groupLabels[key]} (${group.returned}/${group.total})`);
3375
- if (group.records.length === 0)
3376
- lines.push(" None.");
3377
- for (const record of group.records) {
3378
- const scopeState = record.scopeState.status === "present" ? record.scopeState.kind : record.scopeState.status;
3379
- lines.push(` ${safe(record.path)} \u2014 ${safe(record.title)} [${safe(record.matchedScope)}; ${safe(record.match)}; ${safe(scopeState)}]`);
3380
- if (record.description !== undefined)
3381
- lines.push(` ${safe(record.description)}`);
3382
- else if (record.summary !== "")
3383
- lines.push(` ${safe(record.summary)}`);
3384
- }
3385
- if (group.truncated)
3386
- lines.push(` \u2026 ${group.total - group.returned} more.`);
3387
- }
3388
- if (memory.invalidRecords.total > 0) {
3389
- lines.push(`Repository-memory errors (${memory.invalidRecords.returned}/${memory.invalidRecords.total}):`);
3390
- for (const invalid of memory.invalidRecords.details) {
3391
- lines.push(` ${safe(invalid.path)}: ${invalid.issues.map(safe).join(" ")}`);
3392
- }
3393
- }
3394
- if (memory.advisories.total > 0) {
3395
- lines.push(`Repository-memory advisories (${memory.advisories.returned}/${memory.advisories.total}):`);
3396
- for (const advisory of memory.advisories.details)
3397
- lines.push(` ${safe(advisory.message)}`);
3398
- }
3399
- for (const issue of inspection.issues)
3400
- lines.push(`error: ${safe(issue.message)}`);
3401
- if (inspection.matchingContexts.length > 0) {
3402
- lines.push("Open a hub, then use `wordcell links <hub> --root <vault> --depth 1` for bounded neighboring context.");
3403
- }
3404
- return `${lines.join(`
3405
- `)}
3406
- `;
3407
- }
3408
- async function runContext(command, output, dependencies) {
3409
- const snapshot = await (dependencies.scanVault ?? scanVault)(command.root);
3410
- const inspection = await (dependencies.inspectAgentContextRepository ?? inspectAgentContextRepository)(snapshot.notes, {
3411
- repositoryRoot: command.repository,
3412
- target: command.target,
3413
- targetKind: command.targetKind
3414
- });
3415
- const memory = await (dependencies.buildRepositoryMemoryContext ?? buildRepositoryMemoryContext)(snapshot.notes, {
3416
- repositoryRoot: command.repository,
3417
- target: inspection.target
3418
- });
3419
- output.stdout(command.json ? terminalSafeJson(contextPayload(inspection, snapshot, memory)) : sanitizeTerminalText(renderContext(inspection, snapshot, memory)));
3420
- return inspection.issues.length === 0 && memory.invalidRecords.total === 0 ? 0 : 3;
3421
- }
3422
- function agentIdentityPayload(scopeInput) {
3423
- const scope = normalizeRepositoryScope(scopeInput);
3424
- return {
3425
- scope,
3426
- noteId: agentContextNoteId(scope),
3427
- notePath: agentContextNotePath(scope),
3428
- guidePath: agentContextGuidePath(scope),
3429
- marker: agentContextMarkerForScope(scope)
3430
- };
3431
- }
3432
- function renderAgentIdentity(identity) {
3433
- return [
3434
- `Scope: ${safe(identity.scope ?? "")}`,
3435
- `Note ID: ${safe(identity.noteId ?? "")}`,
3436
- `Note path: ${safe(identity.notePath ?? "")}`,
3437
- `Guide path: ${safe(identity.guidePath ?? "")}`,
3438
- `Marker: ${safe(identity.marker ?? "")}`,
3439
- ""
3440
- ].join(`
3441
- `);
3442
- }
3443
- function runAgentIdentity(command, output) {
3444
- const identity = agentIdentityPayload(command.scope);
3445
- output.stdout(command.json ? terminalSafeJson(identity) : sanitizeTerminalText(renderAgentIdentity(identity)));
3446
- return 0;
3447
- }
3448
- function agentCheckErrors(contextIssues, discoveryIssues, audit) {
3449
- return [
3450
- ...uniqueAgentContextIssues(contextIssues).map((issue) => ({ kind: "context", issue })),
3451
- ...discoveryIssues.filter(({ kind }) => kind !== "symlink-directory").map((issue) => ({ kind: "discovery", issue })),
3452
- ...audit.guides.flatMap((guide) => guide.shapeIssues.map((issue) => ({ kind: "shape", path: guide.path, issue })))
3453
- ];
3454
- }
3455
- function renderAgentCheckError(error) {
3456
- if (error.kind === "context")
3457
- return error.issue.message;
3458
- if (error.kind === "discovery")
3459
- return error.issue.message;
3460
- return `${error.path}: ${error.issue.message}`;
3461
- }
3462
- function advisoryLabel(advisory) {
3463
- if (advisory.kind === "contents-budget") {
3464
- return `${advisory.path}: Contents has ${advisory.actualWords} words / ${advisory.actualBullets} bullets`;
3465
- }
3466
- if (advisory.kind === "guidelines-budget") {
3467
- return `${advisory.path}: Guidelines has ${advisory.actualWords} words / ${advisory.actualBullets} bullets`;
3468
- }
3469
- if (advisory.kind === "long-guideline") {
3470
- return `${advisory.path}:${advisory.line}: guideline has ${advisory.words} words`;
3471
- }
3472
- if (advisory.kind === "inherited-budget") {
3473
- return `${advisory.path}: inherited chain has ${advisory.words} words across ${advisory.guides.length} guides`;
3474
- }
3475
- return `${advisory.guides.length} guides repeat a ${advisory.words}-word rule: ${advisory.text}`;
3476
- }
3477
- function agentReportPayload(repositoryRoot, vaultRoot, audit, validContexts, errors, discoveryIssues, includeAudit) {
3478
- return {
3479
- repositoryRoot,
3480
- vaultRoot,
3481
- guideCount: audit.guideCount,
3482
- mappedGuideCount: audit.mappedGuideCount,
3483
- validContextCount: validContexts,
3484
- words: audit.words,
3485
- contentsWords: audit.contentsWords,
3486
- guidelineWords: audit.guidelineWords,
3487
- nonblankLines: audit.nonblankLines,
3488
- errors,
3489
- discoveryIssues,
3490
- ...includeAudit ? {
3491
- advisories: audit.advisories,
3492
- duplicates: audit.duplicates,
3493
- guides: audit.guides.map((guide) => ({
3494
- path: guide.path,
3495
- scope: guide.scope,
3496
- words: guide.words,
3497
- nonblankLines: guide.nonblankLines,
3498
- contentsWords: guide.contents.words,
3499
- guidelineWords: guide.guidelines.words,
3500
- inheritedWords: guide.inheritedWords,
3501
- inheritedGuidePaths: guide.inheritedGuidePaths,
3502
- context: guide.marker.markers[0]?.noteId
3503
- }))
3504
- } : {}
3505
- };
3506
- }
3507
- function renderAgentReport(action, audit, validContexts, errors, discoveryIssues) {
3508
- const lines = [
3509
- `${action === "check" ? "Checked" : "Audited"} ${audit.guideCount} agent guides; ${audit.mappedGuideCount} markers, ${validContexts} valid Wordcell hubs.`,
3510
- `Context: ${audit.words} words (${audit.contentsWords} Contents, ${audit.guidelineWords} Guidelines), ${audit.nonblankLines} nonblank lines.`
3511
- ];
3512
- if (errors.length === 0)
3513
- lines.push("Mappings and guide shape: clean.");
3514
- else
3515
- for (const error of errors)
3516
- lines.push(`error: ${safe(renderAgentCheckError(error))}`);
3517
- const skippedDirectories = discoveryIssues.filter(({ kind }) => kind === "symlink-directory");
3518
- if (skippedDirectories.length > 0) {
3519
- lines.push(`Skipped symbolic-link directories (${skippedDirectories.length}):`);
3520
- for (const issue of skippedDirectories)
3521
- lines.push(` ${safe(issue.path)}`);
3522
- }
3523
- if (action === "audit") {
3524
- lines.push(`Advisories: ${audit.advisories.length}; exact duplicate rules: ${audit.duplicates.length}.`);
3525
- const worstChains = audit.guides.toSorted((left, right) => right.inheritedWords - left.inheritedWords || left.path.localeCompare(right.path)).slice(0, 10);
3526
- lines.push("Largest inherited chains:");
3527
- for (const guide of worstChains) {
3528
- lines.push(` ${guide.inheritedWords} words / ${guide.inheritedGuidePaths.length} guides ${safe(guide.path)}`);
3529
- }
3530
- const shown = audit.advisories.slice(0, 25);
3531
- if (shown.length > 0)
3532
- lines.push("Advisory sample:");
3533
- for (const advisory of shown)
3534
- lines.push(` ${safe(advisoryLabel(advisory))}`);
3535
- if (audit.advisories.length > shown.length) {
3536
- lines.push(` \u2026 ${audit.advisories.length - shown.length} more; rerun with --json for the complete audit.`);
3537
- }
3538
- }
3539
- return `${lines.join(`
3540
- `)}
3541
- `;
3542
- }
3543
- async function runAgents(command, output, dependencies) {
3544
- const snapshot = await (dependencies.scanVault ?? scanVault)(command.root);
3545
- const repository = await (dependencies.auditAgentGuideRepository ?? auditAgentGuideRepository)(command.repository);
3546
- const mapping = analyzeAgentContexts(snapshot.notes, repository.guides);
3547
- const filesystem = await (dependencies.inspectAgentContextRepository ?? inspectAgentContextRepository)(snapshot.notes, {
3548
- repositoryRoot: command.repository,
3549
- target: ".",
3550
- targetKind: "directory",
3551
- validationMode: "all"
3552
- });
3553
- const errors = agentCheckErrors([...mapping.issues, ...filesystem.issues], repository.issues, repository.audit);
3554
- const validContexts = mapping.contexts.filter(({ valid }) => valid).length;
3555
- if (command.json) {
3556
- output.stdout(terminalSafeJson(agentReportPayload(repository.repositoryRoot, snapshot.root, repository.audit, validContexts, errors, repository.issues, command.action === "audit")));
56
+ // src/cli.ts
57
+ if (import.meta.main) {
58
+ const { standaloneSupportEnvironment, isUsefulSupportResult, runProductSupportCommand, showProductSupportInvitation } = await import("./support-vm4mkw0k.js");
59
+ const env = standaloneSupportEnvironment();
60
+ const args = process.argv.slice(2);
61
+ if (args[0] === "support") {
62
+ process.exitCode = await runProductSupportCommand(args.slice(1), { env });
3557
63
  } else {
3558
- output.stdout(sanitizeTerminalText(renderAgentReport(command.action, repository.audit, validContexts, errors, repository.issues)));
3559
- }
3560
- return errors.length === 0 ? 0 : 3;
3561
- }
3562
- async function runVault(command, output, dependencies) {
3563
- const snapshot = command.kind === "refresh" ? await (dependencies.refreshVault ?? refreshVault)(command.root, command.options) : await (dependencies.scanVault ?? scanVault)(command.root, command.options);
3564
- if (command.kind === "refresh" || command.kind === "check") {
3565
- const noCatalog = command.kind === "check" && command.noCatalog === true;
3566
- const attachments = command.kind === "check" ? await (dependencies.validateMarkdownAttachments ?? validateMarkdownAttachments)({
3567
- root: snapshot.root,
3568
- documents: snapshot.notes.map(({ path, content }) => ({ path, content }))
3569
- }) : undefined;
3570
- output.stdout(command.json ? terminalSafeJson(summary(snapshot, { noCatalog, ...attachments === undefined ? {} : { attachments } })) : sanitizeTerminalText(renderSnapshot(command.kind, snapshot, noCatalog, attachments)));
3571
- return checkExitCode(snapshot, noCatalog, attachments);
3572
- }
3573
- if (command.kind === "graph") {
3574
- output.stdout(command.json ? terminalSafeJson(graphJson(snapshot)) : sanitizeTerminalText(renderGraph(snapshot)));
3575
- return 0;
3576
- }
3577
- const lookup = lookupNote(snapshot.notes, command.note ?? "");
3578
- if (lookup.kind === "missing") {
3579
- if (command.json) {
3580
- output.stdout(terminalSafeJson({
3581
- ok: false,
3582
- kind: "missing",
3583
- note: command.note ?? ""
3584
- }));
3585
- } else {
3586
- output.stderr(`error: note was not found
3587
- `);
3588
- }
3589
- return 3;
3590
- }
3591
- if (lookup.kind === "ambiguous") {
3592
- if (command.json) {
3593
- output.stdout(terminalSafeJson({ ok: false, kind: "ambiguous", candidates: lookup.candidates.map(({ path }) => path) }));
3594
- } else {
3595
- output.stderr(`error: note is ambiguous (${lookup.candidates.map(({ path }) => safe(path)).join(", ")})
3596
- `);
3597
- }
3598
- return 3;
3599
- }
3600
- if (command.kind === "links") {
3601
- const neighborhood = navigateLinks(snapshot.notes, snapshot.analysis, lookup.note, {
3602
- direction: command.direction ?? "both",
3603
- depth: command.depth ?? 1,
3604
- ...command.limit === undefined ? {} : { limit: command.limit }
3605
- });
3606
- output.stdout(command.json ? terminalSafeJson(neighborhood) : sanitizeTerminalText(renderLinks(neighborhood)));
3607
- return 0;
3608
- }
3609
- const connection = snapshot.analysis.noteConnections.find(({ id }) => id === lookup.note.id);
3610
- const backlinks = connection?.backlinks ?? [];
3611
- const relationBacklinks = connection?.relationBacklinks ?? [];
3612
- output.stdout(command.json ? terminalSafeJson(backlinkPayload(lookup.note.path, backlinks, relationBacklinks)) : sanitizeTerminalText(renderBacklinks(lookup.note.path, backlinks, relationBacklinks)));
3613
- return 0;
3614
- }
3615
- async function main4(rawArguments = process.argv.slice(2), output = defaultOutput2, dependencies = {}) {
3616
- const jsonRequested = rawArguments.includes("--json");
3617
- const parsed = parseArguments(rawArguments);
3618
- if (!parsed.ok) {
3619
- if (jsonRequested) {
3620
- output.stdout(terminalSafeJson({
3621
- ok: false,
3622
- error: { kind: "parse", message: parsed.message }
3623
- }));
3624
- } else {
3625
- output.stderr(`error: ${safe(parsed.message)}
3626
-
3627
- ${sanitizeTerminalText(usage)}`);
3628
- }
3629
- return 2;
64
+ const exitCode = await runExecutable(args);
65
+ process.exitCode = exitCode;
66
+ if (exitCode === 0 && isUsefulSupportResult(args, env))
67
+ await showProductSupportInvitation({ env });
3630
68
  }
3631
- const command = parsed.value;
3632
- if (command.kind === "help") {
3633
- if (output === defaultOutput2 && !jsonRequested)
3634
- output.stdout(terminalIntro({ isTTY: process.stdout.isTTY, columns: process.stdout.columns, term: process.env.TERM }));
3635
- output.stdout(sanitizeTerminalText(usage));
3636
- return 0;
3637
- }
3638
- try {
3639
- if (command.kind === "clip") {
3640
- return await (dependencies.runClipCommand ?? main)(command.arguments, process.env, output);
3641
- }
3642
- if (command.kind === "capture-bundle")
3643
- return await runCaptureBundle(command, output, dependencies);
3644
- if (command.kind === "capture-diff")
3645
- return await runCaptureDiff(command, output, dependencies);
3646
- if (command.kind === "portfolio-search")
3647
- return await runPortfolioSearch(command, output, dependencies);
3648
- if (command.kind === "portfolio-audit")
3649
- return await runPortfolioAudit(command, output, dependencies);
3650
- if (command.kind === "url-metadata") {
3651
- return await (dependencies.runUrlMetadataCommand ?? main3)(command.arguments, process.env, output);
3652
- }
3653
- if (command.kind === "pdf") {
3654
- return await (dependencies.runPdfCommand ?? main2)(command.arguments, process.env, output);
3655
- }
3656
- if (command.kind === "init") {
3657
- return await runInit(command, output, dependencies.initVault ?? initVault);
3658
- }
3659
- if (command.kind === "index" || command.kind === "search") {
3660
- return await runSemantic(command, output, dependencies);
3661
- }
3662
- if (command.kind === "history")
3663
- return await runHistory(command, output, dependencies);
3664
- if (command.kind === "evaluate")
3665
- return await runEvaluation(command, output, dependencies);
3666
- if (command.kind === "context")
3667
- return await runContext(command, output, dependencies);
3668
- if (command.kind === "agent-identity")
3669
- return runAgentIdentity(command, output);
3670
- if (command.kind === "agents")
3671
- return await runAgents(command, output, dependencies);
3672
- if (command.kind === "note-create")
3673
- return await runNoteCreate(command, output, dependencies);
3674
- if (command.kind === "relation")
3675
- return await runRelation(command, output, dependencies);
3676
- if (command.kind === "graph-rebuild" || command.kind === "graph-verify" || command.kind === "graph-query") {
3677
- const result = await executeGraphCommand(command, dependencies);
3678
- output.stdout(command.json ? terminalSafeJson(result.value) : sanitizeTerminalText(redactSensitiveText(result.text)));
3679
- return result.exitCode;
3680
- }
3681
- if (command.kind === "percolate")
3682
- return await runPercolate(command, output, dependencies);
3683
- if (command.kind === "list")
3684
- return await runList(command, output, dependencies);
3685
- if (command.kind === "inbox")
3686
- return await runInbox(command, output, dependencies);
3687
- if (command.kind === "catalog")
3688
- return await runCatalog(command, output, dependencies);
3689
- return await runVault(command, output, dependencies);
3690
- } catch (error) {
3691
- const message = error instanceof Error ? error.message : String(error);
3692
- if (jsonRequested) {
3693
- output.stdout(terminalSafeJson({
3694
- ok: false,
3695
- error: { kind: "runtime", message }
3696
- }));
3697
- } else {
3698
- output.stderr(`error: ${safe(message)}
3699
- `);
3700
- }
3701
- return 1;
3702
- }
3703
- }
3704
- var strictJsonTail = Promise.resolve();
3705
- async function serializeStrictJson(operation) {
3706
- const previous = strictJsonTail;
3707
- let release2 = () => {
3708
- return;
3709
- };
3710
- strictJsonTail = new Promise((resolvePromise) => {
3711
- release2 = resolvePromise;
3712
- });
3713
- await previous;
3714
- try {
3715
- return await operation();
3716
- } finally {
3717
- release2();
3718
- }
3719
- }
3720
- function strictProtocolObject(value) {
3721
- const parsed = JSON.parse(value);
3722
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
3723
- throw new TypeError("Machine output must be one JSON object.");
3724
- }
3725
- return parsed;
3726
69
  }
3727
- async function runExecutable(rawArguments = process.argv.slice(2), dependencies = {}) {
3728
- if (!rawArguments.includes("--json")) {
3729
- return main4(rawArguments, defaultOutput2, dependencies);
3730
- }
3731
- return serializeStrictJson(async () => {
3732
- const stdout = process.stdout;
3733
- const ownWrite = Object.getOwnPropertyDescriptor(stdout, "write");
3734
- const rawStdoutWrite = stdout.write.bind(stdout);
3735
- const rawStderrWrite = process.stderr.write.bind(process.stderr);
3736
- const originalConsole = {
3737
- log: console.log,
3738
- info: console.info,
3739
- debug: console.debug
3740
- };
3741
- const chunks = [];
3742
- const protocolOutput = {
3743
- stdout: (value) => chunks.push(value),
3744
- stderr: (value) => {
3745
- rawStderrWrite(value);
3746
- }
3747
- };
3748
- const redirectedWrite = (...arguments_) => {
3749
- Reflect.apply(rawStderrWrite, process.stderr, arguments_);
3750
- return true;
3751
- };
3752
- const redirectedConsole = (...arguments_) => {
3753
- rawStderrWrite(`${format(...arguments_)}
3754
- `);
3755
- };
3756
- try {
3757
- Object.defineProperty(stdout, "write", {
3758
- configurable: true,
3759
- writable: true,
3760
- value: redirectedWrite
3761
- });
3762
- console.log = redirectedConsole;
3763
- console.info = redirectedConsole;
3764
- console.debug = redirectedConsole;
3765
- } catch (error) {
3766
- if (ownWrite === undefined)
3767
- Reflect.deleteProperty(stdout, "write");
3768
- else
3769
- Object.defineProperty(stdout, "write", ownWrite);
3770
- console.log = originalConsole.log;
3771
- console.info = originalConsole.info;
3772
- console.debug = originalConsole.debug;
3773
- const fallback = terminalSafeJson({
3774
- ok: false,
3775
- error: {
3776
- kind: "protocol",
3777
- message: `Could not guard machine stdout: ${error instanceof Error ? error.message : String(error)}`
3778
- }
3779
- });
3780
- rawStdoutWrite(fallback);
3781
- return 1;
3782
- }
3783
- let exitCode = 1;
3784
- let protocolValue;
3785
- try {
3786
- exitCode = await main4(rawArguments, protocolOutput, dependencies);
3787
- protocolValue = strictProtocolObject(chunks.join(""));
3788
- } catch (error) {
3789
- protocolValue = {
3790
- ok: false,
3791
- error: {
3792
- kind: "protocol",
3793
- message: error instanceof Error ? error.message : String(error)
3794
- }
3795
- };
3796
- exitCode = 1;
3797
- } finally {
3798
- if (ownWrite === undefined) {
3799
- Reflect.deleteProperty(stdout, "write");
3800
- } else {
3801
- Object.defineProperty(stdout, "write", ownWrite);
3802
- }
3803
- console.log = originalConsole.log;
3804
- console.info = originalConsole.info;
3805
- console.debug = originalConsole.debug;
3806
- }
3807
- rawStdoutWrite(terminalSafeJson(protocolValue));
3808
- return exitCode;
3809
- });
3810
- }
3811
-
3812
- // src/cli.ts
3813
- if (import.meta.main)
3814
- process.exitCode = await runExecutable();
3815
70
  export {
3816
71
  usage,
3817
72
  runExecutable,
3818
73
  parseArguments,
3819
- main4 as main
74
+ main
3820
75
  };