cowork-flow 0.0.37 → 0.0.39
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/README.md +27 -14
- package/package.json +1 -1
- package/src/commands/init.js +39 -28
- package/src/commands/sync.js +2 -2
- package/src/lib/asset-plan.js +127 -0
- package/src/lib/copy-template.js +101 -141
- package/src/lib/host-assets.js +231 -0
- package/src/lib/plan-applier.js +329 -0
- package/src/lib/platforms.js +15 -76
- package/src/lib/skill-registry.js +503 -0
- package/template/.claude/agents/cowork-check.md +10 -1
- package/template/.claude/agents/cowork-implement.md +11 -2
- package/template/.claude/hooks/inject-workflow-state.py +51 -254
- package/template/.codex/agents/cowork-check.toml +12 -3
- package/template/.codex/agents/cowork-implement.toml +11 -2
- package/template/.codex/agents/default.toml +3 -2
- package/template/.codex/agents/explorer.toml +3 -2
- package/template/.codex/agents/worker.toml +2 -1
- package/template/.codex/hooks/inject-workflow-state.py +46 -265
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/scripts/application/__init__.py +1 -0
- package/template/.cowork-flow/scripts/application/batch_execution.py +743 -0
- package/template/.cowork-flow/scripts/application/runtime_context_service.py +365 -0
- package/template/.cowork-flow/scripts/application/task_archive.py +220 -0
- package/template/.cowork-flow/scripts/application/task_context.py +765 -0
- package/template/.cowork-flow/scripts/application/task_creation.py +201 -0
- package/template/.cowork-flow/scripts/application/task_lifecycle.py +532 -0
- package/template/.cowork-flow/scripts/application/task_tree.py +179 -0
- package/template/.cowork-flow/scripts/commands/doctor.py +78 -57
- package/template/.cowork-flow/scripts/commands/party_mode_v2.py +671 -425
- package/template/.cowork-flow/scripts/commands/subagent.py +38 -26
- package/template/.cowork-flow/scripts/commands/task.py +535 -1953
- package/template/.cowork-flow/scripts/commands/task_archive_commands.py +195 -0
- package/template/.cowork-flow/scripts/commands/task_context_commands.py +240 -0
- package/template/.cowork-flow/scripts/commands/task_create_command.py +164 -0
- package/template/.cowork-flow/scripts/commands/task_navigation.py +407 -0
- package/template/.cowork-flow/scripts/commands/task_parser.py +364 -0
- package/template/.cowork-flow/scripts/commands/task_support.py +76 -0
- package/template/.cowork-flow/scripts/commands/task_tree_commands.py +160 -0
- package/template/.cowork-flow/scripts/common/core/execution_context.py +161 -85
- package/template/.cowork-flow/scripts/common/core/host_manifest.py +393 -0
- package/template/.cowork-flow/scripts/common/core/skill_registry.py +568 -0
- package/template/.cowork-flow/scripts/common/gates/coding_standards.py +58 -7
- package/template/.cowork-flow/scripts/common/gates/gates.py +323 -46
- package/template/.cowork-flow/scripts/common/gates/models.py +196 -0
- package/template/.cowork-flow/scripts/common/gates/registry.py +79 -0
- package/template/.cowork-flow/scripts/common/gates/tdd_evidence.py +13 -13
- package/template/.cowork-flow/scripts/common/gates/validate_coding_standards.py +104 -62
- package/template/.cowork-flow/scripts/common/gates/validate_implementation.py +39 -22
- package/template/.cowork-flow/scripts/common/gates/validate_rules.py +223 -40
- package/template/.cowork-flow/scripts/common/git/git_context.py +216 -182
- package/template/.cowork-flow/scripts/common/host/__init__.py +1 -0
- package/template/.cowork-flow/scripts/common/host/workflow_state_hook.py +303 -0
- package/template/.cowork-flow/scripts/common/storage/__init__.py +1 -0
- package/template/.cowork-flow/scripts/common/storage/operation_log.py +72 -0
- package/template/.cowork-flow/scripts/common/storage/state_store.py +279 -0
- package/template/.cowork-flow/scripts/common/storage/unit_of_work.py +214 -0
- package/template/.cowork-flow/scripts/common/task/active_task.py +93 -135
- package/template/.cowork-flow/scripts/common/task/batch_mode.py +33 -120
- package/template/.cowork-flow/scripts/common/task/decision_review.py +85 -0
- package/template/.cowork-flow/scripts/common/task/readiness.py +9 -15
- package/template/.cowork-flow/scripts/common/task/task_repository.py +156 -0
- package/template/.cowork-flow/scripts/run.py +24 -0
- package/template/.cowork-flow/spec/contracts/decision-anchor.md +8 -2
- package/template/.cowork-flow/spec/contracts/subagent-dispatch.md +2 -4
- package/template/.cowork-flow/spec/contracts/workflow-state-templates.md +1 -1
- package/template/.cowork-flow/spec/protocols/decision-review.md +28 -0
- package/template/.cowork-flow/spec/protocols/review.md +34 -0
- package/template/.cowork-flow/spec/protocols/spec-maintenance.md +16 -0
- package/template/.cowork-flow/spec/protocols/tdd.md +30 -0
- package/template/.cowork-flow/spec/references/definition-of-done.md +4 -4
- package/template/.cowork-flow/spec/references/orchestration-patterns.md +1 -1
- package/template/.cowork-flow/spec/runtime/contract-registry.json +25 -0
- package/template/.cowork-flow/spec/runtime/host-assets.json +214 -0
- package/template/.cowork-flow/spec/runtime/index.md +8 -0
- package/template/.cowork-flow/spec/runtime/rules.json +61 -10
- package/template/.cowork-flow/spec/runtime/skill-registry.json +397 -0
- package/template/.cowork-flow/spec/schemas/host-assets.schema.json +173 -0
- package/template/.cowork-flow/spec/schemas/rules.schema.json +10 -1
- package/template/.cowork-flow/spec/schemas/skill-registry.schema.json +202 -0
- package/template/.cowork-flow/workflow.md +18 -13
- package/template/.opencode/agents/cowork-check.md +11 -0
- package/template/.opencode/agents/cowork-implement.md +16 -1
- package/template/.zcode/.zcode-plugin/plugin.json +1 -1
- package/template/.zcode/hooks/inject-context.js +3 -85
- package/template/.zcode/hooks/inject-context.selfcheck.mjs +6 -6
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/decision-anchor.md +8 -2
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/subagent-dispatch.md +2 -4
- package/template/.zcode/scaffold/.cowork-flow/spec/runtime/rules.json +61 -10
- package/template/.zcode/scaffold/.cowork-flow/spec/schemas/rules.schema.json +10 -1
- package/template/.zcode/scaffold/.cowork-flow/workflow.md +18 -13
- package/template/.zcode/scaffold/AGENTS.md +18 -8
- package/template/AGENTS.md +1 -1
- package/template/skills/batch-mode/SKILL.md +140 -76
- package/template/skills/brainstorming/SKILL.md +2 -2
- package/template/skills/cowork-flow/SKILL.md +42 -0
- package/template/skills/party-mode/SHARED-BOUNDARIES.md +1 -1
- package/template/skills/party-mode/SKILL.md +48 -119
- package/template/.cowork-flow/scripts/common/gates/spec_validator.py +0 -53
- package/template/.cowork-flow/scripts/common/gates/validate_jsonl.py +0 -32
- package/template/skills/before-dev/SKILL.md +0 -41
- package/template/skills/check/SKILL.md +0 -53
- package/template/skills/check/simplification-guide.md +0 -47
- package/template/skills/continue/SKILL.md +0 -29
- package/template/skills/doubt-review/SKILL.md +0 -118
- package/template/skills/finish-work/SKILL.md +0 -32
- package/template/skills/party-mode-v2/SKILL.md +0 -75
- package/template/skills/start/SKILL.md +0 -78
- package/template/skills/tdd/SKILL.md +0 -74
- package/template/skills/update-spec/SKILL.md +0 -39
- package/template/skills/using-cowork-flow/SKILL.md +0 -80
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Task creation application service."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from application.task_tree import TaskTreeError, TaskTreeService
|
|
12
|
+
from common.core.paths import (
|
|
13
|
+
FILE_TASK_JSON,
|
|
14
|
+
ensure_task_date_prefix,
|
|
15
|
+
get_tasks_dir,
|
|
16
|
+
)
|
|
17
|
+
from common.task.task_repository import TaskRepository, TaskRepositoryError
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TaskCreationError(RuntimeError):
|
|
21
|
+
"""Raised when task creation cannot be completed."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, code: str, path: Path, detail: str) -> None:
|
|
24
|
+
self.code = code
|
|
25
|
+
self.path = path
|
|
26
|
+
self.detail = detail
|
|
27
|
+
super().__init__(f"{code}: {detail}: {path}")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(frozen=True)
|
|
31
|
+
class TaskCreationRequest:
|
|
32
|
+
title: str
|
|
33
|
+
slug: str
|
|
34
|
+
assignee: str
|
|
35
|
+
priority: str
|
|
36
|
+
description: str | None = None
|
|
37
|
+
creator: str | None = None
|
|
38
|
+
parent: str | Path | None = None
|
|
39
|
+
from_plan: str | Path | None = None
|
|
40
|
+
created_at: str | None = None
|
|
41
|
+
date_prefix: str | None = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class TaskCreationResult:
|
|
46
|
+
task_dir: Path
|
|
47
|
+
directory_existed: bool
|
|
48
|
+
linked_parent: str | None
|
|
49
|
+
missing_parent: str | None
|
|
50
|
+
generated_anchor: bool
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def ensure_tasks_dir(repo_root: Path) -> Path:
|
|
54
|
+
"""Ensure active and archived task directories exist."""
|
|
55
|
+
tasks_dir = get_tasks_dir(repo_root)
|
|
56
|
+
tasks_dir.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
(tasks_dir / "archive").mkdir(parents=True, exist_ok=True)
|
|
58
|
+
return tasks_dir
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TaskCreationService:
|
|
62
|
+
"""Create task metadata and optional parent/plan relationships."""
|
|
63
|
+
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
repo_root: Path,
|
|
67
|
+
*,
|
|
68
|
+
repository: TaskRepository | None = None,
|
|
69
|
+
tree_service: TaskTreeService | None = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
self.repo_root = Path(repo_root)
|
|
72
|
+
self.repository = repository or TaskRepository(self.repo_root)
|
|
73
|
+
self.tree_service = tree_service or TaskTreeService(
|
|
74
|
+
self.repo_root,
|
|
75
|
+
repository=self.repository,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def create(
|
|
79
|
+
self,
|
|
80
|
+
request: TaskCreationRequest,
|
|
81
|
+
) -> TaskCreationResult:
|
|
82
|
+
tasks_dir = ensure_tasks_dir(self.repo_root)
|
|
83
|
+
task_name = self._task_name(request)
|
|
84
|
+
task_dir = tasks_dir / task_name
|
|
85
|
+
directory_existed = task_dir.exists()
|
|
86
|
+
task_dir.mkdir(parents=True, exist_ok=True)
|
|
87
|
+
|
|
88
|
+
created_at = request.created_at or datetime.now().strftime(
|
|
89
|
+
"%Y-%m-%d"
|
|
90
|
+
)
|
|
91
|
+
task_data = {
|
|
92
|
+
"id": request.slug,
|
|
93
|
+
"name": request.slug,
|
|
94
|
+
"title": request.title,
|
|
95
|
+
"description": request.description or "",
|
|
96
|
+
"status": "planning",
|
|
97
|
+
"dev_type": None,
|
|
98
|
+
"scope": None,
|
|
99
|
+
"priority": request.priority,
|
|
100
|
+
"creator": request.creator or request.assignee,
|
|
101
|
+
"assignee": request.assignee,
|
|
102
|
+
"createdAt": created_at,
|
|
103
|
+
"completedAt": None,
|
|
104
|
+
"commit": None,
|
|
105
|
+
"subtasks": [],
|
|
106
|
+
"children": [],
|
|
107
|
+
"parent": None,
|
|
108
|
+
"relatedFiles": [],
|
|
109
|
+
"notes": "",
|
|
110
|
+
"meta": {},
|
|
111
|
+
}
|
|
112
|
+
try:
|
|
113
|
+
self.repository.replace(task_dir, task_data)
|
|
114
|
+
except TaskRepositoryError as error:
|
|
115
|
+
raise TaskCreationError(
|
|
116
|
+
"TASK-CREATE-SAVE-001",
|
|
117
|
+
error.path,
|
|
118
|
+
error.detail,
|
|
119
|
+
) from error
|
|
120
|
+
|
|
121
|
+
linked_parent = None
|
|
122
|
+
missing_parent = None
|
|
123
|
+
if request.parent:
|
|
124
|
+
parent_dir = self.repository.resolve(request.parent)
|
|
125
|
+
if not (parent_dir / FILE_TASK_JSON).is_file():
|
|
126
|
+
missing_parent = str(request.parent)
|
|
127
|
+
else:
|
|
128
|
+
try:
|
|
129
|
+
self.tree_service.link(parent_dir, task_dir)
|
|
130
|
+
except TaskTreeError as error:
|
|
131
|
+
raise TaskCreationError(
|
|
132
|
+
"TASK-CREATE-LINK-001",
|
|
133
|
+
error.path,
|
|
134
|
+
error.detail,
|
|
135
|
+
) from error
|
|
136
|
+
linked_parent = parent_dir.name
|
|
137
|
+
|
|
138
|
+
generated_anchor = self._generate_anchor(
|
|
139
|
+
task_dir,
|
|
140
|
+
request.from_plan,
|
|
141
|
+
)
|
|
142
|
+
return TaskCreationResult(
|
|
143
|
+
task_dir=task_dir,
|
|
144
|
+
directory_existed=directory_existed,
|
|
145
|
+
linked_parent=linked_parent,
|
|
146
|
+
missing_parent=missing_parent,
|
|
147
|
+
generated_anchor=generated_anchor,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
@staticmethod
|
|
151
|
+
def _task_name(request: TaskCreationRequest) -> str:
|
|
152
|
+
if re.match(r"^\d{2}-\d{2}-", request.slug):
|
|
153
|
+
return request.slug
|
|
154
|
+
if request.date_prefix:
|
|
155
|
+
return f"{request.date_prefix}-{request.slug}"
|
|
156
|
+
return ensure_task_date_prefix(request.slug)
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def _generate_anchor(
|
|
160
|
+
task_dir: Path,
|
|
161
|
+
from_plan: str | Path | None,
|
|
162
|
+
) -> bool:
|
|
163
|
+
if not from_plan:
|
|
164
|
+
return False
|
|
165
|
+
plan_path = Path(from_plan)
|
|
166
|
+
if not plan_path.is_file():
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
plan_text = plan_path.read_text(encoding="utf-8")
|
|
171
|
+
except (OSError, UnicodeDecodeError) as error:
|
|
172
|
+
raise TaskCreationError(
|
|
173
|
+
"TASK-CREATE-PLAN-001",
|
|
174
|
+
plan_path,
|
|
175
|
+
"plan cannot be read as UTF-8",
|
|
176
|
+
) from error
|
|
177
|
+
|
|
178
|
+
goal = next(
|
|
179
|
+
(
|
|
180
|
+
line.split(":", 1)[1].strip()
|
|
181
|
+
for line in plan_text.splitlines()
|
|
182
|
+
if line.startswith("**Goal:**")
|
|
183
|
+
or line.startswith("**目标:**")
|
|
184
|
+
),
|
|
185
|
+
None,
|
|
186
|
+
)
|
|
187
|
+
anchor_file = task_dir / "decision-anchor.md"
|
|
188
|
+
if not goal or anchor_file.exists():
|
|
189
|
+
return False
|
|
190
|
+
try:
|
|
191
|
+
anchor_file.write_text(
|
|
192
|
+
f"## 目标\n\n{goal}\n\n## 验收标准\n- [ ] \n",
|
|
193
|
+
encoding="utf-8",
|
|
194
|
+
)
|
|
195
|
+
except OSError as error:
|
|
196
|
+
raise TaskCreationError(
|
|
197
|
+
"TASK-CREATE-PLAN-002",
|
|
198
|
+
anchor_file,
|
|
199
|
+
"decision anchor could not be written",
|
|
200
|
+
) from error
|
|
201
|
+
return True
|