@williamthorsen/kb 0.8.0 → 0.8.1
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/README.md +66 -82
- package/bin/kb.js +2 -4
- package/dist/esm/check/check.d.ts +9 -17
- package/dist/esm/check/enumerate.d.ts +12 -15
- package/dist/esm/check/glob-segments.d.ts +1 -1
- package/dist/esm/check/resolve-foreign-stores.d.ts +9 -8
- package/dist/esm/cli/commands/check.d.ts +4 -10
- package/dist/esm/cli/commands/check.js +2 -2
- package/dist/esm/cli/commands/create.d.ts +3 -7
- package/dist/esm/cli/commands/create.js +1 -1
- package/dist/esm/cli/commands/scaffold.d.ts +5 -9
- package/dist/esm/cli/commands/scaffold.js +5 -5
- package/dist/esm/cli/commands/set-default.d.ts +1 -5
- package/dist/esm/cli/commands/set-default.js +1 -1
- package/dist/esm/cli/commands/taxonomy.d.ts +5 -10
- package/dist/esm/cli/commands/taxonomy.js +10 -9
- package/dist/esm/cli/format.d.ts +8 -10
- package/dist/esm/cli/resolve-store.d.ts +8 -8
- package/dist/esm/cli/run.d.ts +4 -6
- package/dist/esm/cli/run.js +1 -1
- package/dist/esm/cli/select-kb-prompt.d.ts +6 -5
- package/dist/esm/cli/select-kb-prompt.js +1 -1
- package/dist/esm/cli/targeting/resolve-changed-paths.d.ts +3 -3
- package/dist/esm/cli/targeting/select-notes.d.ts +2 -2
- package/dist/esm/config/config-schema.d.ts +10 -9
- package/dist/esm/config/kb-loader-error.d.ts +3 -3
- package/dist/esm/config/load-config.d.ts +2 -2
- package/dist/esm/config/load-config.js +1 -1
- package/dist/esm/config/note-scope.d.ts +7 -7
- package/dist/esm/create/create.d.ts +8 -8
- package/dist/esm/discovery/kb-registry-schema.d.ts +0 -2
- package/dist/esm/discovery/load-registry.d.ts +7 -9
- package/dist/esm/discovery/load-registry.js +1 -1
- package/dist/esm/discovery/register-store.d.ts +3 -4
- package/dist/esm/discovery/register-store.js +2 -2
- package/dist/esm/discovery/registry-document.d.ts +2 -2
- package/dist/esm/discovery/set-default-kb.d.ts +5 -5
- package/dist/esm/discovery/set-default-kb.js +3 -3
- package/dist/esm/filesystem/exists.d.ts +4 -4
- package/dist/esm/frontmatter/parse-note.d.ts +3 -3
- package/dist/esm/git/list-git-scope.d.ts +6 -6
- package/dist/esm/git/run-git.d.ts +2 -2
- package/dist/esm/layout/store-layout.d.ts +5 -5
- package/dist/esm/lints/paths.d.ts +1 -1
- package/dist/esm/lints/paths.js +1 -1
- package/dist/esm/lints/tag-alias.d.ts +1 -1
- package/dist/esm/lints/tag-alias.js +1 -1
- package/dist/esm/lints/taxonomy.d.ts +9 -8
- package/dist/esm/lints/taxonomy.js +2 -2
- package/dist/esm/note-io/field-validators.d.ts +1 -1
- package/dist/esm/note-io/read-note.d.ts +2 -2
- package/dist/esm/note-io/write-note.d.ts +3 -6
- package/dist/esm/records/event.d.ts +3 -3
- package/dist/esm/scaffold/render-seeds.d.ts +3 -3
- package/dist/esm/scaffold/render-seeds.js +2 -2
- package/dist/esm/scaffold/scaffold.d.ts +7 -8
- package/dist/esm/tags/load-aliases.d.ts +3 -4
- package/dist/esm/taxonomy/domain-paths.d.ts +6 -6
- package/dist/esm/taxonomy/load-taxonomy.d.ts +3 -3
- package/dist/esm/taxonomy/load-taxonomy.js +2 -2
- package/dist/esm/taxonomy/taxonomy-schema.d.ts +5 -6
- package/dist/esm/taxonomy/write-taxonomy.d.ts +7 -8
- package/dist/esm/type-guards.d.ts +1 -1
- package/dist/esm/types.d.ts +6 -9
- package/dist/esm/vault-integrity/build-vault-index.d.ts +3 -4
- package/dist/esm/vault-integrity/check-vault-integrity.d.ts +13 -13
- package/dist/esm/vault-integrity/check-vault-integrity.js +1 -1
- package/dist/esm/vault-integrity/wikilink-parse.d.ts +21 -16
- package/package.json +5 -5
package/dist/esm/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A knowledge-base root: the directory
|
|
1
|
+
/** A knowledge-base root: the directory containing a `.kb/`, and that `.kb/` itself. */
|
|
2
2
|
export interface KbRoot {
|
|
3
3
|
/** Absolute path to the directory containing the `.kb/` folder. */
|
|
4
4
|
path: string;
|
|
@@ -7,13 +7,11 @@ export interface KbRoot {
|
|
|
7
7
|
}
|
|
8
8
|
/** A single knowledge base declared in a `kb.yaml` registry, normalized in memory. */
|
|
9
9
|
export interface KbRegistryEntry {
|
|
10
|
-
/** The KB's name,
|
|
10
|
+
/** The KB's name, taken from the `kbs` map key. */
|
|
11
11
|
name: string;
|
|
12
12
|
/** Absolute path to the KB's root directory (tilde expanded, relative resolved). */
|
|
13
13
|
path: string;
|
|
14
|
-
/** Optional human-readable description. */
|
|
15
14
|
description?: string;
|
|
16
|
-
/** Whether the KB is read-only. */
|
|
17
15
|
readonly?: boolean;
|
|
18
16
|
/** Which registry the entry came from. */
|
|
19
17
|
source: 'user' | 'project';
|
|
@@ -43,7 +41,7 @@ export interface Frontmatter {
|
|
|
43
41
|
/** Optional and unknown fields, preserved through round-trip in insertion order. */
|
|
44
42
|
extra: Record<string, unknown>;
|
|
45
43
|
}
|
|
46
|
-
/** The raw frontmatter slice plus parse diagnostics, kept so rules can report at source line numbers. */
|
|
44
|
+
/** The raw frontmatter slice plus parse diagnostics, kept so that rules can report at source line numbers. */
|
|
47
45
|
export interface FrontmatterRaw {
|
|
48
46
|
/** The YAML text between the opening and closing `---` fences. */
|
|
49
47
|
text: string;
|
|
@@ -56,7 +54,7 @@ export interface FrontmatterRaw {
|
|
|
56
54
|
}
|
|
57
55
|
/** A note parsed into frontmatter and body. */
|
|
58
56
|
export interface ParsedNote {
|
|
59
|
-
/** Path or label the note was parsed
|
|
57
|
+
/** Path or label from which the note was parsed. */
|
|
60
58
|
path: string;
|
|
61
59
|
/** The full original note content. */
|
|
62
60
|
content: string;
|
|
@@ -69,11 +67,10 @@ export interface ParsedNote {
|
|
|
69
67
|
/** 1-based line where the body begins. */
|
|
70
68
|
bodyStartLine: number;
|
|
71
69
|
}
|
|
72
|
-
/** Severity of a validation finding. */
|
|
73
70
|
export type FindingSeverity = 'error' | 'warning';
|
|
74
71
|
/** A single validation finding produced by a rule. */
|
|
75
72
|
export interface Finding {
|
|
76
|
-
/** Path or label the finding applies
|
|
73
|
+
/** Path or label to which the finding applies: a note, or the store file that declares the rule's subject. */
|
|
77
74
|
path: string;
|
|
78
75
|
/**
|
|
79
76
|
* What the finding describes, defaulting to `note` when absent. A note-scoped finding is dropped when a run's
|
|
@@ -83,7 +80,7 @@ export interface Finding {
|
|
|
83
80
|
scope?: 'note' | 'vault';
|
|
84
81
|
/** 1-based source line number, when known. */
|
|
85
82
|
line?: number;
|
|
86
|
-
/** Rule code, e.g. `
|
|
83
|
+
/** Rule code, e.g. `wikilinks.basename`. */
|
|
87
84
|
rule: string;
|
|
88
85
|
severity: FindingSeverity;
|
|
89
86
|
message: string;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A vault-wide lookup from a note basename (without the `.md` extension) to the set of note paths that share it. A
|
|
3
|
-
* single-path entry resolves a wikilink unambiguously; a multi-path entry is a basename collision.
|
|
4
|
-
* vault-integrity checks and by curate's wikilink rewriter.
|
|
3
|
+
* single-path entry resolves a wikilink unambiguously; a multi-path entry is a basename collision.
|
|
5
4
|
*/
|
|
6
5
|
export type VaultIndex = ReadonlyMap<string, ReadonlySet<string>>;
|
|
7
6
|
/**
|
|
8
7
|
* Builds a basename → set-of-paths index from a set of notes, mapping each note's `.md` basename (sans extension) to
|
|
9
|
-
* the note paths that share it. Reads only each note's `path`, so it is type-blind
|
|
10
|
-
* projection.
|
|
8
|
+
* the note paths that share it. Reads only each note's `path`, so it is type-blind: It needs no frontmatter or record
|
|
9
|
+
* projection. Because a note's `path` is used verbatim as the index value, callers control whether entries are
|
|
11
10
|
* vault-relative or absolute.
|
|
12
11
|
*/
|
|
13
12
|
export declare function buildVaultIndex(notes: readonly {
|
|
@@ -3,19 +3,19 @@ import type { Finding } from '../types.js';
|
|
|
3
3
|
import { type VaultIndex } from './build-vault-index.js';
|
|
4
4
|
/**
|
|
5
5
|
* Checks whole-vault integrity over a type-blind note set: unresolved `[[link]]` targets and basename collisions.
|
|
6
|
-
* Projects no records and reads no frontmatter
|
|
6
|
+
* Projects no records and reads no frontmatter: A note is just its path and body.
|
|
7
7
|
*
|
|
8
8
|
* A `[[Target]]` whose basename resolves to zero notes is an error (`wikilinks.unresolved`), reported at its
|
|
9
9
|
* file-absolute line. A basename shared by two or more notes is a single vault-wide warning (`wikilinks.basename`),
|
|
10
10
|
* reported once per basename independent of whether any link references it. An ambiguous link (a basename that several
|
|
11
|
-
* notes share) is not flagged per-link
|
|
11
|
+
* notes share) is not flagged per-link: The vault-wide basename warning subsumes it.
|
|
12
12
|
*
|
|
13
|
-
* A `[[store:Target]]` resolves against `options.foreignStores` instead, and never
|
|
14
|
-
* index, so the basename warning stays store-scoped. Without `options`, a qualified target is treated as a
|
|
15
|
-
*
|
|
13
|
+
* A `[[store:Target]]` resolves against `options.foreignStores` instead, and is never added to this store's own
|
|
14
|
+
* basename index, so the basename warning stays store-scoped. Without `options`, a qualified target is treated as a
|
|
15
|
+
* bare one.
|
|
16
16
|
*/
|
|
17
17
|
export declare function checkVaultIntegrity(notes: readonly VaultIntegrityNote[], options?: VaultIntegrityOptions): Finding[];
|
|
18
|
-
/** What a check run found when it looked up a store one of its links
|
|
18
|
+
/** What a check run found when it looked up a store named by one of its links. */
|
|
19
19
|
export type ForeignStore =
|
|
20
20
|
/** The name matches no entry in the merged registry. */
|
|
21
21
|
{
|
|
@@ -26,29 +26,29 @@ export type ForeignStore =
|
|
|
26
26
|
status: 'unavailable';
|
|
27
27
|
reason: string;
|
|
28
28
|
}
|
|
29
|
-
/**
|
|
29
|
+
/** Because the store is less shareable than the source, a link into it would widen disclosure. */
|
|
30
30
|
| {
|
|
31
31
|
status: 'disallowed';
|
|
32
32
|
visibility: StoreVisibility;
|
|
33
33
|
}
|
|
34
|
-
/** The store was read; `index`
|
|
34
|
+
/** The store was read; `index` contains its basenames. */
|
|
35
35
|
| {
|
|
36
36
|
status: 'resolved';
|
|
37
37
|
index: VaultIndex;
|
|
38
38
|
};
|
|
39
|
-
/** A note reduced to what vault integrity inspects
|
|
39
|
+
/** A note reduced to what vault integrity inspects. */
|
|
40
40
|
export interface VaultIntegrityNote {
|
|
41
|
-
/** Path or label the note was read
|
|
41
|
+
/** Path or label from which the note was read; used as the index value and the finding path. */
|
|
42
42
|
path: string;
|
|
43
43
|
/** The note body (everything after the frontmatter block). */
|
|
44
44
|
body: string;
|
|
45
|
-
/** 1-based file line where the body begins, so link findings report file-absolute lines. */
|
|
45
|
+
/** 1-based file line where the body begins, so that link findings report file-absolute lines. */
|
|
46
46
|
bodyStartLine: number;
|
|
47
47
|
}
|
|
48
48
|
/** What a run needs to evaluate a store-qualified link. */
|
|
49
49
|
export interface VaultIntegrityOptions {
|
|
50
|
-
/** What the run found for each store name its links
|
|
50
|
+
/** What the run found for each store name that qualifies one of its links, keyed by that name. */
|
|
51
51
|
foreignStores: ReadonlyMap<string, ForeignStore>;
|
|
52
|
-
/** The visibility of the store being checked, which decides the direction a qualified link may take. */
|
|
52
|
+
/** The visibility of the store being checked, which decides the direction that a qualified link may take. */
|
|
53
53
|
sourceVisibility: StoreVisibility;
|
|
54
54
|
}
|
|
@@ -43,7 +43,7 @@ function describeForeignDefect(store, target, options) {
|
|
|
43
43
|
return {
|
|
44
44
|
rule: 'wikilinks.disallowed-store',
|
|
45
45
|
severity: 'error',
|
|
46
|
-
message: `${link} targets "${store}", a ${foreignStore.visibility} store, which a ${options.sourceVisibility} store may not link into:
|
|
46
|
+
message: `${link} targets "${store}", a ${foreignStore.visibility} store, which a ${options.sourceVisibility} store may not link into: The link discloses the target's title`,
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
const resolved = foreignStore.index.get(lookupKey(target));
|
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
/** Counts the newlines in `text` before
|
|
1
|
+
/** Counts the newlines in `text` before string index `upTo`, used to locate a match's source line. */
|
|
2
2
|
export declare function countNewlines(text: string, upTo: number): number;
|
|
3
3
|
/**
|
|
4
4
|
* Strips `|alias` and `#anchor` from a wikilink inner string and returns the target. Returns `null` for intra-doc
|
|
5
|
-
* links like `[[#heading]]`, which
|
|
5
|
+
* links like `[[#heading]]`, which have no target.
|
|
6
6
|
*/
|
|
7
7
|
export declare function extractTarget(inner: string): string | null;
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Reduces a wikilink target to the basename key on which the vault index is keyed (drops any directory prefix and
|
|
10
|
+
* `.md`).
|
|
11
|
+
*/
|
|
9
12
|
export declare function lookupKey(target: string): string;
|
|
10
|
-
/** A wikilink target separated into the store it names,
|
|
13
|
+
/** A wikilink target separated into the store that it names, when it names one, and the target within that store. */
|
|
11
14
|
export interface QualifiedTarget {
|
|
12
|
-
/** The store the link
|
|
15
|
+
/** The store named by the link, or `undefined` when the target is store-local. */
|
|
13
16
|
store?: string;
|
|
14
17
|
/** The target with any store qualifier removed. */
|
|
15
18
|
target: string;
|
|
16
19
|
}
|
|
17
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* One wikilink accepted by a body scan, with its target already split into an optional store qualifier and a target.
|
|
22
|
+
*/
|
|
18
23
|
export interface ScannedWikilink {
|
|
19
24
|
/** The whole matched link, including any `!` embed prefix. */
|
|
20
25
|
match: string;
|
|
@@ -22,28 +27,28 @@ export interface ScannedWikilink {
|
|
|
22
27
|
inner: string;
|
|
23
28
|
/** Offset of the match within the body. */
|
|
24
29
|
offset: number;
|
|
25
|
-
/** The store the link
|
|
30
|
+
/** The store named by the link, or `undefined` when the target is store-local. */
|
|
26
31
|
store?: string;
|
|
27
32
|
/** The target within that store, with alias, anchor, and any store qualifier stripped. */
|
|
28
33
|
target: string;
|
|
29
34
|
}
|
|
30
35
|
/**
|
|
31
|
-
*
|
|
36
|
+
* Scans a note body and yields every wikilink that has a resolvable target: fenced and inline code are masked
|
|
32
37
|
* first, and backslash-escaped links, intra-doc anchors, and non-Markdown embeds are skipped. This is the single
|
|
33
38
|
* definition of what counts as a link and what its target is, so a consumer that detects links and one that rewrites
|
|
34
39
|
* them cannot drift apart on either question.
|
|
35
40
|
*
|
|
36
|
-
* `offset` indexes the body as passed in.
|
|
37
|
-
* a consumer may slice the unmasked body at the offsets yielded here. It also leaves every newline where it
|
|
38
|
-
* consumer
|
|
39
|
-
* moved a newline while keeping the length would shift reported line numbers rather than fail.
|
|
41
|
+
* `offset` indexes the body as passed in. Because masking substitutes same-length whitespace, which this function
|
|
42
|
+
* asserts, a consumer may slice the unmasked body at the offsets yielded here. It also leaves every newline where it
|
|
43
|
+
* was, which lets a consumer count lines in the unmasked body at those offsets. Nothing asserts that at runtime, so a
|
|
44
|
+
* masker that moved a newline while keeping the length would shift reported line numbers rather than fail.
|
|
40
45
|
*/
|
|
41
46
|
export declare function scanWikilinks(body: string): Generator<ScannedWikilink>;
|
|
42
47
|
/**
|
|
43
|
-
* Separates a leading `store:` qualifier from a wikilink target
|
|
44
|
-
*
|
|
45
|
-
* whitespace and no `/`, and something follows the colon
|
|
46
|
-
*
|
|
48
|
+
* Separates a leading `store:` qualifier from a wikilink target: `fde:Note title` names the note `Note title` in the
|
|
49
|
+
* store `fde`. A qualifier is recognized only when the text before the first colon is non-empty and contains no
|
|
50
|
+
* whitespace and no `/`, and something follows the colon. Every other target stays store-local: A title such as
|
|
51
|
+
* `Release notes: v2` resolves within this store.
|
|
47
52
|
*
|
|
48
53
|
* Call it on the output of {@link extractTarget}, which has already stripped any alias and anchor.
|
|
49
54
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@williamthorsen/kb",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Knowledge-base foundation: discovery, config, frontmatter parsing, records, tags, and vault-integrity checks",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"frontmatter",
|
|
@@ -102,13 +102,13 @@
|
|
|
102
102
|
"dist"
|
|
103
103
|
],
|
|
104
104
|
"dependencies": {
|
|
105
|
-
"@williamthorsen/toolbelt.errors": "0.
|
|
105
|
+
"@williamthorsen/toolbelt.errors": "0.8.1",
|
|
106
106
|
"picomatch": "4.0.7",
|
|
107
|
-
"yaml": "2.9.
|
|
108
|
-
"zod": "4.5
|
|
107
|
+
"yaml": "2.9.1",
|
|
108
|
+
"zod": "4.6.5"
|
|
109
109
|
},
|
|
110
110
|
"devDependencies": {
|
|
111
|
-
"@types/node": "24.13.
|
|
111
|
+
"@types/node": "24.13.4",
|
|
112
112
|
"@types/picomatch": "4.0.3",
|
|
113
113
|
"eslint": "10.10.0",
|
|
114
114
|
"prettier": "3.9.6",
|