@warpgogol/forge 0.27.0 → 0.28.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 (46) hide show
  1. package/AGENTS.md +1 -0
  2. package/dist/bin/cli.js +1 -0
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/os/mission/handlers/archive.d.ts.map +1 -1
  5. package/dist/os/mission/handlers/archive.js +77 -5
  6. package/dist/os/mission/handlers/archive.js.map +1 -1
  7. package/dist/os/notes/index.d.ts +2 -0
  8. package/dist/os/notes/index.d.ts.map +1 -0
  9. package/dist/os/notes/index.js +10 -0
  10. package/dist/os/notes/index.js.map +1 -0
  11. package/dist/os/notes/notes.module.d.ts +3 -0
  12. package/dist/os/notes/notes.module.d.ts.map +1 -0
  13. package/dist/os/notes/notes.module.js +83 -0
  14. package/dist/os/notes/notes.module.js.map +1 -0
  15. package/dist/os/rfc/handlers/validate.d.ts.map +1 -1
  16. package/dist/os/rfc/handlers/validate.js +5 -5
  17. package/dist/os/rfc/handlers/validate.js.map +1 -1
  18. package/dist/src/index.d.ts +1 -0
  19. package/dist/src/index.d.ts.map +1 -1
  20. package/dist/src/index.js +1 -0
  21. package/dist/src/index.js.map +1 -1
  22. package/dist/src/onboarding/invariant-engine.d.ts.map +1 -1
  23. package/dist/src/onboarding/invariant-engine.js +137 -5
  24. package/dist/src/onboarding/invariant-engine.js.map +1 -1
  25. package/dist/src/profiles/profile-schema.d.ts +16 -1
  26. package/dist/src/profiles/profile-schema.d.ts.map +1 -1
  27. package/dist/src/profiles/profile-schema.js +16 -1
  28. package/dist/src/profiles/profile-schema.js.map +1 -1
  29. package/dist/src/profiles/stack-profile.d.ts +5 -0
  30. package/dist/src/profiles/stack-profile.d.ts.map +1 -1
  31. package/dist/src/profiles/stack-profile.js +3 -0
  32. package/dist/src/profiles/stack-profile.js.map +1 -1
  33. package/dist/src/validators/note-frontmatter-validate.d.ts +20 -0
  34. package/dist/src/validators/note-frontmatter-validate.d.ts.map +1 -0
  35. package/dist/src/validators/note-frontmatter-validate.js +117 -0
  36. package/dist/src/validators/note-frontmatter-validate.js.map +1 -0
  37. package/dist/src/validators/note-link-validate.d.ts +21 -0
  38. package/dist/src/validators/note-link-validate.d.ts.map +1 -0
  39. package/dist/src/validators/note-link-validate.js +121 -0
  40. package/dist/src/validators/note-link-validate.js.map +1 -0
  41. package/dist/src/validators/note-orphan-detect.d.ts +19 -0
  42. package/dist/src/validators/note-orphan-detect.d.ts.map +1 -0
  43. package/dist/src/validators/note-orphan-detect.js +123 -0
  44. package/dist/src/validators/note-orphan-detect.js.map +1 -0
  45. package/package.json +17 -1
  46. package/profiles/obsidian-vault.yaml +103 -0
@@ -0,0 +1,121 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Validate wikilink integrity across an Obsidian vault — scans [[wikilinks]] and resolves each against the note graph.</purpose>
4
+ <non-goals>
5
+ <item>Do not import from @warpgogol/* — this module is portable.</item>
6
+ <item>Do not implement domain-specific logic beyond wikilink resolution.</item>
7
+ </non-goals>
8
+ </MODULE_CONTRACT>
9
+ <CHANGE_SUMMARY>
10
+ <item>RFC-0808: initial note.link.validate command handler.</item>
11
+ </CHANGE_SUMMARY>
12
+ */
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ import { parse as parseYaml } from "yaml";
16
+ function collectMarkdownFiles(dir, baseDir, results) {
17
+ const SKIP_DIRS = new Set(["node_modules", ".git", ".turbo", "dist", ".cache", ".obsidian"]);
18
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
19
+ for (const entry of entries) {
20
+ if (entry.isDirectory() && SKIP_DIRS.has(entry.name))
21
+ continue;
22
+ const fullPath = path.join(dir, entry.name);
23
+ const relPath = path.relative(baseDir, fullPath).replace(/\\/g, "/");
24
+ if (entry.isDirectory()) {
25
+ collectMarkdownFiles(fullPath, baseDir, results);
26
+ }
27
+ else if (entry.name.endsWith(".md")) {
28
+ results.push(relPath);
29
+ }
30
+ }
31
+ }
32
+ export function runNoteLinkValidate(input, context) {
33
+ const workspaceRoot = context.workspaceRoot ?? process.cwd();
34
+ const vaultDir = input.flags["vault-dir"] ?? "vault";
35
+ const pathFilter = input.flags["path"];
36
+ const scanDir = pathFilter
37
+ ? path.join(workspaceRoot, vaultDir, pathFilter)
38
+ : path.join(workspaceRoot, vaultDir);
39
+ if (!fs.existsSync(scanDir)) {
40
+ return {
41
+ data: {
42
+ command: "note.link.validate",
43
+ violations: [],
44
+ count: 0,
45
+ },
46
+ exitCode: 0,
47
+ summary: "note.link.validate: vault directory not found — 0 violations",
48
+ };
49
+ }
50
+ const allMdFiles = [];
51
+ collectMarkdownFiles(scanDir, workspaceRoot, allMdFiles);
52
+ const noteMap = new Map();
53
+ for (const mdFile of allMdFiles) {
54
+ const basename = path.basename(mdFile, ".md");
55
+ noteMap.set(basename, mdFile);
56
+ const fullPath = path.join(workspaceRoot, mdFile);
57
+ try {
58
+ const content = fs.readFileSync(fullPath, "utf8");
59
+ const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
60
+ if (fmMatch) {
61
+ try {
62
+ const fm = parseYaml(fmMatch[1]);
63
+ if (fm.aliases && Array.isArray(fm.aliases)) {
64
+ for (const alias of fm.aliases) {
65
+ if (typeof alias === "string")
66
+ noteMap.set(alias, mdFile);
67
+ }
68
+ }
69
+ }
70
+ catch {
71
+ // skip malformed frontmatter
72
+ }
73
+ }
74
+ }
75
+ catch {
76
+ // skip unreadable files
77
+ }
78
+ }
79
+ const linkRegex = /\[\[([^\]]+?)\]\]/g;
80
+ const violations = [];
81
+ for (const file of allMdFiles) {
82
+ const fullPath = path.join(workspaceRoot, file);
83
+ try {
84
+ const content = fs.readFileSync(fullPath, "utf8");
85
+ const lines = content.split(/\r?\n/);
86
+ for (let i = 0; i < lines.length; i++) {
87
+ let match;
88
+ linkRegex.lastIndex = 0;
89
+ while ((match = linkRegex.exec(lines[i])) !== null) {
90
+ const linkTarget = match[1].split("|")[0].split("#")[0].trim();
91
+ if (!linkTarget)
92
+ continue;
93
+ if (!noteMap.has(linkTarget)) {
94
+ violations.push({
95
+ file,
96
+ line: i + 1,
97
+ link: match[0],
98
+ rule: "NOTE-01",
99
+ message: `Wikilink target '${linkTarget}' not found in vault`,
100
+ });
101
+ }
102
+ }
103
+ }
104
+ }
105
+ catch {
106
+ // skip unreadable files
107
+ }
108
+ }
109
+ return {
110
+ data: {
111
+ command: "note.link.validate",
112
+ violations,
113
+ count: violations.length,
114
+ },
115
+ exitCode: violations.length > 0 ? 1 : 0,
116
+ summary: violations.length > 0
117
+ ? `note.link.validate: ${violations.length} violation(s) found`
118
+ : "note.link.validate: OK — 0 violations",
119
+ };
120
+ }
121
+ //# sourceMappingURL=note-link-validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-link-validate.js","sourceRoot":"","sources":["../../../src/validators/note-link-validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { ForgeCommandResult } from "../types.ts";
2
+ interface NoteOrphanDetectInput {
3
+ flags: Record<string, unknown>;
4
+ }
5
+ export interface OrphanReport {
6
+ file: string;
7
+ inboundLinks: 0;
8
+ severity: "warning";
9
+ }
10
+ export interface NoteOrphanDetectResult {
11
+ command: "note.orphan.detect";
12
+ orphans: OrphanReport[];
13
+ count: number;
14
+ }
15
+ export declare function runNoteOrphanDetect(input: NoteOrphanDetectInput, context: {
16
+ workspaceRoot?: string;
17
+ }): ForgeCommandResult<NoteOrphanDetectResult>;
18
+ export {};
19
+ //# sourceMappingURL=note-orphan-detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-orphan-detect.d.ts","sourceRoot":"","sources":["../../../src/validators/note-orphan-detect.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,UAAU,qBAAqB;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,CAAC,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAiBD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,qBAAqB,EAC5B,OAAO,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,kBAAkB,CAAC,sBAAsB,CAAC,CA6F5C"}
@@ -0,0 +1,123 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Detect orphan notes in an Obsidian vault — notes with zero inbound wikilinks.</purpose>
4
+ <non-goals>
5
+ <item>Do not import from @warpgogol/* — this module is portable.</item>
6
+ <item>Do not implement domain-specific logic beyond orphan detection.</item>
7
+ </non-goals>
8
+ </MODULE_CONTRACT>
9
+ <CHANGE_SUMMARY>
10
+ <item>RFC-0808: initial note.orphan.detect command handler.</item>
11
+ </CHANGE_SUMMARY>
12
+ */
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ import { parse as parseYaml } from "yaml";
16
+ function collectMarkdownFiles(dir, baseDir, results) {
17
+ const SKIP_DIRS = new Set(["node_modules", ".git", ".turbo", "dist", ".cache", ".obsidian"]);
18
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
19
+ for (const entry of entries) {
20
+ if (entry.isDirectory() && SKIP_DIRS.has(entry.name))
21
+ continue;
22
+ const fullPath = path.join(dir, entry.name);
23
+ const relPath = path.relative(baseDir, fullPath).replace(/\\/g, "/");
24
+ if (entry.isDirectory()) {
25
+ collectMarkdownFiles(fullPath, baseDir, results);
26
+ }
27
+ else if (entry.name.endsWith(".md")) {
28
+ results.push(relPath);
29
+ }
30
+ }
31
+ }
32
+ export function runNoteOrphanDetect(input, context) {
33
+ const workspaceRoot = context.workspaceRoot ?? process.cwd();
34
+ const vaultDir = input.flags["vault-dir"] ?? "vault";
35
+ const scanDir = path.join(workspaceRoot, vaultDir);
36
+ if (!fs.existsSync(scanDir)) {
37
+ return {
38
+ data: {
39
+ command: "note.orphan.detect",
40
+ orphans: [],
41
+ count: 0,
42
+ },
43
+ exitCode: 0,
44
+ summary: "note.orphan.detect: vault directory not found — 0 orphans",
45
+ };
46
+ }
47
+ const allMdFiles = [];
48
+ collectMarkdownFiles(scanDir, workspaceRoot, allMdFiles);
49
+ const noteMap = new Map();
50
+ for (const mdFile of allMdFiles) {
51
+ const basename = path.basename(mdFile, ".md");
52
+ noteMap.set(basename, mdFile);
53
+ const fullPath = path.join(workspaceRoot, mdFile);
54
+ try {
55
+ const content = fs.readFileSync(fullPath, "utf8");
56
+ const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
57
+ if (fmMatch) {
58
+ try {
59
+ const fm = parseYaml(fmMatch[1]);
60
+ if (fm.aliases && Array.isArray(fm.aliases)) {
61
+ for (const alias of fm.aliases) {
62
+ if (typeof alias === "string")
63
+ noteMap.set(alias, mdFile);
64
+ }
65
+ }
66
+ }
67
+ catch {
68
+ // skip malformed frontmatter
69
+ }
70
+ }
71
+ }
72
+ catch {
73
+ // skip unreadable files
74
+ }
75
+ }
76
+ const inboundLinks = new Map();
77
+ for (const mdFile of allMdFiles) {
78
+ inboundLinks.set(mdFile, 0);
79
+ }
80
+ const linkRegex = /\[\[([^\]]+?)\]\]/g;
81
+ for (const file of allMdFiles) {
82
+ const fullPath = path.join(workspaceRoot, file);
83
+ try {
84
+ const content = fs.readFileSync(fullPath, "utf8");
85
+ let match;
86
+ linkRegex.lastIndex = 0;
87
+ while ((match = linkRegex.exec(content)) !== null) {
88
+ const linkTarget = match[1].split("|")[0].split("#")[0].trim();
89
+ if (!linkTarget)
90
+ continue;
91
+ const targetFile = noteMap.get(linkTarget);
92
+ if (targetFile && targetFile !== file) {
93
+ inboundLinks.set(targetFile, (inboundLinks.get(targetFile) ?? 0) + 1);
94
+ }
95
+ }
96
+ }
97
+ catch {
98
+ // skip unreadable files
99
+ }
100
+ }
101
+ const orphans = [];
102
+ for (const [file, count] of inboundLinks) {
103
+ if (count === 0) {
104
+ orphans.push({
105
+ file,
106
+ inboundLinks: 0,
107
+ severity: "warning",
108
+ });
109
+ }
110
+ }
111
+ return {
112
+ data: {
113
+ command: "note.orphan.detect",
114
+ orphans,
115
+ count: orphans.length,
116
+ },
117
+ exitCode: 0,
118
+ summary: orphans.length > 0
119
+ ? `note.orphan.detect: ${orphans.length} orphan(s) found`
120
+ : "note.orphan.detect: OK — 0 orphans",
121
+ };
122
+ }
123
+ //# sourceMappingURL=note-orphan-detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-orphan-detect.js","sourceRoot":"","sources":["../../../src/validators/note-orphan-detect.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warpgogol/forge",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -124,6 +124,14 @@
124
124
  "./os/exploration-module": {
125
125
  "types": "./os/exploration/exploration.module.ts",
126
126
  "default": "./os/exploration/exploration.module.ts"
127
+ },
128
+ "./os/notes": {
129
+ "types": "./os/notes/index.ts",
130
+ "default": "./os/notes/index.ts"
131
+ },
132
+ "./os/notes-module": {
133
+ "types": "./os/notes/notes.module.ts",
134
+ "default": "./os/notes/notes.module.ts"
127
135
  }
128
136
  },
129
137
  "files": [
@@ -268,6 +276,14 @@
268
276
  "./os/exploration-module": {
269
277
  "types": "./dist/os/exploration/exploration.module.d.ts",
270
278
  "default": "./dist/os/exploration/exploration.module.js"
279
+ },
280
+ "./os/notes": {
281
+ "types": "./dist/os/notes/index.d.ts",
282
+ "default": "./dist/os/notes/index.js"
283
+ },
284
+ "./os/notes-module": {
285
+ "types": "./dist/os/notes/notes.module.d.ts",
286
+ "default": "./dist/os/notes/notes.module.js"
271
287
  }
272
288
  }
273
289
  },
@@ -0,0 +1,103 @@
1
+ schema: forge/stack-profile@1
2
+ id: obsidian-vault
3
+ displayName: Obsidian Knowledge Base
4
+ detect:
5
+ anyOf:
6
+ - .obsidian/app.json
7
+ - vault/**/*.md
8
+ domain: knowledge-base
9
+ register: creative
10
+ terminology:
11
+ artifact: note
12
+ artifactPlural: notes
13
+ module: folder
14
+ source: markdown file
15
+ output: export
16
+ verify: link-check
17
+ operator: author
18
+ scriptDir: scripts
19
+ artifacts:
20
+ - id: note
21
+ extensions:
22
+ - .md
23
+ validate:
24
+ command: note.link.validate
25
+ - id: canvas
26
+ extensions:
27
+ - .canvas
28
+ - id: attachment
29
+ extensions:
30
+ - .png
31
+ - .jpg
32
+ - .jpeg
33
+ - .webp
34
+ - .svg
35
+ - .pdf
36
+ - .mp4
37
+ - .webm
38
+ workspaceTypes:
39
+ - id: vault
40
+ detect:
41
+ glob: "**/*.md"
42
+ contains: "---"
43
+ invariants:
44
+ - id: NOTE-01
45
+ rule: All [[wikilinks]] must resolve to an existing note file
46
+ severity: error
47
+ check:
48
+ kind: link-resolution
49
+ glob: "vault/**/*.md"
50
+ - id: NOTE-02
51
+ rule: Every note must have a title in frontmatter (title or first H1)
52
+ severity: warning
53
+ check:
54
+ kind: frontmatter-required
55
+ glob: "vault/**/*.md"
56
+ fields: [title]
57
+ - id: NOTE-03
58
+ rule: No executable code files in vault/ (scripts go to scripts/ per ADR-0043)
59
+ severity: error
60
+ check:
61
+ kind: path-exclusion
62
+ glob: "vault/**/*.{ts,mjs,js,py,sh}"
63
+ - id: NOTE-04
64
+ rule: Note filenames must use kebab-case (lowercase letters, digits, hyphens)
65
+ severity: warning
66
+ check:
67
+ kind: filename-pattern
68
+ glob: "vault/**/*.md"
69
+ pattern: "^[a-z0-9]+(-[a-z0-9]+)*\\.md$"
70
+ workspace:
71
+ dirs:
72
+ - vault
73
+ - scripts
74
+ - .forge
75
+ files:
76
+ - path: .gitignore
77
+ content: |
78
+ node_modules
79
+ .obsidian/workspace
80
+ .obsidian/workspace.json
81
+ .cache
82
+ operator-profile.md
83
+ - path: forge.yaml
84
+ content: |
85
+ schema: forge/config@1
86
+ project:
87
+ name: __PROJECT_NAME__
88
+ stack:
89
+ - obsidian-vault
90
+ packageManager: pnpm
91
+ paths:
92
+ rfcsDir: docs/rfcs
93
+ adrsDir: docs/adrs
94
+ - path: package.json
95
+ content: |
96
+ {
97
+ "name": "__PROJECT_NAME__",
98
+ "version": "0.1.0",
99
+ "private": true,
100
+ "type": "module"
101
+ }
102
+ install:
103
+ - pnpm add -D @warpgogol/forge