cowork-flow 1.7.2 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -1
- package/docs/direction.md +179 -0
- package/docs/index.md +1 -0
- package/package.json +1 -1
- package/presets/claude-code/.claude-plugin/plugin.json +1 -1
- package/presets/codex/.codex-plugin/plugin.json +1 -1
- package/presets/kimi-code/.kimi-plugin/plugin.json +1 -1
- package/presets/opencode/cowork-flow/plugin-core.js +51 -3
- package/presets/qoder/.qoder-plugin/plugin.json +1 -1
- package/presets/zcode/.zcode-plugin/plugin.json +1 -1
- package/presets/zcode/hooks/hooks.json +3 -3
- package/presets/zcode/hooks/{inject-context.js → inject-context.mjs} +11 -6
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/scripts/adapters/cli/spec_check.py +10 -1
- package/template/.cowork-flow/scripts/adapters/cli/task_lifecycle_commands.py +3 -0
- package/template/.cowork-flow/scripts/adapters/cli/task_parser.py +1 -0
- package/template/.cowork-flow/scripts/adapters/host/workflow_state_hook.py +21 -0
- package/template/.cowork-flow/scripts/adapters/host/zcode_policy.py +1 -1
- package/template/.cowork-flow/scripts/services/ac_evidence.py +107 -0
- package/template/.cowork-flow/scripts/services/fact_view.py +16 -2
- package/template/.cowork-flow/scripts/services/lifecycle_checks.py +84 -0
- package/template/.cowork-flow/scripts/services/lifecycle_policy.py +5 -0
- package/template/.cowork-flow/scripts/services/spec_check.py +11 -1
- package/template/.cowork-flow/scripts/services/task_lifecycle.py +12 -0
- package/template/.cowork-flow/spec/contracts/context-injection.md +6 -4
- package/template/.cowork-flow/spec/contracts/decision-anchor.md +1 -0
- package/template/.cowork-flow/spec/contracts/evidence-completion.md +48 -0
- package/template/.cowork-flow/spec/contracts/index.md +1 -0
- package/template/.cowork-flow/spec/contracts/spec-checks.md +49 -82
- package/template/.cowork-flow/spec/runtime/contract-registry.json +13 -0
- package/template/.opencode/cowork-flow/plugin-core.js +51 -3
- package/template/skills/spec-sync/SKILL.md +1 -0
- package/template/skills/task-review/SKILL.md +3 -2
- package/template/skills/test-first/SKILL.md +4 -0
|
@@ -574,8 +574,14 @@ function parseDecisionAnchor(text) {
|
|
|
574
574
|
if (section === "目标") {
|
|
575
575
|
if (line) goalLines.push(line)
|
|
576
576
|
} else if (section === "验收标准") {
|
|
577
|
-
const match = raw.match(/^\s*-\s
|
|
578
|
-
if (match)
|
|
577
|
+
const match = raw.match(/^\s*-\s*(?:\[([ xX])\]?\s*)?(AC-[A-Za-z0-9-]+)\s*[::]\s*(.+?)\s*$/)
|
|
578
|
+
if (match) {
|
|
579
|
+
result.acceptanceCriteria.push({
|
|
580
|
+
id: match[2],
|
|
581
|
+
text: match[3],
|
|
582
|
+
checked: match[1] === 'x' || match[1] === 'X',
|
|
583
|
+
})
|
|
584
|
+
}
|
|
579
585
|
} else if (section === "被拒方案") {
|
|
580
586
|
const match = raw.match(/^\s*-\s*\*\*(.+?)\*\*/)
|
|
581
587
|
if (match) result.rejectedOptions.push(match[1].trim())
|
|
@@ -836,6 +842,36 @@ function withStageFacts(block, root, taskPath, status, readonly = false) {
|
|
|
836
842
|
return parts.length > 0 ? `${parts.join("\n\n")}\n\n${block}` : block
|
|
837
843
|
}
|
|
838
844
|
|
|
845
|
+
// Evidence coverage for the anchor block: one read of the task's
|
|
846
|
+
// evidence.jsonl, tolerating noise exactly like the python line. Returns
|
|
847
|
+
// null when the file is absent so the coverage line degrades silently.
|
|
848
|
+
function readEvidenceCoverage(root, taskPath) {
|
|
849
|
+
let text = ''
|
|
850
|
+
try {
|
|
851
|
+
text = readFileSync(resolve(root, taskPath, 'evidence.jsonl'), 'utf8')
|
|
852
|
+
} catch {
|
|
853
|
+
return null
|
|
854
|
+
}
|
|
855
|
+
const covered = new Set()
|
|
856
|
+
for (const raw of text.split('\n')) {
|
|
857
|
+
const line = raw.trim()
|
|
858
|
+
if (!line) continue
|
|
859
|
+
let record
|
|
860
|
+
try {
|
|
861
|
+
record = JSON.parse(line)
|
|
862
|
+
} catch {
|
|
863
|
+
continue
|
|
864
|
+
}
|
|
865
|
+
if (!record || typeof record !== 'object' || Array.isArray(record)) continue
|
|
866
|
+
const ac = typeof record.ac === 'string' ? record.ac.trim() : ''
|
|
867
|
+
const ref = typeof record.ref === 'string' ? record.ref.trim() : ''
|
|
868
|
+
if (ac && ref && ['test', 'command', 'manual'].includes(record.kind)) {
|
|
869
|
+
covered.add(ac)
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return covered
|
|
873
|
+
}
|
|
874
|
+
|
|
839
875
|
function decisionAnchorBlock(root, taskPath, status) {
|
|
840
876
|
if (!taskPath) {
|
|
841
877
|
return null
|
|
@@ -868,6 +904,17 @@ function decisionAnchorBlock(root, taskPath, status) {
|
|
|
868
904
|
lines.push(
|
|
869
905
|
`Acceptance: ${parsed.acceptanceCriteria.slice(0, 8).map((item) => `${item.id} ${item.text.slice(0, 80)}`).join("; ")}`
|
|
870
906
|
)
|
|
907
|
+
const covered = readEvidenceCoverage(root, taskPath)
|
|
908
|
+
if (covered) {
|
|
909
|
+
const total = parsed.acceptanceCriteria.length
|
|
910
|
+
const missing = parsed.acceptanceCriteria
|
|
911
|
+
.map((item) => item.id)
|
|
912
|
+
.filter((id) => !covered.has(id))
|
|
913
|
+
const detail = missing.length
|
|
914
|
+
? ` missing=${missing.slice(0, 5).join(',')}`
|
|
915
|
+
: ''
|
|
916
|
+
lines.push(`AC evidence: ${total - missing.length}/${total}${detail}`)
|
|
917
|
+
}
|
|
871
918
|
}
|
|
872
919
|
if (parsed.rejectedOptions.length > 0) {
|
|
873
920
|
lines.push(`Rejected: ${parsed.rejectedOptions.slice(0, 6).join("; ")}`)
|
|
@@ -1073,5 +1120,6 @@ export {
|
|
|
1073
1120
|
runEditSpecCheck,
|
|
1074
1121
|
contractFingerprint,
|
|
1075
1122
|
stableStringify,
|
|
1076
|
-
stageContractBlock
|
|
1123
|
+
stageContractBlock,
|
|
1124
|
+
decisionAnchorBlock
|
|
1077
1125
|
}
|
|
@@ -33,6 +33,7 @@ Keep each update concrete:
|
|
|
33
33
|
- Show the contract or command shape.
|
|
34
34
|
- Include good/bad cases when useful.
|
|
35
35
|
- State tests or checks that protect the behavior.
|
|
36
|
+
- When a clause is machine-checkable (可机检), add or refresh its `checks:` declaration in the same pass (main session only — never rewrite the clause text): the command must pass on a clean tree, a negative case must prove it can fail, `files` must narrow the scope, and a `spec-check` run after writing must confirm the declaration parses.
|
|
36
37
|
- Update the matching `index.md` when adding a new topic.
|
|
37
38
|
- Check for duplicate guidance and remove stale wording before finishing.
|
|
38
39
|
|
|
@@ -37,7 +37,8 @@ Read only what is needed for the current task:
|
|
|
37
37
|
- **Scope**: every changed file is planned or justified; no unrelated cleanup sneaks in.
|
|
38
38
|
- **Behavior**: acceptance criteria are satisfied through observable behavior, not implementation-shaped assertions.
|
|
39
39
|
- **Tests**: test intent is explicit; tests fail for meaningful regressions, reject shallow tests such as existence/mock/snapshot-only checks, and cover boundary/error paths when relevant.
|
|
40
|
-
- **
|
|
40
|
+
- **Evidence coverage**: when the decision anchor declares acceptance criteria (`AC-xxx`), verify each one has an evidence record in `<task>/evidence.jsonl` — or a recorded `meta.evidenceExempt` exemption from an explicit `--allow-missing-evidence` completion. Schema and gate codes (`LIFECYCLE-AC-001/002`) are defined in `.cowork-flow/spec/contracts/evidence-completion.md`. A record must point at real proof (test, command output, or manual verification note); a record that restates the AC without evidence is a finding.
|
|
41
|
+
- **User specs**: every applicable backend/frontend requirement is verified against the diff and marked `pass`, `finding`, or `not_applicable` with reason. Every `finding` is fixed during review; an unfixed spec violation blocks completion and is never accepted as-is or deferred to the user. For each requirement, also ask whether it is machine-checkable (可机检) and already declared with `checks:`; identifying checkable clauses and adding or refreshing declarations is a main-session duty (never rewrite the clause text — raise a conflict through the review instead), and a declared check must earn its place: the command passes on a clean tree, a negative case proves it can fail, `files` narrows the scope, and a `spec-check` run after declaring confirms the declaration parses. Delegated subagents do not edit specs; they report candidates up.
|
|
41
42
|
- **Specs**: project specs are updated when behavior/contracts changed, or the review states why no spec update is needed.
|
|
42
43
|
- **Code quality**: naming, layering, error handling, state boundaries, security-sensitive paths, and complexity are reviewed against applicable user specs.
|
|
43
44
|
- **Lifecycle blockers**: state/scope blockers are fixed before acceptance; review does not invent hard blockers for natural-language specs.
|
|
@@ -61,7 +62,7 @@ Return a concise review result with:
|
|
|
61
62
|
- `status`: `pass`, `needs_fix`, or `blocked`.
|
|
62
63
|
- `findings`: severity, file, line/scope, impact, and fix.
|
|
63
64
|
- `test_intent_review`: why tests prove the intended behavior or what is missing.
|
|
64
|
-
- `user_spec_review`: applicable spec files, per-requirement result, and
|
|
65
|
+
- `user_spec_review`: applicable spec files, per-requirement result, findings, and the "clause → command" list for every `checks:` declaration added or refreshed in this review (`none` when nothing became machine-checkable).
|
|
65
66
|
- `lifecycle_check_review`: lifecycle commands run, blocker status, and resolution.
|
|
66
67
|
- `verification`: exact commands run from this checkout.
|
|
67
68
|
- `specUpdates`: files updated or reason no update was needed.
|
|
@@ -39,6 +39,10 @@ If red-first is skipped, state the reason before or with the implementation summ
|
|
|
39
39
|
|
|
40
40
|
Do not write TDD evidence objects to `check.jsonl`, do not create `tdd.jsonl`, and do not create TDD exemption records. Report the exact red/green commands in the agent response or task review narrative when useful; the workflow does not validate them as separate evidence artifacts.
|
|
41
41
|
|
|
42
|
+
## Evidence records
|
|
43
|
+
|
|
44
|
+
When the task's decision anchor declares acceptance criteria, a green test from a red-green cycle is the canonical completion evidence for the mapped AC: append one record to the task's `evidence.jsonl` — `{"ac": "AC-xxx", "kind": "test", "ref": "<test file>::<case>", "note": "<core assertion>", "recordedAt": "<date>", "by": "<session>"}`. This is task-level completion evidence governed by `.cowork-flow/spec/contracts/evidence-completion.md`; it is a different artifact from the forbidden `tdd.jsonl` above, and this skill still does not require or validate it — recording it as you go simply spares the completion gate a block later.
|
|
45
|
+
|
|
42
46
|
## Anti-Rationalization
|
|
43
47
|
|
|
44
48
|
Do not use these excuses to skip meaningful behavior tests:
|