remote-opencode 1.0.10 β 1.1.1
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/README.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
> Control your AI coding assistant from anywhere β your phone, tablet, or another computer.
|
|
4
4
|
|
|
5
|
+
 π¦ Used by developers worldwide β **800+ weekly downloads** on npm
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
<div align="center">
|
|
6
9
|
<img width="1024" alt="Gemini_Generated_Image_47d5gq47d5gq47d5" src="https://github.com/user-attachments/assets/1defa11d-6195-4a9c-956b-4f87470f6393" />
|
|
7
10
|
</div>
|
|
@@ -561,10 +564,4 @@ MIT
|
|
|
561
564
|
|
|
562
565
|
## Contributing
|
|
563
566
|
|
|
564
|
-
Contributions are welcome! Please
|
|
565
|
-
|
|
566
|
-
1. Fork the repository
|
|
567
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
568
|
-
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
569
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
570
|
-
5. Open a Pull Request
|
|
567
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) before submitting a Pull Request.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { parseSSEEvent, extractTextFromPart, accumulateText, formatOutput, stripAnsi } from '../utils/messageFormatter.js';
|
|
2
|
+
import { parseSSEEvent, extractTextFromPart, accumulateText, formatOutput, stripAnsi, buildContextHeader } from '../utils/messageFormatter.js';
|
|
3
3
|
describe('messageFormatter', () => {
|
|
4
4
|
describe('stripAnsi', () => {
|
|
5
5
|
it('should remove ANSI escape codes', () => {
|
|
@@ -63,6 +63,20 @@ describe('messageFormatter', () => {
|
|
|
63
63
|
expect(accumulateText('', 'Hello')).toBe('Hello');
|
|
64
64
|
});
|
|
65
65
|
});
|
|
66
|
+
describe('buildContextHeader', () => {
|
|
67
|
+
it('should format branch name and model name', () => {
|
|
68
|
+
const result = buildContextHeader('feature/dark-mode', 'claude-sonnet-4-20250514');
|
|
69
|
+
expect(result).toBe('πΏ `feature/dark-mode` Β· π€ `claude-sonnet-4-20250514`');
|
|
70
|
+
});
|
|
71
|
+
it('should handle default model', () => {
|
|
72
|
+
const result = buildContextHeader('main', 'default');
|
|
73
|
+
expect(result).toBe('πΏ `main` Β· π€ `default`');
|
|
74
|
+
});
|
|
75
|
+
it('should handle auto-generated branch names', () => {
|
|
76
|
+
const result = buildContextHeader('auto/abc12345-1738600000000', 'default');
|
|
77
|
+
expect(result).toBe('πΏ `auto/abc12345-1738600000000` Β· π€ `default`');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
66
80
|
describe('formatOutput (existing functionality)', () => {
|
|
67
81
|
it('should work for OpenCode JSON output with newlines preserved', () => {
|
|
68
82
|
const buffer = JSON.stringify({ type: 'text', part: { text: 'Hello' } }) + '\n' +
|
|
@@ -4,7 +4,7 @@ import * as sessionManager from './sessionManager.js';
|
|
|
4
4
|
import * as serveManager from './serveManager.js';
|
|
5
5
|
import * as worktreeManager from './worktreeManager.js';
|
|
6
6
|
import { SSEClient } from './sseClient.js';
|
|
7
|
-
import { formatOutput } from '../utils/messageFormatter.js';
|
|
7
|
+
import { formatOutput, buildContextHeader } from '../utils/messageFormatter.js';
|
|
8
8
|
import { processNextInQueue } from './queueManager.js';
|
|
9
9
|
export async function runPrompt(channel, threadId, prompt, parentChannelId) {
|
|
10
10
|
const projectPath = dataStore.getChannelProjectPath(parentChannelId);
|
|
@@ -52,7 +52,9 @@ export async function runPrompt(channel, threadId, prompt, parentChannelId) {
|
|
|
52
52
|
}
|
|
53
53
|
const effectivePath = worktreeMapping?.worktreePath ?? projectPath;
|
|
54
54
|
const preferredModel = dataStore.getChannelModel(parentChannelId);
|
|
55
|
-
const modelDisplay = preferredModel ?
|
|
55
|
+
const modelDisplay = preferredModel ? `${preferredModel}` : 'default';
|
|
56
|
+
const branchName = worktreeMapping?.branchName ?? await worktreeManager.getCurrentBranch(effectivePath) ?? 'main';
|
|
57
|
+
const contextHeader = buildContextHeader(branchName, modelDisplay);
|
|
56
58
|
const buttons = new ActionRowBuilder()
|
|
57
59
|
.addComponents(new ButtonBuilder()
|
|
58
60
|
.setCustomId(`interrupt_${threadId}`)
|
|
@@ -61,7 +63,7 @@ export async function runPrompt(channel, threadId, prompt, parentChannelId) {
|
|
|
61
63
|
let streamMessage;
|
|
62
64
|
try {
|
|
63
65
|
streamMessage = await channel.send({
|
|
64
|
-
content:
|
|
66
|
+
content: `${contextHeader}\nπ **Prompt**: ${prompt}\n\nπ Starting OpenCode server...`,
|
|
65
67
|
components: [buttons]
|
|
66
68
|
});
|
|
67
69
|
}
|
|
@@ -84,7 +86,7 @@ export async function runPrompt(channel, threadId, prompt, parentChannelId) {
|
|
|
84
86
|
};
|
|
85
87
|
try {
|
|
86
88
|
port = await serveManager.spawnServe(effectivePath, preferredModel);
|
|
87
|
-
await updateStreamMessage(
|
|
89
|
+
await updateStreamMessage(`${contextHeader}\nπ **Prompt**: ${prompt}\n\nβ³ Waiting for OpenCode server...`, [buttons]);
|
|
88
90
|
await serveManager.waitForReady(port, 30000, effectivePath, preferredModel);
|
|
89
91
|
const settings = dataStore.getQueueSettings(threadId);
|
|
90
92
|
// If fresh context is enabled, we always clear the session before starting
|
|
@@ -127,7 +129,7 @@ export async function runPrompt(channel, threadId, prompt, parentChannelId) {
|
|
|
127
129
|
.setLabel('βΈοΈ Interrupt')
|
|
128
130
|
.setStyle(ButtonStyle.Secondary)
|
|
129
131
|
.setDisabled(true));
|
|
130
|
-
await updateStreamMessage(
|
|
132
|
+
await updateStreamMessage(`${contextHeader}\nπ **Prompt**: ${prompt}\n\n\`\`\`\n${formatted}\n\`\`\``, [disabledButtons]);
|
|
131
133
|
await channel.send({ content: 'β
Done' });
|
|
132
134
|
sseClient.disconnect();
|
|
133
135
|
sessionManager.clearSseClient(threadId);
|
|
@@ -146,7 +148,7 @@ export async function runPrompt(channel, threadId, prompt, parentChannelId) {
|
|
|
146
148
|
}
|
|
147
149
|
(async () => {
|
|
148
150
|
try {
|
|
149
|
-
await updateStreamMessage(
|
|
151
|
+
await updateStreamMessage(`${contextHeader}\nπ **Prompt**: ${prompt}\n\nβ Connection error: ${error.message}`, []);
|
|
150
152
|
sseClient.disconnect();
|
|
151
153
|
sessionManager.clearSseClient(threadId);
|
|
152
154
|
const settings = dataStore.getQueueSettings(threadId);
|
|
@@ -170,13 +172,13 @@ export async function runPrompt(channel, threadId, prompt, parentChannelId) {
|
|
|
170
172
|
const newContent = formatted || 'Processing...';
|
|
171
173
|
if (newContent !== lastContent || tick % 2 === 0) {
|
|
172
174
|
lastContent = newContent;
|
|
173
|
-
await updateStreamMessage(
|
|
175
|
+
await updateStreamMessage(`${contextHeader}\nπ **Prompt**: ${prompt}\n\n${spinnerChar} **Running...**\n\`\`\`\n${newContent}\n\`\`\``, [buttons]);
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
catch {
|
|
177
179
|
}
|
|
178
180
|
}, 1000);
|
|
179
|
-
await updateStreamMessage(
|
|
181
|
+
await updateStreamMessage(`${contextHeader}\nπ **Prompt**: ${prompt}\n\nπ Sending prompt...`, [buttons]);
|
|
180
182
|
await sessionManager.sendPrompt(port, sessionId, prompt, preferredModel);
|
|
181
183
|
}
|
|
182
184
|
catch (error) {
|
|
@@ -184,7 +186,7 @@ export async function runPrompt(channel, threadId, prompt, parentChannelId) {
|
|
|
184
186
|
clearInterval(updateInterval);
|
|
185
187
|
}
|
|
186
188
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
187
|
-
await updateStreamMessage(
|
|
189
|
+
await updateStreamMessage(`${contextHeader}\nπ **Prompt**: ${prompt}\n\nβ OpenCode execution failed: ${errorMessage}`, []);
|
|
188
190
|
const client = sessionManager.getSseClient(threadId);
|
|
189
191
|
if (client) {
|
|
190
192
|
client.disconnect();
|
|
@@ -67,6 +67,15 @@ export async function removeWorktree(worktreePath, deleteBranch) {
|
|
|
67
67
|
throw new Error(`Failed to remove worktree: ${error.message}`);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
+
export async function getCurrentBranch(cwd) {
|
|
71
|
+
try {
|
|
72
|
+
const { stdout } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd });
|
|
73
|
+
return stdout.trim() || null;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
70
79
|
export function worktreeExists(worktreePath) {
|
|
71
80
|
return existsSync(worktreePath);
|
|
72
81
|
}
|
|
@@ -54,6 +54,9 @@ export function parseOpenCodeOutput(buffer) {
|
|
|
54
54
|
}
|
|
55
55
|
return result;
|
|
56
56
|
}
|
|
57
|
+
export function buildContextHeader(branchName, modelName) {
|
|
58
|
+
return `πΏ \`${branchName}\` Β· π€ \`${modelName}\``;
|
|
59
|
+
}
|
|
57
60
|
export function formatOutput(buffer, maxLength = 1900) {
|
|
58
61
|
const parsed = parseOpenCodeOutput(buffer);
|
|
59
62
|
if (!parsed.trim()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remote-opencode",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Discord bot for remote OpenCode CLI access",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"eventsource": "^4.1.0",
|
|
43
43
|
"node-pty": "^1.1.0",
|
|
44
44
|
"open": "^10.1.0",
|
|
45
|
+
"opencode-antigravity-auth": "^1.4.6",
|
|
45
46
|
"picocolors": "^1.1.1",
|
|
46
47
|
"update-notifier": "^7.3.1"
|
|
47
48
|
},
|