oh-my-second-brain 0.1.5

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 (90) hide show
  1. package/adapters/README.md +98 -0
  2. package/adapters/claude-code/.claude-plugin/plugin.json +24 -0
  3. package/adapters/claude-code/CLAUDE.md +26 -0
  4. package/adapters/claude-code/skills/capture/SKILL.md +50 -0
  5. package/adapters/claude-code/skills/define/SKILL.md +51 -0
  6. package/adapters/claude-code/skills/doctor/SKILL.md +58 -0
  7. package/adapters/claude-code/skills/retrieve/SKILL.md +55 -0
  8. package/adapters/claude-code/skills/setup/SKILL.md +71 -0
  9. package/adapters/claude-code/skills/uninstall/SKILL.md +34 -0
  10. package/adapters/codex/.codex-plugin/plugin.json +8 -0
  11. package/adapters/codex/.mcp.json +14 -0
  12. package/adapters/codex/AGENTS.md +16 -0
  13. package/adapters/codex/rules/oms.md +25 -0
  14. package/adapters/codex/skills/oms-capture/SKILL.md +16 -0
  15. package/adapters/codex/skills/oms-doctor/SKILL.md +14 -0
  16. package/adapters/codex/skills/oms-install/SKILL.md +19 -0
  17. package/adapters/codex/skills/oms-retrieve/SKILL.md +10 -0
  18. package/adapters/codex/skills/oms-setup/SKILL.md +22 -0
  19. package/adapters/codex/skills/oms-uninstall/SKILL.md +20 -0
  20. package/adapters/hermes/README.md +8 -0
  21. package/adapters/hermes/SOUL.md +19 -0
  22. package/adapters/hermes/manifest.json +7 -0
  23. package/adapters/hermes/skills/capture/SKILL.md +16 -0
  24. package/adapters/hermes/skills/doctor/SKILL.md +14 -0
  25. package/adapters/hermes/skills/install/SKILL.md +19 -0
  26. package/adapters/hermes/skills/retrieve/SKILL.md +10 -0
  27. package/adapters/hermes/skills/setup/SKILL.md +22 -0
  28. package/adapters/hermes/skills/uninstall/SKILL.md +20 -0
  29. package/core/AGENTS.md +110 -0
  30. package/core/agents/librarian.md +43 -0
  31. package/core/agents/retriever.md +62 -0
  32. package/core/ontology/concepts/inbox.yaml +4 -0
  33. package/core/ontology/concepts/literature.yaml +27 -0
  34. package/core/ontology/taxonomy.yaml +11 -0
  35. package/core/skills/capture/SKILL.md +48 -0
  36. package/core/skills/define/SKILL.md +59 -0
  37. package/core/skills/doctor/SKILL.md +49 -0
  38. package/core/skills/retrieve/SKILL.md +56 -0
  39. package/core/skills/setup/SKILL.md +44 -0
  40. package/core/skills/uninstall/SKILL.md +34 -0
  41. package/dist/adapt/HostAdapter.d.ts +21 -0
  42. package/dist/adapt/HostAdapter.js +10 -0
  43. package/dist/adapt/HostAdapter.js.map +1 -0
  44. package/dist/adapt/claudeCode.d.ts +9 -0
  45. package/dist/adapt/claudeCode.js +15 -0
  46. package/dist/adapt/claudeCode.js.map +1 -0
  47. package/dist/adapt/codex.d.ts +9 -0
  48. package/dist/adapt/codex.js +15 -0
  49. package/dist/adapt/codex.js.map +1 -0
  50. package/dist/adapt/hermes.d.ts +9 -0
  51. package/dist/adapt/hermes.js +15 -0
  52. package/dist/adapt/hermes.js.map +1 -0
  53. package/dist/capture/safe.d.ts +36 -0
  54. package/dist/capture/safe.js +167 -0
  55. package/dist/capture/safe.js.map +1 -0
  56. package/dist/cli/oms.d.ts +18 -0
  57. package/dist/cli/oms.js +401 -0
  58. package/dist/cli/oms.js.map +1 -0
  59. package/dist/conventions/frontmatter.d.ts +15 -0
  60. package/dist/conventions/frontmatter.js +23 -0
  61. package/dist/conventions/frontmatter.js.map +1 -0
  62. package/dist/conventions/validate.d.ts +24 -0
  63. package/dist/conventions/validate.js +88 -0
  64. package/dist/conventions/validate.js.map +1 -0
  65. package/dist/graph/cache.d.ts +98 -0
  66. package/dist/graph/cache.js +347 -0
  67. package/dist/graph/cache.js.map +1 -0
  68. package/dist/index.d.ts +7 -0
  69. package/dist/index.js +8 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/install/hosts.d.ts +27 -0
  72. package/dist/install/hosts.js +465 -0
  73. package/dist/install/hosts.js.map +1 -0
  74. package/dist/mcp/server.d.ts +8 -0
  75. package/dist/mcp/server.js +461 -0
  76. package/dist/mcp/server.js.map +1 -0
  77. package/dist/ontology/loader.d.ts +13 -0
  78. package/dist/ontology/loader.js +63 -0
  79. package/dist/ontology/loader.js.map +1 -0
  80. package/dist/ontology/resolver.d.ts +13 -0
  81. package/dist/ontology/resolver.js +37 -0
  82. package/dist/ontology/resolver.js.map +1 -0
  83. package/dist/ontology/types.d.ts +72 -0
  84. package/dist/ontology/types.js +12 -0
  85. package/dist/ontology/types.js.map +1 -0
  86. package/docs/install.md +115 -0
  87. package/docs/release.md +91 -0
  88. package/package.json +64 -0
  89. package/scripts/install.sh +49 -0
  90. package/scripts/uninstall.sh +57 -0
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env node
2
+ import { realpathSync } from "node:fs";
3
+ import { readFile, readdir, mkdir, copyFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { createInterface } from "node:readline/promises";
7
+ import { stringify as yamlStringify } from "yaml";
8
+ import { loadOntology } from "../ontology/loader.js";
9
+ import { resolveConcept } from "../ontology/resolver.js";
10
+ import { parseNote } from "../conventions/frontmatter.js";
11
+ import { validateFrontmatter } from "../conventions/validate.js";
12
+ import { runMcpServer } from "../mcp/server.js";
13
+ import { formatHostOperationResults, runHostOperation, } from "../install/hosts.js";
14
+ const DEFAULT_RELEASE_PACKAGE_SPEC = "https://github.com/GoBeromsu/oms/releases/download/oms-v0.1.5/oms-0.1.5.tgz";
15
+ // ---------------------------------------------------------------------------
16
+ // Path helpers
17
+ // ---------------------------------------------------------------------------
18
+ /**
19
+ * Resolve the bundled `core/ontology` directory.
20
+ * Both the built path (`dist/cli/`) and the source path (`src/cli/`) are two
21
+ * levels beneath the repo root, so `../../core/ontology` works in both cases.
22
+ */
23
+ function bundledOntologyDir() {
24
+ const __filename = fileURLToPath(import.meta.url);
25
+ const __dirname = path.dirname(__filename);
26
+ return path.resolve(__dirname, "../../core/ontology");
27
+ }
28
+ /**
29
+ * Resolve the bundled Claude Code adapter directory.
30
+ * Kept parallel to bundledOntologyDir so source and built paths both work.
31
+ */
32
+ function bundledClaudeAdapterDir() {
33
+ const __filename = fileURLToPath(import.meta.url);
34
+ const __dirname = path.dirname(__filename);
35
+ return path.resolve(__dirname, "../../adapters/claude-code");
36
+ }
37
+ /**
38
+ * Resolve the bundled `adapters` root so host installers can copy the
39
+ * runtime-specific adapter assets from either source or dist execution.
40
+ */
41
+ function bundledAdapterRoot() {
42
+ const __filename = fileURLToPath(import.meta.url);
43
+ const __dirname = path.dirname(__filename);
44
+ return path.resolve(__dirname, "../../adapters");
45
+ }
46
+ // ---------------------------------------------------------------------------
47
+ // Helpers
48
+ // ---------------------------------------------------------------------------
49
+ /** Humanize a folder name: "references" → "References". */
50
+ function humanize(name) {
51
+ return name.charAt(0).toUpperCase() + name.slice(1);
52
+ }
53
+ /** Quote a value for copy/pasteable POSIX shell commands. */
54
+ function shellQuote(value) {
55
+ if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
56
+ return value;
57
+ }
58
+ return `'${value.replace(/'/g, "'\\''")}'`;
59
+ }
60
+ export function buildClaudeInstallPlan(opts) {
61
+ const pluginPath = bundledClaudeAdapterDir();
62
+ return {
63
+ pluginPath,
64
+ pluginInstallCommand: `claude plugin install ${shellQuote(pluginPath)}`,
65
+ mcpRegistrationCommand: `claude mcp add oms -- npx -y ${shellQuote(DEFAULT_RELEASE_PACKAGE_SPEC)} mcp --vault ${shellQuote(opts.vault)}`,
66
+ mcpRuntimeStatus: "read-status-runtime",
67
+ };
68
+ }
69
+ function printClaudeInstallPlan(plan) {
70
+ console.log("Claude Code harness install plan (dry-run).");
71
+ console.log(` Plugin path: ${plan.pluginPath}`);
72
+ console.log(` Plugin command: ${plan.pluginInstallCommand}`);
73
+ console.log(` MCP command: ${plan.mcpRegistrationCommand}`);
74
+ console.log(" MCP status: status/read/cache/retrieval plus safe capture; commit is gated by vault confinement and contract validation.");
75
+ }
76
+ /** Walk a directory recursively, yielding relative paths for all .md files. */
77
+ async function* walkMarkdown(dir, base, skipDirs) {
78
+ let entries;
79
+ try {
80
+ entries = await readdir(dir, { withFileTypes: true });
81
+ }
82
+ catch {
83
+ return;
84
+ }
85
+ for (const entry of entries) {
86
+ if (entry.name.startsWith("."))
87
+ continue;
88
+ if (skipDirs.has(entry.name))
89
+ continue;
90
+ const full = path.join(dir, entry.name);
91
+ if (entry.isDirectory()) {
92
+ yield* walkMarkdown(full, base, skipDirs);
93
+ }
94
+ else if (entry.isFile() && entry.name.endsWith(".md")) {
95
+ yield path.relative(base, full).replace(/\\/g, "/");
96
+ }
97
+ }
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // runSetup
101
+ // ---------------------------------------------------------------------------
102
+ export async function runSetup(opts) {
103
+ const { vault, yes, installClaude = false } = opts;
104
+ const nonInteractive = yes || process.env["OMS_NON_INTERACTIVE"] === "1";
105
+ const ontologyDir = bundledOntologyDir();
106
+ // Load shipped concepts so we can offer meaningful defaults.
107
+ const ontology = await loadOntology(ontologyDir);
108
+ // Scan vault top-level directories (skip dotfiles).
109
+ const topEntries = await readdir(vault, { withFileTypes: true });
110
+ const folders = topEntries
111
+ .filter((e) => e.isDirectory() && !e.name.startsWith("."))
112
+ .map((e) => e.name);
113
+ const folderBindings = {};
114
+ if (nonInteractive) {
115
+ // Non-interactive: use defaults without readline.
116
+ for (const folder of folders) {
117
+ // Find a shipped concept whose folder field matches.
118
+ let conceptName = null;
119
+ for (const [name, concept] of ontology.concepts) {
120
+ if (concept.folder === folder) {
121
+ conceptName = name;
122
+ break;
123
+ }
124
+ }
125
+ folderBindings[folder] = {
126
+ intent: humanize(folder),
127
+ concept: conceptName,
128
+ };
129
+ }
130
+ }
131
+ else {
132
+ // Interactive: ask intent and concept for each folder.
133
+ const rl = createInterface({
134
+ input: process.stdin,
135
+ output: process.stdout,
136
+ });
137
+ const conceptNames = Array.from(ontology.concepts.keys());
138
+ try {
139
+ console.log("\nOh My Second Brain Setup — adopting existing vault folders.\n");
140
+ console.log(`Available shipped concepts: ${conceptNames.join(", ") || "(none)"}\n`);
141
+ for (const folder of folders) {
142
+ const defaultIntent = humanize(folder);
143
+ const rawIntent = await rl.question(`Folder "${folder}" — intent [${defaultIntent}]: `);
144
+ const intent = rawIntent.trim() || defaultIntent;
145
+ // Find default concept
146
+ let defaultConcept = null;
147
+ for (const [name, concept] of ontology.concepts) {
148
+ if (concept.folder === folder) {
149
+ defaultConcept = name;
150
+ break;
151
+ }
152
+ }
153
+ const conceptPrompt = defaultConcept
154
+ ? ` Bind concept [${defaultConcept}] (blank = ${defaultConcept}, "null" = none): `
155
+ : ` Bind concept (${conceptNames.join("/") || "none"}, blank = none): `;
156
+ const rawConcept = await rl.question(conceptPrompt);
157
+ const trimmed = rawConcept.trim();
158
+ let conceptName;
159
+ if (trimmed === "null" || trimmed === "") {
160
+ conceptName = trimmed === "null" ? null : (defaultConcept ?? null);
161
+ }
162
+ else if (ontology.concepts.has(trimmed)) {
163
+ conceptName = trimmed;
164
+ }
165
+ else {
166
+ console.warn(` Unknown concept "${trimmed}"; binding as null.`);
167
+ conceptName = null;
168
+ }
169
+ folderBindings[folder] = { intent, concept: conceptName };
170
+ }
171
+ }
172
+ finally {
173
+ rl.close();
174
+ }
175
+ }
176
+ const taxonomy = { version: 0, folders: folderBindings };
177
+ // Write the vault-local ontology. ``.oms/` IS the ontology directory:
178
+ // `.oms/taxonomy.yaml` + `.oms/concepts/*.yaml`, matching loadOntology's
179
+ // contract so `oms doctor` can load it directly.
180
+ const omsDir = path.join(vault, ".oms");
181
+ const conceptsOutDir = path.join(omsDir, "concepts");
182
+ await mkdir(conceptsOutDir, { recursive: true });
183
+ await import("node:fs/promises").then(({ writeFile }) => writeFile(path.join(omsDir, "taxonomy.yaml"), yamlStringify(taxonomy), "utf-8"));
184
+ // Copy shipped concept yaml files into vault/.oms/concepts/
185
+ const conceptsSourceDir = path.join(ontologyDir, "concepts");
186
+ let copiedFiles = [];
187
+ try {
188
+ const conceptFiles = await readdir(conceptsSourceDir);
189
+ for (const file of conceptFiles) {
190
+ if (file.endsWith(".yaml") || file.endsWith(".yml")) {
191
+ await copyFile(path.join(conceptsSourceDir, file), path.join(conceptsOutDir, file));
192
+ copiedFiles.push(file);
193
+ }
194
+ }
195
+ }
196
+ catch (err) {
197
+ console.warn("[oms] Could not copy concept files:", err);
198
+ }
199
+ // Summary
200
+ console.log(`\nOh My Second Brain setup complete.`);
201
+ console.log(` Vault: ${vault}`);
202
+ console.log(` Written: ${path.join(omsDir, "taxonomy.yaml")}`);
203
+ console.log(` Concepts: ${copiedFiles.join(", ") || "(none)"}`);
204
+ console.log(` Folders: ${Object.keys(folderBindings).join(", ") || "(none)"}`);
205
+ console.log(`\nRun "npx -y https://github.com/GoBeromsu/oms/releases/download/oms-v0.1.5/oms-0.1.5.tgz doctor" to validate existing notes.\n`);
206
+ if (installClaude) {
207
+ printClaudeInstallPlan(buildClaudeInstallPlan({ vault }));
208
+ console.log("");
209
+ }
210
+ }
211
+ // ---------------------------------------------------------------------------
212
+ // runDoctor
213
+ // ---------------------------------------------------------------------------
214
+ export async function runDoctor(opts) {
215
+ const { vault } = opts;
216
+ // Doctor is non-blocking (onViolation: warn). It must ALWAYS exit 0 in v0,
217
+ // even if the ontology is missing or unparseable — wrap the whole body so a
218
+ // failure surfaces as a warning, never a non-zero exit.
219
+ try {
220
+ // Load ontology: prefer the vault-local `.oms/` ontology, fall back to the
221
+ // bundled defaults. The vault-local layout is `.oms/taxonomy.yaml` +
222
+ // `.oms/concepts/`, so `.oms/` itself is the ontology dir.
223
+ const localOntologyDir = path.join(vault, ".oms");
224
+ let ontologyDir;
225
+ try {
226
+ await readdir(path.join(localOntologyDir, "concepts"));
227
+ ontologyDir = localOntologyDir;
228
+ }
229
+ catch {
230
+ ontologyDir = bundledOntologyDir();
231
+ }
232
+ const ontology = await loadOntology(ontologyDir);
233
+ const skipDirs = new Set(["node_modules"]);
234
+ let totalNotes = 0;
235
+ let totalViolations = 0;
236
+ let notesWithViolations = 0;
237
+ for await (const relPath of walkMarkdown(vault, vault, skipDirs)) {
238
+ const concept = resolveConcept(ontology, relPath);
239
+ if (!concept)
240
+ continue;
241
+ totalNotes++;
242
+ const fullPath = path.join(vault, relPath);
243
+ let raw;
244
+ try {
245
+ raw = await readFile(fullPath, "utf-8");
246
+ }
247
+ catch {
248
+ console.warn(`[oms] Could not read ${relPath}`);
249
+ continue;
250
+ }
251
+ const { frontmatter } = parseNote(raw);
252
+ const result = validateFrontmatter(frontmatter, concept);
253
+ if (result.violations.length > 0) {
254
+ notesWithViolations++;
255
+ totalViolations += result.violations.length;
256
+ console.log(`\n ${relPath} [concept: ${concept.concept}]`);
257
+ for (const v of result.violations) {
258
+ console.log(` [${v.rule}] ${v.message}`);
259
+ }
260
+ }
261
+ }
262
+ console.log(`\nOh My Second Brain doctor: ${totalNotes} notes checked, ${notesWithViolations} with violations, ${totalViolations} total violations.`);
263
+ console.log("All violations are warnings (onViolation: warn). Exit 0.\n");
264
+ }
265
+ catch (err) {
266
+ console.warn("[oms] doctor could not complete:", err);
267
+ }
268
+ // Always exit 0 in v0 (non-blocking, onViolation: warn).
269
+ return 0;
270
+ }
271
+ // ---------------------------------------------------------------------------
272
+ // main
273
+ // ---------------------------------------------------------------------------
274
+ function printUsage() {
275
+ console.log(`
276
+ oms — Oh My Second Brain convention layer for Obsidian vaults
277
+
278
+ Usage:
279
+ oms setup [--vault <path>] [--yes] [--install-claude]
280
+ oms install [--vault <path>] [--runtime <auto|all|claude|codex|hermes>] [--dry-run] [--execute] [--yes]
281
+ oms uninstall [--runtime <all|claude|codex|hermes>] [--dry-run] [--execute] [--yes]
282
+ oms doctor [--vault <path>]
283
+ oms mcp [--vault <path>]
284
+
285
+ Commands:
286
+ setup Adopt an existing vault into the Oh My Second Brain convention.
287
+ install Install Oh My Second Brain host adapters and MCP registration.
288
+ uninstall Remove Oh My Second Brain host adapters and MCP registration.
289
+ doctor Validate vault notes against the active ontology.
290
+ mcp Start the read/status MCP stdio server.
291
+
292
+ Options:
293
+ --vault <path> Path to the vault root (default: current directory).
294
+ --yes Non-interactive: accept all defaults (setup only).
295
+ --install-claude Print Claude Code plugin install and MCP registration commands (dry-run).
296
+ --runtime <name> Select host runtime (default: auto for install, all for uninstall).
297
+ --dry-run Preview host config changes without writing files.
298
+ --execute Allow external host CLIs such as \`claude\` to run when available.
299
+ `);
300
+ }
301
+ async function main() {
302
+ const argv = process.argv.slice(2);
303
+ const command = argv[0];
304
+ // Parse shared flags.
305
+ let vault = process.cwd();
306
+ let yes = false;
307
+ let installClaude = false;
308
+ let runtime;
309
+ let dryRun = false;
310
+ let executeExternal = false;
311
+ for (let i = 1; i < argv.length; i++) {
312
+ if (argv[i] === "--vault" && argv[i + 1]) {
313
+ vault = path.resolve(argv[i + 1]);
314
+ i++;
315
+ }
316
+ else if (argv[i] === "--yes") {
317
+ yes = true;
318
+ }
319
+ else if (argv[i] === "--install-claude") {
320
+ installClaude = true;
321
+ }
322
+ else if (argv[i] === "--runtime" && argv[i + 1]) {
323
+ const rawRuntime = argv[i + 1];
324
+ if (rawRuntime === "auto" ||
325
+ rawRuntime === "all" ||
326
+ rawRuntime === "claude" ||
327
+ rawRuntime === "codex" ||
328
+ rawRuntime === "hermes") {
329
+ runtime = rawRuntime;
330
+ }
331
+ else {
332
+ console.error(`[oms] Unsupported runtime: ${rawRuntime}`);
333
+ process.exitCode = 1;
334
+ return;
335
+ }
336
+ i++;
337
+ }
338
+ else if (argv[i] === "--dry-run") {
339
+ dryRun = true;
340
+ }
341
+ else if (argv[i] === "--execute") {
342
+ executeExternal = true;
343
+ }
344
+ }
345
+ if (command === "setup") {
346
+ await runSetup({ vault, yes, installClaude });
347
+ }
348
+ else if (command === "install" || command === "uninstall") {
349
+ const selectedRuntime = runtime ?? (command === "install" ? "auto" : "all");
350
+ if (command === "uninstall" && !yes && !dryRun && process.env["OMS_NON_INTERACTIVE"] !== "1") {
351
+ console.error("[oms] Refusing uninstall without --yes or --dry-run.");
352
+ process.exitCode = 1;
353
+ return;
354
+ }
355
+ const results = await runHostOperation({
356
+ action: command,
357
+ runtime: selectedRuntime,
358
+ vault,
359
+ dryRun,
360
+ executeExternal,
361
+ yes,
362
+ adapterRoot: bundledAdapterRoot(),
363
+ });
364
+ console.log(formatHostOperationResults(results, dryRun));
365
+ }
366
+ else if (command === "doctor") {
367
+ process.exitCode = await runDoctor({ vault });
368
+ }
369
+ else if (command === "mcp") {
370
+ await runMcpServer({ vault });
371
+ }
372
+ else {
373
+ printUsage();
374
+ process.exitCode = 0;
375
+ }
376
+ }
377
+ // Guard: only run main() when this file is the entry point.
378
+ // Works for both source (`src/cli/oms.ts`) and built (`dist/cli/oms.js`) paths.
379
+ const __filename = fileURLToPath(import.meta.url);
380
+ function sameEntrypoint(left, right) {
381
+ const resolvedLeft = path.resolve(left);
382
+ const resolvedRight = path.resolve(right);
383
+ if (resolvedLeft === resolvedRight)
384
+ return true;
385
+ try {
386
+ return realpathSync(resolvedLeft) === realpathSync(resolvedRight);
387
+ }
388
+ catch {
389
+ return false;
390
+ }
391
+ }
392
+ const isMain = process.argv[1] !== undefined &&
393
+ (sameEntrypoint(process.argv[1], __filename) ||
394
+ sameEntrypoint(process.argv[1], __filename.replace(/\.ts$/, ".js")));
395
+ if (isMain) {
396
+ main().catch((err) => {
397
+ console.error("[oms] Fatal error:", err);
398
+ process.exitCode = 1;
399
+ });
400
+ }
401
+ //# sourceMappingURL=oms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oms.js","sourceRoot":"","sources":["../../src/cli/oms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Split a markdown document into its YAML frontmatter and body.
3
+ *
4
+ * Recognizes the standard Obsidian/Jekyll fence: a `---` line at the very start
5
+ * of the file, the YAML block, then a closing `---` line.
6
+ */
7
+ export interface ParsedNote {
8
+ /** Parsed frontmatter as a plain object. Empty object when no frontmatter. */
9
+ frontmatter: Record<string, unknown>;
10
+ /** The markdown body after the closing fence (or the whole doc if no fence). */
11
+ body: string;
12
+ /** Whether a frontmatter block was present. */
13
+ hasFrontmatter: boolean;
14
+ }
15
+ export declare function parseNote(raw: string): ParsedNote;
@@ -0,0 +1,23 @@
1
+ import { parse as parseYaml } from "yaml";
2
+ const FENCE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
3
+ export function parseNote(raw) {
4
+ // Only treat as frontmatter if the document opens with the fence.
5
+ if (!raw.startsWith("---")) {
6
+ return { frontmatter: {}, body: raw, hasFrontmatter: false };
7
+ }
8
+ const match = FENCE.exec(raw);
9
+ if (!match) {
10
+ return { frontmatter: {}, body: raw, hasFrontmatter: false };
11
+ }
12
+ const yamlText = match[1] ?? "";
13
+ const parsed = parseYaml(yamlText);
14
+ const frontmatter = parsed && typeof parsed === "object" && !Array.isArray(parsed)
15
+ ? parsed
16
+ : {};
17
+ return {
18
+ frontmatter,
19
+ body: raw.slice(match[0].length),
20
+ hasFrontmatter: true,
21
+ };
22
+ }
23
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/conventions/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAiB1C,MAAM,KAAK,GAAG,mCAAmC,CAAC;AAElD,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,kEAAkE;IAClE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;IAC/D,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;IAC/D,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,WAAW,GACf,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAC5D,CAAC,CAAE,MAAkC;QACrC,CAAC,CAAC,EAAE,CAAC;IACT,OAAO;QACL,WAAW;QACX,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAChC,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { Concept } from "../ontology/types.js";
2
+ export type ViolationRule = "required" | "type" | "immutable";
3
+ export interface Violation {
4
+ field: string;
5
+ rule: ViolationRule;
6
+ message: string;
7
+ }
8
+ export interface ValidationResult {
9
+ valid: boolean;
10
+ violations: Violation[];
11
+ }
12
+ /**
13
+ * Validate a note's frontmatter against a declared Concept.
14
+ *
15
+ * Rules:
16
+ * - required: field absent or empty → Violation{rule:"required"}
17
+ * - type: field present and non-empty, but wrong type → Violation{rule:"type"}
18
+ * - immutable: intentionally suppressed in v0 (no baseline exists; union member
19
+ * kept for forward-compatibility with v1 delta-tracking).
20
+ * - Undeclared frontmatter keys → NO violation (additionalProperties: preserve).
21
+ *
22
+ * NEVER throws. valid = violations.length === 0.
23
+ */
24
+ export declare function validateFrontmatter(frontmatter: Record<string, unknown>, concept: Concept): ValidationResult;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Check whether a value is "empty" for the purposes of the `required` rule.
3
+ * A value is empty if it is undefined, null, an empty string, or an empty array.
4
+ */
5
+ function isEmpty(value) {
6
+ if (value === undefined || value === null)
7
+ return true;
8
+ if (typeof value === "string" && value.trim() === "")
9
+ return true;
10
+ if (Array.isArray(value) && value.length === 0)
11
+ return true;
12
+ return false;
13
+ }
14
+ /**
15
+ * Check whether a value matches the declared FieldType.
16
+ */
17
+ function matchesType(value, field) {
18
+ switch (field.type) {
19
+ case "string":
20
+ return typeof value === "string";
21
+ case "number":
22
+ return typeof value === "number";
23
+ case "boolean":
24
+ return typeof value === "boolean";
25
+ case "list":
26
+ return Array.isArray(value);
27
+ case "url": {
28
+ if (typeof value !== "string")
29
+ return false;
30
+ try {
31
+ new URL(value);
32
+ return true;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ case "date": {
39
+ if (value instanceof Date)
40
+ return !isNaN(value.getTime());
41
+ if (typeof value === "string") {
42
+ // Accept YYYY-MM-DD and anything Date() parses to a valid date.
43
+ if (!/\S/.test(value))
44
+ return false;
45
+ const d = new Date(value);
46
+ return !isNaN(d.getTime());
47
+ }
48
+ return false;
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Validate a note's frontmatter against a declared Concept.
54
+ *
55
+ * Rules:
56
+ * - required: field absent or empty → Violation{rule:"required"}
57
+ * - type: field present and non-empty, but wrong type → Violation{rule:"type"}
58
+ * - immutable: intentionally suppressed in v0 (no baseline exists; union member
59
+ * kept for forward-compatibility with v1 delta-tracking).
60
+ * - Undeclared frontmatter keys → NO violation (additionalProperties: preserve).
61
+ *
62
+ * NEVER throws. valid = violations.length === 0.
63
+ */
64
+ export function validateFrontmatter(frontmatter, concept) {
65
+ const violations = [];
66
+ for (const field of concept.fields) {
67
+ const value = frontmatter[field.name];
68
+ if (field.required && isEmpty(value)) {
69
+ violations.push({
70
+ field: field.name,
71
+ rule: "required",
72
+ message: `Required field "${field.name}" is absent or empty.`,
73
+ });
74
+ // Skip type check — nothing to check if the value is absent/empty.
75
+ continue;
76
+ }
77
+ // Type-check only if the value is present and non-empty.
78
+ if (!isEmpty(value) && !matchesType(value, field)) {
79
+ violations.push({
80
+ field: field.name,
81
+ rule: "type",
82
+ message: `Field "${field.name}" expected type "${field.type}" but received ${Array.isArray(value) ? "array" : typeof value}.`,
83
+ });
84
+ }
85
+ }
86
+ return { valid: violations.length === 0, violations };
87
+ }
88
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/conventions/validate.ts"],"names":[],"mappings":"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"}