@kaddo/cli 3.76.1 → 3.78.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.
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>admin</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-Y7S2WW1U.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-BPQdYfAp.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
getWorkItemCaptureDefinition as coreGetCaptureDefinition,
|
|
70
70
|
buildRefinementHandoff as coreBuildRefinementHandoff,
|
|
71
71
|
getSystemMapProjection as coreGetSystemMapProjection,
|
|
72
|
+
buildTopologyEnrichmentHandoff as coreBuildTopologyHandoff,
|
|
72
73
|
WorkItemWriteError,
|
|
73
74
|
exists,
|
|
74
75
|
join,
|
|
@@ -139,6 +140,11 @@ function getCaptureDefinition() {
|
|
|
139
140
|
function getSystemMap(dir) {
|
|
140
141
|
return coreGetSystemMapProjection(dir);
|
|
141
142
|
}
|
|
143
|
+
function getTopologyHandoff(dir) {
|
|
144
|
+
const config = loadConfig(dir);
|
|
145
|
+
if (!config) throw new CoreError("PROJECT_NOT_FOUND", "No Kaddo project was found.");
|
|
146
|
+
return coreBuildTopologyHandoff(dir, config.project.name ?? "this project");
|
|
147
|
+
}
|
|
142
148
|
function getRefinementHandoff(dir, workItemId) {
|
|
143
149
|
assertValidWorkItemId(workItemId);
|
|
144
150
|
try {
|
|
@@ -585,11 +591,17 @@ var SystemMapNodeSchema = z.object({
|
|
|
585
591
|
id: z.string(),
|
|
586
592
|
type: z.string(),
|
|
587
593
|
label: z.string(),
|
|
594
|
+
dimension: z.enum(["system", "knowledge", "delivery", "implementation", "unknown"]),
|
|
588
595
|
status: z.string().optional(),
|
|
589
596
|
path: z.string().optional(),
|
|
590
597
|
workItemRef: z.string().optional(),
|
|
591
598
|
knowledgeRef: z.object({ id: z.string(), layer: z.string() }).optional(),
|
|
592
|
-
moduleId: z.string().optional()
|
|
599
|
+
moduleId: z.string().optional(),
|
|
600
|
+
purpose: z.string().optional(),
|
|
601
|
+
implementationRefs: z.array(z.string()).optional(),
|
|
602
|
+
knowledgeRefs: z.array(z.object({ id: z.string(), layer: z.string() })).optional(),
|
|
603
|
+
provenance: z.string().optional(),
|
|
604
|
+
evidence: z.array(z.string()).optional()
|
|
593
605
|
});
|
|
594
606
|
var SystemMapRelationshipSchema = z.object({
|
|
595
607
|
id: z.string(),
|
|
@@ -615,9 +627,22 @@ var SystemMapProjectionSchema = z.object({
|
|
|
615
627
|
nodeCount: z.number(),
|
|
616
628
|
relationshipCount: z.number(),
|
|
617
629
|
coverage: z.enum(["good", "partial", "sparse", "empty"]),
|
|
618
|
-
available: z.boolean()
|
|
630
|
+
available: z.boolean(),
|
|
631
|
+
dimensions: z.object({ system: z.number(), knowledge: z.number(), delivery: z.number(), implementation: z.number(), unknown: z.number() }),
|
|
632
|
+
topologyAvailable: z.boolean(),
|
|
633
|
+
topologyStatus: z.enum(["unavailable", "partial", "available"]),
|
|
634
|
+
semanticEntityCount: z.number(),
|
|
635
|
+
technicalRelationshipCount: z.number(),
|
|
636
|
+
topologyFindings: z.array(z.object({ level: z.enum(["blocking", "warning"]), message: z.string() }))
|
|
619
637
|
})
|
|
620
638
|
});
|
|
639
|
+
var TopologyEnrichmentHandoffSchema = z.object({
|
|
640
|
+
projectName: z.string(),
|
|
641
|
+
recommendedAgent: z.string(),
|
|
642
|
+
recommendedSkill: z.string(),
|
|
643
|
+
targetFile: z.string(),
|
|
644
|
+
text: z.string()
|
|
645
|
+
});
|
|
621
646
|
var ErrorResponseSchema = z.object({
|
|
622
647
|
error: z.object({
|
|
623
648
|
code: z.string(),
|
|
@@ -779,6 +804,7 @@ async function createAdminServer(opts) {
|
|
|
779
804
|
app.get("/api/v1/admin/route", coreRoute(getProjectRoute));
|
|
780
805
|
app.get("/api/v1/admin/findings", coreRoute(getFindings));
|
|
781
806
|
app.get("/api/v1/admin/system", coreRoute(getSystemMap));
|
|
807
|
+
app.get("/api/v1/admin/system/topology-handoff", coreRoute(getTopologyHandoff));
|
|
782
808
|
app.get("/api/v1/admin/knowledge/inventory", coreRoute(getKnowledgeInventory));
|
|
783
809
|
app.get("/api/v1/admin/knowledge/artifact/:artifactId", async (request) => {
|
|
784
810
|
try {
|
|
@@ -937,6 +963,7 @@ export {
|
|
|
937
963
|
SystemMapNodeSchema,
|
|
938
964
|
SystemMapProjectionSchema,
|
|
939
965
|
SystemMapRelationshipSchema,
|
|
966
|
+
TopologyEnrichmentHandoffSchema,
|
|
940
967
|
ValidationResultSchema,
|
|
941
968
|
WorkItemCreateSchema,
|
|
942
969
|
WorkItemCreateWithAnswersSchema,
|
package/dist/core.js
CHANGED
|
@@ -8712,7 +8712,197 @@ function buildRefinementHandoff(dir, workItemId) {
|
|
|
8712
8712
|
};
|
|
8713
8713
|
}
|
|
8714
8714
|
|
|
8715
|
+
// src/core/system-topology.ts
|
|
8716
|
+
import { parse as parseYaml8 } from "yaml";
|
|
8717
|
+
var TOPOLOGY_FILE = "knowledge/tech/system-topology.yml";
|
|
8718
|
+
var SYSTEM_ENTITY_KINDS = /* @__PURE__ */ new Set([
|
|
8719
|
+
"system",
|
|
8720
|
+
"application",
|
|
8721
|
+
"service",
|
|
8722
|
+
"component",
|
|
8723
|
+
"api",
|
|
8724
|
+
"interface",
|
|
8725
|
+
"datastore",
|
|
8726
|
+
"queue",
|
|
8727
|
+
"job",
|
|
8728
|
+
"external-system",
|
|
8729
|
+
"module",
|
|
8730
|
+
"unknown"
|
|
8731
|
+
]);
|
|
8732
|
+
var TECHNICAL_RELATIONSHIP_TYPES = /* @__PURE__ */ new Set([
|
|
8733
|
+
"contains",
|
|
8734
|
+
"depends-on",
|
|
8735
|
+
"calls",
|
|
8736
|
+
"reads-from",
|
|
8737
|
+
"writes-to",
|
|
8738
|
+
"publishes-to",
|
|
8739
|
+
"subscribes-to",
|
|
8740
|
+
"integrates-with",
|
|
8741
|
+
"runs-on",
|
|
8742
|
+
"implemented-by"
|
|
8743
|
+
]);
|
|
8744
|
+
var PROVENANCE = /* @__PURE__ */ new Set(["declared", "derived", "agent-reviewed"]);
|
|
8745
|
+
function isRelative(p2) {
|
|
8746
|
+
return typeof p2 === "string" && p2.trim() !== "" && !/^([a-zA-Z]:[\\/]|\/)/.test(p2) && !p2.includes("..");
|
|
8747
|
+
}
|
|
8748
|
+
function strList(v) {
|
|
8749
|
+
return Array.isArray(v) ? v.map((x) => typeof x === "string" ? x.trim() : "").filter(Boolean) : [];
|
|
8750
|
+
}
|
|
8751
|
+
function loadSystemTopology(dir) {
|
|
8752
|
+
const path3 = join(dir, TOPOLOGY_FILE);
|
|
8753
|
+
if (!exists(path3)) return { entities: [], relationships: [], findings: [], declared: false };
|
|
8754
|
+
let parsed;
|
|
8755
|
+
try {
|
|
8756
|
+
parsed = parseYaml8(readFile(path3)) ?? {};
|
|
8757
|
+
} catch {
|
|
8758
|
+
return { entities: [], relationships: [], findings: [{ level: "blocking", message: "system-topology.yml could not be parsed." }], declared: true };
|
|
8759
|
+
}
|
|
8760
|
+
const findings = [];
|
|
8761
|
+
const validModules = /* @__PURE__ */ new Set(["core", ...loadMappedModules(dir).map((m) => m.id)]);
|
|
8762
|
+
const rawEntities = Array.isArray(parsed.entities) ? parsed.entities : [];
|
|
8763
|
+
const entities = [];
|
|
8764
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
8765
|
+
for (const raw of rawEntities) {
|
|
8766
|
+
if (!raw || typeof raw !== "object") continue;
|
|
8767
|
+
const e = raw;
|
|
8768
|
+
const id = typeof e.id === "string" ? e.id.trim() : "";
|
|
8769
|
+
if (!id) {
|
|
8770
|
+
findings.push({ level: "warning", message: "A topology entity is missing an id and was skipped." });
|
|
8771
|
+
continue;
|
|
8772
|
+
}
|
|
8773
|
+
if (seenIds.has(id)) {
|
|
8774
|
+
findings.push({ level: "blocking", message: `Duplicate topology entity id "${id}".` });
|
|
8775
|
+
continue;
|
|
8776
|
+
}
|
|
8777
|
+
const kind = typeof e.kind === "string" ? e.kind.trim() : "unknown";
|
|
8778
|
+
if (!SYSTEM_ENTITY_KINDS.has(kind)) {
|
|
8779
|
+
findings.push({ level: "warning", message: `Entity "${id}" has an unknown kind "${kind}"; treated as unknown.` });
|
|
8780
|
+
}
|
|
8781
|
+
const moduleRaw = typeof e.module === "string" ? e.module.trim() : void 0;
|
|
8782
|
+
if (moduleRaw && !validModules.has(moduleRaw)) findings.push({ level: "warning", message: `Entity "${id}" references unregistered module "${moduleRaw}".` });
|
|
8783
|
+
const implementation = strList(e.implementation).filter((p2) => {
|
|
8784
|
+
if (isRelative(p2)) return true;
|
|
8785
|
+
findings.push({ level: "warning", message: `Entity "${id}" implementation ref "${p2}" is not a safe relative path and was dropped.` });
|
|
8786
|
+
return false;
|
|
8787
|
+
});
|
|
8788
|
+
const provenance = typeof e.provenance === "string" && PROVENANCE.has(e.provenance) ? e.provenance : void 0;
|
|
8789
|
+
seenIds.add(id);
|
|
8790
|
+
entities.push({
|
|
8791
|
+
id,
|
|
8792
|
+
kind: SYSTEM_ENTITY_KINDS.has(kind) ? kind : "unknown",
|
|
8793
|
+
label: typeof e.label === "string" && e.label.trim() ? e.label.trim() : id,
|
|
8794
|
+
...typeof e.purpose === "string" && e.purpose.trim() ? { purpose: e.purpose.trim() } : {},
|
|
8795
|
+
...moduleRaw && validModules.has(moduleRaw) ? { moduleId: moduleRaw } : {},
|
|
8796
|
+
implementationRefs: implementation,
|
|
8797
|
+
knowledgeRefs: strList(e.knowledge),
|
|
8798
|
+
...provenance ? { provenance } : {},
|
|
8799
|
+
evidence: strList(e.evidence).filter(isRelative)
|
|
8800
|
+
});
|
|
8801
|
+
}
|
|
8802
|
+
const entityIds = new Set(entities.map((e) => e.id));
|
|
8803
|
+
const rawRels = Array.isArray(parsed.relationships) ? parsed.relationships : [];
|
|
8804
|
+
const relationships = [];
|
|
8805
|
+
for (const raw of rawRels) {
|
|
8806
|
+
if (!raw || typeof raw !== "object") continue;
|
|
8807
|
+
const r = raw;
|
|
8808
|
+
const from = typeof r.from === "string" ? r.from.trim() : "";
|
|
8809
|
+
const to = typeof r.to === "string" ? r.to.trim() : "";
|
|
8810
|
+
const type = typeof r.type === "string" ? r.type.trim() : "";
|
|
8811
|
+
if (!from || !to || !type) {
|
|
8812
|
+
findings.push({ level: "warning", message: "A topology relationship is missing from/to/type and was skipped." });
|
|
8813
|
+
continue;
|
|
8814
|
+
}
|
|
8815
|
+
if (!TECHNICAL_RELATIONSHIP_TYPES.has(type)) {
|
|
8816
|
+
findings.push({ level: "warning", message: `Relationship type "${type}" is not recognized and was skipped.` });
|
|
8817
|
+
continue;
|
|
8818
|
+
}
|
|
8819
|
+
if (!entityIds.has(from) || !entityIds.has(to)) {
|
|
8820
|
+
findings.push({ level: "blocking", message: `Relationship ${from} \u2192 ${to} references an unknown entity endpoint.` });
|
|
8821
|
+
continue;
|
|
8822
|
+
}
|
|
8823
|
+
relationships.push({ from, to, type, evidence: strList(r.evidence).filter(isRelative) });
|
|
8824
|
+
}
|
|
8825
|
+
return { entities, relationships, findings, declared: true };
|
|
8826
|
+
}
|
|
8827
|
+
function validateSystemTopology(dir) {
|
|
8828
|
+
return loadSystemTopology(dir).findings;
|
|
8829
|
+
}
|
|
8830
|
+
function buildTopologyEnrichmentHandoff(dir, projectName) {
|
|
8831
|
+
const mappedModules = loadMappedModules(dir).map((m) => m.id);
|
|
8832
|
+
const lines = [
|
|
8833
|
+
`Enrich the semantic system topology for the Kaddo project "${projectName}".`,
|
|
8834
|
+
"",
|
|
8835
|
+
"Use the canonical architecture-agent and graph-metadata-review skill (via Kaddo MCP or skills).",
|
|
8836
|
+
"Inspect the actual repository and relevant mapped modules \u2014 do not infer architecture from",
|
|
8837
|
+
"filenames or directory names."
|
|
8838
|
+
];
|
|
8839
|
+
if (mappedModules.length > 0) {
|
|
8840
|
+
lines.push("", `This is a multirepo project. Inspect the relevant mapped modules (${mappedModules.join(", ")}) before finalizing the topology.`);
|
|
8841
|
+
}
|
|
8842
|
+
lines.push(
|
|
8843
|
+
"",
|
|
8844
|
+
`Write the result to ${TOPOLOGY_FILE} as declared entities and relationships. For each entity`,
|
|
8845
|
+
"capture, only when supported by evidence:",
|
|
8846
|
+
"- a stable id and semantic kind (application/service/component/api/interface/datastore/queue/job/external-system);",
|
|
8847
|
+
"- a responsibility/purpose (what it does, not how);",
|
|
8848
|
+
"- the owning module/repository;",
|
|
8849
|
+
"- implementation references (relative paths);",
|
|
8850
|
+
"- relevant Knowledge references (capability/ADR ids), not Kaddo operational assets.",
|
|
8851
|
+
"",
|
|
8852
|
+
"Capture evidence-backed technical relationships: contains, calls, depends-on, reads-from,",
|
|
8853
|
+
"writes-to, integrates-with, runs-on. Preserve unknowns when evidence is insufficient.",
|
|
8854
|
+
"",
|
|
8855
|
+
"Review the proposed graph metadata (duplicate ids, dangling relationships, unknown modules,",
|
|
8856
|
+
"invalid references) before writing.",
|
|
8857
|
+
"Do not implement application changes. Do not run mutating Git operations."
|
|
8858
|
+
);
|
|
8859
|
+
return {
|
|
8860
|
+
projectName,
|
|
8861
|
+
recommendedAgent: "architecture-agent",
|
|
8862
|
+
recommendedSkill: "graph-metadata-review",
|
|
8863
|
+
targetFile: TOPOLOGY_FILE,
|
|
8864
|
+
text: lines.join("\n")
|
|
8865
|
+
};
|
|
8866
|
+
}
|
|
8867
|
+
|
|
8715
8868
|
// src/core/system-map.ts
|
|
8869
|
+
function dimensionOf(type) {
|
|
8870
|
+
switch (type) {
|
|
8871
|
+
case "module":
|
|
8872
|
+
case "application":
|
|
8873
|
+
case "service":
|
|
8874
|
+
case "component":
|
|
8875
|
+
case "api":
|
|
8876
|
+
case "interface":
|
|
8877
|
+
case "database":
|
|
8878
|
+
case "queue":
|
|
8879
|
+
case "job":
|
|
8880
|
+
case "external-system":
|
|
8881
|
+
return "system";
|
|
8882
|
+
case "business":
|
|
8883
|
+
case "product":
|
|
8884
|
+
case "tech":
|
|
8885
|
+
case "delivery":
|
|
8886
|
+
case "capability":
|
|
8887
|
+
case "decision":
|
|
8888
|
+
case "project":
|
|
8889
|
+
case "knowledge-capsule":
|
|
8890
|
+
return "knowledge";
|
|
8891
|
+
case "work-item":
|
|
8892
|
+
case "initiative":
|
|
8893
|
+
case "roadmap-candidate":
|
|
8894
|
+
case "release":
|
|
8895
|
+
return "delivery";
|
|
8896
|
+
case "code-glob":
|
|
8897
|
+
case "file":
|
|
8898
|
+
case "directory":
|
|
8899
|
+
case "migration":
|
|
8900
|
+
case "configuration-artifact":
|
|
8901
|
+
return "implementation";
|
|
8902
|
+
default:
|
|
8903
|
+
return "unknown";
|
|
8904
|
+
}
|
|
8905
|
+
}
|
|
8716
8906
|
var EDGE_LABELS = {
|
|
8717
8907
|
informs: "informs",
|
|
8718
8908
|
belongs_to: "belongs to",
|
|
@@ -8724,13 +8914,29 @@ var EDGE_LABELS = {
|
|
|
8724
8914
|
provides_external_context: "provides external context",
|
|
8725
8915
|
uses_external_knowledge: "uses external knowledge"
|
|
8726
8916
|
};
|
|
8917
|
+
function emptyDimensions() {
|
|
8918
|
+
return { system: 0, knowledge: 0, delivery: 0, implementation: 0, unknown: 0 };
|
|
8919
|
+
}
|
|
8727
8920
|
function emptyProjection(name, structure) {
|
|
8728
8921
|
return {
|
|
8729
8922
|
system: { name },
|
|
8730
8923
|
nodes: [],
|
|
8731
8924
|
relationships: [],
|
|
8732
8925
|
groups: [],
|
|
8733
|
-
metadata: {
|
|
8926
|
+
metadata: {
|
|
8927
|
+
projectName: name,
|
|
8928
|
+
structure,
|
|
8929
|
+
nodeCount: 0,
|
|
8930
|
+
relationshipCount: 0,
|
|
8931
|
+
coverage: "empty",
|
|
8932
|
+
available: false,
|
|
8933
|
+
dimensions: emptyDimensions(),
|
|
8934
|
+
topologyAvailable: false,
|
|
8935
|
+
topologyStatus: "unavailable",
|
|
8936
|
+
semanticEntityCount: 0,
|
|
8937
|
+
technicalRelationshipCount: 0,
|
|
8938
|
+
topologyFindings: []
|
|
8939
|
+
}
|
|
8734
8940
|
};
|
|
8735
8941
|
}
|
|
8736
8942
|
function getSystemMapProjection(dir) {
|
|
@@ -8756,6 +8962,38 @@ function getSystemMapProjection(dir) {
|
|
|
8756
8962
|
type: e.type,
|
|
8757
8963
|
label: EDGE_LABELS[e.type] ?? e.type.replace(/_/g, " ")
|
|
8758
8964
|
}));
|
|
8965
|
+
const knowledgeById = /* @__PURE__ */ new Map();
|
|
8966
|
+
for (const ref of knowledgeByPath.values()) knowledgeById.set(ref.id, ref);
|
|
8967
|
+
const topology = loadSystemTopology(dir);
|
|
8968
|
+
const existingIds = new Set(nodes.map((n) => n.id));
|
|
8969
|
+
for (const e of topology.entities) {
|
|
8970
|
+
const nodeId = `sys:${e.id}`;
|
|
8971
|
+
const node = {
|
|
8972
|
+
id: nodeId,
|
|
8973
|
+
type: e.kind,
|
|
8974
|
+
label: e.label,
|
|
8975
|
+
dimension: "system",
|
|
8976
|
+
implementationRefs: e.implementationRefs,
|
|
8977
|
+
knowledgeRefs: e.knowledgeRefs.map((k) => knowledgeById.get(k)).filter(Boolean),
|
|
8978
|
+
evidence: e.evidence
|
|
8979
|
+
};
|
|
8980
|
+
if (e.purpose) node.purpose = e.purpose;
|
|
8981
|
+
if (e.moduleId) node.moduleId = e.moduleId;
|
|
8982
|
+
if (e.provenance) node.provenance = e.provenance;
|
|
8983
|
+
nodes.push(node);
|
|
8984
|
+
existingIds.add(nodeId);
|
|
8985
|
+
for (const ref of e.implementationRefs) {
|
|
8986
|
+
const fileId = `file:${ref}`;
|
|
8987
|
+
if (!existingIds.has(fileId)) {
|
|
8988
|
+
nodes.push({ id: fileId, type: "file", label: ref.split("/").pop() || ref, dimension: "implementation", path: ref });
|
|
8989
|
+
existingIds.add(fileId);
|
|
8990
|
+
}
|
|
8991
|
+
relationships.push({ id: `${nodeId}~implemented-by~${fileId}`, source: nodeId, target: fileId, type: "implemented-by", label: "implemented by" });
|
|
8992
|
+
}
|
|
8993
|
+
}
|
|
8994
|
+
for (const r of topology.relationships) {
|
|
8995
|
+
relationships.push({ id: `sys:${r.from}~${r.type}~sys:${r.to}`, source: `sys:${r.from}`, target: `sys:${r.to}`, type: r.type, label: r.type.replace(/-/g, " ") });
|
|
8996
|
+
}
|
|
8759
8997
|
const usedGroups = new Set(nodes.map((n) => n.moduleId).filter(Boolean));
|
|
8760
8998
|
const allGroups = [
|
|
8761
8999
|
{ id: "core", label: "core", repositoryId: "core", available: true },
|
|
@@ -8763,6 +9001,11 @@ function getSystemMapProjection(dir) {
|
|
|
8763
9001
|
...mapped.map((m) => ({ id: m.id, label: m.id, repositoryId: m.id, available: m.repoPath ? exists(join(dir, m.repoPath)) : false }))
|
|
8764
9002
|
];
|
|
8765
9003
|
const groups = allGroups.filter((g) => usedGroups.has(g.id) || g.available === false);
|
|
9004
|
+
const dimensions = emptyDimensions();
|
|
9005
|
+
for (const n of nodes) dimensions[n.dimension]++;
|
|
9006
|
+
const semanticEntityCount = topology.entities.length;
|
|
9007
|
+
const technicalRelationshipCount = relationships.filter((r) => TECHNICAL_RELATIONSHIP_TYPES.has(r.type)).length;
|
|
9008
|
+
const topologyStatus = semanticEntityCount === 0 ? "unavailable" : topology.relationships.length > 0 ? "available" : "partial";
|
|
8766
9009
|
return {
|
|
8767
9010
|
system: { name: config.project.name },
|
|
8768
9011
|
nodes,
|
|
@@ -8774,12 +9017,37 @@ function getSystemMapProjection(dir) {
|
|
|
8774
9017
|
nodeCount: nodes.length,
|
|
8775
9018
|
relationshipCount: relationships.length,
|
|
8776
9019
|
coverage: hints.quality,
|
|
8777
|
-
available: nodes.length > 0
|
|
9020
|
+
available: nodes.length > 0,
|
|
9021
|
+
dimensions,
|
|
9022
|
+
topologyAvailable: dimensions.system > 0,
|
|
9023
|
+
topologyStatus,
|
|
9024
|
+
semanticEntityCount,
|
|
9025
|
+
technicalRelationshipCount,
|
|
9026
|
+
topologyFindings: topology.findings
|
|
8778
9027
|
}
|
|
8779
9028
|
};
|
|
8780
9029
|
}
|
|
9030
|
+
function getSystemNodeContext(dir, nodeId) {
|
|
9031
|
+
const projection = getSystemMapProjection(dir);
|
|
9032
|
+
const byId = new Map(projection.nodes.map((n) => [n.id, n]));
|
|
9033
|
+
const node = byId.get(nodeId);
|
|
9034
|
+
if (!node) return null;
|
|
9035
|
+
const incoming = [];
|
|
9036
|
+
const outgoing = [];
|
|
9037
|
+
for (const r of projection.relationships) {
|
|
9038
|
+
if (r.target === nodeId) {
|
|
9039
|
+
const s = byId.get(r.source);
|
|
9040
|
+
if (s) incoming.push({ relationship: r, node: s });
|
|
9041
|
+
}
|
|
9042
|
+
if (r.source === nodeId) {
|
|
9043
|
+
const t = byId.get(r.target);
|
|
9044
|
+
if (t) outgoing.push({ relationship: r, node: t });
|
|
9045
|
+
}
|
|
9046
|
+
}
|
|
9047
|
+
return { node, incoming, outgoing };
|
|
9048
|
+
}
|
|
8781
9049
|
function toNode(n, knowledgeByPath, wiModules, groupIds) {
|
|
8782
|
-
const node = { id: n.id, type: n.type, label: n.label };
|
|
9050
|
+
const node = { id: n.id, type: n.type, label: n.label, dimension: dimensionOf(n.type) };
|
|
8783
9051
|
if (n.status) node.status = n.status;
|
|
8784
9052
|
if (n.path && !/^([a-zA-Z]:[\\/]|\/)/.test(n.path)) node.path = n.path;
|
|
8785
9053
|
if (n.type === "work-item") {
|
|
@@ -8795,6 +9063,7 @@ function toNode(n, knowledgeByPath, wiModules, groupIds) {
|
|
|
8795
9063
|
return node;
|
|
8796
9064
|
}
|
|
8797
9065
|
export {
|
|
9066
|
+
TOPOLOGY_FILE,
|
|
8798
9067
|
WorkItemNotFoundError,
|
|
8799
9068
|
WorkItemWriteError,
|
|
8800
9069
|
analyzeCrossRepoEvidence,
|
|
@@ -8803,6 +9072,7 @@ export {
|
|
|
8803
9072
|
buildProjectRoute,
|
|
8804
9073
|
buildReadinessReport,
|
|
8805
9074
|
buildRefinementHandoff,
|
|
9075
|
+
buildTopologyEnrichmentHandoff,
|
|
8806
9076
|
computeRefinementStatus,
|
|
8807
9077
|
createWorkItem,
|
|
8808
9078
|
cwd,
|
|
@@ -8810,6 +9080,7 @@ export {
|
|
|
8810
9080
|
discoverWorkItems,
|
|
8811
9081
|
exists,
|
|
8812
9082
|
getSystemMapProjection,
|
|
9083
|
+
getSystemNodeContext,
|
|
8813
9084
|
getWorkItem,
|
|
8814
9085
|
getWorkItemCaptureDefinition,
|
|
8815
9086
|
getWorkItemForEdit,
|
|
@@ -8823,8 +9094,10 @@ export {
|
|
|
8823
9094
|
lifecycleStateOf,
|
|
8824
9095
|
loadConfig,
|
|
8825
9096
|
loadMappedModules,
|
|
9097
|
+
loadSystemTopology,
|
|
8826
9098
|
readFile,
|
|
8827
9099
|
transitionWorkItem,
|
|
8828
9100
|
updateWorkItem,
|
|
9101
|
+
validateSystemTopology,
|
|
8829
9102
|
validateWorkItem
|
|
8830
9103
|
};
|