cowork-flow 0.0.43 → 0.0.45

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.
Files changed (173) hide show
  1. package/README.md +39 -23
  2. package/package.json +8 -4
  3. package/src/commands/install-zcode-plugin.js +3 -15
  4. package/src/lib/copy-template.js +119 -66
  5. package/template/.claude/agents/cowork-check.md +14 -58
  6. package/template/.claude/agents/cowork-implement.md +15 -61
  7. package/template/.claude/agents/cowork-research.md +9 -31
  8. package/template/.claude/hooks/inject-workflow-state.py +1 -1
  9. package/template/.codex/agents/cowork-check.toml +14 -51
  10. package/template/.codex/agents/cowork-implement.toml +15 -54
  11. package/template/.codex/agents/cowork-research.toml +8 -22
  12. package/template/.codex/hooks/inject-workflow-state.py +1 -1
  13. package/template/.cowork-flow/.version +1 -1
  14. package/template/.cowork-flow/scripts/adapters/__init__.py +1 -0
  15. package/template/.cowork-flow/scripts/adapters/cli/_bootstrap.py +14 -0
  16. package/template/.cowork-flow/scripts/{commands → adapters/cli}/add_session.py +3 -3
  17. package/template/.cowork-flow/scripts/adapters/cli/batch_mode.py +90 -0
  18. package/template/.cowork-flow/scripts/{commands → adapters/cli}/change.py +2 -2
  19. package/template/.cowork-flow/scripts/adapters/cli/encoding.py +28 -0
  20. package/template/.cowork-flow/scripts/adapters/cli/execution_context_args.py +121 -0
  21. package/template/.cowork-flow/scripts/{common/core/execution_context.py → adapters/cli/execution_resume.py} +9 -216
  22. package/template/.cowork-flow/scripts/{commands → adapters/cli}/get_context.py +1 -1
  23. package/template/.cowork-flow/scripts/{commands → adapters/cli}/get_developer.py +2 -2
  24. package/template/.cowork-flow/scripts/{commands → adapters/cli}/init_developer.py +2 -2
  25. package/template/.cowork-flow/scripts/{commands → adapters/cli}/resume.py +5 -3
  26. package/template/.cowork-flow/scripts/{commands → adapters/cli}/subagent.py +4 -4
  27. package/template/.cowork-flow/scripts/{commands → adapters/cli}/task.py +259 -179
  28. package/template/.cowork-flow/scripts/{commands → adapters/cli}/task_archive_commands.py +12 -12
  29. package/template/.cowork-flow/scripts/{commands → adapters/cli}/task_context_commands.py +5 -5
  30. package/template/.cowork-flow/scripts/{commands → adapters/cli}/task_create_command.py +26 -8
  31. package/template/.cowork-flow/scripts/adapters/cli/task_navigation.py +226 -0
  32. package/template/.cowork-flow/scripts/adapters/cli/task_parser.py +167 -0
  33. package/template/.cowork-flow/scripts/{commands → adapters/cli}/task_support.py +2 -2
  34. package/template/.cowork-flow/scripts/{commands → adapters/cli}/task_tree_commands.py +4 -4
  35. package/template/.cowork-flow/scripts/{common → adapters}/git/git_context.py +6 -6
  36. package/template/.cowork-flow/scripts/{common/core → adapters/host}/host_manifest.py +28 -1
  37. package/template/.cowork-flow/scripts/{common → adapters}/host/workflow_state_hook.py +7 -7
  38. package/template/.cowork-flow/scripts/adapters/review/__init__.py +1 -0
  39. package/template/.cowork-flow/scripts/{common/gates → adapters/review}/test_intent.py +26 -92
  40. package/template/.cowork-flow/scripts/infra/__init__.py +0 -0
  41. package/template/.cowork-flow/scripts/{common/core → infra}/config.py +1 -1
  42. package/template/.cowork-flow/scripts/{common/core/developer.py → infra/developer_profile.py} +1 -1
  43. package/template/.cowork-flow/scripts/{common/git → infra}/git_snapshot.py +15 -2
  44. package/template/.cowork-flow/scripts/{common/core → infra}/paths.py +0 -0
  45. package/template/.cowork-flow/scripts/{common/core → infra}/quality_sources.py +0 -17
  46. package/template/.cowork-flow/scripts/infra/skill_manifest.py +427 -0
  47. package/template/.cowork-flow/scripts/{common → infra}/storage/operation_log.py +1 -1
  48. package/template/.cowork-flow/scripts/{common → infra}/storage/unit_of_work.py +2 -2
  49. package/template/.cowork-flow/scripts/kernel/__init__.py +1 -0
  50. package/template/.cowork-flow/scripts/{common/task/state_machine.py → kernel/task_state.py} +2 -2
  51. package/template/.cowork-flow/scripts/kernel/workflow_route.py +199 -0
  52. package/template/.cowork-flow/scripts/run.py +65 -42
  53. package/template/.cowork-flow/scripts/runtime/__init__.py +0 -0
  54. package/template/.cowork-flow/scripts/runtime/execution_context.py +121 -0
  55. package/template/.cowork-flow/scripts/{common/task/active_task.py → runtime/session_state.py} +2 -47
  56. package/template/.cowork-flow/scripts/services/__init__.py +1 -0
  57. package/template/.cowork-flow/scripts/services/lifecycle_checks.py +194 -0
  58. package/template/.cowork-flow/scripts/{common/task → services}/readiness.py +8 -90
  59. package/template/.cowork-flow/scripts/{application → services}/task_archive.py +7 -7
  60. package/template/.cowork-flow/scripts/{application → services}/task_context.py +50 -88
  61. package/template/.cowork-flow/scripts/{application → services}/task_creation.py +3 -3
  62. package/template/.cowork-flow/scripts/{application → services}/task_lifecycle.py +52 -84
  63. package/template/.cowork-flow/scripts/{common/task → services}/task_repository.py +3 -3
  64. package/template/.cowork-flow/scripts/services/task_routing.py +148 -0
  65. package/template/.cowork-flow/scripts/{application → services}/task_tree.py +3 -3
  66. package/template/.cowork-flow/scripts/{common/task → services}/task_utils.py +3 -3
  67. package/template/.cowork-flow/scripts/{application/runtime_context_service.py → services/workflow_runtime.py} +38 -3
  68. package/template/.cowork-flow/spec/backend/index.md +1 -1
  69. package/template/.cowork-flow/spec/backend/quality-guidelines.md +1 -3
  70. package/template/.cowork-flow/spec/contracts/decision-anchor.md +2 -2
  71. package/template/.cowork-flow/spec/contracts/error-output-as-data.md +1 -1
  72. package/template/.cowork-flow/spec/contracts/index.md +1 -0
  73. package/template/.cowork-flow/spec/contracts/skill-owned-actions.md +46 -0
  74. package/template/.cowork-flow/spec/contracts/workflow-state-templates.md +22 -39
  75. package/template/.cowork-flow/spec/frontend/index.md +1 -1
  76. package/template/.cowork-flow/spec/frontend/quality-guidelines.md +1 -3
  77. package/template/.cowork-flow/spec/index.md +8 -5
  78. package/template/.cowork-flow/spec/references/definition-of-done.md +4 -4
  79. package/template/.cowork-flow/spec/references/orchestration-patterns.md +2 -2
  80. package/template/.cowork-flow/spec/references/security-checklist.md +1 -1
  81. package/template/.cowork-flow/spec/references/testing-checklist.md +2 -2
  82. package/template/.cowork-flow/spec/runtime/contract-registry.json +4 -17
  83. package/template/.cowork-flow/spec/runtime/host-assets.json +81 -32
  84. package/template/.cowork-flow/spec/runtime/index.md +7 -6
  85. package/template/.cowork-flow/spec/schemas/index.md +1 -3
  86. package/template/.opencode/agents/cowork-check.md +13 -43
  87. package/template/.opencode/agents/cowork-implement.md +14 -207
  88. package/template/.opencode/agents/cowork-research.md +8 -25
  89. package/template/.zcode/.zcode-plugin/plugin.json +1 -1
  90. package/template/.zcode/hooks/inject-context.js +9 -7
  91. package/template/.zcode/hooks/inject-context.selfcheck.mjs +49 -10
  92. package/template/.zcode/scaffold/AGENTS.md +19 -10
  93. package/template/AGENTS.md +3 -3
  94. package/template/skills/adversarial-review/SKILL.md +35 -0
  95. package/template/skills/adversarial-review/manifest.json +18 -0
  96. package/template/skills/agent-dispatch/SKILL.md +37 -0
  97. package/template/skills/{batch-mode → batch-execution}/SKILL.md +19 -24
  98. package/template/skills/batch-execution/manifest.json +20 -0
  99. package/template/skills/batch-execution/scripts/batch_action.py +48 -0
  100. package/template/{.cowork-flow/scripts/application → skills/batch-execution/scripts}/batch_execution.py +3 -3
  101. package/template/skills/brainstorming/SKILL.md +3 -3
  102. package/template/skills/brainstorming/manifest.json +12 -0
  103. package/template/skills/cowork-flow/SKILL.md +10 -7
  104. package/template/skills/cowork-flow/manifest.json +43 -0
  105. package/template/skills/{meta → cowork-flow-maintenance}/SKILL.md +3 -3
  106. package/template/skills/cowork-flow-maintenance/manifest.json +12 -0
  107. package/template/skills/decision-audit/SKILL.md +23 -0
  108. package/template/skills/decision-audit/manifest.json +11 -0
  109. package/template/skills/{break-loop → failure-analysis}/SKILL.md +4 -4
  110. package/template/skills/failure-analysis/manifest.json +18 -0
  111. package/template/skills/game-design/manifest.json +11 -0
  112. package/template/skills/party-mode/SKILL.md +3 -2
  113. package/template/skills/party-mode/manifest.json +13 -0
  114. package/template/{.cowork-flow/scripts/commands → skills/party-mode/scripts}/party_mode_v2.py +13 -6
  115. package/template/skills/{python-design → python-runtime-design}/SKILL.md +2 -2
  116. package/template/skills/python-runtime-design/manifest.json +12 -0
  117. package/template/skills/runtime-health/SKILL.md +27 -0
  118. package/template/skills/runtime-health/manifest.json +11 -0
  119. package/template/skills/runtime-health/scripts/doctor.py +195 -0
  120. package/template/{.cowork-flow/spec/protocols/spec-maintenance.md → skills/spec-sync/SKILL.md} +14 -5
  121. package/template/skills/spec-sync/manifest.json +11 -0
  122. package/template/skills/{writing-plans → task-planning}/SKILL.md +6 -6
  123. package/template/skills/task-planning/manifest.json +12 -0
  124. package/template/skills/task-review/SKILL.md +63 -0
  125. package/template/skills/task-review/manifest.json +34 -0
  126. package/template/skills/task-review/scripts/review_check.py +357 -0
  127. package/template/skills/test-first/SKILL.md +37 -0
  128. package/template/skills/test-first/manifest.json +12 -0
  129. package/src/lib/skill-registry.js +0 -503
  130. package/template/.cowork-flow/scripts/application/__init__.py +0 -1
  131. package/template/.cowork-flow/scripts/commands/_bootstrap.py +0 -10
  132. package/template/.cowork-flow/scripts/commands/doctor.py +0 -455
  133. package/template/.cowork-flow/scripts/commands/task_navigation.py +0 -471
  134. package/template/.cowork-flow/scripts/commands/task_parser.py +0 -365
  135. package/template/.cowork-flow/scripts/common/__init__.py +0 -79
  136. package/template/.cowork-flow/scripts/common/core/__init__.py +0 -1
  137. package/template/.cowork-flow/scripts/common/core/skill_registry.py +0 -568
  138. package/template/.cowork-flow/scripts/common/gates/__init__.py +0 -1
  139. package/template/.cowork-flow/scripts/common/gates/anti_rationalization.py +0 -55
  140. package/template/.cowork-flow/scripts/common/gates/coding_standards.py +0 -261
  141. package/template/.cowork-flow/scripts/common/gates/gates.py +0 -407
  142. package/template/.cowork-flow/scripts/common/gates/models.py +0 -196
  143. package/template/.cowork-flow/scripts/common/gates/quality_review.py +0 -332
  144. package/template/.cowork-flow/scripts/common/gates/registry.py +0 -79
  145. package/template/.cowork-flow/scripts/common/gates/tdd_evidence.py +0 -538
  146. package/template/.cowork-flow/scripts/common/gates/validate_coding_standards.py +0 -392
  147. package/template/.cowork-flow/scripts/common/gates/validate_implementation.py +0 -312
  148. package/template/.cowork-flow/scripts/common/gates/validate_rules.py +0 -645
  149. package/template/.cowork-flow/scripts/common/task/__init__.py +0 -1
  150. package/template/.cowork-flow/scripts/common/task/batch_mode.py +0 -58
  151. package/template/.cowork-flow/scripts/common/task/decision_review.py +0 -85
  152. package/template/.cowork-flow/spec/protocols/decision-review.md +0 -55
  153. package/template/.cowork-flow/spec/protocols/review.md +0 -53
  154. package/template/.cowork-flow/spec/protocols/tdd.md +0 -43
  155. package/template/.cowork-flow/spec/runtime/rules.json +0 -176
  156. package/template/.cowork-flow/spec/runtime/skill-registry.json +0 -448
  157. package/template/.cowork-flow/spec/schemas/rules.schema.json +0 -89
  158. package/template/.cowork-flow/spec/schemas/skill-registry.schema.json +0 -202
  159. package/template/.cowork-flow/workflow.md +0 -262
  160. package/template/.zcode/scaffold/.cowork-flow/.version +0 -1
  161. package/template/.zcode/scaffold/.cowork-flow/config.yaml +0 -65
  162. package/template/.zcode/scaffold/.cowork-flow/run +0 -98
  163. package/template/.zcode/scaffold/.cowork-flow/run.cmd +0 -111
  164. package/template/.zcode/scaffold/.cowork-flow/workflow.md +0 -262
  165. package/template/skills/doubt-review/SKILL.md +0 -125
  166. package/template/skills/tdd/SKILL.md +0 -44
  167. /package/template/.cowork-flow/scripts/{commands → adapters/cli}/__init__.py +0 -0
  168. /package/template/.cowork-flow/scripts/{common → adapters}/git/__init__.py +0 -0
  169. /package/template/.cowork-flow/scripts/{common → adapters}/host/__init__.py +0 -0
  170. /package/template/.cowork-flow/scripts/{common/task → infra}/archive_utils.py +0 -0
  171. /package/template/.cowork-flow/scripts/{common/core → infra}/files.py +0 -0
  172. /package/template/.cowork-flow/scripts/{common → infra}/storage/__init__.py +0 -0
  173. /package/template/.cowork-flow/scripts/{common → infra}/storage/state_store.py +0 -0
package/README.md CHANGED
@@ -39,10 +39,9 @@ template/
39
39
  ├── .codex/ # Codex agents / hooks / config
40
40
  ├── .claude/ # Claude Code settings / agents / hooks
41
41
  ├── .opencode/ # OpenCode agents / commands / plugins
42
- ├── .zcode/ # ⭐ ZCode 插件(hooks + runtime + scaffold)
42
+ ├── .zcode/ # ⭐ ZCode 插件(hooks + skills + scaffold instructions)
43
43
  └── .cowork-flow/
44
44
  ├── config.yaml # 项目配置
45
- ├── workflow.md # 主流程定义
46
45
  ├── scripts/ # Python 运行时
47
46
  ├── spec/ # 规范文档(contracts / schemas / guides)
48
47
  ├── changes/ # 行为变更管理
@@ -58,17 +57,19 @@ template/
58
57
  - **Host Asset Manifest**:`spec/runtime/host-assets.json` 是宿主资产、平台识别、同步策略和 obsolete 迁移清单的权威来源。新增平台或资产时更新 Manifest 与 schema,不在 CLI 中新增硬编码集合。
59
58
  - **事务式 init/sync**:CLI 先构建不可变 Asset Plan,在同文件系统 staging 中校验 hash/权限,再按备份清单提交;失败时逆序回滚,`.cowork-flow/.version` 最后更新。
60
59
  - **共享 Hook 核心**:Codex 与 Claude Code Hook 只做宿主输入适配,工作流状态解析由 `scripts/common/host/workflow_state_hook.py` 统一实现。
60
+ - **流程内核**:公开任务入口只有 `task next`;阶段动作由内核动作表推荐对应 Skill,硬门禁由 runtime gate 执行,不再分发独立流程中枢文件或 Skill 注册控制面。
61
+ - **Skill 自带脚本**:只服务单个 Skill 的控制器或辅助脚本放在 `template/skills/<skill-id>/scripts/`,由 `.cowork-flow/run` 薄分发;`scripts/` 内核只保留任务导航、生命周期、gate、host/runtime、存储和分发所需代码。
61
62
 
62
63
  ## Skills 分发机制
63
64
 
64
- Skills 维护在 `template/skills/` 唯一源码,`init` 时按平台分发到对应目录:
65
+ Skills 维护在 `template/skills/` 唯一源码,`init` / `sync` 时按目录分发到对应平台;`SKILL.md`、可选的 command `manifest.json` 和 `scripts/` 一起归属该 Skill:
65
66
 
66
67
  | 平台 | 目标目录 |
67
68
  |---|---|
68
69
  | `codex` / `opencode` | `.agents/skills/` |
69
70
  | `claude-code` | `.claude/skills/` |
70
71
 
71
- 分发动作:`batch-mode`、`brainstorming`、`break-loop`、`cowork-flow`、`doubt-review`、`game-design`、`party-mode`、`tdd`、`writing-plans`
72
+ 分发动作:`adversarial-review`、`agent-dispatch`、`batch-execution`、`brainstorming`、`cowork-flow`、`cowork-flow-maintenance`、`decision-audit`、`failure-analysis`、`game-design`、`party-mode`、`python-runtime-design`、`runtime-health`、`spec-sync`、`task-planning`、`task-review`、`test-first`
72
73
 
73
74
  ## CLI 命令
74
75
 
@@ -92,7 +93,7 @@ Skills 维护在 `template/skills/` 唯一源码,`init` 时按平台分发到
92
93
 
93
94
  - **自动识别**已安装 host 目录,只同步对应平台资产
94
95
  - **Skills** 从 `template/skills/` 按平台分发
95
- - **保护文件**:`config.yaml`、`workflow.md`、`spec/`(除 `workflow-state-templates.md`)、任务、计划、变更、workspace
96
+ - **保护文件**:`config.yaml`、`spec/`(除 `workflow-state-templates.md`)、任务、计划、变更、workspace
96
97
  - **正式版旧资产清理**:旧脚本位置、旧 adapter 资产和已废弃文件按 Host Asset Manifest 的 `obsoleteFiles` 清理;用户保护文件保持不变
97
98
  - **事务恢复**:上次未完成事务会在新一轮 sync 前恢复;事务元数据缺失或损坏时 fail-closed,不在未知状态上继续写入
98
99
  - `--force` 整文件覆盖保护文件
@@ -106,6 +107,8 @@ cowork-flow install-zcode-plugin --force # 覆盖已安装
106
107
 
107
108
  安装到 `~/.zcode/cli/plugins/cache/zcode-plugins-official/cowork-flow/<version>/`
108
109
 
110
+ ZCode 插件只安装 hook、skills 和轻量说明文件;`.cowork-flow/` 流程文件仍由显式 `cowork-flow init` / `cowork-flow sync` 在项目根目录管理。插件不会通过 scaffold 创建 `.cowork-flow/`,因此不会在多模块项目的模块目录重复落盘流程文件。
111
+
109
112
  **Hook 注入内容:**
110
113
  - `workflow-state` — 当前任务状态
111
114
  - `contract-digest` — 合同摘要(SHA256 fingerprint)
@@ -117,19 +120,17 @@ cowork-flow install-zcode-plugin --force # 覆盖已安装
117
120
  changes → brainstorming → read spec → plan → tasks → implement → check → complete
118
121
  ```
119
122
 
120
- | 阶段 | 命令 | status |
123
+ `./.cowork-flow/run task next` 是唯一公开任务流程入口。它读取当前状态,输出下一步 action、激活 Skill、runtime gate、blocker,以及可执行时的 `task next --run` 命令。
124
+
125
+ | action | 入口 | status 结果 |
121
126
  |---|---|---|
122
- | 创建/计划 | `task create` | `planning` |
123
- | 开始执行 | `task start <dir>` | `in_progress` |
124
- | 进入检查 | `task review [dir]` | `review` |
125
- | 检查完成 | `task complete [dir]` | `completed` |
126
- | 归档 | `task archive <name>` | `completed`(归档副本) |
127
- | 清会话指针 | `task finish` | 不变 |
128
-
129
- > Batch 使用任务图和持久化 Host action:运行
130
- > `task start <parent-task> --auto --approved` 获取 `next_action`,
131
- > Host 完成真实生命周期动作后用 `task batch-record-result <batch-id> --file <result.json>`
132
- > 回写结果;失败会暂停,可用 `task batch-resume <batch-id>` 生成新的重试动作。
127
+ | `create_task` | `task next --run --title "<title>" --slug <name> --assignee <name>` | `planning` |
128
+ | `start_task` | `task next <dir> --run` | `in_progress` |
129
+ | `request_review` | `task next <dir> --run --intent review` | `review` |
130
+ | `complete_task` | `task next <dir> --run --intent review` | `completed` |
131
+ | `archive_task` | `task next <dir> --run --intent archive` | 归档副本保持 `completed` |
132
+
133
+ Batch 使用任务图和持久化 Host action:运行 `task next <parent-task> --run --intent batch --auto --approved` 获取 `next_action`;Host 完成真实生命周期动作后继续通过 `task next` 导航,不暴露独立 batch 子命令。
133
134
 
134
135
  ## 常用命令
135
136
 
@@ -140,16 +141,20 @@ changes → brainstorming → read spec → plan → tasks → implement → che
140
141
 
141
142
  # 上下文
142
143
  ./.cowork-flow/run get-context
143
- ./.cowork-flow/run task list
144
144
  ./.cowork-flow/run task next
145
+ ./.cowork-flow/run task next --json
146
+ ./.cowork-flow/run task next --list
147
+ ./.cowork-flow/run task next <dir> --validate
145
148
 
146
149
  # 变更
147
150
  ./.cowork-flow/run change create <slug>
148
151
  ./.cowork-flow/run change validate <slug>
149
152
 
150
153
  # 任务
151
- ./.cowork-flow/run task create "<title>" --slug <name>
152
- ./.cowork-flow/run task start <dir>
154
+ ./.cowork-flow/run task next --run --title "<title>" --slug <name> --assignee <name>
155
+ ./.cowork-flow/run task next <dir> --run
156
+ ./.cowork-flow/run task next <dir> --run --intent review
157
+ ./.cowork-flow/run task next <dir> --run --intent archive
153
158
 
154
159
  # 子代理
155
160
  ./.cowork-flow/run subagent init --role implement --agent-type cowork-implement --execution-task-dir <dir> --title "<title>"
@@ -170,14 +175,25 @@ runtime 发出的 host-neutral action、记录执行结果并纠偏漂移。
170
175
 
171
176
  ## 发布
172
177
 
178
+ 测试按反馈速度和覆盖范围分层:
179
+
180
+ ```bash
181
+ npm run test:fast # 快速 Node 测试,等价于 npm test
182
+ npm run test:integration # init/sync 关键集成路径
183
+ npm run test:node:full # 完整 Node 测试
184
+ npm run test:template # 核心模板集成测试
185
+ npm run test:template:full # 完整模板 Python discovery
186
+ npm run test:all # 发布前全量测试与打包检查
187
+ ```
188
+
173
189
  ```bash
174
190
  npm run release # patch
175
191
  npm run release -- minor # minor
176
192
  ```
177
193
 
178
194
  **发布流程:**
179
- 1. `npm test`、`npm run test:template`、`npm run pack:check`、`git diff --check`
180
- 2. 稳定性变更使用 `COWORK_TEMPLATE_TEST_REPEAT=3` 和固定 `COWORK_TEMPLATE_TEST_SEED` 重复运行模板测试
195
+ 1. `npm run test:all`、`git diff --check`
196
+ 2. 稳定性变更使用 `COWORK_TEMPLATE_TEST_REPEAT=3` 和固定 `COWORK_TEMPLATE_TEST_SEED` 重复运行 `npm run test:template:full`
181
197
  3. `npm version` 升级版本
182
198
  4. 同步版本到 `template/.cowork-flow/.version` 和 `template/.zcode/.zcode-plugin/plugin.json`
183
199
  5. `git commit` + `git tag`
@@ -191,5 +207,5 @@ Windows 上发布前使用 `run.cmd` 入口验证;POSIX shell 专属 release
191
207
 
192
208
  - 以目标项目事实为准,不把模板内容当成项目事实
193
209
  - 保留有价值的流程骨架,删除不存在的场景
194
- - 项目差异写入 `AGENTS.md`、`workflow.md`、`config.yaml`、`spec/`
210
+ - 项目差异写入 `AGENTS.md`、`config.yaml`、`spec/` 或项目自有 Skill;不要恢复第二套流程中枢文档
195
211
  - 不为了替换项目命令而改写通用 skill
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cowork-flow",
3
- "version": "0.0.43",
3
+ "version": "0.0.45",
4
4
  "description": "CLI for installing and maintaining cowork-flow collaboration templates.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,10 +16,14 @@
16
16
  "!template/**/*.pyc"
17
17
  ],
18
18
  "scripts": {
19
- "test": "node --test",
20
- "test:template": "node scripts/run-template-tests.js",
19
+ "test": "npm run test:fast",
20
+ "test:fast": "node --test test/asset-plan.test.js test/cli.test.js test/host-assets.test.js test/opencode-plugin.test.js test/template-runner.test.js test/update.test.js test/zcode-plugin.test.js",
21
+ "test:integration": "node --test --test-name-pattern=\"^(init copies the template into a new target directory|sync updates safe template files and preserves protected files)$\" test/init.test.js test/sync.test.js",
22
+ "test:node:full": "node --test",
23
+ "test:template": "node scripts/run-template-tests.js --suite core",
24
+ "test:template:full": "node scripts/run-template-tests.js --suite full",
21
25
  "pack:check": "node scripts/pack-check.js",
22
- "test:all": "npm test && npm run test:template && npm run pack:check",
26
+ "test:all": "npm run test:node:full && npm run test:template:full && npm run pack:check",
23
27
  "release": "sh scripts/release.sh"
24
28
  },
25
29
  "engines": {
@@ -72,7 +72,6 @@ export async function runInstallZCodePlugin(args = []) {
72
72
  const { dryRun, force } = parseArgs(args);
73
73
  const pluginSrc = join(templateRoot, ".zcode");
74
74
  const skillsSrc = join(templateRoot, "skills");
75
- const specSrc = join(templateRoot, ".cowork-flow", "spec");
76
75
  const { version } = await readPackageInfo();
77
76
 
78
77
  if (!(await pathExists(pluginSrc))) {
@@ -81,9 +80,6 @@ export async function runInstallZCodePlugin(args = []) {
81
80
  if (!(await pathExists(skillsSrc))) {
82
81
  throw new Error(`Skills source missing at ${skillsSrc}. Reinstall cowork-flow.`);
83
82
  }
84
- if (!(await pathExists(specSrc))) {
85
- throw new Error(`Spec source missing at ${specSrc}. Reinstall cowork-flow.`);
86
- }
87
83
 
88
84
  const cacheRoot = await getZCodeCacheDir();
89
85
  const destDir = join(cacheRoot, version);
@@ -98,7 +94,6 @@ export async function runInstallZCodePlugin(args = []) {
98
94
  console.log(`[dry-run] Would install ZCode plugin:`);
99
95
  console.log(` Plugin: ${pluginSrc} -> ${destDir}`);
100
96
  console.log(` Skills: ${skillsSrc} -> ${join(destDir, 'skills')}`);
101
- console.log(` Spec: ${specSrc} -> ${join(destDir, 'scaffold', '.cowork-flow', 'spec')}`);
102
97
  return;
103
98
  }
104
99
 
@@ -110,16 +105,9 @@ export async function runInstallZCodePlugin(args = []) {
110
105
  // Copy plugin runtime (.zcode-plugin/, hooks/, runtime/, scaffold/) from .zcode/
111
106
  await cp(pluginSrc, destDir, { recursive: true });
112
107
 
113
- // Sync package.json version to scaffold/.version so the plugin-only launcher
114
- // can resolve the correct versioned plugin cache path at runtime.
115
- const scaffoldVersionPath = join(destDir, "scaffold", ".cowork-flow", ".version");
116
- await writeFile(scaffoldVersionPath, `${version}\n`, "utf8");
117
-
118
- // Materialize scaffold specs from the main template instead of maintaining
119
- // a second static copy under template/.zcode/scaffold/.
120
- const scaffoldSpecDest = join(destDir, "scaffold", ".cowork-flow", "spec");
121
- await rm(scaffoldSpecDest, { recursive: true, force: true });
122
- await cp(specSrc, scaffoldSpecDest, { recursive: true, force: true });
108
+ // ZCode may apply plugin scaffold files to each workspace folder. Keep
109
+ // workflow runtime files out of scaffold; explicit init/sync owns .cowork-flow.
110
+ await rm(join(destDir, "scaffold", ".cowork-flow"), { recursive: true, force: true });
123
111
 
124
112
  // Sync canonical scripts from main template (single source of truth).
125
113
  // The .zcode/hooks/runtime/scripts/ copy is stale; overwrite with the
@@ -1,5 +1,5 @@
1
1
  import { constants } from 'node:fs';
2
- import { access, readFile, readdir } from 'node:fs/promises';
2
+ import { access, readFile, readdir, stat } from 'node:fs/promises';
3
3
  import { join, relative } from 'node:path';
4
4
 
5
5
  import { createAssetPlan, planActions } from './asset-plan.js';
@@ -7,7 +7,6 @@ import { hostRegistry } from './host-assets.js';
7
7
  import { applyAssetPlan } from './plan-applier.js';
8
8
  import { templateRoot } from './paths.js';
9
9
  import { shouldIncludeForPlatforms, skillDestinationForPlatform } from './platforms.js';
10
- import { skillRegistry } from './skill-registry.js';
11
10
 
12
11
  async function pathExists(path) {
13
12
  try {
@@ -41,6 +40,83 @@ function toTemplatePath(relativePath) {
41
40
  return relativePath.replaceAll('\\', '/');
42
41
  }
43
42
 
43
+ async function listSkillDirs() {
44
+ const skillsRoot = join(templateRoot, 'skills');
45
+ const entries = await readdir(skillsRoot, { withFileTypes: true });
46
+ const skills = [];
47
+ for (const entry of entries) {
48
+ if (!entry.isDirectory()) {
49
+ continue;
50
+ }
51
+ const skillRoot = join(skillsRoot, entry.name);
52
+ if (await pathExists(join(skillRoot, 'SKILL.md'))) {
53
+ skills.push({ id: entry.name, sourceRoot: skillRoot });
54
+ }
55
+ }
56
+ return skills.sort((left, right) => left.id.localeCompare(right.id));
57
+ }
58
+
59
+ async function listSkillFiles(skill) {
60
+ const sourceRoot = skill.sourceRoot;
61
+ return (await listFiles(sourceRoot)).map((file) => ({
62
+ source: join(sourceRoot, file),
63
+ skillRelativePath: file
64
+ }));
65
+ }
66
+
67
+ async function sourceMatchesDestination(source, destination) {
68
+ try {
69
+ const [sourceContent, targetContent, sourceStats, targetStats] = await Promise.all([
70
+ readFile(source),
71
+ readFile(destination),
72
+ stat(source),
73
+ stat(destination)
74
+ ]);
75
+ return sourceContent.equals(targetContent)
76
+ && (sourceStats.mode & 0o777) === (targetStats.mode & 0o777);
77
+ } catch (error) {
78
+ if (error && error.code === 'ENOENT') {
79
+ return false;
80
+ }
81
+ throw error;
82
+ }
83
+ }
84
+
85
+ async function appendSkillFileActions(actions, {
86
+ targetDir,
87
+ platforms,
88
+ seen,
89
+ sync = false
90
+ }) {
91
+ for (const skill of await listSkillDirs()) {
92
+ const skillFiles = await listSkillFiles(skill);
93
+ for (const platform of platforms) {
94
+ const destBase = skillDestinationForPlatform(platform);
95
+ if (!destBase) continue;
96
+ for (const skillFile of skillFiles) {
97
+ const destination = join(
98
+ targetDir,
99
+ destBase,
100
+ skill.id,
101
+ skillFile.skillRelativePath
102
+ );
103
+ if (seen.has(destination)) continue;
104
+ seen.add(destination);
105
+ const exists = await pathExists(destination);
106
+ const unchanged = sync && exists
107
+ ? await sourceMatchesDestination(skillFile.source, destination)
108
+ : false;
109
+ actions.push({
110
+ action: exists ? (sync ? (unchanged ? 'skip' : 'update') : 'skip') : 'create',
111
+ source: skillFile.source,
112
+ destination,
113
+ relativePath: join(destBase, skill.id, skillFile.skillRelativePath)
114
+ });
115
+ }
116
+ }
117
+ }
118
+ }
119
+
44
120
  export async function buildInitPlan(targetDir, options = {}) {
45
121
  const files = await listFiles(templateRoot);
46
122
  const actions = [];
@@ -67,21 +143,7 @@ export async function buildInitPlan(targetDir, options = {}) {
67
143
  actions.push({ action, source, destination, relativePath: file });
68
144
  }
69
145
 
70
- for (const entry of skillRegistry.publicEntries) {
71
- for (const platform of platforms) {
72
- const destBase = skillDestinationForPlatform(platform);
73
- if (!destBase) continue;
74
- const dest = join(targetDir, destBase, entry.id, 'SKILL.md');
75
- if (seen.has(dest)) continue;
76
- seen.add(dest);
77
- actions.push({
78
- action: (await pathExists(dest)) ? 'skip' : 'create',
79
- source: join(templateRoot, entry.source),
80
- destination: dest,
81
- relativePath: join(destBase, entry.id, 'SKILL.md')
82
- });
83
- }
84
- }
146
+ await appendSkillFileActions(actions, { targetDir, platforms, seen });
85
147
 
86
148
  const versionDestination = join(targetDir, '.cowork-flow', '.version');
87
149
  const versionExists = await pathExists(versionDestination);
@@ -144,6 +206,10 @@ function isSafeSyncFile(relativePath) {
144
206
  || templatePath.endsWith('/.gitkeep');
145
207
  }
146
208
 
209
+ function isCoveredByDeletedParent(relativePath, deletedParents) {
210
+ return deletedParents.some((parent) => relativePath.startsWith(`${parent}/`));
211
+ }
212
+
147
213
  function replaceManagedBlock(targetContent, templateContent) {
148
214
  const targetStart = targetContent.indexOf(COWORK_FLOW_START);
149
215
  const targetEnd = targetContent.indexOf(COWORK_FLOW_END, targetStart + COWORK_FLOW_START.length);
@@ -183,9 +249,22 @@ async function buildManagedBlockSyncAction({ source, destination, exists, option
183
249
  return { action: 'protected', source, destination, relativePath };
184
250
  }
185
251
 
252
+ if (content === targetContent) {
253
+ return { action: 'skip', source, destination, relativePath };
254
+ }
255
+
186
256
  return { action: 'update', source, destination, relativePath, content };
187
257
  }
188
258
 
259
+ async function buildFileSyncAction({ source, destination, relativePath }) {
260
+ return {
261
+ action: await sourceMatchesDestination(source, destination) ? 'skip' : 'update',
262
+ source,
263
+ destination,
264
+ relativePath
265
+ };
266
+ }
267
+
189
268
  export async function buildSyncPlan(targetDir, options = {}) {
190
269
  if (!await pathExists(join(targetDir, '.cowork-flow'))) {
191
270
  throw new Error(`Target is not initialized: ${targetDir}`);
@@ -221,7 +300,11 @@ export async function buildSyncPlan(targetDir, options = {}) {
221
300
  if (protectedFile) {
222
301
  actions.push({ action: 'protected', source, destination, relativePath: file });
223
302
  } else if (exists && (safeFile || options.force)) {
224
- actions.push({ action: 'update', source, destination, relativePath: file });
303
+ actions.push(await buildFileSyncAction({
304
+ source,
305
+ destination,
306
+ relativePath: file
307
+ }));
225
308
  } else if (!exists) {
226
309
  actions.push({ action: 'create', source, destination, relativePath: file });
227
310
  } else {
@@ -229,66 +312,36 @@ export async function buildSyncPlan(targetDir, options = {}) {
229
312
  }
230
313
  }
231
314
 
232
- for (const entry of skillRegistry.publicEntries) {
233
- for (const platform of platforms) {
234
- const destBase = skillDestinationForPlatform(platform);
235
- if (!destBase) continue;
236
- const dest = join(targetDir, destBase, entry.id, 'SKILL.md');
237
- if (seen.has(dest)) continue;
238
- seen.add(dest);
239
- const destExists = await pathExists(dest);
240
- const safe = hostRegistry.skillTargets.some(
241
- (target) => dest.startsWith(join(targetDir, target))
242
- );
243
- if (destExists && (safe || options.force)) {
244
- actions.push({
245
- action: 'update',
246
- source: join(templateRoot, entry.source),
247
- destination: dest,
248
- relativePath: join(destBase, entry.id, 'SKILL.md')
249
- });
250
- } else if (!destExists) {
251
- actions.push({
252
- action: 'create',
253
- source: join(templateRoot, entry.source),
254
- destination: dest,
255
- relativePath: join(destBase, entry.id, 'SKILL.md')
256
- });
257
- }
258
- }
259
- }
315
+ await appendSkillFileActions(actions, { targetDir, platforms, seen, sync: true });
260
316
 
261
- for (const entry of skillRegistry.entries) {
262
- if (entry.status === 'active') {
263
- continue;
317
+ const deletedObsoleteParents = [];
318
+ const obsoleteFiles = [...OBSOLETE_SYNC_FILES].sort((left, right) => {
319
+ if (left.length !== right.length) {
320
+ return left.length - right.length;
264
321
  }
265
- for (const managedPath of entry.managedPaths) {
266
- const relativePath = managedPath.slice(0, -1);
267
- const destination = join(targetDir, relativePath);
268
- if (await pathExists(destination)) {
269
- actions.push({
270
- action: 'delete',
271
- source: null,
272
- destination,
273
- relativePath
274
- });
275
- }
322
+ return left.localeCompare(right);
323
+ });
324
+ for (const file of obsoleteFiles) {
325
+ if (isCoveredByDeletedParent(file, deletedObsoleteParents)) {
326
+ continue;
276
327
  }
277
- }
278
-
279
- for (const file of OBSOLETE_SYNC_FILES) {
280
328
  const destination = join(targetDir, file);
281
329
  if (await pathExists(destination)) {
330
+ deletedObsoleteParents.push(file);
282
331
  actions.push({ action: 'delete', source: null, destination, relativePath: file });
283
332
  }
284
333
  }
285
334
 
335
+ const versionDestination = join(targetDir, '.cowork-flow', '.version');
336
+ const versionContent = `${options.version}\n`;
337
+ const versionUnchanged = await pathExists(versionDestination)
338
+ && (await readFile(versionDestination, 'utf8')) === versionContent;
286
339
  actions.push({
287
- action: 'update',
340
+ action: versionUnchanged ? 'skip' : 'update',
288
341
  source: null,
289
- destination: join(targetDir, '.cowork-flow', '.version'),
342
+ destination: versionDestination,
290
343
  relativePath: '.cowork-flow/.version',
291
- content: `${options.version}\n`
344
+ content: versionContent
292
345
  });
293
346
 
294
347
  return createAssetPlan({
@@ -6,67 +6,23 @@ tools: Read, Write, Edit, Grep, Glob, LS, Bash, Skill
6
6
 
7
7
  You are the `cowork-check` subagent.
8
8
 
9
- You are a leaf executor. Do not coordinate other agents.
9
+ Read and apply these Skills before review work:
10
10
 
11
- Formal `cowork-check` work requires runtime-context dispatch. The prompt or
12
- host metadata must provide:
11
+ - `.claude/skills/agent-dispatch/SKILL.md`
12
+ - `.claude/skills/task-review/SKILL.md`
13
+ - `.claude/skills/decision-audit/SKILL.md`
14
+ - `.claude/skills/spec-sync/SKILL.md`
13
15
 
14
- ```text
15
- cowork_runtime_context_id: <runtime_context_id>
16
- cowork_host_context_key: <host_context_key>
17
- ```
16
+ Execution:
18
17
 
19
- The hook may bind that id to `.cowork-flow/.runtime/subagents/<runtime_context_id>.json`
20
- before workflow state is injected. The first child step must still run:
21
-
22
- ```bash
23
- ./.cowork-flow/run subagent bind <runtime_context_id> <host_context_key>
24
- ```
25
-
26
- On Windows (cmd/PowerShell), use:
27
-
28
- ```cmd
29
- .\.cowork-flow\run.cmd subagent bind <runtime_context_id> <host_context_key>
30
- ```
31
-
32
- If the explicit bind fails, or if the bound runtime context is missing, closed,
33
- invalid, or names another agent type, report `needs_context` and do not execute
34
- the task.
35
-
36
- Load context before checking:
37
- 1. Read the task directory from the bound runtime context.
38
- 2. Read `<task>/decision-anchor.md`.
39
- 3. Read the plan file linked from this task (check `<task>/task.json` `relatedFiles` for a plan path, or search `.cowork-flow/plans/` for a plan file referencing this task directory). Use the plan's Verify commands and Expected results as the checklist for each step.
40
- 4. Read `<task>/check.jsonl`.
41
- 5. Read each JSONL `file` entry from `<task>/check.jsonl`.
42
- 6. Read `<task>/quality-review.jsonl` if present and verify machine warning,
43
- checklist, and Definition of Done evidence.
44
- 7. Read `git diff`.
45
- 8. Include `test_intent_review` in the review output for meaningful behavior
46
- breaks coverage and shallow tests rejection.
47
-
48
- Authoritative internal protocols:
49
- - `.cowork-flow/spec/protocols/review.md`
50
- - `.cowork-flow/spec/protocols/decision-review.md`
51
- - `.cowork-flow/spec/protocols/spec-maintenance.md`
52
-
53
- Apply their output contracts exactly. Review output must preserve
54
- `acceptanceId`, `findings`, `test_intent_review`, `resolution`, and
55
- `specUpdates`.
18
+ 1. Follow `agent-dispatch` to bind runtime context. If binding fails, report `needs_context` and stop.
19
+ 2. Read the task directory, `decision-anchor.md`, linked plan, the `check.jsonl` context index, every referenced `file` entry, and current `git diff`; do not write review conclusions to JSONL.
20
+ 3. Apply `task-review` to verify scope, tests, specs, advisory facts, lifecycle facts, and Definition of Done coverage.
21
+ 4. Fix only clearly in-scope issues; otherwise report findings with acceptance IDs, resolutions, `test_intent_review` (test intent review), and verification commands.
56
22
 
57
23
  Rules:
58
- - Fix issues directly when they are clearly in scope.
24
+
59
25
  - Do not use the Task tool or invoke subagents.
60
- - MUST NOT spawn, wait for, list, or close other agents.
61
- - MUST NOT commit, archive, or mutate cowork-flow task state.
62
- - Report findings, changed files, and exact verification commands.
63
- - Include test intent findings that map tests back to decision-anchor acceptance or
64
- regression behavior.
65
- - Run the deterministic coding gate before accepting quality:
66
- `./.cowork-flow/run python .cowork-flow/scripts/common/gates/validate_coding_standards.py --validate --repo-root .`.
67
- This gate enforces machine-decidable UTF-8/IO checks; backend/frontend
68
- natural-language markdown remains checklist context, not dynamic hard validators.
69
- - Treat machine warning output as review evidence: fix real issues or require
70
- acknowledged warning records in `<task>/quality-review.jsonl`.
71
- - Verify `<task>/quality-review.jsonl` covers Definition of Done, checklist
72
- sources, affected files, and exact verification commands before acceptance.
26
+ - Do not run task start, finish, archive, unscoped resume, commit, or push.
27
+ - Treat backend/frontend natural-language specs as checklist context, not dynamic hard validators.
28
+ - Do not accept shallow tests that would still pass when target behavior breaks.
@@ -6,70 +6,24 @@ tools: Read, Write, Edit, Grep, Glob, LS, Bash, Skill
6
6
 
7
7
  You are the `cowork-implement` subagent.
8
8
 
9
- You are a leaf executor. Do not coordinate other agents.
9
+ Read and apply these Skills before task work:
10
10
 
11
- Formal `cowork-implement` work requires runtime-context dispatch. The prompt or
12
- host metadata must provide:
11
+ - `.claude/skills/agent-dispatch/SKILL.md`
12
+ - `.claude/skills/decision-audit/SKILL.md`
13
+ - `.claude/skills/spec-sync/SKILL.md`
14
+ - `.claude/skills/test-first/SKILL.md` for behavior changes
13
15
 
14
- ```text
15
- cowork_runtime_context_id: <runtime_context_id>
16
- cowork_host_context_key: <host_context_key>
17
- ```
16
+ Execution:
18
17
 
19
- The hook may bind that id to `.cowork-flow/.runtime/subagents/<runtime_context_id>.json`
20
- before workflow state is injected. The first child step must still run:
21
-
22
- ```bash
23
- ./.cowork-flow/run subagent bind <runtime_context_id> <host_context_key>
24
- ```
25
-
26
- On Windows (cmd/PowerShell), use:
27
-
28
- ```cmd
29
- .\.cowork-flow\run.cmd subagent bind <runtime_context_id> <host_context_key>
30
- ```
31
-
32
- If the explicit bind fails, or if the bound runtime context is missing, closed,
33
- invalid, or names another agent type, report `needs_context` and do not execute
34
- the task.
35
-
36
- Load context before editing:
37
- 1. Read the task directory from the bound runtime context.
38
- 2. Read `<task>/decision-anchor.md`.
39
- 3. Read `<task>/info.md` if present.
40
- 4. Read `<task>/implement.jsonl`.
41
- 5. Read each JSONL `file` entry.
42
- 6. Read the plan file linked from this task (check `<task>/task.json` `relatedFiles` for a plan path, or search `.cowork-flow/plans/` for a plan file referencing this task directory). Follow the plan steps in order — each step has Files, Action, Verify, and Expected fields.
43
- 7. Read quality source entries from context; backend/frontend natural-language
44
- specs are review checklists, not dynamic hard validators.
45
- 8. For behavior-change tasks, write the failing test before implementation and record any red/green evidence in `<task>/check.jsonl`, or record a documented exemption there.
46
- 9. Before reporting completion, write `<task>/quality-review.jsonl` with
47
- checklist, machine warning, and Definition of Done evidence.
48
-
49
- Authoritative internal protocols:
50
- - `.cowork-flow/spec/protocols/tdd.md`
51
- - `.cowork-flow/spec/protocols/decision-review.md`
52
- - `.cowork-flow/spec/protocols/spec-maintenance.md`
53
-
54
- Apply their output contracts exactly. Implementation reports and TDD entries in `check.jsonl`
55
- must preserve `acceptanceId`, `redCommand`, `redExitCode`, `greenCommand`,
56
- `greenExitCode`, and `specUpdates`.
18
+ 1. Follow `agent-dispatch` to bind runtime context. If binding fails, report `needs_context` and stop.
19
+ 2. Read the task directory, `decision-anchor.md`, optional `info.md`, `implement.jsonl`, every JSONL `file` entry, and the linked plan.
20
+ 3. Follow the plan in order, keeping edits inside assigned scope.
21
+ 4. Use project specs and quality sources as checklist context; runtime gates remain kernel-owned commands.
22
+ 5. Run planned verification and report changed files, acceptance IDs, verification commands, and spec updates or why none were needed.
57
23
 
58
24
  Rules:
25
+
59
26
  - Do not use the Task tool or invoke subagents.
60
- - MUST NOT spawn, wait for, list, or close other agents.
61
- - MUST NOT run task start, task finish, task archive, or unscoped resume.
62
- - MUST NOT commit or push.
63
- - Keep edits inside requested scope.
64
- - Do not treat shallow tests as TDD evidence; red-green-refactor proof must
65
- include redCommand, redExitCode, greenCommand, greenExitCode, and
66
- decision-anchor acceptance ID mapping.
67
- - Report changed files and exact verification commands.
68
- - Before editing source files, run the deterministic coding gate:
69
- `./.cowork-flow/run python .cowork-flow/scripts/common/gates/validate_coding_standards.py --validate --repo-root .`.
70
- This gate enforces machine-decidable UTF-8/IO checks; backend/frontend
71
- natural-language markdown remains checklist context, not dynamic hard validators.
72
- - Fix machine warning findings or record acknowledged warning evidence in
73
- `<task>/quality-review.jsonl`.
74
- - Record Definition of Done and quality checklist evidence in
75
- `<task>/quality-review.jsonl`.
27
+ - Do not run task start, finish, archive, unscoped resume, commit, or push.
28
+ - Do not create task-local review artifacts, `tdd.jsonl`, or TDD evidence records in `check.jsonl`.
29
+ - Do not claim completion without current verification.