pi-harness-runtime 0.10.26 → 0.10.27

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 (92) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/package.json +1 -1
  3. package/packages/architecture-generator/dist/adr.d.ts +15 -0
  4. package/packages/architecture-generator/dist/adr.d.ts.map +1 -0
  5. package/packages/architecture-generator/dist/adr.js +42 -0
  6. package/packages/architecture-generator/dist/adr.js.map +1 -0
  7. package/packages/architecture-generator/dist/index.d.ts +9 -0
  8. package/packages/architecture-generator/dist/index.d.ts.map +1 -0
  9. package/packages/architecture-generator/dist/index.js +9 -0
  10. package/packages/architecture-generator/dist/index.js.map +1 -0
  11. package/packages/architecture-generator/dist/mermaid.d.ts +30 -0
  12. package/packages/architecture-generator/dist/mermaid.d.ts.map +1 -0
  13. package/packages/architecture-generator/dist/mermaid.js +58 -0
  14. package/packages/architecture-generator/dist/mermaid.js.map +1 -0
  15. package/packages/architecture-generator/dist/types.d.ts +30 -0
  16. package/packages/architecture-generator/dist/types.d.ts.map +1 -0
  17. package/packages/architecture-generator/dist/types.js +7 -0
  18. package/packages/architecture-generator/dist/types.js.map +1 -0
  19. package/packages/architecture-generator/src/adr.ts +51 -0
  20. package/packages/architecture-generator/src/index.ts +9 -0
  21. package/packages/architecture-generator/src/mermaid.ts +82 -0
  22. package/packages/architecture-generator/src/types.ts +30 -0
  23. package/packages/knowledge-graph/dist/graph-extractor.d.ts +27 -0
  24. package/packages/knowledge-graph/dist/graph-extractor.d.ts.map +1 -0
  25. package/packages/knowledge-graph/dist/graph-extractor.js +285 -0
  26. package/packages/knowledge-graph/dist/graph-extractor.js.map +1 -0
  27. package/packages/knowledge-graph/dist/index.d.ts +27 -0
  28. package/packages/knowledge-graph/dist/index.d.ts.map +1 -0
  29. package/packages/knowledge-graph/dist/index.js +27 -0
  30. package/packages/knowledge-graph/dist/index.js.map +1 -0
  31. package/packages/knowledge-graph/dist/mcp-client.d.ts +38 -0
  32. package/packages/knowledge-graph/dist/mcp-client.d.ts.map +1 -0
  33. package/packages/knowledge-graph/dist/mcp-client.js +157 -0
  34. package/packages/knowledge-graph/dist/mcp-client.js.map +1 -0
  35. package/packages/knowledge-graph/dist/provenance-linker.d.ts +19 -0
  36. package/packages/knowledge-graph/dist/provenance-linker.d.ts.map +1 -0
  37. package/packages/knowledge-graph/dist/provenance-linker.js +92 -0
  38. package/packages/knowledge-graph/dist/provenance-linker.js.map +1 -0
  39. package/packages/knowledge-graph/dist/types.d.ts +53 -0
  40. package/packages/knowledge-graph/dist/types.d.ts.map +1 -0
  41. package/packages/knowledge-graph/dist/types.js +7 -0
  42. package/packages/knowledge-graph/dist/types.js.map +1 -0
  43. package/packages/knowledge-graph/src/graph-extractor.ts +355 -0
  44. package/packages/knowledge-graph/src/index.ts +27 -0
  45. package/packages/knowledge-graph/src/mcp-client.ts +246 -0
  46. package/packages/knowledge-graph/src/provenance-linker.ts +105 -0
  47. package/packages/knowledge-graph/src/types.ts +86 -0
  48. package/packages/milestone-manager/dist/engine.d.ts +27 -0
  49. package/packages/milestone-manager/dist/engine.d.ts.map +1 -0
  50. package/packages/milestone-manager/dist/engine.js +80 -0
  51. package/packages/milestone-manager/dist/engine.js.map +1 -0
  52. package/packages/milestone-manager/dist/index.d.ts +6 -0
  53. package/packages/milestone-manager/dist/index.d.ts.map +1 -0
  54. package/packages/milestone-manager/dist/index.js +6 -0
  55. package/packages/milestone-manager/dist/index.js.map +1 -0
  56. package/packages/milestone-manager/dist/types.d.ts +25 -0
  57. package/packages/milestone-manager/dist/types.d.ts.map +1 -0
  58. package/packages/milestone-manager/dist/types.js +7 -0
  59. package/packages/milestone-manager/dist/types.js.map +1 -0
  60. package/packages/milestone-manager/src/engine.ts +113 -0
  61. package/packages/milestone-manager/src/index.ts +6 -0
  62. package/packages/milestone-manager/src/types.ts +28 -0
  63. package/packages/project-bootstrap/dist/bootstrap.d.ts +23 -0
  64. package/packages/project-bootstrap/dist/bootstrap.d.ts.map +1 -0
  65. package/packages/project-bootstrap/dist/bootstrap.js +136 -0
  66. package/packages/project-bootstrap/dist/bootstrap.js.map +1 -0
  67. package/packages/project-bootstrap/dist/frappe.d.ts +8 -0
  68. package/packages/project-bootstrap/dist/frappe.d.ts.map +1 -0
  69. package/packages/project-bootstrap/dist/frappe.js +82 -0
  70. package/packages/project-bootstrap/dist/frappe.js.map +1 -0
  71. package/packages/project-bootstrap/dist/index.d.ts +27 -0
  72. package/packages/project-bootstrap/dist/index.d.ts.map +1 -0
  73. package/packages/project-bootstrap/dist/index.js +27 -0
  74. package/packages/project-bootstrap/dist/index.js.map +1 -0
  75. package/packages/project-bootstrap/dist/minimal.d.ts +8 -0
  76. package/packages/project-bootstrap/dist/minimal.d.ts.map +1 -0
  77. package/packages/project-bootstrap/dist/minimal.js +35 -0
  78. package/packages/project-bootstrap/dist/minimal.js.map +1 -0
  79. package/packages/project-bootstrap/dist/types.d.ts +61 -0
  80. package/packages/project-bootstrap/dist/types.d.ts.map +1 -0
  81. package/packages/project-bootstrap/dist/types.js +7 -0
  82. package/packages/project-bootstrap/dist/types.js.map +1 -0
  83. package/packages/project-bootstrap/dist/typescript.d.ts +8 -0
  84. package/packages/project-bootstrap/dist/typescript.d.ts.map +1 -0
  85. package/packages/project-bootstrap/dist/typescript.js +103 -0
  86. package/packages/project-bootstrap/dist/typescript.js.map +1 -0
  87. package/packages/project-bootstrap/src/bootstrap.ts +181 -0
  88. package/packages/project-bootstrap/src/frappe.ts +103 -0
  89. package/packages/project-bootstrap/src/index.ts +27 -0
  90. package/packages/project-bootstrap/src/minimal.ts +45 -0
  91. package/packages/project-bootstrap/src/types.ts +66 -0
  92. package/packages/project-bootstrap/src/typescript.ts +123 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Knowledge Graph - RFC-0106
3
+ *
4
+ * Provenance linking between skills, RFCs, and implementations.
5
+ */
6
+ /**
7
+ * Build provenance edges based on metadata
8
+ */
9
+ export function buildProvenanceEdges(graph) {
10
+ const edges = [];
11
+ const nodeMap = new Map(graph.nodes.map((n) => [n.id, n]));
12
+ for (const node of graph.nodes) {
13
+ if (node.type === "skill" && node.data.tags.includes("implements")) {
14
+ // Link to RFCs found in tags
15
+ const rfcTag = node.data.tags.find((t) => t.startsWith("rfc-"));
16
+ if (rfcTag) {
17
+ edges.push({
18
+ from: node.id,
19
+ to: `rfc:${rfcTag.toUpperCase()}`,
20
+ type: "implements",
21
+ metadata: { source: "tag:implements" },
22
+ });
23
+ }
24
+ }
25
+ // Implementation -> documents -> RFC
26
+ if (node.type === "implementation") {
27
+ const rfcMatch = node.id.match(/implementation:RFC-(\d+)/i);
28
+ if (rfcMatch) {
29
+ edges.push({
30
+ from: node.id,
31
+ to: `rfc:RFC-${rfcMatch[1].padStart(4, "0")}`,
32
+ type: "documents",
33
+ metadata: { source: "id:parsing" },
34
+ });
35
+ }
36
+ }
37
+ }
38
+ return edges;
39
+ }
40
+ /**
41
+ * Infer additional edges from content analysis
42
+ */
43
+ export function inferRelationships(graph) {
44
+ const edges = [];
45
+ // Group skills by shared tags
46
+ const tagGroups = new Map();
47
+ for (const node of graph.nodes) {
48
+ if (node.type !== "skill")
49
+ continue;
50
+ for (const tag of node.data.tags) {
51
+ if (!tagGroups.has(tag)) {
52
+ tagGroups.set(tag, []);
53
+ }
54
+ tagGroups.get(tag).push(node);
55
+ }
56
+ }
57
+ // Skills sharing 3+ tags are related
58
+ for (const [, nodes] of tagGroups) {
59
+ if (nodes.length < 2)
60
+ continue;
61
+ for (let i = 0; i < nodes.length; i++) {
62
+ for (let j = i + 1; j < nodes.length; j++) {
63
+ const sharedTags = nodes[i].data.tags.filter((t) => nodes[j].data.tags.includes(t));
64
+ if (sharedTags.length >= 3) {
65
+ edges.push({
66
+ from: nodes[i].id,
67
+ to: nodes[j].id,
68
+ type: "related_to",
69
+ metadata: {
70
+ source: "inferred:shared-tags",
71
+ confidence: sharedTags.length /
72
+ Math.max(nodes[i].data.tags.length, nodes[j].data.tags.length),
73
+ },
74
+ });
75
+ }
76
+ }
77
+ }
78
+ }
79
+ return edges;
80
+ }
81
+ /**
82
+ * Complete graph with all provenance links
83
+ */
84
+ export function completeGraph(graph) {
85
+ const provenanceEdges = buildProvenanceEdges(graph);
86
+ const inferredEdges = inferRelationships(graph);
87
+ return {
88
+ nodes: graph.nodes,
89
+ edges: [...graph.edges, ...provenanceEdges, ...inferredEdges],
90
+ };
91
+ }
92
+ //# sourceMappingURL=provenance-linker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance-linker.js","sourceRoot":"","sources":["../src/provenance-linker.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAqB;IACzD,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3D,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACpE,6BAA6B;YAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YAChE,IAAI,MAAM,EAAE,CAAC;gBACZ,KAAK,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,IAAI,CAAC,EAAE;oBACb,EAAE,EAAE,OAAO,MAAM,CAAC,WAAW,EAAE,EAAE;oBACjC,IAAI,EAAE,YAAY;oBAClB,QAAQ,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE;iBACtC,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;QAED,qCAAqC;QACrC,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAC5D,IAAI,QAAQ,EAAE,CAAC;gBACd,KAAK,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,IAAI,CAAC,EAAE;oBACb,EAAE,EAAE,WAAW,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;oBAC7C,IAAI,EAAE,WAAW;oBACjB,QAAQ,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE;iBAClC,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAqB;IACvD,MAAM,KAAK,GAAoB,EAAE,CAAC;IAElC,8BAA8B;IAC9B,MAAM,SAAS,GAAG,IAAI,GAAG,EAA2B,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;YAAE,SAAS;QACpC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACxB,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;IACF,CAAC;IAED,qCAAqC;IACrC,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,SAAS,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAClD,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAC9B,CAAC;gBACF,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;oBAC5B,KAAK,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;wBACjB,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;wBACf,IAAI,EAAE,YAAY;wBAClB,QAAQ,EAAE;4BACT,MAAM,EAAE,sBAAsB;4BAC9B,UAAU,EACT,UAAU,CAAC,MAAM;gCACjB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;yBAC/D;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,KAAqB;IAClD,MAAM,eAAe,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAEhD,OAAO;QACN,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,GAAG,eAAe,EAAE,GAAG,aAAa,CAAC;KAC7D,CAAC;AACH,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Knowledge Graph - RFC-0106
3
+ *
4
+ * Typed definitions for knowledge graph nodes and edges.
5
+ */
6
+ export type KnowledgeNodeType = "skill" | "rfc" | "implementation" | "concept" | "api" | "cli" | "pattern" | "workflow";
7
+ export interface KnowledgeNode {
8
+ id: string;
9
+ type: KnowledgeNodeType;
10
+ data: {
11
+ title: string;
12
+ description?: string;
13
+ tags: string[];
14
+ source?: string;
15
+ url?: string;
16
+ };
17
+ }
18
+ export type KnowledgeEdgeType = "implements" | "depends_on" | "supersedes" | "related_to" | "authored_by" | "documents" | "references";
19
+ export interface KnowledgeEdge {
20
+ from: string;
21
+ to: string;
22
+ type: KnowledgeEdgeType;
23
+ metadata?: {
24
+ confidence?: number;
25
+ source?: string;
26
+ };
27
+ }
28
+ export interface KnowledgeGraph {
29
+ nodes: KnowledgeNode[];
30
+ edges: KnowledgeEdge[];
31
+ }
32
+ export interface ProvenanceData {
33
+ implements?: string;
34
+ related_implementation?: string;
35
+ author?: string;
36
+ version?: string;
37
+ }
38
+ export interface SearchResult {
39
+ node: KnowledgeNode;
40
+ score: number;
41
+ highlights?: string[];
42
+ }
43
+ export interface SearchOptions {
44
+ limit?: number;
45
+ type?: KnowledgeNodeType;
46
+ tags?: string[];
47
+ }
48
+ export interface TencentDBConfig {
49
+ knowledgeUrl: string;
50
+ userKey: string;
51
+ serviceId: string;
52
+ }
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,MAAM,iBAAiB,GAC1B,OAAO,GACP,KAAK,GACL,gBAAgB,GAChB,SAAS,GACT,KAAK,GACL,KAAK,GACL,SAAS,GACT,UAAU,CAAC;AAEd,MAAM,WAAW,aAAa;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;KACb,CAAC;CACF;AAID,MAAM,MAAM,iBAAiB,GAC1B,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,WAAW,GACX,YAAY,CAAC;AAEhB,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACF;AAID,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,KAAK,EAAE,aAAa,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAID,MAAM,WAAW,eAAe;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Knowledge Graph - RFC-0106
3
+ *
4
+ * Typed definitions for knowledge graph nodes and edges.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,355 @@
1
+ /**
2
+ * Knowledge Graph - RFC-0106
3
+ *
4
+ * Extract nodes and edges from SKILL.md files.
5
+ */
6
+
7
+ import type {
8
+ KnowledgeNode,
9
+ KnowledgeEdge,
10
+ KnowledgeGraph,
11
+ ProvenanceData,
12
+ } from "./types.js";
13
+
14
+ // Parse frontmatter manually (simplified - full OKF parser in okf-indexer)
15
+ interface OKFDocument {
16
+ title?: string;
17
+ sections: { title?: string; content: string }[];
18
+ }
19
+
20
+ interface SKILLSection {
21
+ title?: string;
22
+ content: string;
23
+ }
24
+
25
+ function parseSKILL(content: string): OKFDocument {
26
+ const sections: OKFDocument["sections"] = [];
27
+ const lines = content.split("\n");
28
+ let currentSection: SKILLSection = { content: "" };
29
+ let inFrontmatter = false;
30
+
31
+ for (const line of lines) {
32
+ if (line.trim() === "---") {
33
+ inFrontmatter = !inFrontmatter;
34
+ continue;
35
+ }
36
+ if (inFrontmatter) continue;
37
+
38
+ if (line.startsWith("## ")) {
39
+ if (currentSection.content) {
40
+ sections.push(currentSection);
41
+ }
42
+ currentSection = { title: line.slice(3), content: "" };
43
+ } else {
44
+ currentSection.content += (currentSection.content ? "\n" : "") + line;
45
+ }
46
+ }
47
+ if (currentSection.content) {
48
+ sections.push(currentSection);
49
+ }
50
+
51
+ const titleMatch = content.match(/^#\s+(.+)$/m);
52
+ return { title: titleMatch?.[1], sections };
53
+ }
54
+
55
+ /**
56
+ * Extract RFC references from content
57
+ */
58
+ function extractRFCRefs(content: string): string[] {
59
+ const rfcPattern = /RFC[- ]?(\d{4})/gi;
60
+ const matches = content.match(rfcPattern) || [];
61
+ return [
62
+ ...new Set(
63
+ matches.map((m) => {
64
+ const num = m.replace(/[^0-9]/g, "");
65
+ return `RFC-${num.padStart(4, "0")}`;
66
+ }),
67
+ ),
68
+ ];
69
+ }
70
+
71
+ /**
72
+ * Extract wiki links from content (e.g., [[skill:xxx]])
73
+ */
74
+ function extractWikiLinks(content: string): string[] {
75
+ const linkPattern = /\[\[([^\]]+)\]\]/g;
76
+ const matches = content.match(linkPattern) || [];
77
+ return matches.map((m) => m.slice(2, -2).trim());
78
+ }
79
+
80
+ /**
81
+ * Extract skill ID from file path
82
+ */
83
+ function extractSkillId(filePath: string): string {
84
+ // Path: .../skills/{skill-id}/SKILL.md
85
+ const match = filePath.match(/skills\/([^/]+)\/SKILL\.md$/i);
86
+ return match
87
+ ? match[1]
88
+ : filePath.split("/").pop()?.replace(".md", "") || "unknown";
89
+ }
90
+
91
+ /**
92
+ * Parse provenance from frontmatter
93
+ */
94
+ function parseProvenance(frontmatter: Record<string, unknown>): ProvenanceData {
95
+ return {
96
+ implements: (frontmatter.provenance as string) || undefined,
97
+ related_implementation:
98
+ (frontmatter.related_implementation as string) || undefined,
99
+ author: (frontmatter.author as string) || undefined,
100
+ version: (frontmatter.version as string) || undefined,
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Extract a knowledge node from a SKILL.md file
106
+ */
107
+ export function extractSkillNode(
108
+ filePath: string,
109
+ content: string,
110
+ frontmatter: Record<string, unknown>,
111
+ ): KnowledgeNode {
112
+ const skillId = extractSkillId(filePath);
113
+ const provenance = parseProvenance(frontmatter);
114
+ const okf = parseSKILL(content);
115
+
116
+ return {
117
+ id: `skill:${skillId}`,
118
+ type: "skill",
119
+ data: {
120
+ title: (frontmatter.title as string) || okf.title || skillId,
121
+ description: okf.sections[0]?.content.slice(0, 200) || undefined,
122
+ tags: (frontmatter.tags as string[]) || [],
123
+ source: filePath,
124
+ },
125
+ };
126
+ }
127
+
128
+ /**
129
+ * Extract edges from a SKILL.md file
130
+ */
131
+ export function extractSkillEdges(
132
+ filePath: string,
133
+ content: string,
134
+ frontmatter: Record<string, unknown>,
135
+ ): KnowledgeEdge[] {
136
+ const skillId = extractSkillId(filePath);
137
+ const provenance = parseProvenance(frontmatter);
138
+ const edges: KnowledgeEdge[] = [];
139
+
140
+ // Provenance: implements RFC
141
+ if (provenance.implements) {
142
+ const rfcNum = provenance.implements
143
+ .replace(/RFC[- ]?/i, "")
144
+ .padStart(4, "0");
145
+ edges.push({
146
+ from: `skill:${skillId}`,
147
+ to: `rfc:RFC-${rfcNum}`,
148
+ type: "implements",
149
+ metadata: { source: "frontmatter:provenance.implements" },
150
+ });
151
+ }
152
+
153
+ // Provenance: documents implementation
154
+ if (provenance.related_implementation) {
155
+ edges.push({
156
+ from: `skill:${skillId}`,
157
+ to: `implementation:${provenance.related_implementation}`,
158
+ type: "documents",
159
+ metadata: { source: "frontmatter:related_implementation" },
160
+ });
161
+ }
162
+
163
+ // Content: RFC references
164
+ const rfcRefs = extractRFCRefs(content);
165
+ for (const rfc of rfcRefs) {
166
+ if (rfc !== provenance.implements) {
167
+ // Don't duplicate
168
+ edges.push({
169
+ from: `skill:${skillId}`,
170
+ to: rfc,
171
+ type: "references",
172
+ metadata: { source: "content:regex" },
173
+ });
174
+ }
175
+ }
176
+
177
+ // Content: wiki links
178
+ const wikiLinks = extractWikiLinks(content);
179
+ for (const link of wikiLinks) {
180
+ if (link.startsWith("skill:")) {
181
+ edges.push({
182
+ from: `skill:${skillId}`,
183
+ to: link,
184
+ type: "related_to",
185
+ metadata: { source: "content:wiki-link" },
186
+ });
187
+ }
188
+ }
189
+
190
+ return edges;
191
+ }
192
+
193
+ /**
194
+ * Extract RFC nodes from RFC markdown files
195
+ */
196
+ export function extractRFCNode(
197
+ filePath: string,
198
+ content: string,
199
+ title: string,
200
+ ): KnowledgeNode {
201
+ // Extract RFC number from filename: RFC-0106_KNOWLEDGE_GRAPH_PROVENANCE.md
202
+ const match = filePath.match(/RFC[- ]?(\d{4})/i);
203
+ const rfcNum = match ? match[1].padStart(4, "0") : "0000";
204
+
205
+ // Extract summary from first paragraph
206
+ const summaryMatch = content.match(/## Summary\n+([^\n]+)/i);
207
+ const summary = summaryMatch ? summaryMatch[1].slice(0, 200) : undefined;
208
+
209
+ // Extract tags from content
210
+ const tagMatches = content.match(/tag[s]?:?\s*\[([^\]]+)\]/i);
211
+ const tags = tagMatches
212
+ ? tagMatches[1].split(",").map((t) => t.trim().toLowerCase())
213
+ : [];
214
+
215
+ return {
216
+ id: `rfc:RFC-${rfcNum}`,
217
+ type: "rfc",
218
+ data: {
219
+ title,
220
+ description: summary,
221
+ tags,
222
+ source: filePath,
223
+ url: `https://github.com/ManotLuijiu/pi-harness-runtime/blob/main/${filePath}`,
224
+ },
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Extract edges between RFCs
230
+ */
231
+ export function extractRFCEdges(
232
+ filePath: string,
233
+ content: string,
234
+ ): KnowledgeEdge[] {
235
+ const edges: KnowledgeEdge[] = [];
236
+
237
+ // RFC references other RFCs
238
+ const rfcRefs = extractRFCRefs(content);
239
+ const match = filePath.match(/RFC[- ]?(\d{4})/i);
240
+ const rfcNum = match ? `RFC-${match[1].padStart(4, "0")}` : "rfc:unknown";
241
+
242
+ for (const ref of rfcRefs) {
243
+ edges.push({
244
+ from: rfcNum,
245
+ to: ref,
246
+ type: "references",
247
+ metadata: { source: "content:regex" },
248
+ });
249
+ }
250
+
251
+ // Supersedes (e.g., "Supersedes RFC-0008")
252
+ const supersedesMatch = content.match(/supersedes\s+RFC[- ]?(\d{4})/gi);
253
+ if (supersedesMatch) {
254
+ for (const match of supersedesMatch) {
255
+ const numMatch = match.match(/\d{4}/);
256
+ if (numMatch) {
257
+ const superseded = `RFC-${numMatch[0].padStart(4, "0")}`;
258
+ edges.push({
259
+ from: rfcNum,
260
+ to: superseded,
261
+ type: "supersedes",
262
+ metadata: { source: "content:supersedes" },
263
+ });
264
+ }
265
+ }
266
+ }
267
+
268
+ return edges;
269
+ }
270
+
271
+ /**
272
+ * Build complete knowledge graph from directory
273
+ */
274
+ export async function extractKnowledgeGraph(
275
+ skillsPath: string,
276
+ rfcPath: string,
277
+ ): Promise<KnowledgeGraph> {
278
+ const { readdir, readFile } = await import("fs/promises");
279
+ const { join } = await import("path");
280
+
281
+ const nodes: KnowledgeNode[] = [];
282
+ const edges: KnowledgeEdge[] = [];
283
+
284
+ // Extract skill nodes and edges
285
+ try {
286
+ const skillDirs = await readdir(skillsPath, { withFileTypes: true });
287
+
288
+ for (const dir of skillDirs) {
289
+ if (!dir.isDirectory()) continue;
290
+
291
+ const skillPath = join(skillsPath, dir.name, "SKILL.md");
292
+ try {
293
+ const content = await readFile(skillPath, "utf-8");
294
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
295
+ const frontmatter: Record<string, unknown> = {};
296
+
297
+ if (frontmatterMatch) {
298
+ for (const line of frontmatterMatch[1].split("\n")) {
299
+ const [key, ...valueParts] = line.split(":");
300
+ if (key && valueParts.length) {
301
+ const value = valueParts.join(":").trim();
302
+ // Handle arrays
303
+ if (value.startsWith("[")) {
304
+ frontmatter[key.trim()] = value
305
+ .slice(1, -1)
306
+ .split(",")
307
+ .map((v) => v.trim().replace(/['"]/g, ""));
308
+ } else {
309
+ frontmatter[key.trim()] = value.replace(/['"]/g, "");
310
+ }
311
+ }
312
+ }
313
+ }
314
+
315
+ const node = extractSkillNode(skillPath, content, frontmatter);
316
+ nodes.push(node);
317
+
318
+ const skillEdges = extractSkillEdges(skillPath, content, frontmatter);
319
+ edges.push(...skillEdges);
320
+ } catch {
321
+ // Skip files that can't be read
322
+ }
323
+ }
324
+ } catch {
325
+ // Skills directory might not exist
326
+ }
327
+
328
+ // Extract RFC nodes and edges
329
+ try {
330
+ const rfcFiles = await readdir(rfcPath);
331
+
332
+ for (const file of rfcFiles) {
333
+ if (!file.match(/^RFC[- ]?\d{4}_.*\.md$/i)) continue;
334
+
335
+ const filePath = join(rfcPath, file);
336
+ const content = await readFile(filePath, "utf-8");
337
+
338
+ // Extract title from first # heading
339
+ const titleMatch = content.match(/^#\s+(.+)$/m);
340
+ const title = titleMatch
341
+ ? titleMatch[1].replace(/^RFC[-\d]+\s*[-–]\s*/, "")
342
+ : file;
343
+
344
+ const node = extractRFCNode(filePath, content, title);
345
+ nodes.push(node);
346
+
347
+ const rfcEdges = extractRFCEdges(filePath, content);
348
+ edges.push(...rfcEdges);
349
+ }
350
+ } catch {
351
+ // RFC directory might not exist
352
+ }
353
+
354
+ return { nodes, edges };
355
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Knowledge Graph - RFC-0106
3
+ *
4
+ * Knowledge Graph extraction and provenance linking for SKILL.md files.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { extractKnowledgeGraph, completeGraph, syncGraphToKnowledgeService } from '@pi-harness/knowledge-graph';
9
+ *
10
+ * // Extract graph from skills directory
11
+ * const graph = await extractKnowledgeGraph(
12
+ * 'frappe-bench/.claude-plugins/moocoding-skills/skills',
13
+ * 'pi-harness-runtime/RFC'
14
+ * );
15
+ *
16
+ * // Complete with provenance edges
17
+ * const fullGraph = completeGraph(graph);
18
+ *
19
+ * // Sync to TencentDB Knowledge Service
20
+ * await syncGraphToKnowledgeService(fullGraph, config);
21
+ * ```
22
+ */
23
+
24
+ export * from "./types.js";
25
+ export * from "./graph-extractor.js";
26
+ export * from "./provenance-linker.js";
27
+ export * from "./mcp-client.js";