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.
- package/CHANGELOG.md +23 -1
- package/docs/architecture.md +1 -34
- package/docs/direction.md +1 -1
- package/docs/hosts.md +13 -9
- 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/dsh/plugins/workflow-state.js +31 -16
- package/presets/kimi-code/.kimi-plugin/plugin.json +1 -1
- package/presets/opencode/cowork-flow/plugin-core.js +42 -87
- package/presets/opencode/plugins/cowork-flow.js +7 -9
- package/presets/qoder/.qoder-plugin/plugin.json +1 -1
- package/presets/qoder/hooks/hooks.json +1 -1
- package/presets/zcode/.zcode-plugin/plugin.json +1 -1
- package/src/commands/host.js +23 -2
- package/src/commands/registry.js +4 -2
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/adapters/claude-code/adapter.yaml +1 -1
- package/template/.cowork-flow/adapters/codex/adapter.yaml +1 -1
- package/template/.cowork-flow/adapters/dsh/adapter.yaml +1 -1
- package/template/.cowork-flow/adapters/opencode/adapter.yaml +1 -1
- package/template/.cowork-flow/adapters/qoder/adapter.yaml +1 -1
- package/template/.cowork-flow/scripts/adapters/cli/task_lifecycle_commands.py +0 -1
- package/template/.cowork-flow/scripts/adapters/cli/task_parser.py +0 -7
- package/template/.cowork-flow/scripts/adapters/host/claude_code_policy.py +6 -4
- package/template/.cowork-flow/scripts/adapters/host/codex_policy.py +8 -6
- package/template/.cowork-flow/scripts/adapters/host/edit_scope.py +113 -0
- package/template/.cowork-flow/scripts/adapters/host/opencode_policy.py +12 -0
- package/template/.cowork-flow/scripts/adapters/host/qoder_policy.py +7 -5
- package/template/.cowork-flow/scripts/adapters/host/workflow_state_hook.py +0 -91
- package/template/.cowork-flow/scripts/adapters/host/zcode_policy.py +15 -77
- package/template/.cowork-flow/scripts/run.py +0 -2
- package/template/.cowork-flow/scripts/services/context_paths.py +2 -2
- package/template/.cowork-flow/scripts/services/fact_view.py +49 -21
- package/template/.cowork-flow/scripts/services/lifecycle_checks.py +1 -216
- package/template/.cowork-flow/scripts/services/lifecycle_policy.py +0 -5
- package/template/.cowork-flow/scripts/services/task_gate_profiles.py +1 -1
- package/template/.cowork-flow/scripts/services/task_lifecycle.py +14 -31
- package/template/.cowork-flow/spec/backend/error-handling.md +0 -14
- package/template/.cowork-flow/spec/contracts/context-injection.md +49 -22
- package/template/.cowork-flow/spec/contracts/decision-anchor.md +3 -3
- package/template/.cowork-flow/spec/contracts/error-codes.md +1 -3
- package/template/.cowork-flow/spec/contracts/evidence-completion.md +6 -8
- package/template/.cowork-flow/spec/contracts/index.md +0 -1
- package/template/.cowork-flow/spec/contracts/plan-binding.md +3 -2
- package/template/.cowork-flow/spec/contracts/subagent-dispatch.md +6 -21
- package/template/.cowork-flow/spec/contracts/task-adopt.md +1 -1
- package/template/.cowork-flow/spec/runtime/contract-registry.json +0 -13
- package/template/.cowork-flow/spec/runtime/host-assets.json +10 -7
- package/template/.cowork-flow/spec/runtime/scope-rules.json +2 -2
- package/template/.opencode/cowork-flow/plugin-core.js +42 -87
- package/template/.opencode/plugins/cowork-flow.js +7 -9
- package/template/AGENTS.md +0 -1
- package/template/skills/agent-dispatch/SKILL.md +0 -15
- package/template/skills/runtime-health/scripts/doctor.py +0 -49
- package/template/skills/spec-sync/SKILL.md +0 -1
- package/template/skills/task-planning/SKILL.md +1 -1
- package/template/skills/task-review/SKILL.md +3 -3
- package/template/.cowork-flow/scripts/adapters/cli/spec_check.py +0 -178
- package/template/.cowork-flow/scripts/services/spec_check.py +0 -573
- 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())
|