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.
Files changed (34) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/docs/direction.md +179 -0
  3. package/docs/index.md +1 -0
  4. package/package.json +1 -1
  5. package/presets/claude-code/.claude-plugin/plugin.json +1 -1
  6. package/presets/codex/.codex-plugin/plugin.json +1 -1
  7. package/presets/kimi-code/.kimi-plugin/plugin.json +1 -1
  8. package/presets/opencode/cowork-flow/plugin-core.js +51 -3
  9. package/presets/qoder/.qoder-plugin/plugin.json +1 -1
  10. package/presets/zcode/.zcode-plugin/plugin.json +1 -1
  11. package/presets/zcode/hooks/hooks.json +3 -3
  12. package/presets/zcode/hooks/{inject-context.js → inject-context.mjs} +11 -6
  13. package/template/.cowork-flow/.version +1 -1
  14. package/template/.cowork-flow/scripts/adapters/cli/spec_check.py +10 -1
  15. package/template/.cowork-flow/scripts/adapters/cli/task_lifecycle_commands.py +3 -0
  16. package/template/.cowork-flow/scripts/adapters/cli/task_parser.py +1 -0
  17. package/template/.cowork-flow/scripts/adapters/host/workflow_state_hook.py +21 -0
  18. package/template/.cowork-flow/scripts/adapters/host/zcode_policy.py +1 -1
  19. package/template/.cowork-flow/scripts/services/ac_evidence.py +107 -0
  20. package/template/.cowork-flow/scripts/services/fact_view.py +16 -2
  21. package/template/.cowork-flow/scripts/services/lifecycle_checks.py +84 -0
  22. package/template/.cowork-flow/scripts/services/lifecycle_policy.py +5 -0
  23. package/template/.cowork-flow/scripts/services/spec_check.py +11 -1
  24. package/template/.cowork-flow/scripts/services/task_lifecycle.py +12 -0
  25. package/template/.cowork-flow/spec/contracts/context-injection.md +6 -4
  26. package/template/.cowork-flow/spec/contracts/decision-anchor.md +1 -0
  27. package/template/.cowork-flow/spec/contracts/evidence-completion.md +48 -0
  28. package/template/.cowork-flow/spec/contracts/index.md +1 -0
  29. package/template/.cowork-flow/spec/contracts/spec-checks.md +49 -82
  30. package/template/.cowork-flow/spec/runtime/contract-registry.json +13 -0
  31. package/template/.opencode/cowork-flow/plugin-core.js +51 -3
  32. package/template/skills/spec-sync/SKILL.md +1 -0
  33. package/template/skills/task-review/SKILL.md +3 -2
  34. 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*\[[ xX]?\]\s*(AC-[A-Za-z0-9-]+)\s*[::]\s*(.+?)\s*$/)
578
- if (match) result.acceptanceCriteria.push({ id: match[1], text: match[2] })
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
- - **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.
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 findings.
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: