cowork-flow 1.2.0 → 1.3.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 +33 -0
- package/README.md +4 -3
- package/package.json +1 -1
- package/template/.claude/hooks/inject-workflow-state.py +12 -98
- package/template/.codex/hooks/inject-workflow-state.py +13 -89
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/scripts/adapters/cli/task.py +4 -1
- package/template/.cowork-flow/scripts/adapters/cli/task_context_commands.py +65 -0
- package/template/.cowork-flow/scripts/adapters/cli/task_parser.py +23 -0
- package/template/.cowork-flow/scripts/adapters/host/claude_code_policy.py +52 -0
- package/template/.cowork-flow/scripts/adapters/host/codex_policy.py +61 -0
- package/template/.cowork-flow/scripts/adapters/host/inject.py +249 -0
- package/template/.cowork-flow/scripts/adapters/host/workflow_state_hook.py +280 -35
- package/template/.cowork-flow/scripts/adapters/host/zcode_policy.py +230 -0
- package/template/.cowork-flow/scripts/adapters/mcp/state_server.py +2 -5
- package/template/.cowork-flow/scripts/runtime/session_state.py +19 -9
- package/template/.cowork-flow/scripts/services/context_discovery.py +18 -5
- package/template/.cowork-flow/scripts/services/fact_view.py +14 -0
- package/template/.cowork-flow/scripts/services/spec_check.py +34 -12
- package/template/.cowork-flow/scripts/services/task_context.py +0 -1
- package/template/.cowork-flow/spec/contracts/context-injection.md +24 -20
- package/template/.cowork-flow/spec/contracts/fact-layer-access.md +43 -8
- package/template/.cowork-flow/spec/contracts/spec-checks.md +40 -8
- package/template/.cowork-flow/spec/contracts/subagent-dispatch.md +21 -0
- package/template/.cowork-flow/spec/runtime/contract-registry.json +12 -0
- package/template/.opencode/plugins/cowork-flow.js +12 -0
- package/template/.zcode/.zcode-plugin/plugin.json +1 -1
- package/template/.zcode/hooks/inject-context.js +95 -971
- package/template/skills/agent-dispatch/SKILL.md +15 -0
- package/template/skills/runtime-health/scripts/doctor.py +90 -0
- package/template/skills/task-planning/SKILL.md +1 -0
- package/template/skills/task-review/SKILL.md +1 -0
- package/template/.zcode/hooks/inject-context.selfcheck.mjs +0 -795
|
@@ -27,6 +27,21 @@ Use this Skill only inside fixed subagents such as `cowork-implement`,
|
|
|
27
27
|
- Treat runtime gates as CLI adapters backed by kernel services; this Skill may
|
|
28
28
|
explain when to run or report them, but does not enforce them.
|
|
29
29
|
|
|
30
|
+
## Spec Self-Check
|
|
31
|
+
|
|
32
|
+
Delegated subagent tool calls receive no edit-phase hook feedback on hosts
|
|
33
|
+
whose plugin hooks cover only the main session stream — a `spec-check[...]
|
|
34
|
+
violation` line never reaches this session, even when the edit violates a
|
|
35
|
+
declared check. Before reporting completion after any file change, run:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
./.cowork-flow/run spec-check
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Fix every reported violation and re-run until the summary is clean, or report
|
|
42
|
+
the remaining violations as blockers. Honor any hook feedback the host does
|
|
43
|
+
deliver; the self-check exists because delivery is not guaranteed.
|
|
44
|
+
|
|
30
45
|
## Role Outputs
|
|
31
46
|
|
|
32
47
|
- `cowork-implement`: report changed files, acceptance IDs, verification
|
|
@@ -641,6 +641,92 @@ def check_spec_checks(repo_root: Path) -> list[dict[str, str]]:
|
|
|
641
641
|
return issues
|
|
642
642
|
|
|
643
643
|
|
|
644
|
+
def _global_mcp_registered() -> bool:
|
|
645
|
+
"""Tolerant probe of user-level host configs for a cowork-flow MCP
|
|
646
|
+
entry. Read-only; missing files simply mean "not registered"."""
|
|
647
|
+
import os
|
|
648
|
+
|
|
649
|
+
home = Path(os.path.expanduser("~"))
|
|
650
|
+
candidates = (
|
|
651
|
+
home / ".zcode" / "cli" / "config.json",
|
|
652
|
+
home / ".claude.json",
|
|
653
|
+
home / ".codex" / "config.toml",
|
|
654
|
+
)
|
|
655
|
+
for path in candidates:
|
|
656
|
+
try:
|
|
657
|
+
if path.is_file() and "cowork-flow" in path.read_text(
|
|
658
|
+
encoding="utf-8", errors="replace"
|
|
659
|
+
):
|
|
660
|
+
return True
|
|
661
|
+
except OSError:
|
|
662
|
+
continue
|
|
663
|
+
return False
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def check_mcp_registration(repo_root: Path) -> list[dict[str, str]]:
|
|
667
|
+
"""MCP fact-layer registration health. Advisory only (never fatal):
|
|
668
|
+
global registration is a supported default, so absence is a hint, not
|
|
669
|
+
an error. Reports project-level .mcp.json presence and the duplicate
|
|
670
|
+
global+project combination."""
|
|
671
|
+
issues: list[dict[str, str]] = []
|
|
672
|
+
project_registered = False
|
|
673
|
+
project_mcp = repo_root / ".mcp.json"
|
|
674
|
+
if project_mcp.is_file():
|
|
675
|
+
try:
|
|
676
|
+
data = json.loads(project_mcp.read_text(encoding="utf-8"))
|
|
677
|
+
servers = (
|
|
678
|
+
data.get("mcpServers") if isinstance(data, dict) else None
|
|
679
|
+
)
|
|
680
|
+
project_registered = isinstance(servers, dict) and any(
|
|
681
|
+
"cowork" in str(name).lower() for name in servers
|
|
682
|
+
)
|
|
683
|
+
issues.append(
|
|
684
|
+
{
|
|
685
|
+
"kind": "mcp",
|
|
686
|
+
"status": "project",
|
|
687
|
+
"message": (
|
|
688
|
+
"project .mcp.json registers the fact layer"
|
|
689
|
+
if project_registered
|
|
690
|
+
else "project .mcp.json present but no cowork-flow server entry"
|
|
691
|
+
),
|
|
692
|
+
}
|
|
693
|
+
)
|
|
694
|
+
except (OSError, json.JSONDecodeError, ValueError):
|
|
695
|
+
issues.append(
|
|
696
|
+
{
|
|
697
|
+
"kind": "mcp",
|
|
698
|
+
"status": "project",
|
|
699
|
+
"message": "project .mcp.json is not valid JSON",
|
|
700
|
+
}
|
|
701
|
+
)
|
|
702
|
+
global_registered = _global_mcp_registered()
|
|
703
|
+
if project_registered and global_registered:
|
|
704
|
+
issues.append(
|
|
705
|
+
{
|
|
706
|
+
"kind": "mcp",
|
|
707
|
+
"status": "duplicate",
|
|
708
|
+
"message": (
|
|
709
|
+
"cowork-flow is registered both globally and at project "
|
|
710
|
+
"level; hosts deduplicate by server name, but removing "
|
|
711
|
+
"one keeps the tool list clean"
|
|
712
|
+
),
|
|
713
|
+
}
|
|
714
|
+
)
|
|
715
|
+
if not project_registered and not global_registered:
|
|
716
|
+
issues.append(
|
|
717
|
+
{
|
|
718
|
+
"kind": "mcp",
|
|
719
|
+
"status": "absent",
|
|
720
|
+
"message": (
|
|
721
|
+
"fact layer not registered: register globally with "
|
|
722
|
+
"`cowork-flow mcp-state`, or add a project .mcp.json "
|
|
723
|
+
"(see spec/contracts/fact-layer-access.md)"
|
|
724
|
+
),
|
|
725
|
+
}
|
|
726
|
+
)
|
|
727
|
+
return issues
|
|
728
|
+
|
|
729
|
+
|
|
644
730
|
def _all_check_result(repo_root: Path) -> dict[str, object]:
|
|
645
731
|
host_issues = _host_issues(repo_root)
|
|
646
732
|
runtime_errors = check_runtime(repo_root)
|
|
@@ -649,6 +735,7 @@ def _all_check_result(repo_root: Path) -> dict[str, object]:
|
|
|
649
735
|
state_recovery_issues = check_state_recovery(repo_root)
|
|
650
736
|
session_hygiene_issues = check_session_hygiene(repo_root)
|
|
651
737
|
spec_check_issues = check_spec_checks(repo_root)
|
|
738
|
+
mcp_issues = check_mcp_registration(repo_root)
|
|
652
739
|
errors: list[dict[str, object]] = []
|
|
653
740
|
for issue in host_issues:
|
|
654
741
|
errors.append({"kind": "host_adapter", **issue})
|
|
@@ -670,6 +757,7 @@ def _all_check_result(repo_root: Path) -> dict[str, object]:
|
|
|
670
757
|
"stateRecovery": state_recovery_issues,
|
|
671
758
|
"sessionHygiene": session_hygiene_issues,
|
|
672
759
|
"specChecks": spec_check_issues,
|
|
760
|
+
"mcpRegistration": mcp_issues,
|
|
673
761
|
},
|
|
674
762
|
}
|
|
675
763
|
|
|
@@ -683,6 +771,8 @@ def _run_checks(repo_root: Path, *, structured: bool = False) -> int:
|
|
|
683
771
|
_print_task_hygiene_issues(result["issues"]["taskHygiene"])
|
|
684
772
|
_print_state_recovery_issues(result["issues"]["stateRecovery"])
|
|
685
773
|
_print_session_hygiene_issues(result["issues"]["sessionHygiene"])
|
|
774
|
+
for issue in result["issues"]["mcpRegistration"]:
|
|
775
|
+
print(f"MCP ({issue['status']}): {issue['message']}")
|
|
686
776
|
if errors:
|
|
687
777
|
for error in errors:
|
|
688
778
|
print(f"ERROR: {error['message']}", file=sys.stderr)
|
|
@@ -128,6 +128,7 @@ Then list task briefs, followed by integrated verification and completion checks
|
|
|
128
128
|
|
|
129
129
|
- For Tiny tasks, keep the brief short but still name exact file boundaries, completion conditions, and verification commands.
|
|
130
130
|
- For behavior changes, include a failing test before implementation when behavior can be tested.
|
|
131
|
+
- For implementation tasks whose changed files are covered by spec `checks:` declarations, include the spec self-check in the task's Verification Command (for example `./.cowork-flow/run spec-check`): delegated subagents receive no edit-phase hook feedback on some hosts (zcode), so the explicit command is the reliable pull path for both self-check and acceptance.
|
|
131
132
|
- Do not add shallow tests just to satisfy process. Avoid tests that only assert existence, mirror implementation details, count mock calls without behavior, or snapshot empty structure.
|
|
132
133
|
- For complex problems, test depth first: business invariants, cross-layer contracts, state transitions, error boundaries, and real regression paths before narrow unit cases.
|
|
133
134
|
- Map behavior-changing tests to stable `decision-anchor.md` acceptance IDs when useful; do not create `tdd.jsonl` or write TDD evidence records into `check.jsonl`.
|
|
@@ -41,6 +41,7 @@ Read only what is needed for the current task:
|
|
|
41
41
|
- **Specs**: project specs are updated when behavior/contracts changed, or the review states why no spec update is needed.
|
|
42
42
|
- **Code quality**: naming, layering, error handling, state boundaries, security-sensitive paths, and complexity are reviewed against applicable user specs.
|
|
43
43
|
- **Lifecycle blockers**: state/scope blockers are fixed before acceptance; review does not invent hard blockers for natural-language specs.
|
|
44
|
+
- **Delegated acceptance**: when the implementation came from a delegated subagent, run `./.cowork-flow/run spec-check` before accepting its report — delegated sessions receive no edit-phase hook feedback on some hosts (zcode), so the report can be silently non-compliant; every violation is fixed or blocks acceptance.
|
|
44
45
|
- **Advisory facts**: helper output is used to focus review, not to declare pass/fail or block completion.
|
|
45
46
|
- **Anti-self-proof**: every claimed pass maps to source, diff, test output, or lifecycle output.
|
|
46
47
|
- **Anti-rationalization**: every accepted gap has an explicit user decision or narrow technical reason.
|