archgraph-argo 0.10.14 → 0.10.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.
@@ -65,6 +65,7 @@ const SYSTEM_ARCHITECTURE_TOOL_NAMES = new Set([
65
65
  'updateArchitectureView',
66
66
  'removeArchitectureView',
67
67
  'generateArchitectureDiffPlantuml',
68
+ 'queryNeo4jGraph',
68
69
  ]);
69
70
 
70
71
  const TOOLS = [
@@ -781,9 +781,255 @@ function toNumber(value) {
781
781
  return Number(value);
782
782
  }
783
783
 
784
+ // --- Read-only Cypher query + structural projection schema -------------------
785
+
786
+ const FORBIDDEN_CYPHER_CLAUSES = Object.freeze([
787
+ 'CREATE',
788
+ 'MERGE',
789
+ 'DELETE',
790
+ 'SET',
791
+ 'REMOVE',
792
+ 'DROP',
793
+ 'LOAD CSV',
794
+ 'FOREACH',
795
+ 'IN TRANSACTIONS',
796
+ ]);
797
+
798
+ function stripCypherNoise(cypher) {
799
+ let result = String(cypher);
800
+ // Block comments.
801
+ result = result.replace(/\/\*[\s\S]*?\*\//g, ' ');
802
+ // Line comments.
803
+ result = result.replace(/\/\/[^\r\n]*/g, ' ');
804
+ // Single-quoted string literals.
805
+ result = result.replace(/'(?:[^'\\]|\\.)*'/g, ' ');
806
+ // Double-quoted identifiers/literals.
807
+ result = result.replace(/"(?:[^"\\]|\\.)*"/g, ' ');
808
+ // Backtick-escaped identifiers.
809
+ result = result.replace(/`(?:[^`\\]|\\.)*`/g, ' ');
810
+ return result;
811
+ }
812
+
813
+ function assertReadOnlyCypher(cypher) {
814
+ if (typeof cypher !== 'string' || cypher.trim().length === 0) {
815
+ const error = new Error('cypher must be a non-empty string');
816
+ error.category = 'CYPHER_QUERY_REQUIRED';
817
+ throw error;
818
+ }
819
+ if (cypher.length > 20000) {
820
+ const error = new Error('cypher exceeds the 20000 character limit');
821
+ error.category = 'CYPHER_QUERY_TOO_LONG';
822
+ throw error;
823
+ }
824
+
825
+ const normalized = stripCypherNoise(cypher).toUpperCase();
826
+ const found = FORBIDDEN_CYPHER_CLAUSES.find(clause => {
827
+ const escaped = clause.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
828
+ return new RegExp(`\\b${escaped}\\b`).test(normalized);
829
+ });
830
+ if (found) {
831
+ const error = new Error(`Cypher write clause '${found}' is not allowed; the Neo4j graph query interface is read-only`);
832
+ error.category = 'READ_ONLY_CYPHER_REQUIRED';
833
+ error.clause = found;
834
+ throw error;
835
+ }
836
+ return true;
837
+ }
838
+
839
+ function serializeNeo4jValue(value) {
840
+ if (value === null || value === undefined) {
841
+ return value === undefined ? null : value;
842
+ }
843
+ if (typeof value === 'number' || typeof value === 'string' || typeof value === 'boolean') {
844
+ return value;
845
+ }
846
+
847
+ let neo4j = null;
848
+ try {
849
+ neo4j = requireNeo4jDriver();
850
+ } catch {
851
+ neo4j = null;
852
+ }
853
+
854
+ if (neo4j && typeof neo4j.isInt === 'function' && neo4j.isInt(value)) {
855
+ if (typeof value.inSafeRange === 'function' && value.inSafeRange()) {
856
+ return value.toNumber();
857
+ }
858
+ return value.toString();
859
+ }
860
+ if (neo4j && typeof neo4j.isNode === 'function' && neo4j.isNode(value)) {
861
+ return {
862
+ $node: {
863
+ identity: value.identity ? String(value.identity) : null,
864
+ labels: Array.isArray(value.labels) ? value.labels : [],
865
+ properties: serializeNeo4jValue(value.properties),
866
+ },
867
+ };
868
+ }
869
+ if (neo4j && typeof neo4j.isRelationship === 'function' && neo4j.isRelationship(value)) {
870
+ return {
871
+ $relationship: {
872
+ identity: value.identity ? String(value.identity) : null,
873
+ type: value.type,
874
+ start: value.start ? String(value.start) : null,
875
+ end: value.end ? String(value.end) : null,
876
+ properties: serializeNeo4jValue(value.properties),
877
+ },
878
+ };
879
+ }
880
+ if (neo4j && typeof neo4j.isPath === 'function' && neo4j.isPath(value)) {
881
+ return {
882
+ $path: {
883
+ start: serializeNeo4jValue(value.start),
884
+ end: serializeNeo4jValue(value.end),
885
+ length: serializeNeo4jValue(value.length),
886
+ segments: Array.isArray(value.segments) ? value.segments.map(serializeNeo4jValue) : [],
887
+ },
888
+ };
889
+ }
890
+ if (Array.isArray(value)) {
891
+ return value.map(serializeNeo4jValue);
892
+ }
893
+ if (typeof value === 'object') {
894
+ const result = {};
895
+ for (const [key, item] of Object.entries(value)) {
896
+ result[key] = serializeNeo4jValue(item);
897
+ }
898
+ return result;
899
+ }
900
+ return String(value);
901
+ }
902
+
903
+ function buildNeo4jGraphSchema(architecturePath = DEFAULT_GRAPH_PATH) {
904
+ return {
905
+ graphKey: buildGraphKey(architecturePath),
906
+ nodeLabels: {
907
+ ArchitectureGraph: {
908
+ description: 'One node per canonical graph document; identified by graphKey.',
909
+ properties: [
910
+ 'graphKey',
911
+ 'source_path',
912
+ 'name',
913
+ 'description',
914
+ 'attributes_json',
915
+ 'raw_json',
916
+ 'element_count',
917
+ 'relationship_count',
918
+ 'view_count',
919
+ ],
920
+ },
921
+ Element: {
922
+ description: 'Canonical architecture elements. Element.type holds the ArchiMate element type.',
923
+ properties: [
924
+ 'graphKey',
925
+ 'id',
926
+ 'name',
927
+ 'type',
928
+ 'parent',
929
+ 'alias',
930
+ 'classifier',
931
+ 'description',
932
+ 'attributes_json',
933
+ 'subdiagram_views_json',
934
+ 'testcases_json',
935
+ 'raw_json',
936
+ ],
937
+ },
938
+ ArchitectureRelationship: {
939
+ description: 'Canonical architecture relationships. type holds the ArchiMate relationship type; source_id/target_id reference Element.id.',
940
+ properties: [
941
+ 'graphKey',
942
+ 'id',
943
+ 'name',
944
+ 'type',
945
+ 'statement',
946
+ 'description',
947
+ 'document',
948
+ 'attributes_json',
949
+ 'source_id',
950
+ 'source_name',
951
+ 'target_id',
952
+ 'target_name',
953
+ 'raw_json',
954
+ ],
955
+ },
956
+ View: {
957
+ description: 'Canonical views; identified by view_id.',
958
+ properties: [
959
+ 'graphKey',
960
+ 'view_id',
961
+ 'view_name',
962
+ 'parent_element_id',
963
+ 'parent_element_name',
964
+ 'description',
965
+ 'included_elements_json',
966
+ 'included_relationships_json',
967
+ 'raw_json',
968
+ ],
969
+ },
970
+ },
971
+ relationshipTypes: {
972
+ OWNS_ELEMENT: { from: 'ArchitectureGraph', to: 'Element' },
973
+ OWNS_RELATIONSHIP: { from: 'ArchitectureGraph', to: 'ArchitectureRelationship' },
974
+ OWNS_VIEW: { from: 'ArchitectureGraph', to: 'View' },
975
+ RELATIONSHIP_SOURCE: { from: 'ArchitectureRelationship', to: 'Element', description: 'Source endpoint element of a relationship record.' },
976
+ RELATIONSHIP_TARGET: { from: 'ArchitectureRelationship', to: 'Element', description: 'Target endpoint element of a relationship record.' },
977
+ ARCHIMATE_RELATES: { from: 'Element', to: 'Element', properties: ['graphKey', 'relationship_id'], description: 'Direct ArchiMate semantic edge between two elements.' },
978
+ VIEW_OF: { from: 'View', to: 'Element', description: 'Parent element of a sub-view.' },
979
+ INCLUDES_ELEMENT: { from: 'View', to: 'Element', properties: ['order'] },
980
+ INCLUDES_RELATIONSHIP: { from: 'View', to: 'ArchitectureRelationship', properties: ['order'] },
981
+ HAS_SUBDIAGRAM: { from: 'Element', to: 'View' },
982
+ },
983
+ };
984
+ }
985
+
986
+ async function runNeo4jCypherQuery(options = {}) {
987
+ const architecturePath = options.architecturePath || DEFAULT_GRAPH_PATH;
988
+ const cypher = options.cypher;
989
+ assertReadOnlyCypher(cypher);
990
+
991
+ const graphKey = buildGraphKey(architecturePath);
992
+ const config = getNeo4jConfig(options);
993
+ const driver = options.driver || createDriver(config);
994
+ const ownDriver = !options.driver;
995
+ const session = driver.session({ database: config.database });
996
+
997
+ try {
998
+ const result = await session.executeRead(tx => tx.run(cypher, { graphKey }));
999
+ const records = result.records.map(record => {
1000
+ const entry = {};
1001
+ for (const key of record.keys) {
1002
+ entry[key] = serializeNeo4jValue(record.get(key));
1003
+ }
1004
+ return entry;
1005
+ });
1006
+
1007
+ const summary = result.summary;
1008
+ return {
1009
+ architecturePath,
1010
+ graphKey,
1011
+ records,
1012
+ summary: {
1013
+ queryType: summary ? summary.queryType : null,
1014
+ database: summary && summary.database ? summary.database.name : null,
1015
+ containsUpdates: summary && summary.counters && typeof summary.counters.containsUpdates === 'function'
1016
+ ? summary.counters.containsUpdates()
1017
+ : null,
1018
+ },
1019
+ };
1020
+ } finally {
1021
+ await session.close();
1022
+ if (ownDriver) {
1023
+ await driver.close();
1024
+ }
1025
+ }
1026
+ }
1027
+
784
1028
  module.exports = {
785
1029
  DEFAULT_GRAPH_PATH,
1030
+ assertReadOnlyCypher,
786
1031
  buildGraphKey,
1032
+ buildNeo4jGraphSchema,
787
1033
  createDriver,
788
1034
  digestCanonicalArchitecture,
789
1035
  ensureDatabaseExists,
@@ -797,6 +1043,8 @@ module.exports = {
797
1043
  readNeo4jSyncState,
798
1044
  recoverNeo4jSyncIfNeeded,
799
1045
  resolveArchitecturePath,
1046
+ runNeo4jCypherQuery,
1047
+ serializeNeo4jValue,
800
1048
  syncArchitectureToNeo4j,
801
1049
  verifyArchitectureSync,
802
1050
  waitForDatabaseOnline,
@@ -164,7 +164,10 @@ const {
164
164
  } = require('./graph-rag/mutationEmbeddingVectorLifecycle.js');
165
165
  const {
166
166
  DEFAULT_GRAPH_PATH: NEO4J_DEFAULT_GRAPH_PATH,
167
+ buildGraphKey,
168
+ buildNeo4jGraphSchema,
167
169
  recoverNeo4jSyncIfNeeded,
170
+ runNeo4jCypherQuery,
168
171
  syncArchitectureToNeo4j,
169
172
  verifyArchitectureSync,
170
173
  } = require('./neo4j-system-architecture-store.js');
@@ -379,6 +382,19 @@ const TOOLS = [
379
382
  additionalProperties: false,
380
383
  },
381
384
  },
385
+ {
386
+ name: 'queryNeo4jGraph',
387
+ description: 'Run a read-only Cypher query against the Neo4j structural projection of the intent architecture, or request the projection schema so an agent can construct its own Cypher. Pass {schema: true} to return node labels, relationship types, property keys, and the legal ArchiMate element/relationship type enums. Pass {cypher: "..."} to execute a read-only query; scope it with {graphKey: $graphKey}. Write clauses (CREATE/MERGE/DELETE/SET/REMOVE/DROP/LOAD CSV/FOREACH/IN TRANSACTIONS) are rejected.',
388
+ inputSchema: {
389
+ type: 'object',
390
+ properties: {
391
+ architecturePath: { type: 'string', description: `Default: ${DEFAULT_GRAPH_PATH}` },
392
+ cypher: { type: 'string', description: 'Read-only Cypher query to execute. Use $graphKey to scope to the current architecture graph, e.g. MATCH (e:Element {graphKey: $graphKey}) RETURN e.id, e.name.' },
393
+ schema: { type: 'boolean', description: 'When true, return the Neo4j projection schema instead of running a Cypher query.' },
394
+ },
395
+ additionalProperties: false,
396
+ },
397
+ },
382
398
  ];
383
399
 
384
400
  // Every tool accepts an optional per-call `workspaceRoot` (absolute path,
@@ -1041,6 +1057,7 @@ function applyMutations(document, mutations) {
1041
1057
  const existingElement = findById(nextDocument.elements, mutation.element.id);
1042
1058
  if (!existingElement) {
1043
1059
  nextDocument.elements.push(clone(mutation.element));
1060
+ syncViewsToElementSubdiagramViews(nextDocument, findById(nextDocument.elements, mutation.element.id));
1044
1061
  }
1045
1062
  for (const view of scopedViews) {
1046
1063
  view.included_elements = addUnique(view.included_elements || [], [mutation.element.id]);
@@ -1065,7 +1082,12 @@ function applyMutations(document, mutations) {
1065
1082
  throw new Error(`Element '${mutation.id}' does not exist`);
1066
1083
  }
1067
1084
  requirePatchDoesNotChangeElementIdentityOrType(mutation.id, mutation.patch);
1085
+ const patchesSubdiagramViews = Object.prototype.hasOwnProperty.call(mutation.patch, 'subdiagram_views');
1086
+ const patchesName = Object.prototype.hasOwnProperty.call(mutation.patch, 'name');
1068
1087
  Object.assign(element, clone(mutation.patch));
1088
+ if (patchesSubdiagramViews || patchesName) {
1089
+ reconcileSubdiagramViewsForElement(nextDocument, element);
1090
+ }
1069
1091
  touchedElementIds.add(element.id);
1070
1092
  mutationSummaries.push({ type: mutation.type, id: element.id });
1071
1093
  continue;
@@ -1077,6 +1099,10 @@ function applyMutations(document, mutations) {
1077
1099
  if (!element) {
1078
1100
  throw new Error(`Element '${mutation.id}' does not exist`);
1079
1101
  }
1102
+ const childViewIds = collectChildViewIds(nextDocument, mutation.id);
1103
+ if (childViewIds.length > 0) {
1104
+ throw new Error(`Element '${mutation.id}' cannot be removed: it still has ${childViewIds.length} sub-view(s) mounted under it (${childViewIds.join(', ')}). Remove or re-parent those sub-views first.`);
1105
+ }
1080
1106
  const scopedViews = mutation.view_ids === undefined
1081
1107
  ? nextDocument.views
1082
1108
  : requireViewScope(nextDocument.views, mutation.view_ids, 'mutation.view_ids');
@@ -1155,13 +1181,25 @@ function applyMutations(document, mutations) {
1155
1181
  throw new Error(`Relationship '${mutation.id}' does not exist`);
1156
1182
  }
1157
1183
  requirePatchDoesNotChangeRelationshipIdentityOrType(mutation.id, mutation.patch);
1184
+ const oldSourceId = relationship.source_id;
1185
+ const oldTargetId = relationship.target_id;
1158
1186
  Object.assign(relationship, clone(mutation.patch));
1159
1187
  for (const view of nextDocument.views) {
1160
- if ((view.included_relationships || []).includes(relationship.id)) {
1161
- view.included_elements = addUnique(view.included_elements || [], [
1162
- relationship.source_id,
1163
- relationship.target_id,
1164
- ]);
1188
+ if (!(view.included_relationships || []).includes(relationship.id)) {
1189
+ continue;
1190
+ }
1191
+ view.included_elements = addUnique(view.included_elements || [], [
1192
+ relationship.source_id,
1193
+ relationship.target_id,
1194
+ ]);
1195
+ for (const oldEndpointId of [oldSourceId, oldTargetId]) {
1196
+ if (oldEndpointId === relationship.source_id || oldEndpointId === relationship.target_id) {
1197
+ continue;
1198
+ }
1199
+ if (isElementUsedByRelationship(nextDocument, view, oldEndpointId, relationship.id)) {
1200
+ continue;
1201
+ }
1202
+ view.included_elements = removeEntries(view.included_elements || [], [oldEndpointId]);
1165
1203
  }
1166
1204
  }
1167
1205
  touchedRelationshipIds.add(relationship.id);
@@ -1180,6 +1218,12 @@ function applyMutations(document, mutations) {
1180
1218
  : requireViewScope(nextDocument.views, mutation.view_ids, 'mutation.view_ids');
1181
1219
  for (const view of scopedViews) {
1182
1220
  view.included_relationships = removeEntries(view.included_relationships || [], [mutation.id]);
1221
+ for (const endpointId of [relationship.source_id, relationship.target_id]) {
1222
+ if (isElementUsedByRelationship(nextDocument, view, endpointId, mutation.id)) {
1223
+ continue;
1224
+ }
1225
+ view.included_elements = removeEntries(view.included_elements || [], [endpointId]);
1226
+ }
1183
1227
  touchedViewIds.add(view.view_id);
1184
1228
  }
1185
1229
  const stillIncludedInView = nextDocument.views.some(view => (
@@ -1349,6 +1393,78 @@ function upsertSubdiagramViewIntoElement(document, elementId, view) {
1349
1393
  }
1350
1394
  }
1351
1395
 
1396
+ // Forward-sync: make every view listed in `element.subdiagram_views` point back
1397
+ // to this element (stealing the view from any previous parent when necessary).
1398
+ function syncViewsToElementSubdiagramViews(document, element) {
1399
+ if (!element || !Array.isArray(element.subdiagram_views)) {
1400
+ return;
1401
+ }
1402
+ for (const entry of element.subdiagram_views) {
1403
+ if (!entry || !entry.view_id) {
1404
+ continue;
1405
+ }
1406
+ const view = findView(document.views, entry.view_id);
1407
+ if (!view) {
1408
+ continue;
1409
+ }
1410
+ if (view.parent_element_id && view.parent_element_id !== element.id) {
1411
+ removeSubdiagramViewFromElement(document, view.parent_element_id, view.view_id);
1412
+ }
1413
+ view.parent_element_id = element.id;
1414
+ view.parent_element_name = element.name;
1415
+ }
1416
+ }
1417
+
1418
+ // Bidirectional sync after an element's subdiagram_views (or name) changed:
1419
+ // listed views point back, and views no longer listed stop pointing at this element.
1420
+ function reconcileSubdiagramViewsForElement(document, element) {
1421
+ const currentViewIds = new Set(
1422
+ (element.subdiagram_views || [])
1423
+ .filter(entry => entry && entry.view_id)
1424
+ .map(entry => entry.view_id),
1425
+ );
1426
+ syncViewsToElementSubdiagramViews(document, element);
1427
+ for (const view of document.views || []) {
1428
+ if (view && view.parent_element_id === element.id && !currentViewIds.has(view.view_id)) {
1429
+ delete view.parent_element_id;
1430
+ delete view.parent_element_name;
1431
+ }
1432
+ }
1433
+ }
1434
+
1435
+ function collectChildViewIds(document, elementId) {
1436
+ const viewIds = new Set();
1437
+ const element = findById(document.elements, elementId);
1438
+ if (element && Array.isArray(element.subdiagram_views)) {
1439
+ for (const entry of element.subdiagram_views) {
1440
+ if (entry && entry.view_id) {
1441
+ viewIds.add(entry.view_id);
1442
+ }
1443
+ }
1444
+ }
1445
+ for (const view of document.views || []) {
1446
+ if (view && view.parent_element_id === elementId && view.view_id) {
1447
+ viewIds.add(view.view_id);
1448
+ }
1449
+ }
1450
+ return Array.from(viewIds);
1451
+ }
1452
+
1453
+ // Whether any relationship in the view (other than exceptRelationshipId) still
1454
+ // references elementId as one of its endpoints.
1455
+ function isElementUsedByRelationship(document, view, elementId, exceptRelationshipId) {
1456
+ for (const relationshipId of view.included_relationships || []) {
1457
+ if (relationshipId === exceptRelationshipId) {
1458
+ continue;
1459
+ }
1460
+ const relationship = findById(document.relationships, relationshipId);
1461
+ if (relationship && (relationship.source_id === elementId || relationship.target_id === elementId)) {
1462
+ return true;
1463
+ }
1464
+ }
1465
+ return false;
1466
+ }
1467
+
1352
1468
  function addUnique(existing, additions) {
1353
1469
  const result = Array.isArray(existing) ? [...existing] : [];
1354
1470
  for (const addition of additions) {
@@ -2054,9 +2170,80 @@ async function callTool(name, args = {}, dependencies = undefined) {
2054
2170
  return mutationToolResult(attachContextWarnings(await buildMutationResult(context, [{ type: 'removeView', view_id: args.view_id }], write), context), write);
2055
2171
  }
2056
2172
 
2173
+ if (name === 'queryNeo4jGraph') {
2174
+ return queryNeo4jGraphTool(args);
2175
+ }
2176
+
2057
2177
  throw new Error(`Unknown tool: ${name}`);
2058
2178
  }
2059
2179
 
2180
+ async function queryNeo4jGraphTool(args = {}) {
2181
+ const architecturePath = args.architecturePath || DEFAULT_GRAPH_PATH;
2182
+
2183
+ if (args.schema === true) {
2184
+ return queryNeo4jGraphSchemaResult(architecturePath);
2185
+ }
2186
+
2187
+ try {
2188
+ const result = await runNeo4jCypherQuery({
2189
+ architecturePath,
2190
+ cypher: args.cypher,
2191
+ });
2192
+ return toolResult({
2193
+ status: 'passed',
2194
+ architecturePath: result.architecturePath,
2195
+ graphKey: result.graphKey,
2196
+ records: result.records,
2197
+ summary: result.summary,
2198
+ });
2199
+ } catch (error) {
2200
+ return toolResult(queryError(
2201
+ error && error.category ? error.category : 'NEO4J_QUERY_FAILED',
2202
+ String(error && error.message ? error.message : error),
2203
+ {
2204
+ architecturePath,
2205
+ graphKey: buildGraphKey(architecturePath),
2206
+ ...(error && error.clause ? { clause: error.clause } : {}),
2207
+ },
2208
+ ));
2209
+ }
2210
+ }
2211
+
2212
+ function queryNeo4jGraphSchemaResult(architecturePath) {
2213
+ const schema = buildNeo4jGraphSchema(architecturePath);
2214
+ let typeEnums = {};
2215
+ try {
2216
+ const workspaceRoot = resolveWorkspaceRoot({ architecturePath });
2217
+ const schemaPath = resolveSchemaPath(workspaceRoot);
2218
+ const jsonSchema = readJson(schemaPath.absolutePath, schemaPath.relativePath);
2219
+ typeEnums = {
2220
+ archimateElementTypes: (jsonSchema.$defs.archimateElementType || {}).enum || [],
2221
+ archimateRelationshipTypes: (jsonSchema.$defs.archimateRelationshipType || {}).enum || [],
2222
+ };
2223
+ } catch (error) {
2224
+ typeEnums = {
2225
+ archimateElementTypes: [],
2226
+ archimateRelationshipTypes: [],
2227
+ schemaEnumError: String(error && error.message ? error.message : error),
2228
+ };
2229
+ }
2230
+
2231
+ return toolResult({
2232
+ status: 'passed',
2233
+ architecturePath,
2234
+ graphKey: buildGraphKey(architecturePath),
2235
+ schema: {
2236
+ ...schema,
2237
+ ...typeEnums,
2238
+ },
2239
+ usage: {
2240
+ scopeGraph: 'MATCH (e:Element {graphKey: $graphKey}) ...',
2241
+ exampleAllBusinessActors: "MATCH (e:Element {graphKey: $graphKey}) WHERE e.type = 'Business Actor' RETURN e.id, e.name, e.description",
2242
+ exampleAssignments: "MATCH (a:Element {graphKey: $graphKey, type: 'Business Actor'})-[r:ARCHIMATE_RELATES]->(b:Element {graphKey: $graphKey}) WHERE r.relationship_id IS NOT NULL RETURN a.name, type(r), b.name, r.relationship_id",
2243
+ },
2244
+ });
2245
+ }
2246
+
2060
2247
  async function resolveSemanticOperatorJourney(dependencies) {
2061
2248
  return dependencies && dependencies.semanticOperatorJourney
2062
2249
  ? dependencies.semanticOperatorJourney
package/install-argo.ps1 CHANGED
@@ -726,7 +726,7 @@ if ($SkipDsh) {
726
726
  Write-DshManagedBlock -Path $patchPath -Block $block -MarkerStart '# BEGIN ArchGraph ARGO deployment' -MarkerEnd '# END ArchGraph ARGO deployment'
727
727
  }
728
728
 
729
- Write-Host "[19/19] argo\agents2 -> $DshHome\.agent-presets\<id> (DeepSeek Harness agent presets)"
729
+ Write-Host "[19/19] argo\agents5 -> $DshHome\.agent-presets\<id> (DeepSeek Harness agent presets)"
730
730
  New-DshAgentPresets -DshHome $DshHome -AgentsSrc (Join-Path $argoDir 'agents')
731
731
 
732
732
  Write-Host ' Restart `dsh web` to activate the MCP bridge and the wakeup plugin;'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archgraph-argo",
3
- "version": "0.10.14",
3
+ "version": "0.10.16",
4
4
  "description": "Deploy the ArchGraph ARGO toolchain, skills, and rules (schema, scripts, argo-init skill, global rule) with one command.",
5
5
  "license": "MIT",
6
6
  "bin": {