ralph-hero-knowledge-index 0.1.11 → 0.1.13
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/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +1 -1
- package/dist/generate-indexes.js +15 -0
- package/dist/generate-indexes.js.map +1 -1
- package/dist/parser.d.ts +3 -1
- package/dist/parser.js +23 -2
- package/dist/parser.js.map +1 -1
- package/package.json +1 -1
- package/skills/setup-obsidian/SKILL.md +3 -1
- package/src/__tests__/generate-indexes.test.ts +65 -0
- package/src/__tests__/parser.test.ts +140 -1
- package/src/generate-indexes.ts +15 -0
- package/src/parser.ts +27 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ralph-knowledge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Knowledge graph for ralph-hero: semantic search, relationship traversal, and document indexing across thoughts/ documents. Optional companion to ralph-hero.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Chad Dubiel",
|
package/.mcp.json
CHANGED
package/dist/generate-indexes.js
CHANGED
|
@@ -39,6 +39,7 @@ export function writeTypeIndex(outDir, type, heading, docs) {
|
|
|
39
39
|
const TYPE_HEADINGS = {
|
|
40
40
|
research: "Research",
|
|
41
41
|
plan: "Plans",
|
|
42
|
+
spec: "Specs",
|
|
42
43
|
idea: "Ideas",
|
|
43
44
|
review: "Reviews",
|
|
44
45
|
report: "Reports",
|
|
@@ -52,6 +53,18 @@ export function writeIssueHubs(outDir, allDocs) {
|
|
|
52
53
|
byIssue.set(doc.githubIssue, list);
|
|
53
54
|
}
|
|
54
55
|
}
|
|
56
|
+
// Secondary pass: index into additional hubs from githubIssues array
|
|
57
|
+
for (const doc of allDocs) {
|
|
58
|
+
for (const issueNum of doc.githubIssues) {
|
|
59
|
+
if (issueNum === doc.githubIssue)
|
|
60
|
+
continue; // already added in primary pass
|
|
61
|
+
const list = byIssue.get(issueNum) ?? [];
|
|
62
|
+
if (!list.includes(doc)) {
|
|
63
|
+
list.push(doc);
|
|
64
|
+
byIssue.set(issueNum, list);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
55
68
|
const issuesDir = join(outDir, "_issues");
|
|
56
69
|
mkdirSync(issuesDir, { recursive: true });
|
|
57
70
|
for (const [issueNum, docs] of byIssue) {
|
|
@@ -112,6 +125,7 @@ export function writeMasterIndex(outDir, allDocs, hasUncategorized = false) {
|
|
|
112
125
|
"## Browse by Type\n",
|
|
113
126
|
"- [[_research]] — Research documents",
|
|
114
127
|
"- [[_plans]] — Implementation plans",
|
|
128
|
+
"- [[_specs]] — Specifications",
|
|
115
129
|
"- [[_ideas]] — Ideas and drafts",
|
|
116
130
|
"- [[_reviews]] — Code and plan reviews",
|
|
117
131
|
"- [[_reports]] — Status reports",
|
|
@@ -223,6 +237,7 @@ WHERE !contains(rows.type, "plan")
|
|
|
223
237
|
const TYPE_INDEX_CONFIG = [
|
|
224
238
|
{ type: "research", filename: "research", heading: "Research Documents" },
|
|
225
239
|
{ type: "plan", filename: "plans", heading: "Implementation Plans" },
|
|
240
|
+
{ type: "spec", filename: "specs", heading: "Specifications" },
|
|
226
241
|
{ type: "idea", filename: "ideas", heading: "Ideas & Drafts" },
|
|
227
242
|
{ type: "review", filename: "reviews", heading: "Reviews" },
|
|
228
243
|
{ type: "report", filename: "reports", heading: "Reports" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-indexes.js","sourceRoot":"","sources":["../src/generate-indexes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AAGlD,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,OAAO,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAA+B;IACzD,OAAO,QAAQ,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,IAAY,EACZ,OAAe,EACf,IAAsB;IAEtB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;IAEjE,MAAM,UAAU,GAAG,CAAC,CAAiB,EAAE,CAAiB,EAAE,EAAE,CAC1D,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxB,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAE5B,MAAM,KAAK,GAAa;QACtB,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAChF,KAAK,OAAO,IAAI;KACjB,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC1B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,KAAK,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC9B,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,MAAM,eAAe,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC;YAClF,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,QAAQ,eAAe,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1E,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,EAAE,OAAO,KAAK,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,KAAK,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,aAAa,GAA2B;IAC5C,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,OAAO;IACb,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;CAClB,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAAyB;IACtE,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IACpD,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,GAAG,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;YAChD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,GAAG,iBAAiB,CAAC,QAAQ,CAAC,KAAK,CAAC;QACrD,MAAM,KAAK,GAAa;YACtB,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACxG,QAAQ,QAAQ,IAAI;SACrB,CAAC;QAEF,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;QACnD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC;YAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtB,CAAC;QAED,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpC,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;gBAC9B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;oBAC3B,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC/C,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QAED,gFAAgF;QAChF,MAAM,SAAS,GAAqB,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC;YACtC,IAAI,IAAI,KAAK,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC;gBAAE,SAAS;YACtD,SAAS,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACzB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC5B,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;YAC/C,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QACrD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YACjC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC;YACpD,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QAED,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,OAAyB,EAAE,gBAAgB,GAAG,KAAK;IAClG,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IACvF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IAE7C,MAAM,KAAK,GAAa;QACtB,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAChF,qBAAqB;QACrB,qBAAqB;QACrB,sCAAsC;QACtC,qCAAqC;QACrC,iCAAiC;QACjC,wCAAwC;QACxC,iCAAiC;QACjC,0CAA0C;KAC3C,CAAC;IACF,IAAI,gBAAgB,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;IAC/D,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACpC,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,MAAM,IAAI,GAAG,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,OAAO,GAAG,GAAG,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoFpG,CAAC;IAEA,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,iBAAiB,GAA+D;IACpF,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,oBAAoB,EAAE;IACzE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE;IACpE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE;IAC9D,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE;IAC3D,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE;CAC5D,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,OAAyB;IACvE,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,iBAAiB,EAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACxD,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,6DAA6D;IAC7D,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClH,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,yBAAyB,EAAE,aAAa,CAAC,CAAC;IACpF,CAAC;IAED,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5D,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC"}
|
|
1
|
+
{"version":3,"file":"generate-indexes.js","sourceRoot":"","sources":["../src/generate-indexes.ts"],"names":[],"mappings":"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"}
|
package/dist/parser.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface Relationship {
|
|
2
2
|
sourceId: string;
|
|
3
3
|
targetId: string;
|
|
4
|
-
type: "builds_on" | "tensions" | "superseded_by";
|
|
4
|
+
type: "builds_on" | "tensions" | "superseded_by" | "post_mortem";
|
|
5
5
|
}
|
|
6
6
|
export interface ParsedDocument {
|
|
7
7
|
id: string;
|
|
@@ -11,8 +11,10 @@ export interface ParsedDocument {
|
|
|
11
11
|
type: string | null;
|
|
12
12
|
status: string | null;
|
|
13
13
|
githubIssue: number | null;
|
|
14
|
+
githubIssues: number[];
|
|
14
15
|
tags: string[];
|
|
15
16
|
relationships: Relationship[];
|
|
16
17
|
content: string;
|
|
17
18
|
}
|
|
19
|
+
export declare function inferTypeFromPath(path: string): string | null;
|
|
18
20
|
export declare function parseDocument(id: string, path: string, raw: string): ParsedDocument;
|
package/dist/parser.js
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { parse as parseYaml } from "yaml";
|
|
2
2
|
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---/;
|
|
3
3
|
const TITLE_RE = /^# (.+)$/m;
|
|
4
|
-
const WIKILINK_REL_RE = /^- (builds_on|tensions):: \[\[(.+?)\]\]/gm;
|
|
4
|
+
const WIKILINK_REL_RE = /^- (builds_on|tensions|post_mortem):: \[\[(.+?)\]\]/gm;
|
|
5
5
|
const SUPERSEDED_BY_RE = /\[\[(.+?)\]\]/;
|
|
6
|
+
const PATH_TYPE_MAP = [
|
|
7
|
+
{ segment: "/research/", type: "research" },
|
|
8
|
+
{ segment: "/plans/", type: "plan" },
|
|
9
|
+
{ segment: "/ideas/", type: "idea" },
|
|
10
|
+
{ segment: "/reviews/", type: "review" },
|
|
11
|
+
{ segment: "/reports/", type: "report" },
|
|
12
|
+
];
|
|
13
|
+
export function inferTypeFromPath(path) {
|
|
14
|
+
for (const { segment, type } of PATH_TYPE_MAP) {
|
|
15
|
+
if (path.includes(segment))
|
|
16
|
+
return type;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
6
20
|
export function parseDocument(id, path, raw) {
|
|
7
21
|
const fmMatch = raw.match(FRONTMATTER_RE);
|
|
8
22
|
const frontmatter = fmMatch ? parseYaml(fmMatch[1]) ?? {} : {};
|
|
@@ -16,6 +30,8 @@ export function parseDocument(id, path, raw) {
|
|
|
16
30
|
relationships.push({
|
|
17
31
|
sourceId: id,
|
|
18
32
|
targetId: match[2],
|
|
33
|
+
// Cast is safe: WIKILINK_REL_RE alternation matches exactly these three types.
|
|
34
|
+
// "superseded_by" is intentionally absent — it is parsed from frontmatter, not body wikilinks.
|
|
19
35
|
type: match[1],
|
|
20
36
|
});
|
|
21
37
|
}
|
|
@@ -30,7 +46,9 @@ export function parseDocument(id, path, raw) {
|
|
|
30
46
|
return {
|
|
31
47
|
id, path, title,
|
|
32
48
|
date: frontmatter.date ? String(frontmatter.date) : null,
|
|
33
|
-
type: frontmatter.type
|
|
49
|
+
type: (typeof frontmatter.type === "string" && frontmatter.type.length > 0)
|
|
50
|
+
? frontmatter.type
|
|
51
|
+
: inferTypeFromPath(path),
|
|
34
52
|
status: frontmatter.status ?? null,
|
|
35
53
|
githubIssue: typeof frontmatter.github_issue === "number"
|
|
36
54
|
? frontmatter.github_issue
|
|
@@ -39,6 +57,9 @@ export function parseDocument(id, path, raw) {
|
|
|
39
57
|
: typeof frontmatter.primary_issue === "number"
|
|
40
58
|
? frontmatter.primary_issue
|
|
41
59
|
: null,
|
|
60
|
+
githubIssues: Array.isArray(frontmatter.github_issues)
|
|
61
|
+
? frontmatter.github_issues.filter((n) => typeof n === "number")
|
|
62
|
+
: [],
|
|
42
63
|
tags, relationships, content: body,
|
|
43
64
|
};
|
|
44
65
|
}
|
package/dist/parser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -53,7 +53,9 @@ Check if `[thoughts-dir]/.obsidian/` exists.
|
|
|
53
53
|
{ "query": "path:_", "color": { "a": 1, "rgb": 8421504 } },
|
|
54
54
|
{ "query": "tag:#research OR type:research", "color": { "a": 1, "rgb": 4474111 } },
|
|
55
55
|
{ "query": "tag:#plan OR type:plan", "color": { "a": 1, "rgb": 4487360 } },
|
|
56
|
-
{ "query": "tag:#idea OR type:idea", "color": { "a": 1, "rgb": 16761095 } }
|
|
56
|
+
{ "query": "tag:#idea OR type:idea", "color": { "a": 1, "rgb": 16761095 } },
|
|
57
|
+
{ "query": "type:report", "color": { "a": 1, "rgb": 16744272 } },
|
|
58
|
+
{ "query": "type:spec", "color": { "a": 1, "rgb": 12517631 } }
|
|
57
59
|
]
|
|
58
60
|
}
|
|
59
61
|
```
|
|
@@ -15,6 +15,7 @@ function makeParsedDoc(overrides: Partial<ParsedDocument>): ParsedDocument {
|
|
|
15
15
|
type: "research",
|
|
16
16
|
status: "draft",
|
|
17
17
|
githubIssue: null,
|
|
18
|
+
githubIssues: [],
|
|
18
19
|
tags: [],
|
|
19
20
|
relationships: [],
|
|
20
21
|
content: "test content",
|
|
@@ -241,6 +242,70 @@ describe("generateIndexes", () => {
|
|
|
241
242
|
const index = readFileSync(join(dir, "_index.md"), "utf-8");
|
|
242
243
|
expect(index).not.toContain("[[_uncategorized]]");
|
|
243
244
|
});
|
|
245
|
+
|
|
246
|
+
it("routes spec docs to _specs.md and not to uncategorized", () => {
|
|
247
|
+
const dir = mkdtempSync(join(tmpdir(), "gen-test-"));
|
|
248
|
+
const docs = [
|
|
249
|
+
makeParsedDoc({ id: "debug-spec", type: "spec", title: "Debug Mode Spec" }),
|
|
250
|
+
makeParsedDoc({ id: "r1", type: "research" }),
|
|
251
|
+
];
|
|
252
|
+
generateIndexes(dir, docs);
|
|
253
|
+
expect(existsSync(join(dir, "_specs.md"))).toBe(true);
|
|
254
|
+
const specs = readFileSync(join(dir, "_specs.md"), "utf-8");
|
|
255
|
+
expect(specs).toContain("[[debug-spec]]");
|
|
256
|
+
expect(existsSync(join(dir, "_uncategorized.md"))).toBe(false);
|
|
257
|
+
const index = readFileSync(join(dir, "_index.md"), "utf-8");
|
|
258
|
+
expect(index).toContain("[[_specs]]");
|
|
259
|
+
expect(index).not.toContain("[[_uncategorized]]");
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe("writeIssueHubs — multi-hub indexing", () => {
|
|
264
|
+
it("indexes a document into all hubs listed in githubIssues", () => {
|
|
265
|
+
const dir = mkdtempSync(join(tmpdir(), "gen-test-"));
|
|
266
|
+
const doc = makeParsedDoc({
|
|
267
|
+
id: "2026-03-19-ralph-team-GH-611-session",
|
|
268
|
+
title: "Team Session Report",
|
|
269
|
+
type: "report",
|
|
270
|
+
githubIssue: 611,
|
|
271
|
+
githubIssues: [611, 612],
|
|
272
|
+
});
|
|
273
|
+
writeIssueHubs(dir, [doc]);
|
|
274
|
+
const hub611 = readFileSync(join(dir, "_issues", "GH-0611.md"), "utf-8");
|
|
275
|
+
const hub612 = readFileSync(join(dir, "_issues", "GH-0612.md"), "utf-8");
|
|
276
|
+
expect(hub611).toContain("[[2026-03-19-ralph-team-GH-611-session]]");
|
|
277
|
+
expect(hub612).toContain("[[2026-03-19-ralph-team-GH-611-session]]");
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it("does not duplicate document in primary hub when githubIssues includes primary", () => {
|
|
281
|
+
const dir = mkdtempSync(join(tmpdir(), "gen-test-"));
|
|
282
|
+
const doc = makeParsedDoc({
|
|
283
|
+
id: "multi-issue-doc",
|
|
284
|
+
title: "Multi Issue Doc",
|
|
285
|
+
githubIssue: 100,
|
|
286
|
+
githubIssues: [100, 200],
|
|
287
|
+
});
|
|
288
|
+
writeIssueHubs(dir, [doc]);
|
|
289
|
+
const hub100 = readFileSync(join(dir, "_issues", "GH-0100.md"), "utf-8");
|
|
290
|
+
// Should appear exactly once, not twice
|
|
291
|
+
const matches = hub100.match(/\[\[multi-issue-doc\]\]/g) ?? [];
|
|
292
|
+
expect(matches).toHaveLength(1);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it("handles document with githubIssues but null githubIssue", () => {
|
|
296
|
+
const dir = mkdtempSync(join(tmpdir(), "gen-test-"));
|
|
297
|
+
const doc = makeParsedDoc({
|
|
298
|
+
id: "array-only-doc",
|
|
299
|
+
title: "Array Only",
|
|
300
|
+
githubIssue: null,
|
|
301
|
+
githubIssues: [300, 301],
|
|
302
|
+
});
|
|
303
|
+
writeIssueHubs(dir, [doc]);
|
|
304
|
+
const hub300 = readFileSync(join(dir, "_issues", "GH-0300.md"), "utf-8");
|
|
305
|
+
const hub301 = readFileSync(join(dir, "_issues", "GH-0301.md"), "utf-8");
|
|
306
|
+
expect(hub300).toContain("[[array-only-doc]]");
|
|
307
|
+
expect(hub301).toContain("[[array-only-doc]]");
|
|
308
|
+
});
|
|
244
309
|
});
|
|
245
310
|
|
|
246
311
|
describe("findMarkdownFiles", () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { parseDocument } from "../parser.js";
|
|
2
|
+
import { parseDocument, inferTypeFromPath } from "../parser.js";
|
|
3
3
|
|
|
4
4
|
const FULL_DOC = `---
|
|
5
5
|
date: 2026-03-08
|
|
@@ -98,6 +98,41 @@ describe("parseDocument", () => {
|
|
|
98
98
|
expect(doc.content).not.toContain("---");
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
+
it("parses post_mortem relationship from Prior Work", () => {
|
|
102
|
+
const raw = `---
|
|
103
|
+
date: 2026-03-18
|
|
104
|
+
type: plan
|
|
105
|
+
github_issue: 600
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
# My Plan
|
|
109
|
+
|
|
110
|
+
## Prior Work
|
|
111
|
+
|
|
112
|
+
- post_mortem:: [[2026-03-19-ralph-team-GH-600-session]]
|
|
113
|
+
`;
|
|
114
|
+
const doc = parseDocument("my-plan", "thoughts/shared/plans/my-plan.md", raw);
|
|
115
|
+
const postMortem = doc.relationships.filter(r => r.type === "post_mortem");
|
|
116
|
+
expect(postMortem).toHaveLength(1);
|
|
117
|
+
expect(postMortem[0].targetId).toBe("2026-03-19-ralph-team-GH-600-session");
|
|
118
|
+
expect(postMortem[0].sourceId).toBe("my-plan");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("does not parse post_mortem from frontmatter superseded_by path", () => {
|
|
122
|
+
// superseded_by is handled separately; post_mortem must come from body inline fields
|
|
123
|
+
const raw = `---
|
|
124
|
+
date: 2026-03-18
|
|
125
|
+
type: plan
|
|
126
|
+
superseded_by: "[[2026-03-19-ralph-team-GH-600-session]]"
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
# My Plan
|
|
130
|
+
`;
|
|
131
|
+
const doc = parseDocument("my-plan", "thoughts/shared/plans/my-plan.md", raw);
|
|
132
|
+
const postMortem = doc.relationships.filter(r => r.type === "post_mortem");
|
|
133
|
+
expect(postMortem).toHaveLength(0);
|
|
134
|
+
});
|
|
135
|
+
|
|
101
136
|
describe("githubIssue fallback chain", () => {
|
|
102
137
|
function makeDoc(frontmatter: string, body = "# Test\n\nContent."): string {
|
|
103
138
|
return `---\n${frontmatter}\n---\n\n${body}`;
|
|
@@ -180,4 +215,108 @@ describe("parseDocument", () => {
|
|
|
180
215
|
expect(doc.githubIssue).toBe(550);
|
|
181
216
|
});
|
|
182
217
|
});
|
|
218
|
+
|
|
219
|
+
describe("githubIssues array", () => {
|
|
220
|
+
function makeDoc(frontmatter: string, body = "# Test\n\nContent."): string {
|
|
221
|
+
return `---\n${frontmatter}\n---\n\n${body}`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
it("populates githubIssues from github_issues array", () => {
|
|
225
|
+
const raw = makeDoc("github_issues: [100, 200, 300]");
|
|
226
|
+
const doc = parseDocument("test", "test.md", raw);
|
|
227
|
+
expect(doc.githubIssues).toEqual([100, 200, 300]);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("filters non-number values from github_issues", () => {
|
|
231
|
+
const raw = makeDoc('github_issues: [100, "bad", 200]');
|
|
232
|
+
const doc = parseDocument("test", "test.md", raw);
|
|
233
|
+
expect(doc.githubIssues).toEqual([100, 200]);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("returns empty array when github_issues is absent", () => {
|
|
237
|
+
const raw = makeDoc("github_issue: 42");
|
|
238
|
+
const doc = parseDocument("test", "test.md", raw);
|
|
239
|
+
expect(doc.githubIssues).toEqual([]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("returns empty array when github_issues is not an array", () => {
|
|
243
|
+
const raw = makeDoc("github_issues: 42");
|
|
244
|
+
const doc = parseDocument("test", "test.md", raw);
|
|
245
|
+
expect(doc.githubIssues).toEqual([]);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("includes all issues in session post-mortem pattern", () => {
|
|
249
|
+
const raw = makeDoc([
|
|
250
|
+
"github_issue: 611",
|
|
251
|
+
"github_issues: [611, 612]",
|
|
252
|
+
].join("\n"));
|
|
253
|
+
const doc = parseDocument("test", "test.md", raw);
|
|
254
|
+
expect(doc.githubIssues).toEqual([611, 612]);
|
|
255
|
+
expect(doc.githubIssue).toBe(611); // primary unchanged
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
describe("inferTypeFromPath", () => {
|
|
261
|
+
it("infers plan from /plans/ segment", () => {
|
|
262
|
+
expect(inferTypeFromPath("thoughts/shared/plans/foo.md")).toBe("plan");
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it("infers research from /research/ segment", () => {
|
|
266
|
+
expect(inferTypeFromPath("thoughts/shared/research/foo.md")).toBe("research");
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("infers report from /reports/ segment", () => {
|
|
270
|
+
expect(inferTypeFromPath("thoughts/shared/reports/foo.md")).toBe("report");
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("infers idea from /ideas/ segment", () => {
|
|
274
|
+
expect(inferTypeFromPath("thoughts/ideas/foo.md")).toBe("idea");
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("returns null for unknown path", () => {
|
|
278
|
+
expect(inferTypeFromPath("thoughts/misc/foo.md")).toBeNull();
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
describe("parseDocument type inference", () => {
|
|
283
|
+
const NO_TYPE_DOC = `---
|
|
284
|
+
date: 2026-03-01
|
|
285
|
+
status: draft
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
# My Plan
|
|
289
|
+
`;
|
|
290
|
+
|
|
291
|
+
const SPEC_DOC = `---
|
|
292
|
+
date: 2026-02-21
|
|
293
|
+
status: draft
|
|
294
|
+
type: spec
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
# Debug Mode Spec
|
|
298
|
+
`;
|
|
299
|
+
|
|
300
|
+
it("infers type from path when frontmatter type is absent", () => {
|
|
301
|
+
const doc = parseDocument("my-plan", "thoughts/shared/plans/my-plan.md", NO_TYPE_DOC);
|
|
302
|
+
expect(doc.type).toBe("plan");
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("preserves frontmatter type: spec without aliasing", () => {
|
|
306
|
+
const doc = parseDocument("debug-spec", "thoughts/shared/plans/debug-spec.md", SPEC_DOC);
|
|
307
|
+
expect(doc.type).toBe("spec");
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("frontmatter type takes priority over path inference", () => {
|
|
311
|
+
// file is in /plans/ but has type: research in frontmatter
|
|
312
|
+
const raw = `---\ndate: 2026-03-01\ntype: research\n---\n\n# Research in plans dir\n`;
|
|
313
|
+
const doc = parseDocument("x", "thoughts/shared/plans/x.md", raw);
|
|
314
|
+
expect(doc.type).toBe("research");
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("returns null when path gives no hint and type is absent", () => {
|
|
318
|
+
const raw = `---\ndate: 2026-03-01\n---\n\n# Mystery\n`;
|
|
319
|
+
const doc = parseDocument("x", "thoughts/misc/x.md", raw);
|
|
320
|
+
expect(doc.type).toBeNull();
|
|
321
|
+
});
|
|
183
322
|
});
|
package/src/generate-indexes.ts
CHANGED
|
@@ -55,6 +55,7 @@ export function writeTypeIndex(
|
|
|
55
55
|
const TYPE_HEADINGS: Record<string, string> = {
|
|
56
56
|
research: "Research",
|
|
57
57
|
plan: "Plans",
|
|
58
|
+
spec: "Specs",
|
|
58
59
|
idea: "Ideas",
|
|
59
60
|
review: "Reviews",
|
|
60
61
|
report: "Reports",
|
|
@@ -70,6 +71,18 @@ export function writeIssueHubs(outDir: string, allDocs: ParsedDocument[]): void
|
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
// Secondary pass: index into additional hubs from githubIssues array
|
|
75
|
+
for (const doc of allDocs) {
|
|
76
|
+
for (const issueNum of doc.githubIssues) {
|
|
77
|
+
if (issueNum === doc.githubIssue) continue; // already added in primary pass
|
|
78
|
+
const list = byIssue.get(issueNum) ?? [];
|
|
79
|
+
if (!list.includes(doc)) {
|
|
80
|
+
list.push(doc);
|
|
81
|
+
byIssue.set(issueNum, list);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
73
86
|
const issuesDir = join(outDir, "_issues");
|
|
74
87
|
mkdirSync(issuesDir, { recursive: true });
|
|
75
88
|
|
|
@@ -138,6 +151,7 @@ export function writeMasterIndex(outDir: string, allDocs: ParsedDocument[], hasU
|
|
|
138
151
|
"## Browse by Type\n",
|
|
139
152
|
"- [[_research]] — Research documents",
|
|
140
153
|
"- [[_plans]] — Implementation plans",
|
|
154
|
+
"- [[_specs]] — Specifications",
|
|
141
155
|
"- [[_ideas]] — Ideas and drafts",
|
|
142
156
|
"- [[_reviews]] — Code and plan reviews",
|
|
143
157
|
"- [[_reports]] — Status reports",
|
|
@@ -254,6 +268,7 @@ WHERE !contains(rows.type, "plan")
|
|
|
254
268
|
const TYPE_INDEX_CONFIG: Array<{ type: string; filename: string; heading: string }> = [
|
|
255
269
|
{ type: "research", filename: "research", heading: "Research Documents" },
|
|
256
270
|
{ type: "plan", filename: "plans", heading: "Implementation Plans" },
|
|
271
|
+
{ type: "spec", filename: "specs", heading: "Specifications" },
|
|
257
272
|
{ type: "idea", filename: "ideas", heading: "Ideas & Drafts" },
|
|
258
273
|
{ type: "review", filename: "reviews", heading: "Reviews" },
|
|
259
274
|
{ type: "report", filename: "reports", heading: "Reports" },
|
package/src/parser.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { parse as parseYaml } from "yaml";
|
|
|
3
3
|
export interface Relationship {
|
|
4
4
|
sourceId: string;
|
|
5
5
|
targetId: string;
|
|
6
|
-
type: "builds_on" | "tensions" | "superseded_by";
|
|
6
|
+
type: "builds_on" | "tensions" | "superseded_by" | "post_mortem";
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export interface ParsedDocument {
|
|
@@ -14,6 +14,7 @@ export interface ParsedDocument {
|
|
|
14
14
|
type: string | null;
|
|
15
15
|
status: string | null;
|
|
16
16
|
githubIssue: number | null;
|
|
17
|
+
githubIssues: number[];
|
|
17
18
|
tags: string[];
|
|
18
19
|
relationships: Relationship[];
|
|
19
20
|
content: string;
|
|
@@ -21,9 +22,24 @@ export interface ParsedDocument {
|
|
|
21
22
|
|
|
22
23
|
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---/;
|
|
23
24
|
const TITLE_RE = /^# (.+)$/m;
|
|
24
|
-
const WIKILINK_REL_RE = /^- (builds_on|tensions):: \[\[(.+?)\]\]/gm;
|
|
25
|
+
const WIKILINK_REL_RE = /^- (builds_on|tensions|post_mortem):: \[\[(.+?)\]\]/gm;
|
|
25
26
|
const SUPERSEDED_BY_RE = /\[\[(.+?)\]\]/;
|
|
26
27
|
|
|
28
|
+
const PATH_TYPE_MAP: Array<{ segment: string; type: string }> = [
|
|
29
|
+
{ segment: "/research/", type: "research" },
|
|
30
|
+
{ segment: "/plans/", type: "plan" },
|
|
31
|
+
{ segment: "/ideas/", type: "idea" },
|
|
32
|
+
{ segment: "/reviews/", type: "review" },
|
|
33
|
+
{ segment: "/reports/", type: "report" },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export function inferTypeFromPath(path: string): string | null {
|
|
37
|
+
for (const { segment, type } of PATH_TYPE_MAP) {
|
|
38
|
+
if (path.includes(segment)) return type;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
27
43
|
export function parseDocument(id: string, path: string, raw: string): ParsedDocument {
|
|
28
44
|
const fmMatch = raw.match(FRONTMATTER_RE);
|
|
29
45
|
const frontmatter = fmMatch ? parseYaml(fmMatch[1]) ?? {} : {};
|
|
@@ -38,7 +54,9 @@ export function parseDocument(id: string, path: string, raw: string): ParsedDocu
|
|
|
38
54
|
relationships.push({
|
|
39
55
|
sourceId: id,
|
|
40
56
|
targetId: match[2],
|
|
41
|
-
|
|
57
|
+
// Cast is safe: WIKILINK_REL_RE alternation matches exactly these three types.
|
|
58
|
+
// "superseded_by" is intentionally absent — it is parsed from frontmatter, not body wikilinks.
|
|
59
|
+
type: match[1] as "builds_on" | "tensions" | "post_mortem",
|
|
42
60
|
});
|
|
43
61
|
}
|
|
44
62
|
|
|
@@ -55,7 +73,9 @@ export function parseDocument(id: string, path: string, raw: string): ParsedDocu
|
|
|
55
73
|
return {
|
|
56
74
|
id, path, title,
|
|
57
75
|
date: frontmatter.date ? String(frontmatter.date) : null,
|
|
58
|
-
type: frontmatter.type
|
|
76
|
+
type: (typeof frontmatter.type === "string" && frontmatter.type.length > 0)
|
|
77
|
+
? frontmatter.type
|
|
78
|
+
: inferTypeFromPath(path),
|
|
59
79
|
status: frontmatter.status ?? null,
|
|
60
80
|
githubIssue: typeof frontmatter.github_issue === "number"
|
|
61
81
|
? frontmatter.github_issue
|
|
@@ -64,6 +84,9 @@ export function parseDocument(id: string, path: string, raw: string): ParsedDocu
|
|
|
64
84
|
: typeof frontmatter.primary_issue === "number"
|
|
65
85
|
? frontmatter.primary_issue
|
|
66
86
|
: null,
|
|
87
|
+
githubIssues: Array.isArray(frontmatter.github_issues)
|
|
88
|
+
? frontmatter.github_issues.filter((n: unknown) => typeof n === "number")
|
|
89
|
+
: [],
|
|
67
90
|
tags, relationships, content: body,
|
|
68
91
|
};
|
|
69
92
|
}
|