micode 0.7.5 → 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.5",
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",
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
- }