cowork-flow 1.6.0 → 1.7.2
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/CHANGELOG.md +213 -213
- package/CONTRIBUTING.md +137 -0
- package/LICENSE +1 -1
- package/README.md +108 -369
- package/docs/architecture.md +122 -0
- package/docs/hosts.md +290 -0
- package/docs/index.md +32 -0
- package/docs/release.md +104 -0
- package/package.json +37 -7
- package/presets/claude-code/.claude-plugin/plugin.json +28 -0
- package/presets/claude-code/skills/cowork-flow-bootstrap/SKILL.md +35 -0
- package/presets/codex/.codex-plugin/plugin.json +37 -0
- package/presets/codex/assets/logo.svg +4 -0
- package/presets/codex/skills/cowork-flow-bootstrap/SKILL.md +35 -0
- package/presets/dsh/agent.cordis.yml +35 -12
- package/presets/dsh/plugins/workflow-state.js +88 -72
- package/presets/dsh/preset.yml +1 -1
- package/presets/kimi-code/.kimi-plugin/plugin.json +35 -0
- package/presets/kimi-code/hooks/cowork-flow-inject.mjs +14 -2
- package/presets/kimi-code/skills/cowork-flow-bootstrap/SKILL.md +35 -0
- package/presets/opencode/cowork-flow/plugin-core.js +1077 -0
- package/presets/opencode/cowork-flow/skills/cowork-flow-bootstrap/SKILL.md +35 -0
- package/presets/opencode/plugins/cowork-flow.js +44 -0
- package/presets/plugin-meta.json +52 -0
- package/presets/qoder/.qoder-plugin/plugin.json +29 -0
- package/presets/qoder/agents/cowork-check.md +29 -0
- package/presets/qoder/agents/cowork-implement.md +30 -0
- package/presets/qoder/agents/cowork-research.md +23 -0
- package/presets/qoder/hooks/hooks.json +50 -0
- package/presets/qoder/hooks/inject-context.mjs +150 -0
- package/presets/qoder/skills/cowork-flow-bootstrap/SKILL.md +35 -0
- package/{template/.zcode → presets/zcode}/.zcode-plugin/plugin.json +4 -2
- package/{template/.zcode → presets/zcode}/agents/cowork-check.md +4 -4
- package/{template/.zcode → presets/zcode}/agents/cowork-implement.md +4 -4
- package/{template/.zcode → presets/zcode}/agents/cowork-research.md +1 -1
- package/{template/.zcode → presets/zcode}/hooks/inject-context.js +36 -19
- package/presets/zcode/skills/cowork-flow-bootstrap/SKILL.md +35 -0
- package/src/cli.js +130 -130
- package/src/commands/host.js +182 -0
- package/src/commands/init.js +28 -43
- package/src/commands/install-claude-code-plugin.js +129 -0
- package/src/commands/install-codex-plugin.js +312 -0
- package/src/commands/install-dsh-hook.js +36 -43
- package/src/commands/install-dsh-preset.js +228 -49
- package/src/commands/install-kimi-code-plugin.js +142 -0
- package/src/commands/install-kimi-hook.js +142 -122
- package/src/commands/install-opencode-plugin.js +158 -0
- package/src/commands/install-qoder-plugin.js +211 -0
- package/src/commands/install-zcode-plugin.js +131 -82
- package/src/commands/mcp-state.js +7 -6
- package/src/commands/registry.js +345 -0
- package/src/commands/source-refresh.js +10 -11
- package/src/commands/sync.js +10 -13
- package/src/commands/update.js +5 -10
- package/src/lib/cli-flags.js +102 -0
- package/src/lib/copy-template.js +89 -75
- package/src/lib/host-assets.js +192 -57
- package/src/lib/install-support.js +50 -0
- package/src/lib/platforms.js +0 -15
- package/src/lib/plugin-metadata.js +187 -0
- package/src/lib/plugin-payload.js +70 -0
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/adapters/claude-code/adapter.yaml +0 -1
- package/template/.cowork-flow/adapters/dsh/adapter.yaml +0 -1
- package/template/.cowork-flow/adapters/kimi-code/adapter.yaml +0 -1
- package/template/.cowork-flow/adapters/qoder/adapter.yaml +32 -0
- package/template/.cowork-flow/adapters/zcode/adapter.yaml +2 -2
- package/template/.cowork-flow/config.yaml +6 -4
- package/template/.cowork-flow/scripts/adapters/cli/batch_mode.py +10 -12
- package/template/.cowork-flow/scripts/adapters/cli/spec_check.py +67 -35
- package/template/.cowork-flow/scripts/adapters/cli/subagent.py +84 -38
- package/template/.cowork-flow/scripts/adapters/cli/task.py +42 -0
- package/template/.cowork-flow/scripts/adapters/cli/task_create_command.py +1 -9
- package/template/.cowork-flow/scripts/adapters/cli/task_lifecycle_commands.py +6 -0
- package/template/.cowork-flow/scripts/adapters/cli/task_navigation.py +13 -10
- package/template/.cowork-flow/scripts/adapters/cli/task_next_runner.py +2 -1
- package/template/.cowork-flow/scripts/adapters/git/git_context.py +14 -82
- package/template/.cowork-flow/scripts/adapters/host/claude_code_policy.py +2 -3
- package/template/.cowork-flow/scripts/adapters/host/codex_policy.py +2 -5
- package/template/.cowork-flow/scripts/adapters/host/host_manifest.py +122 -10
- package/template/.cowork-flow/scripts/adapters/host/inject.py +49 -19
- package/template/.cowork-flow/scripts/adapters/host/kimi_code_policy.py +1 -1
- package/template/.cowork-flow/scripts/adapters/host/policy_base.py +58 -0
- package/template/.cowork-flow/scripts/adapters/host/qoder_policy.py +66 -0
- package/template/.cowork-flow/scripts/adapters/host/workflow_state_hook.py +136 -132
- package/template/.cowork-flow/scripts/adapters/host/zcode_policy.py +23 -24
- package/template/.cowork-flow/scripts/adapters/mcp/state_server.py +41 -56
- package/template/.cowork-flow/scripts/adapters/review/test_intent.py +2 -2
- package/template/.cowork-flow/scripts/infra/config.py +26 -23
- package/template/.cowork-flow/scripts/infra/developer_profile.py +4 -41
- package/template/.cowork-flow/scripts/infra/files.py +3 -7
- package/template/.cowork-flow/scripts/infra/git_snapshot.py +8 -7
- package/template/.cowork-flow/scripts/infra/paths.py +9 -69
- package/template/.cowork-flow/scripts/infra/process.py +9 -0
- package/template/.cowork-flow/scripts/infra/skill_manifest.py +262 -169
- package/template/.cowork-flow/scripts/infra/storage/operation_log.py +2 -0
- package/template/.cowork-flow/scripts/infra/storage/state_store.py +0 -2
- package/template/.cowork-flow/scripts/infra/storage/unit_of_work.py +163 -18
- package/template/.cowork-flow/scripts/kernel/workflow_route.py +6 -16
- package/template/.cowork-flow/scripts/run.py +14 -4
- package/template/.cowork-flow/scripts/runtime/host_identity.py +33 -15
- package/template/.cowork-flow/scripts/runtime/session_state.py +83 -26
- package/template/.cowork-flow/scripts/services/context_discovery.py +15 -3
- package/template/.cowork-flow/scripts/services/context_paths.py +4 -4
- package/template/.cowork-flow/scripts/services/fact_view.py +13 -10
- package/template/.cowork-flow/scripts/services/lifecycle_checks.py +47 -13
- package/template/.cowork-flow/scripts/services/lifecycle_policy.py +5 -2
- package/template/.cowork-flow/scripts/services/readiness.py +8 -3
- package/template/.cowork-flow/scripts/services/spec_check.py +23 -33
- package/template/.cowork-flow/scripts/services/task_archive.py +76 -41
- package/template/.cowork-flow/scripts/services/task_creation.py +90 -34
- package/template/.cowork-flow/scripts/services/task_lifecycle.py +210 -50
- package/template/.cowork-flow/scripts/services/task_routing.py +0 -8
- package/template/.cowork-flow/scripts/services/task_tree.py +181 -29
- package/template/.cowork-flow/scripts/services/task_utils.py +3 -20
- package/template/.cowork-flow/scripts/services/workflow_runtime.py +39 -22
- package/template/.cowork-flow/spec/contracts/context-injection.md +27 -2
- package/template/.cowork-flow/spec/contracts/fact-layer-access.md +7 -4
- package/template/.cowork-flow/spec/contracts/index.md +4 -0
- package/template/.cowork-flow/spec/contracts/spec-checks.md +13 -2
- package/template/.cowork-flow/spec/runtime/host-assets.json +155 -18
- package/template/.cowork-flow/spec/runtime/index.md +1 -1
- package/template/.cowork-flow/spec/schemas/host-assets.schema.json +69 -7
- package/template/.dsh/README.md +27 -7
- package/template/.opencode/cowork-flow/plugin-core.js +1077 -0
- package/template/.opencode/plugins/cowork-flow.js +23 -800
- package/template/skills/python-runtime-design/SKILL.md +6 -0
- package/template/skills/runtime-health/scripts/doctor.py +725 -14
- /package/{template/.zcode → presets/zcode}/hooks/hooks.json +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-flow-bootstrap
|
|
3
|
+
description: Use only when a repository has no .cowork-flow/ runtime and the user wants to start or continue structured development work — guides installing cowork-flow into the project. Do not use when .cowork-flow/ exists; the project's own cowork-flow Skill owns that case.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cowork Flow Bootstrap
|
|
7
|
+
|
|
8
|
+
This Skill is the plugin-side bootstrap. It applies to repositories that have no
|
|
9
|
+
`.cowork-flow/` runtime yet. Once `.cowork-flow/` exists, stop and use the
|
|
10
|
+
project's own Skills: after init, `./.cowork-flow/run task next` and the project's
|
|
11
|
+
skill copies are authoritative, not this Skill.
|
|
12
|
+
|
|
13
|
+
## Decide first
|
|
14
|
+
|
|
15
|
+
Check the repository root for the runtime directory `.cowork-flow/` (or the
|
|
16
|
+
workflow entry `./.cowork-flow/run`).
|
|
17
|
+
|
|
18
|
+
## No runtime: offer the install
|
|
19
|
+
|
|
20
|
+
Tell the user this repository has no cowork-flow runtime, then offer:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx cowork-flow project init .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
After init the project carries its own Skills (`.agents/skills/`), the task
|
|
27
|
+
runtime (`.cowork-flow/`), and the workflow entry `./.cowork-flow/run task next`.
|
|
28
|
+
Resume the work through that entry.
|
|
29
|
+
|
|
30
|
+
## Never
|
|
31
|
+
|
|
32
|
+
- Do not reproduce lifecycle rules, gates, or a second workflow document here.
|
|
33
|
+
- Do not hand-create `.cowork-flow/` or copy files out of the plugin payload.
|
|
34
|
+
- Do not run task lifecycle commands: without a project runtime there is no task
|
|
35
|
+
to advance.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// opencode plugin adapter for cowork-flow.
|
|
2
|
+
//
|
|
3
|
+
// opencode calls EVERY export of this module as a plugin
|
|
4
|
+
// factory and then every hook of the object it returns, so
|
|
5
|
+
// this file exports exactly one function and nothing else;
|
|
6
|
+
// the logic lives in ../cowork-flow/plugin-core.js. A
|
|
7
|
+
// re-exported helper would be called as a plugin and break
|
|
8
|
+
// host bootstrap.
|
|
9
|
+
import {
|
|
10
|
+
buildInjectedDigest,
|
|
11
|
+
buildRuntimeWorkflowState,
|
|
12
|
+
editedFilePath,
|
|
13
|
+
findRepoRoot,
|
|
14
|
+
injectShellEnv,
|
|
15
|
+
registerPayloadSkills,
|
|
16
|
+
runEditSpecCheck
|
|
17
|
+
} from "../cowork-flow/plugin-core.js"
|
|
18
|
+
|
|
19
|
+
export const CoworkFlowPlugin = async () => {
|
|
20
|
+
return {
|
|
21
|
+
// Registers the payload skills directory for the
|
|
22
|
+
// machine-level install, and is a no-op for the
|
|
23
|
+
// project install, which has no skills/ sibling.
|
|
24
|
+
"config": async (config) => {
|
|
25
|
+
registerPayloadSkills(config)
|
|
26
|
+
},
|
|
27
|
+
"shell.env": async (input, output) => {
|
|
28
|
+
injectShellEnv(input, output)
|
|
29
|
+
},
|
|
30
|
+
"experimental.chat.system.transform": async (input, output) => {
|
|
31
|
+
output.system.push([buildInjectedDigest(input), buildRuntimeWorkflowState(input)].filter(Boolean).join("\n\n"))
|
|
32
|
+
},
|
|
33
|
+
"tool.execute.after": async (input, output) => {
|
|
34
|
+
const filePath = editedFilePath(input)
|
|
35
|
+
if (!filePath) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
const warning = await runEditSpecCheck(findRepoRoot(input), filePath)
|
|
39
|
+
if (warning) {
|
|
40
|
+
output.output = [output.output, warning].filter(Boolean).join("\n")
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cowork-flow",
|
|
3
|
+
"displayName": "Cowork Flow",
|
|
4
|
+
"description": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。",
|
|
5
|
+
"longDescription": "cowork-flow 给 AI 编码宿主的 agent 提供可执行的工作流:任务生命周期、决策记录、规范契约与独立检查。安装后任务状态由运行时统一维护,多个宿主的会话从同一份事实起步。",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "fishlikewater",
|
|
8
|
+
"email": "fishlikewater@126.com",
|
|
9
|
+
"url": "https://github.com/fishlikewater"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/fishlikewater/cowork-flow",
|
|
12
|
+
"repository": "https://github.com/fishlikewater/cowork-flow",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"ai-agent",
|
|
16
|
+
"workflow",
|
|
17
|
+
"task-lifecycle",
|
|
18
|
+
"subagents",
|
|
19
|
+
"codex",
|
|
20
|
+
"claude-code",
|
|
21
|
+
"opencode",
|
|
22
|
+
"zcode",
|
|
23
|
+
"qoder",
|
|
24
|
+
"kimi-code",
|
|
25
|
+
"dsh"
|
|
26
|
+
],
|
|
27
|
+
"category": "Developer Tools",
|
|
28
|
+
"marketplaceCategory": "developer-tools",
|
|
29
|
+
"brandColor": "#2563EB",
|
|
30
|
+
"icon": {
|
|
31
|
+
"source": "assets/icon.svg",
|
|
32
|
+
"raster": "assets/icon.png"
|
|
33
|
+
},
|
|
34
|
+
"defaultBranch": "dev",
|
|
35
|
+
"hosts": {
|
|
36
|
+
"codex": {
|
|
37
|
+
"label": "Codex"
|
|
38
|
+
},
|
|
39
|
+
"zcode": {
|
|
40
|
+
"label": "ZCode"
|
|
41
|
+
},
|
|
42
|
+
"qoder": {
|
|
43
|
+
"label": "Qoder"
|
|
44
|
+
},
|
|
45
|
+
"claude-code": {
|
|
46
|
+
"label": "Claude Code"
|
|
47
|
+
},
|
|
48
|
+
"kimi-code": {
|
|
49
|
+
"label": "Kimi Code"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cowork-flow",
|
|
3
|
+
"version": "1.7.2",
|
|
4
|
+
"description": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。将 cowork-flow 的完整工作流带入 Qoder。",
|
|
5
|
+
"displayName": "Cowork Flow",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "fishlikewater",
|
|
8
|
+
"email": "fishlikewater@126.com",
|
|
9
|
+
"url": "https://github.com/fishlikewater"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/fishlikewater/cowork-flow",
|
|
12
|
+
"repository": "https://github.com/fishlikewater/cowork-flow",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"ai-agent",
|
|
16
|
+
"workflow",
|
|
17
|
+
"task-lifecycle",
|
|
18
|
+
"subagents",
|
|
19
|
+
"codex",
|
|
20
|
+
"claude-code",
|
|
21
|
+
"opencode",
|
|
22
|
+
"zcode",
|
|
23
|
+
"qoder",
|
|
24
|
+
"kimi-code",
|
|
25
|
+
"dsh"
|
|
26
|
+
],
|
|
27
|
+
"hooks": "./hooks/hooks.json",
|
|
28
|
+
"skills": "./skills/"
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-check
|
|
3
|
+
description: Cowork-flow review fixed subagent for scope, tests, specs, and lifecycle verification. Use when the main session dispatches an independent review of completed task work.
|
|
4
|
+
tools: Read, Write, Edit, Grep, Glob, Bash, Skill
|
|
5
|
+
disallowedTools: [Agent]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the `cowork-check` fixed subagent for Qoder.
|
|
9
|
+
|
|
10
|
+
Read and apply these Skills before review work:
|
|
11
|
+
|
|
12
|
+
- `.agents/skills/agent-dispatch/SKILL.md`
|
|
13
|
+
- `.agents/skills/task-review/SKILL.md`
|
|
14
|
+
- `.agents/skills/decision-audit/SKILL.md`
|
|
15
|
+
- `.agents/skills/spec-sync/SKILL.md`
|
|
16
|
+
|
|
17
|
+
Execution:
|
|
18
|
+
|
|
19
|
+
1. Follow `agent-dispatch` to bind runtime context. If binding fails, report `needs_context` and stop.
|
|
20
|
+
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.
|
|
21
|
+
3. Apply `task-review` to verify scope, tests, specs, advisory facts, lifecycle facts, and Definition of Done coverage.
|
|
22
|
+
4. Fix only clearly in-scope issues; otherwise report findings with acceptance IDs, resolutions, `test_intent_review` (test intent review), and verification commands.
|
|
23
|
+
|
|
24
|
+
Rules:
|
|
25
|
+
|
|
26
|
+
- Do not dispatch subagents; `Agent` is removed from this session's tool set.
|
|
27
|
+
- Do not run task start, finish, archive, unscoped resume, commit, or push.
|
|
28
|
+
- Treat backend/frontend natural-language specs as checklist context, not dynamic hard validators.
|
|
29
|
+
- Do not accept shallow tests that would still pass when target behavior breaks.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-implement
|
|
3
|
+
description: Cowork-flow implementation fixed subagent for bounded code changes with runtime context binding. Use when the main session dispatches bounded implementation work that must stay inside an assigned task scope.
|
|
4
|
+
tools: Read, Write, Edit, Grep, Glob, Bash, Skill
|
|
5
|
+
disallowedTools: [Agent]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the `cowork-implement` fixed subagent for Qoder.
|
|
9
|
+
|
|
10
|
+
Read and apply these Skills before task work:
|
|
11
|
+
|
|
12
|
+
- `.agents/skills/agent-dispatch/SKILL.md`
|
|
13
|
+
- `.agents/skills/decision-audit/SKILL.md`
|
|
14
|
+
- `.agents/skills/spec-sync/SKILL.md`
|
|
15
|
+
- `.agents/skills/test-first/SKILL.md` for behavior changes
|
|
16
|
+
|
|
17
|
+
Execution:
|
|
18
|
+
|
|
19
|
+
1. Follow `agent-dispatch` to bind runtime context. If binding fails, report `needs_context` and stop.
|
|
20
|
+
2. Read the task directory, `decision-anchor.md`, optional `info.md`, `implement.jsonl`, every JSONL `file` entry, and the linked plan.
|
|
21
|
+
3. Follow the plan in order, keeping edits inside assigned scope.
|
|
22
|
+
4. Use project specs and quality sources as checklist context; runtime gates remain kernel-owned commands.
|
|
23
|
+
5. Run planned verification and report changed files, acceptance IDs, verification commands, and spec updates or why none were needed.
|
|
24
|
+
|
|
25
|
+
Rules:
|
|
26
|
+
|
|
27
|
+
- Do not dispatch subagents; `Agent` is removed from this session's tool set.
|
|
28
|
+
- Do not run task start, finish, archive, unscoped resume, commit, or push.
|
|
29
|
+
- Do not create task-local review artifacts, `tdd.jsonl`, or TDD evidence records in `check.jsonl`.
|
|
30
|
+
- Do not claim completion without current verification.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-research
|
|
3
|
+
description: Cowork-flow research fixed subagent for sourced codebase and spec investigation. Use when the main session dispatches read-only investigation that must return evidence rather than edits.
|
|
4
|
+
tools: Read, Grep, Glob, Bash, Skill
|
|
5
|
+
disallowedTools: [Agent]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the `cowork-research` fixed subagent for Qoder.
|
|
9
|
+
|
|
10
|
+
Read and apply `.agents/skills/agent-dispatch/SKILL.md` before research work.
|
|
11
|
+
|
|
12
|
+
Execution:
|
|
13
|
+
|
|
14
|
+
1. Follow `agent-dispatch` to bind runtime context. If binding fails, report `needs_context` and stop.
|
|
15
|
+
2. Read the task directory, assignment, and prompt-named context.
|
|
16
|
+
3. Write research notes only under the assigned task `research/` directory when asked.
|
|
17
|
+
4. Report sourced findings, uncertainty, and recommended next action.
|
|
18
|
+
|
|
19
|
+
Rules:
|
|
20
|
+
|
|
21
|
+
- Do not dispatch subagents; `Agent` is removed from this session's tool set.
|
|
22
|
+
- Do not edit code, specs, task state, or git state.
|
|
23
|
+
- Do not run task start, finish, archive, unscoped resume, commit, or push.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "node",
|
|
9
|
+
"args": [
|
|
10
|
+
"${QODER_PLUGIN_ROOT}/hooks/inject-context.mjs"
|
|
11
|
+
],
|
|
12
|
+
"timeout": 30,
|
|
13
|
+
"statusMessage": "cowork-flow: 注入工作流状态"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"UserPromptSubmit": [
|
|
19
|
+
{
|
|
20
|
+
"hooks": [
|
|
21
|
+
{
|
|
22
|
+
"type": "command",
|
|
23
|
+
"command": "node",
|
|
24
|
+
"args": [
|
|
25
|
+
"${QODER_PLUGIN_ROOT}/hooks/inject-context.mjs"
|
|
26
|
+
],
|
|
27
|
+
"timeout": 30,
|
|
28
|
+
"statusMessage": "cowork-flow: 注入工作流状态"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"PostToolUse": [
|
|
34
|
+
{
|
|
35
|
+
"matcher": "Edit|Write",
|
|
36
|
+
"hooks": [
|
|
37
|
+
{
|
|
38
|
+
"type": "command",
|
|
39
|
+
"command": "node",
|
|
40
|
+
"args": [
|
|
41
|
+
"${QODER_PLUGIN_ROOT}/hooks/inject-context.mjs"
|
|
42
|
+
],
|
|
43
|
+
"timeout": 30,
|
|
44
|
+
"statusMessage": "cowork-flow: 规范自查"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* cowork-flow Qoder plugin hook — transport shim.
|
|
4
|
+
*
|
|
5
|
+
* Workflow facts (workflow-state, contract digest, decision
|
|
6
|
+
* anchor, stage contract, scope/spec edits) come from the
|
|
7
|
+
* Python source
|
|
8
|
+
* <scripts>/adapters/host/inject.py; this shim does
|
|
9
|
+
* transport only:
|
|
10
|
+
* 1. project resolution from the hook payload (`cwd`),
|
|
11
|
+
* then QODER_PROJECT_DIR / QODER_WORKING_DIR;
|
|
12
|
+
* 2. interpreter location, COWORK_FLOW_PYTHON -> python3
|
|
13
|
+
* -> python -> py -3 — the hook runs under the host's
|
|
14
|
+
* process PATH, which is not the user's login shell;
|
|
15
|
+
* 3. stdin passthrough to inject.py --host qoder, with
|
|
16
|
+
* stdout forwarded and a failing project runtime
|
|
17
|
+
* absorbed (exit 0, reason on stderr) — Qoder refuses
|
|
18
|
+
* the prompt on a non-zero hook exit, and the hook is
|
|
19
|
+
* machine-level, so it may meet a project runtime
|
|
20
|
+
* older than itself.
|
|
21
|
+
*
|
|
22
|
+
* Deliberately named .mjs: the installed plugin cache has
|
|
23
|
+
* no package.json, so a plain .js entry point is parsed as
|
|
24
|
+
* CommonJS there and an `import` file would only load on
|
|
25
|
+
* Node versions that auto-detect module syntax.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { existsSync, readFileSync } from "fs";
|
|
29
|
+
import { dirname, join, resolve } from "path";
|
|
30
|
+
import { spawnSync } from "child_process";
|
|
31
|
+
|
|
32
|
+
const HOST = "qoder";
|
|
33
|
+
const DIR_WORKFLOW = ".cowork-flow";
|
|
34
|
+
// hooks.json grants 30s per event.
|
|
35
|
+
const SPAWN_TIMEOUT_MS = 25000;
|
|
36
|
+
|
|
37
|
+
function readHookInput() {
|
|
38
|
+
if (process.stdin.isTTY) return { raw: "", parsed: {} };
|
|
39
|
+
let raw = "";
|
|
40
|
+
try {
|
|
41
|
+
raw = readFileSync(0, "utf8");
|
|
42
|
+
} catch {
|
|
43
|
+
return { raw: "", parsed: {} };
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
// Tolerate a UTF-8 BOM and surrounding whitespace: the payload is
|
|
47
|
+
// forwarded verbatim either way, only the parse needs it clean.
|
|
48
|
+
const parsed = JSON.parse(raw.replace(/^\uFEFF/, "").trim());
|
|
49
|
+
return { raw, parsed: parsed && typeof parsed === "object" ? parsed : {} };
|
|
50
|
+
} catch {
|
|
51
|
+
return { raw, parsed: {} };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function findWorkflowRoot(startDir) {
|
|
56
|
+
if (typeof startDir !== "string" || !startDir.trim()) return null;
|
|
57
|
+
let current;
|
|
58
|
+
try {
|
|
59
|
+
current = resolve(startDir);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
for (;;) {
|
|
64
|
+
if (existsSync(join(current, DIR_WORKFLOW))) return current;
|
|
65
|
+
const parent = dirname(current);
|
|
66
|
+
if (parent === current) return null;
|
|
67
|
+
current = parent;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function findProjectRoot(parsedInput) {
|
|
72
|
+
const candidates = [
|
|
73
|
+
parsedInput?.cwd,
|
|
74
|
+
process.env.QODER_PROJECT_DIR,
|
|
75
|
+
process.env.QODER_WORKING_DIR,
|
|
76
|
+
process.cwd(),
|
|
77
|
+
];
|
|
78
|
+
for (const candidate of candidates) {
|
|
79
|
+
const root = findWorkflowRoot(candidate);
|
|
80
|
+
if (root) return root;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function pythonCandidates() {
|
|
86
|
+
const list = [];
|
|
87
|
+
const env = (process.env.COWORK_FLOW_PYTHON || "").trim();
|
|
88
|
+
if (env) list.push([env]);
|
|
89
|
+
list.push(["python3"], ["python"]);
|
|
90
|
+
if (process.platform === "win32") list.push(["py", "-3"]);
|
|
91
|
+
return list;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function main() {
|
|
95
|
+
if (
|
|
96
|
+
process.env.COWORK_FLOW_HOOKS === "0" ||
|
|
97
|
+
process.env.COWORK_FLOW_DISABLE_HOOKS === "1"
|
|
98
|
+
) {
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const { raw, parsed } = readHookInput();
|
|
103
|
+
const root = findProjectRoot(parsed);
|
|
104
|
+
if (!root) process.exit(0);
|
|
105
|
+
const injectScript = join(
|
|
106
|
+
root,
|
|
107
|
+
DIR_WORKFLOW,
|
|
108
|
+
"scripts",
|
|
109
|
+
"adapters",
|
|
110
|
+
"host",
|
|
111
|
+
"inject.py"
|
|
112
|
+
);
|
|
113
|
+
if (!existsSync(injectScript)) process.exit(0);
|
|
114
|
+
|
|
115
|
+
for (const candidate of pythonCandidates()) {
|
|
116
|
+
let result;
|
|
117
|
+
try {
|
|
118
|
+
result = spawnSync(
|
|
119
|
+
candidate[0],
|
|
120
|
+
[...candidate.slice(1), injectScript, "--host", HOST],
|
|
121
|
+
{
|
|
122
|
+
input: raw,
|
|
123
|
+
cwd: root,
|
|
124
|
+
timeout: SPAWN_TIMEOUT_MS,
|
|
125
|
+
encoding: "utf8",
|
|
126
|
+
windowsHide: true,
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
} catch {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (result.error || result.status === null) continue;
|
|
133
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
134
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
135
|
+
// The interpreter ran; its exit status is the project runtime's verdict,
|
|
136
|
+
// not ours. Forwarding it would let a stale project copy fail the event
|
|
137
|
+
// this hook only decorates.
|
|
138
|
+
if (result.status !== 0) {
|
|
139
|
+
process.stderr.write(
|
|
140
|
+
`cowork-flow qoder hook: inject.py exited ${result.status}; skipping injection\n`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}
|
|
145
|
+
// No interpreter could run the entry: stay silent rather
|
|
146
|
+
// than break the host's event stream (fail-open).
|
|
147
|
+
process.exit(0);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
main();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-flow-bootstrap
|
|
3
|
+
description: Use only when a repository has no .cowork-flow/ runtime and the user wants to start or continue structured development work — guides installing cowork-flow into the project. Do not use when .cowork-flow/ exists; the project's own cowork-flow Skill owns that case.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cowork Flow Bootstrap
|
|
7
|
+
|
|
8
|
+
This Skill is the plugin-side bootstrap. It applies to repositories that have no
|
|
9
|
+
`.cowork-flow/` runtime yet. Once `.cowork-flow/` exists, stop and use the
|
|
10
|
+
project's own Skills: after init, `./.cowork-flow/run task next` and the project's
|
|
11
|
+
skill copies are authoritative, not this Skill.
|
|
12
|
+
|
|
13
|
+
## Decide first
|
|
14
|
+
|
|
15
|
+
Check the repository root for the runtime directory `.cowork-flow/` (or the
|
|
16
|
+
workflow entry `./.cowork-flow/run`).
|
|
17
|
+
|
|
18
|
+
## No runtime: offer the install
|
|
19
|
+
|
|
20
|
+
Tell the user this repository has no cowork-flow runtime, then offer:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx cowork-flow project init .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
After init the project carries its own Skills (`.agents/skills/`), the task
|
|
27
|
+
runtime (`.cowork-flow/`), and the workflow entry `./.cowork-flow/run task next`.
|
|
28
|
+
Resume the work through that entry.
|
|
29
|
+
|
|
30
|
+
## Never
|
|
31
|
+
|
|
32
|
+
- Do not reproduce lifecycle rules, gates, or a second workflow document here.
|
|
33
|
+
- Do not hand-create `.cowork-flow/` or copy files out of the plugin payload.
|
|
34
|
+
- Do not run task lifecycle commands: without a project runtime there is no task
|
|
35
|
+
to advance.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cowork-flow",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。将 cowork-flow 的完整工作流带入 ZCode。",
|
|
5
5
|
"author": {
|
|
6
|
-
"name": "
|
|
6
|
+
"name": "fishlikewater",
|
|
7
|
+
"url": "https://github.com/fishlikewater"
|
|
7
8
|
},
|
|
9
|
+
"homepage": "https://github.com/fishlikewater/cowork-flow",
|
|
8
10
|
"license": "MIT",
|
|
9
11
|
"hooks": "hooks/hooks.json",
|
|
10
12
|
"agents": "agents",
|
|
@@ -7,10 +7,10 @@ You are the `cowork-check` fixed subagent for ZCode.
|
|
|
7
7
|
|
|
8
8
|
Read and apply these plugin Skills before review work:
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
10
|
+
- `.agents/skills/agent-dispatch/SKILL.md`
|
|
11
|
+
- `.agents/skills/task-review/SKILL.md`
|
|
12
|
+
- `.agents/skills/decision-audit/SKILL.md`
|
|
13
|
+
- `.agents/skills/spec-sync/SKILL.md`
|
|
14
14
|
|
|
15
15
|
Execution:
|
|
16
16
|
|
|
@@ -7,10 +7,10 @@ You are the `cowork-implement` fixed subagent for ZCode.
|
|
|
7
7
|
|
|
8
8
|
Read and apply these plugin Skills before task work:
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
10
|
+
- `.agents/skills/agent-dispatch/SKILL.md`
|
|
11
|
+
- `.agents/skills/decision-audit/SKILL.md`
|
|
12
|
+
- `.agents/skills/spec-sync/SKILL.md`
|
|
13
|
+
- `.agents/skills/test-first/SKILL.md` for behavior changes
|
|
14
14
|
|
|
15
15
|
Execution:
|
|
16
16
|
|
|
@@ -5,7 +5,7 @@ description: Cowork-flow research-only fixed subagent for sourced investigation
|
|
|
5
5
|
|
|
6
6
|
You are the `cowork-research` fixed subagent for ZCode.
|
|
7
7
|
|
|
8
|
-
Read and apply
|
|
8
|
+
Read and apply `.agents/skills/agent-dispatch/SKILL.md` before research work.
|
|
9
9
|
|
|
10
10
|
Execution:
|
|
11
11
|
|
|
@@ -2,19 +2,26 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* cowork-flow ZCode plugin hook — transport shim.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* stage contract, scope/spec
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
5
|
+
* Workflow facts (workflow-state, contract digest,
|
|
6
|
+
* decision anchor, stage contract, scope/spec edits)
|
|
7
|
+
* come from the Python source
|
|
8
|
+
* <scripts>/adapters/host/inject.py; this shim does
|
|
9
|
+
* transport only:
|
|
10
|
+
* 1. cheap PostToolUse(Bash) filter: anything that
|
|
11
|
+
* is not a lifecycle command exits 0 unspawned;
|
|
12
|
+
* 2. interpreter location, COWORK_FLOW_PYTHON -> python3
|
|
13
|
+
* -> python -> py -3;
|
|
14
|
+
* 3. stdin passthrough to inject.py --host zcode, with
|
|
15
|
+
* stdout forwarded and a failing project runtime
|
|
16
|
+
* absorbed (exit 0, reason on stderr) — the hook
|
|
17
|
+
* is machine-level and may meet an older project
|
|
18
|
+
* copy, which must not fail the event.
|
|
13
19
|
*
|
|
14
|
-
* The project's own runtime copy
|
|
15
|
-
* the plugin cache copy (
|
|
16
|
-
* outside any cowork-flow project. Windows
|
|
17
|
-
* (Node 24+ EINVAL)
|
|
20
|
+
* The project's own runtime copy wins (same root the CLI
|
|
21
|
+
* resolves); the plugin cache copy (runtime/scripts)
|
|
22
|
+
* renders only outside any cowork-flow project. Windows
|
|
23
|
+
* never spawns .cmd shims directly (Node 24+ EINVAL), so
|
|
24
|
+
* interpreters resolve to .exe entries.
|
|
18
25
|
*/
|
|
19
26
|
|
|
20
27
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -26,7 +33,8 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
26
33
|
|
|
27
34
|
const DIR_WORKFLOW = ".cowork-flow";
|
|
28
35
|
const LIFECYCLE_BASH_RE = /\brun(?:\.cmd)?\s+(?:task|subagent|resume)\b/;
|
|
29
|
-
|
|
36
|
+
// hooks.json grants 5s per event.
|
|
37
|
+
const SPAWN_TIMEOUT_MS = 4800;
|
|
30
38
|
|
|
31
39
|
function readHookInput() {
|
|
32
40
|
if (process.stdin.isTTY) return { raw: "", parsed: {} };
|
|
@@ -91,7 +99,7 @@ function resolveInjectScript(parsedInput) {
|
|
|
91
99
|
);
|
|
92
100
|
if (existsSync(projectInject)) return projectInject;
|
|
93
101
|
}
|
|
94
|
-
// Plugin-cache
|
|
102
|
+
// Plugin-cache copy: the not-initialized context for
|
|
95
103
|
// directories outside any cowork-flow project.
|
|
96
104
|
const cacheInject = join(
|
|
97
105
|
__dirname,
|
|
@@ -115,8 +123,8 @@ function main() {
|
|
|
115
123
|
|
|
116
124
|
const { raw, parsed } = readHookInput();
|
|
117
125
|
|
|
118
|
-
//
|
|
119
|
-
// lifecycle command
|
|
126
|
+
// A PostToolUse Bash call matters only when it is a
|
|
127
|
+
// workflow lifecycle command; every other call exits
|
|
120
128
|
// without spawning Python.
|
|
121
129
|
if (
|
|
122
130
|
typeof parsed?.hook_event_name === "string" &&
|
|
@@ -157,10 +165,19 @@ function main() {
|
|
|
157
165
|
if (result.error || result.status === null) continue;
|
|
158
166
|
if (result.stdout) process.stdout.write(result.stdout);
|
|
159
167
|
if (result.stderr) process.stderr.write(result.stderr);
|
|
160
|
-
|
|
168
|
+
// The interpreter ran; its exit status is the project runtime's verdict,
|
|
169
|
+
// not ours. Forwarding it would let a stale project copy fail the event
|
|
170
|
+
// this hook only decorates.
|
|
171
|
+
if (result.status !== 0) {
|
|
172
|
+
process.stderr.write(
|
|
173
|
+
`cowork-flow zcode hook: inject.py exited ${result.status}; skipping injection\n`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
process.exit(0);
|
|
161
177
|
}
|
|
162
|
-
// No interpreter could run the entry: stay silent rather
|
|
163
|
-
// host's event stream (fail-open,
|
|
178
|
+
// No interpreter could run the entry: stay silent rather
|
|
179
|
+
// than break the host's event stream (fail-open, like
|
|
180
|
+
// the spec-edit path).
|
|
164
181
|
process.exit(0);
|
|
165
182
|
}
|
|
166
183
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-flow-bootstrap
|
|
3
|
+
description: Use only when a repository has no .cowork-flow/ runtime and the user wants to start or continue structured development work — guides installing cowork-flow into the project. Do not use when .cowork-flow/ exists; the project's own cowork-flow Skill owns that case.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cowork Flow Bootstrap
|
|
7
|
+
|
|
8
|
+
This Skill is the plugin-side bootstrap. It applies to repositories that have no
|
|
9
|
+
`.cowork-flow/` runtime yet. Once `.cowork-flow/` exists, stop and use the
|
|
10
|
+
project's own Skills: after init, `./.cowork-flow/run task next` and the project's
|
|
11
|
+
skill copies are authoritative, not this Skill.
|
|
12
|
+
|
|
13
|
+
## Decide first
|
|
14
|
+
|
|
15
|
+
Check the repository root for the runtime directory `.cowork-flow/` (or the
|
|
16
|
+
workflow entry `./.cowork-flow/run`).
|
|
17
|
+
|
|
18
|
+
## No runtime: offer the install
|
|
19
|
+
|
|
20
|
+
Tell the user this repository has no cowork-flow runtime, then offer:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx cowork-flow project init .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
After init the project carries its own Skills (`.agents/skills/`), the task
|
|
27
|
+
runtime (`.cowork-flow/`), and the workflow entry `./.cowork-flow/run task next`.
|
|
28
|
+
Resume the work through that entry.
|
|
29
|
+
|
|
30
|
+
## Never
|
|
31
|
+
|
|
32
|
+
- Do not reproduce lifecycle rules, gates, or a second workflow document here.
|
|
33
|
+
- Do not hand-create `.cowork-flow/` or copy files out of the plugin payload.
|
|
34
|
+
- Do not run task lifecycle commands: without a project runtime there is no task
|
|
35
|
+
to advance.
|