@unified-product-graph/mcp-server 0.8.14 → 0.8.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/README.md +2 -2
- package/TOOLS.md +280 -8
- package/dist/index.js +455 -12
- package/dist/index.js.map +1 -1
- package/dist/tools-manifest.json +469 -24
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ For Claude Code, add to `.mcp.json`:
|
|
|
21
21
|
```json
|
|
22
22
|
{
|
|
23
23
|
"mcpServers": {
|
|
24
|
-
"
|
|
24
|
+
"unified-product-graph": {
|
|
25
25
|
"command": "npx",
|
|
26
26
|
"args": ["upg-mcp-server"]
|
|
27
27
|
}
|
|
@@ -34,7 +34,7 @@ The server auto-discovers `.upg` files in the current directory. To point at a s
|
|
|
34
34
|
```json
|
|
35
35
|
{
|
|
36
36
|
"mcpServers": {
|
|
37
|
-
"
|
|
37
|
+
"unified-product-graph": {
|
|
38
38
|
"command": "npx",
|
|
39
39
|
"args": ["upg-mcp-server", "--file", "path/to/product.upg"]
|
|
40
40
|
}
|
package/TOOLS.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# UPG MCP Server: Tool Reference
|
|
2
2
|
|
|
3
|
-
Reference for the
|
|
3
|
+
Reference for the 106 tools exposed by `@unified-product-graph/mcp-server`. Generated from JSDoc on `src/tools/*.ts` (do not edit by hand).
|
|
4
4
|
|
|
5
5
|
## Contents
|
|
6
6
|
|
|
7
7
|
- [Context & Session](#context-session): 5 tools
|
|
8
8
|
- [Nodes](#nodes): 15 tools
|
|
9
9
|
- [Edges](#edges): 9 tools
|
|
10
|
-
- [Areas & Change Log](#areas-change-log):
|
|
11
|
-
- [Workspace & Portfolios](#workspace-portfolios):
|
|
10
|
+
- [Areas & Change Log](#areas-change-log): 10 tools
|
|
11
|
+
- [Workspace & Portfolios](#workspace-portfolios): 15 tools
|
|
12
12
|
- [Schema](#schema): 1 tool
|
|
13
13
|
- [Spec Introspection](#spec-introspection): 45 tools
|
|
14
14
|
- [Cloud Sync](#cloud-sync): 3 tools
|
|
@@ -946,11 +946,42 @@ re-computed on next save; a subsequent reload won't bring them back.
|
|
|
946
946
|
|
|
947
947
|
_Product areas, the `.upg-area.json` cwd scoper, and the session change log._
|
|
948
948
|
|
|
949
|
+
- [`assign_product_to_area`](#assign-product-to-area)
|
|
949
950
|
- [`create_area`](#create-area)
|
|
951
|
+
- [`delete_area`](#delete-area)
|
|
950
952
|
- [`get_area_context`](#get-area-context)
|
|
951
953
|
- [`get_area_graph`](#get-area-graph)
|
|
952
954
|
- [`get_changes`](#get-changes)
|
|
953
955
|
- [`list_product_areas`](#list-product-areas)
|
|
956
|
+
- [`move_product_to_area`](#move-product-to-area)
|
|
957
|
+
- [`remove_product_from_area`](#remove-product-from-area)
|
|
958
|
+
- [`update_area`](#update-area)
|
|
959
|
+
|
|
960
|
+
### `assign_product_to_area`
|
|
961
|
+
|
|
962
|
+
Place an existing product under a product area (adds it to the area's `products[]` in `.upg/portfolio.upg`). Resolves the area against the portfolio document and auto-registers the product on the portfolio registry. Use after `create_product`, or pass `area_id` to `create_product` directly.
|
|
963
|
+
|
|
964
|
+
**Atomicity:** `atomic (single portfolio.upg flush).`
|
|
965
|
+
|
|
966
|
+
**Arguments:**
|
|
967
|
+
|
|
968
|
+
| Name | Type | Required | Description |
|
|
969
|
+
| ---- | ---- | -------- | ----------- |
|
|
970
|
+
| `area_id` | string | ✓ | Product area id (from list_product_areas) |
|
|
971
|
+
| `product_id` | string | ✓ | Product id (from create_product / list_local_products) |
|
|
972
|
+
|
|
973
|
+
**Returns:**
|
|
974
|
+
|
|
975
|
+
JSON: `{ product_id, container_id, container_kind: "product_area",
|
|
976
|
+
container_title?, already_member, registered }`.
|
|
977
|
+
|
|
978
|
+
**Throws:**
|
|
979
|
+
|
|
980
|
+
- textError on a missing workspace, an unknown product, or an unknown
|
|
981
|
+
area id (the message points at list_product_areas / list_local_products).
|
|
982
|
+
|
|
983
|
+
**See also:** `attach_product_to_portfolio`, `create_product`
|
|
984
|
+
|
|
954
985
|
|
|
955
986
|
### `create_area`
|
|
956
987
|
|
|
@@ -966,7 +997,7 @@ flushed in one pass.`
|
|
|
966
997
|
| `description` | string | | What this area covers |
|
|
967
998
|
| `owner` | string | | Person or team that owns this area |
|
|
968
999
|
| `parent_area_id` | string | | Parent area ID for creating a sub-area |
|
|
969
|
-
| `strategic_priority` | `
|
|
1000
|
+
| `strategic_priority` | `urgent` \| `high` \| `medium` \| `low` \| `none` | | Strategic priority of this area (canonical Priority scale) |
|
|
970
1001
|
| `title` | string | ✓ | Area name (e.g. "Search", "Payments") |
|
|
971
1002
|
|
|
972
1003
|
**Returns:**
|
|
@@ -982,6 +1013,31 @@ fails.
|
|
|
982
1013
|
**See also:** `list_product_areas`
|
|
983
1014
|
|
|
984
1015
|
|
|
1016
|
+
### `delete_area`
|
|
1017
|
+
|
|
1018
|
+
Delete a product area from `.upg/portfolio.upg`. Guarded: refuses while the area still has products unless `force: true`. Child areas are un-nested (their parent link is cleared) so no parent reference dangles.
|
|
1019
|
+
|
|
1020
|
+
**Atomicity:** `atomic (single portfolio.upg flush).`
|
|
1021
|
+
|
|
1022
|
+
**Arguments:**
|
|
1023
|
+
|
|
1024
|
+
| Name | Type | Required | Description |
|
|
1025
|
+
| ---- | ---- | -------- | ----------- |
|
|
1026
|
+
| `area_id` | string | ✓ | Product area id to delete (from list_product_areas) |
|
|
1027
|
+
| `force` | boolean | | Delete even if the area still has products (default false) |
|
|
1028
|
+
|
|
1029
|
+
**Returns:**
|
|
1030
|
+
|
|
1031
|
+
JSON: `{ message, area_id, deleted, unnested_children: string[] }`.
|
|
1032
|
+
|
|
1033
|
+
**Throws:**
|
|
1034
|
+
|
|
1035
|
+
- textError on a missing workspace, unknown area, or a non-empty area without
|
|
1036
|
+
`force`.
|
|
1037
|
+
|
|
1038
|
+
**See also:** `create_area`, `remove_product_from_area`
|
|
1039
|
+
|
|
1040
|
+
|
|
985
1041
|
### `get_area_context`
|
|
986
1042
|
|
|
987
1043
|
Check whether the current working directory has a `.upg-area.json` that scopes work to a specific product area.
|
|
@@ -1066,12 +1122,96 @@ parent_area_id?, products? }>, total }`.
|
|
|
1066
1122
|
**See also:** `create_area`, `get_area_graph`
|
|
1067
1123
|
|
|
1068
1124
|
|
|
1125
|
+
### `move_product_to_area`
|
|
1126
|
+
|
|
1127
|
+
Move a product to a different product area: remove it from `from_area_id` (or, when omitted, from every area it currently sits in) and add it to `to_area_id`. Convenience over remove_product_from_area + assign_product_to_area.
|
|
1128
|
+
|
|
1129
|
+
**Atomicity:** `atomic (single portfolio.upg flush).`
|
|
1130
|
+
|
|
1131
|
+
**Arguments:**
|
|
1132
|
+
|
|
1133
|
+
| Name | Type | Required | Description |
|
|
1134
|
+
| ---- | ---- | -------- | ----------- |
|
|
1135
|
+
| `from_area_id` | string | | Source area id to remove from; omit to remove from all areas |
|
|
1136
|
+
| `product_id` | string | ✓ | Product id (from list_local_products) |
|
|
1137
|
+
| `to_area_id` | string | ✓ | Destination product area id (from list_product_areas) |
|
|
1138
|
+
|
|
1139
|
+
**Returns:**
|
|
1140
|
+
|
|
1141
|
+
JSON: `{ product_id, to_area_id, to_area_title?, removed_from: string[], added }`.
|
|
1142
|
+
|
|
1143
|
+
**Throws:**
|
|
1144
|
+
|
|
1145
|
+
- textError on a missing workspace, unknown product, or unknown target area.
|
|
1146
|
+
|
|
1147
|
+
**See also:** `assign_product_to_area`, `remove_product_from_area`
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
### `remove_product_from_area`
|
|
1151
|
+
|
|
1152
|
+
Remove a product from a product area's `products[]` in `.upg/portfolio.upg` (the product stays registered on the portfolio and in any other container). The inverse of `assign_product_to_area`.
|
|
1153
|
+
|
|
1154
|
+
**Atomicity:** `atomic (single portfolio.upg flush).`
|
|
1155
|
+
|
|
1156
|
+
**Arguments:**
|
|
1157
|
+
|
|
1158
|
+
| Name | Type | Required | Description |
|
|
1159
|
+
| ---- | ---- | -------- | ----------- |
|
|
1160
|
+
| `area_id` | string | ✓ | Product area id (from list_product_areas) |
|
|
1161
|
+
| `product_id` | string | ✓ | Product id (from list_local_products) |
|
|
1162
|
+
|
|
1163
|
+
**Returns:**
|
|
1164
|
+
|
|
1165
|
+
JSON: `{ product_id, container_id, container_kind: "product_area",
|
|
1166
|
+
container_title?, removed }`. `removed: false` (not an error) when the product
|
|
1167
|
+
was not a member, so retries are idempotent.
|
|
1168
|
+
|
|
1169
|
+
**Throws:**
|
|
1170
|
+
|
|
1171
|
+
- textError on a missing workspace or an unknown area id.
|
|
1172
|
+
|
|
1173
|
+
**See also:** `assign_product_to_area`, `move_product_to_area`
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
### `update_area`
|
|
1177
|
+
|
|
1178
|
+
Edit a product area in `.upg/portfolio.upg` (title, description, strategic_priority, owner) and/or re-parent it via `parent_area_id`. The mirror of `update_product` for the organisational axis. `parent_area_id` is tri-state: omit to leave unchanged, pass null to un-nest (top-level), or pass an area id to re-parent (rejected if it would create a cycle).
|
|
1179
|
+
|
|
1180
|
+
**Atomicity:** `atomic (single portfolio.upg flush).`
|
|
1181
|
+
|
|
1182
|
+
**Arguments:**
|
|
1183
|
+
|
|
1184
|
+
| Name | Type | Required | Description |
|
|
1185
|
+
| ---- | ---- | -------- | ----------- |
|
|
1186
|
+
| `area_id` | string | ✓ | Product area id to edit (from list_product_areas) |
|
|
1187
|
+
| `description` | string | | New area description |
|
|
1188
|
+
| `owner` | string | | Person or team that owns this area |
|
|
1189
|
+
| `parent_area_id` | string,null | | Re-parent under this area id; null un-nests (top-level); omit to leave unchanged |
|
|
1190
|
+
| `strategic_priority` | `urgent` \| `high` \| `medium` \| `low` \| `none` | | Strategic priority (canonical Priority scale) |
|
|
1191
|
+
| `title` | string | | New area title |
|
|
1192
|
+
|
|
1193
|
+
**Returns:**
|
|
1194
|
+
|
|
1195
|
+
JSON: `{ message, area, updated: string[] }`.
|
|
1196
|
+
|
|
1197
|
+
**Throws:**
|
|
1198
|
+
|
|
1199
|
+
- textError on a missing workspace, unknown area/parent, a re-parent cycle, or
|
|
1200
|
+
when no editable field is supplied.
|
|
1201
|
+
|
|
1202
|
+
**See also:** `create_area`, `list_product_areas`
|
|
1203
|
+
|
|
1204
|
+
|
|
1069
1205
|
## Workspace & Portfolios
|
|
1070
1206
|
|
|
1071
1207
|
_Multi-product discovery, switching, init, cross-product edges._
|
|
1072
1208
|
|
|
1209
|
+
- [`attach_product_to_portfolio`](#attach-product-to-portfolio)
|
|
1210
|
+
- [`batch_create_cross_product_edges`](#batch-create-cross-product-edges)
|
|
1073
1211
|
- [`create_cross_product_edge`](#create-cross-product-edge)
|
|
1074
1212
|
- [`create_product`](#create-product)
|
|
1213
|
+
- [`delete_cross_product_edge`](#delete-cross-product-edge)
|
|
1214
|
+
- [`detach_product_from_portfolio`](#detach-product-from-portfolio)
|
|
1075
1215
|
- [`get_organization`](#get-organization)
|
|
1076
1216
|
- [`get_workspace_info`](#get-workspace-info)
|
|
1077
1217
|
- [`init_workspace`](#init-workspace)
|
|
@@ -1080,10 +1220,63 @@ _Multi-product discovery, switching, init, cross-product edges._
|
|
|
1080
1220
|
- [`list_portfolios`](#list-portfolios)
|
|
1081
1221
|
- [`migrate_cross_edges`](#migrate-cross-edges)
|
|
1082
1222
|
- [`switch_product`](#switch-product)
|
|
1223
|
+
- [`update_product`](#update-product)
|
|
1224
|
+
|
|
1225
|
+
### `attach_product_to_portfolio`
|
|
1226
|
+
|
|
1227
|
+
Place an existing product under a portfolio (adds it to the portfolio's `products[]` in `.upg/portfolio.upg`). Resolves the portfolio against the portfolio document and auto-registers the product on the portfolio registry. Use after `create_product`, or pass `portfolio_id` to `create_product` directly.
|
|
1228
|
+
|
|
1229
|
+
**Atomicity:** `atomic (single portfolio.upg flush).`
|
|
1230
|
+
|
|
1231
|
+
**Arguments:**
|
|
1232
|
+
|
|
1233
|
+
| Name | Type | Required | Description |
|
|
1234
|
+
| ---- | ---- | -------- | ----------- |
|
|
1235
|
+
| `portfolio_id` | string | ✓ | Portfolio id (from list_portfolios) |
|
|
1236
|
+
| `product_id` | string | ✓ | Product id (from create_product / list_local_products) |
|
|
1237
|
+
|
|
1238
|
+
**Returns:**
|
|
1239
|
+
|
|
1240
|
+
JSON: `{ product_id, container_id, container_kind: "portfolio",
|
|
1241
|
+
container_title?, already_member, registered }`.
|
|
1242
|
+
|
|
1243
|
+
**Throws:**
|
|
1244
|
+
|
|
1245
|
+
- textError on a missing workspace, an unknown product, or an unknown
|
|
1246
|
+
portfolio id (the message points at list_portfolios / list_local_products).
|
|
1247
|
+
|
|
1248
|
+
**See also:** `assign_product_to_area`, `create_product`
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
### `batch_create_cross_product_edges`
|
|
1252
|
+
|
|
1253
|
+
Create up to 50 cross-product edges in one atomic write (the portfolio-tier mirror of batch_create_edges). Every edge is validated and qualified before anything is written; if any is invalid the whole batch is rejected. Referenced products are auto-registered.
|
|
1254
|
+
|
|
1255
|
+
**Atomicity:** `atomic. All edges validated first, then a single portfolio.upg flush.`
|
|
1256
|
+
|
|
1257
|
+
**Arguments:**
|
|
1258
|
+
|
|
1259
|
+
| Name | Type | Required | Description |
|
|
1260
|
+
| ---- | ---- | -------- | ----------- |
|
|
1261
|
+
| `auto_create_portfolio` | boolean | | Create an empty portfolio document if none exists (default false) |
|
|
1262
|
+
| `edges` | array | ✓ | Cross-product edges to create (max 50). Each: { source_id, target_id, type, source_product_id?, target_product_id? }. |
|
|
1263
|
+
|
|
1264
|
+
**Returns:**
|
|
1265
|
+
|
|
1266
|
+
JSON: `{ message, created: UPGCrossEdge[], count, portfolio_file,
|
|
1267
|
+
registered_products? }`.
|
|
1268
|
+
|
|
1269
|
+
**Throws:**
|
|
1270
|
+
|
|
1271
|
+
- textError when `edges` is missing/empty/oversized, when any edge is invalid,
|
|
1272
|
+
or when no portfolio document exists (pass `auto_create_portfolio: true` to mint one).
|
|
1273
|
+
|
|
1274
|
+
**See also:** `create_cross_product_edge`, `list_cross_edge_types`
|
|
1275
|
+
|
|
1083
1276
|
|
|
1084
1277
|
### `create_cross_product_edge`
|
|
1085
1278
|
|
|
1086
|
-
Create a cross-product relationship between two entities in different products within a portfolio graph. Types: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds
|
|
1279
|
+
Create a cross-product relationship between two entities in different products within a portfolio graph. Types: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds`, `hosts` (host product runs the hosted product inside itself, directed host to hosted).
|
|
1087
1280
|
|
|
1088
1281
|
**Atomicity:** `non-atomic. Portfolio file create (if new) + edge append are
|
|
1089
1282
|
separate filesystem operations.`
|
|
@@ -1096,7 +1289,7 @@ separate filesystem operations.`
|
|
|
1096
1289
|
| `source_product_id` | string | | Product ID of the source node |
|
|
1097
1290
|
| `target_id` | string | ✓ | Target node ID |
|
|
1098
1291
|
| `target_product_id` | string | | Product ID of the target node |
|
|
1099
|
-
| `type` | `shares_persona` \| `shares_competitor` \| `shares_metric` \| `depends_on_product` \| `cannibalises` \| `succeeds` | ✓ | Cross-product relationship type |
|
|
1292
|
+
| `type` | `shares_persona` \| `shares_competitor` \| `shares_metric` \| `depends_on_product` \| `cannibalises` \| `succeeds` \| `hosts` | ✓ | Cross-product relationship type |
|
|
1100
1293
|
|
|
1101
1294
|
**Returns:**
|
|
1102
1295
|
|
|
@@ -1121,9 +1314,10 @@ portfolio edge are separate mutations.`
|
|
|
1121
1314
|
|
|
1122
1315
|
| Name | Type | Required | Description |
|
|
1123
1316
|
| ---- | ---- | -------- | ----------- |
|
|
1317
|
+
| `area_id` | string | | Optional product_area id (resolved against portfolio.upg) to place the new product under. |
|
|
1124
1318
|
| `description` | string | | Optional product description |
|
|
1125
1319
|
| `name` | string | ✓ | Product display title (required, non-empty). |
|
|
1126
|
-
| `portfolio_id` | string | | Optional portfolio
|
|
1320
|
+
| `portfolio_id` | string | | Optional portfolio id (resolved against portfolio.upg) to place the new product under. A portfolio id that resolves only in the active graph still attaches via an in-graph edge (DEPRECATED; prefer attach_product_to_portfolio). |
|
|
1127
1321
|
| `slug` | string | | Optional slug for the .upg filename. Defaults to a slug derived from `name`. Collisions append `-2`, `-3`, … |
|
|
1128
1322
|
| `stage` | string | | Product lifecycle stage. See UPGProductStage in @unified-product-graph/core. |
|
|
1129
1323
|
|
|
@@ -1141,6 +1335,56 @@ JSON: `{ message, ...result }`. `result` carries `id`, `title`,
|
|
|
1141
1335
|
**See also:** `init_workspace`
|
|
1142
1336
|
|
|
1143
1337
|
|
|
1338
|
+
### `delete_cross_product_edge`
|
|
1339
|
+
|
|
1340
|
+
Delete a cross-product edge from `.upg/portfolio.upg` by id. The inverse of `create_cross_product_edge`. Returns `deleted: false` (not an error) when no edge with that id exists.
|
|
1341
|
+
|
|
1342
|
+
**Atomicity:** `atomic (single portfolio.upg flush).`
|
|
1343
|
+
|
|
1344
|
+
**Arguments:**
|
|
1345
|
+
|
|
1346
|
+
| Name | Type | Required | Description |
|
|
1347
|
+
| ---- | ---- | -------- | ----------- |
|
|
1348
|
+
| `edge_id` | string | ✓ | Cross-product edge id (from list_portfolio_cross_edges) |
|
|
1349
|
+
|
|
1350
|
+
**Returns:**
|
|
1351
|
+
|
|
1352
|
+
JSON: `{ edge_id, deleted, edge? }`. `deleted: false` (not an error) when
|
|
1353
|
+
no edge with that id exists, so retries are idempotent.
|
|
1354
|
+
|
|
1355
|
+
**Throws:**
|
|
1356
|
+
|
|
1357
|
+
- textError on a missing workspace.
|
|
1358
|
+
|
|
1359
|
+
**See also:** `create_cross_product_edge`, `list_portfolio_cross_edges`
|
|
1360
|
+
|
|
1361
|
+
|
|
1362
|
+
### `detach_product_from_portfolio`
|
|
1363
|
+
|
|
1364
|
+
Remove a product from a portfolio's `products[]` in `.upg/portfolio.upg` (the product stays registered and in any other container). The inverse of `attach_product_to_portfolio`.
|
|
1365
|
+
|
|
1366
|
+
**Atomicity:** `atomic (single portfolio.upg flush).`
|
|
1367
|
+
|
|
1368
|
+
**Arguments:**
|
|
1369
|
+
|
|
1370
|
+
| Name | Type | Required | Description |
|
|
1371
|
+
| ---- | ---- | -------- | ----------- |
|
|
1372
|
+
| `portfolio_id` | string | ✓ | Portfolio id (from list_portfolios) |
|
|
1373
|
+
| `product_id` | string | ✓ | Product id (from list_local_products) |
|
|
1374
|
+
|
|
1375
|
+
**Returns:**
|
|
1376
|
+
|
|
1377
|
+
JSON: `{ product_id, container_id, container_kind: "portfolio",
|
|
1378
|
+
container_title?, removed }`. `removed: false` (not an error) when the product was
|
|
1379
|
+
not a member, so retries are idempotent.
|
|
1380
|
+
|
|
1381
|
+
**Throws:**
|
|
1382
|
+
|
|
1383
|
+
- textError on a missing workspace or an unknown portfolio id.
|
|
1384
|
+
|
|
1385
|
+
**See also:** `attach_product_to_portfolio`
|
|
1386
|
+
|
|
1387
|
+
|
|
1144
1388
|
### `get_organization`
|
|
1145
1389
|
|
|
1146
1390
|
Get the organisation that owns the current workspace's portfolio. Reads the singleton `portfolio.upg.organization`. Returns `{ organization: null }` when no portfolio document exists yet.
|
|
@@ -1318,6 +1562,34 @@ before any read/mutation to confirm the active product.
|
|
|
1318
1562
|
**See also:** `get_workspace_info`, `list_local_products`, `init_workspace`
|
|
1319
1563
|
|
|
1320
1564
|
|
|
1565
|
+
### `update_product`
|
|
1566
|
+
|
|
1567
|
+
Update the product header (`$upg.product`): stage, title, description, health_status, url. The supported way to advance a product's lifecycle stage; it writes the value get_graph_digest reads, without hand-editing the .upg file.
|
|
1568
|
+
|
|
1569
|
+
**Atomicity:** `atomic (single flush).`
|
|
1570
|
+
|
|
1571
|
+
**Arguments:**
|
|
1572
|
+
|
|
1573
|
+
| Name | Type | Required | Description |
|
|
1574
|
+
| ---- | ---- | -------- | ----------- |
|
|
1575
|
+
| `description` | string | | Product description. |
|
|
1576
|
+
| `health_status` | string | | Product health (free-form, e.g. on_track / at_risk). |
|
|
1577
|
+
| `stage` | string | | Product lifecycle stage (canonical UPGProductStage). |
|
|
1578
|
+
| `title` | string | | Product display title. |
|
|
1579
|
+
| `url` | string | | Product URL. |
|
|
1580
|
+
|
|
1581
|
+
**Returns:**
|
|
1582
|
+
|
|
1583
|
+
JSON: `{ product, updated: string[] }` (the fields changed).
|
|
1584
|
+
|
|
1585
|
+
**Throws:**
|
|
1586
|
+
|
|
1587
|
+
- textError when no field is supplied, when there is no product header,
|
|
1588
|
+
or when `stage` is non-canonical (same strict validation as create_product).
|
|
1589
|
+
|
|
1590
|
+
**See also:** `create_product`
|
|
1591
|
+
|
|
1592
|
+
|
|
1321
1593
|
## Schema
|
|
1322
1594
|
|
|
1323
1595
|
_Entity schema introspection. Same constraints the LSP enforces._
|
|
@@ -1887,7 +2159,7 @@ JSON: `{ kind, total, count, benchmarks: ... }`
|
|
|
1887
2159
|
|
|
1888
2160
|
### `list_cross_edge_types`
|
|
1889
2161
|
|
|
1890
|
-
List the canonical cross-product edge types from `UPG_CROSS_EDGE_TYPES`: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds`. Portfolio-level relationships across products. Distinct from the within-product `UPG_EDGE_CATALOG`.
|
|
2162
|
+
List the canonical cross-product edge types from `UPG_CROSS_EDGE_TYPES`: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds`, `hosts`. Portfolio-level relationships across products. Distinct from the within-product `UPG_EDGE_CATALOG`.
|
|
1891
2163
|
|
|
1892
2164
|
**Atomicity:** `atomic (read-only)`
|
|
1893
2165
|
|