@vicoa/opencode 0.1.0 → 0.1.2

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.
@@ -1,335 +0,0 @@
1
- const LANGUAGE_MAP = {
2
- py: 'python',
3
- js: 'javascript',
4
- ts: 'typescript',
5
- jsx: 'jsx',
6
- tsx: 'tsx',
7
- java: 'java',
8
- cpp: 'cpp',
9
- c: 'c',
10
- cs: 'csharp',
11
- rb: 'ruby',
12
- go: 'go',
13
- rs: 'rust',
14
- php: 'php',
15
- swift: 'swift',
16
- kt: 'kotlin',
17
- yaml: 'yaml',
18
- yml: 'yaml',
19
- json: 'json',
20
- xml: 'xml',
21
- html: 'html',
22
- css: 'css',
23
- scss: 'scss',
24
- sql: 'sql',
25
- sh: 'bash',
26
- bash: 'bash',
27
- md: 'markdown',
28
- txt: 'text',
29
- };
30
- function truncateText(text, maxLength = 100) {
31
- if (text.length <= maxLength) {
32
- return text;
33
- }
34
- return `${text.slice(0, maxLength)}...`;
35
- }
36
- function detectLanguage(filePath) {
37
- const extension = filePath.includes('.') ? filePath.split('.').pop() ?? '' : '';
38
- return LANGUAGE_MAP[extension] ?? '';
39
- }
40
- function getString(input, keys, fallback = '') {
41
- for (const key of keys) {
42
- const value = input[key];
43
- if (typeof value === 'string') {
44
- return value;
45
- }
46
- }
47
- return fallback;
48
- }
49
- function getBoolean(input, keys, fallback = false) {
50
- for (const key of keys) {
51
- const value = input[key];
52
- if (typeof value === 'boolean') {
53
- return value;
54
- }
55
- }
56
- return fallback;
57
- }
58
- function getArray(input, keys) {
59
- for (const key of keys) {
60
- const value = input[key];
61
- if (Array.isArray(value)) {
62
- return value;
63
- }
64
- }
65
- return [];
66
- }
67
- function formatDiffBlock(oldText, newText) {
68
- const diffLines = ['```diff'];
69
- if (!oldText && newText) {
70
- for (const line of newText.split('\n')) {
71
- diffLines.push(`+ ${line}`);
72
- }
73
- }
74
- else if (oldText && !newText) {
75
- for (const line of oldText.split('\n')) {
76
- diffLines.push(`- ${line}`);
77
- }
78
- }
79
- else {
80
- const oldLines = oldText.split('\n');
81
- const newLines = newText.split('\n');
82
- const commonPrefix = [];
83
- const commonSuffix = [];
84
- for (let i = 0; i < Math.min(oldLines.length, newLines.length); i += 1) {
85
- if (oldLines[i] === newLines[i]) {
86
- commonPrefix.push(oldLines[i]);
87
- }
88
- else {
89
- break;
90
- }
91
- }
92
- const oldRemaining = oldLines.slice(commonPrefix.length);
93
- const newRemaining = newLines.slice(commonPrefix.length);
94
- if (oldRemaining.length && newRemaining.length) {
95
- for (let i = 1; i <= Math.min(oldRemaining.length, newRemaining.length); i += 1) {
96
- if (oldRemaining[oldRemaining.length - i] === newRemaining[newRemaining.length - i]) {
97
- commonSuffix.unshift(oldRemaining[oldRemaining.length - i]);
98
- }
99
- else {
100
- break;
101
- }
102
- }
103
- }
104
- const changedOld = commonSuffix.length
105
- ? oldRemaining.slice(0, oldRemaining.length - commonSuffix.length)
106
- : oldRemaining;
107
- const changedNew = commonSuffix.length
108
- ? newRemaining.slice(0, newRemaining.length - commonSuffix.length)
109
- : newRemaining;
110
- if ((commonPrefix.length || commonSuffix.length) && (changedOld.length || changedNew.length)) {
111
- const contextBefore = commonPrefix.slice(-2);
112
- const contextAfter = commonSuffix.slice(0, 2);
113
- for (const line of contextBefore) {
114
- diffLines.push(` ${line}`);
115
- }
116
- for (const line of changedOld) {
117
- diffLines.push(`- ${line}`);
118
- }
119
- for (const line of changedNew) {
120
- diffLines.push(`+ ${line}`);
121
- }
122
- for (const line of contextAfter) {
123
- diffLines.push(` ${line}`);
124
- }
125
- }
126
- else {
127
- for (const line of oldLines) {
128
- diffLines.push(`- ${line}`);
129
- }
130
- for (const line of newLines) {
131
- diffLines.push(`+ ${line}`);
132
- }
133
- }
134
- }
135
- diffLines.push('```');
136
- return diffLines;
137
- }
138
- export function formatToolUsage(toolName, inputData) {
139
- if (toolName.startsWith('mcp__vicoa__')) {
140
- return `Using tool: ${toolName}`;
141
- }
142
- const normalizedTool = toolName.toLowerCase();
143
- if (normalizedTool === 'write') {
144
- const filePath = getString(inputData, ['file_path', 'filePath', 'path', 'filename'], 'unknown');
145
- const content = getString(inputData, ['content', 'text', 'value']);
146
- const lang = detectLanguage(filePath);
147
- return [`Using tool: Write - \`${filePath}\``, `\`\`\`${lang}`, content, '```']
148
- .filter((line) => line.length > 0)
149
- .join('\n');
150
- }
151
- if (normalizedTool === 'read' || normalizedTool === 'notebookread' || normalizedTool === 'notebookedit') {
152
- const filePath = getString(inputData, ['file_path', 'filePath', 'path', 'notebook_path'], 'unknown');
153
- return `Using tool: ${toolName} - \`${filePath}\``;
154
- }
155
- if (normalizedTool === 'edit') {
156
- const filePath = getString(inputData, ['file_path', 'filePath', 'path'], 'unknown');
157
- const oldString = getString(inputData, ['old_string', 'oldString']);
158
- const newString = getString(inputData, ['new_string', 'newString']);
159
- const replaceAll = getBoolean(inputData, ['replace_all', 'replaceAll']);
160
- const diffLines = [`Using tool: **Edit** - \`${filePath}\``];
161
- if (replaceAll) {
162
- diffLines.push('*Replacing all occurrences*');
163
- }
164
- diffLines.push('');
165
- diffLines.push(...formatDiffBlock(oldString, newString));
166
- return diffLines.join('\n');
167
- }
168
- if (normalizedTool === 'multiedit') {
169
- const filePath = getString(inputData, ['file_path', 'filePath', 'path'], 'unknown');
170
- const edits = getArray(inputData, ['edits']);
171
- const lines = [
172
- `Using tool: **MultiEdit** - \`${filePath}\``,
173
- `*Making ${edits.length} edit${edits.length === 1 ? '' : 's'}:*`,
174
- '',
175
- ];
176
- edits.forEach((edit, index) => {
177
- const editIndex = index + 1;
178
- const oldString = typeof edit.old_string === 'string' ? edit.old_string : edit.oldString ?? '';
179
- const newString = typeof edit.new_string === 'string' ? edit.new_string : edit.newString ?? '';
180
- const replaceAll = Boolean(edit.replace_all ?? edit.replaceAll ?? false);
181
- lines.push(replaceAll ? `### Edit ${editIndex} *(replacing all occurrences)*` : `### Edit ${editIndex}`);
182
- lines.push('');
183
- lines.push(...formatDiffBlock(oldString, newString));
184
- lines.push('');
185
- });
186
- return lines.join('\n');
187
- }
188
- if (normalizedTool === 'bash') {
189
- const command = getString(inputData, ['command', 'cmd']);
190
- return `Using tool: Bash - \`${command}\``;
191
- }
192
- if (normalizedTool === 'grep' || normalizedTool === 'glob') {
193
- const pattern = getString(inputData, ['pattern', 'query'], 'unknown');
194
- const path = getString(inputData, ['path', 'directory'], 'current directory');
195
- return `Using tool: ${toolName} - \`${truncateText(pattern, 50)}\` in ${path}`;
196
- }
197
- if (normalizedTool === 'list' || normalizedTool === 'ls') {
198
- const path = getString(inputData, ['path'], 'unknown');
199
- return `Using tool: list - \`${path}\``;
200
- }
201
- if (normalizedTool === 'patch') {
202
- const file = getString(inputData, ['file', 'path'], 'unknown');
203
- return `Using tool: patch - \`${file}\``;
204
- }
205
- if (normalizedTool === 'skill') {
206
- const name = getString(inputData, ['name', 'skill'], 'unknown');
207
- return `Using tool: skill - \`${name}\``;
208
- }
209
- if (normalizedTool === 'question') {
210
- const text = getString(inputData, ['text', 'question', 'message'], '');
211
- return text ? `Asking: ${truncateText(text, 100)}` : 'Using tool: question';
212
- }
213
- if (normalizedTool === 'lsp') {
214
- const command = getString(inputData, ['command', 'method'], 'unknown');
215
- const file = getString(inputData, ['file', 'path'], '');
216
- return file ? `Using tool: lsp - ${command} on \`${file}\`` : `Using tool: lsp - ${command}`;
217
- }
218
- if (normalizedTool === 'todowrite') {
219
- const todos = getArray(inputData, ['todos']);
220
- if (!todos.length) {
221
- return 'Using tool: TodoWrite - clearing todo list';
222
- }
223
- const statusSymbol = {
224
- pending: '○',
225
- in_progress: '◐',
226
- completed: '●',
227
- };
228
- const lines = ['Using tool: TodoWrite - Todo List', ''];
229
- for (const todo of todos) {
230
- const status = typeof todo.status === 'string' ? todo.status : 'pending';
231
- const content = typeof todo.content === 'string' ? todo.content : '';
232
- const symbol = statusSymbol[status] ?? '•';
233
- lines.push(`${symbol} ${truncateText(content, 100)}`);
234
- }
235
- return lines.join('\n');
236
- }
237
- if (normalizedTool === 'todoread') {
238
- return 'Using tool: todoread';
239
- }
240
- if (normalizedTool === 'task') {
241
- const description = getString(inputData, ['description'], 'unknown task');
242
- const subagentType = getString(inputData, ['subagent_type', 'subagentType', 'agent'], 'unknown');
243
- return `Using tool: Task - ${truncateText(description, 50)} (agent: ${subagentType})`;
244
- }
245
- if (normalizedTool === 'webfetch') {
246
- const url = getString(inputData, ['url'], 'unknown');
247
- return `Using tool: WebFetch - \`${truncateText(url, 80)}\``;
248
- }
249
- if (normalizedTool === 'websearch') {
250
- const query = getString(inputData, ['query'], 'unknown');
251
- return `Using tool: WebSearch - ${truncateText(query, 80)}`;
252
- }
253
- if (toolName === 'ListMcpResourcesTool') {
254
- return 'Using tool: List MCP Resources';
255
- }
256
- const defaultKeys = ['file', 'path', 'query', 'content', 'message', 'description', 'name'];
257
- for (const key of defaultKeys) {
258
- if (typeof inputData[key] === 'string') {
259
- return `Using tool: ${toolName} - ${truncateText(String(inputData[key]), 50)}`;
260
- }
261
- }
262
- return `Using tool: ${toolName}`;
263
- }
264
- // Most tool outputs don't need truncation - show them in full.
265
- // Only truncate for tools that tend to produce very large/noisy output.
266
- const TRUNCATE_OUTPUT_TOOLS = new Set(['']); // set to empty for not to filter message now.
267
- const TRUNCATE_LIMIT = 500;
268
- export function formatToolResult(output, toolName) {
269
- try {
270
- const parsed = JSON.parse(output);
271
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
272
- const keys = Object.keys(parsed).slice(0, 3);
273
- const summary = `JSON object with keys: ${keys.join(', ')}`;
274
- return keys.length < Object.keys(parsed).length ? `${summary} and ${Object.keys(parsed).length - keys.length} more` : summary;
275
- }
276
- }
277
- catch {
278
- // not JSON
279
- }
280
- // Default: don't truncate tool output unless it's in the truncate list
281
- if (toolName && TRUNCATE_OUTPUT_TOOLS.has(toolName.toLowerCase())) {
282
- return truncateText(output, TRUNCATE_LIMIT);
283
- }
284
- return output;
285
- }
286
- // Tools whose Result line is noise: either raw file/list content (read-side)
287
- // or a boilerplate success confirmation like "Edit applied successfully."
288
- // (write-side). Only the usage line is shown for these.
289
- const SUPPRESS_OUTPUT_TOOLS = new Set([
290
- 'read', 'notebookread', 'list', 'ls', 'glob', 'grep', 'todoread', 'lsp',
291
- 'write', 'edit', 'multiedit', 'patch', 'notebookedit', 'todowrite',
292
- ]);
293
- export function shouldSuppressToolOutput(toolName) {
294
- return SUPPRESS_OUTPUT_TOOLS.has(toolName.toLowerCase());
295
- }
296
- export function formatToolPart(toolPart) {
297
- const base = formatToolUsage(toolPart.tool, toolPart.state.input ?? {});
298
- if (toolPart.state.status === 'completed') {
299
- if (shouldSuppressToolOutput(toolPart.tool)) {
300
- return base;
301
- }
302
- const result = toolPart.state.output ? formatToolResult(toolPart.state.output, toolPart.tool) : '[empty]';
303
- return `${base}\nResult: ${result}`;
304
- }
305
- if (toolPart.state.status === 'error') {
306
- const error = toolPart.state.error ? truncateText(toolPart.state.error, 200) : 'Unknown error';
307
- return `${base}\nResult: Error - ${error}`;
308
- }
309
- return base;
310
- }
311
- export function formatReasoningPart(part) {
312
- if (!part.text) {
313
- return '';
314
- }
315
- return `[Thinking: ${truncateText(part.text, 200)}]`;
316
- }
317
- export function formatFilePart(part) {
318
- if (part.mime?.startsWith('image/') && part.url) {
319
- const altText = part.filename ?? 'image';
320
- return `![${altText}](${part.url})`;
321
- }
322
- const source = part.source?.text?.value ?? '';
323
- const path = part.source?.path ?? part.filename ?? part.url ?? 'file';
324
- if (source) {
325
- const lang = detectLanguage(path);
326
- return [`File: \`${path}\``, `\`\`\`${lang}`, source, '```'].join('\n');
327
- }
328
- return `File: \`${path}\``;
329
- }
330
- export function formatPatchPart(part) {
331
- if (part.files?.length) {
332
- return `Patch updated: ${part.files.join(', ')}`;
333
- }
334
- return 'Patch updated';
335
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Polls Vicoa backend for user messages and sends them to OpenCode
3
- *
4
- * This mimics the Claude wrapper's message queue and polling functionality.
5
- */
6
- import type { VicoaClient } from './vicoa-client.js';
7
- export declare class MessagePoller {
8
- private client;
9
- private interval;
10
- private pollIntervalMs;
11
- private onMessage;
12
- private log;
13
- constructor(client: VicoaClient, onMessage: (content: string) => Promise<void>, logFunc?: (level: string, msg: string) => void, pollIntervalMs?: number);
14
- start(): void;
15
- stop(): void;
16
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * Polls Vicoa backend for user messages and sends them to OpenCode
3
- *
4
- * This mimics the Claude wrapper's message queue and polling functionality.
5
- */
6
- export class MessagePoller {
7
- client;
8
- interval = null;
9
- pollIntervalMs;
10
- onMessage;
11
- log;
12
- constructor(client, onMessage, logFunc, pollIntervalMs = 1000) {
13
- this.client = client;
14
- this.onMessage = onMessage;
15
- this.pollIntervalMs = pollIntervalMs;
16
- this.log = logFunc || ((level, msg) => console.log(`[${level}] ${msg}`));
17
- }
18
- start() {
19
- if (this.interval) {
20
- return;
21
- }
22
- this.log('info', 'Starting message poller');
23
- this.interval = setInterval(async () => {
24
- try {
25
- const messages = await this.client.getPendingMessages();
26
- for (const msg of messages) {
27
- if (msg.sender_type === 'USER' && msg.content) {
28
- this.log('debug', `Received user message: ${msg.content.substring(0, 100)}...`);
29
- await this.onMessage(msg.content);
30
- }
31
- }
32
- }
33
- catch (error) {
34
- this.log('warn', `Error polling messages: ${error}`);
35
- }
36
- }, this.pollIntervalMs);
37
- }
38
- stop() {
39
- if (this.interval) {
40
- clearInterval(this.interval);
41
- this.interval = null;
42
- this.log('info', 'Stopped message poller');
43
- }
44
- }
45
- }
@@ -1,5 +0,0 @@
1
- import type { VicoaClient } from './vicoa-client.js';
2
- export declare function syncProjectFiles(vicoaClient: VicoaClient, projectPath: string): Promise<void>;
3
- /**
4
- * Sync project files to Vicoa backend for @ mentions
5
- */
@@ -1,187 +0,0 @@
1
- import * as fs from 'fs/promises';
2
- import * as path from 'path';
3
- import { formatProjectPath } from './path-utils.js';
4
- // Common patterns to always exclude (matching Python version)
5
- const DEFAULT_EXCLUDE_PATTERNS = [
6
- '.git/',
7
- '.pytest_cache/',
8
- '.dart_tool/',
9
- '.ruff_cache/',
10
- '.mypy_cache/',
11
- '__pycache__/',
12
- 'node_modules/',
13
- '.venv/',
14
- 'venv/',
15
- '.tox/',
16
- '.eggs/',
17
- '*.egg-info/',
18
- 'dist/',
19
- 'build/',
20
- 'target/', // Rust build output
21
- '.next/', // Next.js
22
- '.nuxt/', // Nuxt
23
- 'coverage/',
24
- '.coverage',
25
- '.nyc_output/',
26
- '*.pyc',
27
- '*.pyo',
28
- '*.pyd',
29
- ];
30
- // Extract directory names from exclude patterns
31
- function getExcludedDirNames() {
32
- const excluded = new Set();
33
- for (const pattern of DEFAULT_EXCLUDE_PATTERNS) {
34
- // Skip file patterns (contain wildcards)
35
- if (pattern.includes('*')) {
36
- continue;
37
- }
38
- // Strip trailing slashes and add to set
39
- const dirName = pattern.replace(/\/$/, '');
40
- if (dirName) {
41
- excluded.add(dirName);
42
- }
43
- }
44
- return excluded;
45
- }
46
- // Load .gitignore patterns
47
- async function loadGitignorePatterns(projectPath) {
48
- const gitignorePath = path.join(projectPath, '.gitignore');
49
- try {
50
- const content = await fs.readFile(gitignorePath, 'utf-8');
51
- return content
52
- .split('\n')
53
- .map(line => line.trim())
54
- .filter(line => line && !line.startsWith('#'));
55
- }
56
- catch {
57
- return [];
58
- }
59
- }
60
- // Simple gitignore pattern matcher (basic implementation)
61
- function matchesGitignorePattern(filePath, patterns) {
62
- for (const pattern of patterns) {
63
- const normalizedPattern = pattern.trim();
64
- if (!normalizedPattern)
65
- continue;
66
- // Convert to regex for simple matching
67
- const regexPattern = normalizedPattern
68
- .replace(/\./g, '\\.')
69
- .replace(/\*/g, '.*')
70
- .replace(/\?/g, '.');
71
- const regex = new RegExp(`^${regexPattern}`);
72
- // Check both relative path and basename
73
- if (regex.test(filePath) || regex.test(path.basename(filePath))) {
74
- return true;
75
- }
76
- }
77
- return false;
78
- }
79
- // Scan project files recursively
80
- async function scanProjectFiles(projectPath, vicoaClient, maxFiles = 100000) {
81
- const base = path.resolve(projectPath);
82
- try {
83
- const stats = await fs.stat(base);
84
- if (!stats.isDirectory()) {
85
- return [];
86
- }
87
- }
88
- catch {
89
- return [];
90
- }
91
- const excludePatterns = [...DEFAULT_EXCLUDE_PATTERNS];
92
- const gitignorePatterns = await loadGitignorePatterns(base);
93
- excludePatterns.push(...gitignorePatterns);
94
- const skipDirs = getExcludedDirNames();
95
- const files = [];
96
- const folders = new Set();
97
- async function walkDirectory(dirPath, relativePath = '') {
98
- try {
99
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
100
- for (const entry of entries) {
101
- // Skip excluded directories early
102
- if (entry.isDirectory() && skipDirs.has(entry.name)) {
103
- continue;
104
- }
105
- const entryRelativePath = relativePath ? path.join(relativePath, entry.name) : entry.name;
106
- const entryFullPath = path.join(dirPath, entry.name);
107
- if (entry.isDirectory()) {
108
- await walkDirectory(entryFullPath, entryRelativePath);
109
- // Add folder to results (with trailing slash)
110
- const folderPath = entryRelativePath.replace(/\\/g, '/') + '/';
111
- folders.add(folderPath);
112
- }
113
- else if (entry.isFile()) {
114
- // Check if file should be excluded
115
- if (matchesGitignorePattern(entryRelativePath, excludePatterns)) {
116
- continue;
117
- }
118
- files.push(entryRelativePath.replace(/\\/g, '/'));
119
- // Extract parent folders
120
- const parts = entryRelativePath.split(path.sep);
121
- for (let i = 0; i < parts.length - 1; i++) {
122
- const folderPath = parts.slice(0, i + 1).join('/') + '/';
123
- folders.add(folderPath);
124
- }
125
- }
126
- // Stop at max_files limit
127
- if (files.length >= maxFiles) {
128
- vicoaClient.log('warn', `Large project detected: ${maxFiles}+ files found`);
129
- vicoaClient.log('warn', `Only syncing first ${maxFiles} files for performance`);
130
- vicoaClient.log('warn', 'File mentions may be incomplete');
131
- return;
132
- }
133
- }
134
- }
135
- catch (error) {
136
- vicoaClient.log('warn', `Error scanning directory ${dirPath}: ${error}`);
137
- }
138
- }
139
- await walkDirectory(base);
140
- // Combine folders and files
141
- return Array.from(folders).concat(files);
142
- }
143
- // Sync project files to Vicoa backend
144
- export async function syncProjectFiles(vicoaClient, projectPath) {
145
- try {
146
- // Use absolute path for file scanning (needed for fs operations)
147
- const absolutePath = path.resolve(projectPath);
148
- vicoaClient.log('info', 'Preparing fuzzy file search with @ ...');
149
- const files = await scanProjectFiles(absolutePath, vicoaClient);
150
- if (files.length === 0) {
151
- return; // No files to sync
152
- }
153
- // Send tilde path to backend (consistent with Claude wrapper)
154
- const formattedPath = formatProjectPath(absolutePath);
155
- await vicoaClient.syncFiles(formattedPath, files);
156
- vicoaClient.log('info', `Synced ${files.length} files for fuzzy search`);
157
- }
158
- catch (error) {
159
- vicoaClient.log('warn', `Failed to sync project files: ${error}`);
160
- // Silently fail - don't block plugin startup
161
- }
162
- }
163
- // Backup vicoa client api call here
164
- /**
165
- * Sync project files to Vicoa backend for @ mentions
166
- */
167
- // async syncFiles(projectPath: string, files: string[]): Promise<void> {
168
- // try {
169
- // const response = await fetch(`${this.config.baseUrl}/api/v1/files/sync`, {
170
- // method: 'POST',
171
- // headers: {
172
- // 'Authorization': `Bearer ${this.config.apiKey}`,
173
- // 'Content-Type': 'application/json',
174
- // },
175
- // body: JSON.stringify({
176
- // project_path: projectPath,
177
- // files,
178
- // }),
179
- // });
180
- // if (!response.ok) {
181
- // const error = await response.text();
182
- // this.log('warn', `Failed to sync project files: ${response.statusText} - ${error}`);
183
- // }
184
- // } catch (error) {
185
- // this.log('warn', `Error syncing project files: ${error}`);
186
- // }
187
- // }
@@ -1,67 +0,0 @@
1
- /**
2
- * Vicoa API client for OpenCode plugin
3
- *
4
- * This client uses Vicoa's existing REST APIs to communicate with the dashboard.
5
- * It mimics the Python VicoaClient functionality but runs in TypeScript/Node.js.
6
- */
7
- export interface VicoaClientConfig {
8
- apiKey: string;
9
- baseUrl: string;
10
- agentType: string;
11
- agentInstanceId: string;
12
- logFunc?: (level: string, msg: string) => void;
13
- }
14
- export interface VicoaMessage {
15
- id: string;
16
- content: string;
17
- sender_type: 'USER' | 'AGENT';
18
- requires_user_input: boolean;
19
- created_at: string;
20
- }
21
- export declare class VicoaClient {
22
- private config;
23
- lastMessageId: string | null;
24
- log: (level: string, msg: string) => void;
25
- constructor(config: VicoaClientConfig);
26
- /**
27
- * Register agent instance with Vicoa backend
28
- */
29
- registerAgentInstance(project: string, homeDir: string): Promise<{
30
- agent_instance_id: string;
31
- }>;
32
- /**
33
- * Sync custom slash commands to Vicoa backend
34
- */
35
- syncCommands(agentType: string, commands: Record<string, {
36
- description: string;
37
- }>): Promise<void>;
38
- /**
39
- * Send agent message to Vicoa dashboard
40
- */
41
- sendMessage(content: string, requiresUserInput?: boolean): Promise<string | null>;
42
- /**
43
- * Send user message from terminal to Vicoa dashboard
44
- * This is used when the user types a message directly in the OpenCode terminal
45
- */
46
- sendUserMessage(content: string): Promise<string | null>;
47
- /**
48
- * Poll for pending user messages from Vicoa dashboard
49
- */
50
- getPendingMessages(): Promise<VicoaMessage[]>;
51
- /**
52
- * Request user input (equivalent to Claude wrapper's request_user_input)
53
- */
54
- requestUserInput(messageId: string): Promise<void>;
55
- /**
56
- * Update agent instance status
57
- */
58
- updateStatus(status: 'ACTIVE' | 'AWAITING_INPUT' | 'PAUSED' | 'STALE' | 'COMPLETED' | 'FAILED' | 'KILLED' | 'DISCONNECTED' | 'DELETED'): Promise<void>;
59
- /**
60
- * Update agent instance title/name
61
- */
62
- updateAgentInstanceName(name: string): Promise<void>;
63
- /**
64
- * End session
65
- */
66
- endSession(): Promise<void>;
67
- }