@devcxl/opencode-cabbage 1.3.0 → 2.0.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/.codex-plugin/plugin.json +1 -1
- package/README.md +35 -23
- package/README.zh.md +22 -15
- package/assets/agents/dev-lifecycle.md +6 -0
- package/assets/prompts/bootstrap.md +4 -0
- package/assets/skills/flow-change/SKILL.md +109 -0
- package/assets/skills/flow-design/SKILL.md +15 -0
- package/assets/skills/flow-docs/SKILL.md +112 -0
- package/assets/skills/flow-incident/SKILL.md +98 -0
- package/assets/skills/flow-research/SKILL.md +9 -0
- package/assets/skills/flow-setup/SKILL.md +13 -0
- package/codex-skills/agent-dev-lifecycle/SKILL.md +2 -0
- package/codex-skills/flow-change/SKILL.md +109 -0
- package/codex-skills/flow-design/SKILL.md +18 -3
- package/codex-skills/flow-docs/SKILL.md +112 -0
- package/codex-skills/flow-incident/SKILL.md +98 -0
- package/codex-skills/flow-research/SKILL.md +12 -3
- package/codex-skills/flow-setup/SKILL.md +13 -0
- package/dist/index.d.ts +2 -5
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/plugin/agents.d.ts +20 -0
- package/dist/plugin/agents.js +79 -0
- package/dist/plugin/agents.js.map +1 -1
- package/dist/plugin/cabbage-cli.d.ts +28 -0
- package/dist/plugin/cabbage-cli.js +92 -0
- package/dist/plugin/cabbage-cli.js.map +1 -0
- package/dist/plugin/cabbage-tool.d.ts +103 -0
- package/dist/plugin/cabbage-tool.js +169 -0
- package/dist/plugin/cabbage-tool.js.map +1 -0
- package/dist/plugin/commands.d.ts +10 -0
- package/dist/plugin/commands.js +1 -1
- package/dist/plugin/commands.js.map +1 -1
- package/dist/plugin/continuation.d.ts +22 -0
- package/dist/plugin/continuation.js +233 -0
- package/dist/plugin/continuation.js.map +1 -0
- package/dist/plugin/goal-store.d.ts +42 -49
- package/dist/plugin/goal-store.js +35 -32
- package/dist/plugin/goal-store.js.map +1 -1
- package/dist/plugin/goal.d.ts +92 -28
- package/dist/plugin/goal.js +201 -158
- package/dist/plugin/goal.js.map +1 -1
- package/dist/plugin/install-dir.d.ts +13 -0
- package/dist/plugin/install-dir.js +46 -0
- package/dist/plugin/install-dir.js.map +1 -0
- package/dist/plugin/server.d.ts +4 -13
- package/dist/plugin/server.js +278 -423
- package/dist/plugin/server.js.map +1 -1
- package/dist/plugin/session-abort.d.ts +5 -0
- package/dist/plugin/session-abort.js +26 -0
- package/dist/plugin/session-abort.js.map +1 -0
- package/dist/plugin/skills.d.ts +15 -0
- package/dist/plugin/skills.js +47 -50
- package/dist/plugin/skills.js.map +1 -1
- package/dist/plugin.d.ts +2 -2
- package/dist/plugin.js +6 -2
- package/dist/plugin.js.map +1 -1
- package/dist/util/paths.d.ts +0 -6
- package/dist/util/paths.js +0 -15
- package/dist/util/paths.js.map +1 -1
- package/package.json +4 -7
- package/vendor/cabbage/MANIFEST.json +8 -0
- package/vendor/cabbage/cabbage_cli/__init__.py +1 -0
- package/vendor/cabbage/cabbage_cli/__main__.py +2 -0
- package/vendor/cabbage/cabbage_cli/assets/docs-site/.vitepress/config.ts +78 -0
- package/vendor/cabbage/cabbage_cli/assets/docs-site/README.md +31 -0
- package/vendor/cabbage/cabbage_cli/assets/docs-site/package.json +16 -0
- package/vendor/cabbage/cabbage_cli/assets/docs-site/pnpm-lock.yaml +2504 -0
- package/vendor/cabbage/cabbage_cli/assets/integrations/cabbage.yml +127 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/adr.md +47 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/api-design.md +45 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/change-record.md +21 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/database-design.md +37 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/generic.md +20 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/impact.md +41 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/incident.md +48 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/postmortem.md +43 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/prd.md +71 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/release-plan.md +45 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/rfc.md +44 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/security-review.md +35 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/tasks.md +62 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/tech-spec.md +87 -0
- package/vendor/cabbage/cabbage_cli/assets/templates/test-plan.md +44 -0
- package/vendor/cabbage/cabbage_cli/assets/workflows/change.yaml +11 -0
- package/vendor/cabbage/cabbage_cli/assets/workflows/incident.yaml +4 -0
- package/vendor/cabbage/cabbage_cli/cli.py +283 -0
- package/vendor/cabbage/cabbage_cli/core.py +606 -0
- package/vendor/cabbage/cabbage_cli/scaffold.py +313 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flow-change
|
|
3
|
+
description: Maintain a Cabbage change record (tasks + documents) through the built-in `cabbage` tool — create the record, declare risk flags, verify stages, pass gates, sync to docs, archive after merge. Use for bug fixes, refactors, small features, hotfixes, or whenever a tracked record with tasks.md and verification evidence is required in this repository.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# flow-change
|
|
7
|
+
|
|
8
|
+
本仓库的变更记录机制由插件内置的 Cabbage 引擎提供(`cabbage` 工具,无需手工安装)。
|
|
9
|
+
一份记录 = 一个目录(`.cabbage/changes/<id>/`):默认只有一份 `tasks.md`,
|
|
10
|
+
高风险时用影响标记展开专项文档;验证通过、合并确认后归档并同步到 `docs/`。
|
|
11
|
+
|
|
12
|
+
## 何时启用
|
|
13
|
+
|
|
14
|
+
- 任何需要留痕的代码改动:bug 修复、重构、小功能、紧急修复、业务调整。
|
|
15
|
+
- 大流程(requirements/design/code/...)中的具体代码改动:在对应阶段用记录承载
|
|
16
|
+
Goal/Design/Tasks/Verification 与验收证据。
|
|
17
|
+
- **不启用**:纯文档小修(直接改归属文档,用 `flow-docs` 约定)、一次性问答、纯调研
|
|
18
|
+
(见 `flow-research`,调研本身不建记录)。
|
|
19
|
+
|
|
20
|
+
## 默认路径:一次变更一份记录
|
|
21
|
+
|
|
22
|
+
1. 创建记录(需要项目已初始化;未初始化先 `op:"init"`):
|
|
23
|
+
- `cabbage({op:"new", type:"change", change:"fix-label"})`
|
|
24
|
+
- 事故复盘用 `type:"incident"`(incident → postmortem → tasks)。
|
|
25
|
+
2. 填写 `tasks.md`:`Goal`(含复现的问题)、`Design`(最小方案)、`Tasks`、`Verification`。
|
|
26
|
+
3. 实现前评估风险并声明标记(会生成对应专项文档):
|
|
27
|
+
- `cabbage({op:"impact", change:"fix-label", impact:["api=true","design=true"]})`
|
|
28
|
+
- 标记表:`design`→tech-spec、`rfc`→rfc、`architecture`→adr、`api`→api-design、
|
|
29
|
+
`database`→database-design、`security`→security-review、`deployment`→release-plan。
|
|
30
|
+
- 数据迁移 = `database` + `deployment`;跨团队评审 = `rfc`(+按需 `design`)。
|
|
31
|
+
4. 复现失败 → 最小修复 → 回归测试;完成任务清单并写入真实命令与结果。
|
|
32
|
+
5. 逐级验证与门禁:
|
|
33
|
+
- `cabbage({op:"verify", change:"fix-label", stage:"tasks"})`(有专项阶段先逐一验证)
|
|
34
|
+
- `cabbage({op:"gate", change:"fix-label", target:"merge"})` → 应输出 ALLOWED。
|
|
35
|
+
6. 合并后收尾:确认合并 → `cabbage({op:"archive", change:"fix-label"})`(自动 sync + 归档)。
|
|
36
|
+
|
|
37
|
+
速查(亮路径全链路):
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
cabbage({op:"new", type:"change", change:"fix-label"})
|
|
41
|
+
cabbage({op:"impact", change:"fix-label", impact:["api=true"]}) # 仅在确有风险时
|
|
42
|
+
cabbage({op:"verify", change:"fix-label", stage:"tasks"}) # 专项阶段先行
|
|
43
|
+
cabbage({op:"gate", change:"fix-label", target:"merge"}) # 期望 ALLOWED
|
|
44
|
+
cabbage({op:"archive", change:"fix-label"}) # 确认合并后
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 约束
|
|
48
|
+
|
|
49
|
+
- `change.yaml` 与 `state.json` 由 CLI 管理,不要手工编辑;验证后修改产物会让阶段 `stale`。
|
|
50
|
+
- 只声明真实风险;不为省文档隐瞒影响,也不为凑文档虚报标记。
|
|
51
|
+
- `archive` 不检查 Git 合并状态:必须人工确认合并后再归档。
|
|
52
|
+
- 记录描述单次改动;系统当前行为写入 `docs/` 编号目录(sync 只按映射复制,不做语义合并)。
|
|
53
|
+
- CLI 不可用(缺 Python 3.10+)时工具会返回明确错误:告知用户安装 Python,不要伪造验证结果。
|
|
54
|
+
|
|
55
|
+
## 常用操作
|
|
56
|
+
|
|
57
|
+
| 操作 | 用途 |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `init` | 初始化 `.cabbage/`(工作流、CI 模板、vendored CLI),每项目一次 |
|
|
60
|
+
| `status` / `next` | 记录列表与阶段就绪/阻塞(不猜阶段 ID,以 `next` 为准) |
|
|
61
|
+
| `verify` / `gate` | 阶段验证与门禁(`target`:阶段 ID / `merge` / `archive`) |
|
|
62
|
+
| `validate` | 结构校验(省略 `change` 校验全部) |
|
|
63
|
+
| `sync` / `archive` | 同步当前文档 / 收尾归档 |
|
|
64
|
+
| `tasks` / `discard` | 任务清单只读视图 / 废弃记录 |
|
|
65
|
+
|
|
66
|
+
> 无本插件工具的环境(如 Codex):以上操作对应 `python3 -m cabbage_cli <操作>` 直跑 CLI
|
|
67
|
+
> (CLI 需本地可用),语义与参数一致。
|
|
68
|
+
|
|
69
|
+
## Contract
|
|
70
|
+
|
|
71
|
+
### Trigger
|
|
72
|
+
由 `@dev-lifecycle` 分诊(Bug 修复、重构、业务调整、紧急修复等轻量路径)或用户要求建立变更记录时触发;
|
|
73
|
+
大流程的代码改动也可在实现阶段引用本 skill。
|
|
74
|
+
|
|
75
|
+
### Inputs
|
|
76
|
+
- 变更描述(问题/目标、影响范围)
|
|
77
|
+
- 变更 id(kebab-case,按功能派生)
|
|
78
|
+
- 可选:影响标记(design/rfc/architecture/api/database/security/deployment)
|
|
79
|
+
|
|
80
|
+
### Preconditions
|
|
81
|
+
- 项目已初始化(无 `.cabbage/` 时先 `init`)
|
|
82
|
+
- 插件内置引擎可用(缺 Python 3.10+ 时停止并告知用户)
|
|
83
|
+
|
|
84
|
+
### Procedure
|
|
85
|
+
1. 创建记录并填写 `tasks.md` 的 Goal 与 Design
|
|
86
|
+
2. 实现前声明真实风险标记(必要时)
|
|
87
|
+
3. 实现并完成 Tasks 清单,记录真实验证命令与结果
|
|
88
|
+
4. 逐一 `verify` 已启用阶段(专项在前、`tasks` 在后)
|
|
89
|
+
5. `gate merge` 通过后交回编排器提交;合并确认后 `archive`
|
|
90
|
+
|
|
91
|
+
### Outputs
|
|
92
|
+
- `.cabbage/changes/<id>/`:tasks.md 与按需专项文档(验证后签名写入 state.json)
|
|
93
|
+
- 归档:`.cabbage/archive/<year>/<id>/` 与 `docs/` 的同步文档
|
|
94
|
+
|
|
95
|
+
### Failure
|
|
96
|
+
- `gate` BLOCKED → 用 `next` 找到未完成的已启用前置阶段并验证
|
|
97
|
+
- `placeholder content remains` / `unchecked tasks remain` → 清除模板提示、勾选任务后再验证
|
|
98
|
+
- 阶段 `stale` → 对照上游变化重新审阅并重新验证
|
|
99
|
+
- CLI 不可用 → 告知用户安装 Python 3.10+,不得伪造记录或验证结果
|
|
100
|
+
|
|
101
|
+
### Idempotency
|
|
102
|
+
- 同名记录已存在 → 复用并更新(`new` 报错说明已存在)
|
|
103
|
+
- 重复 `verify` 同一未变化阶段 → 幂等,仅刷新签名时间
|
|
104
|
+
- 重复 `sync` → 按映射覆盖目标文档,无副作用
|
|
105
|
+
|
|
106
|
+
### Prohibited Actions
|
|
107
|
+
- 不手工编辑 `change.yaml` / `state.json`
|
|
108
|
+
- 不在实现前伪造验证结果(专项文档写待执行步骤,真实结果回填 `tasks.md`)
|
|
109
|
+
- 不在未确认合并时 `archive`;不为通过门禁删改 CI 与工作流文件
|
|
@@ -29,6 +29,21 @@ description: 技术方案设计 → 方案文档 + ADR → Planning PR
|
|
|
29
29
|
```
|
|
30
30
|
4. **合入基线**:PR 合并后即形成设计基线(Planning Baseline),后续任务拆解以此为前置。
|
|
31
31
|
|
|
32
|
+
## ADR 内容标准
|
|
33
|
+
|
|
34
|
+
ADR 是决策记录,不是设计文档。只有改变组件边界、拓扑、关键依赖或数据归属的决策才写 ADR;
|
|
35
|
+
仅实现细节、内部重构、无长期影响的选型不写,记入变更记录即可。
|
|
36
|
+
|
|
37
|
+
必需标题(工作流逐字校验 `Context` / `Decision` / `Consequences`):
|
|
38
|
+
|
|
39
|
+
- `Context`:约束和现状,不写解决方案。
|
|
40
|
+
- `Decision`:选了什么**以及为什么**,列出被否决的备选方案和否决理由。
|
|
41
|
+
- `Consequences`:同时写正面和负面影响,包括引入的运维负担与待办。
|
|
42
|
+
|
|
43
|
+
需要跨团队评审、方案尚未定案时先写 RFC(`Problem` / `Proposal` / `Alternatives`),评审通过后再落 ADR。
|
|
44
|
+
**已合并的 ADR/RFC 不重命名、不改写**:新决策用新记录显式取代旧的,旧记录保留可追溯。
|
|
45
|
+
完整接口契约进 API 文档、表结构与迁移进数据库文档、测试策略进测试计划——不要塞进 ADR。
|
|
46
|
+
|
|
32
47
|
## 设计约束
|
|
33
48
|
|
|
34
49
|
技术方案必须遵循以下原则:
|
|
@@ -73,7 +88,7 @@ Test Seam 应描述公共行为边界,例如 Session API,而不是 `SessionR
|
|
|
73
88
|
|
|
74
89
|
## 存量 Design Amendment
|
|
75
90
|
|
|
76
|
-
当 tasks、code 或 review 阶段发现旧技术方案缺少 `Testing Decisions` 时,调用方可以在**保持当前 lifecycle stage 不变**的前提下委派 `@
|
|
91
|
+
当 tasks、code 或 review 阶段发现旧技术方案缺少 `Testing Decisions` 时,调用方可以在**保持当前 lifecycle stage 不变**的前提下委派 `@architect` 补齐设计:
|
|
77
92
|
|
|
78
93
|
1. 读取 Design Gap、原技术方案、相关 PRD / ADR 与 repository context。
|
|
79
94
|
2. 优先识别仓库已有的公共 Interface 和测试惯例,不为了补字段创建新 Seam。
|
|
@@ -82,7 +97,7 @@ Test Seam 应描述公共行为边界,例如 Session API,而不是 `SessionR
|
|
|
82
97
|
|
|
83
98
|
如果补齐过程暴露新的架构取舍或多个无法直接判断的 Seam 方案,停止 amendment 并把决策交给用户;不得静默扩大设计。Design Amendment 不回退 goal stage、不重复勾选阶段,也不单独创建新的 lifecycle 状态。
|
|
84
99
|
|
|
85
|
-
Design Amendment 是兼容子流程,覆盖本 skill 的普通发布流程:不创建 design 分支、Planning PR 或新 ADR。`@
|
|
100
|
+
Design Amendment 是兼容子流程,覆盖本 skill 的普通发布流程:不创建 design 分支、Planning PR 或新 ADR。`@architect` 只修改技术方案,primary 负责在当前 stage 保存变更并把补充内容传给后续 agent。
|
|
86
101
|
|
|
87
102
|
## CONTEXT.md 术语
|
|
88
103
|
|
|
@@ -101,7 +116,7 @@ Design Amendment 是兼容子流程,覆盖本 skill 的普通发布流程:
|
|
|
101
116
|
## Contract
|
|
102
117
|
|
|
103
118
|
### Trigger
|
|
104
|
-
由 `/design` 命令、`@
|
|
119
|
+
由 `/design` 命令、`@dev-lifecycle` Phase 1,或存量 Flow 的 Testing Decisions 兼容门触发。
|
|
105
120
|
|
|
106
121
|
### Inputs
|
|
107
122
|
- `docs/prd/<title>.md` — 上游 PRD(来源:requirements 阶段产出)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flow-docs
|
|
3
|
+
description: Write and organize long-lived project documentation — numbered docs tree placement, stable naming, relative links and anchors, Mermaid diagrams, ownership, and site preview or build. Use when authoring or moving current-state docs, fixing broken links, or running the documentation site.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# flow-docs
|
|
7
|
+
|
|
8
|
+
面向长期存在的**当前状态文档**(系统现在如何工作)。变更记录与门禁由 `flow-change` 负责。
|
|
9
|
+
|
|
10
|
+
## 目录归属(编号树)
|
|
11
|
+
|
|
12
|
+
`cabbage init` 生成的当前状态文档写入 `docs/` 下的编号目录,只创建有实际内容的目录:
|
|
13
|
+
|
|
14
|
+
| 目录 | 内容 |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `00-overview/` | 项目概览、范围、快速上手 |
|
|
17
|
+
| `01-product/` | 需求、用户故事、验收标准 |
|
|
18
|
+
| `02-design/` | 交互与视觉设计、原型说明 |
|
|
19
|
+
| `03-architecture/` | 系统设计、`adr/`、`rfc/` |
|
|
20
|
+
| `04-domain/` | 数据模型、数据库设计、迁移与回滚 |
|
|
21
|
+
| `05-api/` | 接口契约、事件、集成 |
|
|
22
|
+
| `06-development/` | 本地开发环境、构建与调试 |
|
|
23
|
+
| `07-standards/` | 编码规范、评审约定 |
|
|
24
|
+
| `08-testing/` | 测试策略与用例 |
|
|
25
|
+
| `09-security/` | 威胁模型、权限与合规控制 |
|
|
26
|
+
| `10-infrastructure/` | 部署拓扑、容量、环境配置 |
|
|
27
|
+
| `11-ci-cd/` | 流水线定义与门禁说明 |
|
|
28
|
+
| `12-release/` | 发布流程与版本策略 |
|
|
29
|
+
| `13-operations/` | 运行手册、监控、应急预案 |
|
|
30
|
+
| `14-performance/` | 性能基线与压测结果 |
|
|
31
|
+
| `15-incidents/` | 事故记录与复盘(不可改写的历史) |
|
|
32
|
+
| `16-dependencies/` | 外部依赖清单与升级策略 |
|
|
33
|
+
| `17-compliance/` | 合规要求与审计证据 |
|
|
34
|
+
|
|
35
|
+
- 变更记录归档时 `archive` 自动 `sync`,把专项文档复制进对应编号目录;`sync` 只按映射复制,
|
|
36
|
+
不做语义合并。
|
|
37
|
+
- 流程阶段产出的 PRD / 技术方案 / ADR 保留各自路径(`docs/prd/`、`docs/dev/specs/`、`docs/adr/`),
|
|
38
|
+
与编号树各司其职:前者是流程产物,后者是长期当前状态。
|
|
39
|
+
- `.cabbage/changes/` 是变更历史,`docs/` 是当前状态,两者不互相复制内容。
|
|
40
|
+
|
|
41
|
+
## 写作原则
|
|
42
|
+
|
|
43
|
+
1. **单一事实来源**:一个事实只在一处定义,其他文档链接过去,不复制正文。
|
|
44
|
+
2. **当前状态 vs 决策历史**:当前状态文档原处更新;ADR/RFC/事故记录是不可改写的历史。
|
|
45
|
+
3. **稳定路径**:不使用 `spec-v2-final.md`、`_latest.md`、`_copy.md` 这类文件名,版本交给 Git。
|
|
46
|
+
4. **相对链接**:仓内链接一律用相对路径并带文件扩展名,不写 `/docs/...` 绝对路径。
|
|
47
|
+
5. **不写占位内容**:`TODO`、`TBD`、`FIXME` 会导致校验失败。
|
|
48
|
+
|
|
49
|
+
## 校验与站点
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cabbage({op:"validate"}) # 结构、标题锚点、相对路径、Mermaid 围栏(不要求先建变更)
|
|
53
|
+
cabbage({op:"validate", change:"x"}) # 或只校验某条记录
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
站点(如仓库使用 VitePress):`pnpm --dir docs run dev` 预览、`pnpm --dir docs run build` 构建;
|
|
57
|
+
构建失败先跑 `validate`(省略 `change` 校验全部)定位死链,再检查围栏闭合与 HTML 标签。
|
|
58
|
+
|
|
59
|
+
## 图表
|
|
60
|
+
|
|
61
|
+
使用 Mermaid,写在 ` ```mermaid ` 围栏内;围栏必须闭合,否则校验与站点构建都会失败。
|
|
62
|
+
常用类型:流程图、时序图、状态图、ER 图。图表只画难以用文字表达的关系。
|
|
63
|
+
|
|
64
|
+
## 归属与评审
|
|
65
|
+
|
|
66
|
+
关键长期文档应在 frontmatter 声明维护方:
|
|
67
|
+
|
|
68
|
+
```yaml
|
|
69
|
+
---
|
|
70
|
+
owner: team-billing
|
|
71
|
+
maintained-by: ["@alice"]
|
|
72
|
+
last-reviewed: 2026-03-01
|
|
73
|
+
---
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
用 `.github/CODEOWNERS` 让架构、安全等目录的改动必须由对应负责人评审。
|
|
77
|
+
该 frontmatter 是约定,CLI 不校验也不强制;真正的强制来自代码托管平台的分支保护。
|
|
78
|
+
|
|
79
|
+
## Contract
|
|
80
|
+
|
|
81
|
+
### Trigger
|
|
82
|
+
撰写或移动当前状态文档、修复死链、整理文档归属、预览或构建文档站点时触发。
|
|
83
|
+
|
|
84
|
+
### Inputs
|
|
85
|
+
- 文档内容或需要修复的链接/结构问题
|
|
86
|
+
- 目标编号目录(按内容性质选择)
|
|
87
|
+
|
|
88
|
+
### Preconditions
|
|
89
|
+
- 项目 docs 树已存在(未初始化时先经 `flow-change` 执行 `op:"init"`)
|
|
90
|
+
|
|
91
|
+
### Procedure
|
|
92
|
+
1. 按内容性质选择编号目录;只创建有实际内容的目录
|
|
93
|
+
2. 遵循写作原则(单一事实来源、稳定路径、相对链接、无占位)
|
|
94
|
+
3. `op:"validate"` 校验结构与链接;站点项目再执行构建
|
|
95
|
+
4. 关键文档补 frontmatter 归属;治理目录配 CODEOWNERS
|
|
96
|
+
|
|
97
|
+
### Outputs
|
|
98
|
+
- `docs/` 编号目录下的当前状态文档(或修复后的链接/结构)
|
|
99
|
+
|
|
100
|
+
### Failure
|
|
101
|
+
- `broken link` → 修正相对路径层级或锚点 slug,确认目标文件存在
|
|
102
|
+
- 链接越出项目根 → 改用仓内相对路径
|
|
103
|
+
- 站点依赖缺失 → 重新安装站点依赖后再构建
|
|
104
|
+
|
|
105
|
+
### Idempotency
|
|
106
|
+
- 重复 `validate` → 幂等只读
|
|
107
|
+
- 同一批移动操作分批提交 → 每批后校验保持可构建
|
|
108
|
+
|
|
109
|
+
### Prohibited Actions
|
|
110
|
+
- 不用 `final-v2`、`_latest`、`_copy` 之类文件名
|
|
111
|
+
- 不改写已归档的历史记录(ADR/RFC/事故)
|
|
112
|
+
- 不在当前状态文档与变更记录间复制正文
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flow-incident
|
|
3
|
+
description: Document production incidents and postmortems — incident timeline, impact, containment and recovery, blameless root cause, corrective actions grounded through the built-in Cabbage engine. Use for outages, severity events, live-service failures, or writing a postmortem retrospective.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# flow-incident
|
|
7
|
+
|
|
8
|
+
处置生产事故时,先止损、再取证、后复盘。**不要在事故进行中伪造完整时间线或结论。**
|
|
9
|
+
|
|
10
|
+
## 流程(经内置引擎)
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
cabbage({op:"new", type:"incident", change:"payment-timeout-2026-08-29"})
|
|
14
|
+
cabbage({op:"next", change:"payment-timeout-2026-08-29"}) # 阶段:incident → postmortem → tasks
|
|
15
|
+
# 1. 记录事实:填写 incident.md
|
|
16
|
+
cabbage({op:"verify", change:"payment-timeout-2026-08-29", stage:"incident"})
|
|
17
|
+
# 2. 分析根因:填写 postmortem.md
|
|
18
|
+
cabbage({op:"verify", change:"payment-timeout-2026-08-29", stage:"postmortem"})
|
|
19
|
+
# 3. 预防措施落地:完成任务清单
|
|
20
|
+
cabbage({op:"verify", change:"payment-timeout-2026-08-29", stage:"tasks"})
|
|
21
|
+
cabbage({op:"gate", change:"payment-timeout-2026-08-29", target:"merge"})
|
|
22
|
+
# 合并确认后:
|
|
23
|
+
cabbage({op:"archive", change:"payment-timeout-2026-08-29"})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
阶段 ID 以 `next` 输出为准:`incident` → `postmortem` → `tasks`。前两个阶段是事实与分析,第三个阶段是实际修复与预防措施。
|
|
27
|
+
|
|
28
|
+
**分级降载**:正在处置的紧急故障不要为了走流程而拖延止血。先经 `flow-change` 走最小修复路径
|
|
29
|
+
(`type:"change"` + 声明 `deployment=true`),事后另立 incident 记录复盘;不要把两者混在同一记录里。
|
|
30
|
+
|
|
31
|
+
## incident.md:先记事实
|
|
32
|
+
|
|
33
|
+
必需标题 `Impact` / `Timeline` / `Mitigation`。
|
|
34
|
+
|
|
35
|
+
- 时间戳统一用 UTC 或明确标注时区;事故期间先记原始观测,不追求措辞。
|
|
36
|
+
- `Impact` 量化受影响用户数、时长、区域、功能、数据与 SLO 影响;无法量化时写估计方法与误差。
|
|
37
|
+
- `Timeline` 记录事件、观测与采取的行动及其执行人,包括误判和无效尝试。
|
|
38
|
+
- `Mitigation` 区分 **Containment**(如何限制影响,如回滚、摘流量、限流)与 **Recovery**(如何恢复,
|
|
39
|
+
及仍然降级的行为)。
|
|
40
|
+
- 恢复后补 `Recovery Verification`:证明恢复的指标、检查项与观察窗口。
|
|
41
|
+
- 不要写"疑似"当结论;不确定的内容标注为待确认。
|
|
42
|
+
|
|
43
|
+
## postmortem.md:对事不对人
|
|
44
|
+
|
|
45
|
+
必需标题 `Root Cause` / `Contributing Factors` / `Corrective Actions`。
|
|
46
|
+
|
|
47
|
+
- 区分 **触发点**(直接原因)与 **根因**(使其可能且未被拦截的系统条件)。
|
|
48
|
+
- 根因结论要有证据支撑:日志、指标、变更记录、复现步骤,而非推测。
|
|
49
|
+
- `Corrective Actions` 每项必须有单一责任人、期限、验证方式与状态;笼统的"加强监控""提高意识"
|
|
50
|
+
不是可验证的措施。
|
|
51
|
+
- 保持无责文化:记录系统为何允许人为错误造成影响,不记录个人过失。
|
|
52
|
+
|
|
53
|
+
## tasks.md:预防措施落地
|
|
54
|
+
|
|
55
|
+
`postmortem.md` 中的措施要落到实际任务,完成并验证后才通过阶段。
|
|
56
|
+
只写计划不执行会阻塞合并门禁,这是刻意的:复盘结论必须兑现。
|
|
57
|
+
|
|
58
|
+
## 边界
|
|
59
|
+
|
|
60
|
+
- 事故记录与变更记录都属于决策历史,归档后不重写、不"现代化"措辞。
|
|
61
|
+
- 当前系统的运行方式写到长期运行文档;事故报告本身是历史记录。
|
|
62
|
+
- 结构校验只检查标题、占位符与链接,不判断根因分析是否正确;复盘质量仍需人工评审。
|
|
63
|
+
|
|
64
|
+
## Contract
|
|
65
|
+
|
|
66
|
+
### Trigger
|
|
67
|
+
生产事故、严重事件、线上服务故障的处置与复盘;或用户要求撰写事故报告时触发。
|
|
68
|
+
|
|
69
|
+
### Inputs
|
|
70
|
+
- 事故基本事实(时间、影响、止损与恢复过程)
|
|
71
|
+
- 证据材料(日志、指标、变更记录、复现步骤)
|
|
72
|
+
|
|
73
|
+
### Preconditions
|
|
74
|
+
- 事故已止血或已恢复(进行中不写完整复盘)
|
|
75
|
+
- 项目已初始化(无 `.cabbage/` 时先经 `flow-change` 执行 `op:"init"`)
|
|
76
|
+
|
|
77
|
+
### Procedure
|
|
78
|
+
1. `op:"new" type:"incident"` 创建记录并如实填写 incident.md(Impact/Timeline/Mitigation)
|
|
79
|
+
2. 验证 incident 阶段后撰写 postmortem.md(根因、促成因素、纠正措施)
|
|
80
|
+
3. 将纠正措施落成 tasks.md 清单并实际执行
|
|
81
|
+
4. 逐阶段 `verify` → `gate merge` → 合并确认后 `archive`
|
|
82
|
+
|
|
83
|
+
### Outputs
|
|
84
|
+
- `.cabbage/changes/<id>/`:incident.md、postmortem.md、tasks.md(验证后签名)
|
|
85
|
+
- 归档后:`.cabbage/archive/<year>/<id>/`
|
|
86
|
+
|
|
87
|
+
### Failure
|
|
88
|
+
- 时间线/证据不完整 → 标注待确认,不编造;补齐后重新验证
|
|
89
|
+
- 措施无法在本次完成 → 转入独立变更(flow-change)跟踪,本记录如实标注状态
|
|
90
|
+
|
|
91
|
+
### Idempotency
|
|
92
|
+
- 重复 `verify` 未变化阶段 → 幂等
|
|
93
|
+
- 事故期间多次追加时间线 → 更新产物后重新验证
|
|
94
|
+
|
|
95
|
+
### Prohibited Actions
|
|
96
|
+
- 不在处置进行中伪造完整时间线或根因结论
|
|
97
|
+
- 不把紧急修复与事故复盘混在同一记录
|
|
98
|
+
- 不将未执行的预防措施勾选为完成
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: flow-research
|
|
3
|
-
description: 调研/事实核查 — 迭代深化 + 一手来源评分 + 反方搜索 + 置信度 → 调研文档(由 @
|
|
3
|
+
description: 调研/事实核查 — 迭代深化 + 一手来源评分 + 反方搜索 + 置信度 → 调研文档(由 @researcher 加载)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# flow-research
|
|
7
7
|
|
|
8
|
-
针对调研问题系统性收集资料、验证来源、交叉对比,产出仅事实、带引用的调研文档。由独立子 agent `@
|
|
8
|
+
针对调研问题系统性收集资料、验证来源、交叉对比,产出仅事实、带引用的调研文档。由独立子 agent `@researcher` 加载执行,可作为 Flow 的阶段,也可作为独立轻量路径。
|
|
9
9
|
|
|
10
10
|
## 核心流程
|
|
11
11
|
|
|
@@ -21,6 +21,15 @@ description: 调研/事实核查 — 迭代深化 + 一手来源评分 + 反方
|
|
|
21
21
|
7. **元评审**(输出前自省):剩余未知、最弱证据、可能错误的假设、遗漏角度、边际收益。
|
|
22
22
|
8. **输出**:写 `docs/dev/research/<topic>.md`,并在消息中给结论/可执行建议摘要。
|
|
23
23
|
|
|
24
|
+
## 调研纪律
|
|
25
|
+
|
|
26
|
+
1. **先定义决策,后收集资料**:开始前写下"要回答什么问题"和"什么条件下选哪个方案";结论不改变决策就不调研。
|
|
27
|
+
2. **硬性约束优先于加权评分**:不满足硬性约束的方案直接淘汰,不进入评分表。
|
|
28
|
+
3. **事实、推断、未知项分开**:不得把推断写成事实;无法验证就写"待验证",禁止补全式猜测。
|
|
29
|
+
4. **优先验证失败路径**,不只验证正常路径。
|
|
30
|
+
5. **PoC 边界**:只验证会导致方案被否决的那个假设,不开发完整系统。
|
|
31
|
+
6. **推荐必须包含适用边界、代价和退出条件**(什么信号出现时需要重新评估)。
|
|
32
|
+
|
|
24
33
|
## 何时停止迭代
|
|
25
34
|
|
|
26
35
|
- 所有关键问题 ≥2 个独立来源支持
|
|
@@ -43,7 +52,7 @@ gh api repos/"$REPO"/issues/<issue-number>/comments --jq '.[].body'
|
|
|
43
52
|
## Contract
|
|
44
53
|
|
|
45
54
|
### Trigger
|
|
46
|
-
由 `@
|
|
55
|
+
由 `@dev-lifecycle` Phase 0 调研场景派发 `@researcher` 触发。
|
|
47
56
|
|
|
48
57
|
### Inputs
|
|
49
58
|
- 用户的调研问题 / 需求(含范围与输出形式)
|
|
@@ -39,6 +39,19 @@ description: 初始化 — 探测环境 → 确认 Profile
|
|
|
39
39
|
- release workflow: `.github/workflows/release.yml`
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
## 存量项目接入(adopt)
|
|
43
|
+
|
|
44
|
+
仓库已有文档时(`init` 只新增骨架、不改写已有文件;无 `.cabbage/` 时先经 flow-change 执行 `op:"init"`):
|
|
45
|
+
|
|
46
|
+
1. `cabbage({op:"adopt"})` 盘点 `docs/` 树之外的 Markdown → 生成 `.cabbage/` 下的 `adoption-report.md`;
|
|
47
|
+
每份文档得到四种动作:`keep`(已在编号目录)/ `migrate`(当前状态文档)/ `import`(历史记录)/
|
|
48
|
+
`review`(无法归类)。分类仅基于目录与文件名推断,**始终需要人工确认**。
|
|
49
|
+
2. 逐行处理 `review`,与文档负责人确认归属;`import` 的历史记录(ADR/RFC/事故)原样归档,
|
|
50
|
+
**不改写内容**。
|
|
51
|
+
3. `migrate` 用 `git mv` 保留历史,一个逻辑批次一个提交;移动后立即修正相对链接。
|
|
52
|
+
4. 每批后 `cabbage({op:"validate"})` + 站点构建,确认无死链。
|
|
53
|
+
5. 接入完成的判据:再次 `op:"adopt"` 应全部报告 `keep`。
|
|
54
|
+
|
|
42
55
|
## Output
|
|
43
56
|
- readiness 报告(git/gh 可用性、CI/release workflow 存在性)
|
|
44
57
|
- 根 AGENTS.md `## Project Profile` 区块
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,eAAe
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,eAAe,eAAe,CAAA"}
|
package/dist/plugin/agents.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Agent frontmatter 的 permission 解析。
|
|
3
3
|
* 值可为字符串(如 "deny"、"npm test|git push")或嵌套规则对象
|
|
4
4
|
* (OpenCode 语义:pattern → action,如 bash: { "*": "deny", "npm *": "allow" })。
|
|
5
|
+
* V2 注册时转换为规则数组(见 buildAgentRules)。
|
|
5
6
|
*/
|
|
6
7
|
export interface AgentPermission {
|
|
7
8
|
[key: string]: string | Record<string, string> | undefined;
|
|
@@ -12,6 +13,25 @@ export interface AgentEntry {
|
|
|
12
13
|
mode?: "subagent" | "primary" | "all";
|
|
13
14
|
color?: string;
|
|
14
15
|
permission?: AgentPermission;
|
|
16
|
+
/** V1 tools 启停映射(write/edit/bash/read…);false 表示禁用该工具 */
|
|
17
|
+
tools?: Record<string, boolean>;
|
|
15
18
|
prompt: string;
|
|
16
19
|
}
|
|
20
|
+
/** V2 permission 规则(@opencode/schema PermissionRule 子集) */
|
|
21
|
+
export interface AgentRule {
|
|
22
|
+
action: string;
|
|
23
|
+
resource: string;
|
|
24
|
+
effect: "allow" | "deny" | "ask";
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 将 agent 的 V1 风格 permission/tools 转换为 V2 规则数组。
|
|
28
|
+
* 顺序保持声明序(V2 最后匹配优先);tools 禁用规则置于末尾(V1 语义:工具整体禁用不可被白名单恢复)。
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildAgentRules(entry: AgentEntry, testCommandToken: string): AgentRule[];
|
|
31
|
+
/** V2 agent 注册载荷:缺失时新增,已存在则保留用户版本(V1 的 skip-if-exists 语义) */
|
|
32
|
+
export interface AgentPayload {
|
|
33
|
+
key: string;
|
|
34
|
+
fields: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
export declare function buildAgentPayloads(agentsDir: string, testCommandToken: string): AgentPayload[];
|
|
17
37
|
export declare function loadAgents(agentsDir: string): AgentEntry[];
|
package/dist/plugin/agents.js
CHANGED
|
@@ -1,6 +1,78 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, existsSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { parse as parseYaml } from "yaml";
|
|
4
|
+
/** V1 tools 名 → V2 permission action(write 工具的权限 action 实测为 "edit") */
|
|
5
|
+
const TOOLS_TO_PERMISSION_ACTION = {
|
|
6
|
+
write: "edit",
|
|
7
|
+
edit: "edit",
|
|
8
|
+
bash: "bash",
|
|
9
|
+
read: "read",
|
|
10
|
+
glob: "glob",
|
|
11
|
+
grep: "grep",
|
|
12
|
+
webfetch: "webfetch",
|
|
13
|
+
websearch: "websearch",
|
|
14
|
+
todowrite: "todowrite",
|
|
15
|
+
task: "subagent",
|
|
16
|
+
};
|
|
17
|
+
function normalizeEffect(value) {
|
|
18
|
+
return value === "allow" ? "allow" : value === "deny" ? "deny" : "ask";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 渲染规则中的 `<profile-test-command>` 占位符为 Profile 测试命令首 token。
|
|
22
|
+
* Profile 未配置(token 为空)时返回 null 表示删除该规则(避免渲染成 "*" 覆盖兜底 deny)。
|
|
23
|
+
*/
|
|
24
|
+
function renderPlaceholder(pattern, testCommandToken) {
|
|
25
|
+
if (!pattern.includes("<profile-test-command>"))
|
|
26
|
+
return pattern;
|
|
27
|
+
if (testCommandToken === "")
|
|
28
|
+
return null;
|
|
29
|
+
return pattern.replaceAll("<profile-test-command>", testCommandToken);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 将 agent 的 V1 风格 permission/tools 转换为 V2 规则数组。
|
|
33
|
+
* 顺序保持声明序(V2 最后匹配优先);tools 禁用规则置于末尾(V1 语义:工具整体禁用不可被白名单恢复)。
|
|
34
|
+
*/
|
|
35
|
+
export function buildAgentRules(entry, testCommandToken) {
|
|
36
|
+
const rules = [];
|
|
37
|
+
for (const [action, value] of Object.entries(entry.permission ?? {})) {
|
|
38
|
+
if (typeof value === "string") {
|
|
39
|
+
rules.push({ action, resource: "*", effect: normalizeEffect(value) });
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (!value)
|
|
43
|
+
continue;
|
|
44
|
+
for (const [pattern, raw] of Object.entries(value)) {
|
|
45
|
+
const rendered = renderPlaceholder(pattern, testCommandToken);
|
|
46
|
+
if (rendered === null)
|
|
47
|
+
continue;
|
|
48
|
+
rules.push({ action, resource: rendered, effect: normalizeEffect(raw) });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const deniedActions = new Set();
|
|
52
|
+
for (const [tool, enabled] of Object.entries(entry.tools ?? {})) {
|
|
53
|
+
if (enabled !== false)
|
|
54
|
+
continue;
|
|
55
|
+
const action = TOOLS_TO_PERMISSION_ACTION[tool] ?? tool;
|
|
56
|
+
if (deniedActions.has(action))
|
|
57
|
+
continue;
|
|
58
|
+
deniedActions.add(action);
|
|
59
|
+
rules.push({ action, resource: "*", effect: "deny" });
|
|
60
|
+
}
|
|
61
|
+
return rules;
|
|
62
|
+
}
|
|
63
|
+
export function buildAgentPayloads(agentsDir, testCommandToken) {
|
|
64
|
+
return loadAgents(agentsDir).map((entry) => ({
|
|
65
|
+
key: entry.key,
|
|
66
|
+
fields: {
|
|
67
|
+
name: entry.key,
|
|
68
|
+
...(entry.description ? { description: entry.description } : {}),
|
|
69
|
+
...(entry.mode ? { mode: entry.mode } : {}),
|
|
70
|
+
...(entry.color ? { color: entry.color } : {}),
|
|
71
|
+
system: entry.prompt,
|
|
72
|
+
permissions: buildAgentRules(entry, testCommandToken),
|
|
73
|
+
},
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
4
76
|
function parseAgentFile(filePath) {
|
|
5
77
|
const content = readFileSync(filePath, "utf8");
|
|
6
78
|
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
@@ -38,12 +110,19 @@ function parseAgentFile(filePath) {
|
|
|
38
110
|
})
|
|
39
111
|
.filter(([, v]) => v !== undefined))
|
|
40
112
|
: undefined;
|
|
113
|
+
const toolsRaw = parsed.tools;
|
|
114
|
+
const tools = toolsRaw && typeof toolsRaw === "object" && !Array.isArray(toolsRaw)
|
|
115
|
+
? Object.fromEntries(Object.entries(toolsRaw)
|
|
116
|
+
.filter(([, v]) => typeof v === "boolean")
|
|
117
|
+
.map(([k, v]) => [k, v]))
|
|
118
|
+
: undefined;
|
|
41
119
|
return {
|
|
42
120
|
key: name,
|
|
43
121
|
description: parsed.description,
|
|
44
122
|
mode: parsed.mode,
|
|
45
123
|
color: parsed.color,
|
|
46
124
|
permission,
|
|
125
|
+
tools,
|
|
47
126
|
prompt: body,
|
|
48
127
|
};
|
|
49
128
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/plugin/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAC/D,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/plugin/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAC/D,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAA;AA8BzC,uEAAuE;AACvE,MAAM,0BAA0B,GAA2B;IACzD,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,UAAU;CACjB,CAAA;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAA;AACxE,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,OAAe,EAAE,gBAAwB;IAClE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QAAE,OAAO,OAAO,CAAA;IAC/D,IAAI,gBAAgB,KAAK,EAAE;QAAE,OAAO,IAAI,CAAA;IACxC,OAAO,OAAO,CAAC,UAAU,CAAC,wBAAwB,EAAE,gBAAgB,CAAC,CAAA;AACvE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAiB,EAAE,gBAAwB;IACzE,MAAM,KAAK,GAAgB,EAAE,CAAA;IAC7B,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;QACrE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YACrE,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAA;YAC7D,IAAI,QAAQ,KAAK,IAAI;gBAAE,SAAQ;YAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC1E,CAAC;IACH,CAAC;IACD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAA;IACvC,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAChE,IAAI,OAAO,KAAK,KAAK;YAAE,SAAQ;QAC/B,MAAM,MAAM,GAAG,0BAA0B,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA;QACvD,IAAI,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAQ;QACvC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACzB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACvD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAQD,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,gBAAwB;IAC5E,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3C,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE;YACN,IAAI,EAAE,KAAK,CAAC,GAAG;YACf,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,WAAW,EAAE,eAAe,CAAC,KAAK,EAAE,gBAAgB,CAAC;SACtD;KACF,CAAC,CAAC,CAAA;AACL,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB;IACtC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAA;IAChE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAEvB,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;IAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAE5B,IAAI,MAA+B,CAAA;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,cAAc,CAA4B,CAAA;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IACtD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;IACtC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IAEtB,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAA;IACvC,MAAM,UAAU,GACd,aAAa,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;QACjF,CAAC,CAAC,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,aAAwC,CAAC;aACrD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YACpB,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YAClD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChE,MAAM,KAAK,GAA2B,EAAE,CAAA;gBACxC,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;oBACjF,IAAI,OAAO,MAAM,KAAK,QAAQ;wBAAE,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM,CAAA;gBACzD,CAAC;gBACD,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACrB,CAAC;YACD,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QACzB,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CACtC;QACH,CAAC,CAAC,SAAS,CAAA;IAEf,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAA;IAC7B,MAAM,KAAK,GAAG,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAChF,CAAC,CAAC,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,QAAmC,CAAC;aAChD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC;aACzC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAY,CAAC,CAAC,CACtC;QACH,CAAC,CAAC,SAAS,CAAA;IAEb,OAAO;QACL,GAAG,EAAE,IAAI;QACT,WAAW,EAAE,MAAM,CAAC,WAAiC;QACrD,IAAI,EAAE,MAAM,CAAC,IAA0B;QACvC,KAAK,EAAE,MAAM,CAAC,KAA2B;QACzC,UAAU;QACV,KAAK;QACL,MAAM,EAAE,IAAI;KACb,CAAA;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,MAAM,GAAiB,EAAE,CAAA;IAE/B,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACpE,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjD,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;gBAC9D,IAAI,KAAK;oBAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IAC5C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YAClE,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjD,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;gBAC5D,IAAI,KAAK;oBAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内置 Cabbage 引擎运行时(阶段二:先内嵌 Python,后续再评估 TS 移植)。
|
|
3
|
+
*
|
|
4
|
+
* 插件包内置 `vendor/cabbage/cabbage_cli`(由 scripts/sync-cabbage.mjs 固定版本生成),
|
|
5
|
+
* 首次 setup 时按插件版本释放到 `~/.config/opencode/cabbage/cli@<version>/`,
|
|
6
|
+
* 之后所有工具调用以 `python3 -m cabbage_cli` 执行(PYTHONPATH 指向该目录)。
|
|
7
|
+
* 需要 Python 3.10+;缺失时 available=false 且给出原因,工具层返回可读错误。
|
|
8
|
+
*/
|
|
9
|
+
export interface CabbageCliRuntime {
|
|
10
|
+
available: boolean;
|
|
11
|
+
python: string | null;
|
|
12
|
+
dir: string | null;
|
|
13
|
+
version: string | null;
|
|
14
|
+
reason: string | null;
|
|
15
|
+
}
|
|
16
|
+
export interface CabbageRunResult {
|
|
17
|
+
code: number;
|
|
18
|
+
stdout: string;
|
|
19
|
+
stderr: string;
|
|
20
|
+
}
|
|
21
|
+
/** 探测可用的 Python 解释器(python3 优先);均不可用返回 null。 */
|
|
22
|
+
export declare function detectPython(): Promise<string | null>;
|
|
23
|
+
export declare function setupCabbageCli(packageRoot: string, version: string): Promise<CabbageCliRuntime>;
|
|
24
|
+
/**
|
|
25
|
+
* 执行一次 cabbage 子命令。非零退出以结果返回(code/stdout/stderr),
|
|
26
|
+
* 仅进程无法启动(如解释器消失)才抛错——调用方按 CLI 语义处理退出码。
|
|
27
|
+
*/
|
|
28
|
+
export declare function runCabbage(cli: CabbageCliRuntime, args: string[], cwd: string): Promise<CabbageRunResult>;
|