archgraph-argo 0.16.0 → 0.16.2
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.
|
@@ -740,24 +740,66 @@ function syncGraphToQea(graph, qeaPath, opts) {
|
|
|
740
740
|
stages.members = nowMs();
|
|
741
741
|
|
|
742
742
|
// --- deletion reconcile (opt-in) ---------------------------------------
|
|
743
|
+
// Elements are anchored by t_object.Alias; relationships have NO Alias column — their
|
|
744
|
+
// canonical id lives in t_connectortag(schema_id). Using row.Alias for relationships made
|
|
745
|
+
// the candidate check always false, so deleted relationships were never projected out.
|
|
743
746
|
const keepAliases = new Set();
|
|
744
747
|
for (const e of graph.elements || []) { if (e && e.id !== undefined) { keepAliases.add(String(e.id)); } }
|
|
745
748
|
for (const rel of graph.relationships || []) { if (rel && rel.id !== undefined) { keepAliases.add(String(rel.id)); } }
|
|
749
|
+
// connector id -> canonical relationship id (schema_id tag)
|
|
750
|
+
const relSchemaById = new Map();
|
|
751
|
+
try {
|
|
752
|
+
const relTagRows = db.prepare("SELECT ElementID, VALUE FROM t_connectortag WHERE Property='schema_id'").all();
|
|
753
|
+
for (const t of relTagRows) { relSchemaById.set(Number(t.ElementID), String(t.VALUE)); }
|
|
754
|
+
} catch { /* table may be absent on a hand-drawn model */ }
|
|
746
755
|
const candidates = [];
|
|
747
756
|
for (const row of existingElems) {
|
|
748
757
|
if (row.Alias && !keepAliases.has(String(row.Alias))) { candidates.push({ type: 'element', id: Number(row.Object_ID), alias: row.Alias }); }
|
|
749
758
|
}
|
|
750
759
|
for (const row of existingRels) {
|
|
751
|
-
|
|
760
|
+
const relId = relSchemaById.get(Number(row.Connector_ID));
|
|
761
|
+
if (relId !== undefined && !keepAliases.has(relId)) { candidates.push({ type: 'relationship', id: Number(row.Connector_ID), alias: relId }); }
|
|
762
|
+
}
|
|
763
|
+
// views: a projected diagram is owned by the projector. Identify its canonical view id via
|
|
764
|
+
// the schema_view_id StyleEx token, or (when EA rewrote StyleEx and dropped the token) by
|
|
765
|
+
// matching the deterministic diagram ea_guid `diag:<viewId>` against the view-id catalog
|
|
766
|
+
// that kg_sync_meta retains. A view id no longer in canonical -> delete the diagram.
|
|
767
|
+
const canonicalViewIds = new Set();
|
|
768
|
+
for (const v of graph.views || []) { if (v && v.view_id !== undefined && v.view_id !== null) { canonicalViewIds.add(String(v.view_id)); } }
|
|
769
|
+
const guidToView = new Map();
|
|
770
|
+
try {
|
|
771
|
+
const viewMetaRows = db.prepare("SELECT key FROM kg_sync_meta WHERE kind='view'").all();
|
|
772
|
+
for (const r of viewMetaRows) { guidToView.set(deterministicGuid('diag:' + String(r.key)), String(r.key)); }
|
|
773
|
+
} catch { /* meta table may be absent */ }
|
|
774
|
+
for (const d of existingDiags) {
|
|
775
|
+
let vid = parseStyleToken(d.StyleEx, 'schema_view_id');
|
|
776
|
+
if (!vid && d.ea_guid) { vid = guidToView.get(String(d.ea_guid)) || ''; }
|
|
777
|
+
if (vid && !canonicalViewIds.has(String(vid))) { candidates.push({ type: 'diagram', id: Number(d.Diagram_ID), alias: String(vid) }); }
|
|
752
778
|
}
|
|
753
779
|
stats.deleteCandidates = candidates.length;
|
|
754
780
|
if (candidates.length > 0 && o.allowDelete && !o.dryRun) {
|
|
755
781
|
for (const c of candidates) {
|
|
756
782
|
if (c.type === 'relationship') {
|
|
783
|
+
// SQLite has no FK cascade: clear the connector's tag + diagram-link rows too.
|
|
784
|
+
db.prepare('DELETE FROM t_connectortag WHERE ElementID=?').run(c.id);
|
|
785
|
+
db.prepare('DELETE FROM t_diagramlinks WHERE ConnectorID=?').run(c.id);
|
|
757
786
|
db.prepare('DELETE FROM t_connector WHERE Connector_ID=?').run(c.id);
|
|
787
|
+
} else if (c.type === 'diagram') {
|
|
788
|
+
db.prepare('DELETE FROM t_diagramobjects WHERE Diagram_ID=?').run(c.id);
|
|
789
|
+
db.prepare('DELETE FROM t_diagramlinks WHERE DiagramID=?').run(c.id);
|
|
790
|
+
db.prepare('DELETE FROM t_diagram WHERE Diagram_ID=?').run(c.id);
|
|
758
791
|
} else {
|
|
792
|
+
// remove connectors attached to this element (start or end) and their children
|
|
793
|
+
const attached = db.prepare('SELECT Connector_ID FROM t_connector WHERE Start_Object_ID=? OR End_Object_ID=?').all(c.id, c.id);
|
|
794
|
+
for (const a of attached) {
|
|
795
|
+
db.prepare('DELETE FROM t_connectortag WHERE ElementID=?').run(Number(a.Connector_ID));
|
|
796
|
+
db.prepare('DELETE FROM t_diagramlinks WHERE ConnectorID=?').run(Number(a.Connector_ID));
|
|
797
|
+
db.prepare('DELETE FROM t_connector WHERE Connector_ID=?').run(Number(a.Connector_ID));
|
|
798
|
+
}
|
|
759
799
|
db.prepare('DELETE FROM t_diagramobjects WHERE Object_ID=?').run(c.id);
|
|
760
800
|
db.prepare('DELETE FROM t_objectproperties WHERE Object_ID=?').run(c.id);
|
|
801
|
+
db.prepare('DELETE FROM t_attribute WHERE Object_ID=?').run(c.id);
|
|
802
|
+
db.prepare('DELETE FROM t_objecttests WHERE Object_ID=?').run(c.id);
|
|
761
803
|
db.prepare('DELETE FROM t_object WHERE Object_ID=?').run(c.id);
|
|
762
804
|
}
|
|
763
805
|
stats.deleted++;
|
|
@@ -1948,7 +1948,11 @@ function runQeaProjection(target) {
|
|
|
1948
1948
|
return;
|
|
1949
1949
|
}
|
|
1950
1950
|
const snapshotDir = path.join(target.workspaceRoot, '.argo', 'temp', 'qea-backups');
|
|
1951
|
-
|
|
1951
|
+
// -y enables the projection-owned delete reconcile: objects that carry a schema anchor
|
|
1952
|
+
// (t_object.Alias / t_connectortag schema_id) but are no longer in canonical are removed
|
|
1953
|
+
// from the .qea, so a graph-side deletion actually disappears from EA on the next
|
|
1954
|
+
// projection. Human-drawn (un-anchored) content is never a delete candidate.
|
|
1955
|
+
const args = [script, '--mode', 'sync', '--graph', target.graphPath, '--qea', target.qeaPath, '--snapshot-dir', snapshotDir, '-y'];
|
|
1952
1956
|
const started = Date.now();
|
|
1953
1957
|
let stderr = '';
|
|
1954
1958
|
let child;
|
|
@@ -2313,7 +2317,9 @@ async function callTool(name, args = {}, dependencies = undefined) {
|
|
|
2313
2317
|
}
|
|
2314
2318
|
}
|
|
2315
2319
|
|
|
2316
|
-
const journey = await resolveSemanticOperatorJourney(dependencies
|
|
2320
|
+
const journey = await resolveSemanticOperatorJourney(dependencies, {
|
|
2321
|
+
repositoryRoot: context.workspaceRoot,
|
|
2322
|
+
});
|
|
2317
2323
|
return applySemanticResponseProfile(await journey.query(query), query, contractOptions);
|
|
2318
2324
|
}
|
|
2319
2325
|
|
|
@@ -2429,7 +2435,9 @@ async function memorySearchTool(args = {}, dependencies = undefined) {
|
|
|
2429
2435
|
const context = await loadContext(args);
|
|
2430
2436
|
let retrieved;
|
|
2431
2437
|
try {
|
|
2432
|
-
const journey = await resolveSemanticOperatorJourney(dependencies
|
|
2438
|
+
const journey = await resolveSemanticOperatorJourney(dependencies, {
|
|
2439
|
+
repositoryRoot: context.workspaceRoot,
|
|
2440
|
+
});
|
|
2433
2441
|
retrieved = await journey.query({ purpose: 'general', intent: query });
|
|
2434
2442
|
} catch (error) {
|
|
2435
2443
|
return {
|
|
@@ -2581,10 +2589,21 @@ function queryNeo4jGraphSchemaResult(architecturePath, workspaceRoot) {
|
|
|
2581
2589
|
});
|
|
2582
2590
|
}
|
|
2583
2591
|
|
|
2584
|
-
async function resolveSemanticOperatorJourney(dependencies) {
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2592
|
+
async function resolveSemanticOperatorJourney(dependencies, options = {}) {
|
|
2593
|
+
if (dependencies && dependencies.semanticOperatorJourney) {
|
|
2594
|
+
return dependencies.semanticOperatorJourney;
|
|
2595
|
+
}
|
|
2596
|
+
// Thread the caller's already-resolved workspace root into the journey: the
|
|
2597
|
+
// no-arg resolveWorkspaceRoot() fallback is process.cwd(), i.e. whatever
|
|
2598
|
+
// directory the host launched this server from (a global ~/.argo installation
|
|
2599
|
+
// started by the host process resolves to that host's cwd, e.g.
|
|
2600
|
+
// C:\Windows\System32), never the workspace the caller asked for.
|
|
2601
|
+
const repositoryRoot = options && typeof options.repositoryRoot === 'string'
|
|
2602
|
+
? options.repositoryRoot
|
|
2603
|
+
: '';
|
|
2604
|
+
return createDefaultProductionSemanticOperatorJourney(
|
|
2605
|
+
repositoryRoot ? { repositoryRoot } : {},
|
|
2606
|
+
);
|
|
2588
2607
|
}
|
|
2589
2608
|
|
|
2590
2609
|
async function executeSemanticSystemArchitectureQuery(args, dependencies) {
|
package/package.json
CHANGED