lobsidian 1.0.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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +15 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/init.d.ts +2 -0
  7. package/dist/commands/init.js +24 -0
  8. package/dist/commands/init.js.map +1 -0
  9. package/dist/commands/validate.d.ts +2 -0
  10. package/dist/commands/validate.js +35 -0
  11. package/dist/commands/validate.js.map +1 -0
  12. package/dist/lib/content.d.ts +11 -0
  13. package/dist/lib/content.js +80 -0
  14. package/dist/lib/content.js.map +1 -0
  15. package/dist/lib/frontmatter.d.ts +29 -0
  16. package/dist/lib/frontmatter.js +372 -0
  17. package/dist/lib/frontmatter.js.map +1 -0
  18. package/dist/lib/scaffold.d.ts +7 -0
  19. package/dist/lib/scaffold.js +105 -0
  20. package/dist/lib/scaffold.js.map +1 -0
  21. package/dist/lib/slug.d.ts +13 -0
  22. package/dist/lib/slug.js +96 -0
  23. package/dist/lib/slug.js.map +1 -0
  24. package/dist/lib/validate/checks.d.ts +23 -0
  25. package/dist/lib/validate/checks.js +777 -0
  26. package/dist/lib/validate/checks.js.map +1 -0
  27. package/dist/lib/validate/fix.d.ts +7 -0
  28. package/dist/lib/validate/fix.js +75 -0
  29. package/dist/lib/validate/fix.js.map +1 -0
  30. package/dist/lib/validate/index.d.ts +37 -0
  31. package/dist/lib/validate/index.js +88 -0
  32. package/dist/lib/validate/index.js.map +1 -0
  33. package/dist/lib/validate/report.d.ts +3 -0
  34. package/dist/lib/validate/report.js +77 -0
  35. package/dist/lib/validate/report.js.map +1 -0
  36. package/dist/lib/vault.d.ts +28 -0
  37. package/dist/lib/vault.js +119 -0
  38. package/dist/lib/vault.js.map +1 -0
  39. package/dist/lib/wikilink.d.ts +45 -0
  40. package/dist/lib/wikilink.js +156 -0
  41. package/dist/lib/wikilink.js.map +1 -0
  42. package/embedded/agent.md +91 -0
  43. package/embedded/config.md.tmpl +48 -0
  44. package/embedded/dashboard.md +35 -0
  45. package/embedded/domains/default.md.tmpl +44 -0
  46. package/embedded/examples/example-cdn-caching.md +53 -0
  47. package/embedded/examples/example-configure-cloudfront.md +56 -0
  48. package/embedded/examples/example-website-performance.md +36 -0
  49. package/embedded/gitignore +4 -0
  50. package/embedded/procedures/cascade.md +33 -0
  51. package/embedded/procedures/context-extraction.md +43 -0
  52. package/embedded/procedures/facilitation.md +43 -0
  53. package/embedded/procedures/review-cycle.md +47 -0
  54. package/embedded/start-here.md +60 -0
  55. package/embedded/templates/decision.md +29 -0
  56. package/embedded/templates/domain.md +46 -0
  57. package/embedded/templates/log.md +12 -0
  58. package/embedded/templates/motive.md +25 -0
  59. package/embedded/templates/note.md +13 -0
  60. package/embedded/templates/task.md +39 -0
  61. package/package.json +50 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lobsidian Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ <p align="center">
2
+ <img src="assets/logo.jpg" alt="Lobsidian" width="480">
3
+ </p>
4
+
5
+ # Lobsidian
6
+
7
+ [![npm version](https://img.shields.io/npm/v/lobsidian.svg)](https://www.npmjs.com/package/lobsidian)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
9
+
10
+ **Structured accountability for AI agents.** Plain markdown files that are simultaneously the agent's memory and the team's knowledge base.
11
+
12
+ ## Quick Start
13
+
14
+ ```bash
15
+ npx lobsidian init ./my-project
16
+ ```
17
+
18
+ That's it. Open `my-project/Start Here.md` to see what was created, or point an AI agent at `my-project/_lobsidian/AGENT.md` and it immediately knows how to operate.
19
+
20
+ To install globally:
21
+
22
+ ```bash
23
+ npm install -g lobsidian
24
+ ```
25
+
26
+ Requires Node.js 18+.
27
+
28
+ ## Why Lobsidian?
29
+
30
+ Existing AI memory tools (Mem0, Zep, Letta) solve what an agent can *recall*. Lobsidian solves what an agent is *accountable for* -- who delegated that authority, and how improvements surface.
31
+
32
+ Give an AI agent access to files and it will *do things*. But:
33
+
34
+ - **Who said it should?** No record of why work was started or who approved it.
35
+ - **Is it working?** No success criteria, no review dates, no feedback loop.
36
+ - **What's the scope?** Agents drift. Without boundaries, they reorganize your entire vault.
37
+ - **Where's the audit trail?** Actions happen, but the reasoning disappears with the conversation.
38
+
39
+ Lobsidian fixes this with a simple protocol: every piece of work traces a chain from **motive** (why) to **decision** (what, with human consent) to **task** (concrete work, with outcome). Decisions carry review dates, closing the loop.
40
+
41
+ ## How It Works
42
+
43
+ ```
44
+ MOTIVE (why) "Website is slow, losing visitors"
45
+ |
46
+ DECISION (what) "Implement CDN caching"
47
+ | success_criteria: "Lighthouse > 90"
48
+ | review_date: 2026-05-20
49
+ | status: proposed -> [human consents] -> active
50
+ |
51
+ TASK (work) "Configure CloudFront distribution"
52
+ | assignee: my-agent
53
+ | outcome: "Lighthouse 94, load time 1.4s"
54
+ |
55
+ REVIEW Is the motive still relevant?
56
+ Did the decision meet its criteria?
57
+ ```
58
+
59
+ Every file is a markdown file with YAML frontmatter. Frontmatter is the API. Folders are human convenience.
60
+
61
+ ## Usage
62
+
63
+ ### Create a Vault
64
+
65
+ ```bash
66
+ lobsidian init ./my-project
67
+ ```
68
+
69
+ The path is where Lobsidian creates the vault structure. Use any directory -- `./my-project`, `/path/to/vault`, or `.` for the current directory.
70
+
71
+ Options:
72
+ - `--name "My Project"` -- vault display name (defaults to directory name)
73
+ - `--agent "my-agent"` -- default agent name (defaults to "agent")
74
+
75
+ This creates:
76
+ ```
77
+ my-project/
78
+ _lobsidian/ # System files (agent skill, config, templates, procedures)
79
+ Motives/ # Why something needs attention
80
+ Decisions/ # What was decided and why
81
+ Tasks/ # Concrete work items
82
+ Knowledge/ # Reference material and notes
83
+ Journal/ # Chronological entries
84
+ Inbox/ # Unprocessed items
85
+ Archive/ # Completed items (nothing is deleted)
86
+ Start Here.md # Orientation guide
87
+ .gitignore
88
+ ```
89
+
90
+ ### Validate a Vault
91
+
92
+ ```bash
93
+ lobsidian validate ./my-project
94
+ # OK 7 files checked, 0 errors, 0 warnings
95
+
96
+ lobsidian validate ./my-project --fix # Auto-fix: stale claims, orphaned tasks
97
+ lobsidian validate ./my-project --json # Machine-readable output
98
+ ```
99
+
100
+ 21 checks covering frontmatter schemas, broken wiki-links, circular references, consent bypasses, overdue reviews, and more.
101
+
102
+ ### Connect an Agent
103
+
104
+ **Agent Skills (recommended):**
105
+ If your platform supports [Agent Skills](https://agentskills.io), Lobsidian ships a skill file at `skills/lobsidian/SKILL.md`. No extra configuration needed -- the agent discovers it automatically.
106
+
107
+ **Manual one-liner:**
108
+ ```bash
109
+ lobsidian init ./my-project --print-shim
110
+ ```
111
+ Outputs a shim you can paste into your agent's startup context (e.g. `CLAUDE.md`, `.cursorrules`).
112
+
113
+ **Direct context injection:**
114
+ Load `_lobsidian/AGENT.md` (~1,500 tokens) into the agent's system prompt or context window. Set `LOBSIDIAN_AGENT_NAME` env var for identity.
115
+
116
+ ### Integration Contract
117
+
118
+ - **File access:** read/write to the vault directory (plain markdown files only)
119
+ - **Startup context:** load `_lobsidian/AGENT.md` (~1,500 tokens) at agent startup
120
+ - **Quick setup:** `lobsidian init --print-shim` outputs a one-liner for agent config files
121
+
122
+ ## What Makes This Different
123
+
124
+ **No infrastructure.** No databases, no servers, no vector stores. Just markdown files on disk. Works offline. Works with git.
125
+
126
+ **Self-documenting agents.** An agent reads one file (`_lobsidian/AGENT.md`, ~1,500 tokens) and knows the entire protocol. No training, no fine-tuning, no SDK integration.
127
+
128
+ **Consent gates.** Agent-created decisions start as `draft` or `proposed`. An agent *cannot* set `status: active` on its own decisions -- human consent is a hard requirement, not a suggestion.
129
+
130
+ **Review cycles.** Every decision carries a `review_date` and `success_criteria`. When the date arrives, the agent surfaces the review. This is the feedback loop that most AI systems lack entirely.
131
+
132
+ **Domain boundaries.** Each agent operates within a defined domain -- a set of filesystem paths with explicit permissions. Built-in WIP limits prevent agents from claiming everything at once.
133
+
134
+ **Framework-agnostic.** Lobsidian is a convention layer. It works with any agent that can read and write files.
135
+
136
+ **Human-compatible.** Everything is plain markdown. Browse motives in Obsidian. Review decisions in VS Code. Approve tasks in your terminal. The vault works without any agent at all.
137
+
138
+ ## Agent Skill
139
+
140
+ Lobsidian ships an [Agent Skill](https://agentskills.io) at [`skills/lobsidian/SKILL.md`](skills/lobsidian/SKILL.md). Compatible with any platform supporting the Agent Skills standard:
141
+
142
+ - Claude Code
143
+ - OpenAI Codex
144
+ - Gemini CLI
145
+ - Cursor
146
+ - GitHub Copilot
147
+ - OpenClaw / ClawHub
148
+ - Goose
149
+ - Any agent supporting Agent Skills
150
+
151
+ If your platform doesn't support Agent Skills, load `_lobsidian/AGENT.md` directly into the agent's context window.
152
+
153
+ ## The Protocol
154
+
155
+ ### Core Types
156
+
157
+ | Type | Folder | Purpose |
158
+ |------|--------|---------|
159
+ | `motive` | `Motives/` | Why something needs attention (situation + need + effect) |
160
+ | `decision` | `Decisions/` | What was decided, with success criteria and review date |
161
+ | `task` | `Tasks/` | Concrete work with assignee, deliverables, and outcome |
162
+ | `note` | `Knowledge/` | Captured insights and reference material |
163
+ | `log` | `Journal/` | Chronological entries (daily, activity, meeting, reflection) |
164
+ | `domain` | `_lobsidian/domains/` | Agent scope, permissions, and boundaries |
165
+
166
+ ### Status Flows
167
+
168
+ **Motives:** `open` -> `addressed` -> `obsolete`
169
+
170
+ **Decisions:** `draft` -> `proposed` -> `active` -> `under-review` -> `retired` or `superseded`
171
+
172
+ **Tasks:** `pending` -> `claimed` -> `in-progress` -> `done` or `cancelled`
173
+
174
+ ## Spec
175
+
176
+ The full protocol specification is in [`spec.md`](spec.md) (~960 lines). Advanced multi-agent coordination, cascade protocols, and domain emergence are in [`spec-advanced.md`](spec-advanced.md).
177
+
178
+ The spec was developed through 15 expert agent reviews and 67 fixes across 8 versions. Design history is in [`CHANGELOG.md`](CHANGELOG.md).
179
+
180
+ ## Contributing
181
+
182
+ Found a bug or have a suggestion? [Open an issue](https://github.com/cannuri/lobsidian/issues).
183
+
184
+ ## License
185
+
186
+ [MIT](LICENSE)
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { Command } from 'commander';
4
+ import { registerInitCommand } from './commands/init.js';
5
+ import { validateCommand } from './commands/validate.js';
6
+ const require = createRequire(import.meta.url);
7
+ const pkg = require('../package.json');
8
+ const program = new Command()
9
+ .name('lobsidian')
10
+ .description('Lobsidian — markdown-based knowledge protocol for AI agents')
11
+ .version(pkg.version, '-v, --version');
12
+ registerInitCommand(program);
13
+ program.addCommand(validateCommand);
14
+ program.parse();
15
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;KAC1B,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,6DAA6D,CAAC;KAC1E,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AAEzC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AAEpC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerInitCommand(program: Command): void;
@@ -0,0 +1,24 @@
1
+ import { resolve, basename, join } from 'node:path';
2
+ import { defaultVars } from '../lib/content.js';
3
+ import { init, summary } from '../lib/scaffold.js';
4
+ export function registerInitCommand(program) {
5
+ program
6
+ .command('init [path]')
7
+ .description('Scaffold a new Lobsidian vault')
8
+ .option('--name <name>', 'vault name (default: directory basename)')
9
+ .option('--agent <agent>', 'default agent name', 'agent')
10
+ .option('--print-shim', 'output one-liner for agent startup context')
11
+ .action((pathArg, opts) => {
12
+ const target = resolve(pathArg ?? '.');
13
+ const vaultName = opts.name || basename(target);
14
+ const vars = defaultVars(vaultName, opts.agent);
15
+ const result = init(target, vars);
16
+ console.log(summary(result));
17
+ if (opts.printShim) {
18
+ const agentMd = join(target, '_lobsidian', 'AGENT.md');
19
+ console.log(`\nOn startup, read ${agentMd} and follow its conventions.`);
20
+ console.log(`Your Lobsidian agent name is: ${opts.agent}`);
21
+ }
22
+ });
23
+ }
24
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,gCAAgC,CAAC;SAC7C,MAAM,CAAC,eAAe,EAAE,0CAA0C,CAAC;SACnE,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,OAAO,CAAC;SACxD,MAAM,CAAC,cAAc,EAAE,4CAA4C,CAAC;SACpE,MAAM,CAAC,CAAC,OAA2B,EAAE,IAA2D,EAAE,EAAE;QACnG,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC;QAEvC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAE7B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,8BAA8B,CAAC,CAAC;YACzE,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const validateCommand: Command;
@@ -0,0 +1,35 @@
1
+ import { Command } from "commander";
2
+ import { run, formatReport, Severity } from "../lib/validate/index.js";
3
+ export const validateCommand = new Command("validate")
4
+ .description("Check a Lobsidian vault for issues")
5
+ .argument("[path]", "path to vault root", ".")
6
+ .option("--fix", "auto-fix safe issues (stale claims, orphaned tasks)", false)
7
+ .option("--json", "output results as JSON", false)
8
+ .option("--no-color", "disable colored output")
9
+ .option("--quiet", "show summary only", false)
10
+ .action((path, options) => {
11
+ const opts = {
12
+ path,
13
+ fix: options.fix === true,
14
+ json: options.json === true,
15
+ noColor: options.color === false, // commander negates --no-color to color=false
16
+ quiet: options.quiet === true,
17
+ };
18
+ const { findings, fileCount } = run(opts);
19
+ const output = formatReport(findings, fileCount, opts);
20
+ process.stdout.write(output);
21
+ // Exit codes: 0=clean, 1=warnings only, 2=errors
22
+ let hasErrors = false;
23
+ let hasWarnings = false;
24
+ for (const r of findings) {
25
+ if (r.severity === Severity.Error)
26
+ hasErrors = true;
27
+ else if (r.severity === Severity.Warning)
28
+ hasWarnings = true;
29
+ }
30
+ if (hasErrors)
31
+ process.exit(2);
32
+ if (hasWarnings)
33
+ process.exit(1);
34
+ });
35
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEvE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC;KACnD,WAAW,CAAC,oCAAoC,CAAC;KACjD,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,CAAC;KAC7C,MAAM,CAAC,OAAO,EAAE,qDAAqD,EAAE,KAAK,CAAC;KAC7E,MAAM,CAAC,QAAQ,EAAE,wBAAwB,EAAE,KAAK,CAAC;KACjD,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC;KAC9C,MAAM,CAAC,SAAS,EAAE,mBAAmB,EAAE,KAAK,CAAC;KAC7C,MAAM,CAAC,CAAC,IAAY,EAAE,OAAgC,EAAE,EAAE;IACzD,MAAM,IAAI,GAAG;QACX,IAAI;QACJ,GAAG,EAAE,OAAO,CAAC,GAAG,KAAK,IAAI;QACzB,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI;QAC3B,OAAO,EAAE,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE,8CAA8C;QAChF,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI;KAC9B,CAAC;IAEF,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACvD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE7B,iDAAiD;IACjD,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,KAAK;YAAE,SAAS,GAAG,IAAI,CAAC;aAC/C,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,OAAO;YAAE,WAAW,GAAG,IAAI,CAAC;IAC/D,CAAC;IAED,IAAI,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,WAAW;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface TemplateVars {
2
+ vaultName: string;
3
+ agentName: string;
4
+ date: string;
5
+ reviewDate: string;
6
+ }
7
+ export declare function defaultVars(vaultName: string, agentName: string): TemplateVars;
8
+ export declare function render(content: string, vars: TemplateVars, filename: string): string;
9
+ export declare function stripTmplExtension(filename: string): string;
10
+ export declare function readEmbedded(path: string): string;
11
+ export declare function listEmbedded(dir: string): string[];
@@ -0,0 +1,80 @@
1
+ import { readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ // defaultVars returns TemplateVars with sensible defaults.
5
+ export function defaultVars(vaultName, agentName) {
6
+ const now = new Date();
7
+ const review = new Date(now);
8
+ review.setMonth(review.getMonth() + 3);
9
+ const fmt = (d) => d.getFullYear() + '-' +
10
+ String(d.getMonth() + 1).padStart(2, '0') + '-' +
11
+ String(d.getDate()).padStart(2, '0');
12
+ return {
13
+ vaultName,
14
+ agentName,
15
+ date: fmt(now),
16
+ reviewDate: fmt(review),
17
+ };
18
+ }
19
+ // render applies template variables to content if it contains Go-style template syntax.
20
+ // Files ending in .tmpl are always treated as templates.
21
+ // Other files are checked for {{ markers before processing.
22
+ export function render(content, vars, filename) {
23
+ const isTemplate = filename.endsWith('.tmpl');
24
+ if (!isTemplate && !content.includes('{{'))
25
+ return content;
26
+ return content
27
+ .replace(/\{\{\.VaultName\}\}/g, vars.vaultName)
28
+ .replace(/\{\{\.AgentName\}\}/g, vars.agentName)
29
+ .replace(/\{\{\.Date\}\}/g, vars.date)
30
+ .replace(/\{\{\.ReviewDate\}\}/g, vars.reviewDate);
31
+ }
32
+ // stripTmplExtension removes the .tmpl suffix if present.
33
+ export function stripTmplExtension(filename) {
34
+ return filename.endsWith('.tmpl') ? filename.slice(0, -5) : filename;
35
+ }
36
+ // Resolve the path to the embedded/ directory.
37
+ // Works both from source (src/) and compiled (dist/) locations.
38
+ function resolveEmbeddedDir() {
39
+ try {
40
+ // import.meta.url points to dist/lib/content.js or src/lib/content.ts
41
+ // embedded/ is at the package root, so ../../embedded from here
42
+ const thisDir = fileURLToPath(new URL('.', import.meta.url));
43
+ const candidate = resolve(thisDir, '..', '..', 'embedded');
44
+ statSync(candidate);
45
+ return candidate;
46
+ }
47
+ catch {
48
+ // Fallback: walk up from __dirname-like resolution
49
+ const thisDir = fileURLToPath(new URL('.', import.meta.url));
50
+ return resolve(thisDir, '..', '..', 'embedded');
51
+ }
52
+ }
53
+ const embeddedDir = resolveEmbeddedDir();
54
+ // readEmbedded reads a file from the embedded directory.
55
+ // path is relative to embedded/, e.g. "templates/motive.md"
56
+ export function readEmbedded(path) {
57
+ return readFileSync(join(embeddedDir, path), 'utf-8');
58
+ }
59
+ // listEmbedded lists all files under a directory in the embedded filesystem.
60
+ // Returns paths relative to embedded/, e.g. ["templates/motive.md", ...].
61
+ export function listEmbedded(dir) {
62
+ const paths = [];
63
+ const base = join(embeddedDir, dir);
64
+ function walk(current) {
65
+ const entries = readdirSync(current, { withFileTypes: true });
66
+ for (const entry of entries) {
67
+ const full = join(current, entry.name);
68
+ if (entry.isDirectory()) {
69
+ walk(full);
70
+ }
71
+ else {
72
+ // Return path relative to embeddedDir
73
+ paths.push(full.slice(embeddedDir.length + 1));
74
+ }
75
+ }
76
+ }
77
+ walk(base);
78
+ return paths;
79
+ }
80
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/lib/content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export type ContentType = 'motive' | 'decision' | 'task' | 'domain' | 'log' | 'note' | 'config' | 'dashboard' | 'cascade-checkpoint' | 'bootstrap-consent';
2
+ export declare const ALL_TYPES: ContentType[];
3
+ export declare const CORE_TYPES: ContentType[];
4
+ export declare const SYSTEM_TYPES: ContentType[];
5
+ export declare function isKnownType(t: string): t is ContentType;
6
+ export declare enum Severity {
7
+ Warning = 0,
8
+ Error = 1
9
+ }
10
+ export declare function severityString(s: Severity): string;
11
+ export interface ValidationResult {
12
+ severity: Severity;
13
+ path: string;
14
+ line: number;
15
+ message: string;
16
+ }
17
+ export declare class Frontmatter {
18
+ fields: Record<string, unknown>;
19
+ fieldLines: Record<string, number>;
20
+ body: string;
21
+ rawYAML: string;
22
+ constructor(fields: Record<string, unknown>, fieldLines: Record<string, number>, body: string, rawYAML: string);
23
+ type(): ContentType | '';
24
+ getString(key: string): string;
25
+ getStringSlice(key: string): string[] | null;
26
+ }
27
+ export declare function parse(content: string): Frontmatter;
28
+ export declare const EXPECTED_FOLDER: Partial<Record<ContentType, string>>;
29
+ export declare function validate(fm: Frontmatter | null, path: string): ValidationResult[];