@unified-product-graph/cloud-server 0.9.15 → 0.9.16

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/dist/index.js CHANGED
@@ -998,6 +998,148 @@ function textError(s) {
998
998
  return { content: [{ type: "text", text: s }], isError: true };
999
999
  }
1000
1000
 
1001
+ // ../upg-mcp-tooling/dist/tree-assemble.js
1002
+ var DEFAULT_MAX_NODES = 400;
1003
+ function shell(reader, id, includeProps) {
1004
+ const n = reader.getNode(id);
1005
+ if (!n)
1006
+ return void 0;
1007
+ const node = { id: n.id, type: n.type, title: n.title, children: [] };
1008
+ if (n.status)
1009
+ node.status = n.status;
1010
+ if (includeProps && includeProps.length > 0 && n.properties) {
1011
+ const picked = {};
1012
+ for (const k of includeProps) {
1013
+ if (k in n.properties)
1014
+ picked[k] = n.properties[k];
1015
+ }
1016
+ if (Object.keys(picked).length > 0)
1017
+ node.properties = picked;
1018
+ }
1019
+ return node;
1020
+ }
1021
+ function childrenOf(reader, nodeId2, childTypes) {
1022
+ if (childTypes.length === 0)
1023
+ return [];
1024
+ const allow = new Set(childTypes);
1025
+ const out = [];
1026
+ const seen = /* @__PURE__ */ new Set();
1027
+ for (const e of reader.getEdgesForNode(nodeId2)) {
1028
+ if (e.source !== nodeId2)
1029
+ continue;
1030
+ if (seen.has(e.target))
1031
+ continue;
1032
+ const t = reader.getNode(e.target);
1033
+ if (t && allow.has(t.type)) {
1034
+ out.push(e.target);
1035
+ seen.add(e.target);
1036
+ }
1037
+ }
1038
+ return out;
1039
+ }
1040
+ function assembleTree(reader, pattern, opts) {
1041
+ const maxNodes = Math.min(Math.max(opts.max_nodes ?? DEFAULT_MAX_NODES, 1), 2e3);
1042
+ const maxDepth = Math.min(Math.max(opts.depth ?? pattern.natural_depth, 1), 12);
1043
+ const includeProps = opts.include_properties;
1044
+ const buildFrom = (rootIds, anchorType) => {
1045
+ const visited = /* @__PURE__ */ new Set();
1046
+ const gaps = [];
1047
+ let nodes = 0;
1048
+ let levels = 0;
1049
+ let truncated = false;
1050
+ let childCount = 0;
1051
+ const expand = (node, depth) => {
1052
+ if (depth > levels)
1053
+ levels = depth;
1054
+ const childTypes = pattern.child_map[node.type] ?? [];
1055
+ if (depth >= maxDepth) {
1056
+ if (childTypes.length > 0 && childrenOf(reader, node.id, childTypes).length > 0)
1057
+ truncated = true;
1058
+ return;
1059
+ }
1060
+ const childIds = childrenOf(reader, node.id, childTypes);
1061
+ if (childTypes.length > 0 && childIds.length === 0) {
1062
+ gaps.push({ node_id: node.id, type: node.type, title: node.title, missing: childTypes });
1063
+ return;
1064
+ }
1065
+ for (const cid of childIds) {
1066
+ if (visited.has(cid))
1067
+ continue;
1068
+ if (nodes >= maxNodes) {
1069
+ truncated = true;
1070
+ return;
1071
+ }
1072
+ const child = shell(reader, cid, includeProps);
1073
+ if (!child)
1074
+ continue;
1075
+ visited.add(cid);
1076
+ nodes++;
1077
+ childCount++;
1078
+ node.children.push(child);
1079
+ expand(child, depth + 1);
1080
+ }
1081
+ };
1082
+ const roots = [];
1083
+ for (const rid of rootIds) {
1084
+ if (visited.has(rid))
1085
+ continue;
1086
+ if (nodes >= maxNodes) {
1087
+ truncated = true;
1088
+ break;
1089
+ }
1090
+ const root = shell(reader, rid, includeProps);
1091
+ if (!root)
1092
+ continue;
1093
+ visited.add(rid);
1094
+ nodes++;
1095
+ roots.push(root);
1096
+ expand(root, 1);
1097
+ }
1098
+ return { anchorType, roots, nodes, levels, truncated, gaps, childCount };
1099
+ };
1100
+ if (opts.from_id) {
1101
+ const n = reader.getNode(opts.from_id);
1102
+ const anchorType = n?.type ?? pattern.anchor_type;
1103
+ const b = buildFrom([opts.from_id], anchorType);
1104
+ return {
1105
+ pattern: pattern.id,
1106
+ framework_id: pattern.framework_id,
1107
+ anchor_type: pattern.anchor_type,
1108
+ anchor_used: anchorType,
1109
+ roots: b.roots,
1110
+ stats: { nodes: b.nodes, levels: b.levels, truncated: b.truncated },
1111
+ gaps: b.gaps
1112
+ };
1113
+ }
1114
+ const candidates = [pattern.anchor_type, ...pattern.fallback_anchors];
1115
+ const idsOfType = (type) => reader.getAllNodes().filter((n) => n.type === type).map((n) => n.id);
1116
+ let chosen;
1117
+ for (const cand of candidates) {
1118
+ const rootIds = idsOfType(cand);
1119
+ if (rootIds.length === 0)
1120
+ continue;
1121
+ const b = buildFrom(rootIds, cand);
1122
+ chosen = b;
1123
+ if (b.childCount > 0)
1124
+ break;
1125
+ }
1126
+ if (!chosen) {
1127
+ chosen = { anchorType: pattern.anchor_type, roots: [], nodes: 0, levels: 0, truncated: false, gaps: [], childCount: 0 };
1128
+ }
1129
+ const result = {
1130
+ pattern: pattern.id,
1131
+ framework_id: pattern.framework_id,
1132
+ anchor_type: pattern.anchor_type,
1133
+ anchor_used: chosen.anchorType,
1134
+ roots: chosen.roots,
1135
+ stats: { nodes: chosen.nodes, levels: chosen.levels, truncated: chosen.truncated },
1136
+ gaps: chosen.gaps
1137
+ };
1138
+ if (chosen.anchorType !== pattern.anchor_type)
1139
+ result.anchor_resolved_from = pattern.anchor_type;
1140
+ return result;
1141
+ }
1142
+
1001
1143
  // ../upg-mcp-tooling/dist/catalog.js
1002
1144
  import { UPG_EDGE_CATALOG, UPG_PROPERTY_SCHEMA, getDomainForType, getGuideForDomain, getLifecycleForType, getPropertySchema, resolveEntityType, UnknownEntityTypeError } from "@unified-product-graph/core";
1003
1145
  function buildEntitySchema(rawType, options = {}) {
@@ -1332,6 +1474,58 @@ var getChanges = async (args, { store }) => {
1332
1474
  return text(JSON.stringify({ changes: filtered, total: filtered.length }, null, 2));
1333
1475
  };
1334
1476
 
1477
+ // src/tools/tree.ts
1478
+ import { getTreePattern, UPG_TREE_PATTERNS } from "@unified-product-graph/core";
1479
+ var getTree = async (args, { store }) => {
1480
+ if (!args.product_id) return textError("Missing required parameter: product_id");
1481
+ const productId = args.product_id;
1482
+ const patternId = args.pattern;
1483
+ if (!patternId) {
1484
+ return textError(
1485
+ `Missing required parameter: pattern. One of: ${UPG_TREE_PATTERNS.map((p) => p.id).join(", ")}.`
1486
+ );
1487
+ }
1488
+ const pattern = getTreePattern(patternId);
1489
+ if (!pattern) {
1490
+ return textError(
1491
+ `Unknown tree pattern: "${patternId}". Valid patterns: ${UPG_TREE_PATTERNS.map((p) => p.id).join(", ")}.`
1492
+ );
1493
+ }
1494
+ const includeProperties = Array.isArray(args.include_properties) ? args.include_properties : void 0;
1495
+ const allNodes = await store.getAllNodes(productId);
1496
+ const allEdges = await store.getAllEdges(productId);
1497
+ const nodeById = new Map(allNodes.map((n) => [n.id, n]));
1498
+ const edgesByNode = /* @__PURE__ */ new Map();
1499
+ for (const e of allEdges) {
1500
+ let src = edgesByNode.get(e.source);
1501
+ if (!src) {
1502
+ src = [];
1503
+ edgesByNode.set(e.source, src);
1504
+ }
1505
+ src.push(e);
1506
+ if (e.target !== e.source) {
1507
+ let tgt = edgesByNode.get(e.target);
1508
+ if (!tgt) {
1509
+ tgt = [];
1510
+ edgesByNode.set(e.target, tgt);
1511
+ }
1512
+ tgt.push(e);
1513
+ }
1514
+ }
1515
+ const reader = {
1516
+ getNode: (id) => nodeById.get(id),
1517
+ getAllNodes: () => allNodes,
1518
+ getEdgesForNode: (id) => edgesByNode.get(id) ?? []
1519
+ };
1520
+ const result = assembleTree(reader, pattern, {
1521
+ from_id: args.from_id,
1522
+ depth: args.depth,
1523
+ include_properties: includeProperties,
1524
+ max_nodes: args.max_nodes
1525
+ });
1526
+ return text(JSON.stringify(result, null, 2));
1527
+ };
1528
+
1335
1529
  // src/tools/nodes.ts
1336
1530
  import { getLifecycleForType as getLifecycleForType2, resolveEntityType as resolveEntityType2, UnknownEntityTypeError as UnknownEntityTypeError2 } from "@unified-product-graph/core";
1337
1531
  import {
@@ -2084,6 +2278,9 @@ import {
2084
2278
  UPG_REGIONS,
2085
2279
  UPG_REGION_MAP,
2086
2280
  UPG_REGION_COUNT,
2281
+ UPG_AREA_TAXONOMY,
2282
+ getCoverageKeysForRegion,
2283
+ getBusinessAreasForRegion,
2087
2284
  UPG_LENSES,
2088
2285
  UPG_TYPE_LABELS,
2089
2286
  UPG_TYPE_LABELS_MAP,
@@ -2358,10 +2555,12 @@ var listRegions = () => {
2358
2555
  composes_atomic_domains: r.composes_atomic_domains,
2359
2556
  entity_count: r.entities.length,
2360
2557
  intra_edge_count: r.intra_edges.length,
2361
- boundary_edge_count: r.boundary_edges.length
2558
+ boundary_edge_count: r.boundary_edges.length,
2559
+ coverage_keys: getCoverageKeysForRegion(r.id),
2560
+ business_areas: getBusinessAreasForRegion(r.id)
2362
2561
  }));
2363
2562
  return text(
2364
- JSON.stringify({ count: UPG_REGION_COUNT, regions }, null, 2)
2563
+ JSON.stringify({ count: UPG_REGION_COUNT, regions, area_taxonomy: UPG_AREA_TAXONOMY }, null, 2)
2365
2564
  );
2366
2565
  };
2367
2566
  var getRegion = (args) => {
@@ -2369,7 +2568,11 @@ var getRegion = (args) => {
2369
2568
  if (!id) return textError("Missing required parameter: id");
2370
2569
  const region = UPG_REGION_MAP[id];
2371
2570
  if (!region) return textError(`Unknown region id: ${id}`);
2372
- return text(JSON.stringify(region, null, 2));
2571
+ return text(JSON.stringify({
2572
+ ...region,
2573
+ coverage_keys: getCoverageKeysForRegion(id),
2574
+ business_areas: getBusinessAreasForRegion(id)
2575
+ }, null, 2));
2373
2576
  };
2374
2577
  var getRegionForEntity = (args) => {
2375
2578
  const entityType = args.entity_type;
@@ -4235,6 +4438,46 @@ var TOOL_DEFINITIONS = [
4235
4438
  ]
4236
4439
  }
4237
4440
  },
4441
+ {
4442
+ "name": "get_tree",
4443
+ "description": "Assemble a canonical tree pattern (ost, okr, user, product, validation, strategy, feature_areas) from the product graph. Walks the pattern's type-driven child map over the live graph (drift-proof, follows whatever edge wired each parent to a child of the expected type), roots at the pattern anchor with fallback, and reports structural gaps. Returns nested data, not rendered text.",
4444
+ "inputSchema": {
4445
+ "type": "object",
4446
+ "properties": {
4447
+ "product_id": {
4448
+ "type": "string",
4449
+ "description": "The product ID"
4450
+ },
4451
+ "pattern": {
4452
+ "type": "string",
4453
+ "description": "Tree pattern id: ost, okr, user, product, validation, strategy, feature_areas"
4454
+ },
4455
+ "from_id": {
4456
+ "type": "string",
4457
+ "description": "Explicit root node id. Defaults to the pattern's canonical anchor type."
4458
+ },
4459
+ "depth": {
4460
+ "type": "number",
4461
+ "description": "Max levels. Defaults to the pattern's natural depth."
4462
+ },
4463
+ "include_properties": {
4464
+ "type": "array",
4465
+ "items": {
4466
+ "type": "string"
4467
+ },
4468
+ "description": "Node property keys to inline on each tree node."
4469
+ },
4470
+ "max_nodes": {
4471
+ "type": "number",
4472
+ "description": "Cap on assembled nodes. The tree is summarised (stats.truncated) rather than silently cut."
4473
+ }
4474
+ },
4475
+ "required": [
4476
+ "product_id",
4477
+ "pattern"
4478
+ ]
4479
+ }
4480
+ },
4238
4481
  {
4239
4482
  "name": "get_graph_digest",
4240
4483
  "description": "Pre-computed graph analytics: counts, health metrics, chain completeness, business area coverage, lifecycle balance. ~500 tokens vs ~5-8K for equivalent manual fetches.",
@@ -5221,6 +5464,7 @@ var HANDLERS = {
5221
5464
  get_product_context: getProductContext,
5222
5465
  get_graph_digest: getGraphDigest,
5223
5466
  query,
5467
+ get_tree: getTree,
5224
5468
  get_changes: getChanges,
5225
5469
  list_nodes: listNodes,
5226
5470
  export_upg_document: exportUpgDocument,