cowork-flow 1.9.2 → 2.0.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 (61) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/docs/architecture.md +1 -34
  3. package/docs/direction.md +1 -1
  4. package/docs/hosts.md +13 -9
  5. package/package.json +1 -1
  6. package/presets/claude-code/.claude-plugin/plugin.json +1 -1
  7. package/presets/codex/.codex-plugin/plugin.json +1 -1
  8. package/presets/dsh/plugins/workflow-state.js +31 -16
  9. package/presets/kimi-code/.kimi-plugin/plugin.json +1 -1
  10. package/presets/opencode/cowork-flow/plugin-core.js +42 -87
  11. package/presets/opencode/plugins/cowork-flow.js +7 -9
  12. package/presets/qoder/.qoder-plugin/plugin.json +1 -1
  13. package/presets/qoder/hooks/hooks.json +1 -1
  14. package/presets/zcode/.zcode-plugin/plugin.json +1 -1
  15. package/src/commands/host.js +23 -2
  16. package/src/commands/registry.js +4 -2
  17. package/template/.cowork-flow/.version +1 -1
  18. package/template/.cowork-flow/adapters/claude-code/adapter.yaml +1 -1
  19. package/template/.cowork-flow/adapters/codex/adapter.yaml +1 -1
  20. package/template/.cowork-flow/adapters/dsh/adapter.yaml +1 -1
  21. package/template/.cowork-flow/adapters/opencode/adapter.yaml +1 -1
  22. package/template/.cowork-flow/adapters/qoder/adapter.yaml +1 -1
  23. package/template/.cowork-flow/scripts/adapters/cli/task_lifecycle_commands.py +0 -1
  24. package/template/.cowork-flow/scripts/adapters/cli/task_parser.py +0 -7
  25. package/template/.cowork-flow/scripts/adapters/host/claude_code_policy.py +6 -4
  26. package/template/.cowork-flow/scripts/adapters/host/codex_policy.py +8 -6
  27. package/template/.cowork-flow/scripts/adapters/host/edit_scope.py +113 -0
  28. package/template/.cowork-flow/scripts/adapters/host/opencode_policy.py +12 -0
  29. package/template/.cowork-flow/scripts/adapters/host/qoder_policy.py +7 -5
  30. package/template/.cowork-flow/scripts/adapters/host/workflow_state_hook.py +0 -91
  31. package/template/.cowork-flow/scripts/adapters/host/zcode_policy.py +15 -77
  32. package/template/.cowork-flow/scripts/run.py +0 -2
  33. package/template/.cowork-flow/scripts/services/context_paths.py +2 -2
  34. package/template/.cowork-flow/scripts/services/fact_view.py +49 -21
  35. package/template/.cowork-flow/scripts/services/lifecycle_checks.py +1 -216
  36. package/template/.cowork-flow/scripts/services/lifecycle_policy.py +0 -5
  37. package/template/.cowork-flow/scripts/services/task_gate_profiles.py +1 -1
  38. package/template/.cowork-flow/scripts/services/task_lifecycle.py +14 -31
  39. package/template/.cowork-flow/spec/backend/error-handling.md +0 -14
  40. package/template/.cowork-flow/spec/contracts/context-injection.md +49 -22
  41. package/template/.cowork-flow/spec/contracts/decision-anchor.md +3 -3
  42. package/template/.cowork-flow/spec/contracts/error-codes.md +1 -3
  43. package/template/.cowork-flow/spec/contracts/evidence-completion.md +6 -8
  44. package/template/.cowork-flow/spec/contracts/index.md +0 -1
  45. package/template/.cowork-flow/spec/contracts/plan-binding.md +3 -2
  46. package/template/.cowork-flow/spec/contracts/subagent-dispatch.md +6 -21
  47. package/template/.cowork-flow/spec/contracts/task-adopt.md +1 -1
  48. package/template/.cowork-flow/spec/runtime/contract-registry.json +0 -13
  49. package/template/.cowork-flow/spec/runtime/host-assets.json +10 -7
  50. package/template/.cowork-flow/spec/runtime/scope-rules.json +2 -2
  51. package/template/.opencode/cowork-flow/plugin-core.js +42 -87
  52. package/template/.opencode/plugins/cowork-flow.js +7 -9
  53. package/template/AGENTS.md +0 -1
  54. package/template/skills/agent-dispatch/SKILL.md +0 -15
  55. package/template/skills/runtime-health/scripts/doctor.py +0 -49
  56. package/template/skills/spec-sync/SKILL.md +0 -1
  57. package/template/skills/task-planning/SKILL.md +1 -1
  58. package/template/skills/task-review/SKILL.md +3 -3
  59. package/template/.cowork-flow/scripts/adapters/cli/spec_check.py +0 -178
  60. package/template/.cowork-flow/scripts/services/spec_check.py +0 -573
  61. package/template/.cowork-flow/spec/contracts/spec-checks.md +0 -281
@@ -1,178 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """`run spec-check [--phase edit|lifecycle] [--file <path>...] [--json]`.
4
-
5
- Executes user-declared spec checks (frontmatter `checks:`) and prints a
6
- normalized one-line summary unless `--json`/`--verbose` asks for more. See
7
- services/spec_check.py for the three-state contract (pass/violation/unchecked).
8
- """
9
-
10
- from __future__ import annotations
11
-
12
- import argparse
13
- import json
14
- import sys
15
-
16
- if __package__:
17
- from . import _bootstrap as _bootstrap # noqa: F401
18
- else:
19
- import _bootstrap # noqa: F401
20
-
21
- from infra.paths import get_repo_root
22
- from services.spec_check import SpecCheckError, run_checks, summary_has
23
-
24
-
25
- def _report_exit_code(report: dict) -> int:
26
- """Map a report to the public spec-check exit contract."""
27
- if summary_has(report, "violation"):
28
- return 1
29
- # An executor failure means the checks never produced a verdict; it must
30
- # never exit 0 just because the synthetic report carries no counter.
31
- if (
32
- summary_has(report, "unchecked")
33
- or summary_has(report, "executorError")
34
- or report.get("parseErrors")
35
- ):
36
- return 2
37
- return 0
38
-
39
-
40
- def _parse_error_line(parse_errors: list) -> str:
41
- """Render parse failures so text mode cannot look like a clean run."""
42
- details = []
43
- for item in parse_errors[:3]:
44
- if isinstance(item, dict):
45
- spec = item.get("spec") or "?"
46
- error = item.get("error") or "unknown parse error"
47
- details.append(f"{spec}: {error}")
48
- suffix = f": {'; '.join(details)}" if details else ""
49
- return f"spec-check: {len(parse_errors)} parse error(s){suffix}"
50
-
51
-
52
- def _build_parser() -> argparse.ArgumentParser:
53
- parser = argparse.ArgumentParser(
54
- prog="spec-check",
55
- description=(
56
- "Run user-declared spec checks (frontmatter checks:) for one phase."
57
- ),
58
- )
59
- parser.add_argument(
60
- "--phase",
61
- choices=("edit", "lifecycle"),
62
- default="lifecycle",
63
- help="edit: only declarations matching the given files (2.5s clamp); "
64
- "lifecycle: every declaration honoring its files scope.",
65
- )
66
- parser.add_argument(
67
- "--file",
68
- action="append",
69
- default=None,
70
- help="Changed file path to match against declaration files filters; "
71
- "repeatable. Drives the edit-phase filter and single-file queries.",
72
- )
73
- parser.add_argument(
74
- "--verbose",
75
- action="store_true",
76
- help="Print full command output per result (query mode only).",
77
- )
78
- parser.add_argument(
79
- "--throttled",
80
- action="store_true",
81
- help="Editor-phase mode: single-line report for one file, throttled "
82
- "per file (empty output when nothing to report).",
83
- )
84
- parser.add_argument(
85
- "--json",
86
- action="store_true",
87
- dest="as_json",
88
- help="Print the machine-readable report.",
89
- )
90
- return parser
91
-
92
-
93
- def _run_throttled(repo_root, changed_files: list[str]) -> int:
94
- from services.spec_check import run_edit_checks
95
-
96
- if len(changed_files) != 1:
97
- print("Error: --throttled requires exactly one --file", file=sys.stderr)
98
- return 2
99
- print(run_edit_checks(repo_root, changed_files[0]))
100
- return 0
101
-
102
-
103
- def _print_text_report(report: dict, *, verbose: bool) -> None:
104
- if verbose:
105
- for result in report.get("results", []):
106
- print(f"--- {result.get('spec')} :: {result.get('cmd')}")
107
- for line in result.get("output", []):
108
- print(line)
109
- if result.get("reason"):
110
- print(f"reason: {result['reason']}")
111
-
112
- parse_errors = report.get("parseErrors") or []
113
- if parse_errors:
114
- print(_parse_error_line(parse_errors))
115
- return
116
-
117
- summary = report.get("summary", {})
118
- if not parse_errors and summary.get("declarations") == 0:
119
- # Zero declarations is a fact, not a pass: name it so a missing or
120
- # silently ignored declaration block cannot look like a clean run.
121
- print(
122
- "spec-check: no checks declared "
123
- f"({report.get('specFiles', 0)} spec files scanned)"
124
- )
125
- # The reader of this branch is the session that has just been told
126
- # nothing is enforced, not a human skimming a terminal: without the
127
- # write path and the syntax reference in the same breath, the fact it
128
- # is looking at has no obvious next action attached to it.
129
- print(
130
- "next: write .cowork-flow/spec/<name>.md with frontmatter "
131
- "checks: (any .md under spec/ outside contracts/, runtime/, "
132
- "schemas/); syntax and example: "
133
- ".cowork-flow/spec/contracts/spec-checks.md"
134
- )
135
- return
136
-
137
- from services.spec_check import normalized_one_line
138
-
139
- line = normalized_one_line(report)
140
- if line:
141
- print(line)
142
- return
143
- print(
144
- "spec-check: {pass} passed, {violation} violations, "
145
- "{unchecked} unchecked".format(
146
- **{**{"pass": 0, "violation": 0, "unchecked": 0}, **summary}
147
- )
148
- )
149
-
150
-
151
- def main() -> int:
152
- args = _build_parser().parse_args()
153
- repo_root = get_repo_root()
154
-
155
- if args.throttled:
156
- return _run_throttled(repo_root, args.file or [])
157
-
158
- try:
159
- report = run_checks(
160
- repo_root,
161
- phase=args.phase,
162
- changed_files=args.file or [],
163
- )
164
- except SpecCheckError as error:
165
- print(f"Error: {error}", file=sys.stderr)
166
- return 2
167
-
168
- exit_code = _report_exit_code(report)
169
- if args.as_json:
170
- print(json.dumps(report, ensure_ascii=False, indent=2))
171
- return exit_code
172
-
173
- _print_text_report(report, verbose=args.verbose)
174
- return exit_code
175
-
176
-
177
- if __name__ == "__main__":
178
- sys.exit(main())