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,37 @@
1
+ {
2
+ "name": "cowork-flow",
3
+ "version": "1.7.2",
4
+ "description": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。将 cowork-flow 的完整工作流带入 Codex。",
5
+ "author": {
6
+ "name": "fishlikewater",
7
+ "email": "fishlikewater@126.com",
8
+ "url": "https://github.com/fishlikewater"
9
+ },
10
+ "homepage": "https://github.com/fishlikewater/cowork-flow",
11
+ "repository": "https://github.com/fishlikewater/cowork-flow",
12
+ "license": "MIT",
13
+ "keywords": [
14
+ "ai-agent",
15
+ "workflow",
16
+ "task-lifecycle",
17
+ "subagents",
18
+ "codex",
19
+ "claude-code",
20
+ "opencode",
21
+ "zcode",
22
+ "qoder",
23
+ "kimi-code",
24
+ "dsh"
25
+ ],
26
+ "skills": "./skills/",
27
+ "interface": {
28
+ "displayName": "Cowork Flow",
29
+ "shortDescription": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。",
30
+ "longDescription": "cowork-flow 给 AI 编码宿主的 agent 提供可执行的工作流:任务生命周期、决策记录、规范契约与独立检查。安装后任务状态由运行时统一维护,多个宿主的会话从同一份事实起步。",
31
+ "developerName": "fishlikewater",
32
+ "category": "Developer Tools",
33
+ "websiteURL": "https://github.com/fishlikewater/cowork-flow",
34
+ "logo": "./assets/logo.svg",
35
+ "brandColor": "#2563EB"
36
+ }
37
+ }
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" role="img" aria-label="Cowork Flow">
2
+ <title>Cowork Flow</title>
3
+ <path d="M3 18H8V12H14V6H21" fill="none" stroke="#2563EB" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -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,17 +1,40 @@
1
1
  # The `cowork-flow` agent preset: the standard coding agent plus the
2
2
  # cowork-flow workflow framework (task gate, planning, fixed subagents, skills).
3
3
  #
4
- # This file is a copy of the deployment's `standard` preset with two changes:
5
- # the persona carries cowork-flow operating rules, and `skill-filesystem`
6
- # points at this preset's own `skills/` directory (installed alongside by
7
- # `cowork-flow install-dsh-preset`).
4
+ # It started from the 0.1.x `standard` preset: the persona carries the
5
+ # cowork-flow operating rules, and `skill-filesystem` keeps the workspace
6
+ # default roots (`<projectRoot>/.dsh/skills` rank 100,
7
+ # `<projectRoot>/.agents/skills` rank 200) plus the user roots, so skills come
8
+ # from the project copy that `cwf project init` / `sync` delivers — this preset
9
+ # ships none of its own.
8
10
  #
9
11
  # The `dsh` host adapter lives in the cowork-flow repository
10
12
  # (template/.cowork-flow/adapters/dsh/adapter.yaml) and declares this preset's
11
13
  # capability model; this file is the DSH-side composition it describes.
14
+ #
15
+ # Version basis: the 0.1.x line. This file is what DSH 0.1.x reads as a preset
16
+ # directory (`$DSH_HOME/.agent-presets/<id>/`), and the 0.2.0 bundle is
17
+ # generated from it. Each delivered form must name only the packages its own
18
+ # line ships and carry only the config keys that line's schema accepts — either
19
+ # mistake makes that line fail the whole preset, not just the row. The lines
20
+ # disagree in two places: 0.1.x mounts `dsh-workflow-worker-thread`, which 0.2.0
21
+ # dropped for `dsh-workflow-ptc`, and this `dsh-persona` row is a single
22
+ # `text`, where 0.2.0 requires `prefix` (plus optional `suffix`). The bundle
23
+ # generator performs both rewrites, and a third: the hook specifier becomes a
24
+ # `file:` URL of the installed copy.
25
+ #
26
+ # Deliberate drift from the 0.1.x `standard` (0.1.2-rc.1), besides the
27
+ # cowork-flow persona and the `workflow-state-hook` row: `tool-subagent` drops
28
+ # `modelSelectionSettings`, the codex / claude-code rows use
29
+ # `enableRunInBackground: false` where the standard takes the `backgroundMode`
30
+ # default, `tool-web` sets `fetch: false`, and `command-goal` is not mounted.
31
+ # Rows the 0.2.0 `standard` adds over its 0.1.x counterpart (`present`,
32
+ # `tool-plugin-manager`) are absent from this preset on either line.
12
33
 
13
34
  # ── identity ────────────────────────────────────────────────────────────────
14
35
 
36
+ # 0.1.x's persona schema: one `text`. 0.2.0 takes `prefix`/`suffix`, so the
37
+ # bundle moves this wording to `prefix` unchanged (see the header).
15
38
  - id: persona
16
39
  name: '@deepseek-ai/dsh-persona'
17
40
  config:
@@ -56,16 +79,13 @@
56
79
 
57
80
  # ── skills ──────────────────────────────────────────────────────────────────
58
81
 
59
- # The skill REGISTRY lives in the host composition and is layered per scope:
60
- # these rows register into THIS preset's layer of it. `skill-filesystem`
61
- # contributes the cowork-flow skills shipped with this preset (`customSkillDirs`,
62
- # resolved against the preset's own directory via `baseUrl`) on top of the
63
- # local-root discovery for the current workspace.
82
+ # The skill REGISTRY lives in the host composition and is layered per scope.
83
+ # `skill-filesystem` discovers skills from the workspace's own roots
84
+ # (`<projectRoot>/.dsh/skills` at rank 100, `<projectRoot>/.agents/skills` at
85
+ # rank 200) plus the user roots, so cowork-flow skills come from the project
86
+ # copy that `init`/`sync` delivers — the preset ships none of its own.
64
87
  - id: skill-filesystem
65
88
  name: '@deepseek-ai/dsh-skill-filesystem'
66
- config:
67
- customSkillDirs:
68
- - !!js "process.getBuiltinModule('node:url').fileURLToPath(new URL('skills/', baseUrl))"
69
89
 
70
90
  - id: tool-skill
71
91
  name: '@deepseek-ai/dsh-tool-skill'
@@ -175,6 +195,9 @@
175
195
  enableRunInBackground: false
176
196
  maxDepth: provider-managed
177
197
 
198
+ # The 0.1.x row: 0.2.0 no longer ships this package and its `standard`
199
+ # mounts `dsh-workflow-ptc` instead, so the generated bundle swaps the row.
200
+ # This file itself is read by 0.1.x, where `ptc` resolves nowhere.
178
201
  - id: workflow-worker-thread
179
202
  name: '@deepseek-ai/dsh-workflow-worker-thread'
180
203
  config:
@@ -1,25 +1,27 @@
1
1
  // cowork-flow DSH workflow-state hook.
2
2
  //
3
- // DSH-native equivalent of the Codex/Claude hooks
4
- // (template/.codex/hooks/inject-workflow-state.py and its Claude sibling):
5
- // this preset plugin registers ONE system-prompt section, rendered last
6
- // (order 1000, after identity/persona/tool guidance), whose text is the
7
- // `<workflow-state>` block produced by the SAME Python protocol the other
8
- // hosts use (adapters/host/workflow_state_hook.py), so the injected content
9
- // is structurally identical across hosts.
3
+ // DSH-native equivalent of the Codex/Claude hooks:
4
+ // registers ONE system-prompt section, rendered last
5
+ // (order 1000, after identity/persona/tool guidance),
6
+ // whose text is the `<workflow-state>` block produced by
7
+ // the SAME Python protocol the other hosts use
8
+ // (adapters/host/workflow_state_hook.py), so the injected
9
+ // content is structurally identical across hosts.
10
10
  //
11
- // The block is refreshed per user message (`agent/session-start` warms it,
12
- // `agent/inbox/claimed` refreshes it) and after lifecycle commands settle
13
- // (`tools/result`), then cached per agent; each prompt assembly re-renders
14
- // the current cached value in place — replace semantics, no accumulation
15
- // across turns or steps. Between refreshes the text is byte-stable, so the
16
- // static prompt prefix stays cacheable and the dynamic cost is confined to
17
- // the trailing block.
11
+ // Refreshed per user message (`agent/created` on 0.2.0, its former name
12
+ // `agent/session-start` on 0.1.x, `agent/inbox/claimed` for each new one)
13
+ // and after lifecycle commands settle (`tools/result`), then cached
14
+ // per agent; each prompt assembly re-renders the cached
15
+ // value in place, with replace semantics and no
16
+ // accumulation across turns or steps. Between refreshes
17
+ // the text is byte-stable, so the static prompt prefix
18
+ // stays cacheable.
18
19
  //
19
- // Degradation is silent: no `.cowork-flow` root, a missing Python, a broken
20
- // runtime, or the `COWORK_FLOW_HOOKS=0` / `COWORK_FLOW_DISABLE_HOOKS=1`
21
- // switches all yield an empty section, and the workspace AGENTS.md gate
22
- // falls back to running the navigator manually.
20
+ // Degradation is silent: no `.cowork-flow` root, a missing
21
+ // Python, a broken runtime, or the `COWORK_FLOW_HOOKS=0` /
22
+ // `COWORK_FLOW_DISABLE_HOOKS=1` switches all yield an
23
+ // empty section. The workspace AGENTS.md gate then falls
24
+ // back to running the navigator manually.
23
25
 
24
26
  import { execFile } from 'node:child_process';
25
27
  import { randomUUID } from 'node:crypto';
@@ -38,15 +40,17 @@ const EXEC_OPTIONS = {
38
40
  maxBuffer: 1024 * 1024,
39
41
  };
40
42
  const NO_ROOT_MARKER = '__COWORK_FLOW_NO_ROOT__';
41
- // How long a "no .cowork-flow root" verdict is trusted for one cwd. Bounded
42
- // on purpose: a project that installs cowork-flow mid-session becomes visible
43
- // after at most one TTL, at the cost of at most one interpreter probe.
43
+ // How long a "no .cowork-flow root" verdict is trusted for
44
+ // one cwd. Bounded on purpose: a project that installs
45
+ // cowork-flow mid-session becomes visible after at most
46
+ // one TTL, at the cost of at most one interpreter probe.
44
47
  const NO_ROOT_TTL_MS = 30_000;
45
48
  const noRootCache = new Map();
46
49
 
47
- // Python 3.9+ protocol reused from the host hook adapters. It resolves the
48
- // `.cowork-flow` root from the given cwd, loads the shared
49
- // workflow_state_hook module, and prints the full hook context block.
50
+ // Python 3.9+ protocol reused from the host hook adapters.
51
+ // It resolves the `.cowork-flow` root from the given cwd,
52
+ // loads the shared workflow_state_hook module, and prints
53
+ // the full hook context block.
50
54
  const PYTHON_PROTOCOL = `\
51
55
  import sys
52
56
  from pathlib import Path
@@ -83,9 +87,9 @@ print(build_hook_context(
83
87
  ))
84
88
  `;
85
89
 
86
- // The edit path sits on the finished tool result, so it gets a short leash:
87
- // a slow checker is dropped rather than delaying the edit the model already
88
- // made.
90
+ // The edit path sits on the finished tool result, so it
91
+ // gets a short leash: a slow checker is dropped rather
92
+ // than delaying the edit the model already made.
89
93
  const EDIT_TIMEOUT_MS = 2500;
90
94
  const EDIT_EXEC_OPTIONS = {
91
95
  timeout: EDIT_TIMEOUT_MS,
@@ -93,9 +97,10 @@ const EDIT_EXEC_OPTIONS = {
93
97
  maxBuffer: 1024 * 1024,
94
98
  };
95
99
 
96
- // Editor-phase spec-check protocol: same root discovery, then the shared
97
- // edit-check entry so DSH sessions receive the single-line violation hint
98
- // the other hosts get from their PostToolUse hook. Always exits 0.
100
+ // Editor-phase spec-check protocol: same root discovery,
101
+ // then the shared edit-check entry so DSH sessions receive
102
+ // the single-line violation hint the other hosts get from
103
+ // their PostToolUse hook. Always exits 0.
99
104
  const PYTHON_EDIT_PROTOCOL = `\
100
105
  import sys
101
106
  from pathlib import Path
@@ -121,19 +126,21 @@ except Exception:
121
126
  pass
122
127
  `;
123
128
 
124
- // The first interpreter that ran the protocol successfully; a missing one is
125
- // dropped so a later refresh can rediscover (e.g. after a PATH change).
129
+ // The first interpreter that ran the protocol
130
+ // successfully; a missing one is dropped so a later
131
+ // refresh can rediscover it after a PATH change.
126
132
  let workingPython = null;
127
133
 
128
- // Cowork-flow lifecycle commands executed through any tool. Matching the
129
- // command text (not the tool name) keeps the trigger stable across tool
130
- // surface changes.
134
+ // Cowork-flow lifecycle commands executed through any
135
+ // tool. Matching the command text (not the tool name)
136
+ // keeps the trigger stable across tool surface changes.
131
137
  const LIFECYCLE_COMMAND = /\.cowork-flow[\\/]run(?:\.cmd)?(?:\s+[^\s"']*)?\s+(task|subagent|resume)\b/;
132
138
 
133
139
 
134
140
  /**
135
- * True when a tool argument value embeds a cowork-flow lifecycle command.
136
- * Accepts strings and JSON-serializable structures; never throws.
141
+ * True when a tool argument value embeds a cowork-flow
142
+ * lifecycle command. Accepts strings and JSON-serializable
143
+ * structures; never throws.
137
144
  */
138
145
  export function isLifecycleCommand(value) {
139
146
  try {
@@ -176,9 +183,10 @@ function tryPython(candidate, cwd, full = true) {
176
183
  EXEC_OPTIONS,
177
184
  (error, stdout) => {
178
185
  if (error) {
179
- // ENOENT = the interpreter does not exist (try the next one).
180
- // Any other failure means the interpreter ran but the protocol
181
- // failed — the candidate works, the project runtime does not.
186
+ // ENOENT = the interpreter does not exist (try
187
+ // the next one). Any other failure means the
188
+ // interpreter ran but the protocol failed — the
189
+ // candidate works, the runtime does not.
182
190
  resolve({ missing: error.code === 'ENOENT', output: '' });
183
191
  return;
184
192
  }
@@ -198,7 +206,8 @@ function normalize(output) {
198
206
 
199
207
 
200
208
  /**
201
- * Test seam: forget the memoized interpreter so the next call rediscovers.
209
+ * Test seam: forget the memoized interpreter so the next
210
+ * call rediscovers.
202
211
  */
203
212
  export function resetWorkingPython() {
204
213
  workingPython = null;
@@ -206,9 +215,10 @@ export function resetWorkingPython() {
206
215
 
207
216
 
208
217
  /**
209
- * Nearest ancestor of `cwd` whose `.cowork-flow` entry is a directory, or
210
- * `null` when no such ancestor exists. Mirrors the root resolution inside
211
- * the Python protocol so a project without cowork-flow never pays for an
218
+ * Nearest ancestor of `cwd` whose `.cowork-flow` entry is
219
+ * a directory, or `null` when no such ancestor exists.
220
+ * Mirrors the root resolution inside the Python protocol,
221
+ * so a project without cowork-flow never pays for an
212
222
  * interpreter spawn at all.
213
223
  */
214
224
  export async function findCoworkRoot(cwd) {
@@ -232,11 +242,13 @@ export async function findCoworkRoot(cwd) {
232
242
 
233
243
 
234
244
  /**
235
- * Produce the `<workflow-state>` hook context block for a workspace cwd.
236
- * `full` selects the digest shape: true (default) for the full contract
237
- * block on session-start-like refreshes, false for the single fingerprint
238
- * line on intra-turn refreshes. Empty string means "contribute nothing"
239
- * (no root, hooks disabled, no usable interpreter, or a broken runtime).
245
+ * Produce the `<workflow-state>` hook context block for a
246
+ * workspace cwd. `full` selects the digest shape: true
247
+ * (default) for the full contract block on
248
+ * session-start-like refreshes, false for the single
249
+ * fingerprint line on intra-turn refreshes. Empty string
250
+ * means "contribute nothing" (no root, hooks disabled, no
251
+ * usable interpreter, or a broken runtime).
240
252
  */
241
253
  export async function runWorkflowState(cwd, full = true) {
242
254
  if (hooksDisabled() || !cwd) {
@@ -277,8 +289,9 @@ const EDIT_TOOL_NAMES = new Set(['write', 'edit']);
277
289
 
278
290
 
279
291
  /**
280
- * Path of the file a finished tool call edited, or '' for anything else.
281
- * DSH's fs tools expose `file_path`; other tool surfaces are ignored.
292
+ * Path of the file a finished tool call edited, or '' for
293
+ * anything else. DSH's fs tools expose `file_path`; other
294
+ * tool surfaces are ignored.
282
295
  */
283
296
  export function editedFilePath(exec) {
284
297
  const name = exec && typeof exec.name === 'string' ? exec.name : '';
@@ -292,9 +305,10 @@ export function editedFilePath(exec) {
292
305
 
293
306
 
294
307
  /**
295
- * Editor-phase spec check for one edited file. Returns the single-line
296
- * warning, or '' when there is nothing to say: no root, no interpreter, no
297
- * declaration, a clean run, or a timeout. Never throws.
308
+ * Editor-phase spec check for one edited file. Returns the
309
+ * single-line warning, or '' when there is nothing to say:
310
+ * no root, no interpreter, no declaration, a clean run, or
311
+ * a timeout. Never throws.
298
312
  */
299
313
  export async function runEditSpecCheck(cwd, filePath) {
300
314
  if (hooksDisabled() || !cwd || !filePath) {
@@ -338,9 +352,10 @@ export async function runEditSpecCheck(cwd, filePath) {
338
352
 
339
353
 
340
354
  /**
341
- * One identified user message carrying a plugin notice. DSH's own
342
- * createUserMessage lives in a package this preset deliberately does not
343
- * import, so the shape is built here with node's uuid.
355
+ * One identified user message carrying a plugin notice.
356
+ * DSH's own createUserMessage lives in a package this
357
+ * preset deliberately does not import, so the shape is
358
+ * built here with node's uuid.
344
359
  */
345
360
  function specNoticeMessage(text) {
346
361
  return {
@@ -358,12 +373,10 @@ function specNoticeMessage(text) {
358
373
 
359
374
 
360
375
  export function apply(ctx) {
361
- // One cache entry per agent: { text, inflight, queued, full }.
362
- // `full` records the digest shape the next refresh should use: session
363
- // starts and inbox claims re-inject the full contract block, intra-turn
364
- // refreshes after lifecycle commands only repeat the fingerprint line.
365
- // The WeakMap key is the live Agent object the events and the assembly
366
- // context both carry.
376
+ // One cache entry per agent: { text, inflight, queued,
377
+ // full }. `full` picks the digest shape for the next
378
+ // refresh: true re-injects the contract block, false
379
+ // repeats the fingerprint. Key: the live Agent.
367
380
  const states = new WeakMap();
368
381
 
369
382
  const refresh = (agent, full = true) => {
@@ -378,9 +391,8 @@ export function apply(ctx) {
378
391
  }
379
392
  entry.full = full;
380
393
  if (entry.inflight) {
381
- // A refresh arrived while one was running (e.g. several lifecycle
382
- // commands back to back). Re-run once after it settles so the latest
383
- // on-disk state wins instead of being dropped.
394
+ // A refresh arrived mid-flight; re-run once after it
395
+ // settles so the latest on-disk state wins.
384
396
  entry.queued = true;
385
397
  return;
386
398
  }
@@ -401,11 +413,15 @@ export function apply(ctx) {
401
413
  });
402
414
  };
403
415
 
416
+ // Session-start warm-up. 0.2.0 renamed the event to `agent/created`
417
+ // (payload `{ agent, source, signal? }` — same `payload.agent` shape), so
418
+ // both names are subscribed and each DSH line keeps a warm-up path.
404
419
  ctx.on('agent/session-start', (payload) => refresh(payload && payload.agent, true));
420
+ ctx.on('agent/created', (payload) => refresh(payload && payload.agent, true));
405
421
  ctx.on('agent/inbox/claimed', (payload) => refresh(payload && payload.agent, true));
406
- // Intra-turn refresh: a lifecycle command just settled, so the next prompt
407
- // assembly should already see the new state instead of the stale block.
408
- // Same-session refresh, so only the fingerprint line is repeated.
422
+ // Intra-turn refresh: a lifecycle command just settled, so
423
+ // the next assembly sees the new state, not the stale
424
+ // block. Only the fingerprint line is repeated.
409
425
  ctx.on('tools/result', (exec) => {
410
426
  const agent = exec && exec.agent;
411
427
  if (!agent || !isLifecycleCommand(exec && exec.arguments)) {
@@ -414,9 +430,9 @@ export function apply(ctx) {
414
430
  refresh(agent, false);
415
431
  });
416
432
 
417
- // Editor-phase spec-check: the tool already ran, so this only attaches
418
- // context for the next request and never blocks the call. Waterfall order
419
- // requires awaiting next() before merging downstream decisions.
433
+ // Editor-phase spec-check: the tool already ran, so this
434
+ // only adds context for the next request and never blocks
435
+ // the call. The waterfall awaits next() first.
420
436
  ctx.on('tools/post-execute', async (exec, _result, next) => {
421
437
  const downstream = await next();
422
438
  const agent = exec && exec.agent;
@@ -1,2 +1,2 @@
1
1
  name: Cowork Flow
2
- description: 接入 cowork-flow 流程框架的编码 Agent:任务门禁(task next)、计划绑定、runtime-context 固定子代理与 16 个流程技能(brainstorming / task-planning / task-review / agent-dispatch 等)。
2
+ description: 接入 cowork-flow 流程框架的编码 Agent:任务门禁(task next)、计划绑定、runtime-context 固定子代理;流程技能由项目级 `.agents/skills` 提供(brainstorming / task-planning / task-review / agent-dispatch 等)。
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "cowork-flow",
3
+ "version": "1.7.2",
4
+ "description": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。将 cowork-flow 的完整工作流带入 Kimi Code。",
5
+ "author": {
6
+ "name": "fishlikewater",
7
+ "email": "fishlikewater@126.com"
8
+ },
9
+ "homepage": "https://github.com/fishlikewater/cowork-flow",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "ai-agent",
13
+ "workflow",
14
+ "task-lifecycle",
15
+ "subagents",
16
+ "codex",
17
+ "claude-code",
18
+ "opencode",
19
+ "zcode",
20
+ "qoder",
21
+ "kimi-code",
22
+ "dsh"
23
+ ],
24
+ "skills": "./skills/",
25
+ "sessionStart": {
26
+ "skill": "cowork-flow-bootstrap"
27
+ },
28
+ "interface": {
29
+ "displayName": "Cowork Flow",
30
+ "shortDescription": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。",
31
+ "longDescription": "cowork-flow 给 AI 编码宿主的 agent 提供可执行的工作流:任务生命周期、决策记录、规范契约与独立检查。安装后任务状态由运行时统一维护,多个宿主的会话从同一份事实起步。",
32
+ "developerName": "fishlikewater",
33
+ "websiteURL": "https://github.com/fishlikewater/cowork-flow"
34
+ }
35
+ }
@@ -10,7 +10,10 @@
10
10
  * exits 0 without spawning anything, so the user-level hook never
11
11
  * touches unrelated repositories;
12
12
  * 2. interpreter location (COWORK_FLOW_PYTHON → python3 → python → py -3);
13
- * 3. stdin passthrough to inject.py, stdout/exit forwarding.
13
+ * 3. stdin passthrough to inject.py, stdout forwarded
14
+ * and a failing project runtime absorbed (exit 0,
15
+ * reason on stderr) — the hook row is machine-wide
16
+ * and may meet an older project copy.
14
17
  *
15
18
  * Fail-open by construction: a missing interpreter, a missing runtime, or a
16
19
  * broken project copy all exit 0 with empty stdout instead of blocking the
@@ -103,7 +106,16 @@ function main() {
103
106
  }
104
107
  if (result.error || result.status === null) continue;
105
108
  if (result.stdout) process.stdout.write(result.stdout);
106
- process.exit(result.status);
109
+ // The interpreter ran; its exit status is the project runtime's verdict,
110
+ // not ours. Forwarding it would let a stale project copy abort the submit
111
+ // this hook only decorates.
112
+ if (result.stderr) process.stderr.write(result.stderr);
113
+ if (result.status !== 0) {
114
+ process.stderr.write(
115
+ `cowork-flow kimi-code hook: inject.py exited ${result.status}; skipping injection\n`
116
+ );
117
+ }
118
+ process.exit(0);
107
119
  }
108
120
  // No interpreter could run the entry: stay silent rather than break the
109
121
  // user's submit (fail-open, same contract as the other host shims).
@@ -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.