@elevasis/core 0.16.0 → 0.17.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.
@@ -0,0 +1,138 @@
1
+ // src/knowledge/queries.ts
2
+ function toGraphNodeId(omNodeId) {
3
+ return `knowledge:${omNodeId}`;
4
+ }
5
+ function buildKnowledgeSourceIdMap(graph) {
6
+ const map = /* @__PURE__ */ new Map();
7
+ for (const node of graph.nodes) {
8
+ if (node.kind === "knowledge" && node.sourceId) {
9
+ map.set(node.id, node.sourceId);
10
+ }
11
+ }
12
+ return map;
13
+ }
14
+ function byFeature(graph, featureId, knowledgeNodes) {
15
+ const targetGraphNodeId = `feature:${featureId}`;
16
+ const governingKnowledgeNodeIds = /* @__PURE__ */ new Set();
17
+ for (const edge of graph.edges) {
18
+ if (edge.kind === "governs" && edge.targetId === targetGraphNodeId && edge.sourceId.startsWith("knowledge:")) {
19
+ governingKnowledgeNodeIds.add(edge.sourceId);
20
+ }
21
+ }
22
+ const sourceIdMap = buildKnowledgeSourceIdMap(graph);
23
+ const matchingOmIds = /* @__PURE__ */ new Set();
24
+ for (const graphNodeId of governingKnowledgeNodeIds) {
25
+ const omId = sourceIdMap.get(graphNodeId);
26
+ if (omId) matchingOmIds.add(omId);
27
+ }
28
+ return knowledgeNodes.filter((n) => matchingOmIds.has(n.id));
29
+ }
30
+ function byKind(_graph, kind, knowledgeNodes) {
31
+ return knowledgeNodes.filter((n) => n.kind === kind);
32
+ }
33
+ function byOwner(_graph, ownerId, knowledgeNodes) {
34
+ return knowledgeNodes.filter((n) => n.ownerIds.includes(ownerId));
35
+ }
36
+ function governs(graph, nodeId) {
37
+ const graphNodeId = nodeId.startsWith("knowledge:") ? nodeId : toGraphNodeId(nodeId);
38
+ const results = [];
39
+ for (const edge of graph.edges) {
40
+ if (edge.kind === "governs" && edge.sourceId === graphNodeId) {
41
+ results.push(edge.targetId);
42
+ }
43
+ }
44
+ return results;
45
+ }
46
+ function governedBy(graph, nodeId) {
47
+ const targetId = nodeId.startsWith("feature:") || nodeId.startsWith("knowledge:") || nodeId.startsWith("resource:") ? nodeId : `feature:${nodeId}`;
48
+ const results = [];
49
+ for (const edge of graph.edges) {
50
+ if (edge.kind === "governs" && edge.targetId === targetId) {
51
+ results.push(edge.sourceId);
52
+ }
53
+ }
54
+ return results;
55
+ }
56
+ function parsePath(pathString) {
57
+ if (!pathString || typeof pathString !== "string") {
58
+ throw new Error("parsePath: path must be a non-empty string");
59
+ }
60
+ if (!pathString.startsWith("/")) {
61
+ throw new Error(`parsePath: path must start with "/", got: "${pathString}"`);
62
+ }
63
+ const normalized = pathString.replace(/\/+$/, "");
64
+ const segments = normalized.split("/").filter((s) => s.length > 0);
65
+ if (segments.length === 0) {
66
+ throw new Error(`parsePath: path resolves to root with no mount: "${pathString}"`);
67
+ }
68
+ const [first, ...rest] = segments;
69
+ if (first === "by-feature") {
70
+ if (rest.length === 0) {
71
+ throw new Error(`parsePath: /by-feature requires a featureId argument, got: "${pathString}"`);
72
+ }
73
+ return { mount: "by-feature", args: [rest.join("/")] };
74
+ }
75
+ if (first === "by-kind") {
76
+ if (rest.length === 0) {
77
+ throw new Error(`parsePath: /by-kind requires a kind argument, got: "${pathString}"`);
78
+ }
79
+ return { mount: "by-kind", args: [rest[0]] };
80
+ }
81
+ if (first === "by-owner") {
82
+ if (rest.length === 0) {
83
+ throw new Error(`parsePath: /by-owner requires an ownerId argument, got: "${pathString}"`);
84
+ }
85
+ return { mount: "by-owner", args: [rest.join("/")] };
86
+ }
87
+ if (first === "graph") {
88
+ if (rest.length < 2) {
89
+ throw new Error(`parsePath: /graph requires <nodeId>/<verb> (governs|governed-by), got: "${pathString}"`);
90
+ }
91
+ const graphNodeId = rest.slice(0, -1).join("/");
92
+ const verb = rest[rest.length - 1];
93
+ if (verb !== "governs" && verb !== "governed-by") {
94
+ throw new Error(
95
+ `parsePath: /graph/<nodeId> verb must be "governs" or "governed-by", got: "${verb}" in "${pathString}"`
96
+ );
97
+ }
98
+ return { mount: "graph", args: [graphNodeId, verb] };
99
+ }
100
+ if (segments.length === 1) {
101
+ return { mount: "node", args: [first] };
102
+ }
103
+ throw new Error(
104
+ `parsePath: unrecognized path pattern "${pathString}". Supported: /by-feature/<id>, /by-kind/<kind>, /by-owner/<id>, /graph/<nodeId>/governs, /graph/<nodeId>/governed-by, /<nodeId>`
105
+ );
106
+ }
107
+
108
+ // src/knowledge/format.ts
109
+ function formatText(results) {
110
+ if (results.length === 0) {
111
+ return "(no results)";
112
+ }
113
+ const kindWidth = Math.max(...results.map((n) => n.kind.length), 8);
114
+ const idWidth = Math.max(...results.map((n) => n.id.length), 4);
115
+ const header = `${"KIND".padEnd(kindWidth)} ${"ID".padEnd(idWidth)} TITLE`;
116
+ const divider = "-".repeat(header.length + 20);
117
+ const rows = results.map((n) => {
118
+ const summary = n.summary.length > 80 ? n.summary.slice(0, 77) + "..." : n.summary;
119
+ return `${n.kind.padEnd(kindWidth)} ${n.id.padEnd(idWidth)} ${n.title} \u2014 ${summary}`;
120
+ });
121
+ return [header, divider, ...rows].join("\n");
122
+ }
123
+ function formatJson(input) {
124
+ const envelope = {
125
+ path: input.path,
126
+ mount: input.parsed.mount,
127
+ args: input.parsed.args,
128
+ results: input.results
129
+ };
130
+ return JSON.stringify(envelope, null, 2);
131
+ }
132
+ function formatIdsOnly(results) {
133
+ if (results.length === 0) return "";
134
+ const ids = results.map((r) => typeof r === "string" ? r : r.id);
135
+ return ids.join("\n");
136
+ }
137
+
138
+ export { byFeature, byKind, byOwner, formatIdsOnly, formatJson, formatText, governedBy, governs, parsePath };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/core",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "license": "MIT",
5
5
  "description": "Minimal shared constants across Elevasis monorepo",
6
6
  "sideEffects": false,