easy-coding-harness 0.3.4 → 0.4.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 +7 -0
- package/package.json +1 -1
- package/templates/common/bundled-skills/ec-meta/references/local-architecture/README.md +5 -0
- package/templates/common/skills/ec-task-management/SKILL.md +44 -10
- package/templates/common/skills/ec-workflow/SKILL.md +45 -39
- package/templates/shared-hooks/easy_coding_state.py +149 -4
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
- `y`:常规功能升级
|
|
7
7
|
- `z`:日常 bug 修复
|
|
8
8
|
|
|
9
|
+
## 0.4.0
|
|
10
|
+
|
|
11
|
+
- 升级跨 agent 交接模型:交接记录只保存交接前 agent、阶段、摘要和时间,不再要求也不保存下一任 agent。
|
|
12
|
+
- 新增 `handoff-task` / `claim-task` 状态 API,交接方可写入 handoff 并释放当前 session,新 agent 可显式 claim 任务并读取最新交接摘要。
|
|
13
|
+
- `ec-task-management` 升级为任务面板:列出未完成任务并标注继续/接手,接手任务展示上一任 agent。
|
|
14
|
+
- `ec-workflow` 路由调整:有当前任务指针时优先继续;无指针时按提示词匹配未完成任务,未命中或无提示词时展示可继续/接手任务列表。
|
|
15
|
+
|
|
9
16
|
## 0.3.4
|
|
10
17
|
|
|
11
18
|
- 修复 Claude Code 中任务已进入 ANALYSIS 但回复没有状态栏的问题:Claude 的 `UserPromptSubmit` 现在会先运行幂等的 `session-start.py`,再运行 `inject-workflow-state.py`,确保每轮提示词都能拿到最新 `status_context`。
|
package/package.json
CHANGED
|
@@ -82,3 +82,8 @@ demand.
|
|
|
82
82
|
continues. All platform-agnostic artifacts (dev-spec, execution.jsonl, task.json, memory)
|
|
83
83
|
make cross-agent handoff lossless. `task.json.last_agent` records the last owner so a new
|
|
84
84
|
agent knows a task was handed off rather than self-interrupted.
|
|
85
|
+
|
|
86
|
+
Handoff is target-less. The leaving agent writes a `handoff` record with `from`, `stage`,
|
|
87
|
+
`summary`, and `timestamp`, then releases its session pointer. It does not know or record the
|
|
88
|
+
next agent. The receiving agent explicitly claims a task through the state API; that claim sets
|
|
89
|
+
the new session pointer and updates `task.json.last_agent`.
|
|
@@ -1,23 +1,56 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ec-task-management
|
|
3
|
-
description:
|
|
3
|
+
description: Task panel for Easy Coding tasks. Use when the user runs {{skill_trigger}}ec-task-management, asks to see tasks, create a task, continue a task, or take over a task handed off by another agent.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# ec-task-management — the task panel
|
|
7
7
|
|
|
8
|
-
A focused
|
|
9
|
-
|
|
8
|
+
A focused task panel: list unfinished tasks, create tasks, and let the user choose one task
|
|
9
|
+
to continue or take over. Stage progression still belongs to ec-workflow; closure belongs
|
|
10
|
+
to ec-task-close.
|
|
10
11
|
|
|
11
12
|
Communicate with the user in the user's language.
|
|
12
13
|
|
|
13
14
|
## Capabilities
|
|
14
15
|
|
|
15
|
-
### List tasks
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
### List unfinished tasks
|
|
17
|
+
|
|
18
|
+
Call the state API with the current agent id:
|
|
19
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py list-tasks --agent <agent-id>`.
|
|
20
|
+
|
|
21
|
+
Show only tasks whose `active` is true. For each task show:
|
|
22
|
+
- id
|
|
23
|
+
- title
|
|
24
|
+
- status
|
|
25
|
+
- created_at
|
|
26
|
+
- action label:
|
|
27
|
+
- `continue` when `action == "continue"`
|
|
28
|
+
- `take over` when `action == "takeover"`
|
|
29
|
+
- previous agent when `previous_agent` is present
|
|
30
|
+
- latest handoff summary when `latest_handoff.summary` is present
|
|
31
|
+
|
|
32
|
+
Use wording in the user's language. The important distinction is:
|
|
33
|
+
- Continue: the current agent was already the last agent.
|
|
34
|
+
- Take over: another agent was the last agent; show that previous agent.
|
|
35
|
+
|
|
36
|
+
### Continue or take over a selected task
|
|
37
|
+
|
|
38
|
+
When the user chooses a listed task, call:
|
|
39
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py claim-task --session-file <P> --task-id <task-id> --agent <agent-id>`.
|
|
40
|
+
|
|
41
|
+
Use the returned `status_context` as the authoritative status source for the rest of the
|
|
42
|
+
current turn. Then report:
|
|
43
|
+
- whether this was `continue` or `takeover`
|
|
44
|
+
- the previous agent if returned
|
|
45
|
+
- the latest handoff summary if returned
|
|
46
|
+
- the current stage
|
|
47
|
+
|
|
48
|
+
After claiming, hand control to ec-workflow semantics: read the task metadata and latest
|
|
49
|
+
execution records, then resume from the current stage. Do not advance stages from this skill
|
|
50
|
+
unless ec-workflow is explicitly invoked or the agent environment routes into it.
|
|
19
51
|
|
|
20
52
|
### Create a task
|
|
53
|
+
|
|
21
54
|
Create through the state API, never by hand-editing `task.json` or session files:
|
|
22
55
|
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py create-task --session-file <P> --task-id <MM-DD-short-name> --type <feature|bugfix|refactor|perf> --title "<one-line summary>" --agent <agent-id> --no-set-current`.
|
|
23
56
|
|
|
@@ -31,6 +64,7 @@ the current turn instead of older hook-injected status text.
|
|
|
31
64
|
|
|
32
65
|
## Boundaries
|
|
33
66
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
- Do not
|
|
67
|
+
- Do not close or cancel tasks — that is ec-task-close.
|
|
68
|
+
- Do not advance stages directly from this skill.
|
|
69
|
+
- Do not ask who the next agent will be. A takeover is decided by the agent that claims the
|
|
70
|
+
task, not by the agent that last handed it off.
|
|
@@ -29,33 +29,32 @@ replies are English.
|
|
|
29
29
|
Do NOT bulk-read ABSTRACT.md or long memory here; ec-analysis loads them on demand.
|
|
30
30
|
3. **State check + Intent routing.** Read the hook-injected breadcrumbs (`[current-task:X]`,
|
|
31
31
|
`[workflow-state:Y]`, `[easy-coding:session-file:P]`) to determine the active task,
|
|
32
|
-
stage, and session file
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
directly (step 4).
|
|
32
|
+
stage, and session file. Then call the task list API with the current agent id:
|
|
33
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py list-tasks --agent <agent-id>`.
|
|
34
|
+
Use only non-terminal tasks (`active == true`) for routing.
|
|
35
|
+
|
|
36
|
+
**Current task pointer exists:**
|
|
37
|
+
- The current task has priority. Resume it by default, even if the user only runs the bare
|
|
38
|
+
skill trigger.
|
|
39
|
+
- If the prompt clearly matches the current task, resume it with the prompt as additional
|
|
40
|
+
context.
|
|
41
|
+
- If the prompt clearly matches a different unfinished task, ask whether to switch to that
|
|
42
|
+
task. Show whether it is `continue` or `takeover`; for takeover show `previous_agent`.
|
|
43
|
+
On confirmation, claim the matched task (see Task switching).
|
|
44
|
+
- If the prompt clearly describes unrelated new work, ask whether to create a new task and
|
|
45
|
+
suspend the current one at its persisted stage.
|
|
46
|
+
|
|
47
|
+
**No current task pointer:**
|
|
48
|
+
- If the prompt matches exactly one unfinished task, show that task and ask whether to
|
|
49
|
+
continue/take it over. For takeover show the previous agent and latest handoff summary.
|
|
50
|
+
On confirmation, claim it (see Task switching).
|
|
51
|
+
- If the prompt matches multiple unfinished tasks, list the matches with `continue` /
|
|
52
|
+
`takeover` labels and ask the user to choose one.
|
|
53
|
+
- If the prompt matches none, or there is no prompt beyond the bare skill trigger, list all
|
|
54
|
+
unfinished tasks with `continue` / `takeover` labels. For takeover entries, show the
|
|
55
|
+
previous agent. Let the user choose one to claim, or choose to start a new task.
|
|
56
|
+
- If there are no unfinished tasks, create a new task only when the user supplied a real
|
|
57
|
+
task prompt; otherwise report that the harness is ready for a new task.
|
|
59
58
|
|
|
60
59
|
4. **New task.** When creating a task (from step 3), create
|
|
61
60
|
the task through the state API, which creates `task.json`, sets `status:"INIT"`, writes
|
|
@@ -98,10 +97,11 @@ any stage --[user abort via ec-task-close]--> CLOSED
|
|
|
98
97
|
|
|
99
98
|
When the user confirms switching from task A to task B:
|
|
100
99
|
1. Task A's status is already persisted in its `task.json` — nothing extra to save.
|
|
101
|
-
2.
|
|
102
|
-
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py
|
|
100
|
+
2. Claim the selected task through the state API:
|
|
101
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py claim-task --session-file <P> --task-id <task-b-id> --agent <agent-id>`.
|
|
103
102
|
3. Use the returned `status_context` as the current status source, then read task B's
|
|
104
|
-
`task.json` to determine its current stage.
|
|
103
|
+
`task.json` to determine its current stage. If the result says `action:"takeover"`, tell
|
|
104
|
+
the user which previous agent owned the task.
|
|
105
105
|
4. Resume task B's stage via the appropriate stage skill.
|
|
106
106
|
|
|
107
107
|
No data is lost — task A's dev-spec, execution.jsonl, and test-strategy.md stay intact on
|
|
@@ -180,12 +180,12 @@ Hook breadcrumbs you may receive: `[workflow-state:X]`, `[current-task:Y]`,
|
|
|
180
180
|
`[easy-coding:session-file:P]`, `[easy-coding:handoff-from:Z]`,
|
|
181
181
|
`[easy-coding:init-required]`.
|
|
182
182
|
|
|
183
|
-
Resuming an active task (whether from session restart, handoff, or task switch):
|
|
183
|
+
Resuming an active task (whether from session restart, claim, handoff, or task switch):
|
|
184
184
|
1. Read `task.json` and the dev-spec sections relevant to the current stage.
|
|
185
185
|
2. Read the tail of `execution.jsonl` — the latest `plan` / `result` / `verify` / `handoff`
|
|
186
186
|
records tell you exactly where work stopped.
|
|
187
|
-
3. If
|
|
188
|
-
|
|
187
|
+
3. If the task was claimed from another agent, read the latest `handoff` record first for the
|
|
188
|
+
fast summary and tell the user which previous agent handed it off.
|
|
189
189
|
4. Tell the user what is being resumed and from which stage, then continue.
|
|
190
190
|
|
|
191
191
|
After a task switch, the same resume flow applies — the only difference is that `current_task`
|
|
@@ -193,13 +193,19 @@ was just changed by the switching procedure rather than being loaded from a prio
|
|
|
193
193
|
|
|
194
194
|
Offering handoff — at WAITING_CONFIRM, after presenting the plan, offer exactly:
|
|
195
195
|
1. Start implementation
|
|
196
|
-
2.
|
|
196
|
+
2. Write handoff and stop
|
|
197
197
|
3. Revise the plan
|
|
198
|
-
On option 2:
|
|
199
|
-
`{
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
198
|
+
On option 2, call:
|
|
199
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py handoff-task --session-file <P> --agent <agent-id> --summary "<dense context: plan shape, key decisions, user emphases>"`.
|
|
200
|
+
|
|
201
|
+
The handoff record is target-less:
|
|
202
|
+
`{"type":"handoff","from":"<agent>","stage":"<stage>","summary":"<dense context>","timestamp":"<ISO>"}`.
|
|
203
|
+
It records who handed the task off, not who will take it next. Do not ask the user to name
|
|
204
|
+
the next agent, and do not invent or store a next-agent field. After writing handoff, stop
|
|
205
|
+
owning the task; another agent can use ec-task-management or ec-workflow to claim it.
|
|
206
|
+
|
|
207
|
+
Handoff is also legal at any other stage boundary on user request. The harness never switches
|
|
208
|
+
agents by itself; the next agent claims the task explicitly.
|
|
203
209
|
|
|
204
210
|
## Status line
|
|
205
211
|
|
|
@@ -242,6 +242,38 @@ def write_task(root: Path, task_id: str, task: dict) -> None:
|
|
|
242
242
|
write_json(task_json_path(root, task_id), task)
|
|
243
243
|
|
|
244
244
|
|
|
245
|
+
def execution_log_path(root: Path, task_id: str) -> Path:
|
|
246
|
+
assert_safe_task_id(task_id)
|
|
247
|
+
return root / ".easy-coding" / "tasks" / task_id / "execution.jsonl"
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def append_execution_record(root: Path, task_id: str, record: dict) -> None:
|
|
251
|
+
path = execution_log_path(root, task_id)
|
|
252
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
253
|
+
with path.open("a", encoding="utf-8") as handle:
|
|
254
|
+
handle.write(json.dumps(record, ensure_ascii=False) + "\n")
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def latest_handoff_record(root: Path, task_id: str) -> dict | None:
|
|
258
|
+
path = execution_log_path(root, task_id)
|
|
259
|
+
if not path.exists():
|
|
260
|
+
return None
|
|
261
|
+
latest: dict | None = None
|
|
262
|
+
try:
|
|
263
|
+
for line in path.read_text(encoding="utf-8").splitlines():
|
|
264
|
+
if not line.strip():
|
|
265
|
+
continue
|
|
266
|
+
try:
|
|
267
|
+
record = json.loads(line)
|
|
268
|
+
except json.JSONDecodeError:
|
|
269
|
+
continue
|
|
270
|
+
if isinstance(record, dict) and record.get("type") == "handoff":
|
|
271
|
+
latest = record
|
|
272
|
+
except OSError:
|
|
273
|
+
return None
|
|
274
|
+
return latest
|
|
275
|
+
|
|
276
|
+
|
|
245
277
|
def assert_safe_task_id(task_id: str) -> None:
|
|
246
278
|
path = Path(task_id)
|
|
247
279
|
if not task_id or path.is_absolute() or "/" in task_id or "\\" in task_id or ".." in path.parts:
|
|
@@ -432,7 +464,15 @@ def attach_status_context(
|
|
|
432
464
|
return enriched
|
|
433
465
|
|
|
434
466
|
|
|
435
|
-
def
|
|
467
|
+
def task_claim_action(task: dict, agent: str | None) -> str | None:
|
|
468
|
+
status = str(task.get("status") or "PENDING")
|
|
469
|
+
if status in TERMINAL_STATUSES or not agent:
|
|
470
|
+
return None
|
|
471
|
+
last_agent = task.get("last_agent")
|
|
472
|
+
return "continue" if not last_agent or last_agent == agent else "takeover"
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def list_tasks(root: Path, agent: str | None = None) -> list[dict]:
|
|
436
476
|
tasks_dir = root / ".easy-coding" / "tasks"
|
|
437
477
|
if not tasks_dir.is_dir():
|
|
438
478
|
return []
|
|
@@ -444,6 +484,8 @@ def list_tasks(root: Path) -> list[dict]:
|
|
|
444
484
|
if not task:
|
|
445
485
|
continue
|
|
446
486
|
status = str(task.get("status") or "PENDING")
|
|
487
|
+
action = task_claim_action(task, agent)
|
|
488
|
+
last_agent = task.get("last_agent")
|
|
447
489
|
items.append(
|
|
448
490
|
{
|
|
449
491
|
"id": entry.name,
|
|
@@ -452,7 +494,10 @@ def list_tasks(root: Path) -> list[dict]:
|
|
|
452
494
|
"status": status,
|
|
453
495
|
"active": status not in TERMINAL_STATUSES,
|
|
454
496
|
"created_at": task.get("created_at"),
|
|
455
|
-
"last_agent":
|
|
497
|
+
"last_agent": last_agent,
|
|
498
|
+
"action": action,
|
|
499
|
+
"previous_agent": last_agent if action == "takeover" else None,
|
|
500
|
+
"latest_handoff": latest_handoff_record(root, entry.name),
|
|
456
501
|
}
|
|
457
502
|
)
|
|
458
503
|
return items
|
|
@@ -487,6 +532,77 @@ def clear_current_task(root: Path, agent: str, session_file: str | Path | None =
|
|
|
487
532
|
return snapshot_state(root, session_file, session)
|
|
488
533
|
|
|
489
534
|
|
|
535
|
+
def handoff_task(
|
|
536
|
+
root: Path,
|
|
537
|
+
agent: str,
|
|
538
|
+
summary: str,
|
|
539
|
+
task_id: str | None = None,
|
|
540
|
+
session_file: str | Path | None = None,
|
|
541
|
+
) -> dict:
|
|
542
|
+
if not summary.strip():
|
|
543
|
+
raise StateError("Handoff summary is required.")
|
|
544
|
+
session = ensure_session(root, session_file)
|
|
545
|
+
resolved_task_id = task_id or session.get("current_task")
|
|
546
|
+
if not resolved_task_id:
|
|
547
|
+
raise StateError("No current task is set.")
|
|
548
|
+
task = load_task(root, str(resolved_task_id))
|
|
549
|
+
if task is None:
|
|
550
|
+
raise StateError(f"Task not found: {resolved_task_id}")
|
|
551
|
+
stage = str(task.get("status") or "PENDING")
|
|
552
|
+
if stage in TERMINAL_STATUSES:
|
|
553
|
+
raise StateError(f"Cannot hand off terminal task: {resolved_task_id}")
|
|
554
|
+
|
|
555
|
+
record = {
|
|
556
|
+
"type": "handoff",
|
|
557
|
+
"from": agent,
|
|
558
|
+
"stage": stage,
|
|
559
|
+
"summary": summary.strip(),
|
|
560
|
+
"timestamp": now_iso(),
|
|
561
|
+
}
|
|
562
|
+
append_execution_record(root, str(resolved_task_id), record)
|
|
563
|
+
task["last_agent"] = agent
|
|
564
|
+
write_task(root, str(resolved_task_id), task)
|
|
565
|
+
|
|
566
|
+
if session.get("current_task") == resolved_task_id:
|
|
567
|
+
clear_session_pointer(session, agent)
|
|
568
|
+
write_session(root, session, session_file)
|
|
569
|
+
|
|
570
|
+
snapshot = snapshot_state(root, session_file, session)
|
|
571
|
+
snapshot["task_id"] = str(resolved_task_id)
|
|
572
|
+
snapshot["handoff"] = record
|
|
573
|
+
snapshot["action"] = "handoff"
|
|
574
|
+
return snapshot
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def claim_task(root: Path, task_id: str, agent: str, session_file: str | Path | None = None) -> dict:
|
|
578
|
+
task = load_task(root, task_id)
|
|
579
|
+
if task is None:
|
|
580
|
+
raise StateError(f"Task not found: {task_id}")
|
|
581
|
+
status = str(task.get("status") or "PENDING")
|
|
582
|
+
if status in TERMINAL_STATUSES:
|
|
583
|
+
raise StateError(f"Cannot claim terminal task: {task_id}")
|
|
584
|
+
|
|
585
|
+
previous_agent = task.get("last_agent")
|
|
586
|
+
action = "continue" if not previous_agent or previous_agent == agent else "takeover"
|
|
587
|
+
latest_handoff = latest_handoff_record(root, task_id)
|
|
588
|
+
task["last_agent"] = agent
|
|
589
|
+
write_task(root, task_id, task)
|
|
590
|
+
|
|
591
|
+
session = ensure_session(root, session_file)
|
|
592
|
+
session["current_task"] = task_id
|
|
593
|
+
session["last_seen_task"] = task_id
|
|
594
|
+
session["last_seen_stage"] = status
|
|
595
|
+
session["last_agent"] = agent
|
|
596
|
+
write_session(root, session, session_file)
|
|
597
|
+
|
|
598
|
+
snapshot = snapshot_state(root, session_file, session)
|
|
599
|
+
snapshot["task_id"] = task_id
|
|
600
|
+
snapshot["action"] = action
|
|
601
|
+
snapshot["previous_agent"] = previous_agent
|
|
602
|
+
snapshot["latest_handoff"] = latest_handoff
|
|
603
|
+
return snapshot
|
|
604
|
+
|
|
605
|
+
|
|
490
606
|
def create_task(
|
|
491
607
|
root: Path,
|
|
492
608
|
task_id: str,
|
|
@@ -675,7 +791,9 @@ def main() -> int:
|
|
|
675
791
|
subcommands = parser.add_subparsers(dest="command")
|
|
676
792
|
|
|
677
793
|
subcommands.add_parser("snapshot", parents=[common])
|
|
678
|
-
|
|
794
|
+
|
|
795
|
+
list_tasks_parser = subcommands.add_parser("list-tasks", parents=[common])
|
|
796
|
+
list_tasks_parser.add_argument("--agent")
|
|
679
797
|
|
|
680
798
|
create = subcommands.add_parser("create-task", parents=[common])
|
|
681
799
|
create.add_argument("--task-id", required=True)
|
|
@@ -691,6 +809,15 @@ def main() -> int:
|
|
|
691
809
|
clear_current = subcommands.add_parser("clear-current", parents=[common])
|
|
692
810
|
clear_current.add_argument("--agent", required=True)
|
|
693
811
|
|
|
812
|
+
handoff = subcommands.add_parser("handoff-task", parents=[common])
|
|
813
|
+
handoff.add_argument("--agent", required=True)
|
|
814
|
+
handoff.add_argument("--summary", required=True)
|
|
815
|
+
handoff.add_argument("--task-id")
|
|
816
|
+
|
|
817
|
+
claim = subcommands.add_parser("claim-task", parents=[common])
|
|
818
|
+
claim.add_argument("--task-id", required=True)
|
|
819
|
+
claim.add_argument("--agent", required=True)
|
|
820
|
+
|
|
694
821
|
transition = subcommands.add_parser("transition", parents=[common])
|
|
695
822
|
transition.add_argument("--stage", required=True)
|
|
696
823
|
transition.add_argument("--agent", required=True)
|
|
@@ -716,7 +843,7 @@ def main() -> int:
|
|
|
716
843
|
if command == "snapshot":
|
|
717
844
|
emit(snapshot_state(root, session_file))
|
|
718
845
|
elif command == "list-tasks":
|
|
719
|
-
emit({"tasks": list_tasks(root)})
|
|
846
|
+
emit({"tasks": list_tasks(root, getattr(args, "agent", None))})
|
|
720
847
|
elif command == "create-task":
|
|
721
848
|
emit(
|
|
722
849
|
attach_status_context(
|
|
@@ -752,6 +879,24 @@ def main() -> int:
|
|
|
752
879
|
session_file,
|
|
753
880
|
)
|
|
754
881
|
)
|
|
882
|
+
elif command == "handoff-task":
|
|
883
|
+
emit(
|
|
884
|
+
attach_status_context(
|
|
885
|
+
root,
|
|
886
|
+
handoff_task(root, args.agent, args.summary, args.task_id, session_file),
|
|
887
|
+
args.agent,
|
|
888
|
+
session_file,
|
|
889
|
+
)
|
|
890
|
+
)
|
|
891
|
+
elif command == "claim-task":
|
|
892
|
+
emit(
|
|
893
|
+
attach_status_context(
|
|
894
|
+
root,
|
|
895
|
+
claim_task(root, args.task_id, args.agent, session_file),
|
|
896
|
+
args.agent,
|
|
897
|
+
session_file,
|
|
898
|
+
)
|
|
899
|
+
)
|
|
755
900
|
elif command == "transition":
|
|
756
901
|
emit(
|
|
757
902
|
attach_status_context(
|