@hraness/kb 0.18.1 → 0.19.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 (38) hide show
  1. package/README.md +79 -21
  2. package/dist/authoring.js +2 -2
  3. package/dist/benchmark.js +3 -3
  4. package/dist/cli.js +16 -12
  5. package/dist/evaluation-builder.js +5 -5
  6. package/dist/evaluation-kb.js +5 -5
  7. package/dist/graph.js +3 -1
  8. package/dist/{index-zxdy5pby.js → index-5m2ydj5q.js} +2 -2
  9. package/dist/{index-cxfrakt7.js → index-ekpwvbra.js} +5 -2
  10. package/dist/{index-jsmvyyvf.js → index-ey46z1zf.js} +4 -4
  11. package/dist/{index-cv6fh7z5.js → index-gm9t95d9.js} +1 -1
  12. package/dist/{index-01jj6rbv.js → index-gxr0fctd.js} +3 -3
  13. package/dist/index-nd6nynv2.js +1162 -0
  14. package/dist/{index-s2gw5aw9.js → index-qwgsmtsz.js} +1 -1
  15. package/dist/{index-zzhgcwyt.js → index-vxmf14m1.js} +3 -3
  16. package/dist/{index-n5dd7r0v.js → index-xw9ac71d.js} +2 -2
  17. package/dist/{index-1vrd1rmn.js → index-ykvvkd77.js} +1 -1
  18. package/dist/index.js +30 -8
  19. package/dist/percolate.js +22 -2
  20. package/dist/portfolio.js +5 -5
  21. package/dist/sdk.js +4 -4
  22. package/dist/search.js +2 -2
  23. package/dist/semantic.js +3 -3
  24. package/dist/workflows/decision-context.js +5 -5
  25. package/dist/workflows/index.js +5 -5
  26. package/package.json +1 -1
  27. package/skills/kb/AGENTS.md +3 -0
  28. package/skills/kb/SKILL.md +39 -31
  29. package/skills/kb/agents/openai.yaml +2 -2
  30. package/skills/kb/references/companion-skills.md +96 -0
  31. package/skills/kb/references/customize.md +123 -0
  32. package/skills/kb/references/percolate.md +39 -7
  33. package/skills/kb/templates/companion-skill.template.md +57 -0
  34. package/src/authoring.ts +5 -3
  35. package/src/cli.ts +12 -7
  36. package/src/graph.ts +8 -1
  37. package/src/percolate.ts +1088 -17
  38. package/dist/index-dyqwejk5.js +0 -531
package/README.md CHANGED
@@ -14,7 +14,7 @@ system.
14
14
  Bun 1.3.14 or newer is required.
15
15
 
16
16
  ```sh
17
- bun add --global @hraness/kb@0.18.1
17
+ bun add --global @hraness/kb@0.19.0
18
18
  kb --help
19
19
  ```
20
20
 
@@ -188,6 +188,14 @@ Retrieval is bounded. The high-level `kb search` and `KnowledgeBaseSession.searc
188
188
 
189
189
  Each note owns its outbound typed relationships in frontmatter. KB derives backlinks, inverse edges, and bounded traversal at read time, so parallel agents do not contend on one generated fact file. `kb percolate <note>` reports recurring concepts and missing-link candidates with inspectable support but writes nothing. An agent reads the cited notes before creating a reusable concept or relationship. Semantic similarity never creates an edge automatically.
190
190
 
191
+ Percolation Result V2 presents a missing relationship as an unordered pair of
192
+ notes with a required predicate. It does not choose the source, direction, or a
193
+ `related-to` fallback. Recommended authored predicates include `synthesizes`,
194
+ `evidenced-by`, `informed-by`, `supersedes`, and `contradicts`; they are an
195
+ advisory vocabulary, so a vault can use another canonical predicate when its
196
+ prose and evidence define the claim. KB never infers reciprocal, inverse,
197
+ transitive, or similarity-derived relationships.
198
+
191
199
  Git provenance is opt-in. A search without `--history` performs no Git indexing. `--history` requests best-effort provenance, while `--require-history` rejects unavailable history or incomplete provenance for the selected notes. If one commit exceeds the 2,000-path detail limit, KB retains its identity and vault-local note associations, marks its co-change detail incomplete, and continues through later commits. Best-effort search reports that requested lane as partial.
192
200
 
193
201
  Local attachment checks cover Markdown and Obsidian references to images, PDFs, and editable tldraw sources. They reject missing or escaping files while leaving external URLs alone. A source-inbox view separately lists recent captures that have no inbound disposition from maintained knowledge. It is an advisory, not an automatic backlink requirement: a saved source may intentionally remain a leaf.
@@ -204,6 +212,39 @@ The same mixed-cache, single-run test recorded p95 latencies of 44.345 milliseco
204
212
 
205
213
  Search finds candidates. Similarity does not establish that a passage is current, correct, or supported by its sources. The Markdown, cited captures, explicit relationships, and requested Git history supply the material a reader must inspect.
206
214
 
215
+ ### Customize through an approved proposal
216
+
217
+ The Agent Skill routes setup and evolution requests before it prepares a
218
+ runtime. It inspects the proposed location without mutation, interviews the
219
+ user about the memory questions the KB should answer, and presents exact read
220
+ and write targets. Only the approved targets may be scaffolded. A changed path,
221
+ repository, account, integration, or companion skill requires renewed
222
+ approval.
223
+
224
+ The standard router may be enough. A recurring ritual can instead receive a
225
+ companion skill with explicit inputs, authority, durable outputs, idempotence,
226
+ failure behavior, and verification. These skills are inert instructions. They
227
+ do not create a plugin runtime, execute vault metadata, inherit ambient account
228
+ access, or couple application code to the KB. An exact repeat is a no-op;
229
+ divergence, path escape, symbolic links, partial writes, and unapproved
230
+ external surfaces stop the workflow.
231
+
232
+ The repository's fake-capability suite exercises those transitions. It is a
233
+ tested contract example, not proof that every agent or host integration
234
+ complies.
235
+
236
+ This workflow builds on Frank Chen's public notes about [designing a personal
237
+ knowledge base with an
238
+ agent](https://gist.github.com/fxchen/773397095d7a6bffda621e4237da0da9)
239
+ and [extending it with
240
+ skills](https://gist.github.com/fxchen/09cb410b22c9c5256d80243ee925b57e).
241
+
242
+ KB ships no `kb_role` metadata, lifecycle resolver or API, lifecycle CLI,
243
+ compatibility diagnostic, or metadata migration. A frozen Phase 0 value gate
244
+ must show that those surfaces improve deterministic agent decisions before they
245
+ are introduced. Current and historical plan routing remains derived from
246
+ existing type, path, and status conventions.
247
+
207
248
  ### Adopt the smallest useful split
208
249
 
209
250
  Start with a short inherited `AGENTS.md` path for rules whose omission would make an edit wrong. A small knowledge base may need only Markdown, Git, an index page, and ordinary file search. Add source capture when evidence keeps disappearing. Add repository scopes when agents need to recover current memory from code paths. Add metadata or hybrid search when file search stops answering the repository's questions. Add links and graph views only when the relationships themselves help people make decisions.
@@ -219,9 +260,9 @@ Treat the knowledge base as repository-adjacent durable memory. Authored Markdow
219
260
  Copy this prompt into Codex, Claude Code, or another coding agent:
220
261
 
221
262
  ```text
222
- Install the `kb` Agent Skill from `hraness/kb#v0.18.1` with the standard skills
263
+ Install the `kb` Agent Skill from `hraness/kb#v0.19.0` with the standard skills
223
264
  CLI. Use the skill's runtime instructions to install the exact
224
- `@hraness/kb@0.18.1` registry release only when the command is missing. Verify it
265
+ `@hraness/kb@0.19.0` registry release only when the command is missing. Verify it
225
266
  with `kb doctor` and `kb --help`, but do not initialize or modify a vault until
226
267
  I ask.
227
268
  ```
@@ -229,25 +270,25 @@ I ask.
229
270
  Install the single public skill with either runner:
230
271
 
231
272
  ```sh
232
- npx skills add hraness/kb#v0.18.1
233
- bunx skills add hraness/kb#v0.18.1
273
+ npx skills add hraness/kb#v0.19.0
274
+ bunx skills add hraness/kb#v0.19.0
234
275
  ```
235
276
 
236
277
  Both commands discover the same `kb` skill and install it into the selected
237
278
  agent runner. Skill installation is inert: it does not initialize a vault,
238
279
  refresh a catalog, or edit Markdown. When invoked, the skill uses an existing
239
280
  `kb` command or, when the command is missing, checks for Bun and installs the
240
- CLI from the immutable `@hraness/kb@0.18.1` npm version.
281
+ CLI from the immutable `@hraness/kb@0.19.0` npm version.
241
282
 
242
283
  The public skills CLI reads `skills/kb/` from the repository. The immutable
243
- `0.18.1` npm package includes the same tree under
284
+ `0.19.0` npm package includes the same tree under
244
285
  `node_modules/@hraness/kb/skills/kb/`, and the package check verifies that the
245
286
  installed skill is byte-identical to the repository source.
246
287
 
247
288
  Install the two global commands with Bun:
248
289
 
249
290
  ```sh
250
- bun add --global @hraness/kb@0.18.1
291
+ bun add --global @hraness/kb@0.19.0
251
292
  kb --help
252
293
  kb-evaluation-builder --help
253
294
  ```
@@ -255,7 +296,7 @@ kb-evaluation-builder --help
255
296
  The same registry package can be installed with npm:
256
297
 
257
298
  ```sh
258
- npm install --global --ignore-scripts @hraness/kb@0.18.1
299
+ npm install --global --ignore-scripts @hraness/kb@0.19.0
259
300
  kb --help
260
301
  ```
261
302
 
@@ -268,7 +309,7 @@ reviewed and enabled; run `kb doctor` to inspect the resulting capabilities.
268
309
  For programmatic use, add the exact npm version to a Bun project:
269
310
 
270
311
  ```sh
271
- bun add --exact @hraness/kb@0.18.1
312
+ bun add --exact @hraness/kb@0.19.0
272
313
  ```
273
314
 
274
315
  The resulting dependency should remain exact:
@@ -276,12 +317,12 @@ The resulting dependency should remain exact:
276
317
  ```json
277
318
  {
278
319
  "dependencies": {
279
- "@hraness/kb": "0.18.1"
320
+ "@hraness/kb": "0.19.0"
280
321
  }
281
322
  }
282
323
  ```
283
324
 
284
- Version 0.18.1 retains three public GitHub dependencies: `@hraness/oh` at
325
+ Version 0.19.0 retains three public GitHub dependencies: `@hraness/oh` at
285
326
  immutable release `v0.2.0` for closure verification,
286
327
  `@steipete/sweet-cookie` at Hraness release `v0.4.2` for the cookie-scope safety
287
328
  fork, and `@tobilu/qmd` at commit
@@ -467,7 +508,12 @@ Predicates use lower-kebab-case. Local targets use exact vault-root IDs without
467
508
  `.md`; cross-vault targets use canonical stable `kb://` URIs. `kb graph`, `kb backlinks`, `kb relation list`, and `kb links` derive
468
509
  inverse edges and bounded paths without injecting reciprocal or inferred facts into notes.
469
510
  `kb percolate` proposes reusable concepts and missing connections with explicit
470
- support; an agent reviews the cited prose before authoring anything.
511
+ support; an agent reviews the cited prose before authoring anything. In its V2
512
+ result, a missing relationship is an unordered endpoint pair with a required
513
+ predicate, never an executable directed assertion or an automatic
514
+ `related-to`. Common reviewed claims use `synthesizes`, `evidenced-by`,
515
+ `informed-by`, `supersedes`, or `contradicts`; other canonical custom predicates
516
+ remain valid when their meaning is supported.
471
517
 
472
518
  Within a portfolio, a note can target a stable cross-vault identity such as
473
519
  `kb://hraness/sleepyland/sound-wellness-expansion`. The target vault must be
@@ -540,26 +586,38 @@ diffs, and the explicit local job ledger are available from
540
586
  The repository ships one reusable `kb` Agent Skill under `skills/kb/`. Its
541
587
  intent router loads focused references only when a task needs them: querying
542
588
  repository context and agent memory, capturing URLs or PDFs, writing durable
543
- plans, promoting concepts and typed relationships, or refreshing and checking
544
- a vault. The package smoke test keeps future tagged packages byte-identical to
589
+ plans, promoting concepts and typed relationships, refreshing and checking a
590
+ vault, or designing a setup through an interview and approved proposal. An
591
+ approved setup may scaffold a bounded companion skill for a distinct recurring
592
+ ritual. The package smoke test keeps future tagged packages byte-identical to
545
593
  that source tree.
546
594
 
547
595
  ```sh
548
- npx skills add hraness/kb#v0.18.1
596
+ npx skills add hraness/kb#v0.19.0
549
597
  # or
550
- bunx skills add hraness/kb#v0.18.1
598
+ bunx skills add hraness/kb#v0.19.0
551
599
  ```
552
600
 
553
601
  The skill invokes the installed `kb` command without depending on a repository
554
- checkout. Its runtime setup installs the pinned CLI only when the command is
555
- missing, and it never initializes or mutates a vault as an installation side
556
- effect. The repository's phase-orchestration skill remains available to local
557
- repository agents but is marked internal, so public skill discovery omits it.
602
+ checkout. It routes setup and evolution before runtime preparation. For
603
+ execution workflows, runtime setup installs the pinned CLI only when the
604
+ command is missing, and it never initializes or mutates a vault as an
605
+ installation side effect. The repository's phase-orchestration skill remains
606
+ available to local repository agents but is marked internal, so public skill
607
+ discovery omits it.
558
608
 
559
609
  See [Design](docs/design.md), [Portfolio federation](docs/portfolio.md), [Agent workflow](docs/agent-workflow.md), [PDF capture](docs/pdf.md), and [Contributing](CONTRIBUTING.md) for the durable contracts and development gate. hraness/kb is available under the [MIT License](LICENSE).
560
610
 
561
611
  ## Release notes
562
612
 
613
+ ### Upgrade to v0.19.0
614
+
615
+ Version 0.19.0 adds interview-first setup and evolution guidance, a bounded
616
+ filesystem-only companion-skill scaffold contract, and Percolation Result V2.
617
+ V2 requires an explicit predicate and leaves relationship ownership and
618
+ direction to review. The release does not add lifecycle metadata, a resolver,
619
+ a lifecycle CLI, inferred edges, or automatic account and network actions.
620
+
563
621
  ### Upgrade to v0.18.1
564
622
 
565
623
  Version 0.18.1 restructures the public README and hosted projection around one
package/dist/authoring.js CHANGED
@@ -13,9 +13,9 @@ import {
13
13
  normalizeRelationPredicate,
14
14
  noteRevision,
15
15
  removeNoteRelation
16
- } from "./index-01jj6rbv.js";
16
+ } from "./index-gxr0fctd.js";
17
17
  import"./index-3rm7cz6h.js";
18
- import"./index-cxfrakt7.js";
18
+ import"./index-ekpwvbra.js";
19
19
  export {
20
20
  removeNoteRelation,
21
21
  noteRevision,
package/dist/benchmark.js CHANGED
@@ -4,13 +4,13 @@ import {
4
4
  createSyntheticRankFusionFixture,
5
5
  evaluateRanking,
6
6
  evaluateRetrievalBenchmark
7
- } from "./index-s2gw5aw9.js";
8
- import"./index-cv6fh7z5.js";
7
+ } from "./index-qwgsmtsz.js";
8
+ import"./index-gm9t95d9.js";
9
9
  import"./index-d13v9ckt.js";
10
10
  import"./index-48pz4jpc.js";
11
11
  import"./index-06c9ctr6.js";
12
12
  import"./index-5vwpzb5a.js";
13
- import"./index-cxfrakt7.js";
13
+ import"./index-ekpwvbra.js";
14
14
  export {
15
15
  evaluateRetrievalBenchmark,
16
16
  evaluateRanking,
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  loadPortfolioRegistry,
14
14
  openKnowledgePortfolio,
15
15
  snapshotPortfolioRegistry
16
- } from "./index-jsmvyyvf.js";
16
+ } from "./index-ey46z1zf.js";
17
17
  import {
18
18
  diffCaptureBundle
19
19
  } from "./index-j4zgmzjr.js";
@@ -34,11 +34,11 @@ import {
34
34
  MAX_PERCOLATION_NOTES,
35
35
  MAX_SCOPED_PERCOLATION_MENTION_PAIRS,
36
36
  percolateVault
37
- } from "./index-dyqwejk5.js";
37
+ } from "./index-nd6nynv2.js";
38
38
  import {
39
39
  knowledgeBaseEvaluationRetrieverIds,
40
40
  openKnowledgeBaseEvaluation
41
- } from "./index-n5dd7r0v.js";
41
+ } from "./index-xw9ac71d.js";
42
42
  import {
43
43
  DEFAULT_SEARCH_RESULTS,
44
44
  MAX_SEARCH_CANDIDATES,
@@ -46,7 +46,7 @@ import {
46
46
  MAX_SEARCH_RELATED_SEEDS,
47
47
  MAX_SEARCH_RESULTS,
48
48
  openKnowledgeBase
49
- } from "./index-zzhgcwyt.js";
49
+ } from "./index-vxmf14m1.js";
50
50
  import {
51
51
  MAX_SEARCH_RULE_CONFIG_BYTES,
52
52
  parseSearchRules
@@ -59,7 +59,7 @@ import {
59
59
  refreshVault,
60
60
  scanVault,
61
61
  sha256EmbeddingModelFile
62
- } from "./index-zxdy5pby.js";
62
+ } from "./index-5m2ydj5q.js";
63
63
  import"./index-4j3tt0c3.js";
64
64
  import"./index-1gwbassd.js";
65
65
  import {
@@ -79,11 +79,11 @@ import {
79
79
  addNoteRelation,
80
80
  createNote,
81
81
  removeNoteRelation
82
- } from "./index-01jj6rbv.js";
82
+ } from "./index-gxr0fctd.js";
83
83
  import"./index-3rm7cz6h.js";
84
84
  import {
85
85
  validateSearchQuery
86
- } from "./index-cv6fh7z5.js";
86
+ } from "./index-gm9t95d9.js";
87
87
  import {
88
88
  navigateLinks
89
89
  } from "./index-d13v9ckt.js";
@@ -111,7 +111,7 @@ import {
111
111
  lookupNote,
112
112
  parseVaultKey,
113
113
  renderCatalog
114
- } from "./index-cxfrakt7.js";
114
+ } from "./index-ekpwvbra.js";
115
115
  import {
116
116
  main
117
117
  } from "./index-0kavxzqj.js";
@@ -2885,7 +2885,7 @@ function renderPercolation(result, note) {
2885
2885
  if (candidate.kind === "missing-concept") {
2886
2886
  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)}`));
2887
2887
  } else if (candidate.kind === "missing-relation") {
2888
- lines.push(` relation ${safe(candidate.source)} ${safe(candidate.suggestedPredicate)} ${safe(candidate.target)} (${candidate.support} shared signals)`);
2888
+ lines.push(` relation pair {${safe(candidate.source)}, ${safe(candidate.target)}} (predicate required; ${candidate.support} shared signals)`);
2889
2889
  } else if (candidate.kind === "unlinked-mention") {
2890
2890
  lines.push(` mention ${safe(candidate.source)} \u2192 ${safe(candidate.target)} (${candidate.support})`);
2891
2891
  } else {
@@ -2927,12 +2927,16 @@ async function runPercolate(command, output, dependencies) {
2927
2927
  minSupport: command.minSupport,
2928
2928
  limit: command.limit
2929
2929
  });
2930
- output.stdout(command.json ? terminalSafeJson({
2930
+ const jsonOutput = {
2931
2931
  root: snapshot.root,
2932
2932
  note: command.note ?? null,
2933
2933
  minSupport: command.minSupport,
2934
- ...result
2935
- }) : sanitizeTerminalText(renderPercolation(result, command.note)));
2934
+ limit: command.limit,
2935
+ schemaVersion: result.schemaVersion,
2936
+ candidates: result.candidates,
2937
+ truncated: result.truncated
2938
+ };
2939
+ output.stdout(command.json ? terminalSafeJson(jsonOutput) : sanitizeTerminalText(renderPercolation(result, command.note)));
2936
2940
  return 0;
2937
2941
  }
2938
2942
  async function runList(command, output, dependencies) {
@@ -4,15 +4,15 @@ import {
4
4
  knowledgeBaseEvaluationRetrieverIds,
5
5
  openKnowledgeBaseEvaluation,
6
6
  verifyFrozenEvaluationSnapshot
7
- } from "./index-n5dd7r0v.js";
8
- import"./index-zzhgcwyt.js";
7
+ } from "./index-xw9ac71d.js";
8
+ import"./index-vxmf14m1.js";
9
9
  import"./index-adx6khj5.js";
10
10
  import {
11
11
  indexSemanticVault,
12
12
  recommendedEmbeddingModel,
13
13
  recommendedEmbeddingModelSha256,
14
14
  scanVault
15
- } from "./index-zxdy5pby.js";
15
+ } from "./index-5m2ydj5q.js";
16
16
  import"./index-4j3tt0c3.js";
17
17
  import {
18
18
  runGitCommand
@@ -22,12 +22,12 @@ import {
22
22
  MAX_EVALUATION_EVIDENCE_BYTES,
23
23
  MAX_EVALUATION_RESULTS_PER_QUERY
24
24
  } from "./index-b88v3vtm.js";
25
- import"./index-cv6fh7z5.js";
25
+ import"./index-gm9t95d9.js";
26
26
  import"./index-d13v9ckt.js";
27
27
  import"./index-48pz4jpc.js";
28
28
  import"./index-06c9ctr6.js";
29
29
  import"./index-5vwpzb5a.js";
30
- import"./index-cxfrakt7.js";
30
+ import"./index-ekpwvbra.js";
31
31
  import"./index-1xxnjn0d.js";
32
32
 
33
33
  // src/evaluation-builder.ts
@@ -4,19 +4,19 @@ import {
4
4
  knowledgeBaseEvaluationRetrieverIds,
5
5
  openKnowledgeBaseEvaluation,
6
6
  verifyFrozenEvaluationSnapshot
7
- } from "./index-n5dd7r0v.js";
8
- import"./index-zzhgcwyt.js";
7
+ } from "./index-xw9ac71d.js";
8
+ import"./index-vxmf14m1.js";
9
9
  import"./index-adx6khj5.js";
10
- import"./index-zxdy5pby.js";
10
+ import"./index-5m2ydj5q.js";
11
11
  import"./index-4j3tt0c3.js";
12
12
  import"./index-1gwbassd.js";
13
13
  import"./index-b88v3vtm.js";
14
- import"./index-cv6fh7z5.js";
14
+ import"./index-gm9t95d9.js";
15
15
  import"./index-d13v9ckt.js";
16
16
  import"./index-48pz4jpc.js";
17
17
  import"./index-06c9ctr6.js";
18
18
  import"./index-5vwpzb5a.js";
19
- import"./index-cxfrakt7.js";
19
+ import"./index-ekpwvbra.js";
20
20
  import"./index-1xxnjn0d.js";
21
21
  export {
22
22
  verifyFrozenEvaluationSnapshot,
package/dist/graph.js CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  catalogEnd,
10
10
  catalogStart,
11
11
  isCanonicalNoteId,
12
+ isCanonicalRelationPredicate,
12
13
  lookupNote,
13
14
  metadataValueFromUnknown,
14
15
  normalizeVaultPath,
@@ -17,7 +18,7 @@ import {
17
18
  replaceCatalog,
18
19
  searchableMarkdown,
19
20
  wikiLinks
20
- } from "./index-cxfrakt7.js";
21
+ } from "./index-ekpwvbra.js";
21
22
  export {
22
23
  wikiLinks,
23
24
  searchableMarkdown,
@@ -27,6 +28,7 @@ export {
27
28
  normalizeVaultPath,
28
29
  metadataValueFromUnknown,
29
30
  lookupNote,
31
+ isCanonicalRelationPredicate,
30
32
  isCanonicalNoteId,
31
33
  catalogStart,
32
34
  catalogEnd,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  fuseRankedCandidates,
4
4
  validateSearchQuery
5
- } from "./index-cv6fh7z5.js";
5
+ } from "./index-gm9t95d9.js";
6
6
  import {
7
7
  MAX_ANALYZED_NOTES,
8
8
  analyzeVault,
@@ -12,7 +12,7 @@ import {
12
12
  parseNote,
13
13
  renderCatalog,
14
14
  replaceCatalog
15
- } from "./index-cxfrakt7.js";
15
+ } from "./index-ekpwvbra.js";
16
16
 
17
17
  // src/semantic.ts
18
18
  import { createHash as createHash2 } from "crypto";
@@ -207,6 +207,9 @@ function emptyMetadata() {
207
207
  }
208
208
  var relationPredicatePattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
209
209
  var maxNoteIdLength = 2048;
210
+ function isCanonicalRelationPredicate(value) {
211
+ return value !== "" && value === value.normalize("NFC") && relationPredicatePattern.test(value);
212
+ }
210
213
  function isCanonicalNoteId(value) {
211
214
  if (value === "" || value.length > maxNoteIdLength || value !== value.trim() || value !== value.normalize("NFC") || value.includes("\\") || value.includes("\x00") || value.includes(`
212
215
  `) || value.includes("\r") || value.startsWith("/") || value.endsWith("/") || value.toLocaleLowerCase("en-US").endsWith(".md")) {
@@ -275,7 +278,7 @@ function parsedRelations(contents, source, lineCounter) {
275
278
  continue;
276
279
  }
277
280
  const predicate = pair.key.value.normalize("NFC");
278
- if (!relationPredicatePattern.test(predicate)) {
281
+ if (!isCanonicalRelationPredicate(predicate)) {
279
282
  relationIssues.push(malformedRelation(source, predicateLine, `Invalid relation predicate "${predicate}"; use strict lower kebab-case.`, { predicate }));
280
283
  continue;
281
284
  }
@@ -1064,4 +1067,4 @@ function replaceCatalog(indexContent, catalog) {
1064
1067
  return indexContent.slice(0, start) + catalog + indexContent.slice(end + catalogEnd.length);
1065
1068
  }
1066
1069
 
1067
- export { MAX_PORTFOLIO_NAME_BYTES, MAX_DOCUMENT_ID_BYTES, portfolioVaultIdentity, parseVaultKey, parseDocumentId, documentIdState, formatQualifiedDocumentUri, parseQualifiedDocumentUri, portfolioDocumentIdentity, catalogStart, catalogEnd, MAX_ANALYZED_NOTES, MAX_CONNECTION_OBSERVATIONS, MAX_MENTION_PAIRS, MAX_MENTIONS, VaultAnalysisBudgetError, metadataValueFromUnknown, isCanonicalNoteId, normalizeVaultPath, searchableMarkdown, wikiLinks, parseNote, lookupNote, analyzeVault, renderCatalog, replaceCatalog };
1070
+ export { MAX_PORTFOLIO_NAME_BYTES, MAX_DOCUMENT_ID_BYTES, portfolioVaultIdentity, parseVaultKey, parseDocumentId, documentIdState, formatQualifiedDocumentUri, parseQualifiedDocumentUri, portfolioDocumentIdentity, catalogStart, catalogEnd, MAX_ANALYZED_NOTES, MAX_CONNECTION_OBSERVATIONS, MAX_MENTION_PAIRS, MAX_MENTIONS, VaultAnalysisBudgetError, metadataValueFromUnknown, isCanonicalRelationPredicate, isCanonicalNoteId, normalizeVaultPath, searchableMarkdown, wikiLinks, parseNote, lookupNote, analyzeVault, renderCatalog, replaceCatalog };
@@ -5,14 +5,14 @@ import {
5
5
  MAX_SEARCH_RESULTS,
6
6
  openKnowledgeBase,
7
7
  validateKnowledgeBaseSearchHistory
8
- } from "./index-zzhgcwyt.js";
8
+ } from "./index-vxmf14m1.js";
9
9
  import {
10
10
  expandSearchRequest,
11
11
  parseSearchRules
12
12
  } from "./index-adx6khj5.js";
13
13
  import {
14
14
  scanVault
15
- } from "./index-zxdy5pby.js";
15
+ } from "./index-5m2ydj5q.js";
16
16
  import {
17
17
  indexGitHistory
18
18
  } from "./index-1gwbassd.js";
@@ -22,7 +22,7 @@ import {
22
22
  } from "./index-x3fthpsc.js";
23
23
  import {
24
24
  validateSearchQuery
25
- } from "./index-cv6fh7z5.js";
25
+ } from "./index-gm9t95d9.js";
26
26
  import {
27
27
  validateQueryOptions
28
28
  } from "./index-48pz4jpc.js";
@@ -32,7 +32,7 @@ import {
32
32
  parseVaultKey,
33
33
  portfolioDocumentIdentity,
34
34
  portfolioVaultIdentity
35
- } from "./index-cxfrakt7.js";
35
+ } from "./index-ekpwvbra.js";
36
36
 
37
37
  // src/portfolio.ts
38
38
  import { createHash as createHash2 } from "crypto";
@@ -7,7 +7,7 @@ import {
7
7
  } from "./index-48pz4jpc.js";
8
8
  import {
9
9
  lookupNote
10
- } from "./index-cxfrakt7.js";
10
+ } from "./index-ekpwvbra.js";
11
11
 
12
12
  // src/search.ts
13
13
  var MAX_EXACT_RESULTS = 500;
@@ -4,9 +4,10 @@ import {
4
4
  } from "./index-3rm7cz6h.js";
5
5
  import {
6
6
  isCanonicalNoteId,
7
+ isCanonicalRelationPredicate,
7
8
  parseDocumentId,
8
9
  parseQualifiedDocumentUri
9
- } from "./index-cxfrakt7.js";
10
+ } from "./index-ekpwvbra.js";
10
11
 
11
12
  // src/authoring.ts
12
13
  import { createHash, randomUUID } from "crypto";
@@ -40,7 +41,6 @@ import {
40
41
  } from "yaml";
41
42
  var MAX_NOTE_BYTES = 16 * 1024 * 1024;
42
43
  var NOTE_REVISION_PATTERN = /^sha256:[0-9a-f]{64}$/u;
43
- var PREDICATE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
44
44
  var MAX_PARENT_DIRECTORY_ENTRIES = 1e5;
45
45
  var MAX_RECOVERY_LOCATIONS_PER_NOTE = 8;
46
46
 
@@ -113,7 +113,7 @@ function canonicalRelationTarget(value) {
113
113
  }
114
114
  function normalizeRelationPredicate(value) {
115
115
  const normalized = value.trim().normalize("NFC").toLocaleLowerCase("en-US").replaceAll("_", "-").replace(/\s+/gu, "-").replace(/-{2,}/gu, "-");
116
- if (!PREDICATE_PATTERN.test(normalized)) {
116
+ if (!isCanonicalRelationPredicate(normalized)) {
117
117
  throw new TypeError(`not a valid relation predicate: ${JSON.stringify(value)}`);
118
118
  }
119
119
  return normalized;