archgraph-argo 0.15.3 → 0.16.1
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;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ea-human-reconcile
|
|
3
|
+
description: "把人类从 EA 提取的 draft 提议(results/human-draft.md,内嵌 JSON 提议集)交给 Agent 后,Agent 结合当前全局(canonical 意图图 design/KG/SystemArchitecture.json + Neo4j 语义检索)逐条/整体分析并给出建议,最终由人类裁决是否写入。它是『人类 EA 草稿 → 语义 diff 提取 → 人类裁决写回』的最后一步:Agent 只做分析+建议,绝不自作主张 apply。Use when the user hands over an EA human-draft proposal set (human-draft.md) and wants the agent to analyze it against the whole architecture and propose, leaving the final decision to the human. Keywords: EA human draft, reconcile, EA 人类草稿裁决, draft review, 语义diff建议, ARGO preview/apply, 人类裁决."
|
|
4
|
+
argument-hint: human-draft
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# EA HUMAN DRAFT RECONCILE(EA 人类草稿 → Agent 分析建议 → 人类裁决)
|
|
9
|
+
|
|
10
|
+
Agent 的职责:结合全局分析 draft 中的每条提议、给出建议与理由、识别风险,把结论呈现给人类,由人类裁决。Agent 不自动执行写入。
|
|
11
|
+
|
|
12
|
+
## 前置
|
|
13
|
+
|
|
14
|
+
- [ ] 存在 `results/human-draft.md`(人类从 EA 提取的草稿提议集)。
|
|
15
|
+
- [ ] 工作区有 `design/KG/SystemArchitecture.json`(canonical 意图图)——分析全局的依据。
|
|
16
|
+
- [ ] ARGO MCP 可用。关键查询手段:
|
|
17
|
+
- 语义/上下文:`getSystemArchitecture`(带 query.purpose + query.intent)、`getIntentElementContext`(看单个元素/关系/视图的依赖与受影响对象)。
|
|
18
|
+
- 结构/类型:`queryNeo4jGraph`(只读 Cypher,如 `MATCH (e:Element {graphKey: $graphKey, type:'Business Actor'}) ...`;先 `{schema:true}` 查投影 schema)。
|
|
19
|
+
- 校验:`validateSystemArchitecture`;写图:`previewSystemArchitectureMutation` / `applySystemArchitectureMutation`。
|
|
20
|
+
|
|
21
|
+
## 原则
|
|
22
|
+
|
|
23
|
+
- **人类裁决**:Agent 只分析、给建议、识别风险;**MUST NOT 未经人类裁决就 `applySystemArchitectureMutation`(或任何写图)**。人类拍板(采纳/拒绝/修改)后才写。
|
|
24
|
+
- **全局优先**:不只对着 draft 字段,要用查询手段读 canonical 中相关对象及其依赖(被谁引用、级联影响谁、子视图是否悬空、命名/类型是否与全局一致、是否与既有元素重复冲突),再下判断。
|
|
25
|
+
- **删除/破坏性提议单独把关**:对 `removeElement` / `removeRelationship` / `removeView`,必须指出 canonical 里谁引用它、删除会级联影响谁,并给出「保留 / 改挂 / 确认删除」的建议,交由人类确认。
|
|
26
|
+
- **新增/更新提议**:核对 type / name / description / attributes 是否与全局命名与类型一致、是否与既有元素/关系重复冲突、应挂在哪个 parent / 视图下。
|
|
27
|
+
- **视图提议**:核对成员是否落在正确层级(parent_element_id 是否合理)、删视图会否使相关 subdiagram_views 悬空。
|
|
28
|
+
- **只读取、不泄露**:MUST NOT 读取/复述 `.env` 里的 secret 或推断敏感配置值。
|
|
29
|
+
|
|
30
|
+
## 目标
|
|
31
|
+
|
|
32
|
+
读 draft → 结合全局逐条分析 → 给出「逐条建议 + 整体结论 + 待人类裁决项」。具体产出:
|
|
33
|
+
|
|
34
|
+
1. **操作统计**:add/update/remove × element/relationship/view。
|
|
35
|
+
2. **逐条建议**:每条含 `提议`(op + id/名称)、`分析`(全局依赖/冲突/层级)、`建议`(采纳/拒绝/修改后采纳,附理由)、`风险`(若有)。
|
|
36
|
+
3. **整体结论**:这批草稿的整体风险等级、必人工确认的高风险项。
|
|
37
|
+
4. **待裁决**:明确列出需人类拍板的条目,并询问哪些采纳、哪些修改、哪些拒绝。
|
|
38
|
+
|
|
39
|
+
**等待人类答复之后**才进入写回;若人类同意,才经 `previewSystemArchitectureMutation` →(确认后)`applySystemArchitectureMutation`;拒绝/搁置的不写。
|
package/install-argo.ps1
CHANGED
|
@@ -761,6 +761,9 @@ $skillSrc = Join-Path (Join-Path $argoDir 'skills') 'argo-init'
|
|
|
761
761
|
$skillDest = Join-Path $SkillsRoot 'argo-init'
|
|
762
762
|
Write-Host "[4/22] argo\skills\argo-init -> $skillDest"
|
|
763
763
|
Copy-Tree -Source $skillSrc -Destination $skillDest
|
|
764
|
+
$reconcileSkillSrc = Join-Path (Join-Path $argoDir 'skills') 'ea-human-reconcile'
|
|
765
|
+
Write-Host ' argo\skills\ea-human-reconcile -> $SkillsRoot\ea-human-reconcile (EA human draft reconcile skill)'
|
|
766
|
+
Copy-Tree -Source $reconcileSkillSrc -Destination (Join-Path $SkillsRoot 'ea-human-reconcile')
|
|
764
767
|
|
|
765
768
|
$ruleSrc = Join-Path (Join-Path $argoDir 'rules') 'archgraph.instructions.md'
|
|
766
769
|
$ruleDest = Join-Path $PromptsRoot 'archgraph.instructions.md'
|
|
@@ -776,6 +779,8 @@ Copy-Item -Force -Path $depsSrc -Destination $depsDest
|
|
|
776
779
|
$cursorSkillDest = Join-Path $CursorSkillsRoot 'argo-init'
|
|
777
780
|
Write-Host "[7/22] argo\skills\argo-init -> $cursorSkillDest (Cursor)"
|
|
778
781
|
Copy-Tree -Source $skillSrc -Destination $cursorSkillDest
|
|
782
|
+
Write-Host ' argo\skills\ea-human-reconcile -> $CursorSkillsRoot\ea-human-reconcile (Cursor)'
|
|
783
|
+
Copy-Tree -Source $reconcileSkillSrc -Destination (Join-Path $CursorSkillsRoot 'ea-human-reconcile')
|
|
779
784
|
|
|
780
785
|
$mcpBridgeSrc = Join-Path $argoDir 'mcp-bridges'
|
|
781
786
|
$mcpBridgeDest = Join-Path $CursorMcpBridgesRoot ''
|
|
@@ -785,6 +790,8 @@ Copy-Tree -Source $mcpBridgeSrc -Destination $mcpBridgeDest
|
|
|
785
790
|
$openCodeSkillDest = Join-Path $OpenCodeSkillsRoot 'argo-init'
|
|
786
791
|
Write-Host "[8/22] argo\skills\argo-init -> $openCodeSkillDest (OpenCode)"
|
|
787
792
|
Copy-Tree -Source $skillSrc -Destination $openCodeSkillDest
|
|
793
|
+
Write-Host ' argo\skills\ea-human-reconcile -> $OpenCodeSkillsRoot\ea-human-reconcile (OpenCode)'
|
|
794
|
+
Copy-Tree -Source $reconcileSkillSrc -Destination (Join-Path $OpenCodeSkillsRoot 'ea-human-reconcile')
|
|
788
795
|
|
|
789
796
|
Write-Host "[9/22] argo\rules\archgraph.instructions.md -> $OpenCodeAgentsPath (OpenCode global AGENTS.md)"
|
|
790
797
|
Add-AgentsRule -AgentsPath $OpenCodeAgentsPath -RulePath $ruleSrc
|
|
@@ -822,6 +829,8 @@ if ($SkipDsh) {
|
|
|
822
829
|
|
|
823
830
|
Write-Host "[16/22] argo\skills\argo-init -> $dshSkillDest (DeepSeek Harness skill)"
|
|
824
831
|
Copy-Tree -Source (Join-Path $argoDir 'skills\argo-init') -Destination $dshSkillDest
|
|
832
|
+
Write-Host ' argo\skills\ea-human-reconcile -> $DshHome\skills\ea-human-reconcile (DeepSeek Harness skill)'
|
|
833
|
+
Copy-Tree -Source (Join-Path $argoDir 'skills\ea-human-reconcile') -Destination (Join-Path (Join-Path $DshHome 'skills') 'ea-human-reconcile')
|
|
825
834
|
|
|
826
835
|
Write-Host "[17/22] argo\rules\<WakeupGuideline> -> $DshHome\plugins\dsh-argo-wakeup\index.js (DeepSeek Harness wakeup plugin)"
|
|
827
836
|
$wakeupDshPath = New-DshWakeupPlugin -DshHome $DshHome -RuleText $ruleSrcContent
|
|
@@ -883,6 +892,8 @@ if ($SkipOpenClaw) {
|
|
|
883
892
|
|
|
884
893
|
Write-Host "[21/22] argo\skills\argo-init -> $openClawSkillDest (OpenClaw managed skill, all agents)"
|
|
885
894
|
Copy-Tree -Source (Join-Path $argoDir 'skills\argo-init') -Destination $openClawSkillDest
|
|
895
|
+
Write-Host ' argo\skills\ea-human-reconcile -> $OpenClawHome\skills\ea-human-reconcile (OpenClaw managed skill, all agents)'
|
|
896
|
+
Copy-Tree -Source (Join-Path $argoDir 'skills\ea-human-reconcile') -Destination (Join-Path (Join-Path $OpenClawHome 'skills') 'ea-human-reconcile')
|
|
886
897
|
|
|
887
898
|
Write-Host ' OpenClaw injects AGENTS.md into Project Context on every session, so the wakeup'
|
|
888
899
|
Write-Host ' gate (UNCONDITIONAL STARTUP GATE) is active on the next OpenClaw session; restart'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archgraph-argo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
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": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"argo/plugins",
|
|
15
15
|
"argo/mcp-bridges",
|
|
16
16
|
"argo/skills/argo-init",
|
|
17
|
+
"argo/skills/ea-human-reconcile",
|
|
17
18
|
"argo/rules",
|
|
18
19
|
"argo/package.json",
|
|
19
20
|
"vendor",
|