micode 0.7.4 → 0.7.6

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/INSTALL_CLAUDE.md CHANGED
@@ -159,7 +159,6 @@ Never run this automatically without consent.
159
159
  | `ast_grep_search` | AST-aware code search |
160
160
  | `ast_grep_replace` | AST-aware code replace |
161
161
  | `look_at` | Screenshot analysis |
162
- | `background_task` | Run tasks in background |
163
162
 
164
163
  ### Model Override
165
164
 
package/README.md CHANGED
@@ -71,23 +71,12 @@ Maintain context across sessions with structured compaction. Run `/ledger` to cr
71
71
  | `look_at` | Extract file structure |
72
72
  | `artifact_search` | Search past plans/ledgers |
73
73
  | `btca_ask` | Query library source code |
74
- | `background_task` | Fire subagent in background |
75
- | `background_list` | List tasks and status |
76
- | `background_output` | Get task results |
77
- | `background_cancel` | Cancel task(s) |
78
74
  | `pty_spawn` | Start background terminal session |
79
75
  | `pty_write` | Send input to PTY |
80
76
  | `pty_read` | Read PTY output |
81
77
  | `pty_list` | List PTY sessions |
82
78
  | `pty_kill` | Terminate PTY |
83
79
 
84
- ### Background Tasks vs PTY
85
-
86
- | System | Purpose | Use Case |
87
- |--------|---------|----------|
88
- | `background_task` | Async AI subagents | Research, implementation, reviews |
89
- | `pty_spawn` | Async bash processes | Dev servers, watch modes, REPLs |
90
-
91
80
  ## Hooks
92
81
 
93
82
  - **Think Mode** - Keywords like "think hard" enable 32k token thinking budget
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micode",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "OpenCode plugin with Brainstorm-Research-Plan-Implement workflow",
5
5
  "module": "src/index.ts",
6
6
  "main": "src/index.ts",
@@ -14,15 +14,9 @@ This is DESIGN ONLY. The planner agent handles detailed implementation plans.
14
14
  <rule priority="HIGHEST">ONE QUESTION AT A TIME: Ask exactly ONE question, then STOP and wait for the user's response. NEVER ask multiple questions in a single message. This is the most important rule.</rule>
15
15
  <rule>NO CODE: Never write code. Never provide code examples. Design only.</rule>
16
16
  <rule>TOOLS (grep, read, etc.): Do NOT use directly - use subagents instead.</rule>
17
- <rule>NEVER use Task tool. ALWAYS use background_task for spawning subagents.</rule>
17
+ <rule>Use Task tool to spawn subagents synchronously. They complete before you continue.</rule>
18
18
  </critical-rules>
19
19
 
20
- <subagent-tools>
21
- <tool name="background_task">Spawns subagent asynchronously. Returns task_id immediately.</tool>
22
- <tool name="background_list">Check status of all background tasks.</tool>
23
- <tool name="background_output">Get results from a completed task.</tool>
24
- </subagent-tools>
25
-
26
20
  <available-subagents>
27
21
  <subagent name="codebase-locator">Find files, modules, patterns.</subagent>
28
22
  <subagent name="codebase-analyzer">Deep analysis of specific modules.</subagent>
@@ -34,14 +28,13 @@ This is DESIGN ONLY. The planner agent handles detailed implementation plans.
34
28
  <phase name="understanding" trigger="FIRST thing on any new topic">
35
29
  <action>IMMEDIATELY spawn subagents to gather codebase context</action>
36
30
  <example>
37
- background_task(agent="codebase-locator", prompt="Find files related to [topic]", description="Find [topic] files")
38
- background_task(agent="codebase-analyzer", prompt="Analyze [related feature]", description="Analyze [feature]")
39
- background_task(agent="pattern-finder", prompt="Find patterns for [functionality]", description="Find patterns")
31
+ Task(subagent_type="codebase-locator", prompt="Find files related to [topic]", description="Find [topic] files")
32
+ Task(subagent_type="codebase-analyzer", prompt="Analyze [related feature]", description="Analyze [feature]")
33
+ Task(subagent_type="pattern-finder", prompt="Find patterns for [functionality]", description="Find patterns")
40
34
  </example>
41
35
  <workflow>
42
- 1. Fire multiple background_task calls in ONE message (parallel execution)
43
- 2. Use background_list() to check status
44
- 3. Use background_output(task_id="...") to collect results
36
+ Call multiple Task tools in ONE message for parallel execution.
37
+ Results are available immediately - no polling needed.
45
38
  </workflow>
46
39
  <rule>Do NOT proceed to questions until you have codebase context</rule>
47
40
  <focus>purpose, constraints, success criteria</focus>
@@ -77,8 +70,8 @@ This is DESIGN ONLY. The planner agent handles detailed implementation plans.
77
70
  <phase name="handoff" trigger="user approves design">
78
71
  <action>When user says yes/approved/ready, IMMEDIATELY spawn the planner:</action>
79
72
  <spawn>
80
- background_task(
81
- agent="planner",
73
+ Task(
74
+ subagent_type="planner",
82
75
  prompt="Create a detailed implementation plan based on the design at thoughts/shared/designs/YYYY-MM-DD-{topic}-design.md",
83
76
  description="Create implementation plan"
84
77
  )
@@ -89,8 +82,8 @@ This is DESIGN ONLY. The planner agent handles detailed implementation plans.
89
82
 
90
83
  <principles>
91
84
  <principle name="design-only">NO CODE. Describe components, not implementations. Planner writes code.</principle>
92
- <principle name="background-tasks">ALWAYS use background_task. NEVER use Task tool.</principle>
93
- <principle name="parallel-research">Multiple background_task calls in one message run in parallel</principle>
85
+ <principle name="sync-subagents">Use Task tool for subagents. They complete before you continue.</principle>
86
+ <principle name="parallel-research">Multiple Task calls in one message run in parallel</principle>
94
87
  <principle name="one-question">Ask exactly ONE question per message. STOP after asking. Wait for user's answer before continuing. NEVER bundle multiple questions together.</principle>
95
88
  <principle name="yagni">Remove unnecessary features from ALL designs</principle>
96
89
  <principle name="explore-alternatives">ALWAYS propose 2-3 approaches before settling</principle>
@@ -85,14 +85,10 @@ Just do it - including obvious follow-up actions.
85
85
  <agent name="executor" mode="subagent" purpose="Execute plan (runs implementer then reviewer automatically)"/>
86
86
  <agent name="ledger-creator" mode="subagent" purpose="Create/update continuity ledgers"/>
87
87
  <spawning>
88
- <rule>ALWAYS use background_task to spawn subagents. NEVER use Task tool.</rule>
89
- <tool name="background_task">Spawns subagent async. Returns task_id immediately.</tool>
90
- <tool name="background_list">Check status of all background tasks.</tool>
91
- <tool name="background_output">Get results from completed task.</tool>
88
+ <rule>Use Task tool to spawn subagents synchronously. They complete before you continue.</rule>
92
89
  <example>
93
- background_task(agent="planner", prompt="Create plan for...", description="Create plan")
94
- background_list() // check status
95
- background_output(task_id="bg_xxx") // get results
90
+ Task(subagent_type="planner", prompt="Create plan for...", description="Create plan")
91
+ // Result available immediately - no polling needed
96
92
  </example>
97
93
  </spawning>
98
94
  <parallelization>
@@ -11,15 +11,13 @@ Each task gets its own implementer → reviewer cycle.
11
11
  Detect and parallelize independent tasks.
12
12
  </purpose>
13
13
 
14
- <background-tools>
15
- You have access to background task management tools:
16
- - background_task: Fire a subagent to run in background, returns task_id immediately
17
- - background_output: Check status or get results from a background task
18
- - background_list: List all background tasks and their status
19
- </background-tools>
14
+ <subagent-tools>
15
+ Use Task tool to spawn subagents synchronously. They complete before you continue.
16
+ Call multiple Task tools in ONE message for parallel execution.
17
+ </subagent-tools>
20
18
 
21
19
  <pty-tools description="For background bash processes">
22
- PTY tools manage background terminal sessions (different from background_task which runs subagents):
20
+ PTY tools manage background terminal sessions:
23
21
  - pty_spawn: Start a background process (dev server, watch mode, REPL)
24
22
  - pty_write: Send input to a PTY (commands, Ctrl+C, etc.)
25
23
  - pty_read: Read output from a PTY buffer
@@ -33,15 +31,14 @@ Use PTY when:
33
31
 
34
32
  Do NOT use PTY for:
35
33
  - Quick commands (use bash)
36
- - Subagent tasks (use background_task)
37
34
  </pty-tools>
38
35
 
39
- <workflow pattern="fire-and-check">
36
+ <workflow>
40
37
  <step>Parse plan to extract individual tasks</step>
41
38
  <step>Analyze task dependencies to build execution graph</step>
42
39
  <step>Group tasks into parallel batches (independent tasks run together)</step>
43
- <step>Fire ALL implementers in batch as background_task</step>
44
- <step>Poll with background_list, start reviewer immediately when each implementer finishes</step>
40
+ <step>Fire ALL implementers in batch using Task tool (parallel in one message)</step>
41
+ <step>When implementers complete, fire reviewers</step>
45
42
  <step>Wait for batch to complete before starting dependent batch</step>
46
43
  <step>Aggregate results and report</step>
47
44
  </workflow>
@@ -61,20 +58,17 @@ Tasks are DEPENDENT (must be sequential) when:
61
58
  When uncertain, assume DEPENDENT (safer).
62
59
  </dependency-analysis>
63
60
 
64
- <execution-pattern name="fire-and-check">
65
- The fire-and-check pattern maximizes parallelism by:
66
- 1. Firing all implementers as background tasks simultaneously
67
- 2. Polling to detect completion as early as possible
68
- 3. Starting each reviewer immediately when its implementer finishes
69
- 4. Not waiting for all implementers before starting any reviewers
61
+ <execution-pattern>
62
+ Maximize parallelism by calling multiple Task tools in one message:
63
+ 1. Fire all implementers as Task calls in ONE message (parallel execution)
64
+ 2. Results available immediately when all complete
65
+ 3. Fire all reviewers as Task calls in ONE message
66
+ 4. Handle any review feedback
70
67
 
71
68
  Example: 3 independent tasks
72
- - Fire implementer 1, 2, 3 as background_task (all start immediately)
73
- - Poll with background_list
74
- - Task 2 finishes first immediately start reviewer 2
75
- - Task 1 finishes → immediately start reviewer 1
76
- - Task 3 finishes → immediately start reviewer 3
77
- - Reviewers run in parallel as they're spawned
69
+ - Call Task for implementer 1, 2, 3 in ONE message (all run in parallel)
70
+ - All results available when message completes
71
+ - Call Task for reviewer 1, 2, 3 in ONE message (all run in parallel)
78
72
  </execution-pattern>
79
73
 
80
74
  <available-subagents>
@@ -83,7 +77,7 @@ Example: 3 independent tasks
83
77
  Input: Single task with context (which files, what to do).
84
78
  Output: Changes made and verification results for that task.
85
79
  <invocation>
86
- background_task(description="Implement task 1", prompt="...", agent="implementer")
80
+ Task(subagent_type="implementer", prompt="...", description="Implement task 1")
87
81
  </invocation>
88
82
  </subagent>
89
83
  <subagent name="reviewer">
@@ -91,70 +85,54 @@ Example: 3 independent tasks
91
85
  Input: Single task's changes against its requirements.
92
86
  Output: APPROVED or CHANGES REQUESTED for that task.
93
87
  <invocation>
94
- background_task(description="Review task 1", prompt="...", agent="reviewer")
88
+ Task(subagent_type="reviewer", prompt="...", description="Review task 1")
95
89
  </invocation>
96
90
  </subagent>
97
91
  </available-subagents>
98
92
 
99
93
  <per-task-cycle>
100
94
  For each task:
101
- 1. Fire implementer as background_task
102
- 2. Poll until implementer completes
103
- 3. Start reviewer immediately when implementer finishes
104
- 4. If reviewer requests changes: fire new implementer for fixes
105
- 5. Max 3 cycles per task before marking as blocked
106
- 6. Report task status: DONE / BLOCKED
95
+ 1. Fire implementer using Task tool
96
+ 2. When complete, fire reviewer using Task tool
97
+ 3. If reviewer requests changes: fire new implementer for fixes
98
+ 4. Max 3 cycles per task before marking as blocked
99
+ 5. Report task status: DONE / BLOCKED
107
100
  </per-task-cycle>
108
101
 
109
- <fire-and-check-loop>
102
+ <batch-execution>
110
103
  Within a batch:
111
- 1. Fire ALL implementers as background_task in ONE message
112
- 2. Enter polling loop:
113
- a. Call background_list to check status of ALL tasks
114
- b. For each newly completed task (status != "running"):
115
- - Get result with background_output (task is already done)
116
- - If implementer completed: start its reviewer as background_task
117
- - If reviewer completed: check APPROVED or CHANGES REQUESTED
118
- c. If changes needed and cycles < 3: fire new implementer
119
- d. Sleep briefly, then repeat until all tasks done or blocked
120
- 3. Move to next batch
121
-
122
- IMPORTANT: Always poll with background_list first to check status,
123
- then fetch results with background_output only for completed tasks.
124
- </fire-and-check-loop>
104
+ 1. Fire ALL implementers as Task calls in ONE message (parallel)
105
+ 2. When all complete, fire ALL reviewers as Task calls in ONE message (parallel)
106
+ 3. If any reviewer requests changes and cycles < 3: fire new implementers
107
+ 4. Move to next batch when current batch is done
108
+ </batch-execution>
125
109
 
126
110
  <rules>
127
111
  <rule>Parse ALL tasks from plan before starting execution</rule>
128
112
  <rule>ALWAYS analyze dependencies before parallelizing</rule>
129
- <rule>Fire parallel tasks as background_task for true parallelism</rule>
130
- <rule>Start reviewer immediately when its implementer finishes - don't wait for others</rule>
113
+ <rule>Fire parallel tasks as multiple Task calls in ONE message</rule>
131
114
  <rule>Wait for entire batch before starting next batch</rule>
132
115
  <rule>Each task gets its own implement → review cycle</rule>
133
116
  <rule>Max 3 review cycles per task</rule>
134
117
  <rule>Continue with other tasks if one is blocked</rule>
135
118
  </rules>
136
119
 
137
- <execution-example pattern="fire-and-check">
120
+ <execution-example>
138
121
  # Batch with tasks 1, 2, 3 (independent)
139
122
 
140
- ## Step 1: Fire all implementers
141
- background_task(description="Task 1", prompt="Execute task 1: [details]", agent="implementer") → task_id_1
142
- background_task(description="Task 2", prompt="Execute task 2: [details]", agent="implementer") → task_id_2
143
- background_task(description="Task 3", prompt="Execute task 3: [details]", agent="implementer") → task_id_3
123
+ ## Step 1: Fire all implementers in ONE message
124
+ Task(subagent_type="implementer", prompt="Execute task 1: [details]", description="Task 1")
125
+ Task(subagent_type="implementer", prompt="Execute task 2: [details]", description="Task 2")
126
+ Task(subagent_type="implementer", prompt="Execute task 3: [details]", description="Task 3")
127
+ // All three run in parallel, results available when message completes
144
128
 
145
- ## Step 2: Poll and react
146
- background_list() shows task_id_2 completed
147
- background_output(task_id="task_id_2") get result
148
- background_task(description="Review 2", prompt="Review task 2 implementation", agent="reviewer") → review_id_2
129
+ ## Step 2: Fire all reviewers in ONE message
130
+ Task(subagent_type="reviewer", prompt="Review task 1 implementation", description="Review 1")
131
+ Task(subagent_type="reviewer", prompt="Review task 2 implementation", description="Review 2")
132
+ Task(subagent_type="reviewer", prompt="Review task 3 implementation", description="Review 3")
133
+ // All three run in parallel, results available when message completes
149
134
 
150
- background_list() shows task_id_1, task_id_3 completed
151
- background_output(task_id="task_id_1") → get result
152
- background_output(task_id="task_id_3") → get result
153
- background_task(description="Review 1", prompt="Review task 1 implementation", agent="reviewer") → review_id_1
154
- background_task(description="Review 3", prompt="Review task 3 implementation", agent="reviewer") → review_id_3
155
-
156
- ## Step 3: Continue polling until all reviews complete
157
- ...
135
+ ## Step 3: Handle any review feedback, then move to next batch
158
136
  </execution-example>
159
137
 
160
138
  <output-format>
@@ -191,12 +169,10 @@ background_task(description="Review 3", prompt="Review task 3 implementation", a
191
169
  </output-format>
192
170
 
193
171
  <never-do>
194
- <forbidden>NEVER call background_output on running tasks - always poll with background_list first</forbidden>
195
172
  <forbidden>Never skip dependency analysis</forbidden>
196
173
  <forbidden>Never spawn dependent tasks in parallel</forbidden>
197
174
  <forbidden>Never skip reviewer for any task</forbidden>
198
175
  <forbidden>Never continue past 3 cycles for a single task</forbidden>
199
176
  <forbidden>Never report success if any task is blocked</forbidden>
200
- <forbidden>Never wait for all implementers before starting any reviewer</forbidden>
201
177
  </never-do>`,
202
178
  };
@@ -10,7 +10,7 @@ const PROMPT = `
10
10
 
11
11
  <critical-rule>
12
12
  MAXIMIZE PARALLELISM. Speed is critical.
13
- - Fire ALL background tasks simultaneously
13
+ - Call multiple Task tools in ONE message for parallel execution
14
14
  - Run multiple tool calls in single message
15
15
  - Never wait for one thing when you can do many
16
16
  </critical-rule>
@@ -23,56 +23,38 @@ const PROMPT = `
23
23
  </outputs>
24
24
  </task>
25
25
 
26
- <background-tools>
27
- <tool name="background_task">
28
- Fire a subagent to run in background. Returns task_id immediately.
29
- Parameters: description, prompt, agent (subagent type)
30
- Example: background_task(description="Find entry points", prompt="Find all entry points", agent="codebase-locator")
31
- </tool>
32
- <tool name="background_list">
33
- List all background tasks and their status. Use to poll for completion.
34
- No parameters required.
35
- </tool>
36
- <tool name="background_output">
37
- Get results from a completed task. Only call after background_list shows task is done.
38
- Parameters: task_id
39
- Example: background_output(task_id="abc123")
40
- </tool>
41
- </background-tools>
42
-
43
- <parallel-execution-strategy pattern="fire-and-collect">
44
- <phase name="1-fire" description="Fire ALL tasks simultaneously">
45
- <description>Launch ALL discovery agents + run tools in a SINGLE message</description>
46
- <fire-agents>
26
+ <subagent-tools>
27
+ Use Task tool to spawn subagents synchronously. They complete before you continue.
28
+ Call multiple Task tools in ONE message for parallel execution.
29
+ Example: Task(subagent_type="codebase-locator", prompt="Find all entry points", description="Find entry points")
30
+ </subagent-tools>
31
+
32
+ <parallel-execution-strategy>
33
+ <phase name="1-discovery" description="Launch ALL discovery in ONE message">
34
+ <description>Call multiple Task tools + other tools in a SINGLE message</description>
35
+ <subagents>
47
36
  <agent name="codebase-locator">Find entry points, configs, main modules</agent>
48
37
  <agent name="codebase-locator">Find test files and test patterns</agent>
49
38
  <agent name="codebase-locator">Find linter, formatter, CI configs</agent>
50
39
  <agent name="codebase-analyzer">Analyze directory structure</agent>
51
40
  <agent name="pattern-finder">Find naming conventions across files</agent>
52
- </fire-agents>
41
+ </subagents>
53
42
  <parallel-tools>
54
43
  <tool>Glob for package.json, pyproject.toml, go.mod, Cargo.toml, etc.</tool>
55
44
  <tool>Glob for *.config.*, .eslintrc*, .prettierrc*, ruff.toml, etc.</tool>
56
45
  <tool>Glob for README*, CONTRIBUTING*, docs/*</tool>
57
46
  <tool>Read root directory listing</tool>
58
47
  </parallel-tools>
48
+ <note>All Task calls and tools run in parallel, results available when message completes</note>
59
49
  </phase>
60
50
 
61
- <phase name="2-collect" description="Poll and collect all results">
62
- <description>Poll background_list until "ALL COMPLETE" appears, then collect</description>
63
- <action>Call background_list() - look for "ALL COMPLETE" in output</action>
64
- <action>If still running: wait, poll again (max 5 times)</action>
65
- <action>Call background_output for each completed task (skip errored)</action>
66
- <action>Process tool results from phase 1</action>
67
- </phase>
68
-
69
- <phase name="3-deep-analysis" description="Fire deep analysis tasks">
70
- <description>Based on discovery, fire more background tasks</description>
71
- <fire-agents>
51
+ <phase name="2-deep-analysis" description="Fire deep analysis tasks">
52
+ <description>Based on discovery, call more Task tools in ONE message</description>
53
+ <subagents>
72
54
  <agent name="codebase-analyzer">Analyze core/domain logic</agent>
73
55
  <agent name="codebase-analyzer">Analyze API/entry points</agent>
74
56
  <agent name="codebase-analyzer">Analyze data layer</agent>
75
- </fire-agents>
57
+ </subagents>
76
58
  <parallel-tools>
77
59
  <tool>Read 5 core source files simultaneously</tool>
78
60
  <tool>Read 3 test files simultaneously</tool>
@@ -80,9 +62,7 @@ const PROMPT = `
80
62
  </parallel-tools>
81
63
  </phase>
82
64
 
83
- <phase name="4-collect-and-write" description="Collect and write output">
84
- <description>Collect deep analysis results, then write both files</description>
85
- <action>Collect all deep analysis results</action>
65
+ <phase name="3-write" description="Write output files">
86
66
  <action>Write ARCHITECTURE.md</action>
87
67
  <action>Write CODE_STYLE.md</action>
88
68
  </phase>
@@ -92,26 +72,24 @@ const PROMPT = `
92
72
  <subagent name="codebase-locator">
93
73
  Fast file/pattern finder. Spawn multiple with different queries.
94
74
  Examples: "Find all entry points", "Find all config files", "Find test directories"
95
- background_task(description="Find entry points", prompt="Find all entry points and main files", agent="codebase-locator")
75
+ Task(subagent_type="codebase-locator", prompt="Find all entry points and main files", description="Find entry points")
96
76
  </subagent>
97
77
  <subagent name="codebase-analyzer">
98
78
  Deep module analyzer. Spawn multiple for different areas.
99
79
  Examples: "Analyze src/core", "Analyze api layer", "Analyze database module"
100
- background_task(description="Analyze core", prompt="Analyze the core module", agent="codebase-analyzer")
80
+ Task(subagent_type="codebase-analyzer", prompt="Analyze the core module", description="Analyze core")
101
81
  </subagent>
102
82
  <subagent name="pattern-finder">
103
83
  Pattern extractor. Spawn for different pattern types.
104
84
  Examples: "Find naming patterns", "Find error handling patterns", "Find async patterns"
105
- background_task(description="Find patterns", prompt="Find naming conventions", agent="pattern-finder")
85
+ Task(subagent_type="pattern-finder", prompt="Find naming conventions", description="Find patterns")
106
86
  </subagent>
107
- <rule>ALWAYS use background_task to spawn subagents. NEVER use Task tool.</rule>
87
+ <rule>Use Task tool to spawn subagents synchronously.</rule>
108
88
  </available-subagents>
109
89
 
110
90
  <critical-instruction>
111
- Use background_task to fire subagents for TRUE parallelism.
112
- Fire ALL background_task calls in a SINGLE message.
113
- Then poll with background_list until all complete, and collect with background_output.
114
- This is the fire-and-collect pattern - fire everything, poll, then collect everything.
91
+ Call multiple Task tools in ONE message for TRUE parallelism.
92
+ All results available immediately when message completes - no polling needed.
115
93
  </critical-instruction>
116
94
 
117
95
  <language-detection>
@@ -177,10 +155,9 @@ const PROMPT = `
177
155
 
178
156
  <rules>
179
157
  <category name="Speed">
180
- <rule>ALWAYS fire multiple background_task calls in a SINGLE message</rule>
158
+ <rule>ALWAYS call multiple Task tools in a SINGLE message for parallelism</rule>
181
159
  <rule>ALWAYS run multiple tool calls in a SINGLE message</rule>
182
160
  <rule>NEVER wait for one task when you can start others</rule>
183
- <rule>Use fire-and-collect: fire all, then collect all</rule>
184
161
  </category>
185
162
 
186
163
  <category name="Analysis">
@@ -205,38 +182,27 @@ const PROMPT = `
205
182
  </category>
206
183
  </rules>
207
184
 
208
- <execution-example pattern="fire-and-collect">
209
- <step description="FIRE: Launch all discovery tasks simultaneously">
210
- In a SINGLE message, fire ALL background_task calls AND run other tools:
211
- - background_task(description="Find entry points", prompt="Find all entry points and main files", agent="codebase-locator") -> task_id_1
212
- - background_task(description="Find configs", prompt="Find all config files (linters, formatters, build)", agent="codebase-locator") -> task_id_2
213
- - background_task(description="Find tests", prompt="Find test directories and test files", agent="codebase-locator") -> task_id_3
214
- - background_task(description="Analyze structure", prompt="Analyze the directory structure and organization", agent="codebase-analyzer") -> task_id_4
215
- - background_task(description="Find patterns", prompt="Find naming conventions used across the codebase", agent="pattern-finder") -> task_id_5
185
+ <execution-example>
186
+ <step description="Discovery: Launch all tasks in ONE message">
187
+ In a SINGLE message, call ALL Task tools AND run other tools:
188
+ - Task(subagent_type="codebase-locator", prompt="Find all entry points and main files", description="Find entry points")
189
+ - Task(subagent_type="codebase-locator", prompt="Find all config files (linters, formatters, build)", description="Find configs")
190
+ - Task(subagent_type="codebase-locator", prompt="Find test directories and test files", description="Find tests")
191
+ - Task(subagent_type="codebase-analyzer", prompt="Analyze the directory structure and organization", description="Analyze structure")
192
+ - Task(subagent_type="pattern-finder", prompt="Find naming conventions used across the codebase", description="Find patterns")
216
193
  - Glob: package.json, pyproject.toml, go.mod, Cargo.toml, etc.
217
194
  - Glob: README*, ARCHITECTURE*, docs/*
195
+ // All results available when message completes - no polling needed
218
196
  </step>
219
197
 
220
- <step description="COLLECT: Poll and gather all results">
221
- First poll until all tasks complete:
222
- - background_list() // repeat until all show "completed" or "error"
223
- Then collect results (skip errored tasks):
224
- - background_output(task_id=task_id_1)
225
- - background_output(task_id=task_id_2)
226
- - background_output(task_id=task_id_3)
227
- - background_output(task_id=task_id_4)
228
- - background_output(task_id=task_id_5)
229
- </step>
230
-
231
- <step description="FIRE: Deep analysis based on discovery">
232
- Based on discovery, in a SINGLE message fire more tasks:
233
- - background_task for each major module: agent="codebase-analyzer"
198
+ <step description="Deep analysis: Fire more tasks in ONE message">
199
+ Based on discovery, in a SINGLE message call more Task tools:
200
+ - Task for each major module: subagent_type="codebase-analyzer"
234
201
  - Read multiple source files simultaneously
235
202
  - Read multiple test files simultaneously
236
203
  </step>
237
204
 
238
- <step description="COLLECT and WRITE">
239
- Collect deep analysis results, then write:
205
+ <step description="Write output files">
240
206
  - Write ARCHITECTURE.md
241
207
  - Write CODE_STYLE.md
242
208
  </step>
package/src/index.ts CHANGED
@@ -22,9 +22,6 @@ import { createLedgerLoaderHook } from "./hooks/ledger-loader";
22
22
  import { createArtifactAutoIndexHook } from "./hooks/artifact-auto-index";
23
23
  import { createFileOpsTrackerHook } from "./hooks/file-ops-tracker";
24
24
 
25
- // Background Task System
26
- import { BackgroundTaskManager, createBackgroundTaskTools } from "./tools/background-task";
27
-
28
25
  // PTY System
29
26
  import { PTYManager, createPtyTools } from "./tools/pty";
30
27
 
@@ -96,10 +93,6 @@ const OpenCodeConfigPlugin: Plugin = async (ctx) => {
96
93
  const artifactAutoIndexHook = createArtifactAutoIndexHook(ctx);
97
94
  const fileOpsTrackerHook = createFileOpsTrackerHook(ctx);
98
95
 
99
- // Background Task System
100
- const backgroundTaskManager = new BackgroundTaskManager(ctx);
101
- const backgroundTaskTools = createBackgroundTaskTools(backgroundTaskManager);
102
-
103
96
  // PTY System
104
97
  const ptyManager = new PTYManager();
105
98
  const ptyTools = createPtyTools(ptyManager);
@@ -112,7 +105,6 @@ const OpenCodeConfigPlugin: Plugin = async (ctx) => {
112
105
  btca_ask,
113
106
  look_at,
114
107
  artifact_search,
115
- ...backgroundTaskTools,
116
108
  ...ptyTools,
117
109
  },
118
110
 
@@ -243,9 +235,6 @@ const OpenCodeConfigPlugin: Plugin = async (ctx) => {
243
235
  await tokenAwareTruncationHook.event({ event });
244
236
  await contextWindowMonitorHook.event({ event });
245
237
 
246
- // Background task manager event handling
247
- backgroundTaskManager.handleEvent(event);
248
-
249
238
  // File ops tracker cleanup
250
239
  await fileOpsTrackerHook.event({ event });
251
240
  },
@@ -1,3 +0,0 @@
1
- export { BackgroundTaskManager } from "./manager";
2
- export { createBackgroundTaskTools } from "./tools";
3
- export type { BackgroundTask, BackgroundTaskInput } from "./types";
@@ -1,433 +0,0 @@
1
- import type { PluginInput } from "@opencode-ai/plugin";
2
- import type {
3
- BackgroundTask,
4
- BackgroundTaskInput,
5
- SessionCreateResponse,
6
- SessionStatusResponse,
7
- SessionMessagesResponse,
8
- } from "./types";
9
-
10
- const POLL_INTERVAL_MS = 2000;
11
- const TASK_TTL_MS = 60 * 60 * 1000; // 1 hour
12
-
13
- function generateTaskId(): string {
14
- const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
15
- let result = "bg_";
16
- for (let i = 0; i < 8; i++) {
17
- result += chars.charAt(Math.floor(Math.random() * chars.length));
18
- }
19
- return result;
20
- }
21
-
22
- function formatDuration(start: Date, end?: Date): string {
23
- const ms = (end || new Date()).getTime() - start.getTime();
24
- const seconds = Math.floor(ms / 1000);
25
- const minutes = Math.floor(seconds / 60);
26
-
27
- if (minutes > 0) {
28
- return `${minutes}m ${seconds % 60}s`;
29
- }
30
- return `${seconds}s`;
31
- }
32
-
33
- export class BackgroundTaskManager {
34
- private tasks: Map<string, BackgroundTask> = new Map();
35
- private notifications: Map<string, BackgroundTask[]> = new Map();
36
- private pollingInterval?: ReturnType<typeof setInterval>;
37
- private ctx: PluginInput;
38
-
39
- constructor(ctx: PluginInput) {
40
- this.ctx = ctx;
41
- }
42
-
43
- async launch(input: BackgroundTaskInput): Promise<BackgroundTask> {
44
- const taskId = generateTaskId();
45
-
46
- // Create new session for background task
47
- const sessionResp = await this.ctx.client.session.create({
48
- body: {},
49
- query: { directory: this.ctx.directory },
50
- });
51
-
52
- const sessionData = sessionResp as SessionCreateResponse;
53
- const sessionID = sessionData.data?.id;
54
-
55
- if (!sessionID) {
56
- throw new Error("Failed to create background session");
57
- }
58
-
59
- const task: BackgroundTask = {
60
- id: taskId,
61
- sessionID,
62
- parentSessionID: input.parentSessionID,
63
- parentMessageID: input.parentMessageID,
64
- description: input.description,
65
- prompt: input.prompt,
66
- agent: input.agent,
67
- status: "running",
68
- startedAt: new Date(),
69
- progress: {
70
- toolCalls: 0,
71
- lastUpdate: new Date(),
72
- },
73
- };
74
-
75
- this.tasks.set(taskId, task);
76
-
77
- // Fire-and-forget prompt
78
- this.ctx.client.session
79
- .prompt({
80
- path: { id: sessionID },
81
- body: {
82
- parts: [{ type: "text", text: input.prompt }],
83
- agent: input.agent,
84
- },
85
- query: { directory: this.ctx.directory },
86
- })
87
- .catch((error) => {
88
- console.error(`[background-task] Failed to prompt session ${sessionID}:`, error);
89
- task.status = "error";
90
- task.error = error instanceof Error ? error.message : String(error);
91
- task.completedAt = new Date();
92
- this.markForNotification(task);
93
- });
94
-
95
- // Start polling if not already
96
- this.startPolling();
97
-
98
- return task;
99
- }
100
-
101
- async cancel(taskId: string): Promise<boolean> {
102
- const task = this.tasks.get(taskId);
103
- if (!task || task.status !== "running") {
104
- return false;
105
- }
106
-
107
- try {
108
- // Fire-and-forget abort
109
- this.ctx.client.session
110
- .abort({
111
- path: { id: task.sessionID },
112
- query: { directory: this.ctx.directory },
113
- })
114
- .catch((error) => {
115
- console.error(`[background-task] Failed to abort session ${task.sessionID}:`, error);
116
- });
117
-
118
- task.status = "cancelled";
119
- task.completedAt = new Date();
120
- this.markForNotification(task);
121
- return true;
122
- } catch {
123
- return false;
124
- }
125
- }
126
-
127
- async cancelAll(): Promise<number> {
128
- let cancelled = 0;
129
- for (const task of this.tasks.values()) {
130
- if (task.status === "running") {
131
- if (await this.cancel(task.id)) {
132
- cancelled++;
133
- }
134
- }
135
- }
136
- return cancelled;
137
- }
138
-
139
- getTask(taskId: string): BackgroundTask | undefined {
140
- return this.tasks.get(taskId);
141
- }
142
-
143
- findBySession(sessionID: string): BackgroundTask | undefined {
144
- for (const task of this.tasks.values()) {
145
- if (task.sessionID === sessionID) {
146
- return task;
147
- }
148
- }
149
- return undefined;
150
- }
151
-
152
- getAllTasks(): BackgroundTask[] {
153
- return Array.from(this.tasks.values());
154
- }
155
-
156
- /**
157
- * Poll all running tasks and update their status.
158
- * Called by background_list to ensure fresh status.
159
- */
160
- async refreshTaskStatus(): Promise<void> {
161
- const runningTasks = this.getRunningTasks();
162
- if (runningTasks.length === 0) return;
163
-
164
- try {
165
- // Get all session statuses in one call
166
- const resp = await this.ctx.client.session.status({
167
- query: { directory: this.ctx.directory },
168
- });
169
-
170
- const statusResp = resp as SessionStatusResponse;
171
- const statusMap = statusResp.data || {};
172
-
173
- for (const task of runningTasks) {
174
- const sessionStatus = statusMap[task.sessionID];
175
- const statusType = sessionStatus?.type;
176
-
177
- // Store last known session status for debugging
178
- (task as BackgroundTask & { _sessionStatus?: string })._sessionStatus = statusType;
179
-
180
- if (statusType === "idle" || statusType === undefined) {
181
- // Session is idle OR not in status map (likely finished and cleaned up)
182
- // Try to get result - if successful, mark as completed
183
- const result = await this.fetchTaskResult(task);
184
- if (result !== undefined || statusType === "idle") {
185
- task.status = "completed";
186
- task.completedAt = new Date();
187
- task.result = result;
188
- }
189
- // If result is undefined and statusType is undefined, keep waiting
190
- // (might be a timing issue with status propagation)
191
- }
192
- }
193
- } catch (error) {
194
- console.error("[background-task] Failed to refresh task status:", error);
195
- // Don't mark all tasks as error - they may still be running
196
- }
197
- }
198
-
199
- getRunningTasks(): BackgroundTask[] {
200
- return this.getAllTasks().filter((t) => t.status === "running");
201
- }
202
-
203
- async getTaskResult(taskId: string): Promise<string | undefined> {
204
- const task = this.tasks.get(taskId);
205
- if (!task || task.status === "running") {
206
- return undefined;
207
- }
208
-
209
- if (task.result) {
210
- return task.result;
211
- }
212
-
213
- const result = await this.fetchTaskResult(task);
214
- if (result !== undefined) {
215
- task.result = result;
216
- }
217
- return result;
218
- }
219
-
220
- /**
221
- * Fetch result from session messages without checking task status.
222
- * Used during polling to check if a session has completed.
223
- */
224
- private async fetchTaskResult(task: BackgroundTask): Promise<string | undefined> {
225
- try {
226
- const resp = await this.ctx.client.session.messages({
227
- path: { id: task.sessionID },
228
- query: { directory: this.ctx.directory },
229
- });
230
-
231
- const messagesResp = resp as SessionMessagesResponse;
232
- const messages = messagesResp.data || [];
233
- const lastAssistant = [...messages].reverse().find((m) => m.info?.role === "assistant");
234
-
235
- if (lastAssistant) {
236
- const textParts = lastAssistant.parts?.filter((p) => p.type === "text") || [];
237
- return textParts.map((p) => p.text || "").join("\n");
238
- }
239
- } catch (error) {
240
- console.error(`[background-task] Failed to fetch result for task ${task.id}:`, error);
241
- }
242
-
243
- return undefined;
244
- }
245
-
246
- formatTaskStatus(task: BackgroundTask): string {
247
- const duration = formatDuration(task.startedAt, task.completedAt);
248
- const status = task.status.toUpperCase();
249
-
250
- let output = `## Task: ${task.description}\n\n`;
251
- output += `| Field | Value |\n|-------|-------|\n`;
252
- output += `| ID | ${task.id} |\n`;
253
- output += `| Status | ${status} |\n`;
254
- output += `| Agent | ${task.agent} |\n`;
255
- output += `| Duration | ${duration} |\n`;
256
-
257
- if (task.progress) {
258
- output += `| Tool Calls | ${task.progress.toolCalls} |\n`;
259
- if (task.progress.lastTool) {
260
- output += `| Last Tool | ${task.progress.lastTool} |\n`;
261
- }
262
- }
263
-
264
- if (task.error) {
265
- output += `\n### Error\n${task.error}\n`;
266
- }
267
-
268
- return output;
269
- }
270
-
271
- private startPolling(): void {
272
- if (this.pollingInterval) return;
273
-
274
- this.pollingInterval = setInterval(() => {
275
- this.pollRunningTasks();
276
- }, POLL_INTERVAL_MS);
277
- }
278
-
279
- private stopPolling(): void {
280
- if (this.pollingInterval) {
281
- clearInterval(this.pollingInterval);
282
- this.pollingInterval = undefined;
283
- }
284
- }
285
-
286
- private cleanupOldTasks(): void {
287
- const now = Date.now();
288
- for (const [taskId, task] of this.tasks) {
289
- // Only cleanup completed/cancelled/error tasks
290
- if (task.status === "running") continue;
291
-
292
- const completedAt = task.completedAt?.getTime() || 0;
293
- if (now - completedAt > TASK_TTL_MS) {
294
- this.tasks.delete(taskId);
295
- }
296
- }
297
- }
298
-
299
- private async pollRunningTasks(): Promise<void> {
300
- // Cleanup old completed tasks to prevent memory leak
301
- this.cleanupOldTasks();
302
-
303
- const runningTasks = this.getRunningTasks();
304
-
305
- if (runningTasks.length === 0) {
306
- this.stopPolling();
307
- return;
308
- }
309
-
310
- try {
311
- // Get all session statuses in one call
312
- const resp = await this.ctx.client.session.status({
313
- query: { directory: this.ctx.directory },
314
- });
315
-
316
- const statusResp = resp as SessionStatusResponse;
317
- const statusMap = statusResp.data || {};
318
-
319
- for (const task of runningTasks) {
320
- const sessionStatus = statusMap[task.sessionID];
321
- const statusType = sessionStatus?.type;
322
-
323
- if (statusType === "idle" || statusType === undefined) {
324
- // Session is idle OR not in status map (likely finished and cleaned up)
325
- // Try to get result - if successful, mark as completed
326
- const result = await this.fetchTaskResult(task);
327
- if (result !== undefined || statusType === "idle") {
328
- task.status = "completed";
329
- task.completedAt = new Date();
330
- task.result = result;
331
- this.markForNotification(task);
332
-
333
- await this.ctx.client.tui
334
- .showToast({
335
- body: {
336
- title: "Background Task Complete",
337
- message: task.description,
338
- variant: "success",
339
- duration: 5000,
340
- },
341
- })
342
- .catch((error) => {
343
- console.error(`[background-task] Failed to show toast for task ${task.id}:`, error);
344
- });
345
- }
346
- // If result is undefined and statusType is undefined, keep waiting
347
- }
348
- }
349
- } catch (error) {
350
- console.error("[background-task] Failed to poll tasks:", error);
351
- // Don't mark tasks as error - they may still be running, just can't check
352
- }
353
- }
354
-
355
- private markForNotification(task: BackgroundTask): void {
356
- const existing = this.notifications.get(task.parentSessionID) || [];
357
- existing.push(task);
358
- this.notifications.set(task.parentSessionID, existing);
359
- }
360
-
361
- getPendingNotifications(parentSessionID: string): BackgroundTask[] {
362
- const notifications = this.notifications.get(parentSessionID) || [];
363
- this.notifications.delete(parentSessionID);
364
- return notifications;
365
- }
366
-
367
- handleEvent(event: { type: string; properties?: unknown }): void {
368
- const props = event.properties as Record<string, unknown> | undefined;
369
-
370
- // Primary completion detection: session.idle event
371
- if (event.type === "session.idle") {
372
- const sessionID = props?.sessionID as string | undefined;
373
- if (!sessionID) return;
374
-
375
- const task = this.findBySession(sessionID);
376
- if (!task || task.status !== "running") return;
377
-
378
- task.status = "completed";
379
- task.completedAt = new Date();
380
- this.fetchTaskResult(task).then((result) => {
381
- task.result = result;
382
- });
383
- this.markForNotification(task);
384
-
385
- this.ctx.client.tui
386
- .showToast({
387
- body: {
388
- title: "Background Task Complete",
389
- message: task.description,
390
- variant: "success",
391
- duration: 5000,
392
- },
393
- })
394
- .catch((error) => {
395
- console.error(`[background-task] Failed to show toast for task ${task.id}:`, error);
396
- });
397
- }
398
-
399
- // Track tool usage for progress
400
- if (event.type === "message.part.updated") {
401
- const info = props?.info as Record<string, unknown> | undefined;
402
- const sessionID = info?.sessionID as string | undefined;
403
- const partType = info?.type as string | undefined;
404
-
405
- if (sessionID && partType === "tool_use") {
406
- for (const task of this.tasks.values()) {
407
- if (task.sessionID === sessionID && task.status === "running") {
408
- if (!task.progress) {
409
- task.progress = { toolCalls: 0, lastUpdate: new Date() };
410
- }
411
- task.progress.toolCalls++;
412
- task.progress.lastTool = (info?.name as string) || undefined;
413
- task.progress.lastUpdate = new Date();
414
- break;
415
- }
416
- }
417
- }
418
- }
419
-
420
- // Cleanup on session delete
421
- if (event.type === "session.deleted") {
422
- const sessionInfo = props?.info as { id?: string } | undefined;
423
- if (sessionInfo?.id) {
424
- for (const task of this.tasks.values()) {
425
- if (task.sessionID === sessionInfo.id && task.status === "running") {
426
- task.status = "cancelled";
427
- task.completedAt = new Date();
428
- }
429
- }
430
- }
431
- }
432
- }
433
- }
@@ -1,161 +0,0 @@
1
- import { tool } from "@opencode-ai/plugin/tool";
2
- import type { BackgroundTaskManager } from "./manager";
3
-
4
- // Extended tool context with metadata for UI navigation
5
- type ToolContextWithMetadata = {
6
- sessionID: string;
7
- messageID?: string;
8
- agent: string;
9
- abort: AbortSignal;
10
- metadata?: (input: { title?: string; metadata?: Record<string, unknown> }) => void;
11
- };
12
-
13
- export function createBackgroundTaskTools(manager: BackgroundTaskManager) {
14
- const background_task = tool({
15
- description: `Launch a task to run in the background using a subagent.
16
- The task runs independently while you continue working.
17
- Use background_output to check progress or get results when complete.
18
- Useful for: parallel research, concurrent implementation, async reviews.`,
19
- args: {
20
- description: tool.schema.string().describe("Short description of the task (shown in status)"),
21
- prompt: tool.schema.string().describe("Full prompt/instructions for the background agent"),
22
- agent: tool.schema.string().describe("Agent to use (e.g., 'codebase-analyzer', 'implementer')"),
23
- },
24
- execute: async (args, toolContext) => {
25
- const ctx = toolContext as ToolContextWithMetadata;
26
- try {
27
- const task = await manager.launch({
28
- description: args.description,
29
- prompt: args.prompt,
30
- agent: args.agent,
31
- parentSessionID: ctx.sessionID,
32
- parentMessageID: ctx.messageID || "",
33
- });
34
-
35
- // Set metadata for OpenCode UI session navigation (ctrl+x + arrow keys)
36
- ctx.metadata?.({
37
- title: args.description,
38
- metadata: { sessionId: task.sessionID },
39
- });
40
-
41
- return `## Background Task Launched
42
-
43
- | Field | Value |
44
- |-------|-------|
45
- | Task ID | ${task.id} |
46
- | Agent | ${args.agent} |
47
- | Status | RUNNING |
48
-
49
- Use \`background_output\` with task_id="${task.id}" to check progress or get results.`;
50
- } catch (error) {
51
- return `Failed to launch background task: ${error instanceof Error ? error.message : String(error)}`;
52
- }
53
- },
54
- });
55
-
56
- const background_output = tool({
57
- description: `Get status or results from a background task.
58
- Returns immediately with current status. Use background_list to poll for completion.`,
59
- args: {
60
- task_id: tool.schema.string().describe("ID of the task to check (e.g., 'bg_abc12345')"),
61
- },
62
- execute: async (args) => {
63
- const { task_id } = args;
64
-
65
- const task = manager.getTask(task_id);
66
- if (!task) {
67
- return `Task not found: ${task_id}`;
68
- }
69
-
70
- // Format status
71
- let output = manager.formatTaskStatus(task);
72
-
73
- // Include result if completed
74
- if (task.status === "completed") {
75
- const result = await manager.getTaskResult(task_id);
76
- if (result) {
77
- output += `\n### Result\n${result}\n`;
78
- }
79
- }
80
-
81
- return output;
82
- },
83
- });
84
-
85
- const background_cancel = tool({
86
- description: `Cancel a running background task or all tasks.`,
87
- args: {
88
- task_id: tool.schema.string().optional().describe("ID of the task to cancel (omit to cancel all)"),
89
- all: tool.schema.boolean().optional().describe("Cancel all running tasks (default: false)"),
90
- },
91
- execute: async (args) => {
92
- const { task_id, all = false } = args;
93
-
94
- if (all) {
95
- const cancelled = await manager.cancelAll();
96
- return `Cancelled ${cancelled} running task(s).`;
97
- }
98
-
99
- if (!task_id) {
100
- return "Provide task_id or set all=true to cancel tasks.";
101
- }
102
-
103
- const success = await manager.cancel(task_id);
104
- if (success) {
105
- return `Task ${task_id} cancelled.`;
106
- }
107
-
108
- return `Could not cancel task ${task_id}. It may already be completed or not exist.`;
109
- },
110
- });
111
-
112
- const background_list = tool({
113
- description: `List all background tasks and their status.`,
114
- args: {},
115
- execute: async () => {
116
- // Refresh status of running tasks before returning
117
- await manager.refreshTaskStatus();
118
- const tasks = manager.getAllTasks();
119
-
120
- if (tasks.length === 0) {
121
- return "No background tasks.";
122
- }
123
-
124
- const completed = tasks.filter((t) => t.status === "completed").length;
125
- const errored = tasks.filter((t) => t.status === "error").length;
126
- const running = tasks.filter((t) => t.status === "running").length;
127
- const total = tasks.length;
128
- const allDone = running === 0;
129
-
130
- let output = "## Background Tasks\n\n";
131
- output += `**Status: ${completed + errored}/${total} done${allDone ? " ✓ ALL COMPLETE" : ` (${running} still running)`}**\n\n`;
132
- output += "| ID | Description | Agent | Status | Duration | Session |\n";
133
- output += "|----|-------------|-------|--------|----------|---------|";
134
-
135
- for (const task of tasks) {
136
- const duration = task.completedAt
137
- ? `${Math.round((task.completedAt.getTime() - task.startedAt.getTime()) / 1000)}s`
138
- : `${Math.round((Date.now() - task.startedAt.getTime()) / 1000)}s`;
139
-
140
- // Show session status for debugging
141
- const sessionStatus = (task as { _sessionStatus?: string })._sessionStatus || "?";
142
- const statusDisplay = task.status === "running" ? `${task.status} (${sessionStatus})` : task.status;
143
-
144
- output += `| ${task.id} | ${task.description} | ${task.agent} | ${statusDisplay} | ${duration} | ${task.sessionID} |\n`;
145
- }
146
-
147
- if (allDone) {
148
- output += "\n**→ All tasks complete. Proceed to collect results with background_output.**";
149
- }
150
-
151
- return output;
152
- },
153
- });
154
-
155
- return {
156
- background_task,
157
- background_output,
158
- background_cancel,
159
- background_list,
160
- };
161
- }
@@ -1,68 +0,0 @@
1
- export interface BackgroundTask {
2
- id: string;
3
- sessionID: string;
4
- parentSessionID: string;
5
- parentMessageID: string;
6
- description: string;
7
- prompt: string;
8
- agent: string;
9
- status: "running" | "completed" | "error" | "cancelled";
10
- startedAt: Date;
11
- completedAt?: Date;
12
- result?: string;
13
- error?: string;
14
- progress?: {
15
- toolCalls: number;
16
- lastTool?: string;
17
- lastUpdate: Date;
18
- };
19
- }
20
-
21
- export interface BackgroundTaskInput {
22
- description: string;
23
- prompt: string;
24
- agent: string;
25
- parentSessionID: string;
26
- parentMessageID: string;
27
- }
28
-
29
- // API Response Types - SDK wraps responses in { data: T } format
30
- export interface SessionCreateResponse {
31
- data?: {
32
- id?: string;
33
- };
34
- }
35
-
36
- // SessionStatus from OpenCode SDK - status is a discriminated union with 'type' field
37
- export type SessionStatus =
38
- | { type: "idle" }
39
- | { type: "retry"; attempt: number; message: string; next: number }
40
- | { type: "busy" };
41
-
42
- // session.status() returns { data: map of sessionID -> SessionStatus }
43
- export interface SessionStatusResponse {
44
- data?: {
45
- [sessionID: string]: SessionStatus;
46
- };
47
- }
48
-
49
- export interface MessagePart {
50
- type: string;
51
- text?: string;
52
- }
53
-
54
- export interface MessageInfo {
55
- role?: "user" | "assistant";
56
- sessionID?: string;
57
- type?: string;
58
- name?: string;
59
- }
60
-
61
- export interface SessionMessage {
62
- info?: MessageInfo;
63
- parts?: MessagePart[];
64
- }
65
-
66
- export interface SessionMessagesResponse {
67
- data?: SessionMessage[];
68
- }