caedora-mcp 0.2.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.
- package/README.md +71 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +100 -0
- package/dist/cli.js.map +1 -0
- package/dist/lib/conventions.d.ts +3 -0
- package/dist/lib/conventions.d.ts.map +1 -0
- package/dist/lib/conventions.js +12 -0
- package/dist/lib/conventions.js.map +1 -0
- package/dist/lib/frontmatter.d.ts +23 -0
- package/dist/lib/frontmatter.d.ts.map +1 -0
- package/dist/lib/frontmatter.js +139 -0
- package/dist/lib/frontmatter.js.map +1 -0
- package/dist/lib/okf.d.ts +55 -0
- package/dist/lib/okf.d.ts.map +1 -0
- package/dist/lib/okf.js +276 -0
- package/dist/lib/okf.js.map +1 -0
- package/dist/providers/github.d.ts +26 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +144 -0
- package/dist/providers/github.js.map +1 -0
- package/dist/providers/local-node.d.ts +25 -0
- package/dist/providers/local-node.d.ts.map +1 -0
- package/dist/providers/local-node.js +112 -0
- package/dist/providers/local-node.js.map +1 -0
- package/dist/providers/types.d.ts +25 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +21 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +43 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/operations.d.ts +60 -0
- package/dist/tools/operations.d.ts.map +1 -0
- package/dist/tools/operations.js +48 -0
- package/dist/tools/operations.js.map +1 -0
- package/dist/tools/read.d.ts +49 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +74 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/search.d.ts +77 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +107 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/write.d.ts +89 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +114 -0
- package/dist/tools/write.js.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# caedora-mcp
|
|
2
|
+
|
|
3
|
+
An MCP server for reading, searching, validating, and maintaining Open Knowledge
|
|
4
|
+
Format bundles. It exposes structured concept metadata, cross-links, backlinks,
|
|
5
|
+
source ingestion, progressive indexes, and bundle logs to MCP-aware agents.
|
|
6
|
+
|
|
7
|
+
## Run
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx caedora-mcp --bundle /path/to/knowledge-bundle
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The legacy `--vault` flag remains an alias for `--bundle`.
|
|
14
|
+
|
|
15
|
+
For GitHub-hosted bundles:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
GITHUB_TOKEN=github_pat_xxx npx caedora-mcp --github owner/repository
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Add `--read-only` to disable all write tools.
|
|
22
|
+
|
|
23
|
+
## Connect an MCP client
|
|
24
|
+
|
|
25
|
+
The server speaks stdio, so any MCP-aware client uses the same config block:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"caedora": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "caedora-mcp", "--bundle", "/absolute/path/to/your-vault"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Config file locations:
|
|
39
|
+
|
|
40
|
+
- **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
41
|
+
(macOS) / `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
|
|
42
|
+
- **Cursor** — `~/.cursor/mcp.json`
|
|
43
|
+
- **Gemini CLI** — `~/.gemini/settings.json`
|
|
44
|
+
- **Claude Code** — already has file tools; run `claude` from the vault folder, and
|
|
45
|
+
optionally add this server for indexed search, graph traversal, and conformant writes.
|
|
46
|
+
|
|
47
|
+
## Read tools
|
|
48
|
+
|
|
49
|
+
- `list_concepts(folder?, type?)`
|
|
50
|
+
- `read_concept(path)`
|
|
51
|
+
- `search_concepts(query, tag?, type?, limit?)`
|
|
52
|
+
- `grep_concepts(regex, flags?, limit?)`
|
|
53
|
+
- `list_tags()`
|
|
54
|
+
- `list_types()`
|
|
55
|
+
- `concepts_by_tag(tag)`
|
|
56
|
+
- `concept_graph(path?)`
|
|
57
|
+
- `lint_bundle(recordLint?)`
|
|
58
|
+
|
|
59
|
+
## Write tools
|
|
60
|
+
|
|
61
|
+
- `create_concept(...)`
|
|
62
|
+
- `update_concept(...)`
|
|
63
|
+
- `rename_concept(from, to)`
|
|
64
|
+
- `delete_concept(path)`
|
|
65
|
+
- `ingest_source(...)`
|
|
66
|
+
- `rebuild_indexes()`
|
|
67
|
+
- `record_query(summary, conceptPaths?)`
|
|
68
|
+
|
|
69
|
+
Every mutation preserves producer-defined YAML fields, maintains timestamps,
|
|
70
|
+
regenerates hierarchical indexes, and records significant operations in
|
|
71
|
+
`log.md`. Reserved `index.md` and `log.md` documents are protected.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { buildServer } from './server.js';
|
|
5
|
+
import { LocalNodeProvider } from './providers/local-node.js';
|
|
6
|
+
import { GitHubNodeProvider } from './providers/github.js';
|
|
7
|
+
function parseArgs(argv) {
|
|
8
|
+
const out = { readOnly: false, help: false };
|
|
9
|
+
for (let index = 0; index < argv.length; index++) {
|
|
10
|
+
switch (argv[index]) {
|
|
11
|
+
case '--bundle':
|
|
12
|
+
case '--vault':
|
|
13
|
+
out.bundle = argv[++index];
|
|
14
|
+
break;
|
|
15
|
+
case '--github':
|
|
16
|
+
out.github = argv[++index];
|
|
17
|
+
break;
|
|
18
|
+
case '--pat':
|
|
19
|
+
out.pat = argv[++index];
|
|
20
|
+
break;
|
|
21
|
+
case '--read-only':
|
|
22
|
+
out.readOnly = true;
|
|
23
|
+
break;
|
|
24
|
+
case '-h':
|
|
25
|
+
case '--help':
|
|
26
|
+
out.help = true;
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
if (argv[index].startsWith('--')) {
|
|
30
|
+
console.error(`Unknown flag: ${argv[index]}`);
|
|
31
|
+
process.exit(2);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
function printHelp() {
|
|
38
|
+
console.error(`caedora-mcp - MCP server for OKF knowledge bundles
|
|
39
|
+
|
|
40
|
+
Usage:
|
|
41
|
+
caedora-mcp --bundle <path>
|
|
42
|
+
caedora-mcp --github <owner>/<repo> --pat <token>
|
|
43
|
+
caedora-mcp --bundle <path> --read-only
|
|
44
|
+
|
|
45
|
+
Options:
|
|
46
|
+
--bundle <path> Serve a local OKF bundle.
|
|
47
|
+
--vault <path> Legacy alias for --bundle.
|
|
48
|
+
--github owner/repo Serve a GitHub-hosted OKF bundle.
|
|
49
|
+
--pat <token> GitHub personal access token. Falls back to GITHUB_TOKEN.
|
|
50
|
+
--read-only Disable all write tools.
|
|
51
|
+
-h, --help Show this help.
|
|
52
|
+
|
|
53
|
+
The server speaks stdio. Example MCP configuration:
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"caedora": {
|
|
58
|
+
"command": "npx",
|
|
59
|
+
"args": ["-y", "caedora-mcp", "--bundle", "/path/to/bundle"]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
`);
|
|
64
|
+
}
|
|
65
|
+
async function main() {
|
|
66
|
+
const args = parseArgs(process.argv.slice(2));
|
|
67
|
+
if (args.help) {
|
|
68
|
+
printHelp();
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
let provider;
|
|
72
|
+
if (args.bundle) {
|
|
73
|
+
provider = new LocalNodeProvider(path.resolve(args.bundle));
|
|
74
|
+
}
|
|
75
|
+
else if (args.github) {
|
|
76
|
+
const [owner, repo] = args.github.split('/');
|
|
77
|
+
if (!owner || !repo) {
|
|
78
|
+
console.error('--github must be in the form owner/repo');
|
|
79
|
+
process.exit(2);
|
|
80
|
+
}
|
|
81
|
+
const token = args.pat ?? process.env.GITHUB_TOKEN;
|
|
82
|
+
if (!token) {
|
|
83
|
+
console.error('Missing --pat (or GITHUB_TOKEN) for --github mode');
|
|
84
|
+
process.exit(2);
|
|
85
|
+
}
|
|
86
|
+
provider = new GitHubNodeProvider(token, owner, repo);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.error('Must provide either --bundle <path> or --github owner/repo');
|
|
90
|
+
printHelp();
|
|
91
|
+
process.exit(2);
|
|
92
|
+
}
|
|
93
|
+
const server = buildServer({ provider, readOnly: args.readOnly });
|
|
94
|
+
await server.connect(new StdioServerTransport());
|
|
95
|
+
}
|
|
96
|
+
main().catch((error) => {
|
|
97
|
+
console.error(`caedora-mcp: fatal error - ${error instanceof Error ? error.message : String(error)}`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conventions.d.ts","sourceRoot":"","sources":["../../src/lib/conventions.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function stemFromPath(path) {
|
|
2
|
+
const name = path.split('/').pop() ?? path;
|
|
3
|
+
return name.replace(/\.md$/i, '');
|
|
4
|
+
}
|
|
5
|
+
export function titleFromPath(path) {
|
|
6
|
+
return stemFromPath(path)
|
|
7
|
+
.split(/[-_]+/)
|
|
8
|
+
.filter(Boolean)
|
|
9
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
10
|
+
.join(' ');
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=conventions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conventions.js","sourceRoot":"","sources":["../../src/lib/conventions.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAA;IAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;AACnC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC;SACtB,KAAK,CAAC,OAAO,CAAC;SACd,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAC3D,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface Frontmatter {
|
|
2
|
+
type: string;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
resource: string;
|
|
6
|
+
tags: string[];
|
|
7
|
+
timestamp: string;
|
|
8
|
+
extra: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export declare function emptyFrontmatter(overrides?: Partial<Frontmatter>): Frontmatter;
|
|
11
|
+
export declare function parseFrontmatter(markdown: string): {
|
|
12
|
+
frontmatter: Frontmatter;
|
|
13
|
+
body: string;
|
|
14
|
+
hasFrontmatter: boolean;
|
|
15
|
+
error: string | null;
|
|
16
|
+
};
|
|
17
|
+
export declare function serializeFrontmatter(frontmatter: Frontmatter): string;
|
|
18
|
+
export declare function combine(frontmatter: Frontmatter, body: string): string;
|
|
19
|
+
export declare function createConceptFrontmatter(title: string, type: string, overrides?: Partial<Frontmatter>): Frontmatter;
|
|
20
|
+
export declare function normalizeTag(raw: string): string;
|
|
21
|
+
export declare function uniqueTags(tags: string[]): string[];
|
|
22
|
+
export declare function slugifyFilename(raw: string): string;
|
|
23
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAYD,wBAAgB,gBAAgB,CAAC,SAAS,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAWlF;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM;;;;WAO5B,MAAM,GAAG,IAAI;EAwCjC;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAarE;AAED,wBAAgB,OAAO,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,OAAO,CAAC,WAAW,CAAM,GACnC,WAAW,CASb;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAEnD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASnD"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { parseDocument, stringify } from 'yaml';
|
|
2
|
+
const FENCE = /^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?/;
|
|
3
|
+
const STANDARD_KEYS = new Set([
|
|
4
|
+
'type',
|
|
5
|
+
'title',
|
|
6
|
+
'description',
|
|
7
|
+
'resource',
|
|
8
|
+
'tags',
|
|
9
|
+
'timestamp',
|
|
10
|
+
]);
|
|
11
|
+
export function emptyFrontmatter(overrides = {}) {
|
|
12
|
+
return {
|
|
13
|
+
type: '',
|
|
14
|
+
title: '',
|
|
15
|
+
description: '',
|
|
16
|
+
resource: '',
|
|
17
|
+
tags: [],
|
|
18
|
+
timestamp: '',
|
|
19
|
+
extra: {},
|
|
20
|
+
...overrides,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function parseFrontmatter(markdown) {
|
|
24
|
+
const match = markdown.match(FENCE);
|
|
25
|
+
if (!match) {
|
|
26
|
+
return {
|
|
27
|
+
frontmatter: emptyFrontmatter(),
|
|
28
|
+
body: markdown,
|
|
29
|
+
hasFrontmatter: false,
|
|
30
|
+
error: null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const document = parseDocument(match[1], { prettyErrors: false, uniqueKeys: false });
|
|
35
|
+
if (document.errors.length > 0)
|
|
36
|
+
throw new Error(document.errors[0].message);
|
|
37
|
+
const value = document.toJS();
|
|
38
|
+
if (!isRecord(value))
|
|
39
|
+
throw new Error('YAML frontmatter must be a mapping.');
|
|
40
|
+
const extra = {};
|
|
41
|
+
for (const [key, fieldValue] of Object.entries(value)) {
|
|
42
|
+
if (!STANDARD_KEYS.has(key))
|
|
43
|
+
extra[key] = fieldValue;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
frontmatter: {
|
|
47
|
+
type: stringValue(value.type),
|
|
48
|
+
title: stringValue(value.title),
|
|
49
|
+
description: stringValue(value.description),
|
|
50
|
+
resource: stringValue(value.resource),
|
|
51
|
+
tags: uniqueTags(Array.isArray(value.tags)
|
|
52
|
+
? value.tags.filter((item) => typeof item === 'string')
|
|
53
|
+
: typeof value.tags === 'string'
|
|
54
|
+
? value.tags.split(/[\s,]+/)
|
|
55
|
+
: []),
|
|
56
|
+
timestamp: stringValue(value.timestamp),
|
|
57
|
+
extra,
|
|
58
|
+
},
|
|
59
|
+
body: markdown.slice(match[0].length),
|
|
60
|
+
hasFrontmatter: true,
|
|
61
|
+
error: null,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
frontmatter: emptyFrontmatter(),
|
|
67
|
+
body: markdown.slice(match[0].length),
|
|
68
|
+
hasFrontmatter: true,
|
|
69
|
+
error: error instanceof Error ? error.message : 'Invalid YAML frontmatter.',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function serializeFrontmatter(frontmatter) {
|
|
74
|
+
const data = {};
|
|
75
|
+
if (frontmatter.type.trim())
|
|
76
|
+
data.type = frontmatter.type.trim();
|
|
77
|
+
if (frontmatter.title.trim())
|
|
78
|
+
data.title = frontmatter.title.trim();
|
|
79
|
+
if (frontmatter.description.trim())
|
|
80
|
+
data.description = frontmatter.description.trim();
|
|
81
|
+
if (frontmatter.resource.trim())
|
|
82
|
+
data.resource = frontmatter.resource.trim();
|
|
83
|
+
if (frontmatter.tags.length > 0)
|
|
84
|
+
data.tags = uniqueTags(frontmatter.tags);
|
|
85
|
+
if (frontmatter.timestamp.trim())
|
|
86
|
+
data.timestamp = frontmatter.timestamp.trim();
|
|
87
|
+
for (const [key, value] of Object.entries(frontmatter.extra)) {
|
|
88
|
+
if (!STANDARD_KEYS.has(key) && value !== undefined)
|
|
89
|
+
data[key] = value;
|
|
90
|
+
}
|
|
91
|
+
if (Object.keys(data).length === 0)
|
|
92
|
+
return '';
|
|
93
|
+
return `---\n${stringify(data, { lineWidth: 0 }).trimEnd()}\n---\n`;
|
|
94
|
+
}
|
|
95
|
+
export function combine(frontmatter, body) {
|
|
96
|
+
return `${serializeFrontmatter(frontmatter)}\n${body.replace(/^\n+/, '')}`;
|
|
97
|
+
}
|
|
98
|
+
export function createConceptFrontmatter(title, type, overrides = {}) {
|
|
99
|
+
return emptyFrontmatter({
|
|
100
|
+
type: type.trim(),
|
|
101
|
+
title: title.trim(),
|
|
102
|
+
timestamp: new Date().toISOString(),
|
|
103
|
+
...overrides,
|
|
104
|
+
tags: uniqueTags(overrides.tags ?? []),
|
|
105
|
+
extra: overrides.extra ?? {},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
export function normalizeTag(raw) {
|
|
109
|
+
return raw
|
|
110
|
+
.trim()
|
|
111
|
+
.replace(/^#/, '')
|
|
112
|
+
.replace(/\s+/g, '-')
|
|
113
|
+
.toLowerCase()
|
|
114
|
+
.replace(/[^a-z0-9_-]/g, '');
|
|
115
|
+
}
|
|
116
|
+
export function uniqueTags(tags) {
|
|
117
|
+
return [...new Set(tags.map(normalizeTag).filter(Boolean))];
|
|
118
|
+
}
|
|
119
|
+
export function slugifyFilename(raw) {
|
|
120
|
+
const stem = raw.replace(/\.md$/i, '');
|
|
121
|
+
return stem
|
|
122
|
+
.normalize('NFKD')
|
|
123
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
124
|
+
.toLowerCase()
|
|
125
|
+
.replace(/['"]/g, '')
|
|
126
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
127
|
+
.replace(/^-+|-+$/g, '') || 'untitled';
|
|
128
|
+
}
|
|
129
|
+
function stringValue(value) {
|
|
130
|
+
if (value === null || value === undefined)
|
|
131
|
+
return '';
|
|
132
|
+
if (value instanceof Date)
|
|
133
|
+
return value.toISOString();
|
|
134
|
+
return typeof value === 'string' ? value : String(value);
|
|
135
|
+
}
|
|
136
|
+
function isRecord(value) {
|
|
137
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type VaultProvider } from '../providers/types.js';
|
|
2
|
+
export declare const OKF_VERSION = "0.1";
|
|
3
|
+
export declare const INDEX_FILENAME = "index.md";
|
|
4
|
+
export declare const LOG_FILENAME = "log.md";
|
|
5
|
+
export declare function isReservedPath(path: string): boolean;
|
|
6
|
+
export declare function isConceptPath(path: string): boolean;
|
|
7
|
+
export declare function conceptId(path: string): string;
|
|
8
|
+
export declare function extractLinks(markdown: string, sourcePath: string): {
|
|
9
|
+
label: string;
|
|
10
|
+
href: string;
|
|
11
|
+
targetPath: string | null;
|
|
12
|
+
targetId: string | null;
|
|
13
|
+
external: boolean;
|
|
14
|
+
}[];
|
|
15
|
+
export declare function resolveBundleLink(sourcePath: string, href: string): string | null;
|
|
16
|
+
export declare function validateBundle(provider: VaultProvider): Promise<{
|
|
17
|
+
version: string;
|
|
18
|
+
conformant: boolean;
|
|
19
|
+
concepts: number;
|
|
20
|
+
links: number;
|
|
21
|
+
brokenLinks: number;
|
|
22
|
+
issues: {
|
|
23
|
+
path: string;
|
|
24
|
+
severity: "error" | "warning";
|
|
25
|
+
code: string;
|
|
26
|
+
message: string;
|
|
27
|
+
}[];
|
|
28
|
+
}>;
|
|
29
|
+
export declare function buildConceptCatalog(provider: VaultProvider): Promise<{
|
|
30
|
+
id: string;
|
|
31
|
+
path: string;
|
|
32
|
+
type: string;
|
|
33
|
+
title: string;
|
|
34
|
+
description: string;
|
|
35
|
+
resource: string;
|
|
36
|
+
tags: string[];
|
|
37
|
+
timestamp: string;
|
|
38
|
+
links: {
|
|
39
|
+
label: string;
|
|
40
|
+
href: string;
|
|
41
|
+
targetPath: string | null;
|
|
42
|
+
targetId: string | null;
|
|
43
|
+
external: boolean;
|
|
44
|
+
}[];
|
|
45
|
+
conformant: boolean;
|
|
46
|
+
}[]>;
|
|
47
|
+
export declare function rebuildIndexes(provider: VaultProvider): Promise<{
|
|
48
|
+
updated: string[];
|
|
49
|
+
}>;
|
|
50
|
+
export declare function appendLog(provider: VaultProvider, action: string, message: string): Promise<{
|
|
51
|
+
path: string;
|
|
52
|
+
action: string;
|
|
53
|
+
recorded: boolean;
|
|
54
|
+
}>;
|
|
55
|
+
//# sourceMappingURL=okf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"okf.d.ts","sourceRoot":"","sources":["../../src/lib/okf.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsC,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE9F,eAAO,MAAM,WAAW,QAAQ,CAAA;AAChC,eAAO,MAAM,cAAc,aAAa,CAAA;AACxC,eAAO,MAAM,YAAY,WAAW,CAAA;AAEpC,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;WAGtD,MAAM;UACP,MAAM;gBACA,MAAM,GAAG,IAAI;cACf,MAAM,GAAG,IAAI;cACb,OAAO;IAcpB;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjF;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,aAAa;;;;;;;cAI9B,MAAM;kBAAY,OAAO,GAAG,SAAS;cAAQ,MAAM;iBAAW,MAAM;;GA4CjG;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,aAAa;;;;;;;;;;eAjFtD,MAAM;cACP,MAAM;oBACA,MAAM,GAAG,IAAI;kBACf,MAAM,GAAG,IAAI;kBACb,OAAO;;;KAiGpB;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,aAAa;;GAiB3D;AAED,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;;;;GAmBhB"}
|