@hraness/wordcell 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +37 -35
  2. package/dist/capture.js +6 -6
  3. package/dist/cli-bin.js +14 -0
  4. package/dist/cli-release-c74c5m3k.js +799 -0
  5. package/dist/cli.js +26 -23
  6. package/dist/clip/acquire.js +3 -3
  7. package/dist/clip/cli.js +6 -6
  8. package/dist/clip/doctor.js +4 -4
  9. package/dist/evaluation-builder-bin.js +14 -0
  10. package/dist/evaluation-builder.js +12 -17
  11. package/dist/evaluation-kb.js +6 -6
  12. package/dist/graph-percolation.js +2 -2
  13. package/dist/index-3t0v457d.js +18 -0
  14. package/dist/{index-47893rgw.js → index-5h5awwh4.js} +4 -4
  15. package/dist/index-8pabwzqg.js +909 -0
  16. package/dist/{index-1wccy765.js → index-8w1zsgcm.js} +63 -930
  17. package/dist/{index-7drercgk.js → index-9fywek7g.js} +1 -1
  18. package/dist/{index-hz2wyggk.js → index-9paxge84.js} +1 -1
  19. package/dist/{index-mcpppwbq.js → index-9zkba8hr.js} +6 -6
  20. package/dist/{index-59bcxqee.js → index-j2jt49gr.js} +1 -1
  21. package/dist/index-ncgdaja4.js +64 -0
  22. package/dist/{index-nwrehke7.js → index-nd8v7r0z.js} +1 -1
  23. package/dist/{index-t3abkwk4.js → index-zbv70qmk.js} +15 -15
  24. package/dist/index.js +40 -40
  25. package/dist/pdf.js +2 -2
  26. package/dist/portfolio.js +5 -5
  27. package/dist/sdk.js +4 -4
  28. package/dist/{support-adj7bbge.js → support-ym4mpf7w.js} +19 -18
  29. package/dist/url-intelligence.js +3 -3
  30. package/dist/workflows/decision-context.js +5 -5
  31. package/dist/workflows/index.js +5 -5
  32. package/package.json +13 -6
  33. package/skills/wordcell/SKILL.md +10 -1
  34. package/src/cli-bin.ts +5 -0
  35. package/src/cli-help.ts +12 -0
  36. package/src/cli-program.ts +3 -57
  37. package/src/cli-release.ts +732 -0
  38. package/src/cli-startup.ts +76 -0
  39. package/src/cli-update.ts +53 -0
  40. package/src/cli.ts +5 -4
  41. package/src/clip/metadata-search-tool/src/openalex.rs +156 -8
  42. package/src/evaluation-builder-bin.ts +5 -0
  43. package/src/evaluation-builder-cli-args.ts +30 -0
  44. package/src/evaluation-builder.ts +3 -27
  45. package/src/import-supermemory.ts +3 -1
  46. package/dist/{index-hxyjer3x.js → index-hacpnaew.js} +3 -3
  47. package/dist/{index-qfqjfxaa.js → index-m9p2a4mj.js} +4 -4
  48. package/dist/{index-xwxy71ew.js → index-ncwzmsge.js} +5 -5
  49. package/dist/{index-e26mdwxz.js → index-wqx1x32f.js} +3 -3
@@ -0,0 +1,909 @@
1
+ // @bun
2
+ // src/cli-help.ts
3
+ var ROOT = ["--root <directory>", "Knowledge base folder (default: current directory)"];
4
+ var INDEX = ["--index <path>", "Catalog note to use (default: index.md)"];
5
+ var JSON_OPTION = ["--json", "Print machine-readable output"];
6
+ var REPO = ["--repo <repository>", "Git repository the notes describe"];
7
+ var WHERE = ["--where <path=value>", "Keep notes whose metadata field has this value"];
8
+ var HAS = ["--has <path>", "Keep notes that set this metadata field"];
9
+ var TAG = ["--tag <tag>", "Keep notes with this tag"];
10
+ var SCOPE = ["--scope <repository-path>", "Keep notes about this code path"];
11
+ var DATABASE = ["--database <path>", "Use this search index file"];
12
+ var MODE = [
13
+ "--mode <hybrid|exact|keyword|semantic>",
14
+ "Match exact words, the keyword index, meaning, or keywords and meaning together"
15
+ ];
16
+ var RULES = ["--rules <file>", "Apply reviewed search aliases from a JSON file"];
17
+ var PRIORITY = ["--priority", "Order results by the rules file first"];
18
+ var DEPTH = ["--depth <count>", "How many links to follow (1 to 10)"];
19
+ var DIRECTION = ["--direction <in|out|both>", "Follow incoming links, outgoing links, or both"];
20
+ var commandHelp = [
21
+ {
22
+ id: "init",
23
+ label: "init [directory]",
24
+ usage: "wordcell init [directory] [--json]",
25
+ summary: "Create a knowledge base folder (default: kb). It never merges into an existing folder.",
26
+ group: "start",
27
+ options: [JSON_OPTION],
28
+ examples: ["wordcell init kb"]
29
+ },
30
+ {
31
+ id: "note create",
32
+ label: "note create <id>",
33
+ usage: "wordcell note create <id> --title <title> [options]",
34
+ summary: "Write one new Markdown note.",
35
+ group: "start",
36
+ options: [
37
+ ["--title <title>", "Note title (required)"],
38
+ ["--type <type>", "Note type, such as decision or concept"],
39
+ ["--tag <tag>", "Add a tag (repeatable)"],
40
+ ["--body <markdown>", "Note body"],
41
+ ["--body-file <path|->", "Read the body from a file, or from piped input with -"],
42
+ ROOT,
43
+ JSON_OPTION
44
+ ],
45
+ examples: [
46
+ 'wordcell note create notes/first --title "First note" --body "Keep retries bounded." --root kb'
47
+ ]
48
+ },
49
+ {
50
+ id: "search",
51
+ label: "search <query>",
52
+ usage: "wordcell search <query> [options]",
53
+ summary: "Search notes by words or meaning.",
54
+ group: "start",
55
+ notes: [
56
+ "Exact mode needs no index or model. Keyword, semantic, and hybrid modes",
57
+ "use the local index from `wordcell index`."
58
+ ],
59
+ options: [
60
+ ROOT,
61
+ MODE,
62
+ ["--limit <count>", "Show at most this many results"],
63
+ WHERE,
64
+ HAS,
65
+ TAG,
66
+ SCOPE,
67
+ ["--related <note>", "Also show notes linked to this note"],
68
+ ["--graph-depth <1|2>", "How far to follow links for context"],
69
+ ["--no-graph", "Skip link context"],
70
+ ["--history", "Add recent Git history when available"],
71
+ ["--no-history", "Skip Git history (default)"],
72
+ ["--require-history", "Fail when Git history is unavailable"],
73
+ REPO,
74
+ DATABASE,
75
+ RULES,
76
+ PRIORITY,
77
+ ["--candidate-limit <count>", "How many candidates to rank before trimming"],
78
+ ["--min-score <score>", "Drop results scoring below this (0 to 1)"],
79
+ ["--rerank <typesafe>", "Rerank results with the hosted TypeSafe service"],
80
+ ["--rerank-limit <2..25>", "How many results the reranker sees"],
81
+ ["--selected-passage", "Add a local source excerpt to each result"],
82
+ JSON_OPTION
83
+ ],
84
+ examples: ['wordcell search "retries" --root kb --mode exact', 'wordcell search "retry policy" --root kb --limit 5']
85
+ },
86
+ {
87
+ id: "check",
88
+ label: "check",
89
+ usage: "wordcell check [options]",
90
+ summary: "Check links, metadata, and attachments. It changes no files.",
91
+ group: "start",
92
+ options: [
93
+ ROOT,
94
+ INDEX,
95
+ ["--no-catalog", "Skip the catalog check"],
96
+ ["--repo <repository>", "Also report notes whose code paths no longer exist"],
97
+ JSON_OPTION
98
+ ],
99
+ examples: ["wordcell check --root kb", "wordcell check --root kb --repo ."]
100
+ },
101
+ {
102
+ id: "list",
103
+ label: "list",
104
+ usage: "wordcell list [options]",
105
+ summary: "List notes by metadata or tag. Also: wordcell notes.",
106
+ group: "notes",
107
+ options: [
108
+ ROOT,
109
+ INDEX,
110
+ WHERE,
111
+ HAS,
112
+ TAG,
113
+ SCOPE,
114
+ ["--sort <field>", "Sort by a metadata field, title, path, or link counts"],
115
+ ["--order <asc|desc>", "Sort direction"],
116
+ ["--limit <count>", "Show at most this many notes"],
117
+ JSON_OPTION
118
+ ],
119
+ examples: ["wordcell list --root kb --tag decision", "wordcell list --root kb --where status=active"]
120
+ },
121
+ {
122
+ id: "links",
123
+ label: "links <note>",
124
+ usage: "wordcell links <note> [options]",
125
+ summary: "Follow links into and out of a note.",
126
+ group: "notes",
127
+ options: [ROOT, INDEX, DIRECTION, DEPTH, ["--limit <count>", "Show at most this many notes"], JSON_OPTION],
128
+ examples: ["wordcell links notes/first --root kb --direction both --depth 2"]
129
+ },
130
+ {
131
+ id: "backlinks",
132
+ label: "backlinks <note>",
133
+ usage: "wordcell backlinks <note> [options]",
134
+ summary: "Show the notes that link to a note.",
135
+ group: "notes",
136
+ options: [ROOT, INDEX, JSON_OPTION],
137
+ examples: ["wordcell backlinks notes/first --root kb"]
138
+ },
139
+ {
140
+ id: "relation",
141
+ label: "relation add|remove|list",
142
+ usage: "wordcell relation <add|remove|list> ...",
143
+ summary: "Edit a note's typed links. They live in its frontmatter.",
144
+ group: "notes",
145
+ family: true,
146
+ options: [],
147
+ examples: ["wordcell relation add notes/first supersedes notes/old --root kb"],
148
+ notes: ["Run `wordcell relation add --help` for each action."]
149
+ },
150
+ {
151
+ id: "relation add",
152
+ label: "relation add <source> <predicate> <target>",
153
+ usage: "wordcell relation add <source> <predicate> <target> [options]",
154
+ summary: "Add a typed link from one note to another. Running it twice changes nothing.",
155
+ group: "notes",
156
+ unlisted: true,
157
+ options: [ROOT, ["--expected-revision <sha256:...>", "Only write if the note is still at this revision"], JSON_OPTION],
158
+ examples: ["wordcell relation add notes/first supersedes notes/old --root kb"]
159
+ },
160
+ {
161
+ id: "relation remove",
162
+ label: "relation remove <source> <predicate> <target>",
163
+ usage: "wordcell relation remove <source> <predicate> <target> [options]",
164
+ summary: "Remove a typed link from a note.",
165
+ group: "notes",
166
+ unlisted: true,
167
+ options: [ROOT, ["--expected-revision <sha256:...>", "Only write if the note is still at this revision"], JSON_OPTION],
168
+ examples: ["wordcell relation remove notes/first supersedes notes/old --root kb"]
169
+ },
170
+ {
171
+ id: "relation list",
172
+ label: "relation list <note>",
173
+ usage: "wordcell relation list <note> [options]",
174
+ summary: "List a note's typed links in both directions.",
175
+ group: "notes",
176
+ unlisted: true,
177
+ options: [ROOT, JSON_OPTION],
178
+ examples: ["wordcell relation list notes/first --root kb"]
179
+ },
180
+ {
181
+ id: "refresh",
182
+ label: "refresh",
183
+ usage: "wordcell refresh [options]",
184
+ summary: "Update the catalog in index.md. It also reports link problems.",
185
+ group: "notes",
186
+ options: [ROOT, INDEX, JSON_OPTION],
187
+ examples: ["wordcell refresh --root kb"]
188
+ },
189
+ {
190
+ id: "catalog",
191
+ label: "catalog",
192
+ usage: "wordcell catalog [options]",
193
+ summary: "Print a catalog of every note. It writes nothing.",
194
+ group: "notes",
195
+ options: [ROOT, INDEX, JSON_OPTION],
196
+ examples: ["wordcell catalog --root kb"]
197
+ },
198
+ {
199
+ id: "import supermemory",
200
+ label: "import supermemory <file>",
201
+ usage: "wordcell import supermemory <export.json>... [options]",
202
+ summary: "Import a Supermemory export as notes.",
203
+ group: "notes",
204
+ options: [
205
+ ROOT,
206
+ ["--prefix <directory>", "Put every imported note in this folder"],
207
+ ["--dry-run", "Show what would be written without writing"],
208
+ JSON_OPTION
209
+ ],
210
+ examples: ["wordcell import supermemory export.json --root kb --dry-run"]
211
+ },
212
+ {
213
+ id: "index",
214
+ label: "index",
215
+ usage: "wordcell index [options]",
216
+ summary: "Build the local index for meaning-based search.",
217
+ group: "search",
218
+ notes: ["The first run downloads a local embedding model (about 300 MB) once."],
219
+ options: [ROOT, DATABASE, ["--force", "Rebuild the index from scratch"], JSON_OPTION],
220
+ examples: ["wordcell index --root kb"]
221
+ },
222
+ {
223
+ id: "context",
224
+ label: "context <path>",
225
+ usage: "wordcell context <repository-path> [options]",
226
+ summary: "Find notes and AGENTS.md files for a code path.",
227
+ group: "search",
228
+ options: [
229
+ ["--root <vault>", "Knowledge base folder (default: current directory)"],
230
+ REPO,
231
+ ["--kind <auto|file|directory>", "Treat the path as a file or a folder"],
232
+ JSON_OPTION
233
+ ],
234
+ examples: ["wordcell context src/index.ts --root kb --repo ."]
235
+ },
236
+ {
237
+ id: "history",
238
+ label: "history <note>",
239
+ usage: "wordcell history <note> [options]",
240
+ summary: "Show the Git commits that changed a note. Also: wordcell history search <query>.",
241
+ group: "search",
242
+ options: [
243
+ ROOT,
244
+ REPO,
245
+ ["--limit <count>", "Show at most this many commits"],
246
+ ["--cochanged-limit <count>", "Show at most this many files changed alongside"],
247
+ JSON_OPTION
248
+ ],
249
+ examples: ["wordcell history notes/first --root kb --repo ."]
250
+ },
251
+ {
252
+ id: "history search",
253
+ label: "history search <query>",
254
+ usage: "wordcell history search <query-or-path> [options]",
255
+ summary: "Search commit messages and changed paths in the repository.",
256
+ group: "search",
257
+ unlisted: true,
258
+ options: [
259
+ ROOT,
260
+ REPO,
261
+ ["--limit <count>", "Show at most this many results"],
262
+ ["--commit-limit <count>", "Read at most this many commits"],
263
+ ["--cochanged-limit <count>", "Show at most this many files changed alongside"],
264
+ JSON_OPTION
265
+ ],
266
+ examples: ['wordcell history search "retry" --root kb --repo .']
267
+ },
268
+ {
269
+ id: "inbox",
270
+ label: "inbox",
271
+ usage: "wordcell inbox [options]",
272
+ summary: "List saved sources no note links to yet. Also: wordcell source-inbox.",
273
+ group: "search",
274
+ options: [
275
+ ROOT,
276
+ INDEX,
277
+ ["--source-prefix <directory>", "Look for sources in this folder (repeatable)"],
278
+ ["--limit <count>", "Show at most this many sources"],
279
+ JSON_OPTION
280
+ ],
281
+ examples: ["wordcell inbox --root kb"]
282
+ },
283
+ {
284
+ id: "clip",
285
+ label: "clip <url|current>",
286
+ usage: "wordcell clip <url|current> [options]",
287
+ summary: "Save a web page as Markdown. Threads, videos, and images are kept too.",
288
+ group: "capture",
289
+ options: [],
290
+ examples: ["wordcell clip https://example.com/article --output kb/articles"],
291
+ notes: ["Run `wordcell clip --help` for every capture option."]
292
+ },
293
+ {
294
+ id: "inspect",
295
+ label: "inspect <url>",
296
+ usage: "wordcell inspect <url> [options]",
297
+ summary: "Preview a capture. It writes no files.",
298
+ group: "capture",
299
+ options: [],
300
+ examples: ["wordcell inspect https://example.com/article"]
301
+ },
302
+ {
303
+ id: "pdf",
304
+ label: "pdf <file-or-url>",
305
+ usage: "wordcell pdf <file-or-url> [options]",
306
+ summary: "Save a PDF as Markdown. The original file and its images are kept.",
307
+ group: "capture",
308
+ options: [],
309
+ examples: ["wordcell pdf paper.pdf --output kb/articles"]
310
+ },
311
+ {
312
+ id: "capture",
313
+ label: "capture show|verify|diff",
314
+ usage: "wordcell capture <show|verify|diff> <bundle> [options]",
315
+ summary: "Read, check, or compare a saved capture.",
316
+ group: "capture",
317
+ family: true,
318
+ options: [],
319
+ examples: ["wordcell capture verify kb/articles/example"],
320
+ notes: ["Run `wordcell capture show --help` for each action. `wordcell capture <url>` is the same as clip."]
321
+ },
322
+ {
323
+ id: "capture show",
324
+ label: "capture show <bundle>",
325
+ usage: "wordcell capture show <bundle> [options]",
326
+ summary: "Print a saved capture as plain text.",
327
+ group: "capture",
328
+ unlisted: true,
329
+ options: [
330
+ ["--verify-assets", "Also check saved images and files"],
331
+ ["--include-source-html", "Include the original page HTML"],
332
+ JSON_OPTION
333
+ ],
334
+ examples: ["wordcell capture show kb/articles/example"]
335
+ },
336
+ {
337
+ id: "capture verify",
338
+ label: "capture verify <bundle>",
339
+ usage: "wordcell capture verify <bundle> [options]",
340
+ summary: "Check that a saved capture still matches its recorded hashes.",
341
+ group: "capture",
342
+ unlisted: true,
343
+ options: [["--verify-assets", "Also check saved images and files"], JSON_OPTION],
344
+ examples: ["wordcell capture verify kb/articles/example --verify-assets"]
345
+ },
346
+ {
347
+ id: "capture diff",
348
+ label: "capture diff <bundle>",
349
+ usage: "wordcell capture diff <bundle> [options]",
350
+ summary: "Compare a saved capture with an earlier Git version.",
351
+ group: "capture",
352
+ unlisted: true,
353
+ options: [REPO, ["--ref <ref>", "Git version to compare with (default: HEAD)"], JSON_OPTION],
354
+ examples: ["wordcell capture diff kb/articles/example --repo . --ref main"]
355
+ },
356
+ {
357
+ id: "publish",
358
+ label: "publish --out <directory>",
359
+ usage: "wordcell publish --out <directory> [options]",
360
+ summary: "Build a static website from your notes.",
361
+ group: "publish",
362
+ options: [
363
+ ["--out <directory>", "Folder to write the site to (required)"],
364
+ ROOT,
365
+ INDEX,
366
+ ["--include <path>", "Publish only these notes or folders (repeatable)"],
367
+ ["--exclude <path>", "Leave out these notes or folders (repeatable)"],
368
+ ["--include-glob <pattern>", "Publish notes matching a pattern (repeatable)"],
369
+ ["--exclude-glob <pattern>", "Leave out notes matching a pattern (repeatable)"],
370
+ WHERE,
371
+ HAS,
372
+ TAG,
373
+ SCOPE,
374
+ ["--from <note>", "Publish the notes linked from this note"],
375
+ DEPTH,
376
+ DIRECTION,
377
+ ["--title <title>", "Site title"],
378
+ ["--description <text>", "Site description"],
379
+ ["--base-path <path>", "Serve the site under this path"],
380
+ ["--base-url <url>", "Public address of the site"],
381
+ ["--noindex", "Ask search engines not to index the site"],
382
+ ["--no-index-content", "Leave note text out of the site search"],
383
+ ["--deterministic", "Omit the build time so builds match byte for byte"],
384
+ ["--dry-run", "Show what would be published without writing"],
385
+ ["--list-limit <0-1000>", "How many paths to list in the report"],
386
+ ["--force", "Replace an existing output folder"],
387
+ JSON_OPTION
388
+ ],
389
+ examples: ["wordcell publish --root kb --out site", "wordcell publish --root kb --out site --tag public"]
390
+ },
391
+ {
392
+ id: "serve",
393
+ label: "serve --root <directory>",
394
+ usage: "wordcell serve --root <directory> [options]",
395
+ summary: "Preview a published site on this computer.",
396
+ group: "publish",
397
+ options: [
398
+ ["--root <directory>", "Published site folder (required)"],
399
+ ["--host <host>", "Address to listen on (default: 127.0.0.1)"],
400
+ ["--port <port>", "Port to listen on"],
401
+ JSON_OPTION
402
+ ],
403
+ examples: ["wordcell serve --root site --port 8080"]
404
+ },
405
+ {
406
+ id: "mcp",
407
+ label: "mcp --root <vault>",
408
+ usage: "wordcell mcp --root <vault> [options]",
409
+ summary: "Serve your notes to AI apps over MCP.",
410
+ group: "publish",
411
+ notes: ["MCP (Model Context Protocol) is how AI apps such as Claude call local tools."],
412
+ options: [
413
+ ["--root <vault>", "Knowledge base folder (required)"],
414
+ REPO,
415
+ ["--read-only", "Offer only the read tools"]
416
+ ],
417
+ examples: ["wordcell mcp --root /absolute/path/to/kb --read-only"]
418
+ },
419
+ {
420
+ id: "agents",
421
+ label: "agents check|audit",
422
+ usage: "wordcell agents <check|audit|identity> ...",
423
+ summary: "Check the notes that give coding agents context for each code folder.",
424
+ group: "agents",
425
+ family: true,
426
+ unlisted: true,
427
+ options: [],
428
+ examples: ["wordcell agents check --root kb --repo ."],
429
+ notes: ["Run `wordcell agents check --help` for each action."]
430
+ },
431
+ {
432
+ id: "agents check",
433
+ label: "agents check",
434
+ usage: "wordcell agents check [options]",
435
+ summary: "Check AGENTS.md context notes against the code.",
436
+ group: "agents",
437
+ options: [["--root <vault>", "Knowledge base folder"], REPO, JSON_OPTION],
438
+ examples: ["wordcell agents check --root kb --repo ."]
439
+ },
440
+ {
441
+ id: "agents audit",
442
+ label: "agents audit",
443
+ usage: "wordcell agents audit [options]",
444
+ summary: "Find long or repeated AGENTS.md rules. It runs agents check first.",
445
+ group: "agents",
446
+ options: [["--root <vault>", "Knowledge base folder"], REPO, JSON_OPTION],
447
+ examples: ["wordcell agents audit --root kb --repo ."]
448
+ },
449
+ {
450
+ id: "doctor",
451
+ label: "doctor",
452
+ usage: "wordcell doctor [--json]",
453
+ summary: "Check optional tools for capture and search. It changes nothing.",
454
+ group: "diagnostics",
455
+ options: [JSON_OPTION],
456
+ examples: ["wordcell doctor"]
457
+ },
458
+ {
459
+ id: "adapters",
460
+ label: "adapters",
461
+ usage: "wordcell adapters [--json]",
462
+ summary: "List the sites and platforms clip supports.",
463
+ group: "diagnostics",
464
+ options: [JSON_OPTION],
465
+ examples: ["wordcell adapters"]
466
+ },
467
+ {
468
+ id: "graph",
469
+ label: "graph",
470
+ usage: "wordcell graph [options]",
471
+ summary: "Show the link graph and broken links. Unlinked notes are listed too.",
472
+ group: "diagnostics",
473
+ notes: ["See `wordcell help advanced` for graph rebuild, verify, and query."],
474
+ options: [ROOT, INDEX, JSON_OPTION],
475
+ examples: ["wordcell graph --root kb"]
476
+ },
477
+ {
478
+ id: "agents identity",
479
+ label: "agents identity <scope>",
480
+ usage: "wordcell agents identity <repository-scope> [--json]",
481
+ summary: "Print the context note name and marker for a code folder, without writing.",
482
+ group: "advanced",
483
+ options: [JSON_OPTION],
484
+ examples: ["wordcell agents identity packages/parser"]
485
+ },
486
+ {
487
+ id: "graph rebuild",
488
+ label: "graph rebuild",
489
+ usage: "wordcell graph rebuild [options]",
490
+ summary: "Rebuild the local graph cache from the Markdown files.",
491
+ group: "advanced",
492
+ options: [["--fresh", "Discard the old cache first"], ROOT, INDEX, JSON_OPTION],
493
+ examples: ["wordcell graph rebuild --root kb"]
494
+ },
495
+ {
496
+ id: "graph verify",
497
+ label: "graph verify",
498
+ usage: "wordcell graph verify [options]",
499
+ summary: "Check that the local graph cache matches the Markdown files.",
500
+ group: "advanced",
501
+ options: [ROOT, INDEX, JSON_OPTION],
502
+ examples: ["wordcell graph verify --root kb"]
503
+ },
504
+ {
505
+ id: "graph query",
506
+ label: "graph query --program <name>",
507
+ usage: "wordcell graph query --program <name> [options]",
508
+ summary: "Run a built-in graph query, with proof of each answer.",
509
+ group: "advanced",
510
+ options: [
511
+ ["--program <name>", "backlinks, reachability, scope-route, relation-closure, shared-tags, or shared-concepts"],
512
+ ["--note <id>", "Start from this note"],
513
+ ["--scope <path>", "Start from this code path"],
514
+ ["--predicate <predicate>", "Follow only this typed link"],
515
+ DEPTH,
516
+ ["--limit <count>", "Show at most this many results"],
517
+ ["--persisted", "Read the saved graph cache"],
518
+ ROOT,
519
+ INDEX,
520
+ JSON_OPTION
521
+ ],
522
+ examples: ["wordcell graph query --program backlinks --note notes/first --root kb"]
523
+ },
524
+ {
525
+ id: "percolate",
526
+ label: "percolate [note]",
527
+ usage: "wordcell percolate [note] [options]",
528
+ summary: "Suggest recurring concepts and missing links, with evidence. Writes nothing.",
529
+ group: "advanced",
530
+ options: [
531
+ ["--proofs", "Show the evidence for one note"],
532
+ ["--min-support <count>", "Require this many supporting notes"],
533
+ ["--limit <count>", "Show at most this many suggestions"],
534
+ ROOT,
535
+ JSON_OPTION
536
+ ],
537
+ examples: ["wordcell percolate --root kb"]
538
+ },
539
+ {
540
+ id: "portfolio search",
541
+ label: "portfolio search <query>",
542
+ usage: "wordcell portfolio search <query> --registry <file> --workspace <directory> [options]",
543
+ summary: "Search several knowledge bases you list in a registry file.",
544
+ group: "advanced",
545
+ options: [
546
+ ["--registry <file>", "Registry of knowledge bases (required)"],
547
+ ["--workspace <directory>", "Folder that holds their checkouts (required)"],
548
+ ["--shared", "Search every shared entry"],
549
+ ["--vault <owner/id>", "Search this entry (repeatable)"],
550
+ MODE,
551
+ RULES,
552
+ PRIORITY,
553
+ ["--limit <count>", "Show at most this many results"],
554
+ ["--require-all", "Fail when any selected knowledge base is missing"],
555
+ JSON_OPTION
556
+ ],
557
+ examples: ['wordcell portfolio search "retries" --registry kb-portfolio.json --workspace .. --shared']
558
+ },
559
+ {
560
+ id: "portfolio audit",
561
+ label: "portfolio audit",
562
+ usage: "wordcell portfolio audit --registry <file> --workspace <directory> [options]",
563
+ summary: "Check several knowledge bases for broken links, duplicates, and missing files.",
564
+ group: "advanced",
565
+ options: [
566
+ ["--registry <file>", "Registry of knowledge bases (required)"],
567
+ ["--workspace <directory>", "Folder that holds their checkouts (required)"],
568
+ ["--all", "Audit every entry"],
569
+ ["--shared", "Audit every shared entry"],
570
+ ["--vault <owner/id>", "Audit this entry (repeatable)"],
571
+ ["--strict", "Fail on warnings"],
572
+ JSON_OPTION
573
+ ],
574
+ examples: ["wordcell portfolio audit --registry kb-portfolio.json --workspace .. --all"]
575
+ },
576
+ {
577
+ id: "evaluate",
578
+ label: "evaluate <manifest.json>",
579
+ usage: "wordcell evaluate <manifest.json> [options]",
580
+ summary: "Measure how well each search method finds the right notes in a frozen test set.",
581
+ group: "advanced",
582
+ options: [
583
+ ROOT,
584
+ REPO,
585
+ DATABASE,
586
+ ["--retriever <id>", "Run only this search method (repeatable)"],
587
+ ["--split <development|test|all>", "Which questions to run"],
588
+ ["--limit <count>", "Results to keep per question"],
589
+ ["--cutoff <count>", "Rank cutoff for the scores"],
590
+ ["--timeout <milliseconds>", "Time limit per question"],
591
+ ["--baseline <id>", "Compare every method with this one"],
592
+ ["--model-file <path>", "Record the embedding model file used"],
593
+ ["--cache-state <cold|mixed|warm>", "Record how warm the caches were"],
594
+ JSON_OPTION
595
+ ],
596
+ examples: ["wordcell evaluate eval/manifest.json --root kb --repo ."]
597
+ },
598
+ {
599
+ id: "url-metadata tool",
600
+ label: "url-metadata tool build|check",
601
+ usage: "wordcell url-metadata tool <build|check>",
602
+ summary: "Build or check the helper that looks up metadata for saved links. Needs Rust.",
603
+ group: "advanced",
604
+ options: [],
605
+ examples: ["wordcell url-metadata tool build"]
606
+ },
607
+ {
608
+ id: "url-metadata backfill",
609
+ label: "url-metadata backfill",
610
+ usage: "wordcell url-metadata backfill [options]",
611
+ summary: "Add title and archive metadata files next to saved links.",
612
+ group: "advanced",
613
+ options: [],
614
+ examples: ["wordcell url-metadata backfill --root kb"],
615
+ notes: ["Run `wordcell url-metadata --help` for every option."]
616
+ },
617
+ {
618
+ id: "update",
619
+ label: "update [check|status|enable|disable]",
620
+ usage: "wordcell update [check|status|enable|disable] [--json]",
621
+ summary: "Update this global installation or change automatic update settings.",
622
+ group: "advanced",
623
+ options: [JSON_OPTION, ["--check", "Check the latest release without installing"]],
624
+ examples: ["wordcell update status", "wordcell update disable"],
625
+ notes: [
626
+ "Supported global installs on macOS and Linux update daily before work.",
627
+ "Set HRANESS_NO_UPDATE=1 to skip automatic checks for one invocation.",
628
+ "Active commands prevent replacement. SDK imports never check for updates."
629
+ ]
630
+ },
631
+ {
632
+ id: "support",
633
+ label: "support",
634
+ usage: "wordcell support [status | enable | dismiss | snooze] [--json]",
635
+ summary: "Optional support settings. No command signs you up or charges you.",
636
+ group: "advanced",
637
+ notes: ["Set HRANESS_SUPPORT=off to turn off support invitations."],
638
+ options: [JSON_OPTION],
639
+ examples: ["wordcell support status"]
640
+ }
641
+ ];
642
+ var COMMAND_ALIASES = {
643
+ notes: "list",
644
+ "source-inbox": "inbox"
645
+ };
646
+ var byId = new Map(commandHelp.map((entry) => [entry.id, entry]));
647
+ var GROUP_TITLES = [
648
+ ["start", "Start here"],
649
+ ["notes", "Notes and links"],
650
+ ["search", "Search"],
651
+ ["capture", "Capture"],
652
+ ["publish", "Publish and serve"],
653
+ ["agents", "Agents"],
654
+ ["diagnostics", "Diagnostics"]
655
+ ];
656
+ var DESCRIPTION = [
657
+ "Wordcell keeps decisions, plans, and sources as Markdown beside your code,",
658
+ "so coding agents can find them from the file they are about to change."
659
+ ];
660
+ var LABEL_WIDTH = 28;
661
+ var MAX_COLUMNS = 80;
662
+ function wrapWords(text, width) {
663
+ const lines = [];
664
+ let current = "";
665
+ for (const word of text.split(" ")) {
666
+ if (current !== "" && current.length + 1 + word.length > width) {
667
+ lines.push(current);
668
+ current = word;
669
+ } else {
670
+ current = current === "" ? word : `${current} ${word}`;
671
+ }
672
+ }
673
+ if (current !== "")
674
+ lines.push(current);
675
+ return lines;
676
+ }
677
+ function row(label, summary, indent = " ", width = LABEL_WIDTH) {
678
+ const column = indent.length + width;
679
+ const padded = `${indent}${label}`;
680
+ const summaryLines = wrapWords(summary, Math.max(20, MAX_COLUMNS - column));
681
+ const continuation = summaryLines.slice(1).map((line) => `${" ".repeat(column)}${line}`);
682
+ if (label === "")
683
+ return [`${" ".repeat(column)}${summaryLines[0] ?? ""}`, ...continuation].join(`
684
+ `);
685
+ const head = padded.length < column ? [`${padded.padEnd(column)}${summaryLines[0] ?? ""}`] : [padded, `${" ".repeat(column)}${summaryLines[0] ?? ""}`];
686
+ return [...head, ...continuation].join(`
687
+ `);
688
+ }
689
+ function firstSentence(summary) {
690
+ const end = summary.search(/\.(\s|$)/u);
691
+ return end === -1 ? summary : summary.slice(0, end);
692
+ }
693
+ function listGroup(group) {
694
+ return commandHelp.filter((entry) => entry.group === group && entry.unlisted !== true).map((entry) => row(entry.label, firstSentence(entry.summary)));
695
+ }
696
+ function startHelp(version) {
697
+ const start = (command, summary) => row(command, summary, " ", 40);
698
+ const lines = [
699
+ ...DESCRIPTION,
700
+ "",
701
+ "Start here (no account or model needed)",
702
+ start("wordcell init kb", "Create a knowledge base in ./kb"),
703
+ start('wordcell note create notes/first --title "First note" --root kb', "Write your first note"),
704
+ start('wordcell search "first" --root kb', "Search your notes"),
705
+ start("wordcell check --root kb", "Check links and metadata"),
706
+ "",
707
+ "Everyday",
708
+ start("wordcell clip <url> --output kb/articles", "Save a web page as Markdown"),
709
+ start("wordcell context <path> --root kb", "Find notes about a code path"),
710
+ start("wordcell index --root kb", "Turn on meaning-based search"),
711
+ "",
712
+ "All commands: wordcell --help \xB7 Command help: wordcell help <command>"
713
+ ];
714
+ if (version !== undefined)
715
+ lines.push(`wordcell ${version}`);
716
+ return `${lines.join(`
717
+ `)}
718
+ `;
719
+ }
720
+ function rootHelp() {
721
+ const lines = ["Usage: wordcell <command> [options]", "", ...DESCRIPTION];
722
+ for (const [group, title] of GROUP_TITLES) {
723
+ lines.push("", title, ...listGroup(group));
724
+ }
725
+ lines.push("", "Options", row("-h, --help", "Show help. Also: wordcell help <command>", " ", 22), row("-V, --version", "Print the version", " ", 22), row("--root <directory>", "Knowledge base folder (default: current directory)", " ", 22), row("--json", "Print machine-readable output", " ", 22), "", "More commands: wordcell help advanced \xB7 Docs: https://wordcell.io/docs", "Optional support: wordcell support \xB7 Turn off: HRANESS_SUPPORT=off");
726
+ return `${lines.join(`
727
+ `)}
728
+ `;
729
+ }
730
+ function advancedHelp() {
731
+ const lines = [
732
+ "Usage: wordcell <command> [options]",
733
+ "",
734
+ "Advanced commands for maintainers, evaluation, and several knowledge bases.",
735
+ "",
736
+ ...listGroup("advanced"),
737
+ "",
738
+ "Command help: wordcell help <command> \xB7 Everyday commands: wordcell --help"
739
+ ];
740
+ return `${lines.join(`
741
+ `)}
742
+ `;
743
+ }
744
+ function commandHelpText(id) {
745
+ const entry = byId.get(id);
746
+ if (entry === undefined)
747
+ return;
748
+ const lines = [`Usage: ${entry.usage}`, "", ...wrapWords(entry.summary, MAX_COLUMNS)];
749
+ if (entry.notes !== undefined)
750
+ lines.push(...entry.notes);
751
+ const family = commandHelp.filter((candidate) => candidate.id.startsWith(`${entry.id} `));
752
+ if (family.length > 0) {
753
+ lines.push("", "Commands", ...family.map((candidate) => row(`${candidate.label}`, firstSentence(candidate.summary))));
754
+ }
755
+ if (entry.options.length > 0) {
756
+ const width = Math.min(30, Math.max(...entry.options.map(([spelling]) => spelling.length)) + 2);
757
+ lines.push("", "Options", ...entry.options.map(([spelling, description]) => row(spelling, description, " ", width)));
758
+ }
759
+ if (entry.examples.length > 0) {
760
+ lines.push("", entry.examples.length === 1 ? "Example" : "Examples", ...entry.examples.map((example) => ` ${example}`));
761
+ }
762
+ return `${lines.join(`
763
+ `)}
764
+ `;
765
+ }
766
+ function canonicalFirstWord(word) {
767
+ return COMMAND_ALIASES[word] ?? word;
768
+ }
769
+ function resolveCommandId(words) {
770
+ const first = words[0];
771
+ if (first === undefined)
772
+ return;
773
+ const head = canonicalFirstWord(first);
774
+ const second = words[1];
775
+ if (second !== undefined && byId.has(`${head} ${second}`))
776
+ return `${head} ${second}`;
777
+ if (byId.has(head))
778
+ return head;
779
+ if (head === "note")
780
+ return "note create";
781
+ if (head === "import")
782
+ return "import supermemory";
783
+ if (head === "portfolio")
784
+ return "portfolio search";
785
+ if (head === "url-metadata")
786
+ return "url-metadata backfill";
787
+ return;
788
+ }
789
+ function commandWordCount(id) {
790
+ return id.split(" ").length;
791
+ }
792
+ function knownCommandWords() {
793
+ const words = new Set;
794
+ for (const entry of commandHelp)
795
+ words.add(entry.id.split(" ")[0] ?? entry.id);
796
+ for (const alias of Object.keys(COMMAND_ALIASES))
797
+ words.add(alias);
798
+ for (const word of ["help", "version", "note", "import", "portfolio", "url-metadata"])
799
+ words.add(word);
800
+ return [...words].toSorted();
801
+ }
802
+ function valueOptions(id) {
803
+ const entry = byId.get(id);
804
+ const names = new Set;
805
+ for (const [spelling] of entry?.options ?? []) {
806
+ if (spelling.includes("<"))
807
+ names.add(spelling.split(" ")[0] ?? spelling);
808
+ }
809
+ return names;
810
+ }
811
+ function optionNames(id) {
812
+ const entry = byId.get(id);
813
+ return (entry?.options ?? []).map(([spelling]) => spelling.split(" ")[0] ?? spelling);
814
+ }
815
+ function editDistance(left, right) {
816
+ const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
817
+ for (let row_ = 1;row_ <= left.length; row_ += 1) {
818
+ let diagonal = previous[0] ?? 0;
819
+ previous[0] = row_;
820
+ for (let column = 1;column <= right.length; column += 1) {
821
+ const above = previous[column] ?? 0;
822
+ const cost = left[row_ - 1] === right[column - 1] ? 0 : 1;
823
+ previous[column] = Math.min(above + 1, (previous[column - 1] ?? 0) + 1, diagonal + cost);
824
+ diagonal = above;
825
+ }
826
+ }
827
+ return previous[right.length] ?? Number.MAX_SAFE_INTEGER;
828
+ }
829
+ function closestMatch(input, candidates) {
830
+ const letters = input.replace(/^-+/u, "").length;
831
+ let best;
832
+ let bestDistance = Math.max(1, Math.floor(letters / 3)) + 1;
833
+ for (const candidate of candidates) {
834
+ const distance = editDistance(input, candidate);
835
+ if (distance < bestDistance) {
836
+ best = candidate;
837
+ bestDistance = distance;
838
+ }
839
+ }
840
+ return best;
841
+ }
842
+
843
+ // src/cli-startup.ts
844
+ function isHelpFlag(argument) {
845
+ return argument === "--help" || argument === "-h";
846
+ }
847
+ function delegatedHelp(first) {
848
+ if (first === "clip" || first === "inspect")
849
+ return { kind: "clip", arguments: ["help"] };
850
+ if (first === "pdf")
851
+ return { kind: "pdf", arguments: ["--help"] };
852
+ if (first === "url-metadata")
853
+ return { kind: "url-metadata", arguments: ["--help"] };
854
+ return;
855
+ }
856
+ function parseHelpTopic(words) {
857
+ const topic = words.filter((word) => !isHelpFlag(word) && word !== "--json");
858
+ if (topic.length === 0)
859
+ return { ok: true, value: { kind: "help" } };
860
+ if (topic.length === 1 && topic[0] === "advanced")
861
+ return { ok: true, value: { kind: "help", topic: "advanced" } };
862
+ const delegated = delegatedHelp(topic[0] ?? "");
863
+ if (delegated !== undefined)
864
+ return { ok: true, value: delegated };
865
+ const id = resolveCommandId(topic);
866
+ if (id === undefined)
867
+ return { ok: false, message: "unknown help topic" };
868
+ return { ok: true, value: { kind: "help", topic: id } };
869
+ }
870
+ function embeddedHelp(arguments_) {
871
+ const separator = arguments_.indexOf("--");
872
+ const end = separator === -1 ? arguments_.length : separator;
873
+ const index = arguments_.slice(0, end).findIndex(isHelpFlag);
874
+ if (index <= 0)
875
+ return;
876
+ const delegated = delegatedHelp(arguments_[0] ?? "");
877
+ if (delegated !== undefined) {
878
+ return index === 1 || index === end - 1 ? { ok: true, value: delegated } : undefined;
879
+ }
880
+ const id = resolveCommandId(arguments_.slice(0, index).filter((word) => !word.startsWith("-")));
881
+ if (id === undefined)
882
+ return;
883
+ const words = commandWordCount(id);
884
+ const previous = arguments_[index - 1] ?? "";
885
+ const flag = arguments_[index];
886
+ const lastArgument = index === end - 1 && (flag === "--help" || !valueOptions(id).has(previous));
887
+ if (index !== words && !lastArgument)
888
+ return;
889
+ return { ok: true, value: { kind: "help", topic: id } };
890
+ }
891
+ function parseCliStartupCommand(arguments_) {
892
+ const command = arguments_[0];
893
+ if (command === undefined)
894
+ return { ok: true, value: { kind: "help", topic: "start" } };
895
+ if (command === "help" || isHelpFlag(command))
896
+ return parseHelpTopic(arguments_.slice(1));
897
+ if (command === "--version" || command === "-V" || command === "-v" || command === "version") {
898
+ return { ok: true, value: { kind: "version", json: arguments_.includes("--json") } };
899
+ }
900
+ const help = embeddedHelp(arguments_);
901
+ if (help !== undefined)
902
+ return help;
903
+ if ((command === "clip" || command === "capture" || command === "inspect") && ["--help", "-h", "help"].includes(arguments_[1] ?? "")) {
904
+ return { ok: true, value: { kind: "clip", arguments: ["help"] } };
905
+ }
906
+ return;
907
+ }
908
+
909
+ export { startHelp, rootHelp, advancedHelp, commandHelpText, resolveCommandId, knownCommandWords, optionNames, closestMatch, parseCliStartupCommand };