@dawipong/opcflow 0.3.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 +255 -64
- package/package.json +3 -1
- package/web/dist/assets/{abnfDiagram-VRR7QNED-B5Ymr02_.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-DkSnVejp.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-BH7du1zb.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-BJQ2jnj0.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-C6SYgnAr.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-CPVDLAL6.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-C1e5y-Qt.js → cynefinDiagram-TSTJHNR4-BQ_p-vVW.js} +1 -1
- package/web/dist/assets/{dagre-VKFMJZFB-C9vqkLKd.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-B0YXSheC.js → diagram-G47NLZAW-BFZHUq5q.js} +1 -1
- package/web/dist/assets/{diagram-NH7WQ7WH-B-0nt2Rj.js → diagram-NH7WQ7WH-CnF3KhFt.js} +1 -1
- package/web/dist/assets/{diagram-OA4YK3LP-hTbE8qZc.js → diagram-OA4YK3LP-DyxQbSTl.js} +1 -1
- package/web/dist/assets/{diagram-WEI45ONY-z9AYL1YS.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-BhlcOI7N.js → ebnfDiagram-CCIWWBDH-CRWFKre6.js} +1 -1
- package/web/dist/assets/{erDiagram-Q63AITRT-Djt4xUn4.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-DcyiJUfy.js → infoDiagram-FWYZ7A6U-C2mnh_tb.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-C_XXRphh.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-BxPpLtNJ.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-DMqPdkF8.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-D3Uh6VmT.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-Cfk6tbDs.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-DY-MNsQI.js → railroadDiagram-RFXS5EU6-zGdHxvjI.js} +1 -1
- package/web/dist/assets/{requirementDiagram-TGXJPOKE-DkBeHVjA.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-C3xWt8pk.js → sequenceDiagram-DBY2YBRQ-yoZvzY4D.js} +1 -1
- package/web/dist/assets/src-Bp5IDfvJ.js +1 -0
- package/web/dist/assets/{stateDiagram-2N3HPSRC-awwgArtJ.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-Diauu8OM.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-CzLt2q6q.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-gYZsJaVB.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-N-mJLzn_.js → wardleyDiagram-EHGQE667-DEJFp47s.js} +1 -1
- package/web/dist/assets/{xychartDiagram-FW5EYKEG-CbPlSd84.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-Bq-vpAZV.js +0 -1
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-Bq-vpAZV.js +0 -1
- package/web/dist/assets/eventmodeling-45OFAUF4-CA5_fuzk.js +0 -1
- package/web/dist/assets/flowDiagram-23GEKE2U-KXHFGTuX.js +0 -1
- package/web/dist/assets/index-BUs4sN1r.css +0 -1
- package/web/dist/assets/index-D02utICb.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-DCBMLj_H.js +0 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-CTpA1N8I.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
|
}
|
|
@@ -690,6 +697,7 @@ __export(kind_exports, {
|
|
|
690
697
|
META_KINDS: () => META_KINDS,
|
|
691
698
|
PM_KINDS: () => PM_KINDS,
|
|
692
699
|
contractKinds: () => contractKinds,
|
|
700
|
+
expandPattern: () => expandPattern,
|
|
693
701
|
getKindRegistry: () => getKindRegistry,
|
|
694
702
|
inferKind: () => inferKind,
|
|
695
703
|
kindSpec: () => kindSpec,
|
|
@@ -755,15 +763,15 @@ var init_kind = __esm({
|
|
|
755
763
|
project: { level: "project", approval: "human", parents: [], drivesStale: true, hashMode: "text-normalize", retrieval: "summary", pathPatterns: ["{prd}/project.md"] },
|
|
756
764
|
roles: { level: "project", approval: "human", parents: ["project"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{prd}/roles.md"] },
|
|
757
765
|
glossary: { level: "project", approval: "human", parents: ["project"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{prd}/glossary.md"] },
|
|
758
|
-
flow: { level: "module", approval: "human", parents: ["project", "roles", "glossary"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{prd}/flows/"] },
|
|
759
|
-
"module-prd": { level: "module", approval: "human", parents: ["flow"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{prd}/modules/"] },
|
|
760
|
-
"page-prd": { level: "page", approval: "human", parents: ["module-prd"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{prd}/pages/"] },
|
|
761
|
-
"db-doc": { level: "module", approval: "human", parents: ["module-prd"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{architecture}/database/"] },
|
|
762
|
-
"api-doc": { level: "module", approval: "human", parents: ["module-prd", "db-doc"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{architecture}/api/"] },
|
|
763
|
-
"design-system": { level: "endpoint", approval: "human", parents: ["baseline"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{design}/systems/"] },
|
|
764
|
-
"design-prompt": { level: "page", approval: "none", parents: ["page-prd", "api-doc", "design-system"], drivesStale: false, hashMode: "text-normalize", retrieval: "summary", pathPatterns: ["{design}/prompts/"] },
|
|
765
|
-
prototype: { level: "page", approval: "thumbs", parents: ["design-prompt", "design-system"], drivesStale: true, hashMode: "text-normalize", retrieval: "summary", pathPatterns: ["{design}/prototypes/"] },
|
|
766
|
-
acceptance: { level: "page", approval: "human", parents: ["page-prd", "prototype"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{acceptance}/"] },
|
|
766
|
+
flow: { level: "module", approval: "human", parents: ["project", "roles", "glossary"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{prd}/flows/"], coords: "{module}", defaultEndpoint: "common" },
|
|
767
|
+
"module-prd": { level: "module", approval: "human", parents: ["flow"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{prd}/modules/"], coords: "{module}", defaultEndpoint: "common" },
|
|
768
|
+
"page-prd": { level: "page", approval: "human", parents: ["module-prd"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{prd}/pages/"], coords: "{endpoint}/{module}/{page}" },
|
|
769
|
+
"db-doc": { level: "module", approval: "human", parents: ["module-prd"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{architecture}/database/"], coords: "{module}", defaultEndpoint: "common" },
|
|
770
|
+
"api-doc": { level: "module", approval: "human", parents: ["module-prd", "db-doc"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{architecture}/api/"], coords: "{module}", defaultEndpoint: "service" },
|
|
771
|
+
"design-system": { level: "endpoint", approval: "human", parents: ["baseline"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{design}/systems/"], coords: "{endpoint}" },
|
|
772
|
+
"design-prompt": { level: "page", approval: "none", parents: ["page-prd", "api-doc", "design-system"], drivesStale: false, hashMode: "text-normalize", retrieval: "summary", pathPatterns: ["{design}/prompts/"], coords: "{endpoint}/{module}/{page}" },
|
|
773
|
+
prototype: { level: "page", approval: "thumbs", parents: ["design-prompt", "design-system"], drivesStale: true, hashMode: "text-normalize", retrieval: "summary", pathPatterns: ["{design}/prototypes/"], coords: "{endpoint}/{module}/{page}" },
|
|
774
|
+
acceptance: { level: "page", approval: "human", parents: ["page-prd", "prototype"], drivesStale: true, hashMode: "text-normalize", retrieval: "full", pathPatterns: ["{acceptance}/"], coords: "{endpoint}/{module}/{page}" },
|
|
767
775
|
code: { level: "module", approval: "machine", parents: ["baseline", "api-doc", "prototype"], drivesStale: false, hashMode: "directory", retrieval: "semantic" },
|
|
768
776
|
doc: { level: "module", approval: "none", parents: [], drivesStale: false, hashMode: "text-normalize", retrieval: "summary" }
|
|
769
777
|
};
|
|
@@ -2412,31 +2420,37 @@ import { existsSync as existsSync9, readdirSync as readdirSync4, statSync as sta
|
|
|
2412
2420
|
import { join as join10 } from "node:path";
|
|
2413
2421
|
function parseCoords(ctx, kind, relPath) {
|
|
2414
2422
|
const none = { module: null, endpoint: null, page: null };
|
|
2415
|
-
const
|
|
2416
|
-
const
|
|
2423
|
+
const spec = getKindRegistry(ctx.config)[kind];
|
|
2424
|
+
const grammar = spec?.coords;
|
|
2425
|
+
if (!grammar) return none;
|
|
2426
|
+
const prefix = spec.pathPatterns?.[0] ? expandPattern(spec.pathPatterns[0], ctx.config) : "";
|
|
2427
|
+
const tail = relPath.startsWith(prefix) ? relPath.slice(prefix.length) : relPath;
|
|
2428
|
+
const tailSegs = tail.split("/").filter(Boolean);
|
|
2429
|
+
const gSegs = grammar.split("/");
|
|
2430
|
+
const defEnd = spec.defaultEndpoint ?? null;
|
|
2417
2431
|
const mod = (raw) => normalizeModule(raw, ctx.config);
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
}
|
|
2432
|
+
if (gSegs.length === 1) {
|
|
2433
|
+
if (tailSegs.length === 0) return null;
|
|
2434
|
+
const leaf = stripExt(tailSegs[tailSegs.length - 1]);
|
|
2435
|
+
if (gSegs[0] === "{module}") return { module: mod(leaf), endpoint: defEnd, page: null };
|
|
2436
|
+
if (gSegs[0] === "{endpoint}") return { module: null, endpoint: leaf, page: null };
|
|
2437
|
+
return none;
|
|
2438
|
+
}
|
|
2439
|
+
const hasPage = gSegs[gSegs.length - 1] === "{page}";
|
|
2440
|
+
const fixed = hasPage ? gSegs.length - 1 : gSegs.length;
|
|
2441
|
+
if (hasPage ? tailSegs.length < gSegs.length : tailSegs.length !== gSegs.length) return null;
|
|
2442
|
+
const cap = {};
|
|
2443
|
+
for (let i = 0; i < fixed; i++) cap[gSegs[i]] = stripExt(tailSegs[i]);
|
|
2444
|
+
if (cap["{endpoint}"] !== void 0 && !ctx.config.endpoints.includes(cap["{endpoint}"])) return null;
|
|
2445
|
+
const endpoint = cap["{endpoint}"] ?? defEnd;
|
|
2446
|
+
const module = cap["{module}"] !== void 0 ? mod(cap["{module}"]) : null;
|
|
2447
|
+
let page = null;
|
|
2448
|
+
if (hasPage) {
|
|
2449
|
+
const pageSegs = tailSegs.slice(fixed);
|
|
2450
|
+
const pageTail = pageSegs.map((s, i) => i === pageSegs.length - 1 ? stripExt(s) : s).join("/");
|
|
2451
|
+
page = module ? `${module}/${pageTail}` : pageTail;
|
|
2452
|
+
}
|
|
2453
|
+
return { module, endpoint, page };
|
|
2440
2454
|
}
|
|
2441
2455
|
function isMetaPath(ctx, relPath) {
|
|
2442
2456
|
const registry = getKindRegistry(ctx.config);
|
|
@@ -2505,30 +2519,42 @@ function deriveEdges(ctx) {
|
|
|
2505
2519
|
list.push(a);
|
|
2506
2520
|
byKind.set(a.kind, list);
|
|
2507
2521
|
}
|
|
2508
|
-
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 = ?");
|
|
2509
2540
|
let created = 0;
|
|
2541
|
+
let pruned = 0;
|
|
2510
2542
|
const tx = ctx.db.transaction(() => {
|
|
2511
|
-
for (const
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
return true;
|
|
2520
|
-
});
|
|
2521
|
-
for (const parent of candidates) {
|
|
2522
|
-
created += insert.run(parent.id, child.id).changes;
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
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;
|
|
2525
2551
|
}
|
|
2526
2552
|
});
|
|
2527
2553
|
tx();
|
|
2528
|
-
return created;
|
|
2554
|
+
return { created, pruned };
|
|
2529
2555
|
}
|
|
2530
2556
|
function scanArtifacts(ctx, actor = "system") {
|
|
2531
|
-
const summary = { registered: 0, refreshed: 0, remapped: 0, edges: 0, skipped: [] };
|
|
2557
|
+
const summary = { registered: 0, refreshed: 0, remapped: 0, edges: 0, edgesPruned: 0, moved: 0, skipped: [], unresolved: [] };
|
|
2532
2558
|
const files = [];
|
|
2533
2559
|
for (const dir of Object.values(ctx.config.docs)) {
|
|
2534
2560
|
const abs = join10(ctx.root, dir);
|
|
@@ -2552,7 +2578,7 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2552
2578
|
const before = row.content_hash;
|
|
2553
2579
|
const after = refreshArtifact(ctx, { id: row.id }, actor);
|
|
2554
2580
|
if (after.content_hash !== before) summary.refreshed++;
|
|
2555
|
-
if (row.kind !== kind || row.module !== coords.module || row.endpoint !== coords.endpoint || row.page !== coords.page) {
|
|
2581
|
+
if (coords && (row.kind !== kind || row.module !== coords.module || row.endpoint !== coords.endpoint || row.page !== coords.page)) {
|
|
2556
2582
|
const tx2 = ctx.db.transaction(() => {
|
|
2557
2583
|
remap.run(kind, coords.module, coords.endpoint, coords.page, row.id);
|
|
2558
2584
|
logEvent(ctx.db, {
|
|
@@ -2575,8 +2601,32 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2575
2601
|
}
|
|
2576
2602
|
return;
|
|
2577
2603
|
}
|
|
2604
|
+
if (!coords) {
|
|
2605
|
+
summary.unresolved.push(relPath);
|
|
2606
|
+
return;
|
|
2607
|
+
}
|
|
2578
2608
|
const hash = hashPath(join10(ctx.root, relPath));
|
|
2579
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
|
+
}
|
|
2580
2630
|
const tx = ctx.db.transaction(() => {
|
|
2581
2631
|
const result = insert.run(kind, coords.module, coords.endpoint, coords.page, relPath, hash);
|
|
2582
2632
|
logEvent(ctx.db, {
|
|
@@ -2604,9 +2654,36 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2604
2654
|
for (const code of expandCodeRoots(ctx)) {
|
|
2605
2655
|
registerOne(code.dir, "code", { module: code.module, endpoint: code.endpoint, page: null });
|
|
2606
2656
|
}
|
|
2607
|
-
|
|
2657
|
+
const edgeResult = deriveEdges(ctx);
|
|
2658
|
+
summary.edges = edgeResult.created;
|
|
2659
|
+
summary.edgesPruned = edgeResult.pruned;
|
|
2608
2660
|
return summary;
|
|
2609
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
|
+
}
|
|
2686
|
+
var stripExt;
|
|
2610
2687
|
var init_scan_command = __esm({
|
|
2611
2688
|
"core/commands/scan.command.ts"() {
|
|
2612
2689
|
"use strict";
|
|
@@ -2614,6 +2691,7 @@ var init_scan_command = __esm({
|
|
|
2614
2691
|
init_hash();
|
|
2615
2692
|
init_kind();
|
|
2616
2693
|
init_artifact_commands();
|
|
2694
|
+
stripExt = (s) => s.replace(/\.(md|html)$/i, "");
|
|
2617
2695
|
}
|
|
2618
2696
|
});
|
|
2619
2697
|
|
|
@@ -3435,6 +3513,7 @@ __export(core_exports, {
|
|
|
3435
3513
|
distillFeedback: () => distillFeedback,
|
|
3436
3514
|
ensureSchema: () => ensureSchema,
|
|
3437
3515
|
everApproved: () => everApproved,
|
|
3516
|
+
expandPattern: () => expandPattern,
|
|
3438
3517
|
exportEventLog: () => exportEventLog,
|
|
3439
3518
|
feedbackArtifact: () => feedbackArtifact,
|
|
3440
3519
|
findProjectRoot: () => findProjectRoot,
|
|
@@ -3473,6 +3552,7 @@ __export(core_exports, {
|
|
|
3473
3552
|
recordNote: () => recordNote,
|
|
3474
3553
|
recordQaResult: () => recordQaResult,
|
|
3475
3554
|
refreshArtifact: () => refreshArtifact,
|
|
3555
|
+
registerAdHocArtifact: () => registerAdHocArtifact,
|
|
3476
3556
|
registerMetaArtifacts: () => registerMetaArtifacts,
|
|
3477
3557
|
registerOutput: () => registerOutput,
|
|
3478
3558
|
rejectArtifact: () => rejectArtifact,
|
|
@@ -3682,7 +3762,7 @@ __export(app_exports, {
|
|
|
3682
3762
|
import fastifyCors from "@fastify/cors";
|
|
3683
3763
|
import fastifyStatic from "@fastify/static";
|
|
3684
3764
|
import Fastify from "fastify";
|
|
3685
|
-
import { existsSync as existsSync14, readFileSync as readFileSync8, readdirSync as readdirSync7, statSync as statSync6 } from "node:fs";
|
|
3765
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync8, readdirSync as readdirSync7, statSync as statSync6 } from "node:fs";
|
|
3686
3766
|
import { isAbsolute as isAbsolute2, join as join16, normalize, relative as relative2 } from "node:path";
|
|
3687
3767
|
function getArtifact(ctx, id) {
|
|
3688
3768
|
const row = ctx.db.prepare("SELECT * FROM artifacts WHERE id = ?").get(id);
|
|
@@ -3706,6 +3786,9 @@ async function createServer(ctx) {
|
|
|
3706
3786
|
if (existsSync14(webDist)) {
|
|
3707
3787
|
await app.register(fastifyStatic, { root: webDist });
|
|
3708
3788
|
}
|
|
3789
|
+
const protoRoot = join16(ctx.root, ctx.config.docs.design, "prototypes");
|
|
3790
|
+
mkdirSync8(protoRoot, { recursive: true });
|
|
3791
|
+
await app.register(fastifyStatic, { root: protoRoot, prefix: "/proto/", decorateReply: false });
|
|
3709
3792
|
app.get("/api/meta", async () => ({
|
|
3710
3793
|
root: ctx.root,
|
|
3711
3794
|
language: ctx.config.language,
|
|
@@ -3747,15 +3830,6 @@ async function createServer(ctx) {
|
|
|
3747
3830
|
}
|
|
3748
3831
|
return { artifact, content, isDirectory, missing, feedback, events };
|
|
3749
3832
|
});
|
|
3750
|
-
app.get("/api/artifact/:id/raw", async (req, reply) => {
|
|
3751
|
-
const artifact = getArtifact(ctx, parseInt(req.params.id));
|
|
3752
|
-
const abs = guardedAbsPath(ctx, artifact);
|
|
3753
|
-
if (!existsSync14(abs) || statSync6(abs).isDirectory()) {
|
|
3754
|
-
return reply.code(404).send("not found");
|
|
3755
|
-
}
|
|
3756
|
-
reply.header("content-type", artifact.path.endsWith(".html") ? "text/html; charset=utf-8" : "text/plain; charset=utf-8");
|
|
3757
|
-
return reply.send(readFileSync8(abs));
|
|
3758
|
-
});
|
|
3759
3833
|
app.get("/api/artifact/:id/files", async (req) => {
|
|
3760
3834
|
const artifact = getArtifact(ctx, parseInt(req.params.id));
|
|
3761
3835
|
const base = guardedAbsPath(ctx, artifact);
|
|
@@ -3817,6 +3891,117 @@ data: {"cursor":${cursor2}}
|
|
|
3817
3891
|
}, 500);
|
|
3818
3892
|
req.raw.on("close", () => clearInterval(timer));
|
|
3819
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
|
+
});
|
|
3820
4005
|
app.get("/api/review-queue", async () => {
|
|
3821
4006
|
return listArtifacts(ctx, {}).filter((r) => r.review_status === "pending" || r.review_status === "invalidated").map((r) => ({
|
|
3822
4007
|
...r,
|
|
@@ -3886,11 +4071,13 @@ var init_app = __esm({
|
|
|
3886
4071
|
"use strict";
|
|
3887
4072
|
init_artifact_commands();
|
|
3888
4073
|
init_retro_command();
|
|
4074
|
+
init_scan_command();
|
|
3889
4075
|
init_sync_command();
|
|
3890
4076
|
init_config();
|
|
3891
4077
|
init_task_commands();
|
|
3892
4078
|
init_derive();
|
|
3893
4079
|
init_events();
|
|
4080
|
+
init_kind();
|
|
3894
4081
|
init_tree();
|
|
3895
4082
|
MAX_INLINE_SIZE = 1024 * 1024;
|
|
3896
4083
|
}
|
|
@@ -4439,7 +4626,11 @@ async function runCommand(ctx, command, a) {
|
|
|
4439
4626
|
}
|
|
4440
4627
|
case "scan": {
|
|
4441
4628
|
const s = scanArtifacts(ctx, a.actor || "system");
|
|
4442
|
-
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}`));
|
|
4630
|
+
if (s.unresolved.length > 0) {
|
|
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?):`));
|
|
4632
|
+
for (const p of s.unresolved) console.log(chalk.yellow(` - ${p}`));
|
|
4633
|
+
}
|
|
4443
4634
|
break;
|
|
4444
4635
|
}
|
|
4445
4636
|
case "move": {
|
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-B5Ymr02_.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};
|