cowork-flow 0.0.44 → 0.0.46
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/README.md +11 -3
- package/package.json +1 -1
- package/src/cli.js +1 -1
- package/src/commands/install-zcode-plugin.js +165 -21
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/scripts/adapters/cli/subagent.py +3 -0
- package/template/.cowork-flow/scripts/runtime/session_state.py +2 -0
- package/template/.zcode/.zcode-plugin/plugin.json +3 -1
- package/template/.zcode/agents/cowork-check.md +27 -0
- package/template/.zcode/agents/cowork-implement.md +28 -0
- package/template/.zcode/agents/cowork-research.md +21 -0
- package/template/.zcode/hooks/hooks.json +12 -6
- package/template/.zcode/hooks/inject-context.js +40 -13
- package/template/.zcode/hooks/inject-context.selfcheck.mjs +8 -2
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ template/
|
|
|
39
39
|
├── .codex/ # Codex agents / hooks / config
|
|
40
40
|
├── .claude/ # Claude Code settings / agents / hooks
|
|
41
41
|
├── .opencode/ # OpenCode agents / commands / plugins
|
|
42
|
-
├── .zcode/ # ⭐ ZCode 插件(hooks + skills + scaffold instructions)
|
|
42
|
+
├── .zcode/ # ⭐ ZCode 插件(hooks + skills + agents + scaffold instructions)
|
|
43
43
|
└── .cowork-flow/
|
|
44
44
|
├── config.yaml # 项目配置
|
|
45
45
|
├── scripts/ # Python 运行时
|
|
@@ -103,17 +103,25 @@ Skills 维护在 `template/skills/` 唯一源码,`init` / `sync` 时按目录
|
|
|
103
103
|
```bash
|
|
104
104
|
cowork-flow install-zcode-plugin # 安装
|
|
105
105
|
cowork-flow install-zcode-plugin --force # 覆盖已安装
|
|
106
|
+
cowork-flow install-zcode-plugin --force --prune-old # 覆盖并清理旧版本缓存
|
|
106
107
|
```
|
|
107
108
|
|
|
108
|
-
安装到 `~/.zcode/cli/plugins/cache/
|
|
109
|
+
安装到 `~/.zcode/cli/plugins/cache/cowork-flow-local/cowork-flow/<version>/`。安装器会同时写入稳定 marketplace source:`~/.zcode/cli/plugins/cache/marketplaces/cowork-flow-local/marketplace.json`,以及 ZCode 当前使用的活动副本:`~/.zcode/cli/plugins/marketplaces/cowork-flow-local/marketplace.json`。`known_marketplaces.json` 指向稳定 source 目录,避免 ZCode 刷新活动副本时删除自己的 source。
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
安装新版本时,marketplace 中只保留一个 `cowork-flow` entry 并指向最新版本目录;旧版本缓存默认保留,避免正在运行的 ZCode session 仍引用旧插件根目录。需要清理旧版本时显式传 `--prune-old`。
|
|
112
|
+
|
|
113
|
+
ZCode 插件只安装 hook、skills、agents 和轻量说明文件;`.cowork-flow/` 流程文件仍由显式 `cowork-flow init` / `cowork-flow sync` 在项目根目录管理。插件不会通过 scaffold 创建 `.cowork-flow/`,因此不会在多模块项目的模块目录重复落盘流程文件。
|
|
111
114
|
|
|
112
115
|
**Hook 注入内容:**
|
|
113
116
|
- `workflow-state` — 当前任务状态
|
|
114
117
|
- `contract-digest` — 合同摘要(SHA256 fingerprint)
|
|
115
118
|
- `delegated_subtask` — 子代理运行时上下文
|
|
116
119
|
|
|
120
|
+
**插件子代理:**
|
|
121
|
+
- `cowork-implement` — 绑定 runtime context 后执行计划内实现
|
|
122
|
+
- `cowork-check` — 绑定 runtime context 后做独立检查
|
|
123
|
+
- `cowork-research` — 绑定 runtime context 后做只读调研
|
|
124
|
+
|
|
117
125
|
## 任务流程
|
|
118
126
|
|
|
119
127
|
```
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ const HELP = `cowork-flow
|
|
|
12
12
|
|
|
13
13
|
Usage:
|
|
14
14
|
cowork-flow init [target] --platform <codex|opencode|claude-code|all> [--developer <name>] [--dry-run] [--force]
|
|
15
|
-
cowork-flow install-zcode-plugin [--force]
|
|
15
|
+
cowork-flow install-zcode-plugin [--dry-run] [--force] [--prune-old]
|
|
16
16
|
cowork-flow update
|
|
17
17
|
cowork-flow sync [target] [--dry-run] [--force]
|
|
18
18
|
cowork-flow --version
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { cp, mkdir, readFile, writeFile, access, rm } from 'node:fs/promises';
|
|
2
|
-
import { join
|
|
1
|
+
import { cp, mkdir, readFile, writeFile, access, rm, readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
|
|
5
5
|
import { readPackageInfo } from '../lib/package-info.js';
|
|
6
6
|
import { templateRoot } from '../lib/paths.js';
|
|
7
7
|
|
|
8
|
-
const ZCODE_MARKETPLACE = '
|
|
8
|
+
const ZCODE_MARKETPLACE = 'cowork-flow-local';
|
|
9
|
+
const LEGACY_ZCODE_MARKETPLACE = 'zcode-plugins-official';
|
|
9
10
|
const PLUGIN_NAME = 'cowork-flow';
|
|
11
|
+
const LOCAL_MARKETPLACE_DESCRIPTION = 'Local marketplace registration for cowork-flow during local development.';
|
|
10
12
|
|
|
11
13
|
function parseArgs(args) {
|
|
12
14
|
return {
|
|
13
15
|
dryRun: args.includes('--dry-run'),
|
|
14
|
-
force: args.includes('--force')
|
|
16
|
+
force: args.includes('--force'),
|
|
17
|
+
pruneOld: args.includes('--prune-old')
|
|
15
18
|
};
|
|
16
19
|
}
|
|
17
20
|
|
|
@@ -24,9 +27,13 @@ async function pathExists(target) {
|
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
function getZCodePluginsRoot() {
|
|
28
31
|
const base = process.env.ZCODE_HOME || join(homedir(), '.zcode');
|
|
29
|
-
return join(base, 'cli', 'plugins'
|
|
32
|
+
return join(base, 'cli', 'plugins');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function getZCodeCacheDir() {
|
|
36
|
+
return join(getZCodePluginsRoot(), 'cache', ZCODE_MARKETPLACE, PLUGIN_NAME);
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
async function readJsonSafe(path) {
|
|
@@ -46,14 +53,46 @@ function dirname(path) {
|
|
|
46
53
|
return idx >= 0 ? path.slice(0, idx) : path;
|
|
47
54
|
}
|
|
48
55
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
function normalizedPath(path) {
|
|
57
|
+
return path.split('\\').join('/');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function marketplacePaths(pluginsRoot) {
|
|
61
|
+
return {
|
|
62
|
+
activeMarketplacePath: join(pluginsRoot, 'marketplaces', ZCODE_MARKETPLACE, 'marketplace.json'),
|
|
63
|
+
sourceMarketplacePath: join(pluginsRoot, 'cache', 'marketplaces', ZCODE_MARKETPLACE, 'marketplace.json')
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function updateMarketplace(pluginsRoot, cacheRoot, version, manifest = {}) {
|
|
68
|
+
const { activeMarketplacePath, sourceMarketplacePath } = marketplacePaths(pluginsRoot);
|
|
69
|
+
const market = (await readJsonSafe(sourceMarketplacePath))
|
|
70
|
+
|| (await readJsonSafe(activeMarketplacePath))
|
|
71
|
+
|| {
|
|
72
|
+
name: ZCODE_MARKETPLACE,
|
|
73
|
+
description: LOCAL_MARKETPLACE_DESCRIPTION,
|
|
74
|
+
plugins: [],
|
|
75
|
+
version: 1
|
|
76
|
+
};
|
|
77
|
+
const pluginPath = normalizedPath(join(cacheRoot, version));
|
|
78
|
+
|
|
79
|
+
market.name = ZCODE_MARKETPLACE;
|
|
80
|
+
market.description = market.description || LOCAL_MARKETPLACE_DESCRIPTION;
|
|
81
|
+
market.version = 1;
|
|
82
|
+
if (!Array.isArray(market.plugins)) {
|
|
83
|
+
market.plugins = [];
|
|
84
|
+
}
|
|
52
85
|
|
|
53
86
|
const entry = {
|
|
54
|
-
|
|
87
|
+
author: manifest.author || { name: 'fisklikewater' },
|
|
88
|
+
category: 'developer-tools',
|
|
89
|
+
description: manifest.description || 'cowork-flow task lifecycle, hooks, skills, and fixed subagents for ZCode.',
|
|
90
|
+
license: manifest.license || 'MIT',
|
|
55
91
|
name: PLUGIN_NAME,
|
|
56
|
-
source:
|
|
92
|
+
source: {
|
|
93
|
+
source: 'directory',
|
|
94
|
+
path: pluginPath
|
|
95
|
+
},
|
|
57
96
|
version
|
|
58
97
|
};
|
|
59
98
|
|
|
@@ -64,15 +103,99 @@ async function updateMarketplace(cacheRoot, version) {
|
|
|
64
103
|
market.plugins.push(entry);
|
|
65
104
|
}
|
|
66
105
|
|
|
67
|
-
|
|
68
|
-
|
|
106
|
+
for (const targetPath of [sourceMarketplacePath, activeMarketplacePath]) {
|
|
107
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
108
|
+
await writeJsonAtomic(targetPath, market);
|
|
109
|
+
}
|
|
110
|
+
return { activeMarketplacePath, sourceMarketplacePath };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function updateKnownMarketplaces(pluginsRoot) {
|
|
114
|
+
const knownPath = join(pluginsRoot, 'known_marketplaces.json');
|
|
115
|
+
const known = (await readJsonSafe(knownPath)) || {
|
|
116
|
+
version: 1,
|
|
117
|
+
marketplaces: []
|
|
118
|
+
};
|
|
119
|
+
const now = new Date().toISOString();
|
|
120
|
+
const marketplaceDir = join(pluginsRoot, 'cache', 'marketplaces', ZCODE_MARKETPLACE);
|
|
121
|
+
const existingIdx = Array.isArray(known.marketplaces)
|
|
122
|
+
? known.marketplaces.findIndex((marketplace) => marketplace.id === ZCODE_MARKETPLACE)
|
|
123
|
+
: -1;
|
|
124
|
+
const existing = existingIdx >= 0 ? known.marketplaces[existingIdx] : {};
|
|
125
|
+
const entry = {
|
|
126
|
+
id: ZCODE_MARKETPLACE,
|
|
127
|
+
source: {
|
|
128
|
+
source: 'directory',
|
|
129
|
+
path: normalizedPath(marketplaceDir)
|
|
130
|
+
},
|
|
131
|
+
name: ZCODE_MARKETPLACE,
|
|
132
|
+
description: LOCAL_MARKETPLACE_DESCRIPTION,
|
|
133
|
+
addedAt: existing.addedAt || now,
|
|
134
|
+
pluginCount: 1,
|
|
135
|
+
lastUpdated: now
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
known.version = 1;
|
|
139
|
+
if (!Array.isArray(known.marketplaces)) {
|
|
140
|
+
known.marketplaces = [];
|
|
141
|
+
}
|
|
142
|
+
if (existingIdx >= 0) {
|
|
143
|
+
known.marketplaces[existingIdx] = entry;
|
|
144
|
+
} else {
|
|
145
|
+
known.marketplaces.push(entry);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
await mkdir(dirname(knownPath), { recursive: true });
|
|
149
|
+
await writeJsonAtomic(knownPath, known);
|
|
150
|
+
return knownPath;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function removeLegacyMarketplaceEntry(pluginsRoot) {
|
|
154
|
+
const legacyPath = join(
|
|
155
|
+
pluginsRoot,
|
|
156
|
+
'marketplaces',
|
|
157
|
+
LEGACY_ZCODE_MARKETPLACE,
|
|
158
|
+
'marketplace.json'
|
|
159
|
+
);
|
|
160
|
+
const legacy = await readJsonSafe(legacyPath);
|
|
161
|
+
if (!legacy || !Array.isArray(legacy.plugins)) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const filteredPlugins = legacy.plugins.filter((plugin) => plugin.name !== PLUGIN_NAME);
|
|
166
|
+
if (filteredPlugins.length === legacy.plugins.length) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
legacy.plugins = filteredPlugins;
|
|
171
|
+
await writeJsonAtomic(legacyPath, legacy);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function pruneOldVersions(cacheRoot, currentVersion) {
|
|
176
|
+
if (!(await pathExists(cacheRoot))) {
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const removed = [];
|
|
181
|
+
const entries = await readdir(cacheRoot, { withFileTypes: true });
|
|
182
|
+
for (const entry of entries) {
|
|
183
|
+
if (!entry.isDirectory() || entry.name === currentVersion) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const target = join(cacheRoot, entry.name);
|
|
187
|
+
await rm(target, { recursive: true, force: true });
|
|
188
|
+
removed.push(entry.name);
|
|
189
|
+
}
|
|
190
|
+
return removed;
|
|
69
191
|
}
|
|
70
192
|
|
|
71
193
|
export async function runInstallZCodePlugin(args = []) {
|
|
72
|
-
const { dryRun, force } = parseArgs(args);
|
|
194
|
+
const { dryRun, force, pruneOld } = parseArgs(args);
|
|
73
195
|
const pluginSrc = join(templateRoot, ".zcode");
|
|
74
196
|
const skillsSrc = join(templateRoot, "skills");
|
|
75
197
|
const { version } = await readPackageInfo();
|
|
198
|
+
const manifest = (await readJsonSafe(join(pluginSrc, '.zcode-plugin', 'plugin.json'))) || {};
|
|
76
199
|
|
|
77
200
|
if (!(await pathExists(pluginSrc))) {
|
|
78
201
|
throw new Error(`ZCode plugin source missing at ${pluginSrc}. Reinstall cowork-flow.`);
|
|
@@ -81,19 +204,32 @@ export async function runInstallZCodePlugin(args = []) {
|
|
|
81
204
|
throw new Error(`Skills source missing at ${skillsSrc}. Reinstall cowork-flow.`);
|
|
82
205
|
}
|
|
83
206
|
|
|
207
|
+
const pluginsRoot = getZCodePluginsRoot();
|
|
84
208
|
const cacheRoot = await getZCodeCacheDir();
|
|
85
209
|
const destDir = join(cacheRoot, version);
|
|
86
210
|
|
|
87
|
-
if (!force && (await pathExists(destDir))) {
|
|
88
|
-
console.log(`cowork-flow ZCode plugin already installed at ${destDir}`);
|
|
89
|
-
console.log('Use --force to overwrite.');
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
211
|
if (dryRun) {
|
|
94
212
|
console.log(`[dry-run] Would install ZCode plugin:`);
|
|
95
213
|
console.log(` Plugin: ${pluginSrc} -> ${destDir}`);
|
|
96
214
|
console.log(` Skills: ${skillsSrc} -> ${join(destDir, 'skills')}`);
|
|
215
|
+
console.log(` Marketplace source: ${join(pluginsRoot, 'cache', 'marketplaces', ZCODE_MARKETPLACE, 'marketplace.json')}`);
|
|
216
|
+
console.log(` Active marketplace: ${join(pluginsRoot, 'marketplaces', ZCODE_MARKETPLACE, 'marketplace.json')}`);
|
|
217
|
+
console.log(` Known marketplaces: ${join(pluginsRoot, 'known_marketplaces.json')}`);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (!force && (await pathExists(destDir))) {
|
|
222
|
+
await updateMarketplace(pluginsRoot, cacheRoot, version, manifest);
|
|
223
|
+
await updateKnownMarketplaces(pluginsRoot);
|
|
224
|
+
await removeLegacyMarketplaceEntry(pluginsRoot);
|
|
225
|
+
if (pruneOld) {
|
|
226
|
+
const removed = await pruneOldVersions(cacheRoot, version);
|
|
227
|
+
if (removed.length > 0) {
|
|
228
|
+
console.log(`Pruned old cowork-flow ZCode plugin versions: ${removed.join(', ')}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
console.log(`cowork-flow ZCode plugin already installed at ${destDir}`);
|
|
232
|
+
console.log('Use --force to overwrite.');
|
|
97
233
|
return;
|
|
98
234
|
}
|
|
99
235
|
|
|
@@ -121,7 +257,15 @@ export async function runInstallZCodePlugin(args = []) {
|
|
|
121
257
|
// Copy canonical skills into the plugin cache so plugin.json "skills" resolves.
|
|
122
258
|
await cp(skillsSrc, join(destDir, "skills"), { recursive: true, force: true });
|
|
123
259
|
|
|
124
|
-
await updateMarketplace(cacheRoot, version);
|
|
260
|
+
await updateMarketplace(pluginsRoot, cacheRoot, version, manifest);
|
|
261
|
+
await updateKnownMarketplaces(pluginsRoot);
|
|
262
|
+
await removeLegacyMarketplaceEntry(pluginsRoot);
|
|
263
|
+
if (pruneOld) {
|
|
264
|
+
const removed = await pruneOldVersions(cacheRoot, version);
|
|
265
|
+
if (removed.length > 0) {
|
|
266
|
+
console.log(`Pruned old cowork-flow ZCode plugin versions: ${removed.join(', ')}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
125
269
|
|
|
126
270
|
// Write seed file for install tracking
|
|
127
271
|
await writeJsonAtomic(join(destDir, ".zcode-plugin-seed.json"), {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.46
|
|
@@ -72,6 +72,8 @@ def _detect_host() -> str:
|
|
|
72
72
|
return "claude-code"
|
|
73
73
|
if env.get("CODEX_SESSION_ID") or env.get("CODEX_THREAD_ID"):
|
|
74
74
|
return "codex"
|
|
75
|
+
if env.get("ZCODE_SESSION_ID"):
|
|
76
|
+
return "zcode"
|
|
75
77
|
if env.get("OPENCODE_SESSION_ID"):
|
|
76
78
|
return "opencode"
|
|
77
79
|
return "codex"
|
|
@@ -82,6 +84,7 @@ def _detect_adapter(host: str) -> str:
|
|
|
82
84
|
"claude-code": "claude-code.hooks",
|
|
83
85
|
"codex": "codex.spawn_agent",
|
|
84
86
|
"opencode": "opencode.task",
|
|
87
|
+
"zcode": "zcode.plugin",
|
|
85
88
|
}
|
|
86
89
|
return adapters.get(host, "codex.spawn_agent")
|
|
87
90
|
|
|
@@ -69,6 +69,7 @@ def _resolve_env_context_key() -> str | None:
|
|
|
69
69
|
return _sanitize(explicit)
|
|
70
70
|
|
|
71
71
|
for prefix, env_name in (
|
|
72
|
+
("zcode", "ZCODE_SESSION_ID"),
|
|
72
73
|
("opencode", "OPENCODE_SESSION_ID"),
|
|
73
74
|
("claude", "CLAUDE_SESSION_ID"),
|
|
74
75
|
("claude", "CLAUDE_CODE_SESSION_ID"),
|
|
@@ -90,6 +91,7 @@ def _resolve_input_context_key(values: Mapping[str, object] | None) -> str | Non
|
|
|
90
91
|
return _sanitize(explicit)
|
|
91
92
|
|
|
92
93
|
for prefix, names in (
|
|
94
|
+
("zcode", ("ZCODE_SESSION_ID", "zcode_session_id")),
|
|
93
95
|
("opencode", ("OPENCODE_SESSION_ID", "opencode_session_id", "sessionID", "sessionId")),
|
|
94
96
|
("claude", ("CLAUDE_SESSION_ID", "claude_session_id", "CLAUDE_CODE_SESSION_ID", "claude_code_session_id")),
|
|
95
97
|
("codex", ("CODEX_SESSION_ID", "codex_session_id", "session_id")),
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cowork-flow",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.46",
|
|
4
4
|
"description": "AI 协作工作流引擎:任务生命周期、子代理调度、门禁与状态注入。将 cowork-flow 的完整工作流带入 ZCode。",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "fisklikewater"
|
|
7
7
|
},
|
|
8
8
|
"license": "MIT",
|
|
9
|
+
"hooks": "hooks/hooks.json",
|
|
10
|
+
"agents": "agents",
|
|
9
11
|
"skills": "skills"
|
|
10
12
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-check
|
|
3
|
+
description: Cowork-flow check fixed subagent for independent implementation review with runtime context binding.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are the `cowork-check` fixed subagent for ZCode.
|
|
7
|
+
|
|
8
|
+
Read and apply these plugin Skills before review work:
|
|
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`
|
|
14
|
+
|
|
15
|
+
Execution:
|
|
16
|
+
|
|
17
|
+
1. Follow `agent-dispatch` to bind runtime context. If binding fails, report `needs_context` and stop.
|
|
18
|
+
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.
|
|
19
|
+
3. Apply `task-review` to verify scope, tests, specs, advisory facts, lifecycle facts, and Definition of Done coverage.
|
|
20
|
+
4. Fix only clearly in-scope issues; otherwise report findings with acceptance IDs, resolutions, `test_intent_review` (test intent review), and verification commands.
|
|
21
|
+
|
|
22
|
+
Rules:
|
|
23
|
+
|
|
24
|
+
- Do not invoke subagents.
|
|
25
|
+
- Do not run task start, finish, archive, unscoped resume, commit, or push.
|
|
26
|
+
- Treat backend/frontend natural-language specs as checklist context, not dynamic hard validators.
|
|
27
|
+
- Do not accept shallow tests that would still pass when target behavior breaks.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-implement
|
|
3
|
+
description: Cowork-flow implementation fixed subagent for bounded code changes with runtime context binding.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are the `cowork-implement` fixed subagent for ZCode.
|
|
7
|
+
|
|
8
|
+
Read and apply these plugin Skills before task work:
|
|
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
|
|
14
|
+
|
|
15
|
+
Execution:
|
|
16
|
+
|
|
17
|
+
1. Follow `agent-dispatch` to bind runtime context. If binding fails, report `needs_context` and stop.
|
|
18
|
+
2. Read the task directory, `decision-anchor.md`, optional `info.md`, `implement.jsonl`, every JSONL `file` entry, and the linked plan.
|
|
19
|
+
3. Follow the plan in order, keeping edits inside assigned scope.
|
|
20
|
+
4. Use project specs and quality sources as checklist context; runtime gates remain kernel-owned commands.
|
|
21
|
+
5. Run planned verification and report changed files, acceptance IDs, verification commands, and spec updates or why none were needed.
|
|
22
|
+
|
|
23
|
+
Rules:
|
|
24
|
+
|
|
25
|
+
- Do not invoke subagents.
|
|
26
|
+
- Do not run task start, finish, archive, unscoped resume, commit, or push.
|
|
27
|
+
- Do not create task-local review artifacts, `tdd.jsonl`, or TDD evidence records in `check.jsonl`.
|
|
28
|
+
- Do not claim completion without current verification.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cowork-research
|
|
3
|
+
description: Cowork-flow research-only fixed subagent for sourced investigation with runtime context binding.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are the `cowork-research` fixed subagent for ZCode.
|
|
7
|
+
|
|
8
|
+
Read and apply `skills/agent-dispatch/SKILL.md` before research work.
|
|
9
|
+
|
|
10
|
+
Execution:
|
|
11
|
+
|
|
12
|
+
1. Follow `agent-dispatch` to bind runtime context. If binding fails, report `needs_context` and stop.
|
|
13
|
+
2. Read the task directory, assignment, and prompt-named context.
|
|
14
|
+
3. Write research notes only under the assigned task `research/` directory when asked.
|
|
15
|
+
4. Report sourced findings, uncertainty, and recommended next action.
|
|
16
|
+
|
|
17
|
+
Rules:
|
|
18
|
+
|
|
19
|
+
- Do not invoke subagents.
|
|
20
|
+
- Do not edit code, specs, task state, or git state.
|
|
21
|
+
- Do not run task start, finish, archive, unscoped resume, commit, or push.
|
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
"matcher": "startup|clear|compact",
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
|
-
"type": "
|
|
9
|
-
"command": "node
|
|
10
|
-
"
|
|
8
|
+
"type": "process",
|
|
9
|
+
"command": "node",
|
|
10
|
+
"args": [
|
|
11
|
+
"${ZCODE_PLUGIN_ROOT}/hooks/inject-context.js"
|
|
12
|
+
],
|
|
13
|
+
"timeoutMs": 5000
|
|
11
14
|
}
|
|
12
15
|
]
|
|
13
16
|
}
|
|
@@ -16,9 +19,12 @@
|
|
|
16
19
|
{
|
|
17
20
|
"hooks": [
|
|
18
21
|
{
|
|
19
|
-
"type": "
|
|
20
|
-
"command": "node
|
|
21
|
-
"
|
|
22
|
+
"type": "process",
|
|
23
|
+
"command": "node",
|
|
24
|
+
"args": [
|
|
25
|
+
"${ZCODE_PLUGIN_ROOT}/hooks/inject-context.js"
|
|
26
|
+
],
|
|
27
|
+
"timeoutMs": 5000
|
|
22
28
|
}
|
|
23
29
|
]
|
|
24
30
|
}
|
|
@@ -29,7 +29,22 @@ const DEFAULT_CONTRACT_REGISTRY = {
|
|
|
29
29
|
],
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
function
|
|
32
|
+
function readHookInput() {
|
|
33
|
+
if (process.stdin.isTTY) return {};
|
|
34
|
+
try {
|
|
35
|
+
const raw = readFileSync(0, "utf8").trim();
|
|
36
|
+
if (!raw) return {};
|
|
37
|
+
const parsed = JSON.parse(raw);
|
|
38
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
39
|
+
} catch {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function detectEventName(input) {
|
|
45
|
+
if (typeof input?.hook_event_name === "string" && input.hook_event_name.trim()) {
|
|
46
|
+
return input.hook_event_name.trim();
|
|
47
|
+
}
|
|
33
48
|
if (process.env.CURSOR_PLUGIN_ROOT) return "SessionStart";
|
|
34
49
|
return "UserPromptSubmit";
|
|
35
50
|
}
|
|
@@ -43,12 +58,9 @@ function outputFormat() {
|
|
|
43
58
|
// ---------------------------------------------------------------------------
|
|
44
59
|
// Find project root
|
|
45
60
|
// ---------------------------------------------------------------------------
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return existsSync(join(envDir, DIR_WORKFLOW)) ? envDir : null;
|
|
50
|
-
}
|
|
51
|
-
let current = process.cwd();
|
|
61
|
+
function findWorkflowRoot(startDir) {
|
|
62
|
+
if (typeof startDir !== "string" || !startDir.trim()) return null;
|
|
63
|
+
let current = startDir;
|
|
52
64
|
const root = dirname(current);
|
|
53
65
|
while (current !== root) {
|
|
54
66
|
if (existsSync(join(current, DIR_WORKFLOW))) return current;
|
|
@@ -57,6 +69,20 @@ function findProjectRoot() {
|
|
|
57
69
|
return existsSync(join(current, DIR_WORKFLOW)) ? current : null;
|
|
58
70
|
}
|
|
59
71
|
|
|
72
|
+
function findProjectRoot(input) {
|
|
73
|
+
const candidates = [
|
|
74
|
+
input?.cwd,
|
|
75
|
+
process.env.ZCODE_PROJECT_DIR,
|
|
76
|
+
process.env.CLAUDE_PROJECT_DIR,
|
|
77
|
+
process.cwd(),
|
|
78
|
+
];
|
|
79
|
+
for (const candidate of candidates) {
|
|
80
|
+
const root = findWorkflowRoot(candidate);
|
|
81
|
+
if (root) return root;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
60
86
|
// ---------------------------------------------------------------------------
|
|
61
87
|
// Read active task from .cowork-flow/.runtime/sessions/
|
|
62
88
|
// ---------------------------------------------------------------------------
|
|
@@ -289,14 +315,15 @@ function main() {
|
|
|
289
315
|
process.exit(0);
|
|
290
316
|
}
|
|
291
317
|
|
|
292
|
-
const
|
|
318
|
+
const input = readHookInput();
|
|
319
|
+
const event = detectEventName(input);
|
|
293
320
|
const format = outputFormat();
|
|
294
|
-
const repoRoot = findProjectRoot();
|
|
321
|
+
const repoRoot = findProjectRoot(input);
|
|
295
322
|
|
|
296
323
|
let context;
|
|
297
324
|
|
|
298
|
-
const envDir = process.env.ZCODE_PROJECT_DIR;
|
|
299
|
-
const effectiveRoot = repoRoot || (envDir
|
|
325
|
+
const envDir = process.env.ZCODE_PROJECT_DIR || process.env.CLAUDE_PROJECT_DIR;
|
|
326
|
+
const effectiveRoot = repoRoot || findWorkflowRoot(envDir);
|
|
300
327
|
|
|
301
328
|
if (!effectiveRoot) {
|
|
302
329
|
context = `<workflow-state>
|
|
@@ -308,7 +335,7 @@ Source: cowork-flow-plugin
|
|
|
308
335
|
</workflow-state>`;
|
|
309
336
|
} else {
|
|
310
337
|
// PRIORITY 1: Detect delegated_subtask from runtime context
|
|
311
|
-
const userPrompt = "";
|
|
338
|
+
const userPrompt = typeof input.prompt === "string" ? input.prompt : "";
|
|
312
339
|
const delegated = detectDelegatedSubtask(effectiveRoot, userPrompt);
|
|
313
340
|
if (delegated) {
|
|
314
341
|
context = buildDelegatedSubtask(delegated.contextId, delegated.ctx);
|
|
@@ -321,7 +348,7 @@ Source: cowork-flow-plugin
|
|
|
321
348
|
}
|
|
322
349
|
|
|
323
350
|
// Inject contract digest
|
|
324
|
-
const rootForDigest = effectiveRoot || envDir;
|
|
351
|
+
const rootForDigest = effectiveRoot || envDir || input.cwd;
|
|
325
352
|
if (rootForDigest) {
|
|
326
353
|
const contractDigest = buildContractDigest(rootForDigest);
|
|
327
354
|
context = `${contractDigest}\n\n${context}`;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { existsSync, writeFileSync, mkdirSync, rmSync } from "fs";
|
|
7
7
|
import { join, dirname } from "path";
|
|
8
|
-
import {
|
|
8
|
+
import { spawnSync } from "child_process";
|
|
9
9
|
import assert from "assert/strict";
|
|
10
10
|
|
|
11
11
|
const tmpRoot = join(import.meta.dirname, ".selfcheck-tmp");
|
|
@@ -27,12 +27,18 @@ function test(name, fn) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function runHook(env = {}, stdin) {
|
|
30
|
-
|
|
30
|
+
const result = spawnSync(process.execPath, [hookScript], {
|
|
31
31
|
env: { ...process.env, ...env },
|
|
32
32
|
encoding: "utf8",
|
|
33
33
|
cwd: import.meta.dirname,
|
|
34
34
|
input: stdin,
|
|
35
35
|
});
|
|
36
|
+
if (result.status !== 0) {
|
|
37
|
+
const error = new Error(result.stderr || `hook exited with ${result.status}`);
|
|
38
|
+
error.status = result.status;
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
return result.stdout;
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
function writeProjectFile(repoRoot, relativePath, content) {
|