@dawipong/opcflow 0.4.0 → 0.5.0
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.en.md +3 -1
- package/README.md +3 -2
- package/dist/cli.mjs +199 -20
- package/package.json +3 -1
- package/web/dist/assets/{abnfDiagram-VRR7QNED-DAx6EpGI.js → abnfDiagram-VRR7QNED-Cwj4KBKb.js} +1 -1
- package/web/dist/assets/{arc-DPoWLLje.js → arc-Ci--dbFA.js} +1 -1
- package/web/dist/assets/architecture-TIHT7OUA-Dx_ZsFnL.js +1 -0
- package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-Dvr2nr59.js → architectureDiagram-ZJ3FMSHR-B83QZuM-.js} +2 -2
- package/web/dist/assets/{blockDiagram-677ZJIJ3-CUYUzMZC.js → blockDiagram-677ZJIJ3-C5lnvD0j.js} +1 -1
- package/web/dist/assets/{c4Diagram-LMCZKHZV-DhT2uxnj.js → c4Diagram-LMCZKHZV-Di1TmZQy.js} +1 -1
- package/web/dist/assets/channel-Bk0jbqCs.js +1 -0
- package/web/dist/assets/{chunk-32BRIVSS-CztnJRkA.js → chunk-32BRIVSS-BWSjcFoD.js} +1 -1
- package/web/dist/assets/{chunk-C7G6YPKG-jsbUGVSb.js → chunk-C7G6YPKG-DSkQqM00.js} +1 -1
- package/web/dist/assets/{chunk-EX3LRPZG-M3QhKBUG.js → chunk-EX3LRPZG-DOdm7LPI.js} +1 -1
- package/web/dist/assets/{chunk-HOUHSVGY-DDAtZMtg.js → chunk-HOUHSVGY-D1LueKb6.js} +1 -1
- package/web/dist/assets/{chunk-ICXQ74PX-C2h9d1ob.js → chunk-ICXQ74PX-CFh6Ch4J.js} +1 -1
- package/web/dist/assets/{chunk-MOJQB5TN-DXlFl9Jv.js → chunk-MOJQB5TN-BrFLYoih.js} +1 -1
- package/web/dist/assets/{chunk-OGEWGWER-B5mrusUD.js → chunk-OGEWGWER-C1n7EcC_.js} +1 -1
- package/web/dist/assets/{chunk-PUDLZKDR-BTWHaeTZ.js → chunk-PUDLZKDR-D4rKEnrx.js} +1 -1
- package/web/dist/assets/{chunk-Q4XR5HBZ-Cfw3UWMb.js → chunk-Q4XR5HBZ-DVm0yUET.js} +1 -1
- package/web/dist/assets/{chunk-RYQCIY6F-CCUojmgb.js → chunk-RYQCIY6F-BlZZOayN.js} +1 -1
- package/web/dist/assets/{chunk-V7JOEXUC-Cbgml1c1.js → chunk-V7JOEXUC-Bb-id9Vk.js} +1 -1
- package/web/dist/assets/{chunk-VR4S4FIN-CUMv178C.js → chunk-VR4S4FIN-DbbNoX70.js} +1 -1
- package/web/dist/assets/{chunk-WYO6CB5R-BaRUDpDl.js → chunk-WYO6CB5R-C0vPAP7X.js} +1 -1
- package/web/dist/assets/{chunk-XXDRQBXY-tmq33VNh.js → chunk-XXDRQBXY-BS9H__hw.js} +1 -1
- package/web/dist/assets/{chunk-ZGVPDNZ5-DK9a-Iwy.js → chunk-ZGVPDNZ5-BiBGMdZe.js} +1 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-XODf2seK.js +1 -0
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-XODf2seK.js +1 -0
- package/web/dist/assets/{cose-bilkent-JH36ORCC-BV8ttTSE.js → cose-bilkent-JH36ORCC-TcTcCWyr.js} +1 -1
- package/web/dist/assets/{cynefin-VYW2F7L2-BncvlU8s.js → cynefin-VYW2F7L2-D6vfZhRU.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-TSTJHNR4-DrrKaXmw.js → cynefinDiagram-TSTJHNR4-BQ_p-vVW.js} +1 -1
- package/web/dist/assets/{dagre-VKFMJZFB-BxDsa977.js → dagre-VKFMJZFB-sC49sUfv.js} +1 -1
- package/web/dist/assets/{diagram-FQU43EPY-DkeAFpQM.js → diagram-FQU43EPY-znBmjqaC.js} +1 -1
- package/web/dist/assets/{diagram-G47NLZAW-BxVnT5Li.js → diagram-G47NLZAW-BFZHUq5q.js} +1 -1
- package/web/dist/assets/{diagram-NH7WQ7WH-BT56mGuK.js → diagram-NH7WQ7WH-CnF3KhFt.js} +1 -1
- package/web/dist/assets/{diagram-OA4YK3LP-CezybdJA.js → diagram-OA4YK3LP-DyxQbSTl.js} +1 -1
- package/web/dist/assets/{diagram-WEI45ONY-CO8JNWNf.js → diagram-WEI45ONY-u45fnoLo.js} +1 -1
- package/web/dist/assets/{dist-zlHGdC4Y.js → dist-DeM6hNwF.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-CCIWWBDH-B-OkdWz4.js → ebnfDiagram-CCIWWBDH-CRWFKre6.js} +1 -1
- package/web/dist/assets/{erDiagram-Q63AITRT-DQNn2L0y.js → erDiagram-Q63AITRT-BWW0EF63.js} +1 -1
- package/web/dist/assets/eventmodeling-45OFAUF4-C8O_2_YB.js +1 -0
- package/web/dist/assets/flowDiagram-23GEKE2U-ADg31f6W.js +1 -0
- package/web/dist/assets/{ganttDiagram-NO4QXBWP-CFmDEUpW.js → ganttDiagram-NO4QXBWP-Cs24RF6t.js} +2 -2
- package/web/dist/assets/{gitGraph-TEB2WS4Q-BiEBwxQy.js → gitGraph-TEB2WS4Q-CWN94LWl.js} +1 -1
- package/web/dist/assets/{gitGraphDiagram-IHSO6WYX--62v4OfD.js → gitGraphDiagram-IHSO6WYX-B_EZLwDH.js} +1 -1
- package/web/dist/assets/index-C58B02oD.css +1 -0
- package/web/dist/assets/index-Cf-76g9P.js +420 -0
- package/web/dist/assets/{info-DKCQHKI2-BLKxCcH7.js → info-DKCQHKI2-_3TeAGLT.js} +1 -1
- package/web/dist/assets/{infoDiagram-FWYZ7A6U-DM429PMt.js → infoDiagram-FWYZ7A6U-C2mnh_tb.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-D-nr9wXb.js → ishikawaDiagram-FXEZZL3T-B_eQA-ns.js} +1 -1
- package/web/dist/assets/{journeyDiagram-5HDEW3XC-CsPvawEB.js → journeyDiagram-5HDEW3XC-pWgngszB.js} +1 -1
- package/web/dist/assets/{kanban-definition-HUTT4EX6-Cq6fbJBF.js → kanban-definition-HUTT4EX6-ov2PISLL.js} +1 -1
- package/web/dist/assets/{line-CE9BvxIa.js → line-DdBTKf-T.js} +1 -1
- package/web/dist/assets/linear-BcjVZ8a_.js +1 -0
- package/web/dist/assets/{mermaid-parser.core-CAAH_OSq.js → mermaid-parser.core-CICKlqAN.js} +3 -3
- package/web/dist/assets/{mindmap-definition-LN4V7U3C-zZ5w-lPU.js → mindmap-definition-LN4V7U3C-0NmEERgv.js} +1 -1
- package/web/dist/assets/{packet-7NZHBO7P-ap_XD9pB.js → packet-7NZHBO7P-TpNRNd61.js} +1 -1
- package/web/dist/assets/{pegDiagram-2B236MQR-BL13lL1j.js → pegDiagram-2B236MQR-CiAlAiVi.js} +1 -1
- package/web/dist/assets/{pie-RZYD4A2V-C7RWGzoe.js → pie-RZYD4A2V-x4UQuGC2.js} +1 -1
- package/web/dist/assets/{pieDiagram-ENE6RG2P-B1mmu34A.js → pieDiagram-ENE6RG2P-inbfmWLn.js} +1 -1
- package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-CotpR7ZY.js → quadrantDiagram-ABIIQ3AL-BG-L4IlR.js} +1 -1
- package/web/dist/assets/{radar-I7S5WNFK-D8ICPnt1.js → radar-I7S5WNFK-ifrr9rf8.js} +1 -1
- package/web/dist/assets/{railroad-3IZDKUUU-B7ZJ3IRr.js → railroad-3IZDKUUU-3WK9FStR.js} +1 -1
- package/web/dist/assets/railroad-abnf-AHOZXSZD-DI7lfwbp.js +1 -0
- package/web/dist/assets/railroad-ebnf-EBAXGLYW-COZaOyR2.js +1 -0
- package/web/dist/assets/railroad-peg-LSFZ7HO6-BE8vI_mk.js +1 -0
- package/web/dist/assets/{railroadDiagram-RFXS5EU6-BUbf08v3.js → railroadDiagram-RFXS5EU6-zGdHxvjI.js} +1 -1
- package/web/dist/assets/{requirementDiagram-TGXJPOKE-CgepHMpy.js → requirementDiagram-TGXJPOKE-DYBqltr1.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-HTMAVEWB-9CV0aY5J.js → sankeyDiagram-HTMAVEWB-Cwthl6yk.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-CkIJuJ5O.js → sequenceDiagram-DBY2YBRQ-yoZvzY4D.js} +1 -1
- package/web/dist/assets/src-Bp5IDfvJ.js +1 -0
- package/web/dist/assets/{stateDiagram-2N3HPSRC-wX6zU3Hv.js → stateDiagram-2N3HPSRC-UXu_N6p7.js} +1 -1
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-K2x-LOU8.js +1 -0
- package/web/dist/assets/{swimlanes-5IMT3BWC-YXgGP77C.js → swimlanes-5IMT3BWC-CJml4vNZ.js} +1 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-BJTq-tR6.js +8 -0
- package/web/dist/assets/{timeline-definition-FHXFAJF6-CtMf684d.js → timeline-definition-FHXFAJF6-DmHx8Bri.js} +1 -1
- package/web/dist/assets/{treeView-QDETBFTQ-lUySd_Pd.js → treeView-QDETBFTQ-CW1zfcRK.js} +1 -1
- package/web/dist/assets/{treemap-6X3UGDF4-BewRw9PG.js → treemap-6X3UGDF4-ReFheQXq.js} +1 -1
- package/web/dist/assets/{vennDiagram-L72KCM5P-DbFoFgBM.js → vennDiagram-L72KCM5P-jIe_jCw3.js} +1 -1
- package/web/dist/assets/{wardley-OPB4EBWU-BCrrgDHP.js → wardley-OPB4EBWU-DqwQFz9-.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-EHGQE667-C3J4of-x.js → wardleyDiagram-EHGQE667-DEJFp47s.js} +1 -1
- package/web/dist/assets/{xychartDiagram-FW5EYKEG-Fbzeb84K.js → xychartDiagram-FW5EYKEG-DBBG2OXr.js} +1 -1
- package/web/dist/index.html +12 -12
- package/web/dist/assets/architecture-TIHT7OUA-Bgyz4pDY.js +0 -1
- package/web/dist/assets/channel-vHKEEV51.js +0 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-Blusw6t4.js +0 -1
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-Blusw6t4.js +0 -1
- package/web/dist/assets/eventmodeling-45OFAUF4-CA5_fuzk.js +0 -1
- package/web/dist/assets/flowDiagram-23GEKE2U-CPO1BGjg.js +0 -1
- package/web/dist/assets/index-BUs4sN1r.css +0 -1
- package/web/dist/assets/index-HsPwY2CU.js +0 -414
- package/web/dist/assets/linear-B8yeZliB.js +0 -1
- package/web/dist/assets/railroad-abnf-AHOZXSZD-uSXjMlP2.js +0 -1
- package/web/dist/assets/railroad-ebnf-EBAXGLYW-9im8bOEZ.js +0 -1
- package/web/dist/assets/railroad-peg-LSFZ7HO6-62Yk_rP2.js +0 -1
- package/web/dist/assets/src-W4W9ly-y.js +0 -1
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-CAdDNary.js +0 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV--Ha4WrTi.js +0 -8
package/README.en.md
CHANGED
|
@@ -172,7 +172,9 @@ Generated by `init`, hand-edited afterwards — each project's coordinate system
|
|
|
172
172
|
|
|
173
173
|
`opcflow serve` serves at `http://127.0.0.1:5620`: the artifact tree (colors update live), markdown /
|
|
174
174
|
mermaid / HTML-prototype iframe / code rendering, the **review-queue diff** (approved version vs.
|
|
175
|
-
current),
|
|
175
|
+
current), the **artifact relation graph** (derived edges + manually declared edges: drag to connect,
|
|
176
|
+
manual edges unbindable, derived edges reconciled by scan; manual edges join invalidation propagation),
|
|
177
|
+
an event timeline, and live SSE refresh. Approve, reject, and thumbs-up/down prototypes right
|
|
176
178
|
here.
|
|
177
179
|
|
|
178
180
|
## Scripts
|
package/README.md
CHANGED
|
@@ -159,8 +159,9 @@ flowchart LR
|
|
|
159
159
|
## 可视化工作台
|
|
160
160
|
|
|
161
161
|
`opcflow serve` 起在 `http://127.0.0.1:5620`:artifact 树(状态实时变色)、markdown / mermaid / HTML 原型
|
|
162
|
-
iframe / 代码渲染、**待审队列 diff**(approved 版本 vs 当前)
|
|
163
|
-
|
|
162
|
+
iframe / 代码渲染、**待审队列 diff**(approved 版本 vs 当前)、**产出物关系图**(自动推导边 + 手动声明边:
|
|
163
|
+
画布上拖线即声明、手动边可解绑、推导边由 scan 对账维护;手动边同样参与失效传播)、事件时间线、
|
|
164
|
+
SSE 实时刷新。审批、打回、给原型 👍👎 都在这里点。
|
|
164
165
|
|
|
165
166
|
## 脚本
|
|
166
167
|
|
package/dist/cli.mjs
CHANGED
|
@@ -279,7 +279,14 @@ CREATE INDEX IF NOT EXISTS idx_events_event ON events(event);
|
|
|
279
279
|
}
|
|
280
280
|
},
|
|
281
281
|
// 迁移 3:claim 时记录 git HEAD,供 hotfix 契约触碰检测与 trailer 交叉验证
|
|
282
|
-
{ version: 3, up: (db) => db.exec("ALTER TABLE tasks ADD COLUMN claim_commit TEXT") }
|
|
282
|
+
{ version: 3, up: (db) => db.exec("ALTER TABLE tasks ADD COLUMN claim_commit TEXT") },
|
|
283
|
+
// 迁移 4:边来源(derived=scan 按 parents×坐标推导,对账维护;manual=用户手动声明,可解绑、scan 永不动)
|
|
284
|
+
{
|
|
285
|
+
version: 4,
|
|
286
|
+
up: (db) => db.exec(
|
|
287
|
+
"ALTER TABLE artifact_edges ADD COLUMN source TEXT NOT NULL DEFAULT 'derived' CHECK (source IN ('derived','manual'))"
|
|
288
|
+
)
|
|
289
|
+
}
|
|
283
290
|
];
|
|
284
291
|
CURRENT_SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version;
|
|
285
292
|
}
|
|
@@ -2512,30 +2519,42 @@ function deriveEdges(ctx) {
|
|
|
2512
2519
|
list.push(a);
|
|
2513
2520
|
byKind.set(a.kind, list);
|
|
2514
2521
|
}
|
|
2515
|
-
const
|
|
2522
|
+
const expected = /* @__PURE__ */ new Set();
|
|
2523
|
+
for (const child of nonMeta) {
|
|
2524
|
+
const parents = registry[child.kind]?.parents ?? [];
|
|
2525
|
+
for (const parentKind of parents) {
|
|
2526
|
+
const level = registry[parentKind]?.level ?? "module";
|
|
2527
|
+
const candidates = (byKind.get(parentKind) ?? []).filter((p) => {
|
|
2528
|
+
if ((level === "module" || level === "page") && child.module && p.module !== child.module) return false;
|
|
2529
|
+
if ((level === "endpoint" || level === "page") && child.endpoint && p.endpoint !== child.endpoint) return false;
|
|
2530
|
+
if (level === "page" && child.page && p.page !== child.page) return false;
|
|
2531
|
+
return true;
|
|
2532
|
+
});
|
|
2533
|
+
for (const parent of candidates) expected.add(`${parent.id}|${child.id}`);
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
const existing = ctx.db.prepare("SELECT id, from_id, to_id, source FROM artifact_edges").all();
|
|
2537
|
+
const have = new Set(existing.map((e) => `${e.from_id}|${e.to_id}`));
|
|
2538
|
+
const insert = ctx.db.prepare("INSERT OR IGNORE INTO artifact_edges (from_id, to_id, source) VALUES (?, ?, 'derived')");
|
|
2539
|
+
const del = ctx.db.prepare("DELETE FROM artifact_edges WHERE id = ?");
|
|
2516
2540
|
let created = 0;
|
|
2541
|
+
let pruned = 0;
|
|
2517
2542
|
const tx = ctx.db.transaction(() => {
|
|
2518
|
-
for (const
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
return true;
|
|
2527
|
-
});
|
|
2528
|
-
for (const parent of candidates) {
|
|
2529
|
-
created += insert.run(parent.id, child.id).changes;
|
|
2530
|
-
}
|
|
2531
|
-
}
|
|
2543
|
+
for (const key of expected) {
|
|
2544
|
+
if (have.has(key)) continue;
|
|
2545
|
+
const [from, to] = key.split("|");
|
|
2546
|
+
created += insert.run(Number(from), Number(to)).changes;
|
|
2547
|
+
}
|
|
2548
|
+
for (const e of existing) {
|
|
2549
|
+
if (e.source !== "derived") continue;
|
|
2550
|
+
if (!expected.has(`${e.from_id}|${e.to_id}`)) pruned += del.run(e.id).changes;
|
|
2532
2551
|
}
|
|
2533
2552
|
});
|
|
2534
2553
|
tx();
|
|
2535
|
-
return created;
|
|
2554
|
+
return { created, pruned };
|
|
2536
2555
|
}
|
|
2537
2556
|
function scanArtifacts(ctx, actor = "system") {
|
|
2538
|
-
const summary = { registered: 0, refreshed: 0, remapped: 0, edges: 0, skipped: [], unresolved: [] };
|
|
2557
|
+
const summary = { registered: 0, refreshed: 0, remapped: 0, edges: 0, edgesPruned: 0, moved: 0, skipped: [], unresolved: [] };
|
|
2539
2558
|
const files = [];
|
|
2540
2559
|
for (const dir of Object.values(ctx.config.docs)) {
|
|
2541
2560
|
const abs = join10(ctx.root, dir);
|
|
@@ -2588,6 +2607,26 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2588
2607
|
}
|
|
2589
2608
|
const hash = hashPath(join10(ctx.root, relPath));
|
|
2590
2609
|
if (hash === null) return;
|
|
2610
|
+
const movedFrom = ctx.db.prepare("SELECT * FROM artifacts WHERE content_hash = ? AND kind = ?").all(hash, kind).filter((a) => !existsSync9(join10(ctx.root, a.path)));
|
|
2611
|
+
if (movedFrom.length === 1) {
|
|
2612
|
+
const old = movedFrom[0];
|
|
2613
|
+
const tx2 = ctx.db.transaction(() => {
|
|
2614
|
+
ctx.db.prepare("UPDATE artifacts SET path = ?, module = ?, endpoint = ?, page = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(relPath, coords.module, coords.endpoint, coords.page, old.id);
|
|
2615
|
+
logEvent(ctx.db, {
|
|
2616
|
+
entityType: "artifact",
|
|
2617
|
+
entityId: old.id,
|
|
2618
|
+
event: "auto_moved",
|
|
2619
|
+
actor,
|
|
2620
|
+
payload: { from: old.path, to: relPath },
|
|
2621
|
+
module: coords.module,
|
|
2622
|
+
endpoint: coords.endpoint,
|
|
2623
|
+
page: coords.page
|
|
2624
|
+
});
|
|
2625
|
+
});
|
|
2626
|
+
tx2();
|
|
2627
|
+
summary.moved++;
|
|
2628
|
+
return;
|
|
2629
|
+
}
|
|
2591
2630
|
const tx = ctx.db.transaction(() => {
|
|
2592
2631
|
const result = insert.run(kind, coords.module, coords.endpoint, coords.page, relPath, hash);
|
|
2593
2632
|
logEvent(ctx.db, {
|
|
@@ -2615,9 +2654,35 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2615
2654
|
for (const code of expandCodeRoots(ctx)) {
|
|
2616
2655
|
registerOne(code.dir, "code", { module: code.module, endpoint: code.endpoint, page: null });
|
|
2617
2656
|
}
|
|
2618
|
-
|
|
2657
|
+
const edgeResult = deriveEdges(ctx);
|
|
2658
|
+
summary.edges = edgeResult.created;
|
|
2659
|
+
summary.edgesPruned = edgeResult.pruned;
|
|
2619
2660
|
return summary;
|
|
2620
2661
|
}
|
|
2662
|
+
function registerAdHocArtifact(ctx, relPathRaw, actor) {
|
|
2663
|
+
const relPath = normalizeRelPath(ctx, relPathRaw);
|
|
2664
|
+
const existing = ctx.db.prepare("SELECT * FROM artifacts WHERE path = ?").get(relPath);
|
|
2665
|
+
if (existing) return existing;
|
|
2666
|
+
const hash = hashPath(join10(ctx.root, relPath));
|
|
2667
|
+
if (hash === null) throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${relPath}`);
|
|
2668
|
+
const kind = inferKind(relPath, ctx.config);
|
|
2669
|
+
const coords = parseCoords(ctx, kind, relPath) ?? { module: null, endpoint: null, page: null };
|
|
2670
|
+
const tx = ctx.db.transaction(() => {
|
|
2671
|
+
const r = ctx.db.prepare("INSERT INTO artifacts (kind, module, endpoint, page, path, content_hash) VALUES (?, ?, ?, ?, ?, ?)").run(kind, coords.module, coords.endpoint, coords.page, relPath, hash);
|
|
2672
|
+
logEvent(ctx.db, {
|
|
2673
|
+
entityType: "artifact",
|
|
2674
|
+
entityId: r.lastInsertRowid,
|
|
2675
|
+
event: "scan_registered",
|
|
2676
|
+
actor,
|
|
2677
|
+
payload: { path: relPath, kind, adHoc: true },
|
|
2678
|
+
module: coords.module,
|
|
2679
|
+
endpoint: coords.endpoint,
|
|
2680
|
+
page: coords.page
|
|
2681
|
+
});
|
|
2682
|
+
});
|
|
2683
|
+
tx();
|
|
2684
|
+
return ctx.db.prepare("SELECT * FROM artifacts WHERE path = ?").get(relPath);
|
|
2685
|
+
}
|
|
2621
2686
|
var stripExt;
|
|
2622
2687
|
var init_scan_command = __esm({
|
|
2623
2688
|
"core/commands/scan.command.ts"() {
|
|
@@ -3487,6 +3552,7 @@ __export(core_exports, {
|
|
|
3487
3552
|
recordNote: () => recordNote,
|
|
3488
3553
|
recordQaResult: () => recordQaResult,
|
|
3489
3554
|
refreshArtifact: () => refreshArtifact,
|
|
3555
|
+
registerAdHocArtifact: () => registerAdHocArtifact,
|
|
3490
3556
|
registerMetaArtifacts: () => registerMetaArtifacts,
|
|
3491
3557
|
registerOutput: () => registerOutput,
|
|
3492
3558
|
rejectArtifact: () => rejectArtifact,
|
|
@@ -3825,6 +3891,117 @@ data: {"cursor":${cursor2}}
|
|
|
3825
3891
|
}, 500);
|
|
3826
3892
|
req.raw.on("close", () => clearInterval(timer));
|
|
3827
3893
|
});
|
|
3894
|
+
app.get("/api/graph", async () => {
|
|
3895
|
+
const registry = getKindRegistry(ctx.config);
|
|
3896
|
+
const rows = ctx.db.prepare("SELECT * FROM artifacts ORDER BY id").all().filter(
|
|
3897
|
+
(a) => !registry[a.kind]?.meta
|
|
3898
|
+
);
|
|
3899
|
+
const ids = new Set(rows.map((a) => a.id));
|
|
3900
|
+
const nodes = rows.map((a) => ({
|
|
3901
|
+
id: a.id,
|
|
3902
|
+
kind: a.kind,
|
|
3903
|
+
path: a.path,
|
|
3904
|
+
module: a.module,
|
|
3905
|
+
endpoint: a.endpoint,
|
|
3906
|
+
page: a.page,
|
|
3907
|
+
review_status: reviewStatus(a),
|
|
3908
|
+
missing: !existsSync14(join16(ctx.root, a.path))
|
|
3909
|
+
}));
|
|
3910
|
+
const edges = ctx.db.prepare("SELECT id, from_id, to_id, source FROM artifact_edges").all().filter((e) => ids.has(e.from_id) && ids.has(e.to_id));
|
|
3911
|
+
return { nodes, edges };
|
|
3912
|
+
});
|
|
3913
|
+
app.get("/api/search", async (req) => {
|
|
3914
|
+
const q = (req.query.q ?? "").trim().toLowerCase();
|
|
3915
|
+
if (!q) return { artifacts: [], files: [] };
|
|
3916
|
+
const like = `%${q.replace(/[%_\\]/g, (c) => "\\" + c)}%`;
|
|
3917
|
+
const artifacts = ctx.db.prepare("SELECT * FROM artifacts WHERE path LIKE ? ESCAPE '\\' ORDER BY path LIMIT 30").all(like).map((a) => ({ id: a.id, kind: a.kind, path: a.path, module: a.module, endpoint: a.endpoint, review_status: reviewStatus(a) }));
|
|
3918
|
+
const registered = new Set(ctx.db.prepare("SELECT path FROM artifacts").all().map((r) => r.path));
|
|
3919
|
+
const files = [];
|
|
3920
|
+
const walk = (dir, rel) => {
|
|
3921
|
+
if (files.length >= 30) return;
|
|
3922
|
+
for (const name of readdirSync7(dir).sort()) {
|
|
3923
|
+
if (files.length >= 30) return;
|
|
3924
|
+
if (name.startsWith(".") || name === "node_modules" || name === "dist" || name === "build") continue;
|
|
3925
|
+
const full = join16(dir, name);
|
|
3926
|
+
const relPath = rel ? `${rel}/${name}` : name;
|
|
3927
|
+
if (statSync6(full).isDirectory()) walk(full, relPath);
|
|
3928
|
+
else if (relPath.toLowerCase().includes(q) && !registered.has(relPath)) files.push(relPath);
|
|
3929
|
+
}
|
|
3930
|
+
};
|
|
3931
|
+
walk(ctx.root, "");
|
|
3932
|
+
return { artifacts, files };
|
|
3933
|
+
});
|
|
3934
|
+
app.post("/api/artifact/register", async (req) => {
|
|
3935
|
+
return registerAdHocArtifact(ctx, req.body.path, req.body.actor || "user");
|
|
3936
|
+
});
|
|
3937
|
+
app.post("/api/edge", async (req, reply) => {
|
|
3938
|
+
const { fromId, toId } = req.body;
|
|
3939
|
+
const actor = req.body.actor || "user";
|
|
3940
|
+
if (!fromId || !toId || fromId === toId) {
|
|
3941
|
+
return reply.code(400).send({ error: "\u65E0\u6548\u7684\u8FB9:\u9700\u8981\u4E24\u4E2A\u4E0D\u540C\u7684\u4EA7\u7269" });
|
|
3942
|
+
}
|
|
3943
|
+
const has = (id) => ctx.db.prepare("SELECT COUNT(*) c FROM artifacts WHERE id = ?").get(id).c > 0;
|
|
3944
|
+
if (!has(fromId) || !has(toId)) return reply.code(404).send({ error: "\u4EA7\u7269\u4E0D\u5B58\u5728" });
|
|
3945
|
+
const seen = /* @__PURE__ */ new Set([toId]);
|
|
3946
|
+
const queue = [toId];
|
|
3947
|
+
const next = ctx.db.prepare("SELECT to_id FROM artifact_edges WHERE from_id = ?");
|
|
3948
|
+
while (queue.length) {
|
|
3949
|
+
const cur = queue.pop();
|
|
3950
|
+
for (const row of next.all(cur)) {
|
|
3951
|
+
if (row.to_id === fromId) return reply.code(400).send({ error: "\u4F1A\u5F62\u6210\u73AF,\u5DF2\u62D2\u7EDD" });
|
|
3952
|
+
if (!seen.has(row.to_id)) {
|
|
3953
|
+
seen.add(row.to_id);
|
|
3954
|
+
queue.push(row.to_id);
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3958
|
+
const r = ctx.db.prepare("INSERT OR IGNORE INTO artifact_edges (from_id, to_id, source) VALUES (?, ?, 'manual')").run(fromId, toId);
|
|
3959
|
+
if (r.changes === 0) return reply.code(409).send({ error: "\u8BE5\u5173\u7CFB\u5DF2\u5B58\u5728" });
|
|
3960
|
+
logEvent(ctx.db, { entityType: "artifact", entityId: toId, event: "edge_added", actor, payload: { fromId, toId, source: "manual" } });
|
|
3961
|
+
return { id: r.lastInsertRowid, fromId, toId, source: "manual" };
|
|
3962
|
+
});
|
|
3963
|
+
app.delete("/api/artifact/:id", async (req, reply) => {
|
|
3964
|
+
const id = parseInt(req.params.id);
|
|
3965
|
+
const row = ctx.db.prepare("SELECT * FROM artifacts WHERE id = ?").get(id);
|
|
3966
|
+
if (!row) return reply.code(404).send({ error: "\u4EA7\u7269\u4E0D\u5B58\u5728" });
|
|
3967
|
+
if (row.approved_hash !== null) return reply.code(403).send({ error: "\u8BE5\u4EA7\u7269\u6709\u5BA1\u6279\u5386\u53F2,\u4E0D\u53EF\u53D6\u6D88\u767B\u8BB0" });
|
|
3968
|
+
const refs = ctx.db.prepare(
|
|
3969
|
+
`SELECT (SELECT COUNT(*) FROM task_inputs WHERE artifact_id = ?) +
|
|
3970
|
+
(SELECT COUNT(*) FROM task_outputs WHERE artifact_id = ?) +
|
|
3971
|
+
(SELECT COUNT(*) FROM artifact_feedback WHERE artifact_id = ?) AS c`
|
|
3972
|
+
).get(id, id, id);
|
|
3973
|
+
if (refs.c > 0) return reply.code(403).send({ error: "\u8BE5\u4EA7\u7269\u5DF2\u88AB\u4EFB\u52A1/\u53CD\u9988\u5F15\u7528,\u4E0D\u53EF\u53D6\u6D88\u767B\u8BB0" });
|
|
3974
|
+
const tx = ctx.db.transaction(() => {
|
|
3975
|
+
logEvent(ctx.db, {
|
|
3976
|
+
entityType: "artifact",
|
|
3977
|
+
entityId: id,
|
|
3978
|
+
event: "unregistered",
|
|
3979
|
+
actor: req.body?.actor || "user",
|
|
3980
|
+
payload: { path: row.path, kind: row.kind },
|
|
3981
|
+
module: row.module,
|
|
3982
|
+
endpoint: row.endpoint,
|
|
3983
|
+
page: row.page
|
|
3984
|
+
});
|
|
3985
|
+
ctx.db.prepare("DELETE FROM artifacts WHERE id = ?").run(id);
|
|
3986
|
+
});
|
|
3987
|
+
tx();
|
|
3988
|
+
return { ok: true };
|
|
3989
|
+
});
|
|
3990
|
+
app.delete("/api/edge/:id", async (req, reply) => {
|
|
3991
|
+
const id = parseInt(req.params.id);
|
|
3992
|
+
const edge = ctx.db.prepare("SELECT * FROM artifact_edges WHERE id = ?").get(id);
|
|
3993
|
+
if (!edge) return reply.code(404).send({ error: "\u8FB9\u4E0D\u5B58\u5728" });
|
|
3994
|
+
if (edge.source !== "manual") return reply.code(403).send({ error: "\u81EA\u52A8\u63A8\u5BFC\u7684\u5173\u7CFB\u4E0D\u53EF\u89E3\u7ED1(\u7531 scan \u6309\u5750\u6807\u4E8B\u5B9E\u7EF4\u62A4)" });
|
|
3995
|
+
ctx.db.prepare("DELETE FROM artifact_edges WHERE id = ?").run(id);
|
|
3996
|
+
logEvent(ctx.db, {
|
|
3997
|
+
entityType: "artifact",
|
|
3998
|
+
entityId: edge.to_id,
|
|
3999
|
+
event: "edge_removed",
|
|
4000
|
+
actor: req.body?.actor || "user",
|
|
4001
|
+
payload: { fromId: edge.from_id, toId: edge.to_id }
|
|
4002
|
+
});
|
|
4003
|
+
return { ok: true };
|
|
4004
|
+
});
|
|
3828
4005
|
app.get("/api/review-queue", async () => {
|
|
3829
4006
|
return listArtifacts(ctx, {}).filter((r) => r.review_status === "pending" || r.review_status === "invalidated").map((r) => ({
|
|
3830
4007
|
...r,
|
|
@@ -3894,11 +4071,13 @@ var init_app = __esm({
|
|
|
3894
4071
|
"use strict";
|
|
3895
4072
|
init_artifact_commands();
|
|
3896
4073
|
init_retro_command();
|
|
4074
|
+
init_scan_command();
|
|
3897
4075
|
init_sync_command();
|
|
3898
4076
|
init_config();
|
|
3899
4077
|
init_task_commands();
|
|
3900
4078
|
init_derive();
|
|
3901
4079
|
init_events();
|
|
4080
|
+
init_kind();
|
|
3902
4081
|
init_tree();
|
|
3903
4082
|
MAX_INLINE_SIZE = 1024 * 1024;
|
|
3904
4083
|
}
|
|
@@ -4447,7 +4626,7 @@ async function runCommand(ctx, command, a) {
|
|
|
4447
4626
|
}
|
|
4448
4627
|
case "scan": {
|
|
4449
4628
|
const s = scanArtifacts(ctx, a.actor || "system");
|
|
4450
|
-
console.log(chalk.green(`\u2705 \u626B\u63CF\u5B8C\u6210:\u65B0\u767B\u8BB0 ${s.registered},\u5185\u5BB9\u5237\u65B0 ${s.refreshed},\u91CD\u6302\u5750\u6807 ${s.remapped},\u65B0\u589E\u8FB9 ${s.edges},\u6392\u9664\u5143\u4EA7\u7269 ${s.skipped.length}`));
|
|
4629
|
+
console.log(chalk.green(`\u2705 \u626B\u63CF\u5B8C\u6210:\u65B0\u767B\u8BB0 ${s.registered},\u5185\u5BB9\u5237\u65B0 ${s.refreshed},\u91CD\u6302\u5750\u6807 ${s.remapped},\u81EA\u52A8\u8DDF\u968F\u79FB\u52A8 ${s.moved},\u65B0\u589E\u8FB9 ${s.edges},\u6E05\u7406\u6B8B\u7559\u8FB9 ${s.edgesPruned},\u6392\u9664\u5143\u4EA7\u7269 ${s.skipped.length}`));
|
|
4451
4630
|
if (s.unresolved.length > 0) {
|
|
4452
4631
|
console.log(chalk.yellow(`\u26A0 ${s.unresolved.length} \u4E2A\u6587\u4EF6\u547D\u4E2D kind \u4F46\u8DEF\u5F84\u4E0D\u7B26 coords \u6587\u6CD5,\u672A\u767B\u8BB0(\u975E\u89C4\u8303/\u5E9F\u5F03\u7AEF?):`));
|
|
4453
4632
|
for (const p of s.unresolved) console.log(chalk.yellow(` - ${p}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dawipong/opcflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Spec-anchored, drift-enforced execution layer for AI coding agents — artifact DAG, trust gates, multi-role pipeline; generates agents/MCP/hooks for Claude Code, Codex, OpenCode & Cursor.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Dawi",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@ant-design/icons": "^6",
|
|
62
|
+
"@dagrejs/dagre": "^3.0.0",
|
|
62
63
|
"@monaco-editor/react": "^4.7.0",
|
|
63
64
|
"@semantic-release/changelog": "^6.0.3",
|
|
64
65
|
"@semantic-release/git": "^10.0.1",
|
|
@@ -67,6 +68,7 @@
|
|
|
67
68
|
"@types/react": "^18",
|
|
68
69
|
"@types/react-dom": "^18",
|
|
69
70
|
"@vitejs/plugin-react": "^6",
|
|
71
|
+
"@xyflow/react": "^12.11.2",
|
|
70
72
|
"antd": "^6",
|
|
71
73
|
"esbuild": "^0.28.1",
|
|
72
74
|
"mermaid": "^11",
|
package/web/dist/assets/{abnfDiagram-VRR7QNED-DAx6EpGI.js → abnfDiagram-VRR7QNED-Cwj4KBKb.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{E as e}from"./src-Bp5IDfvJ.js";import{n as t}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import"./chunk-WYO6CB5R-C0vPAP7X.js";import"./index-Cf-76g9P.js";import{m as n,t as r}from"./mermaid-parser.core-CICKlqAN.js";import{n as i,r as a,t as o}from"./chunk-MOJQB5TN-BrFLYoih.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";var c=n().RailroadAbnf.parser.LangiumParser,l=t(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=t(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=t(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=t(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=t(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=t(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=t(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:t(t=>{o.clear(),e.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(t);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new r(n);let i=n.value;e.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),e.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,t}from"./path-BWPyau1x.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-
|
|
1
|
+
import{n as e,t}from"./path-BWPyau1x.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-DeM6hNwF.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i)if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./chunk-KEIR6QF5-BfrZ3jm6.js";import{M as e}from"./mermaid-parser.core-CICKlqAN.js";export{e as createArchitectureServices};
|