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.
Files changed (129) hide show
  1. package/CHANGELOG.md +213 -213
  2. package/CONTRIBUTING.md +137 -0
  3. package/LICENSE +1 -1
  4. package/README.md +108 -369
  5. package/docs/architecture.md +122 -0
  6. package/docs/hosts.md +290 -0
  7. package/docs/index.md +32 -0
  8. package/docs/release.md +104 -0
  9. package/package.json +37 -7
  10. package/presets/claude-code/.claude-plugin/plugin.json +28 -0
  11. package/presets/claude-code/skills/cowork-flow-bootstrap/SKILL.md +35 -0
  12. package/presets/codex/.codex-plugin/plugin.json +37 -0
  13. package/presets/codex/assets/logo.svg +4 -0
  14. package/presets/codex/skills/cowork-flow-bootstrap/SKILL.md +35 -0
  15. package/presets/dsh/agent.cordis.yml +35 -12
  16. package/presets/dsh/plugins/workflow-state.js +88 -72
  17. package/presets/dsh/preset.yml +1 -1
  18. package/presets/kimi-code/.kimi-plugin/plugin.json +35 -0
  19. package/presets/kimi-code/hooks/cowork-flow-inject.mjs +14 -2
  20. package/presets/kimi-code/skills/cowork-flow-bootstrap/SKILL.md +35 -0
  21. package/presets/opencode/cowork-flow/plugin-core.js +1077 -0
  22. package/presets/opencode/cowork-flow/skills/cowork-flow-bootstrap/SKILL.md +35 -0
  23. package/presets/opencode/plugins/cowork-flow.js +44 -0
  24. package/presets/plugin-meta.json +52 -0
  25. package/presets/qoder/.qoder-plugin/plugin.json +29 -0
  26. package/presets/qoder/agents/cowork-check.md +29 -0
  27. package/presets/qoder/agents/cowork-implement.md +30 -0
  28. package/presets/qoder/agents/cowork-research.md +23 -0
  29. package/presets/qoder/hooks/hooks.json +50 -0
  30. package/presets/qoder/hooks/inject-context.mjs +150 -0
  31. package/presets/qoder/skills/cowork-flow-bootstrap/SKILL.md +35 -0
  32. package/{template/.zcode → presets/zcode}/.zcode-plugin/plugin.json +4 -2
  33. package/{template/.zcode → presets/zcode}/agents/cowork-check.md +4 -4
  34. package/{template/.zcode → presets/zcode}/agents/cowork-implement.md +4 -4
  35. package/{template/.zcode → presets/zcode}/agents/cowork-research.md +1 -1
  36. package/{template/.zcode → presets/zcode}/hooks/inject-context.js +36 -19
  37. package/presets/zcode/skills/cowork-flow-bootstrap/SKILL.md +35 -0
  38. package/src/cli.js +130 -130
  39. package/src/commands/host.js +182 -0
  40. package/src/commands/init.js +28 -43
  41. package/src/commands/install-claude-code-plugin.js +129 -0
  42. package/src/commands/install-codex-plugin.js +312 -0
  43. package/src/commands/install-dsh-hook.js +36 -43
  44. package/src/commands/install-dsh-preset.js +228 -49
  45. package/src/commands/install-kimi-code-plugin.js +142 -0
  46. package/src/commands/install-kimi-hook.js +142 -122
  47. package/src/commands/install-opencode-plugin.js +158 -0
  48. package/src/commands/install-qoder-plugin.js +211 -0
  49. package/src/commands/install-zcode-plugin.js +131 -82
  50. package/src/commands/mcp-state.js +7 -6
  51. package/src/commands/registry.js +345 -0
  52. package/src/commands/source-refresh.js +10 -11
  53. package/src/commands/sync.js +10 -13
  54. package/src/commands/update.js +5 -10
  55. package/src/lib/cli-flags.js +102 -0
  56. package/src/lib/copy-template.js +89 -75
  57. package/src/lib/host-assets.js +192 -57
  58. package/src/lib/install-support.js +50 -0
  59. package/src/lib/platforms.js +0 -15
  60. package/src/lib/plugin-metadata.js +187 -0
  61. package/src/lib/plugin-payload.js +70 -0
  62. package/template/.cowork-flow/.version +1 -1
  63. package/template/.cowork-flow/adapters/claude-code/adapter.yaml +0 -1
  64. package/template/.cowork-flow/adapters/dsh/adapter.yaml +0 -1
  65. package/template/.cowork-flow/adapters/kimi-code/adapter.yaml +0 -1
  66. package/template/.cowork-flow/adapters/qoder/adapter.yaml +32 -0
  67. package/template/.cowork-flow/adapters/zcode/adapter.yaml +2 -2
  68. package/template/.cowork-flow/config.yaml +6 -4
  69. package/template/.cowork-flow/scripts/adapters/cli/batch_mode.py +10 -12
  70. package/template/.cowork-flow/scripts/adapters/cli/spec_check.py +67 -35
  71. package/template/.cowork-flow/scripts/adapters/cli/subagent.py +84 -38
  72. package/template/.cowork-flow/scripts/adapters/cli/task.py +42 -0
  73. package/template/.cowork-flow/scripts/adapters/cli/task_create_command.py +1 -9
  74. package/template/.cowork-flow/scripts/adapters/cli/task_lifecycle_commands.py +6 -0
  75. package/template/.cowork-flow/scripts/adapters/cli/task_navigation.py +13 -10
  76. package/template/.cowork-flow/scripts/adapters/cli/task_next_runner.py +2 -1
  77. package/template/.cowork-flow/scripts/adapters/git/git_context.py +14 -82
  78. package/template/.cowork-flow/scripts/adapters/host/claude_code_policy.py +2 -3
  79. package/template/.cowork-flow/scripts/adapters/host/codex_policy.py +2 -5
  80. package/template/.cowork-flow/scripts/adapters/host/host_manifest.py +122 -10
  81. package/template/.cowork-flow/scripts/adapters/host/inject.py +49 -19
  82. package/template/.cowork-flow/scripts/adapters/host/kimi_code_policy.py +1 -1
  83. package/template/.cowork-flow/scripts/adapters/host/policy_base.py +58 -0
  84. package/template/.cowork-flow/scripts/adapters/host/qoder_policy.py +66 -0
  85. package/template/.cowork-flow/scripts/adapters/host/workflow_state_hook.py +136 -132
  86. package/template/.cowork-flow/scripts/adapters/host/zcode_policy.py +23 -24
  87. package/template/.cowork-flow/scripts/adapters/mcp/state_server.py +41 -56
  88. package/template/.cowork-flow/scripts/adapters/review/test_intent.py +2 -2
  89. package/template/.cowork-flow/scripts/infra/config.py +26 -23
  90. package/template/.cowork-flow/scripts/infra/developer_profile.py +4 -41
  91. package/template/.cowork-flow/scripts/infra/files.py +3 -7
  92. package/template/.cowork-flow/scripts/infra/git_snapshot.py +8 -7
  93. package/template/.cowork-flow/scripts/infra/paths.py +9 -69
  94. package/template/.cowork-flow/scripts/infra/process.py +9 -0
  95. package/template/.cowork-flow/scripts/infra/skill_manifest.py +262 -169
  96. package/template/.cowork-flow/scripts/infra/storage/operation_log.py +2 -0
  97. package/template/.cowork-flow/scripts/infra/storage/state_store.py +0 -2
  98. package/template/.cowork-flow/scripts/infra/storage/unit_of_work.py +163 -18
  99. package/template/.cowork-flow/scripts/kernel/workflow_route.py +6 -16
  100. package/template/.cowork-flow/scripts/run.py +14 -4
  101. package/template/.cowork-flow/scripts/runtime/host_identity.py +33 -15
  102. package/template/.cowork-flow/scripts/runtime/session_state.py +83 -26
  103. package/template/.cowork-flow/scripts/services/context_discovery.py +15 -3
  104. package/template/.cowork-flow/scripts/services/context_paths.py +4 -4
  105. package/template/.cowork-flow/scripts/services/fact_view.py +13 -10
  106. package/template/.cowork-flow/scripts/services/lifecycle_checks.py +47 -13
  107. package/template/.cowork-flow/scripts/services/lifecycle_policy.py +5 -2
  108. package/template/.cowork-flow/scripts/services/readiness.py +8 -3
  109. package/template/.cowork-flow/scripts/services/spec_check.py +23 -33
  110. package/template/.cowork-flow/scripts/services/task_archive.py +76 -41
  111. package/template/.cowork-flow/scripts/services/task_creation.py +90 -34
  112. package/template/.cowork-flow/scripts/services/task_lifecycle.py +210 -50
  113. package/template/.cowork-flow/scripts/services/task_routing.py +0 -8
  114. package/template/.cowork-flow/scripts/services/task_tree.py +181 -29
  115. package/template/.cowork-flow/scripts/services/task_utils.py +3 -20
  116. package/template/.cowork-flow/scripts/services/workflow_runtime.py +39 -22
  117. package/template/.cowork-flow/spec/contracts/context-injection.md +27 -2
  118. package/template/.cowork-flow/spec/contracts/fact-layer-access.md +7 -4
  119. package/template/.cowork-flow/spec/contracts/index.md +4 -0
  120. package/template/.cowork-flow/spec/contracts/spec-checks.md +13 -2
  121. package/template/.cowork-flow/spec/runtime/host-assets.json +155 -18
  122. package/template/.cowork-flow/spec/runtime/index.md +1 -1
  123. package/template/.cowork-flow/spec/schemas/host-assets.schema.json +69 -7
  124. package/template/.dsh/README.md +27 -7
  125. package/template/.opencode/cowork-flow/plugin-core.js +1077 -0
  126. package/template/.opencode/plugins/cowork-flow.js +23 -800
  127. package/template/skills/python-runtime-design/SKILL.md +6 -0
  128. package/template/skills/runtime-health/scripts/doctor.py +725 -14
  129. /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.6.0",
3
+ "version": "1.7.2",
4
4
  "description": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。将 cowork-flow 的完整工作流带入 ZCode。",
5
5
  "author": {
6
- "name": "fisklikewater"
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
- - `skills/agent-dispatch/SKILL.md`
11
- - `skills/task-review/SKILL.md`
12
- - `skills/decision-audit/SKILL.md`
13
- - `skills/spec-sync/SKILL.md`
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
- - `skills/agent-dispatch/SKILL.md`
11
- - `skills/decision-audit/SKILL.md`
12
- - `skills/spec-sync/SKILL.md`
13
- - `skills/test-first/SKILL.md` for behavior changes
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 `skills/agent-dispatch/SKILL.md` before research work.
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
- * All workflow facts (workflow-state, contract digest, decision anchor,
6
- * stage contract, scope/spec edit warnings) are rendered by the single
7
- * Python source: <scripts>/adapters/host/inject.py. This shim keeps only
8
- * transport duties:
9
- * 1. cheap PostToolUse(Bash) filter — non-lifecycle commands exit 0
10
- * without spawning anything (the highest-frequency event);
11
- * 2. interpreter location (COWORK_FLOW_PYTHON → python3 → python → py -3);
12
- * 3. stdin passthrough to inject.py --host zcode, stdout/exit forwarding.
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 is preferred (same root the CLI resolves);
15
- * the plugin cache copy (hooks/runtime/scripts) renders only for directories
16
- * outside any cowork-flow project. Windows never spawns .cmd shims directly
17
- * (Node 24+ EINVAL) — interpreters resolve to .exe entries.
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
- const SPAWN_TIMEOUT_MS = 4800; // hooks.json grants 5s per event
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 runtime copy: renders the not-initialized context for
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
- // Cheap first: a PostToolUse Bash call only matters when it is a workflow
119
- // lifecycle command (mid-turn state refresh); every other Bash call exits
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
- process.exit(result.status);
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 than break the
163
- // host's event stream (fail-open, same contract as the spec-edit path).
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.