cowork-flow 0.0.25 → 0.0.27

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 (29) hide show
  1. package/README.md +4 -2
  2. package/package.json +1 -1
  3. package/template/.agents/skills/party-mode-v2/SKILL.md +73 -0
  4. package/template/.claude/agents/cowork-implement.md +163 -4
  5. package/template/.claude/skills/party-mode-v2/SKILL.md +73 -0
  6. package/template/.cowork-flow/.version +1 -1
  7. package/template/.cowork-flow/config.yaml +16 -0
  8. package/template/.cowork-flow/scripts/common/active_task.py +8 -0
  9. package/template/.cowork-flow/scripts/common/archive_utils.py +1 -1
  10. package/template/.cowork-flow/scripts/common/config.py +93 -0
  11. package/template/.cowork-flow/scripts/common/errors.py +107 -0
  12. package/template/.cowork-flow/scripts/common/validate_coding_standards.py +179 -0
  13. package/template/.cowork-flow/scripts/common/validate_implementation.py +195 -0
  14. package/template/.cowork-flow/scripts/common/validate_rules.py +302 -0
  15. package/template/.cowork-flow/scripts/party_mode_v2.py +646 -0
  16. package/template/.cowork-flow/scripts/run.py +3 -0
  17. package/template/.cowork-flow/scripts/subagent.py +1 -0
  18. package/template/.cowork-flow/scripts/task.py +68 -2
  19. package/template/.cowork-flow/spec/party-mode-v2-actions.schema.json +43 -0
  20. package/template/.cowork-flow/spec/party-mode-v2-board.md +43 -0
  21. package/template/.cowork-flow/spec/registry.json +13 -0
  22. package/template/.cowork-flow/spec/rules.json +159 -0
  23. package/template/.cowork-flow/spec/rules.schema.json +67 -0
  24. package/template/.cowork-flow/spec/subagent-dispatch.md +2 -0
  25. package/template/.cowork-flow/workflow.md +6 -0
  26. package/template/.opencode/agents/cowork-implement.md +153 -0
  27. package/template/.opencode/commands/party-mode-v2.md +21 -0
  28. package/template/.opencode/plugins/cowork-flow.js +36 -1
  29. package/template/AGENTS.md +2 -6
package/README.md CHANGED
@@ -55,9 +55,11 @@ cowork-flow 是一个用于新项目初始化协作流程的模板仓库。它
55
55
  项目级协作入口,包含编码前思考、简单优先、外科手术式改动、验证优先等基础原则。接入项目后,应把项目名称、技术栈、运行命令、测试命令和提交策略补齐。
56
56
 
57
57
  `template/.agents/skills/`
58
- 本地技能入口,覆盖 start、before-dev、brainstorming、party-mode、writing-plans、check、finish-work、continue、meta、python-design、update-spec 和 break-loop 等协作动作。这里的 skill 应保持通用,不承载某个业务项目的一次性细节。
58
+ 本地技能入口,覆盖 start、before-dev、brainstorming、party-mode、party-mode-v2、writing-plans、check、finish-work、continue、meta、python-design、update-spec 和 break-loop 等协作动作。这里的 skill 应保持通用,不承载某个业务项目的一次性细节。
59
59
 
60
- `party-mode` 是用户手动调用的 advisory roundtable。它通过当前 Host Adapter 协调真实子代理讨论,而不是模拟人设;默认 `max_agents=3`、`max_rounds=3`,配置优先级为本次调用、task/change、本地配置、skill 默认值。Party Mode 只产出建议、证据、分歧和验收信号,不能推进任务状态,也不能替代 `cowork-implement` 或 `cowork-check`。
60
+ `party-mode` 是用户手动调用的 advisory roundtable。它通过当前 Host Adapter 协调真实子代理讨论,而不是模拟人设;默认 `max_agents=3`、`max_rounds=5`,配置优先级为本次调用、task/change、本地配置、skill 默认值。Party Mode 只产出建议、证据、分歧和验收信号,不能推进任务状态,也不能替代 `cowork-implement` 或 `cowork-check`。
61
+
62
+ `party-mode-v2` 是 runtime board controlled advisory workflow。Python runtime 管理看板、当前轮视图、schema 校验、轮次上限和最终报告;子代理通过 board API 交流,主持人只监控和纠偏,不转发或综合观点。
61
63
 
62
64
  `template/.codex/agents/`
63
65
  固定角色 agent 定义,包含 `cowork-research`、`cowork-implement` 和 `cowork-check`,以及对 Codex 默认 `worker`、`default`、`explorer` 的项目级防漂移约束。主会话负责计划与收口,并通过 host adapter 派发固定 agent;正式派发必须先创建 runtime context,再把 `cowork_runtime_context_id` 和 `cowork_host_context_key` 传给子代理。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cowork-flow",
3
- "version": "0.0.25",
3
+ "version": "0.0.27",
4
4
  "description": "CLI for installing and maintaining cowork-flow collaboration templates.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: party-mode-v2
3
+ description: Use when the user requests a runtime-controlled multi-agent board discussion where children communicate through Party Mode V2 board APIs and the moderator only monitors or corrects drift.
4
+ ---
5
+
6
+ # Party Mode V2
7
+
8
+ Use this skill as a thin entrypoint for the Party Mode V2 runtime board. The Python runtime is the source of truth for discussion state, board visibility, validation, round limits, and final reports.
9
+
10
+ ## Boundaries
11
+
12
+ - Party Mode V2 is advisory only.
13
+ - It cannot mutate task status, start/review/complete/archive tasks, add sessions, commit, push, or satisfy formal workflow gates.
14
+ - It cannot satisfy formal Implement or Check completion. Use `cowork-implement` and `cowork-check` for formal phases.
15
+ - Discussion children are leaf executors. They do not dispatch, wait for, list, or close other agents.
16
+ - The moderator does not forward, summarize, rewrite, or synthesize child opinions for other child agents.
17
+
18
+ ## Runtime First
19
+
20
+ Always use the runtime controller:
21
+
22
+ ```text
23
+ .cowork-flow/run party-v2 init
24
+ .cowork-flow/run party-v2 monitor
25
+ .cowork-flow/run party-v2 view
26
+ .cowork-flow/run party-v2 post
27
+ .cowork-flow/run party-v2 respond
28
+ .cowork-flow/run party-v2 advance
29
+ .cowork-flow/run party-v2 finalize
30
+ ```
31
+
32
+ Do not bypass a runtime rejection by manually accepting child output. Runtime validation failures must be fixed by a corrected child submission or by ending the discussion.
33
+
34
+ ## Board Rules
35
+
36
+ - Child agents communicate through the board API.
37
+ - Child-visible board output must be current-round only.
38
+ - Historical board state is runtime-private and may be used only for audit or final reports.
39
+ - Use at least three child agents unless the effective runtime config explicitly allows a different value.
40
+ - The runtime emits host-neutral next actions. The active Host Adapter or moderator executes them for Codex, Claude Code, or OpenCode.
41
+
42
+ ## Child Response Rules
43
+
44
+ When a child sees a different position, it must choose exactly one:
45
+
46
+ ```text
47
+ maintain
48
+ revise
49
+ concede
50
+ ```
51
+
52
+ `concede` requires accepted evidence and why the prior position failed.
53
+ `revise` requires the accepted part, rejected part, and updated position.
54
+ `maintain` requires counter evidence or counter reasoning.
55
+
56
+ Unsupported agreement, vague revision, and evidence-free rebuttal are invalid.
57
+
58
+ ## Moderator Role
59
+
60
+ The moderator may:
61
+
62
+ - run runtime commands,
63
+ - execute host-neutral next actions through the active host,
64
+ - record off-topic warnings through the runtime,
65
+ - close children only when the runtime asks for closeout,
66
+ - show runtime status or final reports to the user.
67
+
68
+ The moderator must not:
69
+
70
+ - forward one child opinion to another child,
71
+ - create a claim table for child prompts,
72
+ - vote-count as validation,
73
+ - decide which child is correct.
@@ -1,10 +1,16 @@
1
1
  ---
2
2
  name: cowork-implement
3
3
  description: Cowork-flow implementation fixed subagent.
4
- tools: Read, Write, Edit, MultiEdit, Grep, Glob, LS, Bash
4
+ mode: subagent
5
+ permission:
6
+ edit: ask
7
+ bash: ask
8
+ task: deny
9
+ todowrite: deny
10
+ external_directory: deny
5
11
  ---
6
12
 
7
- You are the `cowork-implement` fixed subagent for Claude Code.
13
+ You are the `cowork-implement` fixed subagent for OpenCode.
8
14
  You are a leaf executor and must not invoke other agents.
9
15
 
10
16
  Formal `cowork-implement` work requires a bound runtime context. The prompt,
@@ -15,7 +21,7 @@ cowork_runtime_context_id: <runtime_context_id>
15
21
  cowork_host_context_key: <host_context_key>
16
22
  ```
17
23
 
18
- The hook may bind that id to
24
+ The plugin may bind that id to
19
25
  `.cowork-flow/.runtime/subagents/<runtime_context_id>.json` before workflow
20
26
  state is injected. The first child step must still run:
21
27
 
@@ -28,6 +34,159 @@ or names another agent type, report `needs_context` and stop. Do not use
28
34
  `COWORK_ENTRY_CONTRACT_V1` to infer subagent identity; that contract classifies
29
35
  main-session prompts only.
30
36
 
37
+ ---
38
+
39
+ ## Mandatory Pre-Implementation Checklist
40
+
41
+ Before writing any code, you MUST read and apply these spec files:
42
+
43
+ 1. `.cowork-flow/spec/guides/pre-implementation-checklist.md` — confirm scope, level, and success criteria
44
+ 2. `.cowork-flow/spec/guides/cross-layer-thinking-guide.md` — if changes cross 3+ layers
45
+ 3. `.cowork-flow/spec/guides/code-reuse-thinking-guide.md` — before adding new constants/utilities/DTOs
46
+
47
+ Then read the relevant spec directory:
48
+ - Backend work: `.cowork-flow/spec/backend/index.md` (and all linked docs)
49
+ - Frontend work: `.cowork-flow/spec/frontend/index.md` (and all linked docs)
50
+
51
+ ---
52
+
53
+ ## Coding Gates (Hard Constraints)
54
+
55
+ You MUST satisfy every gate below before considering a change complete.
56
+ These are not suggestions — they are mandatory checkpoints.
57
+
58
+ ### Gate 1: Directory Structure Compliance
59
+
60
+ - Backend: follow `.cowork-flow/spec/backend/directory-structure.md`
61
+ - Controller/API: thin entry only (param receive, auth entry, response orchestration)
62
+ - Service/UseCase: business rules
63
+ - Repository/DAO: persistence access
64
+ - Domain Model/Entity/Aggregate: clear boundaries
65
+ - No mixing of unrelated business in one module
66
+ - No business logic in Controllers
67
+ - No business-specialized logic in public modules
68
+ - Frontend: follow `.cowork-flow/spec/frontend/directory-structure.md`
69
+ - Organize by functional module, not by "generic/non-generic"
70
+ - Page entry, business component, shared component, data access, state management must have clear layers
71
+ - Related files for the same feature should be colocated
72
+
73
+ ### Gate 2: Type Safety & Contract Sync
74
+
75
+ - Frontend: follow `.cowork-flow/spec/frontend/type-safety.md`
76
+ - Shared interfaces, enums, error codes come from a single contract source
77
+ - No handwritten duplicate interface definitions
78
+ - When interfaces change, update callers, validation, and display layers together
79
+ - No masking structure problems with casts or forced assertions
80
+ - No missing null/empty/error/boundary state definitions
81
+ - Backend: follow `.cowork-flow/spec/backend/error-handling.md`
82
+ - Unified error codes or error types
83
+ - Layered handling: parameter validation errors, business errors, system errors
84
+ - Stable external error structure; internal context preserved
85
+ - No leaking of underlying exceptions to callers
86
+ - Distinguish "expected business failure" from "system exception"
87
+ - Preserve traceId/requestId/correlationId
88
+ - Have a unified exception fallback
89
+
90
+ ### Gate 3: State Management Boundaries
91
+
92
+ - Frontend: follow `.cowork-flow/spec/frontend/state-management.md`
93
+ - Server state managed by project's unified request/cache solution
94
+ - Client temporary state managed locally
95
+ - Global state only for truly cross-module shared state
96
+ - Handle loading, empty, error, disabled, and insufficient-permission states for ALL user-visible states
97
+ - No elevating local state to global unnecessarily
98
+ - No mixing server state with local state
99
+ - No bypass entries in permission state
100
+
101
+ ### Gate 4: Component & Hook Boundaries
102
+
103
+ - Frontend: follow `.cowork-flow/spec/frontend/component-guidelines.md`
104
+ - Container components handle data & state; presentational components handle rendering
105
+ - Component API stays simple; no "universal component"
106
+ - Complex interactions split into reusable but clearly bounded small components
107
+ - Components must NOT承担过多业务逻辑
108
+ - Props must not be excessive or poorly named
109
+ - Components must not depend on too much external state
110
+ - Frontend: follow `.cowork-flow/spec/frontend/hook-guidelines.md`
111
+ - Extract data fetching, subscriptions, side effects, complex state flows into Hooks
112
+ - Hook return values stay stable and understandable
113
+ - Hook names reflect behavior, not implementation
114
+ - Hooks must NOT hide incomprehensible side effects
115
+ - Hooks must NOT mix multiple unrelated responsibilities
116
+
117
+ ### Gate 5: Database & Transaction Boundaries
118
+
119
+ - Backend: follow `.cowork-flow/spec/backend/database-guidelines.md`
120
+ - Table structure changes managed via migration files or versioned scripts
121
+ - Queries use the project's unified data access approach
122
+ - Write operations must address idempotency, concurrency impact, failure compensation, retry boundaries
123
+ - Audit fields, logical deletion, version numbers, tenant isolation must be consistent within the same data domain
124
+ - Raw SQL, bulk updates, cross-table aggregations, and long transactions must document index/lock/performance/rollback impact
125
+ - New tables must have primary keys, unique constraints, indexes, and necessary audit info
126
+ - Complex queries must avoid N+1, implicit full table scans, and uncontrolled pagination
127
+ - Transactions must NOT include external calls, slow queries, or unnecessary long lock holding
128
+ - Data migrations must address historical data, idempotency, failure recovery, and online rollback
129
+
130
+ ### Gate 6: Logging Standards
131
+
132
+ - Backend: follow `.cowork-flow/spec/backend/logging-guidelines.md`
133
+ - Structured logging
134
+ - Unified recording of request ID, user ID, task ID, or trace ID
135
+ - Error logs record context without repeating the same exception
136
+ - Sensitive fields (account, token, key, ID card, phone) must be masked
137
+ - Never output complete request/response body
138
+ - No temporary `print`/`console` debug output left in main branch
139
+ - No duplicate error printing across layers
140
+
141
+ ### Gate 7: Quality Gates (Pre-Completion)
142
+
143
+ - Backend: follow `.cowork-flow/spec/backend/quality-guidelines.md`
144
+ - Frontend: follow `.cowork-flow/spec/frontend/quality-guidelines.md`
145
+
146
+ Before marking any change complete, you MUST verify:
147
+ 1. Compilation/build/type-check passes
148
+ 2. Key business/interaction paths have automated test or explicit manual verification record
149
+ 3. Error paths, permission paths, data boundaries are verified
150
+ 4. New conventions, contracts, or migration impacts are documented in spec or task records
151
+ 5. Failed verification is NOT worked around by shrinking assertions, deleting tests, or skipping critical paths
152
+
153
+ ---
154
+
155
+ ## Forbidden Patterns (Zero Tolerance)
156
+
157
+ You MUST NOT do any of the following:
158
+
159
+ - Claim completion without verification
160
+ - Use hardcoded values to bypass configuration, permissions, or contracts
161
+ - Use temporary compatibility logic instead of real fixes
162
+ - Change interfaces or data structures without updating docs and callers
163
+ - Catch exceptions and silently swallow errors or return success
164
+ - Use `any`, forced assertions, or empty object defaults to mask real type problems
165
+ - Leave components without loading/empty/error/disabled/permission states
166
+ - Rely on implicit side effects for interactions without explicit data flow and cleanup logic
167
+ - Elevate local state to global state, or duplicate server state as multiple local states
168
+ - Only verify ideal paths, not failures, empty data, or repeated operations
169
+ - Introduce features not required by the PRD
170
+ - Refactor unrelated modules "while you're at it"
171
+ - Make premature abstractions for one-off code
172
+
173
+ ---
174
+
175
+ ## Execution Order
176
+
177
+ 1. Bind runtime context: `./.cowork-flow/run subagent bind <runtime_context_id> <host_context_key>`
178
+ 2. Read task directory from bound runtime context
179
+ 3. Read `<task>/prd.md`, `<task>/info.md`, `<task>/implement.jsonl`, and each JSONL `file` entry
180
+ 4. Read pre-implementation checklist: `.cowork-flow/spec/guides/pre-implementation-checklist.md`
181
+ 5. Read relevant spec directory (backend or frontend) and ALL linked documents
182
+ 6. Apply coding gates — verify each gate before proceeding
183
+ 7. Implement changes within assigned scope
184
+ 8. Run verification commands (compile, lint, test, build, type-check)
185
+ 9. Report changed files and exact verification commands
186
+ 10. Do NOT run task start, task finish, task archive, unscoped resume, commit, or push
187
+
188
+ ---
189
+
31
190
  Rules:
32
191
 
33
192
  - Read the task directory from the bound runtime context.
@@ -35,6 +194,6 @@ Rules:
35
194
  and each JSONL `file` entry.
36
195
  - Keep edits inside the assigned scope.
37
196
  - Report changed files and exact verification commands.
38
- - Do not use the Task tool or invoke subagents.
197
+ - Do not use the `task` tool or invoke subagents.
39
198
  - Do not run task start, task finish, task archive, unscoped resume, commit, or
40
199
  push.
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: party-mode-v2
3
+ description: Use when the user requests a runtime-controlled multi-agent board discussion where children communicate through Party Mode V2 board APIs and the moderator only monitors or corrects drift.
4
+ ---
5
+
6
+ # Party Mode V2
7
+
8
+ Use this skill as a thin entrypoint for the Party Mode V2 runtime board. The Python runtime is the source of truth for discussion state, board visibility, validation, round limits, and final reports.
9
+
10
+ ## Boundaries
11
+
12
+ - Party Mode V2 is advisory only.
13
+ - It cannot mutate task status, start/review/complete/archive tasks, add sessions, commit, push, or satisfy formal workflow gates.
14
+ - It cannot satisfy formal Implement or Check completion. Use `cowork-implement` and `cowork-check` for formal phases.
15
+ - Discussion children are leaf executors. They do not dispatch, wait for, list, or close other agents.
16
+ - The moderator does not forward, summarize, rewrite, or synthesize child opinions for other child agents.
17
+
18
+ ## Runtime First
19
+
20
+ Always use the runtime controller:
21
+
22
+ ```text
23
+ .cowork-flow/run party-v2 init
24
+ .cowork-flow/run party-v2 monitor
25
+ .cowork-flow/run party-v2 view
26
+ .cowork-flow/run party-v2 post
27
+ .cowork-flow/run party-v2 respond
28
+ .cowork-flow/run party-v2 advance
29
+ .cowork-flow/run party-v2 finalize
30
+ ```
31
+
32
+ Do not bypass a runtime rejection by manually accepting child output. Runtime validation failures must be fixed by a corrected child submission or by ending the discussion.
33
+
34
+ ## Board Rules
35
+
36
+ - Child agents communicate through the board API.
37
+ - Child-visible board output must be current-round only.
38
+ - Historical board state is runtime-private and may be used only for audit or final reports.
39
+ - Use at least three child agents unless the effective runtime config explicitly allows a different value.
40
+ - The runtime emits host-neutral next actions. The active Host Adapter or moderator executes them for Codex, Claude Code, or OpenCode.
41
+
42
+ ## Child Response Rules
43
+
44
+ When a child sees a different position, it must choose exactly one:
45
+
46
+ ```text
47
+ maintain
48
+ revise
49
+ concede
50
+ ```
51
+
52
+ `concede` requires accepted evidence and why the prior position failed.
53
+ `revise` requires the accepted part, rejected part, and updated position.
54
+ `maintain` requires counter evidence or counter reasoning.
55
+
56
+ Unsupported agreement, vague revision, and evidence-free rebuttal are invalid.
57
+
58
+ ## Moderator Role
59
+
60
+ The moderator may:
61
+
62
+ - run runtime commands,
63
+ - execute host-neutral next actions through the active host,
64
+ - record off-topic warnings through the runtime,
65
+ - close children only when the runtime asks for closeout,
66
+ - show runtime status or final reports to the user.
67
+
68
+ The moderator must not:
69
+
70
+ - forward one child opinion to another child,
71
+ - create a claim table for child prompts,
72
+ - vote-count as validation,
73
+ - decide which child is correct.
@@ -1 +1 @@
1
- 0.0.25
1
+ 0.0.27
@@ -28,6 +28,22 @@ codex:
28
28
  # .cowork-flow/.runtime/subagents/<id>.json with the subagent helper, then
29
29
  # passes cowork_runtime_context_id through the active host adapter transport.
30
30
 
31
+ #-------------------------------------------------------------------------------
32
+ # Party Mode V2 Runtime Board
33
+ #-------------------------------------------------------------------------------
34
+
35
+ # Party Mode V2 is an advisory, runtime-controlled board discussion mode.
36
+ # The Python runtime owns board state and emits host-neutral next actions; the
37
+ # active host adapter still performs dispatch/wait/close.
38
+ party_mode_v2:
39
+ min_agents: 3
40
+ max_agents: 5
41
+ max_rounds: 5
42
+ max_rebuttal_targets_per_agent: 2
43
+ max_drift_warnings: 2
44
+ fresh_context_per_round: "true"
45
+ require_current_round_only: "true"
46
+
31
47
  #-------------------------------------------------------------------------------
32
48
  # Task Lifecycle Hooks
33
49
  #-------------------------------------------------------------------------------
@@ -66,6 +66,10 @@ def resolve_context_key(values: Mapping[str, object] | None = None) -> str | Non
66
66
  if claude_session and claude_session.strip():
67
67
  return f"claude_{_sanitize(claude_session)}"
68
68
 
69
+ claude_code_session = os.environ.get("CLAUDE_CODE_SESSION_ID")
70
+ if claude_code_session and claude_code_session.strip():
71
+ return f"claude_{_sanitize(claude_code_session)}"
72
+
69
73
  codex_session = os.environ.get("CODEX_SESSION_ID")
70
74
  if codex_session and codex_session.strip():
71
75
  return f"codex_{_sanitize(codex_session)}"
@@ -90,6 +94,8 @@ def resolve_context_key(values: Mapping[str, object] | None = None) -> str | Non
90
94
  (
91
95
  "OPENCODE_SESSION_ID",
92
96
  "opencode_session_id",
97
+ "sessionID",
98
+ "sessionId",
93
99
  ),
94
100
  )
95
101
  if input_opencode_session:
@@ -100,6 +106,8 @@ def resolve_context_key(values: Mapping[str, object] | None = None) -> str | Non
100
106
  (
101
107
  "CLAUDE_SESSION_ID",
102
108
  "claude_session_id",
109
+ "CLAUDE_CODE_SESSION_ID",
110
+ "claude_code_session_id",
103
111
  ),
104
112
  )
105
113
  if input_claude_session:
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env python3
1
+ #!/usr/bin/env python3
2
2
  """Small resumable directory archive helpers."""
3
3
 
4
4
  from __future__ import annotations
@@ -16,6 +16,13 @@ from .paths import DIR_WORKFLOW, get_repo_root
16
16
  DEFAULT_SESSION_COMMIT_MESSAGE = "chore: record journal"
17
17
  DEFAULT_MAX_JOURNAL_LINES = 2000
18
18
  DEFAULT_CODEX_DISPATCH_MODE = "sub-agent"
19
+ DEFAULT_PARTY_MODE_V2_MIN_AGENTS = 3
20
+ DEFAULT_PARTY_MODE_V2_MAX_AGENTS = 5
21
+ DEFAULT_PARTY_MODE_V2_MAX_ROUNDS = 5
22
+ DEFAULT_PARTY_MODE_V2_MAX_REBUTTAL_TARGETS_PER_AGENT = 2
23
+ DEFAULT_PARTY_MODE_V2_MAX_DRIFT_WARNINGS = 2
24
+ DEFAULT_PARTY_MODE_V2_FRESH_CONTEXT_PER_ROUND = True
25
+ DEFAULT_PARTY_MODE_V2_REQUIRE_CURRENT_ROUND_ONLY = True
19
26
 
20
27
  CONFIG_FILE = "config.yaml"
21
28
 
@@ -139,3 +146,89 @@ def get_codex_dispatch_mode(repo_root: Path | None = None) -> str:
139
146
  if mode in {"sub-agent", "inline"}:
140
147
  return str(mode)
141
148
  return DEFAULT_CODEX_DISPATCH_MODE
149
+
150
+ def _get_section(config: dict, section_name: str) -> dict:
151
+ section = config.get(section_name)
152
+ if isinstance(section, dict):
153
+ return section
154
+ return {}
155
+
156
+ def _get_int(section: dict, key: str, default: int, *, minimum: int | None = None) -> int:
157
+ value = section.get(key, default)
158
+ try:
159
+ parsed = int(value)
160
+ except (TypeError, ValueError):
161
+ return default
162
+ if minimum is not None and parsed < minimum:
163
+ return default
164
+ return parsed
165
+
166
+ def _get_bool(section: dict, key: str, default: bool) -> bool:
167
+ value = section.get(key, default)
168
+ if isinstance(value, bool):
169
+ return value
170
+ if isinstance(value, str):
171
+ normalized = value.strip().lower()
172
+ if normalized in {"true", "1", "yes", "on"}:
173
+ return True
174
+ if normalized in {"false", "0", "no", "off"}:
175
+ return False
176
+ return default
177
+
178
+ def get_party_mode_v2_config(repo_root: Path | None = None) -> dict[str, int | bool]:
179
+ """Get Party Mode V2 runtime-board defaults."""
180
+ config = _load_config(repo_root)
181
+ section = _get_section(config, "party_mode_v2")
182
+ min_agents = _get_int(
183
+ section,
184
+ "min_agents",
185
+ DEFAULT_PARTY_MODE_V2_MIN_AGENTS,
186
+ minimum=3,
187
+ )
188
+ max_agents = _get_int(
189
+ section,
190
+ "max_agents",
191
+ DEFAULT_PARTY_MODE_V2_MAX_AGENTS,
192
+ minimum=min_agents,
193
+ )
194
+ return {
195
+ "min_agents": min_agents,
196
+ "max_agents": max_agents,
197
+ "max_rounds": _get_int(
198
+ section,
199
+ "max_rounds",
200
+ DEFAULT_PARTY_MODE_V2_MAX_ROUNDS,
201
+ minimum=1,
202
+ ),
203
+ "max_rebuttal_targets_per_agent": _get_int(
204
+ section,
205
+ "max_rebuttal_targets_per_agent",
206
+ DEFAULT_PARTY_MODE_V2_MAX_REBUTTAL_TARGETS_PER_AGENT,
207
+ minimum=1,
208
+ ),
209
+ "max_drift_warnings": _get_int(
210
+ section,
211
+ "max_drift_warnings",
212
+ DEFAULT_PARTY_MODE_V2_MAX_DRIFT_WARNINGS,
213
+ minimum=0,
214
+ ),
215
+ "fresh_context_per_round": _get_bool(
216
+ section,
217
+ "fresh_context_per_round",
218
+ DEFAULT_PARTY_MODE_V2_FRESH_CONTEXT_PER_ROUND,
219
+ ),
220
+ "require_current_round_only": _get_bool(
221
+ section,
222
+ "require_current_round_only",
223
+ DEFAULT_PARTY_MODE_V2_REQUIRE_CURRENT_ROUND_ONLY,
224
+ ),
225
+ }
226
+
227
+ def get_party_mode_v2_min_agents(repo_root: Path | None = None) -> int:
228
+ return int(get_party_mode_v2_config(repo_root)["min_agents"])
229
+
230
+ def get_party_mode_v2_max_agents(repo_root: Path | None = None) -> int:
231
+ return int(get_party_mode_v2_config(repo_root)["max_agents"])
232
+
233
+ def get_party_mode_v2_max_rounds(repo_root: Path | None = None) -> int:
234
+ return int(get_party_mode_v2_config(repo_root)["max_rounds"])
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Error handling utilities for cowork-flow.
4
+
5
+ Provides centralized error types and formatted output.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import sys
11
+ from typing import Any
12
+
13
+
14
+ class CoworkFlowError(Exception):
15
+ """Base error for cowork-flow."""
16
+
17
+ def __init__(
18
+ self,
19
+ message: str,
20
+ suggestion: str | None = None,
21
+ exit_code: int = 1,
22
+ context: dict[str, Any] | None = None,
23
+ ):
24
+ super().__init__(message)
25
+ self.suggestion = suggestion
26
+ self.exit_code = exit_code
27
+ self.context = context or {}
28
+
29
+ def to_dict(self) -> dict[str, Any]:
30
+ """Convert error to dictionary format."""
31
+ result = {
32
+ "error_code": self.__class__.__name__,
33
+ "message": str(self),
34
+ "suggestion": self.suggestion,
35
+ "context": self.context,
36
+ }
37
+ return result
38
+
39
+
40
+ class TaskError(CoworkFlowError):
41
+ """Task-related errors."""
42
+ pass
43
+
44
+
45
+ class ConfigError(CoworkFlowError):
46
+ """Configuration errors."""
47
+ pass
48
+
49
+
50
+ class ValidationError(CoworkFlowError):
51
+ """Validation errors."""
52
+ pass
53
+
54
+
55
+ class AdapterError(CoworkFlowError):
56
+ """Adapter-related errors."""
57
+ pass
58
+
59
+
60
+ def print_error(error: CoworkFlowError, file=None) -> None:
61
+ """
62
+ Print formatted error with suggestion.
63
+
64
+ Args:
65
+ error: The error to print
66
+ file: Output file (defaults to stderr)
67
+ """
68
+ output = file or sys.stderr
69
+
70
+ print(f"Error: {error}", file=output)
71
+ if error.suggestion:
72
+ print(f"Suggestion: {error.suggestion}", file=output)
73
+
74
+ if error.context:
75
+ print("Context:", file=output)
76
+ for key, value in error.context.items():
77
+ print(f" {key}: {value}", file=output)
78
+
79
+
80
+ def format_error_message(
81
+ error_code: str,
82
+ message: str,
83
+ suggestion: str | None = None,
84
+ context: dict[str, Any] | None = None,
85
+ ) -> str:
86
+ """
87
+ Format error message as JSON string.
88
+
89
+ Args:
90
+ error_code: Error code identifier
91
+ message: Error message
92
+ suggestion: Recovery suggestion
93
+ context: Additional context
94
+
95
+ Returns:
96
+ JSON string of formatted error
97
+ """
98
+ import json
99
+
100
+ error_dict = {
101
+ "error_code": error_code,
102
+ "message": message,
103
+ "suggestion": suggestion,
104
+ "context": context or {},
105
+ }
106
+
107
+ return json.dumps(error_dict, ensure_ascii=False)