@dawipong/opcflow 0.2.0 → 0.3.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 +17 -81
- package/README.md +17 -80
- package/dist/cli.mjs +44 -16
- package/package.json +1 -1
- package/web/dist/assets/{abnfDiagram-VRR7QNED-DctuL32B.js → abnfDiagram-VRR7QNED-B5Ymr02_.js} +1 -1
- package/web/dist/assets/{architectureDiagram-ZJ3FMSHR--07w7V0c.js → architectureDiagram-ZJ3FMSHR-DkSnVejp.js} +1 -1
- package/web/dist/assets/{chunk-EX3LRPZG-DQGT_sG5.js → chunk-EX3LRPZG-BH7du1zb.js} +1 -1
- package/web/dist/assets/{chunk-MOJQB5TN-Y0jSjq4a.js → chunk-MOJQB5TN-BJQ2jnj0.js} +1 -1
- package/web/dist/assets/{chunk-PUDLZKDR-pSIk3CZr.js → chunk-PUDLZKDR-C6SYgnAr.js} +1 -1
- package/web/dist/assets/{chunk-V7JOEXUC-D_2vwCJz.js → chunk-V7JOEXUC-CPVDLAL6.js} +1 -1
- package/web/dist/assets/{classDiagram-OUVF2IWQ-Ckf-YAkB.js → classDiagram-OUVF2IWQ-Bq-vpAZV.js} +1 -1
- package/web/dist/assets/{classDiagram-v2-EOCWNBFH-Ckf-YAkB.js → classDiagram-v2-EOCWNBFH-Bq-vpAZV.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-TSTJHNR4-CtVxnYLa.js → cynefinDiagram-TSTJHNR4-C1e5y-Qt.js} +1 -1
- package/web/dist/assets/{dagre-VKFMJZFB-CbAaKbWe.js → dagre-VKFMJZFB-C9vqkLKd.js} +1 -1
- package/web/dist/assets/{diagram-G47NLZAW-BdfPbsL1.js → diagram-G47NLZAW-B0YXSheC.js} +1 -1
- package/web/dist/assets/{diagram-NH7WQ7WH-wWIYA2VS.js → diagram-NH7WQ7WH-B-0nt2Rj.js} +1 -1
- package/web/dist/assets/{diagram-OA4YK3LP-Chx7_D6X.js → diagram-OA4YK3LP-hTbE8qZc.js} +1 -1
- package/web/dist/assets/{diagram-WEI45ONY-DxAoHRrP.js → diagram-WEI45ONY-z9AYL1YS.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-CCIWWBDH-DcnWNqZc.js → ebnfDiagram-CCIWWBDH-BhlcOI7N.js} +1 -1
- package/web/dist/assets/{erDiagram-Q63AITRT-BX0XqX5B.js → erDiagram-Q63AITRT-Djt4xUn4.js} +1 -1
- package/web/dist/assets/{flowDiagram-23GEKE2U-DL5kTdXb.js → flowDiagram-23GEKE2U-KXHFGTuX.js} +1 -1
- package/web/dist/assets/{index-DVXPy-Pj.js → index-D02utICb.js} +5 -5
- package/web/dist/assets/{infoDiagram-FWYZ7A6U-BnrcoE4X.js → infoDiagram-FWYZ7A6U-DcyiJUfy.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-BuUSROzL.js → ishikawaDiagram-FXEZZL3T-C_XXRphh.js} +1 -1
- package/web/dist/assets/{kanban-definition-HUTT4EX6-hCokh58u.js → kanban-definition-HUTT4EX6-BxPpLtNJ.js} +1 -1
- package/web/dist/assets/{mindmap-definition-LN4V7U3C-plfH1Ve5.js → mindmap-definition-LN4V7U3C-DMqPdkF8.js} +1 -1
- package/web/dist/assets/{pegDiagram-2B236MQR-DpbGacSD.js → pegDiagram-2B236MQR-D3Uh6VmT.js} +1 -1
- package/web/dist/assets/{pieDiagram-ENE6RG2P-DsEjdRIW.js → pieDiagram-ENE6RG2P-Cfk6tbDs.js} +1 -1
- package/web/dist/assets/{railroadDiagram-RFXS5EU6-C9kLSHvN.js → railroadDiagram-RFXS5EU6-DY-MNsQI.js} +1 -1
- package/web/dist/assets/{requirementDiagram-TGXJPOKE-BslCStWL.js → requirementDiagram-TGXJPOKE-DkBeHVjA.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-Cg8Nc-TM.js → sequenceDiagram-DBY2YBRQ-C3xWt8pk.js} +1 -1
- package/web/dist/assets/{stateDiagram-2N3HPSRC-DB4TsO7Z.js → stateDiagram-2N3HPSRC-awwgArtJ.js} +1 -1
- package/web/dist/assets/{stateDiagram-v2-6OUMAXLB-SUHVLdPI.js → stateDiagram-v2-6OUMAXLB-DCBMLj_H.js} +1 -1
- package/web/dist/assets/{swimlanes-5IMT3BWC-CgeBbl6U.js → swimlanes-5IMT3BWC-Diauu8OM.js} +1 -1
- package/web/dist/assets/{swimlanesDiagram-G3AALYLV-BfFfe5gc.js → swimlanesDiagram-G3AALYLV-CTpA1N8I.js} +1 -1
- package/web/dist/assets/{timeline-definition-FHXFAJF6-BRSnucVn.js → timeline-definition-FHXFAJF6-CzLt2q6q.js} +1 -1
- package/web/dist/assets/{vennDiagram-L72KCM5P-gearbXh2.js → vennDiagram-L72KCM5P-gYZsJaVB.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-EHGQE667-DBWn9RRb.js → wardleyDiagram-EHGQE667-N-mJLzn_.js} +1 -1
- package/web/dist/assets/{xychartDiagram-FW5EYKEG-CUL1Ijyf.js → xychartDiagram-FW5EYKEG-CbPlSd84.js} +1 -1
- package/web/dist/index.html +1 -1
package/README.en.md
CHANGED
|
@@ -33,7 +33,7 @@ contracts, thumbs-up/down outputs, and answer rulings**.
|
|
|
33
33
|
- **Change propagation** — `sync` reconciles → invalidate → dispatch review along the graph (deduped)
|
|
34
34
|
- **QA loop** — fail → auto rework → auto re-verify, no human in the loop
|
|
35
35
|
- **Write-gate hooks** — block agents from editing an approved contract (observe mode by default)
|
|
36
|
-
- **Feedback evolution** — 👍👎 and QA verdicts, half-life weighted → skill
|
|
36
|
+
- **Feedback evolution** — 👍👎 and QA verdicts, half-life weighted → candidates (AI decides skill / rule / memory) / Red Flags
|
|
37
37
|
- **Multi-platform** — one definition generates each platform's agent + MCP + hooks (see [PLATFORMS.md](PLATFORMS.md))
|
|
38
38
|
- **Visual opcflow** — tree + markdown/mermaid/prototype/code rendering + review-queue diff + live SSE
|
|
39
39
|
|
|
@@ -55,7 +55,7 @@ complementary:
|
|
|
55
55
|
| Roles | Essentially single-flow (one agent implements) | Five-role pipeline, each with its own gate and output channel |
|
|
56
56
|
| Construction constraints | The spec is advisory | Gates block tasks whose upstream isn't approved; write-gate blocks edits to approved contracts; protocol lints as checkpoints |
|
|
57
57
|
| Acceptance | Not covered | Two-stage QA + fail→rework→re-verify auto loop |
|
|
58
|
-
| Evolution | Not covered | 👍👎/verdict half-life weighting →
|
|
58
|
+
| Evolution | Not covered | 👍👎/verdict half-life weighting → candidates (skill/rule/memory) / Red Flags |
|
|
59
59
|
|
|
60
60
|
In one line: **Spec Kit treats the spec as "context for the agent"; opcflow treats it as "an
|
|
61
61
|
approved contract that can go stale, propagate, and block construction," and governs the entire drift
|
|
@@ -141,94 +141,30 @@ never silently deviate.
|
|
|
141
141
|
> `docs/design/prototypes/<endpoint>/<module>/<page>.html` — once `scan` registers it, it goes through
|
|
142
142
|
> the usual 👍 release. Both paths are equivalent in the system; both must pass a user 👍.
|
|
143
143
|
|
|
144
|
-
## CLI Commands
|
|
144
|
+
## CLI Commands
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
root (otherwise it searches upward for `workbench.config.json`). File-path arguments are separated with
|
|
148
|
-
`--` (e.g. `submit --actor=x -- <path>`).
|
|
146
|
+
`opcflow <command> [args]` (after a global install; or `npx -y @dawipong/opcflow <command>` without installing). Approval actions (approve/reject) are human-only; the AI uses the MCP `wb_*` typed tools.
|
|
149
147
|
|
|
150
|
-
**
|
|
148
|
+
**Each command's purpose, when to use it, and parameters are in [COMMANDS.en.md](COMMANDS.en.md).** At a glance:
|
|
151
149
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
| `update <id>` | change status | `--status` `--operator`; `--force=true` bypasses the stale block (traced) |
|
|
159
|
-
| `remove <id>` | delete a task | `--operator`; `--force=true` |
|
|
160
|
-
| `record <id> "note"` | add a note | `--operator` |
|
|
161
|
-
| `input <id> -- <path>` | declare a dependency read outside the gate | `--operator` |
|
|
162
|
-
|
|
163
|
-
**Outputs**
|
|
164
|
-
|
|
165
|
-
| Command | Purpose | Parameters |
|
|
166
|
-
| --- | --- | --- |
|
|
167
|
-
| `output -- <path>` | register an output (auto-links your claimed task) | required `--role` `--endpoint`; opt `--module` `--page` `--task` |
|
|
168
|
-
| `artifacts` | list artifacts | `--module` `--endpoint` `--page` `--kind` |
|
|
169
|
-
| `scan` | full scan & register (docs + codeRoots), derive DAG edges | `--actor` |
|
|
170
|
-
| `move --from=<> --to=<>` | move an artifact (keeps id, keeps approval) | `--actor` |
|
|
171
|
-
|
|
172
|
-
**Trust**
|
|
173
|
-
|
|
174
|
-
| Command | Purpose | Parameters |
|
|
175
|
-
| --- | --- | --- |
|
|
176
|
-
| `submit -- <path>` | submit for review | `--actor` |
|
|
177
|
-
| `approve -- <path>` | approve | `--actor`; `--trivial=true` for tweaks: re-bless downstream + close derived reviews |
|
|
178
|
-
| `reject -- <path>` | reject | `--actor` `--reason` |
|
|
179
|
-
| `feedback -- <path>` | feedback / 👍👎 (release prototype) | `--actor` `--verdict=+1\|-1`; opt `--comment` `--task` |
|
|
180
|
-
| `dispute -- <path>` | trace an objection to approved content and stop for a ruling | `--actor` `--reason` |
|
|
181
|
-
| `queue` | review queue (pending + invalidated) | — |
|
|
182
|
-
| `sync` | reconcile: invalidation propagation + dispatch review | `--actor` |
|
|
183
|
-
|
|
184
|
-
**Flow**
|
|
185
|
-
|
|
186
|
-
| Command | Purpose | Parameters |
|
|
187
|
-
| --- | --- | --- |
|
|
188
|
-
| `plan` | dispatch downstream tasks once contracts are approved | `--module`; opt `--creator` |
|
|
189
|
-
| `qa <id>` | record acceptance result (fail auto-dispatches rework) | `--result=pass\|fail` `--operator`; fail needs `--reason` |
|
|
190
|
-
| `audit` | module contract reconciliation report (settlement status) | `--module` |
|
|
191
|
-
| `graph` | emit a Mermaid dependency graph | `--module` |
|
|
192
|
-
| `lint` | run protocol lints | opt `--role` `--endpoint` |
|
|
193
|
-
| `events` | event stream | `--taskId`/`<id>` `--module` `--event` `--limit` `--json` |
|
|
194
|
-
| `intake` | pull GitHub issues into the queue (standard lane / hotfix) | — |
|
|
195
|
-
|
|
196
|
-
**Evolution / Maintenance**
|
|
197
|
-
|
|
198
|
-
| Command | Purpose | Parameters |
|
|
199
|
-
| --- | --- | --- |
|
|
200
|
-
| `retro` | retrospective: skill candidates / Red Flags / approval throughput | opt `--module` `--json` |
|
|
201
|
-
| `export` | export events/feedback as jsonl | — |
|
|
202
|
-
| `init` | bootstrap a new project | `--endpoints` (required); `--platforms` `--model` `--writehooks=false` `--preset=false` `--hooks=false` |
|
|
203
|
-
| `gen-agents` | regenerate agent definitions from templates | — |
|
|
204
|
-
| `register-meta` | register meta artifacts (agent-def/skill/plan) | `--actor` |
|
|
205
|
-
| `install-hooks` | install git hooks | — |
|
|
206
|
-
| `migrate` | migrate a legacy DB | `--from=<path>` |
|
|
207
|
-
|
|
208
|
-
> On the AI side, prefer the MCP `wb_*` typed tools (same source & transaction as the CLI). **approve/reject are deliberately not exposed to the AI — those are your actions.**
|
|
150
|
+
- **Tasks** `list` · `show` · `create` · `claim` · `update` · `remove` · `record` · `input`
|
|
151
|
+
- **Outputs** `output` · `artifacts` · `scan` · `move`
|
|
152
|
+
- **Trust** `submit` · `approve` · `reject` · `feedback` · `dispute` · `queue` · `sync`
|
|
153
|
+
- **Flow** `plan` · `qa` · `audit` · `graph` · `lint` · `events` · `intake`
|
|
154
|
+
- **Evolution / Maintenance** `retro` · `export` · `init` · `gen-agents` · `register-meta` · `install-hooks` · `migrate`
|
|
155
|
+
- **Service & Integration** `serve` · `mcp` · `hook` · `postcommit` (mostly auto-invoked by platform / git)
|
|
209
156
|
|
|
210
157
|
## Configuration (workbench.config.json)
|
|
211
158
|
|
|
159
|
+
Generated by `init`, hand-edited afterwards — each project's coordinate system and discipline switches. **Every field's purpose, default, and when to tune it is in [CONFIG.en.md](CONFIG.en.md).**
|
|
160
|
+
|
|
212
161
|
```jsonc
|
|
213
162
|
{
|
|
214
|
-
"platforms": ["claude", "cursor"], // target platforms
|
|
163
|
+
"platforms": ["claude", "cursor"], // target platforms
|
|
215
164
|
"endpoints": ["service", "web"], // your endpoints
|
|
216
|
-
"pipeline": ["product-manager", "architect", "designer", "developer", "qa"],
|
|
217
|
-
"codeRoots": {
|
|
218
|
-
|
|
219
|
-
"web": ["web/src/pages/{module}"]
|
|
220
|
-
},
|
|
221
|
-
"moduleMapping": { "userProfile": "user" }, // merge fine modules into coarse ones
|
|
222
|
-
"machineChecks": { "enabled": false, // run on developer complete
|
|
223
|
-
"service": ["cd service && npx tsc --noEmit"] },
|
|
224
|
-
"protocolLints": [ // machine-checkable conventions → lints (violations block complete)
|
|
225
|
-
{ "name": "no-page-size", "grep": "pageSize", "paths": ["service/src"] }
|
|
226
|
-
],
|
|
227
|
-
"gates": {
|
|
228
|
-
"approvalMode": "warn", // warn = unreviewed only warns / enforce = blocks
|
|
229
|
-
"writeGate": "observe" // off / observe (log only) / enforce (block edits to approved contracts)
|
|
230
|
-
},
|
|
231
|
-
"git": { "taskTrailer": "off", "trailerKey": "Task" } // on = inject a Task:#id attribution trailer on commit
|
|
165
|
+
"pipeline": ["product-manager", "architect", "designer", "developer", "qa"],
|
|
166
|
+
"codeRoots": { "service": ["service/src/modules/{module}"] }, // [required] code dir per endpoint, {module} placeholder
|
|
167
|
+
"gates": { "approvalMode": "warn", "writeGate": "observe" } // approval / write-gate discipline levels
|
|
232
168
|
}
|
|
233
169
|
```
|
|
234
170
|
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
- **变更传播** —— `sync` 对账 → 失效 → 沿图派 review(去重)
|
|
32
32
|
- **QA 闭环** —— fail → 自动 rework → 自动复验,不消耗人
|
|
33
33
|
- **写门禁 hooks** —— agent 改到已 approved 契约时拦截(默认 observe 观察期)
|
|
34
|
-
- **反馈进化** —— 👍👎 与 QA verdict 半衰期加权 → skill
|
|
34
|
+
- **反馈进化** —— 👍👎 与 QA verdict 半衰期加权 → 经验候选(由 AI 判断沉淀为 skill / 规则 / 记忆)/ Red Flags
|
|
35
35
|
- **多平台** —— 一套定义生成四家平台各自的 agent + MCP + hooks(见 [PLATFORMS.md](PLATFORMS.md))
|
|
36
36
|
- **可视化工作台** —— 树 + markdown/mermaid/原型/代码渲染 + 待审队列 diff + SSE 实时
|
|
37
37
|
|
|
@@ -51,7 +51,7 @@ opcflow 接管 **spec 之后的执行与验证**,两者是不同层次、可互
|
|
|
51
51
|
| 角色 | 基本单流程(一个 agent 实现) | 五角色流水线,各有 gate 与产出通道 |
|
|
52
52
|
| 施工约束 | spec 是建议 | gate 拦住上游未批的任务;写门禁拦改已批契约;协议 lint 卡点 |
|
|
53
53
|
| 验收 | 不涉及 | 两段式 QA + fail→rework→复验自动闭环 |
|
|
54
|
-
| 进化 | 不涉及 | 👍👎/verdict 半衰期加权 → skill
|
|
54
|
+
| 进化 | 不涉及 | 👍👎/verdict 半衰期加权 → 经验候选(skill/规则/记忆)/ Red Flags |
|
|
55
55
|
|
|
56
56
|
一句话:**Spec Kit 把 spec 当"给 agent 的上下文";opcflow 把 spec 当"会失效、会传播、卡得住施工
|
|
57
57
|
的已批契约",并管住从契约到代码到验收的整条漂移。**
|
|
@@ -129,93 +129,30 @@ flowchart LR
|
|
|
129
129
|
> `docs/design/prototypes/<端>/<模块>/<页面>.html`,`scan` 登记后照常走 👍 放行——两条路径产出的原型
|
|
130
130
|
> 在体系里等价,都要过用户 👍。
|
|
131
131
|
|
|
132
|
-
## CLI
|
|
132
|
+
## CLI 命令
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
`workbench.config.json`)。文件路径参数用 `--` 分隔(如 `submit --actor=x -- <路径>`)。
|
|
134
|
+
`opcflow <命令> [参数]`(全局装后即用;或 `npx -y @dawipong/opcflow <命令>` 免装)。审批类动作(approve/reject)只给人,AI 侧走 MCP 的 `wb_*` typed tools。
|
|
136
135
|
|
|
137
|
-
|
|
136
|
+
**每条命令的作用、使用场景与参数见 [COMMANDS.md](COMMANDS.md)。** 速览:
|
|
138
137
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
| `update <id>` | 改状态 | `--status` `--operator`;`--force=true` 越过 stale 拦截(留痕) |
|
|
146
|
-
| `remove <id>` | 删任务 | `--operator`;`--force=true` |
|
|
147
|
-
| `record <id> "备注"` | 加备注 | `--operator` |
|
|
148
|
-
| `input <id> -- <路径>` | 补充申报 gate 之外读过的依赖 | `--operator` |
|
|
149
|
-
|
|
150
|
-
**产出**
|
|
151
|
-
|
|
152
|
-
| 命令 | 作用 | 参数 |
|
|
153
|
-
| --- | --- | --- |
|
|
154
|
-
| `output -- <路径>` | 登记产物(自动关联你领取的任务) | 必填 `--role` `--endpoint`;选 `--module` `--page` `--task` |
|
|
155
|
-
| `artifacts` | 列产物 | `--module` `--endpoint` `--page` `--kind` |
|
|
156
|
-
| `scan` | 全量扫描登记(docs + codeRoots),推导 DAG 边 | `--actor` |
|
|
157
|
-
| `move --from=<> --to=<>` | 移动产物(保 id、不断审批) | `--actor` |
|
|
158
|
-
|
|
159
|
-
**信任**
|
|
160
|
-
|
|
161
|
-
| 命令 | 作用 | 参数 |
|
|
162
|
-
| --- | --- | --- |
|
|
163
|
-
| `submit -- <路径>` | 送审 | `--actor` |
|
|
164
|
-
| `approve -- <路径>` | 批准 | `--actor`;`--trivial=true` 微调:re-bless 下游 + 关派生 review |
|
|
165
|
-
| `reject -- <路径>` | 打回 | `--actor` `--reason` |
|
|
166
|
-
| `feedback -- <路径>` | 反馈 / 👍👎(原型放行) | `--actor` `--verdict=+1\|-1`;选 `--comment` `--task` |
|
|
167
|
-
| `dispute -- <路径>` | 对 approved 内容留痕异议,停下等裁决 | `--actor` `--reason` |
|
|
168
|
-
| `queue` | 待审队列(pending + invalidated) | — |
|
|
169
|
-
| `sync` | 对账:失效传播 + 沿图派 review | `--actor` |
|
|
170
|
-
|
|
171
|
-
**流程**
|
|
172
|
-
|
|
173
|
-
| 命令 | 作用 | 参数 |
|
|
174
|
-
| --- | --- | --- |
|
|
175
|
-
| `plan` | 契约全批后一键派发下游任务 | `--module`;选 `--creator` |
|
|
176
|
-
| `qa <id>` | 记验收结果(fail 自动派 rework) | `--result=pass\|fail` `--operator`;fail 需 `--reason` |
|
|
177
|
-
| `audit` | 模块契约对账报告(清算状态) | `--module` |
|
|
178
|
-
| `graph` | 输出 Mermaid 依赖图 | `--module` |
|
|
179
|
-
| `lint` | 跑协议 lint | 选 `--role` `--endpoint` |
|
|
180
|
-
| `events` | 事件流 | `--taskId`/`<id>` `--module` `--event` `--limit` `--json` |
|
|
181
|
-
| `intake` | 拉 GitHub issue 入队(标准道 / hotfix) | — |
|
|
182
|
-
|
|
183
|
-
**进化 / 维护**
|
|
184
|
-
|
|
185
|
-
| 命令 | 作用 | 参数 |
|
|
186
|
-
| --- | --- | --- |
|
|
187
|
-
| `retro` | 复盘:skill 候选 / Red Flag / 审批吞吐 | 选 `--module` `--json` |
|
|
188
|
-
| `export` | 导出 events/feedback 为 jsonl | — |
|
|
189
|
-
| `init` | 新项目引导 | `--endpoints`(必填);`--platforms` `--model` `--writehooks=false` `--preset=false` `--hooks=false` |
|
|
190
|
-
| `gen-agents` | 从模板重生成 agent 定义 | — |
|
|
191
|
-
| `register-meta` | 注册元产物(agent-def/skill/plan) | `--actor` |
|
|
192
|
-
| `install-hooks` | 安装 git hooks | — |
|
|
193
|
-
| `migrate` | 迁移旧库 | `--from=<路径>` |
|
|
194
|
-
|
|
195
|
-
> AI 侧优先用 MCP 的 `wb_*` typed tools(与 CLI 同源同事务);**审批 approve/reject 刻意不暴露给 AI——那是你的动作**。
|
|
138
|
+
- **任务** `list` · `show` · `create` · `claim` · `update` · `remove` · `record` · `input`
|
|
139
|
+
- **产出** `output` · `artifacts` · `scan` · `move`
|
|
140
|
+
- **信任** `submit` · `approve` · `reject` · `feedback` · `dispute` · `queue` · `sync`
|
|
141
|
+
- **流程** `plan` · `qa` · `audit` · `graph` · `lint` · `events` · `intake`
|
|
142
|
+
- **进化 / 维护** `retro` · `export` · `init` · `gen-agents` · `register-meta` · `install-hooks` · `migrate`
|
|
143
|
+
- **服务与集成** `serve` · `mcp` · `hook` · `postcommit`(多由平台 / git 自动调用)
|
|
196
144
|
|
|
197
145
|
## 配置(workbench.config.json)
|
|
198
146
|
|
|
147
|
+
`init` 生成、之后手工编辑,是每个项目的坐标系与纪律开关。**每个字段的作用、默认值与何时调,见 [CONFIG.md](CONFIG.md)。**
|
|
148
|
+
|
|
199
149
|
```jsonc
|
|
200
150
|
{
|
|
201
|
-
"platforms": ["claude", "cursor"], // 目标平台
|
|
151
|
+
"platforms": ["claude", "cursor"], // 目标平台
|
|
202
152
|
"endpoints": ["service", "web"], // 你的端
|
|
203
|
-
"pipeline": ["product-manager", "architect", "designer", "developer", "qa"],
|
|
204
|
-
"codeRoots": {
|
|
205
|
-
|
|
206
|
-
"web": ["web/src/pages/{module}"]
|
|
207
|
-
},
|
|
208
|
-
"moduleMapping": { "userProfile": "user" }, // 细模块归并到粗模块
|
|
209
|
-
"machineChecks": { "enabled": false, // developer complete 时跑
|
|
210
|
-
"service": ["cd service && npx tsc --noEmit"] },
|
|
211
|
-
"protocolLints": [ // 能机器查的约定 → 降级为 lint(违例阻断 complete)
|
|
212
|
-
{ "name": "no-page-size", "grep": "pageSize", "paths": ["service/src"] }
|
|
213
|
-
],
|
|
214
|
-
"gates": {
|
|
215
|
-
"approvalMode": "warn", // warn=未批只警告 / enforce=阻断
|
|
216
|
-
"writeGate": "observe" // off / observe(只记录)/ enforce(拦改 approved 契约)
|
|
217
|
-
},
|
|
218
|
-
"git": { "taskTrailer": "off", "trailerKey": "Task" } // on=提交注入 Task:#id 归因 trailer
|
|
153
|
+
"pipeline": ["product-manager", "architect", "designer", "developer", "qa"],
|
|
154
|
+
"codeRoots": { "service": ["service/src/modules/{module}"] }, // 【必填】每端代码目录,{module} 占位
|
|
155
|
+
"gates": { "approvalMode": "warn", "writeGate": "observe" } // 审批 / 写门禁纪律档位
|
|
219
156
|
}
|
|
220
157
|
```
|
|
221
158
|
|
package/dist/cli.mjs
CHANGED
|
@@ -2528,7 +2528,7 @@ function deriveEdges(ctx) {
|
|
|
2528
2528
|
return created;
|
|
2529
2529
|
}
|
|
2530
2530
|
function scanArtifacts(ctx, actor = "system") {
|
|
2531
|
-
const summary = { registered: 0, refreshed: 0, edges: 0, skipped: [] };
|
|
2531
|
+
const summary = { registered: 0, refreshed: 0, remapped: 0, edges: 0, skipped: [] };
|
|
2532
2532
|
const files = [];
|
|
2533
2533
|
for (const dir of Object.values(ctx.config.docs)) {
|
|
2534
2534
|
const abs = join10(ctx.root, dir);
|
|
@@ -2537,7 +2537,12 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2537
2537
|
for (const p of ["ARCHITECTURE.md", "TECH.md"]) {
|
|
2538
2538
|
if (existsSync9(join10(ctx.root, p))) files.push(p);
|
|
2539
2539
|
}
|
|
2540
|
-
const exists = ctx.db.prepare(
|
|
2540
|
+
const exists = ctx.db.prepare(
|
|
2541
|
+
"SELECT id, kind, module, endpoint, page, content_hash FROM artifacts WHERE path = ?"
|
|
2542
|
+
);
|
|
2543
|
+
const remap = ctx.db.prepare(
|
|
2544
|
+
"UPDATE artifacts SET kind = ?, module = ?, endpoint = ?, page = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?"
|
|
2545
|
+
);
|
|
2541
2546
|
const insert = ctx.db.prepare(
|
|
2542
2547
|
"INSERT INTO artifacts (kind, module, endpoint, page, path, content_hash) VALUES (?, ?, ?, ?, ?, ?)"
|
|
2543
2548
|
);
|
|
@@ -2547,6 +2552,27 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2547
2552
|
const before = row.content_hash;
|
|
2548
2553
|
const after = refreshArtifact(ctx, { id: row.id }, actor);
|
|
2549
2554
|
if (after.content_hash !== before) summary.refreshed++;
|
|
2555
|
+
if (row.kind !== kind || row.module !== coords.module || row.endpoint !== coords.endpoint || row.page !== coords.page) {
|
|
2556
|
+
const tx2 = ctx.db.transaction(() => {
|
|
2557
|
+
remap.run(kind, coords.module, coords.endpoint, coords.page, row.id);
|
|
2558
|
+
logEvent(ctx.db, {
|
|
2559
|
+
entityType: "artifact",
|
|
2560
|
+
entityId: row.id,
|
|
2561
|
+
event: "coords_remapped",
|
|
2562
|
+
actor,
|
|
2563
|
+
payload: {
|
|
2564
|
+
path: relPath,
|
|
2565
|
+
from: { kind: row.kind, module: row.module, endpoint: row.endpoint, page: row.page },
|
|
2566
|
+
to: { kind, module: coords.module, endpoint: coords.endpoint, page: coords.page }
|
|
2567
|
+
},
|
|
2568
|
+
module: coords.module,
|
|
2569
|
+
endpoint: coords.endpoint,
|
|
2570
|
+
page: coords.page
|
|
2571
|
+
});
|
|
2572
|
+
});
|
|
2573
|
+
tx2();
|
|
2574
|
+
summary.remapped++;
|
|
2575
|
+
}
|
|
2550
2576
|
return;
|
|
2551
2577
|
}
|
|
2552
2578
|
const hash = hashPath(join10(ctx.root, relPath));
|
|
@@ -2655,8 +2681,8 @@ var init_qa_command = __esm({
|
|
|
2655
2681
|
var retro_command_exports = {};
|
|
2656
2682
|
__export(retro_command_exports, {
|
|
2657
2683
|
AUTO_ACTOR_WEIGHT: () => AUTO_ACTOR_WEIGHT,
|
|
2684
|
+
CANDIDATE_THRESHOLD: () => CANDIDATE_THRESHOLD,
|
|
2658
2685
|
RED_FLAG_THRESHOLD: () => RED_FLAG_THRESHOLD,
|
|
2659
|
-
SKILL_CANDIDATE_THRESHOLD: () => SKILL_CANDIDATE_THRESHOLD,
|
|
2660
2686
|
approvalStats: () => approvalStats,
|
|
2661
2687
|
distillFeedback: () => distillFeedback,
|
|
2662
2688
|
exportEventLog: () => exportEventLog,
|
|
@@ -2670,6 +2696,8 @@ function parseDbTime(s) {
|
|
|
2670
2696
|
function distillFeedback(ctx, opts = {}) {
|
|
2671
2697
|
const now = (opts.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
2672
2698
|
const halfLifeMs = ctx.config.feedbackHalfLifeDays * 24 * 60 * 60 * 1e3;
|
|
2699
|
+
const candidateThreshold = ctx.config.candidateThreshold ?? CANDIDATE_THRESHOLD;
|
|
2700
|
+
const redFlagThreshold = ctx.config.redFlagThreshold ?? RED_FLAG_THRESHOLD;
|
|
2673
2701
|
let query = `
|
|
2674
2702
|
SELECT f.artifact_id, f.verdict, f.comment, f.actor, f.created_at,
|
|
2675
2703
|
a.kind, a.module, a.endpoint, a.path
|
|
@@ -2710,13 +2738,13 @@ function distillFeedback(ctx, opts = {}) {
|
|
|
2710
2738
|
for (const g of result) {
|
|
2711
2739
|
g.posScore = Math.round(g.posScore * 100) / 100;
|
|
2712
2740
|
g.negScore = Math.round(g.negScore * 100) / 100;
|
|
2713
|
-
const pos = g.posScore >=
|
|
2714
|
-
const neg = g.negScore >=
|
|
2741
|
+
const pos = g.posScore >= candidateThreshold;
|
|
2742
|
+
const neg = g.negScore >= redFlagThreshold;
|
|
2715
2743
|
if (pos && neg) {
|
|
2716
2744
|
g.bucket = "observation";
|
|
2717
2745
|
g.reason = "mixed";
|
|
2718
2746
|
} else if (pos) {
|
|
2719
|
-
g.bucket = "
|
|
2747
|
+
g.bucket = "candidate";
|
|
2720
2748
|
} else if (neg) {
|
|
2721
2749
|
g.bucket = "red-flag";
|
|
2722
2750
|
} else {
|
|
@@ -2724,7 +2752,7 @@ function distillFeedback(ctx, opts = {}) {
|
|
|
2724
2752
|
g.reason = "insufficient";
|
|
2725
2753
|
}
|
|
2726
2754
|
}
|
|
2727
|
-
const order = {
|
|
2755
|
+
const order = { candidate: 0, "red-flag": 1, observation: 2 };
|
|
2728
2756
|
return result.sort((a, b) => order[a.bucket] - order[b.bucket] || `${a.endpoint}/${a.kind}`.localeCompare(`${b.endpoint}/${b.kind}`));
|
|
2729
2757
|
}
|
|
2730
2758
|
function approvalStats(ctx) {
|
|
@@ -2779,18 +2807,18 @@ function approvalStats(ctx) {
|
|
|
2779
2807
|
}
|
|
2780
2808
|
function runRetrospective(ctx, opts = {}) {
|
|
2781
2809
|
const groups = distillFeedback(ctx, opts);
|
|
2782
|
-
const candidates = groups.filter((g) => g.bucket === "
|
|
2810
|
+
const candidates = groups.filter((g) => g.bucket === "candidate").length;
|
|
2783
2811
|
const redFlags = groups.filter((g) => g.bucket === "red-flag").length;
|
|
2784
2812
|
const cli = ctx.config.cli;
|
|
2785
2813
|
const guidance = [];
|
|
2786
2814
|
if (candidates > 0) {
|
|
2787
2815
|
guidance.push(
|
|
2788
|
-
`\u53D1\u73B0 ${candidates} \u4E2A
|
|
2816
|
+
`\u53D1\u73B0 ${candidates} \u4E2A\u7ECF\u9A8C\u5019\u9009\u7EC4:\u5BF9\u6BCF\u7EC4\u4F9D\u636E evidence(\u8DEF\u5F84+comment)\u5224\u65AD\u8BE5\u6C89\u6DC0\u4E3A\u54EA\u4E00\u79CD,\u518D\u6309\u5BF9\u5E94\u8DEF\u5F84\u4EA7\u51FA\u2014\u2014\u8DE8\u4F1A\u8BDD\u53EF\u590D\u7528\u7684\u505A\u6CD5/\u6D41\u7A0B \u2192 skill(.claude/skills/<\u540D\u79F0>/SKILL.md;\`${cli} register-meta\` \u6CE8\u518C + \`${cli} submit --actor=<\u89D2\u8272> -- <\u8DEF\u5F84>\` \u9001\u4EBA\u5BA1,approved \u624D\u751F\u6548);\u5FC5\u987B\u59CB\u7EC8\u6210\u7ACB\u3001\u53EF grep \u7684\u786C\u7EA6\u675F \u2192 \u89C4\u5219(workbench.config.json \u7684 protocolLints \u5361\u70B9,\u6216\u5199\u5165 TECH.md / \u57FA\u7EBF\u7EA6\u5B9A);\u53EA\u5BF9\u7279\u5B9A\u89D2\u8272/\u9879\u76EE\u6709\u7528\u3001\u4E0D\u503C\u5F97\u5355\u72EC\u6210\u7BC7\u7684\u6559\u8BAD\u6216\u504F\u597D \u2192 \u8BB0\u5FC6(.claude/agent-memory/<\u89D2\u8272>/,\u66F4\u65B0 MEMORY.md \u7D22\u5F15)`
|
|
2789
2817
|
);
|
|
2790
2818
|
}
|
|
2791
2819
|
if (redFlags > 0) {
|
|
2792
2820
|
guidance.push(
|
|
2793
|
-
`\u53D1\u73B0 ${redFlags} \u4E2A Red Flags \u7EC4:\u8D1F\u4F8B comment \u5373\u7D20\u6750,\u5199\
|
|
2821
|
+
`\u53D1\u73B0 ${redFlags} \u4E2A Red Flags \u7EC4:\u8D1F\u4F8B comment \u5373\u300C\u522B\u518D\u72AF\u300D\u7684\u7D20\u6750,\u540C\u6837\u4E09\u9009\u4E00\u2014\u2014\u80FD\u673A\u5668\u67E5 \u2192 protocolLints \u5361\u70B9;\u8DE8\u4F1A\u8BDD\u901A\u7528\u5751 \u2192 \u5199\u8FDB\u5BF9\u5E94 skill \u7684 Red Flags \u7AE0\u8282;\u89D2\u8272\u4E13\u5C5E\u5751 \u2192 \u8BB0\u5FC6`
|
|
2794
2822
|
);
|
|
2795
2823
|
}
|
|
2796
2824
|
if (guidance.length === 0) {
|
|
@@ -2821,11 +2849,11 @@ function exportEventLog(ctx) {
|
|
|
2821
2849
|
files: [`${ctx.config.dataDir}/events.jsonl`, `${ctx.config.dataDir}/feedback.jsonl`]
|
|
2822
2850
|
};
|
|
2823
2851
|
}
|
|
2824
|
-
var
|
|
2852
|
+
var CANDIDATE_THRESHOLD, RED_FLAG_THRESHOLD, AUTO_ACTOR_WEIGHT;
|
|
2825
2853
|
var init_retro_command = __esm({
|
|
2826
2854
|
"core/commands/retro.command.ts"() {
|
|
2827
2855
|
"use strict";
|
|
2828
|
-
|
|
2856
|
+
CANDIDATE_THRESHOLD = 3;
|
|
2829
2857
|
RED_FLAG_THRESHOLD = 2;
|
|
2830
2858
|
AUTO_ACTOR_WEIGHT = 0.5;
|
|
2831
2859
|
}
|
|
@@ -3377,6 +3405,7 @@ var init_init_command = __esm({
|
|
|
3377
3405
|
var core_exports = {};
|
|
3378
3406
|
__export(core_exports, {
|
|
3379
3407
|
AUTO_ACTOR_WEIGHT: () => AUTO_ACTOR_WEIGHT,
|
|
3408
|
+
CANDIDATE_THRESHOLD: () => CANDIDATE_THRESHOLD,
|
|
3380
3409
|
CONFIG_FILENAME: () => CONFIG_FILENAME,
|
|
3381
3410
|
CURRENT_SCHEMA_VERSION: () => CURRENT_SCHEMA_VERSION,
|
|
3382
3411
|
DEFAULT_KIND_REGISTRY: () => DEFAULT_KIND_REGISTRY,
|
|
@@ -3388,7 +3417,6 @@ __export(core_exports, {
|
|
|
3388
3417
|
PM_KINDS: () => PM_KINDS,
|
|
3389
3418
|
RED_FLAG_THRESHOLD: () => RED_FLAG_THRESHOLD,
|
|
3390
3419
|
SCHEMA_V1: () => SCHEMA_V1,
|
|
3391
|
-
SKILL_CANDIDATE_THRESHOLD: () => SKILL_CANDIDATE_THRESHOLD,
|
|
3392
3420
|
WORKBENCH_BIN: () => WORKBENCH_BIN,
|
|
3393
3421
|
WORKBENCH_DIR: () => WORKBENCH_DIR,
|
|
3394
3422
|
addTaskInput: () => addTaskInput,
|
|
@@ -3615,7 +3643,7 @@ function buildMcpServer(ctx) {
|
|
|
3615
3643
|
server.registerTool(
|
|
3616
3644
|
"wb_retro",
|
|
3617
3645
|
{
|
|
3618
|
-
description: "retrospective \u8BC1\u636E\u5305:\u53CD\u9988\u534A\u8870\u671F\u52A0\u6743\u63D0\u70BC(
|
|
3646
|
+
description: "retrospective \u8BC1\u636E\u5305:\u53CD\u9988\u534A\u8870\u671F\u52A0\u6743\u63D0\u70BC(\u7ECF\u9A8C\u5019\u9009/Red Flags/\u89C2\u5BDF)+ \u5BA1\u6279\u541E\u5410\u62A5\u8868\u3002\u4F9D\u636E evidence \u5224\u65AD\u6BCF\u7EC4\u8BE5\u6C89\u6DC0\u4E3A\u54EA\u4E00\u79CD\u518D\u4EA7\u51FA:\u53EF\u590D\u7528\u505A\u6CD5\u2192skill(.claude/skills/<\u540D\u79F0>/SKILL.md,register-meta+submit \u9001\u4EBA\u5BA1,approved \u624D\u751F\u6548);\u80FD\u673A\u5668\u67E5\u7684\u786C\u7EA6\u675F\u2192\u89C4\u5219(workbench.config.json \u7684 protocolLints);\u89D2\u8272\u4E13\u5C5E\u6559\u8BAD\u2192\u8BB0\u5FC6(.claude/agent-memory/<\u89D2\u8272>/)\u3002\u89C1 report.guidance",
|
|
3619
3647
|
inputSchema: { module: z.string().optional() }
|
|
3620
3648
|
},
|
|
3621
3649
|
async (args) => json(runRetrospective(ctx, args))
|
|
@@ -3799,7 +3827,7 @@ data: {"cursor":${cursor2}}
|
|
|
3799
3827
|
app.get("/api/skill-candidates", async () => {
|
|
3800
3828
|
const report = runRetrospective(ctx);
|
|
3801
3829
|
return {
|
|
3802
|
-
groups: report.groups.filter((g) => g.bucket === "
|
|
3830
|
+
groups: report.groups.filter((g) => g.bucket === "candidate" || g.bucket === "red-flag"),
|
|
3803
3831
|
candidates: report.candidates,
|
|
3804
3832
|
redFlags: report.redFlags,
|
|
3805
3833
|
halfLifeDays: report.halfLifeDays,
|
|
@@ -4411,7 +4439,7 @@ async function runCommand(ctx, command, a) {
|
|
|
4411
4439
|
}
|
|
4412
4440
|
case "scan": {
|
|
4413
4441
|
const s = scanArtifacts(ctx, a.actor || "system");
|
|
4414
|
-
console.log(chalk.green(`\u2705 \u626B\u63CF\u5B8C\u6210:\u65B0\u767B\u8BB0 ${s.registered},\u5185\u5BB9\u5237\u65B0 ${s.refreshed},\u65B0\u589E\u8FB9 ${s.edges},\u6392\u9664\u5143\u4EA7\u7269 ${s.skipped.length}`));
|
|
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}`));
|
|
4415
4443
|
break;
|
|
4416
4444
|
}
|
|
4417
4445
|
case "move": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dawipong/opcflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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",
|
package/web/dist/assets/{abnfDiagram-VRR7QNED-DctuL32B.js → abnfDiagram-VRR7QNED-B5Ymr02_.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e}from"./src-W4W9ly-y.js";import{n as t}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import"./chunk-WYO6CB5R-BaRUDpDl.js";import"./index-
|
|
1
|
+
import{m as e}from"./src-W4W9ly-y.js";import{n as t}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import"./chunk-WYO6CB5R-BaRUDpDl.js";import"./index-D02utICb.js";import{m as n,t as r}from"./mermaid-parser.core-CAAH_OSq.js";import{n as i,r as a,t as o}from"./chunk-MOJQB5TN-BJQ2jnj0.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};
|