@accomplish_ai/agent-core 0.3.2 → 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.
Files changed (131) hide show
  1. package/dist/common/constants/model-display.d.ts.map +1 -1
  2. package/dist/common/constants/model-display.js +1 -0
  3. package/dist/common/constants/model-display.js.map +1 -1
  4. package/dist/common/index.d.ts +1 -1
  5. package/dist/common/index.d.ts.map +1 -1
  6. package/dist/common/index.js.map +1 -1
  7. package/dist/common/types/index.d.ts +1 -1
  8. package/dist/common/types/index.d.ts.map +1 -1
  9. package/dist/common/types/index.js.map +1 -1
  10. package/dist/common/types/provider.d.ts +18 -0
  11. package/dist/common/types/provider.d.ts.map +1 -1
  12. package/dist/common/types/provider.js +60 -179
  13. package/dist/common/types/provider.js.map +1 -1
  14. package/dist/common/types/providerSettings.d.ts +5 -0
  15. package/dist/common/types/providerSettings.d.ts.map +1 -1
  16. package/dist/common/types/providerSettings.js +9 -1
  17. package/dist/common/types/providerSettings.js.map +1 -1
  18. package/dist/common.d.ts +2 -1
  19. package/dist/common.d.ts.map +1 -1
  20. package/dist/common.js +2 -0
  21. package/dist/common.js.map +1 -1
  22. package/dist/factories/storage.d.ts.map +1 -1
  23. package/dist/factories/storage.js +3 -1
  24. package/dist/factories/storage.js.map +1 -1
  25. package/dist/index.d.ts +7 -4
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +4 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/internal/classes/OpenCodeAdapter.d.ts +2 -0
  30. package/dist/internal/classes/OpenCodeAdapter.d.ts.map +1 -1
  31. package/dist/internal/classes/OpenCodeAdapter.js +62 -17
  32. package/dist/internal/classes/OpenCodeAdapter.js.map +1 -1
  33. package/dist/opencode/completion/completion-enforcer.d.ts +6 -2
  34. package/dist/opencode/completion/completion-enforcer.d.ts.map +1 -1
  35. package/dist/opencode/completion/completion-enforcer.js +29 -10
  36. package/dist/opencode/completion/completion-enforcer.js.map +1 -1
  37. package/dist/opencode/completion/completion-state.js +1 -1
  38. package/dist/opencode/completion/index.d.ts +1 -1
  39. package/dist/opencode/completion/index.d.ts.map +1 -1
  40. package/dist/opencode/completion/index.js +1 -1
  41. package/dist/opencode/completion/index.js.map +1 -1
  42. package/dist/opencode/completion/prompts.d.ts +1 -2
  43. package/dist/opencode/completion/prompts.d.ts.map +1 -1
  44. package/dist/opencode/completion/prompts.js +10 -8
  45. package/dist/opencode/completion/prompts.js.map +1 -1
  46. package/dist/opencode/config-builder.d.ts.map +1 -1
  47. package/dist/opencode/config-builder.js +21 -6
  48. package/dist/opencode/config-builder.js.map +1 -1
  49. package/dist/opencode/config-generator.d.ts.map +1 -1
  50. package/dist/opencode/config-generator.js +14 -16
  51. package/dist/opencode/config-generator.js.map +1 -1
  52. package/dist/opencode/message-processor.d.ts +2 -0
  53. package/dist/opencode/message-processor.d.ts.map +1 -1
  54. package/dist/opencode/message-processor.js +57 -3
  55. package/dist/opencode/message-processor.js.map +1 -1
  56. package/dist/providers/fetch-models.d.ts +27 -0
  57. package/dist/providers/fetch-models.d.ts.map +1 -0
  58. package/dist/providers/fetch-models.js +128 -0
  59. package/dist/providers/fetch-models.js.map +1 -0
  60. package/dist/providers/index.d.ts +1 -0
  61. package/dist/providers/index.d.ts.map +1 -1
  62. package/dist/providers/index.js +1 -0
  63. package/dist/providers/index.js.map +1 -1
  64. package/dist/storage/index.d.ts +1 -1
  65. package/dist/storage/index.d.ts.map +1 -1
  66. package/dist/storage/index.js +1 -1
  67. package/dist/storage/index.js.map +1 -1
  68. package/dist/storage/migrations/index.d.ts +1 -1
  69. package/dist/storage/migrations/index.d.ts.map +1 -1
  70. package/dist/storage/migrations/index.js +3 -1
  71. package/dist/storage/migrations/index.js.map +1 -1
  72. package/dist/storage/migrations/v008-theme.d.ts +3 -0
  73. package/dist/storage/migrations/v008-theme.d.ts.map +1 -0
  74. package/dist/storage/migrations/v008-theme.js +7 -0
  75. package/dist/storage/migrations/v008-theme.js.map +1 -0
  76. package/dist/storage/repositories/appSettings.d.ts +4 -0
  77. package/dist/storage/repositories/appSettings.d.ts.map +1 -1
  78. package/dist/storage/repositories/appSettings.js +19 -1
  79. package/dist/storage/repositories/appSettings.js.map +1 -1
  80. package/dist/storage/repositories/index.d.ts +1 -1
  81. package/dist/storage/repositories/index.d.ts.map +1 -1
  82. package/dist/storage/repositories/index.js +1 -1
  83. package/dist/storage/repositories/index.js.map +1 -1
  84. package/dist/types/index.d.ts +1 -1
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/types/storage.d.ts +6 -0
  87. package/dist/types/storage.d.ts.map +1 -1
  88. package/dist/utils/error.d.ts +9 -0
  89. package/dist/utils/error.d.ts.map +1 -0
  90. package/dist/utils/error.js +14 -0
  91. package/dist/utils/error.js.map +1 -0
  92. package/dist/utils/index.d.ts +1 -0
  93. package/dist/utils/index.d.ts.map +1 -1
  94. package/dist/utils/index.js +1 -0
  95. package/dist/utils/index.js.map +1 -1
  96. package/dist/utils/sanitize.d.ts +1 -0
  97. package/dist/utils/sanitize.d.ts.map +1 -1
  98. package/dist/utils/sanitize.js +3 -3
  99. package/dist/utils/sanitize.js.map +1 -1
  100. package/mcp-tools/ask-user-question/dist/index.mjs +7 -14
  101. package/mcp-tools/complete-task/dist/index.mjs +7 -14
  102. package/mcp-tools/dev-browser/dist/start-relay.mjs +39 -39
  103. package/mcp-tools/dev-browser/dist/start-server.mjs +34 -138
  104. package/mcp-tools/dev-browser-mcp/dist/index.mjs +7 -14
  105. package/mcp-tools/file-permission/dist/index.mjs +7 -14
  106. package/mcp-tools/start-task/dist/index.mjs +26 -22
  107. package/package.json +1 -1
  108. package/dist/internal/classes/CompletionEnforcer.d.ts +0 -27
  109. package/dist/internal/classes/CompletionEnforcer.d.ts.map +0 -1
  110. package/dist/internal/classes/CompletionEnforcer.js +0 -109
  111. package/dist/internal/classes/CompletionEnforcer.js.map +0 -1
  112. package/dist/opencode/adapter.d.ts +0 -93
  113. package/dist/opencode/adapter.d.ts.map +0 -1
  114. package/dist/opencode/adapter.js +0 -650
  115. package/dist/opencode/adapter.js.map +0 -1
  116. package/dist/opencode/index.d.ts +0 -23
  117. package/dist/opencode/index.d.ts.map +0 -1
  118. package/dist/opencode/index.js +0 -13
  119. package/dist/opencode/index.js.map +0 -1
  120. package/dist/opencode/log-watcher.d.ts +0 -36
  121. package/dist/opencode/log-watcher.d.ts.map +0 -1
  122. package/dist/opencode/log-watcher.js +0 -257
  123. package/dist/opencode/log-watcher.js.map +0 -1
  124. package/dist/opencode/stream-parser.d.ts +0 -18
  125. package/dist/opencode/stream-parser.d.ts.map +0 -1
  126. package/dist/opencode/stream-parser.js +0 -117
  127. package/dist/opencode/stream-parser.js.map +0 -1
  128. package/dist/opencode/task-manager.d.ts +0 -71
  129. package/dist/opencode/task-manager.d.ts.map +0 -1
  130. package/dist/opencode/task-manager.js +0 -279
  131. package/dist/opencode/task-manager.js.map +0 -1
@@ -1,650 +0,0 @@
1
- import * as pty from 'node-pty';
2
- import { EventEmitter } from 'events';
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { StreamParser } from './stream-parser.js';
6
- import { OpenCodeLogWatcher, createLogWatcher } from './log-watcher.js';
7
- import { CompletionEnforcer } from './completion/index.js';
8
- export class OpenCodeCliNotFoundError extends Error {
9
- constructor() {
10
- super('OpenCode CLI is not available. The bundled CLI may be missing or corrupted. Please reinstall the application.');
11
- this.name = 'OpenCodeCliNotFoundError';
12
- }
13
- }
14
- export class OpenCodeAdapter extends EventEmitter {
15
- ptyProcess = null;
16
- streamParser;
17
- logWatcher = null;
18
- currentSessionId = null;
19
- currentTaskId = null;
20
- messages = [];
21
- hasCompleted = false;
22
- isDisposed = false;
23
- wasInterrupted = false;
24
- completionEnforcer;
25
- lastWorkingDirectory;
26
- currentModelId = null;
27
- waitingTransitionTimer = null;
28
- hasReceivedFirstTool = false;
29
- startTaskCalled = false;
30
- options;
31
- constructor(options, taskId) {
32
- super();
33
- this.options = options;
34
- this.currentTaskId = taskId || null;
35
- this.streamParser = new StreamParser();
36
- this.completionEnforcer = this.createCompletionEnforcer();
37
- this.setupStreamParsing();
38
- this.setupLogWatcher();
39
- }
40
- createCompletionEnforcer() {
41
- const callbacks = {
42
- onStartContinuation: async (prompt) => {
43
- await this.spawnSessionResumption(prompt);
44
- },
45
- onComplete: () => {
46
- this.hasCompleted = true;
47
- this.emit('complete', {
48
- status: 'success',
49
- sessionId: this.currentSessionId || undefined,
50
- });
51
- },
52
- onDebug: (type, message, data) => {
53
- this.emit('debug', { type, message, data });
54
- },
55
- };
56
- return new CompletionEnforcer(callbacks);
57
- }
58
- setupLogWatcher() {
59
- this.logWatcher = createLogWatcher();
60
- this.logWatcher.on('error', (error) => {
61
- if (!this.hasCompleted && this.ptyProcess) {
62
- console.log('[OpenCode Adapter] Log watcher detected error:', error.errorName);
63
- const errorMessage = OpenCodeLogWatcher.getErrorMessage(error);
64
- this.emit('debug', {
65
- type: 'error',
66
- message: `[${error.errorName}] ${errorMessage}`,
67
- data: {
68
- errorName: error.errorName,
69
- statusCode: error.statusCode,
70
- providerID: error.providerID,
71
- modelID: error.modelID,
72
- message: error.message,
73
- },
74
- });
75
- if (error.isAuthError && error.providerID) {
76
- console.log('[OpenCode Adapter] Emitting auth-error for provider:', error.providerID);
77
- this.emit('auth-error', {
78
- providerId: error.providerID,
79
- message: errorMessage,
80
- });
81
- }
82
- this.hasCompleted = true;
83
- this.emit('complete', {
84
- status: 'error',
85
- sessionId: this.currentSessionId || undefined,
86
- error: errorMessage,
87
- });
88
- if (this.ptyProcess) {
89
- try {
90
- this.ptyProcess.kill();
91
- }
92
- catch (err) {
93
- console.warn('[OpenCode Adapter] Error killing PTY after log error:', err);
94
- }
95
- this.ptyProcess = null;
96
- }
97
- }
98
- });
99
- }
100
- async startTask(config) {
101
- if (this.isDisposed) {
102
- throw new Error('Adapter has been disposed and cannot start new tasks');
103
- }
104
- const taskId = config.taskId || this.generateTaskId();
105
- this.currentTaskId = taskId;
106
- this.currentSessionId = null;
107
- this.currentModelId = config.modelId || null;
108
- this.messages = [];
109
- this.streamParser.reset();
110
- this.hasCompleted = false;
111
- this.wasInterrupted = false;
112
- this.completionEnforcer.reset();
113
- this.lastWorkingDirectory = config.workingDirectory;
114
- this.hasReceivedFirstTool = false;
115
- this.startTaskCalled = false;
116
- if (this.waitingTransitionTimer) {
117
- clearTimeout(this.waitingTransitionTimer);
118
- this.waitingTransitionTimer = null;
119
- }
120
- if (this.logWatcher) {
121
- await this.logWatcher.start();
122
- }
123
- if (this.options.onBeforeStart) {
124
- await this.options.onBeforeStart();
125
- }
126
- const cliArgs = await this.options.buildCliArgs(config);
127
- const { command, args: baseArgs } = this.options.getCliCommand();
128
- const startMsg = `Starting: ${command} ${[...baseArgs, ...cliArgs].join(' ')}`;
129
- console.log('[OpenCode CLI]', startMsg);
130
- this.emit('debug', { type: 'info', message: startMsg });
131
- const env = await this.options.buildEnvironment(taskId);
132
- const allArgs = [...baseArgs, ...cliArgs];
133
- const cmdMsg = `Command: ${command}`;
134
- const argsMsg = `Args: ${allArgs.join(' ')}`;
135
- const safeCwd = config.workingDirectory || this.options.tempPath;
136
- const cwdMsg = `Working directory: ${safeCwd}`;
137
- if (this.options.isPackaged && this.options.platform === 'win32') {
138
- const dummyPackageJson = path.join(safeCwd, 'package.json');
139
- if (!fs.existsSync(dummyPackageJson)) {
140
- try {
141
- fs.writeFileSync(dummyPackageJson, JSON.stringify({ name: 'opencode-workspace', private: true }, null, 2));
142
- console.log('[OpenCode CLI] Created workspace package.json at:', dummyPackageJson);
143
- }
144
- catch (err) {
145
- console.warn('[OpenCode CLI] Could not create workspace package.json:', err);
146
- }
147
- }
148
- }
149
- console.log('[OpenCode CLI]', cmdMsg);
150
- console.log('[OpenCode CLI]', argsMsg);
151
- console.log('[OpenCode CLI]', cwdMsg);
152
- this.emit('debug', { type: 'info', message: cmdMsg });
153
- this.emit('debug', { type: 'info', message: argsMsg, data: { args: allArgs } });
154
- this.emit('debug', { type: 'info', message: cwdMsg });
155
- {
156
- const fullCommand = this.buildShellCommand(command, allArgs);
157
- const shellCmdMsg = `Full shell command: ${fullCommand}`;
158
- console.log('[OpenCode CLI]', shellCmdMsg);
159
- this.emit('debug', { type: 'info', message: shellCmdMsg });
160
- const shellCmd = this.getPlatformShell();
161
- const shellArgs = this.getShellArgs(fullCommand);
162
- const shellMsg = `Using shell: ${shellCmd} ${shellArgs.join(' ')}`;
163
- console.log('[OpenCode CLI]', shellMsg);
164
- this.emit('debug', { type: 'info', message: shellMsg });
165
- this.ptyProcess = pty.spawn(shellCmd, shellArgs, {
166
- name: 'xterm-256color',
167
- cols: 32000,
168
- rows: 30,
169
- cwd: safeCwd,
170
- env: env,
171
- });
172
- const pidMsg = `PTY Process PID: ${this.ptyProcess.pid}`;
173
- console.log('[OpenCode CLI]', pidMsg);
174
- this.emit('debug', { type: 'info', message: pidMsg });
175
- this.emit('progress', { stage: 'loading', message: 'Loading agent...' });
176
- this.ptyProcess.onData((data) => {
177
- const cleanData = data
178
- .replace(/\x1B\[[0-9;?]*[a-zA-Z]/g, '')
179
- .replace(/\x1B\][^\x07]*\x07/g, '')
180
- .replace(/\x1B\][^\x1B]*\x1B\\/g, '');
181
- if (cleanData.trim()) {
182
- const truncated = cleanData.substring(0, 500) + (cleanData.length > 500 ? '...' : '');
183
- console.log('[OpenCode CLI stdout]:', truncated);
184
- this.emit('debug', { type: 'stdout', message: cleanData });
185
- this.streamParser.feed(cleanData);
186
- }
187
- });
188
- this.ptyProcess.onExit(({ exitCode, signal }) => {
189
- const exitMsg = `PTY Process exited with code: ${exitCode}, signal: ${signal}`;
190
- console.log('[OpenCode CLI]', exitMsg);
191
- this.emit('debug', { type: 'exit', message: exitMsg, data: { exitCode, signal } });
192
- this.handleProcessExit(exitCode);
193
- });
194
- }
195
- return {
196
- id: taskId,
197
- prompt: config.prompt,
198
- status: 'running',
199
- messages: [],
200
- createdAt: new Date().toISOString(),
201
- startedAt: new Date().toISOString(),
202
- };
203
- }
204
- async resumeSession(sessionId, prompt) {
205
- return this.startTask({
206
- prompt,
207
- sessionId,
208
- });
209
- }
210
- async sendResponse(response) {
211
- if (!this.ptyProcess) {
212
- throw new Error('No active process');
213
- }
214
- this.ptyProcess.write(response + '\n');
215
- console.log('[OpenCode CLI] Response sent via PTY');
216
- }
217
- async cancelTask() {
218
- if (this.ptyProcess) {
219
- this.ptyProcess.kill();
220
- this.ptyProcess = null;
221
- }
222
- }
223
- async interruptTask() {
224
- if (!this.ptyProcess) {
225
- console.log('[OpenCode CLI] No active process to interrupt');
226
- return;
227
- }
228
- this.wasInterrupted = true;
229
- this.ptyProcess.write('\x03');
230
- console.log('[OpenCode CLI] Sent Ctrl+C interrupt signal');
231
- if (this.options.platform === 'win32') {
232
- setTimeout(() => {
233
- if (this.ptyProcess) {
234
- this.ptyProcess.write('Y\n');
235
- console.log('[OpenCode CLI] Sent Y to confirm batch termination');
236
- }
237
- }, 100);
238
- }
239
- }
240
- getSessionId() {
241
- return this.currentSessionId;
242
- }
243
- getTaskId() {
244
- return this.currentTaskId;
245
- }
246
- get running() {
247
- return this.ptyProcess !== null && !this.hasCompleted;
248
- }
249
- isAdapterDisposed() {
250
- return this.isDisposed;
251
- }
252
- dispose() {
253
- if (this.isDisposed) {
254
- return;
255
- }
256
- console.log(`[OpenCode Adapter] Disposing adapter for task ${this.currentTaskId}`);
257
- this.isDisposed = true;
258
- if (this.logWatcher) {
259
- this.logWatcher.stop().catch((err) => {
260
- console.warn('[OpenCode Adapter] Error stopping log watcher:', err);
261
- });
262
- }
263
- if (this.ptyProcess) {
264
- try {
265
- this.ptyProcess.kill();
266
- }
267
- catch (error) {
268
- console.error('[OpenCode Adapter] Error killing PTY process:', error);
269
- }
270
- this.ptyProcess = null;
271
- }
272
- this.currentSessionId = null;
273
- this.currentTaskId = null;
274
- this.messages = [];
275
- this.hasCompleted = true;
276
- this.currentModelId = null;
277
- this.hasReceivedFirstTool = false;
278
- this.startTaskCalled = false;
279
- if (this.waitingTransitionTimer) {
280
- clearTimeout(this.waitingTransitionTimer);
281
- this.waitingTransitionTimer = null;
282
- }
283
- this.streamParser.reset();
284
- this.removeAllListeners();
285
- console.log('[OpenCode Adapter] Adapter disposed');
286
- }
287
- escapeShellArg(arg) {
288
- if (this.options.platform === 'win32') {
289
- if (arg.includes(' ') || arg.includes('"')) {
290
- return `"${arg.replace(/"/g, '""')}"`;
291
- }
292
- return arg;
293
- }
294
- else {
295
- const needsEscaping = ["'", ' ', '$', '`', '\\', '"', '\n'].some(c => arg.includes(c));
296
- if (needsEscaping) {
297
- return `'${arg.replace(/'/g, "'\\''")}'`;
298
- }
299
- return arg;
300
- }
301
- }
302
- buildShellCommand(command, args) {
303
- const escapedCommand = this.escapeShellArg(command);
304
- const escapedArgs = args.map(arg => this.escapeShellArg(arg));
305
- return [escapedCommand, ...escapedArgs].join(' ');
306
- }
307
- setupStreamParsing() {
308
- this.streamParser.on('message', (message) => {
309
- this.handleMessage(message);
310
- });
311
- this.streamParser.on('error', (error) => {
312
- console.warn('[OpenCode Adapter] Stream parse warning:', error.message);
313
- this.emit('debug', { type: 'parse-warning', message: error.message });
314
- });
315
- }
316
- handleMessage(message) {
317
- console.log('[OpenCode Adapter] Handling message type:', message.type);
318
- switch (message.type) {
319
- case 'step_start':
320
- this.currentSessionId = message.part.sessionID;
321
- const modelDisplayName = this.currentModelId && this.options.getModelDisplayName
322
- ? this.options.getModelDisplayName(this.currentModelId)
323
- : 'AI';
324
- this.emit('progress', {
325
- stage: 'connecting',
326
- message: `Connecting to ${modelDisplayName}...`,
327
- modelName: modelDisplayName,
328
- });
329
- if (this.waitingTransitionTimer) {
330
- clearTimeout(this.waitingTransitionTimer);
331
- }
332
- this.waitingTransitionTimer = setTimeout(() => {
333
- if (!this.hasReceivedFirstTool && !this.hasCompleted) {
334
- this.emit('progress', { stage: 'waiting', message: 'Waiting for response...' });
335
- }
336
- }, 500);
337
- break;
338
- case 'text':
339
- if (!this.currentSessionId && message.part.sessionID) {
340
- this.currentSessionId = message.part.sessionID;
341
- }
342
- this.emit('message', message);
343
- if (message.part.text) {
344
- const taskMessage = {
345
- id: this.generateMessageId(),
346
- type: 'assistant',
347
- content: message.part.text,
348
- timestamp: new Date().toISOString(),
349
- };
350
- this.messages.push(taskMessage);
351
- }
352
- break;
353
- case 'tool_call':
354
- this.handleToolCall(message.part.tool || 'unknown', message.part.input, message.part.sessionID);
355
- break;
356
- case 'tool_use':
357
- const toolUseMessage = message;
358
- const toolUseName = toolUseMessage.part.tool || 'unknown';
359
- const toolUseInput = toolUseMessage.part.state?.input;
360
- const toolUseOutput = toolUseMessage.part.state?.output || '';
361
- this.handleToolCall(toolUseName, toolUseInput, toolUseMessage.part.sessionID);
362
- const toolDescription = toolUseInput?.description;
363
- if (toolDescription) {
364
- const syntheticTextMessage = {
365
- type: 'text',
366
- timestamp: message.timestamp,
367
- sessionID: message.sessionID,
368
- part: {
369
- id: this.generateMessageId(),
370
- sessionID: toolUseMessage.part.sessionID,
371
- messageID: toolUseMessage.part.messageID,
372
- type: 'text',
373
- text: toolDescription,
374
- },
375
- };
376
- this.emit('message', syntheticTextMessage);
377
- }
378
- this.emit('message', message);
379
- const toolUseStatus = toolUseMessage.part.state?.status;
380
- console.log('[OpenCode Adapter] Tool use:', toolUseName, 'status:', toolUseStatus);
381
- if (toolUseStatus === 'completed' || toolUseStatus === 'error') {
382
- this.emit('tool-result', toolUseOutput);
383
- }
384
- if (toolUseName === 'AskUserQuestion') {
385
- this.handleAskUserQuestion(toolUseInput);
386
- }
387
- break;
388
- case 'tool_result':
389
- const toolOutput = message.part.output || '';
390
- console.log('[OpenCode Adapter] Tool result received, length:', toolOutput.length);
391
- this.emit('tool-result', toolOutput);
392
- break;
393
- case 'step_finish':
394
- if (message.part.reason === 'error') {
395
- if (!this.hasCompleted) {
396
- this.hasCompleted = true;
397
- this.emit('complete', {
398
- status: 'error',
399
- sessionId: this.currentSessionId || undefined,
400
- error: 'Task failed',
401
- });
402
- }
403
- break;
404
- }
405
- const action = this.completionEnforcer.handleStepFinish(message.part.reason);
406
- console.log(`[OpenCode Adapter] step_finish action: ${action}`);
407
- if (action === 'complete' && !this.hasCompleted) {
408
- this.hasCompleted = true;
409
- this.emit('complete', {
410
- status: 'success',
411
- sessionId: this.currentSessionId || undefined,
412
- });
413
- }
414
- break;
415
- case 'error':
416
- this.hasCompleted = true;
417
- this.emit('complete', {
418
- status: 'error',
419
- sessionId: this.currentSessionId || undefined,
420
- error: message.error,
421
- });
422
- break;
423
- default:
424
- const unknownMessage = message;
425
- console.log('[OpenCode Adapter] Unknown message type:', unknownMessage.type);
426
- }
427
- }
428
- handleToolCall(toolName, toolInput, sessionID) {
429
- console.log('[OpenCode Adapter] Tool call:', toolName);
430
- if (this.isStartTaskTool(toolName)) {
431
- this.startTaskCalled = true;
432
- const startInput = toolInput;
433
- if (startInput?.goal && startInput?.steps) {
434
- this.emitPlanMessage(startInput, sessionID || this.currentSessionId || '');
435
- const todos = startInput.steps.map((step, i) => ({
436
- id: String(i + 1),
437
- content: step,
438
- status: i === 0 ? 'in_progress' : 'pending',
439
- priority: 'medium',
440
- }));
441
- if (todos.length > 0) {
442
- this.emit('todo:update', todos);
443
- this.completionEnforcer.updateTodos(todos);
444
- console.log('[OpenCode Adapter] Created todos from start_task steps');
445
- }
446
- }
447
- }
448
- if (!this.startTaskCalled && !this.isExemptTool(toolName)) {
449
- console.warn(`[OpenCode Adapter] Tool "${toolName}" called before start_task`);
450
- this.emit('debug', {
451
- type: 'warning',
452
- message: `Tool "${toolName}" called before start_task - plan may not be captured`,
453
- });
454
- }
455
- if (!this.hasReceivedFirstTool) {
456
- this.hasReceivedFirstTool = true;
457
- if (this.waitingTransitionTimer) {
458
- clearTimeout(this.waitingTransitionTimer);
459
- this.waitingTransitionTimer = null;
460
- }
461
- }
462
- this.completionEnforcer.markToolsUsed();
463
- if (toolName === 'complete_task' || toolName.endsWith('_complete_task')) {
464
- this.completionEnforcer.handleCompleteTaskDetection(toolInput);
465
- }
466
- if (toolName === 'todowrite' || toolName.endsWith('_todowrite')) {
467
- const input = toolInput;
468
- if (input?.todos && Array.isArray(input.todos) && input.todos.length > 0) {
469
- this.emit('todo:update', input.todos);
470
- this.completionEnforcer.updateTodos(input.todos);
471
- }
472
- }
473
- this.emit('tool-use', toolName, toolInput);
474
- this.emit('progress', {
475
- stage: 'tool-use',
476
- message: `Using ${toolName}`,
477
- });
478
- if (toolName === 'AskUserQuestion') {
479
- this.handleAskUserQuestion(toolInput);
480
- }
481
- }
482
- handleAskUserQuestion(input) {
483
- const question = input.questions?.[0];
484
- if (!question)
485
- return;
486
- const permissionRequest = {
487
- id: this.generateRequestId(),
488
- taskId: this.currentTaskId || '',
489
- type: 'question',
490
- question: question.question,
491
- options: question.options?.map((o) => ({
492
- label: o.label,
493
- description: o.description,
494
- })),
495
- multiSelect: question.multiSelect,
496
- createdAt: new Date().toISOString(),
497
- };
498
- this.emit('permission-request', permissionRequest);
499
- }
500
- handleProcessExit(code) {
501
- this.ptyProcess = null;
502
- if (this.wasInterrupted && code === 0 && !this.hasCompleted) {
503
- console.log('[OpenCode CLI] Task was interrupted by user');
504
- this.hasCompleted = true;
505
- this.emit('complete', {
506
- status: 'interrupted',
507
- sessionId: this.currentSessionId || undefined,
508
- });
509
- this.currentTaskId = null;
510
- return;
511
- }
512
- if (code === 0 && !this.hasCompleted) {
513
- this.completionEnforcer.handleProcessExit(code).catch((error) => {
514
- console.error('[OpenCode Adapter] Completion enforcer error:', error);
515
- this.hasCompleted = true;
516
- this.emit('complete', {
517
- status: 'error',
518
- sessionId: this.currentSessionId || undefined,
519
- error: `Failed to complete: ${error.message}`,
520
- });
521
- });
522
- return;
523
- }
524
- if (!this.hasCompleted) {
525
- if (code !== null && code !== 0) {
526
- this.emit('error', new Error(`OpenCode CLI exited with code ${code}`));
527
- }
528
- }
529
- this.currentTaskId = null;
530
- }
531
- async spawnSessionResumption(prompt) {
532
- const sessionId = this.currentSessionId;
533
- if (!sessionId) {
534
- throw new Error('No session ID available for session resumption');
535
- }
536
- console.log(`[OpenCode Adapter] Starting session resumption with session ${sessionId}`);
537
- this.streamParser.reset();
538
- const config = {
539
- prompt,
540
- sessionId: sessionId,
541
- workingDirectory: this.lastWorkingDirectory,
542
- };
543
- const cliArgs = await this.options.buildCliArgs(config);
544
- const { command, args: baseArgs } = this.options.getCliCommand();
545
- console.log('[OpenCode Adapter] Session resumption command:', command, [...baseArgs, ...cliArgs].join(' '));
546
- const env = await this.options.buildEnvironment(this.currentTaskId || 'default');
547
- const allArgs = [...baseArgs, ...cliArgs];
548
- const safeCwd = config.workingDirectory || this.options.tempPath;
549
- const fullCommand = this.buildShellCommand(command, allArgs);
550
- const shellCmd = this.getPlatformShell();
551
- const shellArgs = this.getShellArgs(fullCommand);
552
- this.ptyProcess = pty.spawn(shellCmd, shellArgs, {
553
- name: 'xterm-256color',
554
- cols: 32000,
555
- rows: 30,
556
- cwd: safeCwd,
557
- env: env,
558
- });
559
- this.ptyProcess.onData((data) => {
560
- const cleanData = data
561
- .replace(/\x1B\[[0-9;?]*[a-zA-Z]/g, '')
562
- .replace(/\x1B\][^\x07]*\x07/g, '')
563
- .replace(/\x1B\][^\x1B]*\x1B\\/g, '');
564
- if (cleanData.trim()) {
565
- const truncated = cleanData.substring(0, 500) + (cleanData.length > 500 ? '...' : '');
566
- console.log('[OpenCode CLI stdout]:', truncated);
567
- this.emit('debug', { type: 'stdout', message: cleanData });
568
- this.streamParser.feed(cleanData);
569
- }
570
- });
571
- this.ptyProcess.onExit(({ exitCode }) => {
572
- this.handleProcessExit(exitCode);
573
- });
574
- }
575
- generateTaskId() {
576
- return `task_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
577
- }
578
- generateMessageId() {
579
- return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
580
- }
581
- generateRequestId() {
582
- return `req_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
583
- }
584
- isStartTaskTool(toolName) {
585
- return toolName === 'start_task' || toolName.endsWith('_start_task');
586
- }
587
- isExemptTool(toolName) {
588
- if (toolName === 'todowrite' || toolName.endsWith('_todowrite')) {
589
- return true;
590
- }
591
- if (this.isStartTaskTool(toolName)) {
592
- return true;
593
- }
594
- return false;
595
- }
596
- emitPlanMessage(input, sessionId) {
597
- const verificationSection = input.verification?.length
598
- ? `\n\n**Verification:**\n${input.verification.map((v, i) => `${i + 1}. ${v}`).join('\n')}`
599
- : '';
600
- const skillsSection = input.skills?.length
601
- ? `\n\n**Skills:** ${input.skills.join(', ')}`
602
- : '';
603
- const planText = `**Plan:**\n\n**Goal:** ${input.goal}\n\n**Steps:**\n${input.steps.map((s, i) => `${i + 1}. ${s}`).join('\n')}${verificationSection}${skillsSection}`;
604
- const syntheticMessage = {
605
- type: 'text',
606
- timestamp: Date.now(),
607
- sessionID: sessionId,
608
- part: {
609
- id: this.generateMessageId(),
610
- sessionID: sessionId,
611
- messageID: this.generateMessageId(),
612
- type: 'text',
613
- text: planText,
614
- },
615
- };
616
- this.emit('message', syntheticMessage);
617
- console.log('[OpenCode Adapter] Emitted synthetic plan message');
618
- }
619
- getPlatformShell() {
620
- if (this.options.platform === 'win32') {
621
- return 'cmd.exe';
622
- }
623
- else if (this.options.isPackaged && this.options.platform === 'darwin') {
624
- return '/bin/sh';
625
- }
626
- else {
627
- const userShell = process.env.SHELL;
628
- if (userShell) {
629
- return userShell;
630
- }
631
- if (fs.existsSync('/bin/bash'))
632
- return '/bin/bash';
633
- if (fs.existsSync('/bin/zsh'))
634
- return '/bin/zsh';
635
- return '/bin/sh';
636
- }
637
- }
638
- getShellArgs(command) {
639
- if (this.options.platform === 'win32') {
640
- return ['/s', '/c', command];
641
- }
642
- else {
643
- return ['-c', command];
644
- }
645
- }
646
- }
647
- export function createAdapter(options, taskId) {
648
- return new OpenCodeAdapter(options, taskId);
649
- }
650
- //# sourceMappingURL=adapter.js.map