cowork-flow 0.0.30 → 0.0.32
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 +116 -284
- package/package.json +2 -2
- package/src/cli.js +6 -0
- package/src/commands/install-zcode-plugin.js +125 -0
- package/src/lib/copy-template.js +54 -2
- package/src/lib/platforms.js +27 -2
- package/template/.claude/agents/cowork-check.md +4 -3
- package/template/.claude/agents/cowork-implement.md +2 -1
- package/template/.codex/agents/cowork-check.toml +11 -3
- package/template/.codex/agents/cowork-implement.toml +8 -1
- package/template/.codex/hooks/inject-workflow-state.py +0 -0
- package/template/.codex/hooks.json +1 -1
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/run +3 -3
- package/template/.cowork-flow/run.cmd +88 -88
- package/template/.cowork-flow/scripts/commands/doctor.py +5 -42
- package/template/.cowork-flow/scripts/common/gates/validate_coding_standards.py +254 -132
- package/template/.cowork-flow/scripts/common/gates/validate_rules.py +13 -5
- package/template/.cowork-flow/spec/contracts/workflow-state-templates.md +2 -2
- package/template/.opencode/agents/cowork-check.md +1 -1
- package/template/.opencode/agents/cowork-implement.md +9 -7
- package/template/.zcode/.zcode-plugin/plugin.json +10 -0
- package/template/.zcode/hooks/hooks.json +27 -0
- package/template/.zcode/hooks/inject-context.js +397 -0
- package/template/.zcode/hooks/inject-context.selfcheck.mjs +191 -0
- package/template/.zcode/hooks/runtime/run +58 -0
- package/template/.zcode/hooks/runtime/run.cmd +37 -0
- package/template/.zcode/hooks/runtime/scripts/commands/__init__.py +1 -0
- package/template/.zcode/hooks/runtime/scripts/commands/_bootstrap.py +10 -0
- package/template/.zcode/hooks/runtime/scripts/commands/add_session.py +452 -0
- package/template/.zcode/hooks/runtime/scripts/commands/change.py +412 -0
- package/template/.zcode/hooks/runtime/scripts/commands/doctor.py +471 -0
- package/template/.zcode/hooks/runtime/scripts/commands/get_context.py +20 -0
- package/template/.zcode/hooks/runtime/scripts/commands/get_developer.py +30 -0
- package/template/.zcode/hooks/runtime/scripts/commands/init_developer.py +55 -0
- package/template/.zcode/hooks/runtime/scripts/commands/party_mode_v2.py +1166 -0
- package/template/.zcode/hooks/runtime/scripts/commands/resume.py +62 -0
- package/template/.zcode/hooks/runtime/scripts/commands/subagent.py +321 -0
- package/template/.zcode/hooks/runtime/scripts/commands/task.py +2040 -0
- package/template/.zcode/hooks/runtime/scripts/common/__init__.py +79 -0
- package/template/.zcode/hooks/runtime/scripts/common/core/__init__.py +1 -0
- package/template/.zcode/hooks/runtime/scripts/common/core/config.py +242 -0
- package/template/.zcode/hooks/runtime/scripts/common/core/developer.py +205 -0
- package/template/.zcode/hooks/runtime/scripts/common/core/execution_context.py +385 -0
- package/template/.zcode/hooks/runtime/scripts/common/core/files.py +37 -0
- package/template/.zcode/hooks/runtime/scripts/common/core/paths.py +239 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/__init__.py +1 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/coding_standards.py +210 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/gates.py +66 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/tdd_evidence.py +367 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/test_intent.py +266 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/validate_coding_standards.py +181 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/validate_coding_standaries.py +316 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/validate_implementation.py +243 -0
- package/template/.zcode/hooks/runtime/scripts/common/gates/validate_rules.py +473 -0
- package/template/.zcode/hooks/runtime/scripts/common/git/__init__.py +1 -0
- package/template/.zcode/hooks/runtime/scripts/common/git/git_context.py +765 -0
- package/template/.zcode/hooks/runtime/scripts/common/git/git_snapshot.py +83 -0
- package/template/.zcode/hooks/runtime/scripts/common/task/__init__.py +1 -0
- package/template/.zcode/hooks/runtime/scripts/common/task/active_task.py +403 -0
- package/template/.zcode/hooks/runtime/scripts/common/task/archive_utils.py +72 -0
- package/template/.zcode/hooks/runtime/scripts/common/task/readiness.py +249 -0
- package/template/.zcode/hooks/runtime/scripts/common/task/state_machine.py +56 -0
- package/template/.zcode/hooks/runtime/scripts/common/task/task_utils.py +187 -0
- package/template/.zcode/hooks/runtime/scripts/run.py +138 -0
- package/template/.zcode/scaffold/.cowork-flow/.version +1 -0
- package/template/.zcode/scaffold/.cowork-flow/config.yaml +65 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/backend/database-guidelines.md +23 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/backend/directory-structure.md +27 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/backend/encoding-guidelines.md +27 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/backend/error-handling.md +20 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/backend/index.md +40 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/backend/logging-guidelines.md +20 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/backend/quality-guidelines.md +25 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/capabilities.md +34 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/index.md +11 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/party-mode-v2-board.md +68 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/subagent-dispatch.md +85 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/workflow-state-templates.md +72 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/frontend/component-guidelines.md +19 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/frontend/directory-structure.md +18 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/frontend/hook-guidelines.md +17 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/frontend/index.md +39 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/frontend/quality-guidelines.md +25 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/frontend/state-management.md +18 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/frontend/type-safety.md +18 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/game/asset-pipeline.md +53 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/game/engine-guidelines.md +43 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/game/index.md +23 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/game/multiplayer-guidelines.md +44 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/game/performance-guidelines.md +58 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/guides/code-reuse-thinking-guide.md +26 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/guides/cross-layer-thinking-guide.md +21 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/guides/index.md +31 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/guides/pre-implementation-checklist.md +15 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/index.md +15 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/runtime/contract-registry.json +68 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/runtime/index.md +10 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/runtime/rules.json +173 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/schemas/adapter.schema.json +128 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/schemas/index.md +10 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/schemas/party-mode-v2-actions.schema.json +90 -0
- package/template/.zcode/scaffold/.cowork-flow/spec/schemas/rules.schema.json +80 -0
- package/template/.zcode/scaffold/.cowork-flow/workflow.md +247 -0
- package/template/.zcode/scaffold/AGENTS.md +126 -0
- package/template/.zcode/scaffold/CLAUDE.md +5 -0
- package/template/AGENTS.md +22 -14
- package/template/{.agents/skills → skills}/before-dev/SKILL.md +6 -5
- package/template/{.claude/skills → skills}/writing-plans/SKILL.md +23 -1
- package/template/.agents/skills/writing-plans/SKILL.md +0 -71
- package/template/.claude/skills/before-dev/SKILL.md +0 -144
- package/template/.claude/skills/brainstorming/SKILL.md +0 -32
- package/template/.claude/skills/break-loop/SKILL.md +0 -26
- package/template/.claude/skills/check/SKILL.md +0 -35
- package/template/.claude/skills/continue/SKILL.md +0 -29
- package/template/.claude/skills/finish-work/SKILL.md +0 -32
- package/template/.claude/skills/game-design/SKILL.md +0 -39
- package/template/.claude/skills/meta/SKILL.md +0 -30
- package/template/.claude/skills/party-mode/SKILL.md +0 -151
- package/template/.claude/skills/party-mode-v2/SKILL.md +0 -75
- package/template/.claude/skills/python-design/SKILL.md +0 -27
- package/template/.claude/skills/start/SKILL.md +0 -78
- package/template/.claude/skills/tdd/SKILL.md +0 -61
- package/template/.claude/skills/update-spec/SKILL.md +0 -39
- /package/template/{.agents/skills → skills}/brainstorming/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/break-loop/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/check/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/continue/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/finish-work/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/game-design/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/meta/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/party-mode/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/party-mode-v2/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/python-design/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/start/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/tdd/SKILL.md +0 -0
- /package/template/{.agents/skills → skills}/update-spec/SKILL.md +0 -0
package/src/lib/copy-template.js
CHANGED
|
@@ -3,7 +3,7 @@ import { access, chmod, copyFile, mkdir, readFile, readdir, rm, stat, writeFile
|
|
|
3
3
|
import { dirname, join, relative } from 'node:path';
|
|
4
4
|
|
|
5
5
|
import { templateRoot } from './paths.js';
|
|
6
|
-
import { shouldIncludeForPlatforms } from './platforms.js';
|
|
6
|
+
import { shouldIncludeForPlatforms, skillDestinationForPlatform } from './platforms.js';
|
|
7
7
|
|
|
8
8
|
async function pathExists(path) {
|
|
9
9
|
try {
|
|
@@ -41,6 +41,7 @@ export async function buildInitPlan(targetDir, options = {}) {
|
|
|
41
41
|
const files = await listFiles(templateRoot);
|
|
42
42
|
const actions = [];
|
|
43
43
|
const platforms = options.platforms ?? [];
|
|
44
|
+
const seen = new Set();
|
|
44
45
|
|
|
45
46
|
for (const file of files) {
|
|
46
47
|
if (!shouldIncludeForPlatforms(file, platforms)) {
|
|
@@ -54,6 +55,7 @@ export async function buildInitPlan(targetDir, options = {}) {
|
|
|
54
55
|
|
|
55
56
|
const source = join(templateRoot, file);
|
|
56
57
|
const destination = join(targetDir, file);
|
|
58
|
+
seen.add(destination);
|
|
57
59
|
const exists = await pathExists(destination);
|
|
58
60
|
const action = exists
|
|
59
61
|
? (options.force && templatePath !== '.cowork-flow/.developer' ? 'update' : 'skip')
|
|
@@ -61,6 +63,29 @@ export async function buildInitPlan(targetDir, options = {}) {
|
|
|
61
63
|
actions.push({ action, source, destination, relativePath: file });
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
// Inject per-platform skills directories from the canonical template/skills/.
|
|
67
|
+
const skillsSrc = join(templateRoot, 'skills');
|
|
68
|
+
if (await pathExists(skillsSrc)) {
|
|
69
|
+
const skillEntries = await readdir(skillsSrc, { withFileTypes: true });
|
|
70
|
+
for (const entry of skillEntries) {
|
|
71
|
+
if (!entry.isDirectory()) continue;
|
|
72
|
+
const skillName = entry.name;
|
|
73
|
+
for (const platform of platforms) {
|
|
74
|
+
const destBase = skillDestinationForPlatform(platform);
|
|
75
|
+
if (!destBase) continue;
|
|
76
|
+
const dest = join(targetDir, destBase, skillName, 'SKILL.md');
|
|
77
|
+
if (seen.has(dest)) continue;
|
|
78
|
+
seen.add(dest);
|
|
79
|
+
actions.push({
|
|
80
|
+
action: (await pathExists(dest)) ? 'skip' : 'create',
|
|
81
|
+
source: join(skillsSrc, skillName, 'SKILL.md'),
|
|
82
|
+
destination: dest,
|
|
83
|
+
relativePath: join(destBase, skillName, 'SKILL.md')
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
64
89
|
const versionDestination = join(targetDir, '.cowork-flow', '.version');
|
|
65
90
|
const versionExists = await pathExists(versionDestination);
|
|
66
91
|
actions.push({
|
|
@@ -206,18 +231,21 @@ export async function buildSyncPlan(targetDir, options = {}) {
|
|
|
206
231
|
const files = await listFiles(templateRoot);
|
|
207
232
|
const actions = [];
|
|
208
233
|
const platforms = options.platforms ?? await detectInstalledPlatforms(targetDir);
|
|
234
|
+
const seen = new Set();
|
|
209
235
|
|
|
210
236
|
for (const file of files) {
|
|
211
237
|
if (!shouldIncludeForPlatforms(file, platforms)) {
|
|
212
238
|
continue;
|
|
213
239
|
}
|
|
214
240
|
|
|
241
|
+
const destination = join(targetDir, file);
|
|
242
|
+
seen.add(destination);
|
|
243
|
+
|
|
215
244
|
if (toTemplatePath(file) === '.cowork-flow/.version') {
|
|
216
245
|
continue;
|
|
217
246
|
}
|
|
218
247
|
|
|
219
248
|
const source = join(templateRoot, file);
|
|
220
|
-
const destination = join(targetDir, file);
|
|
221
249
|
const exists = await pathExists(destination);
|
|
222
250
|
if (file === 'AGENTS.md' || file === 'CLAUDE.md') {
|
|
223
251
|
actions.push(await buildManagedBlockSyncAction({ source, destination, exists, options, relativePath: file }));
|
|
@@ -238,6 +266,30 @@ export async function buildSyncPlan(targetDir, options = {}) {
|
|
|
238
266
|
}
|
|
239
267
|
}
|
|
240
268
|
|
|
269
|
+
// Inject per-platform skills directories from the canonical template/skills/.
|
|
270
|
+
const skillsSrc = join(templateRoot, 'skills');
|
|
271
|
+
if (await pathExists(skillsSrc)) {
|
|
272
|
+
const skillEntries = await readdir(skillsSrc, { withFileTypes: true });
|
|
273
|
+
for (const entry of skillEntries) {
|
|
274
|
+
if (!entry.isDirectory()) continue;
|
|
275
|
+
const skillName = entry.name;
|
|
276
|
+
for (const platform of platforms) {
|
|
277
|
+
const destBase = skillDestinationForPlatform(platform);
|
|
278
|
+
if (!destBase) continue;
|
|
279
|
+
const dest = join(targetDir, destBase, skillName, 'SKILL.md');
|
|
280
|
+
if (seen.has(dest)) continue;
|
|
281
|
+
seen.add(dest);
|
|
282
|
+
const destExists = await pathExists(dest);
|
|
283
|
+
const safe = ['.agents/skills', '.claude/skills'].some((p) => dest.startsWith(join(targetDir, p)));
|
|
284
|
+
if (destExists && (safe || options.force)) {
|
|
285
|
+
actions.push({ action: 'update', source: join(skillsSrc, skillName, 'SKILL.md'), destination: dest, relativePath: join(destBase, skillName, 'SKILL.md') });
|
|
286
|
+
} else if (!destExists) {
|
|
287
|
+
actions.push({ action: 'create', source: join(skillsSrc, skillName, 'SKILL.md'), destination: dest, relativePath: join(destBase, skillName, 'SKILL.md') });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
241
293
|
for (const file of OBSOLETE_SYNC_FILES) {
|
|
242
294
|
const destination = join(targetDir, file);
|
|
243
295
|
if (await pathExists(destination)) {
|
package/src/lib/platforms.js
CHANGED
|
@@ -50,9 +50,19 @@ export function formatPlatformList(platforms) {
|
|
|
50
50
|
|
|
51
51
|
export function shouldIncludeForPlatforms(relativePath, platforms) {
|
|
52
52
|
const normalized = relativePath.replaceAll('\\', '/');
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
|
|
54
|
+
// Canonical skills directory at template root — never copied directly;
|
|
55
|
+
// init logic injects per-platform copies separately.
|
|
56
|
+
if (normalized.startsWith('skills/')) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ZCode plugin bundle (.zcode/) is installed via a dedicated
|
|
61
|
+
// command, not by init/sync; keep it out of project directories.
|
|
62
|
+
if (normalized.startsWith(".zcode")) {
|
|
63
|
+
return false;
|
|
55
64
|
}
|
|
65
|
+
|
|
56
66
|
if (normalized.startsWith('.codex/') || normalized.startsWith('.cowork-flow/adapters/codex/')) {
|
|
57
67
|
return platforms.includes('codex');
|
|
58
68
|
}
|
|
@@ -68,3 +78,18 @@ export function shouldIncludeForPlatforms(relativePath, platforms) {
|
|
|
68
78
|
}
|
|
69
79
|
return true;
|
|
70
80
|
}
|
|
81
|
+
|
|
82
|
+
// Destination directory for copied skills, per host platform.
|
|
83
|
+
// ZCode is absent because it ships the plugin bundle via install-zcode-plugin,
|
|
84
|
+
// not by stashing files next to the project.
|
|
85
|
+
export function skillDestinationForPlatform(platform) {
|
|
86
|
+
switch (platform) {
|
|
87
|
+
case 'codex':
|
|
88
|
+
case 'opencode':
|
|
89
|
+
return '.agents/skills';
|
|
90
|
+
case 'claude-code':
|
|
91
|
+
return '.claude/skills';
|
|
92
|
+
default:
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -36,9 +36,10 @@ the task.
|
|
|
36
36
|
Load context before checking:
|
|
37
37
|
1. Read the task directory from the bound runtime context.
|
|
38
38
|
2. Read `<task>/prd.md`.
|
|
39
|
-
3. Read `<task>/
|
|
40
|
-
4. Read
|
|
41
|
-
5.
|
|
39
|
+
3. Read the plan file linked from this task (check `<task>/task.json` `relatedFiles` for a plan path, or search `.cowork-flow/plans/` for a plan file referencing this task directory). Use the plan's Verify commands and Expected results as the checklist for each step.
|
|
40
|
+
4. Read `<task>/check.jsonl`.
|
|
41
|
+
5. Read `git diff`.
|
|
42
|
+
6. Include `test_intent_review` in the review output for meaningful behavior
|
|
42
43
|
breaks coverage and shallow tests rejection.
|
|
43
44
|
|
|
44
45
|
Rules:
|
|
@@ -39,7 +39,8 @@ Load context before editing:
|
|
|
39
39
|
3. Read `<task>/info.md` if present.
|
|
40
40
|
4. Read `<task>/implement.jsonl`.
|
|
41
41
|
5. Read each JSONL `file` entry.
|
|
42
|
-
6.
|
|
42
|
+
6. Read the plan file linked from this task (check `<task>/task.json` `relatedFiles` for a plan path, or search `.cowork-flow/plans/` for a plan file referencing this task directory). Follow the plan steps in order — each step has Files, Action, Verify, and Expected fields.
|
|
43
|
+
7. For behavior-change tasks, create or verify `<task>/tdd.jsonl` before
|
|
43
44
|
implementation or record a documented exemption.
|
|
44
45
|
|
|
45
46
|
Rules:
|
|
@@ -27,9 +27,10 @@ the task.
|
|
|
27
27
|
Load context before checking:
|
|
28
28
|
1. Read the task directory from the bound runtime context.
|
|
29
29
|
2. Read `<task>/prd.md`.
|
|
30
|
-
3. Read `<task>/
|
|
31
|
-
4. Read
|
|
32
|
-
5.
|
|
30
|
+
3. Read the plan file linked from this task (check `<task>/task.json` `relatedFiles` for a plan path, or search `.cowork-flow/plans/` for a plan file referencing this task directory). Use the plan's Verify commands and Expected results as the checklist for each step.
|
|
31
|
+
4. Read `<task>/check.jsonl`.
|
|
32
|
+
5. Read `git diff`.
|
|
33
|
+
6. Include `test_intent_review` in the review output for meaningful behavior breaks coverage and shallow tests rejection.
|
|
33
34
|
|
|
34
35
|
Rules:
|
|
35
36
|
- Fix issues directly when they are clearly in scope.
|
|
@@ -37,6 +38,13 @@ Rules:
|
|
|
37
38
|
- MUST NOT commit, archive, or mutate cowork-flow task state.
|
|
38
39
|
- Report findings, changed files, and exact verification commands.
|
|
39
40
|
- Include test intent findings that map tests back to PRD acceptance or regression behavior.
|
|
41
|
+
- BEFORE declaring PRD acceptance passed, run the spec-driven coding gate and
|
|
42
|
+
treat a nonzero exit as a hard blocker:
|
|
43
|
+
./.cowork-flow/run python .cowork-flow/scripts/common/gates/validate_coding_standaries.py --validate --repo-root .
|
|
44
|
+
This naturally enforces every rule the user added to
|
|
45
|
+
.cowork-flow/spec/backend/*.md and spec/frontend/*.md — they are not just
|
|
46
|
+
documentation but active validators. On violation, either fix the code or
|
|
47
|
+
explicitly discard the rule from the spec; do not skip the gate.
|
|
40
48
|
"""
|
|
41
49
|
|
|
42
50
|
[features]
|
|
@@ -30,7 +30,8 @@ Load context before editing:
|
|
|
30
30
|
3. Read `<task>/info.md` if present.
|
|
31
31
|
4. Read `<task>/implement.jsonl`.
|
|
32
32
|
5. Read each JSONL `file` entry.
|
|
33
|
-
6.
|
|
33
|
+
6. Read the plan file linked from this task (check `<task>/task.json` `relatedFiles` for a plan path, or search `.cowork-flow/plans/` for a plan file referencing this task directory). Follow the plan steps in order — each step has Files, Action, Verify, and Expected fields.
|
|
34
|
+
7. For behavior-change tasks, create or verify `<task>/tdd.jsonl` before implementation or record a documented exemption.
|
|
34
35
|
|
|
35
36
|
Rules:
|
|
36
37
|
- MUST NOT spawn, wait for, list, or close other agents.
|
|
@@ -39,6 +40,12 @@ Rules:
|
|
|
39
40
|
- Keep edits inside requested scope.
|
|
40
41
|
- Do not treat shallow tests as TDD evidence; red-green-refactor proof must include redCommand, redExitCode, greenCommand, greenExitCode, and PRD acceptance ID mapping.
|
|
41
42
|
- Report changed files and exact verification commands.
|
|
43
|
+
- BEFORE editing any source file, run the spec-driven coding gate and treat a
|
|
44
|
+
nonzero exit as a hard blocker:
|
|
45
|
+
./.cowork-flow/run python .cowork-flow/scripts/common/gates/validate_coding_standaries.py --validate --repo-root .
|
|
46
|
+
Parse every *.md under .cowork-flow/spec/backend and spec/frontend; rules
|
|
47
|
+
declared there activate validators dynamically. On violation, fix the code
|
|
48
|
+
(do not disable the rule) and re-run until exit code 0.
|
|
42
49
|
"""
|
|
43
50
|
|
|
44
51
|
[features]
|
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.32
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
set -u
|
|
3
3
|
|
|
4
|
-
MIN_PYTHON_LABEL="Python 3.
|
|
5
|
-
VERSION_CHECK='import sys; raise SystemExit(0 if sys.version_info >= (3,
|
|
4
|
+
MIN_PYTHON_LABEL="Python 3.9+"
|
|
5
|
+
VERSION_CHECK='import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)'
|
|
6
6
|
WORKFLOW_DIR=$(CDPATH= cd "$(dirname "$0")" && pwd) || exit 1
|
|
7
7
|
RUNNER_SCRIPT="$WORKFLOW_DIR/scripts/run.py"
|
|
8
8
|
|
|
@@ -30,7 +30,7 @@ select_explicit_python() {
|
|
|
30
30
|
fi
|
|
31
31
|
|
|
32
32
|
echo "Error: $env_name does not point to a usable ${MIN_PYTHON_LABEL} interpreter: $env_value" >&2
|
|
33
|
-
echo "Set $env_name to an executable
|
|
33
|
+
echo "Set $env_name to an executable ${MIN_PYTHON_LABEL} interpreter path." >&2
|
|
34
34
|
exit 127
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
@echo off
|
|
2
|
-
setlocal EnableExtensions
|
|
3
|
-
|
|
4
|
-
set "MIN_PYTHON_LABEL=Python 3.
|
|
5
|
-
set "VERSION_CHECK=import sys; raise SystemExit(0 if sys.version_info >= (3,
|
|
6
|
-
set "WORKFLOW_DIR=%~dp0"
|
|
7
|
-
set "RUNNER_SCRIPT=%WORKFLOW_DIR%scripts\run.py"
|
|
8
|
-
set "SELECTED_PYTHON="
|
|
9
|
-
set "SELECTED_PYTHON_ARG="
|
|
10
|
-
|
|
11
|
-
call :select_python
|
|
12
|
-
if errorlevel 1 exit /b %ERRORLEVEL%
|
|
13
|
-
|
|
14
|
-
if not "%SELECTED_PYTHON_ARG%"=="" (
|
|
15
|
-
"%SELECTED_PYTHON%" "%SELECTED_PYTHON_ARG%" "%RUNNER_SCRIPT%" %*
|
|
16
|
-
) else (
|
|
17
|
-
"%SELECTED_PYTHON%" "%RUNNER_SCRIPT%" %*
|
|
18
|
-
)
|
|
19
|
-
exit /b %ERRORLEVEL%
|
|
20
|
-
|
|
21
|
-
:candidate_is_valid
|
|
22
|
-
set "CANDIDATE_CMD=%~1"
|
|
23
|
-
set "CANDIDATE_ARG=%~2"
|
|
24
|
-
|
|
25
|
-
where "%CANDIDATE_CMD%" >nul 2>nul
|
|
26
|
-
if errorlevel 1 (
|
|
27
|
-
if not exist "%CANDIDATE_CMD%" exit /b 1
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
if not "%CANDIDATE_ARG%"=="" (
|
|
31
|
-
"%CANDIDATE_CMD%" "%CANDIDATE_ARG%" -c "%VERSION_CHECK%" >nul 2>nul
|
|
32
|
-
) else (
|
|
33
|
-
"%CANDIDATE_CMD%" -c "%VERSION_CHECK%" >nul 2>nul
|
|
34
|
-
)
|
|
35
|
-
exit /b %ERRORLEVEL%
|
|
36
|
-
|
|
37
|
-
:select_explicit_python
|
|
38
|
-
set "ENV_NAME=%~1"
|
|
39
|
-
set "ENV_VALUE=%~2"
|
|
40
|
-
|
|
41
|
-
call :candidate_is_valid "%ENV_VALUE%" ""
|
|
42
|
-
if not errorlevel 1 (
|
|
43
|
-
set "SELECTED_PYTHON=%ENV_VALUE%"
|
|
44
|
-
set "SELECTED_PYTHON_ARG="
|
|
45
|
-
exit /b 0
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
echo Error: %ENV_NAME% does not point to a usable %MIN_PYTHON_LABEL% interpreter: %ENV_VALUE% 1>&2
|
|
49
|
-
echo Set %ENV_NAME% to an executable Python 3.
|
|
50
|
-
exit /b 127
|
|
51
|
-
|
|
52
|
-
:select_python
|
|
53
|
-
set "SELECTED_PYTHON="
|
|
54
|
-
set "SELECTED_PYTHON_ARG="
|
|
55
|
-
|
|
56
|
-
if not "%COWORK_FLOW_PYTHON%"=="" (
|
|
57
|
-
call :select_explicit_python "COWORK_FLOW_PYTHON" "%COWORK_FLOW_PYTHON%"
|
|
58
|
-
exit /b %ERRORLEVEL%
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
if not "%PYTHON%"=="" (
|
|
62
|
-
call :select_explicit_python "PYTHON" "%PYTHON%"
|
|
63
|
-
exit /b %ERRORLEVEL%
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
call :candidate_is_valid "python3" ""
|
|
67
|
-
if not errorlevel 1 (
|
|
68
|
-
set "SELECTED_PYTHON=python3"
|
|
69
|
-
exit /b 0
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
call :candidate_is_valid "python" ""
|
|
73
|
-
if not errorlevel 1 (
|
|
74
|
-
set "SELECTED_PYTHON=python"
|
|
75
|
-
exit /b 0
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
call :candidate_is_valid "py" "-3"
|
|
79
|
-
if not errorlevel 1 (
|
|
80
|
-
set "SELECTED_PYTHON=py"
|
|
81
|
-
set "SELECTED_PYTHON_ARG=-3"
|
|
82
|
-
exit /b 0
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
echo Error: %MIN_PYTHON_LABEL% is required, but no usable interpreter was found. 1>&2
|
|
86
|
-
echo Tried: COWORK_FLOW_PYTHON, PYTHON, python3, python, py -3. 1>&2
|
|
87
|
-
echo Set COWORK_FLOW_PYTHON=C:\Path\To\python.exe and retry. 1>&2
|
|
88
|
-
exit /b 127
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal EnableExtensions
|
|
3
|
+
|
|
4
|
+
set "MIN_PYTHON_LABEL=Python 3.9+"
|
|
5
|
+
set "VERSION_CHECK=import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)"
|
|
6
|
+
set "WORKFLOW_DIR=%~dp0"
|
|
7
|
+
set "RUNNER_SCRIPT=%WORKFLOW_DIR%scripts\run.py"
|
|
8
|
+
set "SELECTED_PYTHON="
|
|
9
|
+
set "SELECTED_PYTHON_ARG="
|
|
10
|
+
|
|
11
|
+
call :select_python
|
|
12
|
+
if errorlevel 1 exit /b %ERRORLEVEL%
|
|
13
|
+
|
|
14
|
+
if not "%SELECTED_PYTHON_ARG%"=="" (
|
|
15
|
+
"%SELECTED_PYTHON%" "%SELECTED_PYTHON_ARG%" "%RUNNER_SCRIPT%" %*
|
|
16
|
+
) else (
|
|
17
|
+
"%SELECTED_PYTHON%" "%RUNNER_SCRIPT%" %*
|
|
18
|
+
)
|
|
19
|
+
exit /b %ERRORLEVEL%
|
|
20
|
+
|
|
21
|
+
:candidate_is_valid
|
|
22
|
+
set "CANDIDATE_CMD=%~1"
|
|
23
|
+
set "CANDIDATE_ARG=%~2"
|
|
24
|
+
|
|
25
|
+
where "%CANDIDATE_CMD%" >nul 2>nul
|
|
26
|
+
if errorlevel 1 (
|
|
27
|
+
if not exist "%CANDIDATE_CMD%" exit /b 1
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
if not "%CANDIDATE_ARG%"=="" (
|
|
31
|
+
"%CANDIDATE_CMD%" "%CANDIDATE_ARG%" -c "%VERSION_CHECK%" >nul 2>nul
|
|
32
|
+
) else (
|
|
33
|
+
"%CANDIDATE_CMD%" -c "%VERSION_CHECK%" >nul 2>nul
|
|
34
|
+
)
|
|
35
|
+
exit /b %ERRORLEVEL%
|
|
36
|
+
|
|
37
|
+
:select_explicit_python
|
|
38
|
+
set "ENV_NAME=%~1"
|
|
39
|
+
set "ENV_VALUE=%~2"
|
|
40
|
+
|
|
41
|
+
call :candidate_is_valid "%ENV_VALUE%" ""
|
|
42
|
+
if not errorlevel 1 (
|
|
43
|
+
set "SELECTED_PYTHON=%ENV_VALUE%"
|
|
44
|
+
set "SELECTED_PYTHON_ARG="
|
|
45
|
+
exit /b 0
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
echo Error: %ENV_NAME% does not point to a usable %MIN_PYTHON_LABEL% interpreter: %ENV_VALUE% 1>&2
|
|
49
|
+
echo Set %ENV_NAME% to an executable Python 3.9+ interpreter path. 1>&2
|
|
50
|
+
exit /b 127
|
|
51
|
+
|
|
52
|
+
:select_python
|
|
53
|
+
set "SELECTED_PYTHON="
|
|
54
|
+
set "SELECTED_PYTHON_ARG="
|
|
55
|
+
|
|
56
|
+
if not "%COWORK_FLOW_PYTHON%"=="" (
|
|
57
|
+
call :select_explicit_python "COWORK_FLOW_PYTHON" "%COWORK_FLOW_PYTHON%"
|
|
58
|
+
exit /b %ERRORLEVEL%
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if not "%PYTHON%"=="" (
|
|
62
|
+
call :select_explicit_python "PYTHON" "%PYTHON%"
|
|
63
|
+
exit /b %ERRORLEVEL%
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
call :candidate_is_valid "python3" ""
|
|
67
|
+
if not errorlevel 1 (
|
|
68
|
+
set "SELECTED_PYTHON=python3"
|
|
69
|
+
exit /b 0
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
call :candidate_is_valid "python" ""
|
|
73
|
+
if not errorlevel 1 (
|
|
74
|
+
set "SELECTED_PYTHON=python"
|
|
75
|
+
exit /b 0
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
call :candidate_is_valid "py" "-3"
|
|
79
|
+
if not errorlevel 1 (
|
|
80
|
+
set "SELECTED_PYTHON=py"
|
|
81
|
+
set "SELECTED_PYTHON_ARG=-3"
|
|
82
|
+
exit /b 0
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
echo Error: %MIN_PYTHON_LABEL% is required, but no usable interpreter was found. 1>&2
|
|
86
|
+
echo Tried: COWORK_FLOW_PYTHON, PYTHON, python3, python, py -3. 1>&2
|
|
87
|
+
echo Set COWORK_FLOW_PYTHON=C:\Path\To\python.exe and retry. 1>&2
|
|
88
|
+
exit /b 127
|
|
@@ -240,16 +240,12 @@ def _check_host_adapters(repo_root: Path, errors: list[str]) -> None:
|
|
|
240
240
|
errors,
|
|
241
241
|
)
|
|
242
242
|
for rel in (
|
|
243
|
-
".cowork-flow/adapters/codex/adapter.yaml",
|
|
244
|
-
".cowork-flow/adapters/opencode/adapter.yaml",
|
|
245
|
-
".cowork-flow/adapters/claude-code/adapter.yaml",
|
|
246
243
|
"template/.cowork-flow/adapters/codex/adapter.yaml",
|
|
247
244
|
"template/.cowork-flow/adapters/opencode/adapter.yaml",
|
|
248
245
|
"template/.cowork-flow/adapters/claude-code/adapter.yaml",
|
|
249
246
|
):
|
|
250
247
|
_check_file_contains(repo_root / rel, REQUIRED_ADAPTER_SNIPPETS, errors)
|
|
251
248
|
for rel in (
|
|
252
|
-
".cowork-flow/adapters/claude-code/adapter.yaml",
|
|
253
249
|
"template/.cowork-flow/adapters/claude-code/adapter.yaml",
|
|
254
250
|
):
|
|
255
251
|
_check_file_contains(
|
|
@@ -268,30 +264,18 @@ def cmd_host_adapters(_: argparse.Namespace) -> int:
|
|
|
268
264
|
errors: list[str] = []
|
|
269
265
|
_check_host_adapters(repo_root, errors)
|
|
270
266
|
for rel in (
|
|
271
|
-
".opencode/agents/cowork-research.md",
|
|
272
|
-
".opencode/agents/cowork-implement.md",
|
|
273
|
-
".opencode/agents/cowork-check.md",
|
|
274
267
|
"template/.opencode/agents/cowork-research.md",
|
|
275
268
|
"template/.opencode/agents/cowork-implement.md",
|
|
276
269
|
"template/.opencode/agents/cowork-check.md",
|
|
277
270
|
):
|
|
278
271
|
_check_file_contains(repo_root / rel, REQUIRED_OPENCODE_AGENT_SNIPPETS, errors)
|
|
279
272
|
for rel in (
|
|
280
|
-
".claude/agents/cowork-research.md",
|
|
281
|
-
".claude/agents/cowork-implement.md",
|
|
282
|
-
".claude/agents/cowork-check.md",
|
|
283
273
|
"template/.claude/agents/cowork-research.md",
|
|
284
274
|
"template/.claude/agents/cowork-implement.md",
|
|
285
275
|
"template/.claude/agents/cowork-check.md",
|
|
286
276
|
):
|
|
287
277
|
_check_file_contains(repo_root / rel, REQUIRED_CLAUDE_AGENT_SNIPPETS, errors)
|
|
288
278
|
for rel in (
|
|
289
|
-
".claude/commands/cowork-research.md",
|
|
290
|
-
".claude/commands/cowork-implement.md",
|
|
291
|
-
".claude/commands/cowork-check.md",
|
|
292
|
-
".opencode/commands/cowork-research.md",
|
|
293
|
-
".opencode/commands/cowork-implement.md",
|
|
294
|
-
".opencode/commands/cowork-check.md",
|
|
295
279
|
"template/.claude/commands/cowork-research.md",
|
|
296
280
|
"template/.claude/commands/cowork-implement.md",
|
|
297
281
|
"template/.claude/commands/cowork-check.md",
|
|
@@ -301,26 +285,20 @@ def cmd_host_adapters(_: argparse.Namespace) -> int:
|
|
|
301
285
|
):
|
|
302
286
|
_check_file_contains(repo_root / rel, REQUIRED_RUNTIME_COMMAND_SNIPPETS, errors)
|
|
303
287
|
for rel in (
|
|
304
|
-
"
|
|
305
|
-
"
|
|
306
|
-
"template/.claude/skills/start/SKILL.md",
|
|
307
|
-
"template/.claude/skills/check/SKILL.md",
|
|
288
|
+
"template/skills/start/SKILL.md",
|
|
289
|
+
"template/skills/check/SKILL.md",
|
|
308
290
|
):
|
|
309
291
|
_check_file_contains(repo_root / rel, REQUIRED_CLAUDE_SKILL_SNIPPETS, errors)
|
|
310
292
|
for rel in (
|
|
311
|
-
f"
|
|
312
|
-
f"template/.claude/skills/{ENTRY_BOUNDARY_DIR}/SKILL.md",
|
|
293
|
+
f"template/skills/{ENTRY_BOUNDARY_DIR}/SKILL.md",
|
|
313
294
|
):
|
|
314
295
|
_check_file_absent(repo_root / rel, errors)
|
|
315
296
|
for rel in (
|
|
316
|
-
".claude/settings.json",
|
|
317
297
|
"template/.claude/settings.json",
|
|
318
298
|
):
|
|
319
299
|
_check_file_contains(repo_root / rel, REQUIRED_CLAUDE_HOOK_SETTINGS_SNIPPETS, errors)
|
|
320
300
|
for rel in (
|
|
321
|
-
".claude/hooks/inject-workflow-state.py",
|
|
322
301
|
"template/.claude/hooks/inject-workflow-state.py",
|
|
323
|
-
".codex/hooks/inject-workflow-state.py",
|
|
324
302
|
"template/.codex/hooks/inject-workflow-state.py",
|
|
325
303
|
):
|
|
326
304
|
_check_file_contains(repo_root / rel, REQUIRED_RUNTIME_HOOK_SNIPPETS, errors)
|
|
@@ -337,7 +315,6 @@ def cmd_host_adapters(_: argparse.Namespace) -> int:
|
|
|
337
315
|
errors,
|
|
338
316
|
)
|
|
339
317
|
for rel in (
|
|
340
|
-
".opencode/plugins/cowork-flow.js",
|
|
341
318
|
"template/.opencode/plugins/cowork-flow.js",
|
|
342
319
|
):
|
|
343
320
|
_check_file_contains(
|
|
@@ -366,19 +343,14 @@ def cmd_subagent_safety(_: argparse.Namespace) -> int:
|
|
|
366
343
|
repo_root = get_repo_root()
|
|
367
344
|
errors: list[str] = []
|
|
368
345
|
for rel in (
|
|
369
|
-
"
|
|
370
|
-
"template/.agents/skills/start/SKILL.md",
|
|
346
|
+
"template/skills/start/SKILL.md",
|
|
371
347
|
):
|
|
372
348
|
_check_file_contains(repo_root / rel, REQUIRED_START_SNIPPETS, errors)
|
|
373
349
|
for rel in (
|
|
374
|
-
f"
|
|
375
|
-
f"template/.agents/skills/{ENTRY_BOUNDARY_DIR}/SKILL.md",
|
|
350
|
+
f"template/skills/{ENTRY_BOUNDARY_DIR}/SKILL.md",
|
|
376
351
|
):
|
|
377
352
|
_check_file_absent(repo_root / rel, errors)
|
|
378
353
|
for rel in (
|
|
379
|
-
".codex/agents/cowork-research.toml",
|
|
380
|
-
".codex/agents/cowork-implement.toml",
|
|
381
|
-
".codex/agents/cowork-check.toml",
|
|
382
354
|
"template/.codex/agents/cowork-research.toml",
|
|
383
355
|
"template/.codex/agents/cowork-implement.toml",
|
|
384
356
|
"template/.codex/agents/cowork-check.toml",
|
|
@@ -401,9 +373,6 @@ def cmd_subagent_safety(_: argparse.Namespace) -> int:
|
|
|
401
373
|
if (repo_root / "README.md").is_file():
|
|
402
374
|
_check_file_omits(repo_root / "README.md", FORBIDDEN_README_DISPATCH_SNIPPETS, errors)
|
|
403
375
|
for rel in (
|
|
404
|
-
".codex/agents/worker.toml",
|
|
405
|
-
".codex/agents/default.toml",
|
|
406
|
-
".codex/agents/explorer.toml",
|
|
407
376
|
"template/.codex/agents/worker.toml",
|
|
408
377
|
"template/.codex/agents/default.toml",
|
|
409
378
|
"template/.codex/agents/explorer.toml",
|
|
@@ -420,23 +389,17 @@ def cmd_subagent_safety(_: argparse.Namespace) -> int:
|
|
|
420
389
|
_check_common_contracts(repo_root, errors)
|
|
421
390
|
_check_host_adapters(repo_root, errors)
|
|
422
391
|
for rel in (
|
|
423
|
-
".codex/hooks.json",
|
|
424
392
|
"template/.codex/hooks.json",
|
|
425
393
|
):
|
|
426
394
|
_check_file_contains(repo_root / rel, REQUIRED_HOOK_SNIPPETS, errors)
|
|
427
395
|
for rel in (
|
|
428
|
-
".codex/hooks/inject-workflow-state.py",
|
|
429
396
|
"template/.codex/hooks/inject-workflow-state.py",
|
|
430
|
-
".claude/hooks/inject-workflow-state.py",
|
|
431
397
|
"template/.claude/hooks/inject-workflow-state.py",
|
|
432
398
|
):
|
|
433
399
|
_check_file_contains(repo_root / rel, REQUIRED_RUNTIME_HOOK_SNIPPETS, errors)
|
|
434
400
|
for rel in (
|
|
435
|
-
".cowork-flow/scripts/commands/subagent.py",
|
|
436
401
|
"template/.cowork-flow/scripts/commands/subagent.py",
|
|
437
|
-
".cowork-flow/scripts/common/core/execution_context.py",
|
|
438
402
|
"template/.cowork-flow/scripts/common/core/execution_context.py",
|
|
439
|
-
".cowork-flow/scripts/common/task/active_task.py",
|
|
440
403
|
"template/.cowork-flow/scripts/common/task/active_task.py",
|
|
441
404
|
):
|
|
442
405
|
if not (repo_root / rel).is_file():
|