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.
- package/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/packages/architecture-generator/dist/adr.d.ts +15 -0
- package/packages/architecture-generator/dist/adr.d.ts.map +1 -0
- package/packages/architecture-generator/dist/adr.js +42 -0
- package/packages/architecture-generator/dist/adr.js.map +1 -0
- package/packages/architecture-generator/dist/index.d.ts +9 -0
- package/packages/architecture-generator/dist/index.d.ts.map +1 -0
- package/packages/architecture-generator/dist/index.js +9 -0
- package/packages/architecture-generator/dist/index.js.map +1 -0
- package/packages/architecture-generator/dist/mermaid.d.ts +30 -0
- package/packages/architecture-generator/dist/mermaid.d.ts.map +1 -0
- package/packages/architecture-generator/dist/mermaid.js +58 -0
- package/packages/architecture-generator/dist/mermaid.js.map +1 -0
- package/packages/architecture-generator/dist/types.d.ts +30 -0
- package/packages/architecture-generator/dist/types.d.ts.map +1 -0
- package/packages/architecture-generator/dist/types.js +7 -0
- package/packages/architecture-generator/dist/types.js.map +1 -0
- package/packages/architecture-generator/src/adr.ts +51 -0
- package/packages/architecture-generator/src/index.ts +9 -0
- package/packages/architecture-generator/src/mermaid.ts +82 -0
- package/packages/architecture-generator/src/types.ts +30 -0
- package/packages/knowledge-graph/dist/graph-extractor.d.ts +27 -0
- package/packages/knowledge-graph/dist/graph-extractor.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/graph-extractor.js +285 -0
- package/packages/knowledge-graph/dist/graph-extractor.js.map +1 -0
- package/packages/knowledge-graph/dist/index.d.ts +27 -0
- package/packages/knowledge-graph/dist/index.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/index.js +27 -0
- package/packages/knowledge-graph/dist/index.js.map +1 -0
- package/packages/knowledge-graph/dist/mcp-client.d.ts +38 -0
- package/packages/knowledge-graph/dist/mcp-client.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/mcp-client.js +157 -0
- package/packages/knowledge-graph/dist/mcp-client.js.map +1 -0
- package/packages/knowledge-graph/dist/provenance-linker.d.ts +19 -0
- package/packages/knowledge-graph/dist/provenance-linker.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/provenance-linker.js +92 -0
- package/packages/knowledge-graph/dist/provenance-linker.js.map +1 -0
- package/packages/knowledge-graph/dist/types.d.ts +53 -0
- package/packages/knowledge-graph/dist/types.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/types.js +7 -0
- package/packages/knowledge-graph/dist/types.js.map +1 -0
- package/packages/knowledge-graph/src/graph-extractor.ts +355 -0
- package/packages/knowledge-graph/src/index.ts +27 -0
- package/packages/knowledge-graph/src/mcp-client.ts +246 -0
- package/packages/knowledge-graph/src/provenance-linker.ts +105 -0
- package/packages/knowledge-graph/src/types.ts +86 -0
- package/packages/milestone-manager/dist/engine.d.ts +27 -0
- package/packages/milestone-manager/dist/engine.d.ts.map +1 -0
- package/packages/milestone-manager/dist/engine.js +80 -0
- package/packages/milestone-manager/dist/engine.js.map +1 -0
- package/packages/milestone-manager/dist/index.d.ts +6 -0
- package/packages/milestone-manager/dist/index.d.ts.map +1 -0
- package/packages/milestone-manager/dist/index.js +6 -0
- package/packages/milestone-manager/dist/index.js.map +1 -0
- package/packages/milestone-manager/dist/types.d.ts +25 -0
- package/packages/milestone-manager/dist/types.d.ts.map +1 -0
- package/packages/milestone-manager/dist/types.js +7 -0
- package/packages/milestone-manager/dist/types.js.map +1 -0
- package/packages/milestone-manager/src/engine.ts +113 -0
- package/packages/milestone-manager/src/index.ts +6 -0
- package/packages/milestone-manager/src/types.ts +28 -0
- package/packages/project-bootstrap/dist/bootstrap.d.ts +23 -0
- package/packages/project-bootstrap/dist/bootstrap.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/bootstrap.js +136 -0
- package/packages/project-bootstrap/dist/bootstrap.js.map +1 -0
- package/packages/project-bootstrap/dist/frappe.d.ts +8 -0
- package/packages/project-bootstrap/dist/frappe.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/frappe.js +82 -0
- package/packages/project-bootstrap/dist/frappe.js.map +1 -0
- package/packages/project-bootstrap/dist/index.d.ts +27 -0
- package/packages/project-bootstrap/dist/index.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/index.js +27 -0
- package/packages/project-bootstrap/dist/index.js.map +1 -0
- package/packages/project-bootstrap/dist/minimal.d.ts +8 -0
- package/packages/project-bootstrap/dist/minimal.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/minimal.js +35 -0
- package/packages/project-bootstrap/dist/minimal.js.map +1 -0
- package/packages/project-bootstrap/dist/types.d.ts +61 -0
- package/packages/project-bootstrap/dist/types.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/types.js +7 -0
- package/packages/project-bootstrap/dist/types.js.map +1 -0
- package/packages/project-bootstrap/dist/typescript.d.ts +8 -0
- package/packages/project-bootstrap/dist/typescript.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/typescript.js +103 -0
- package/packages/project-bootstrap/dist/typescript.js.map +1 -0
- package/packages/project-bootstrap/src/bootstrap.ts +181 -0
- package/packages/project-bootstrap/src/frappe.ts +103 -0
- package/packages/project-bootstrap/src/index.ts +27 -0
- package/packages/project-bootstrap/src/minimal.ts +45 -0
- package/packages/project-bootstrap/src/types.ts +66 -0
- 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":"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"}
|
|
@@ -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 @@
|
|
|
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";
|