opencode-miniterm 1.0.1 → 1.0.3
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/AGENTS.md +46 -11
- package/README.md +164 -1
- package/bun.lock +3 -3
- package/package.json +3 -3
- package/src/ansi.ts +4 -0
- package/src/commands/diff.ts +3 -2
- package/src/commands/init.ts +3 -2
- package/src/commands/new.ts +1 -1
- package/src/commands/page.ts +9 -6
- package/src/commands/sessions.ts +4 -4
- package/src/commands/undo.ts +4 -3
- package/src/config.ts +2 -1
- package/src/index.ts +108 -39
- package/src/render.ts +57 -35
- package/test/render.test.ts +54 -41
- package/src/commands/kill.ts +0 -33
package/AGENTS.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
# OpenCode
|
|
1
|
+
# OpenCode Miniterm - Agent Guidelines
|
|
2
2
|
|
|
3
3
|
## Build & Development Commands
|
|
4
4
|
|
|
5
5
|
### Run the application
|
|
6
|
+
|
|
6
7
|
```bash
|
|
7
8
|
bun run src/index.ts
|
|
8
9
|
# Or just:
|
|
@@ -10,46 +11,55 @@ bun src/index.ts
|
|
|
10
11
|
```
|
|
11
12
|
|
|
12
13
|
### Build (when bundler is added)
|
|
14
|
+
|
|
13
15
|
```bash
|
|
14
16
|
bun build src/index.ts --outdir dist
|
|
15
17
|
```
|
|
16
18
|
|
|
17
19
|
### Testing
|
|
20
|
+
|
|
18
21
|
No test framework is currently configured. Add one of these to package.json:
|
|
22
|
+
|
|
19
23
|
- **Bun Test**: `bun test` (recommended - built-in, fast)
|
|
20
24
|
- **Jest**: `npm test` or `bun run test`
|
|
21
25
|
- **Vitest**: `vitest`
|
|
22
26
|
|
|
23
27
|
To run a single test (once configured):
|
|
28
|
+
|
|
24
29
|
- Bun Test: `bun test --test-name-pattern "testName"`
|
|
25
30
|
- Jest: `npm test -- testName`
|
|
26
31
|
- Vitest: `vitest run testName`
|
|
27
32
|
|
|
28
33
|
### Linting & Formatting (recommended additions)
|
|
34
|
+
|
|
29
35
|
Install and configure these tools:
|
|
36
|
+
|
|
30
37
|
```bash
|
|
31
38
|
bun add -d eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser prettier
|
|
32
39
|
```
|
|
33
40
|
|
|
34
41
|
Commands to add to package.json:
|
|
42
|
+
|
|
35
43
|
```json
|
|
36
44
|
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
"lint": "eslint src --ext .ts",
|
|
46
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
47
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
48
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
49
|
+
"typecheck": "tsc --noEmit"
|
|
42
50
|
}
|
|
43
51
|
```
|
|
44
52
|
|
|
45
53
|
## Code Style Guidelines
|
|
46
54
|
|
|
47
55
|
### TypeScript Configuration
|
|
56
|
+
|
|
48
57
|
- Use strict mode: `"strict": true` in tsconfig.json
|
|
49
58
|
- Target ES2022+ for modern Node/Bun features
|
|
50
59
|
- Use `moduleResolution: "bundler"` for Bun compatibility
|
|
51
60
|
|
|
52
61
|
### Imports
|
|
62
|
+
|
|
53
63
|
- Use ES6 imports (ESM): `import { something } from 'module'`
|
|
54
64
|
- Group imports in this order:
|
|
55
65
|
1. Node/Bun built-ins
|
|
@@ -59,6 +69,7 @@ Commands to add to package.json:
|
|
|
59
69
|
- Avoid default exports; prefer named exports for better tree-shaking
|
|
60
70
|
|
|
61
71
|
### Formatting
|
|
72
|
+
|
|
62
73
|
- Use 2 spaces for indentation
|
|
63
74
|
- Use single quotes for strings
|
|
64
75
|
- Use semicolons at end of statements
|
|
@@ -67,6 +78,7 @@ Commands to add to package.json:
|
|
|
67
78
|
- Spaces around operators: `a = b + c` not `a=b+c`
|
|
68
79
|
|
|
69
80
|
### Types & Type Safety
|
|
81
|
+
|
|
70
82
|
- Always provide explicit return types for functions
|
|
71
83
|
- Use `interface` for object shapes, `type` for unions/primitives
|
|
72
84
|
- Avoid `any`; use `unknown` when type is truly unknown
|
|
@@ -74,6 +86,7 @@ Commands to add to package.json:
|
|
|
74
86
|
- Leverage Bun's built-in type definitions (from `bun-types`)
|
|
75
87
|
|
|
76
88
|
### Naming Conventions
|
|
89
|
+
|
|
77
90
|
- **Files**: kebab-case: `my-service.ts`
|
|
78
91
|
- **Variables/Functions**: camelCase: `myFunction`
|
|
79
92
|
- **Classes**: PascalCase: `MyService`
|
|
@@ -82,14 +95,18 @@ Commands to add to package.json:
|
|
|
82
95
|
- **Types/Interfaces**: PascalCase, often with suffixes: `UserService`, `ConfigOptions`
|
|
83
96
|
|
|
84
97
|
### Error Handling
|
|
98
|
+
|
|
85
99
|
- Use try/catch for async operations
|
|
86
100
|
- Create custom error classes for domain-specific errors:
|
|
87
101
|
```ts
|
|
88
102
|
class TerminalError extends Error {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
103
|
+
constructor(
|
|
104
|
+
message: string,
|
|
105
|
+
public code: string,
|
|
106
|
+
) {
|
|
107
|
+
super(message);
|
|
108
|
+
this.name = "TerminalError";
|
|
109
|
+
}
|
|
93
110
|
}
|
|
94
111
|
```
|
|
95
112
|
- Always include error context in error messages
|
|
@@ -97,24 +114,28 @@ Commands to add to package.json:
|
|
|
97
114
|
- Never swallow errors silently
|
|
98
115
|
|
|
99
116
|
### Async/Promise Handling
|
|
117
|
+
|
|
100
118
|
- Use async/await over .then()/.catch()
|
|
101
119
|
- Handle promise rejections: `process.on('unhandledRejection')`
|
|
102
120
|
- Use Bun's optimized APIs where available (e.g., `Bun.file()`)
|
|
103
121
|
- Implement timeouts for network requests
|
|
104
122
|
|
|
105
123
|
### Code Organization
|
|
124
|
+
|
|
106
125
|
- Structure by feature/domain, not by file type
|
|
107
126
|
- Keep files focused: one responsibility per file
|
|
108
127
|
- Export at file end; avoid export分散
|
|
109
128
|
- Use barrel files (`index.ts`) for cleaner imports
|
|
110
129
|
|
|
111
130
|
### Comments
|
|
131
|
+
|
|
112
132
|
- Use JSDoc for public APIs: `/** @description ... */`
|
|
113
133
|
- Comment WHY, not WHAT
|
|
114
134
|
- Keep comments current with code changes
|
|
115
135
|
- Avoid inline comments for obvious logic
|
|
116
136
|
|
|
117
137
|
### Performance (Bun-Specific)
|
|
138
|
+
|
|
118
139
|
- Leverage Bun's fast I/O: `Bun.write()`, `Bun.file()`
|
|
119
140
|
- Use `TextEncoder`/`TextDecoder` for encoding
|
|
120
141
|
- Prefer native over polyfills
|
|
@@ -123,6 +144,7 @@ Commands to add to package.json:
|
|
|
123
144
|
## Project Context
|
|
124
145
|
|
|
125
146
|
This is an alternative terminal UI for OpenCode. Focus on:
|
|
147
|
+
|
|
126
148
|
- Fast, responsive terminal rendering
|
|
127
149
|
- Clean CLI UX with good error messages
|
|
128
150
|
- Efficient resource usage (memory/CPU)
|
|
@@ -138,6 +160,7 @@ This is an alternative terminal UI for OpenCode. Focus on:
|
|
|
138
160
|
## OpenCode Server Integration
|
|
139
161
|
|
|
140
162
|
### Starting the Server
|
|
163
|
+
|
|
141
164
|
- Use `opencode serve` to start a headless HTTP server (not `opencode server`)
|
|
142
165
|
- Default URL: `http://127.0.0.1:4096` (port may vary, can be 0/random)
|
|
143
166
|
- Server requires 2-3 seconds to initialize before accepting requests
|
|
@@ -145,6 +168,7 @@ This is an alternative terminal UI for OpenCode. Focus on:
|
|
|
145
168
|
- Always handle SIGINT to properly shut down the server process
|
|
146
169
|
|
|
147
170
|
### Authentication
|
|
171
|
+
|
|
148
172
|
- Server may require HTTP Basic Auth if `OPENCODE_SERVER_PASSWORD` is set
|
|
149
173
|
- Username: `OPENCODE_SERVER_USERNAME` env var (default: 'opencode')
|
|
150
174
|
- Password: `OPENCODE_SERVER_PASSWORD` env var (required if server has password set)
|
|
@@ -153,6 +177,7 @@ This is an alternative terminal UI for OpenCode. Focus on:
|
|
|
153
177
|
- Check env vars at startup: `echo $OPENCODE_SERVER_PASSWORD` to verify it's set
|
|
154
178
|
|
|
155
179
|
### Creating Sessions
|
|
180
|
+
|
|
156
181
|
```ts
|
|
157
182
|
POST /session
|
|
158
183
|
Headers: { "Content-Type": "application/json", "Authorization": "Basic <creds>" }
|
|
@@ -161,14 +186,17 @@ Response: { id: string, title?: string, ... }
|
|
|
161
186
|
```
|
|
162
187
|
|
|
163
188
|
### Getting Available Models
|
|
189
|
+
|
|
164
190
|
```ts
|
|
165
191
|
GET /config/providers
|
|
166
192
|
Headers: { "Authorization": "Basic <creds>" }
|
|
167
193
|
Response: { providers: Provider[], default: { [key: string]: string } }
|
|
168
194
|
```
|
|
195
|
+
|
|
169
196
|
Note: `/models` endpoint returns HTML documentation, not JSON. Use `/config/providers` for programmatic access.
|
|
170
197
|
|
|
171
198
|
### Sending Messages
|
|
199
|
+
|
|
172
200
|
```ts
|
|
173
201
|
POST /session/:id/message
|
|
174
202
|
Headers: { "Content-Type": "application/json", "Authorization": "Basic <creds>" }
|
|
@@ -183,6 +211,7 @@ Response: { info: Message, parts: Part[] }
|
|
|
183
211
|
```
|
|
184
212
|
|
|
185
213
|
### Getting Session Messages
|
|
214
|
+
|
|
186
215
|
```ts
|
|
187
216
|
GET /session/:id/message
|
|
188
217
|
Headers: { "Authorization": "Basic <creds>" }
|
|
@@ -190,20 +219,24 @@ Response: { info: Message, parts: Part[] }[]
|
|
|
190
219
|
```
|
|
191
220
|
|
|
192
221
|
### Undoing Messages (Revert)
|
|
222
|
+
|
|
193
223
|
```ts
|
|
194
224
|
POST /session/:id/revert
|
|
195
225
|
Headers: { "Content-Type": "application/json", "Authorization": "Basic <creds>" }
|
|
196
226
|
Body: { messageID: string, partID?: string }
|
|
197
227
|
Response: { id: string, revert: { messageID, snapshot, diff } }
|
|
198
228
|
```
|
|
229
|
+
|
|
199
230
|
Typically used to undo the last assistant message by fetching messages first, then reverting the last one.
|
|
200
231
|
|
|
201
232
|
**IMPORTANT**: The `model` field is required when sending messages. Without it, the request will hang indefinitely. Get available models from `GET /config/providers` or `GET /models`. Common models:
|
|
233
|
+
|
|
202
234
|
- `big-pickle` (opencode provider) - default, high quality
|
|
203
235
|
- `glm-5-free` (opencode provider) - free GLM model
|
|
204
236
|
- `gpt-5-nano` (opencode provider) - fast GPT model
|
|
205
237
|
|
|
206
238
|
### Response Format
|
|
239
|
+
|
|
207
240
|
- Response has `{ info, parts }` structure
|
|
208
241
|
- Parts can be: `step-start`, `reasoning`, `text`, `step-finish`, `tool_use`, `tool_result`
|
|
209
242
|
- `step-start` - Indicates beginning of a thinking/processing step
|
|
@@ -215,6 +248,7 @@ Typically used to undo the last assistant message by fetching messages first, th
|
|
|
215
248
|
- Display reasoning and text parts to the user for transparency
|
|
216
249
|
|
|
217
250
|
### Server-Sent Events (SSE)
|
|
251
|
+
|
|
218
252
|
- Connect to event stream at `/event` for real-time updates
|
|
219
253
|
- Events include: `message.part.updated`, `session.status`, `session.updated`, `message.updated`, `session.diff`, `session.idle`
|
|
220
254
|
- Event structure: `{ type: string, properties: {...} }`
|
|
@@ -224,6 +258,7 @@ Typically used to undo the last assistant message by fetching messages first, th
|
|
|
224
258
|
- Delta updates allow streaming reasoning and text for better UX
|
|
225
259
|
|
|
226
260
|
### Error Handling
|
|
261
|
+
|
|
227
262
|
- Server returns 401 Unauthorized when authentication is missing/invalid
|
|
228
263
|
- Handle connection errors (server may not be ready yet)
|
|
229
264
|
- Always parse error text from response for debugging
|
|
@@ -240,4 +275,4 @@ Typically used to undo the last assistant message by fetching messages first, th
|
|
|
240
275
|
- Never commit API keys, tokens, or secrets
|
|
241
276
|
- Validate all user inputs
|
|
242
277
|
- Sanitize terminal output to prevent injection
|
|
243
|
-
- Use environment variables for configuration
|
|
278
|
+
- Use environment variables for configuration
|
package/README.md
CHANGED
|
@@ -2,4 +2,167 @@
|
|
|
2
2
|
|
|
3
3
|
A small front-end terminal UI for [OpenCode](https://github.com/anomalyco/opencode).
|
|
4
4
|
|
|
5
|
-
This project is not affiliated with OpenCode.
|
|
5
|
+
> **Note:** This project is not affiliated with OpenCode.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Slash Commands** - Quick access to common operations
|
|
10
|
+
- **File Auto-Completion** - Type `@` followed by file path for intelligent completions
|
|
11
|
+
- **Real-Time Streaming** - See AI responses as they're being generated
|
|
12
|
+
- **Logging Support** - Optional conversation logging for debugging
|
|
13
|
+
- **Keyboard Navigation** - Readline support with history and editing
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### Prerequisites
|
|
18
|
+
|
|
19
|
+
- [OpenCode](https://github.com/anomalyco/opencode) - OpenCode server
|
|
20
|
+
- [Bun](https://bun.sh/) - Required runtime
|
|
21
|
+
|
|
22
|
+
### Install from npm
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g opencode-miniterm
|
|
26
|
+
# or
|
|
27
|
+
pnpm add -g opencode-miniterm
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Install from Source
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/your-repo/opencode-miniterm.git
|
|
34
|
+
cd opencode-miniterm
|
|
35
|
+
bun install
|
|
36
|
+
bun link
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Quick Start
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
ocmt
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This will:
|
|
46
|
+
|
|
47
|
+
1. Start the OpenCode server (if not already running)
|
|
48
|
+
2. Create or resume a session for the current directory
|
|
49
|
+
3. Present the interactive prompt
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
Configuration is stored in `~/.config/opencode-miniterm/opencode-miniterm.json`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"providerID": "opencode",
|
|
58
|
+
"modelID": "big-pickle",
|
|
59
|
+
"agentID": "build",
|
|
60
|
+
"sessionIDs": {
|
|
61
|
+
"/path/to/project1": "session-id-1",
|
|
62
|
+
"/path/to/project2": "session-id-2"
|
|
63
|
+
},
|
|
64
|
+
"loggingEnabled": false
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Environment Variables
|
|
69
|
+
|
|
70
|
+
- `OPENCODE_SERVER_USERNAME` - Server username (default: "opencode")
|
|
71
|
+
- `OPENCODE_SERVER_PASSWORD` - Server password (required if server has auth)
|
|
72
|
+
- `OPENCODE_MT_CONFIG_CONTENT` - Override config as JSON string
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
### Basic Interaction
|
|
77
|
+
|
|
78
|
+
Simply type your question or request at the prompt and press Enter:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
> Help me fix the bug in auth.ts
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Slash Commands
|
|
85
|
+
|
|
86
|
+
| Command | Description |
|
|
87
|
+
| ------------------ | ------------------------------------------- |
|
|
88
|
+
| `/help` | Show available commands |
|
|
89
|
+
| `/init` | Analyze project and create/update AGENTS.md |
|
|
90
|
+
| `/new` | Create a new session |
|
|
91
|
+
| `/sessions` | List and switch sessions |
|
|
92
|
+
| `/diff` | Show file additions and deletions |
|
|
93
|
+
| `/undo` | Undo last assistant request |
|
|
94
|
+
| `/details` | Show detailed info for the previous request |
|
|
95
|
+
| `/page` | Page through the detailed info |
|
|
96
|
+
| `/agents` | Show available agents |
|
|
97
|
+
| `/models` | Show available models |
|
|
98
|
+
| `/log` | Enable/disable logging |
|
|
99
|
+
| `/run <cmd>` | Run a shell command from within miniterm |
|
|
100
|
+
| `/exit` or `/quit` | Exit the application |
|
|
101
|
+
|
|
102
|
+
### File References
|
|
103
|
+
|
|
104
|
+
Reference files in your conversation using `@` followed by the path:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
> Review @src/index.ts and suggest improvements
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Tab completion is supported for file paths:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
> @sr<tab> → @src/
|
|
114
|
+
> @src/in<tab> → @src/index.ts
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Keyboard Shortcuts
|
|
118
|
+
|
|
119
|
+
| Key | Action |
|
|
120
|
+
| ---------------------- | ---------------------------- |
|
|
121
|
+
| `↑` / `↓` | Navigate command history |
|
|
122
|
+
| `←` / `→` | Move cursor |
|
|
123
|
+
| `Opt+←` / `Opt+→` | Move by word boundaries |
|
|
124
|
+
| `Tab` | Auto-complete commands/files |
|
|
125
|
+
| `Backspace` / `Delete` | Delete characters |
|
|
126
|
+
| `Esc` | Cancel current request |
|
|
127
|
+
| `Ctrl+C` | Force quit application |
|
|
128
|
+
|
|
129
|
+
## Session Management
|
|
130
|
+
|
|
131
|
+
OpenCode Miniterm automatically manages sessions per directory:
|
|
132
|
+
|
|
133
|
+
- **First Launch**: Creates a new session for the current directory
|
|
134
|
+
- **Subsequent Launches**: Resumes the last session for that directory
|
|
135
|
+
- **New Session**: Use `/new` to create a fresh session
|
|
136
|
+
- **Switch Sessions**: Use `/sessions` to browse and switch between all your sessions
|
|
137
|
+
|
|
138
|
+
## Development
|
|
139
|
+
|
|
140
|
+
### Running Locally
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
bun run dev
|
|
144
|
+
# or
|
|
145
|
+
bun src/index.ts
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Build
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
bun build src/index.ts --outdir dist
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Type Check
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
bun run check
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Formatting
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
bunx prettier --write "**/*.{ts,json,md}"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
ISC
|
package/bun.lock
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"": {
|
|
6
6
|
"name": "opencode-miniterm",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@opencode-ai/sdk": "^1.2.
|
|
8
|
+
"@opencode-ai/sdk": "^1.2.14",
|
|
9
9
|
"allmark": "^1.0.0",
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
|
|
48
48
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
|
49
49
|
|
|
50
|
-
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.2.
|
|
50
|
+
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.2.15", "", {}, "sha512-NUJNlyBCdZ4R0EBLjJziEQOp2XbRPJosaMcTcWSWO5XJPKGUpz0u8ql+5cR8K+v2RJ+hp2NobtNwpjEYfe6BRQ=="],
|
|
51
51
|
|
|
52
52
|
"@trivago/prettier-plugin-sort-imports": ["@trivago/prettier-plugin-sort-imports@6.0.2", "", { "dependencies": { "@babel/generator": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "javascript-natural-sort": "^0.7.1", "lodash-es": "^4.17.21", "minimatch": "^9.0.0", "parse-imports-exports": "^0.2.4" }, "peerDependencies": { "@vue/compiler-sfc": "3.x", "prettier": "2.x - 3.x", "prettier-plugin-ember-template-tag": ">= 2.0.0", "prettier-plugin-svelte": "3.x", "svelte": "4.x || 5.x" }, "optionalPeers": ["@vue/compiler-sfc", "prettier-plugin-ember-template-tag", "prettier-plugin-svelte", "svelte"] }, "sha512-3DgfkukFyC/sE/VuYjaUUWoFfuVjPK55vOFDsxD56XXynFMCZDYFogH2l/hDfOsQAm1myoU/1xByJ3tWqtulXA=="],
|
|
53
53
|
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
|
|
72
72
|
"@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260122.2", "", { "os": "win32", "cpu": "x64" }, "sha512-TJH+sSn7vxcGvaSm+fhcpW//dfSGBZGHrxoy0edAbE7UpFf8ub/3cILL5V1pCsF7w3aLNNgVKRpUkowdUgYcPQ=="],
|
|
73
73
|
|
|
74
|
-
"allmark": ["allmark@1.0.
|
|
74
|
+
"allmark": ["allmark@1.0.1", "", { "bin": { "allmark": "dist/bin/index.mjs" } }, "sha512-r4eeGshglWb3G99D4anWSPpieZ9kw9zXHeGd6NXjBbsbq+aCq/7W9hkrqYq0ywlf43ync2KKfmjeTHJum0AHEQ=="],
|
|
75
75
|
|
|
76
76
|
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
|
77
77
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-miniterm",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A small front-end terminal UI for OpenCode",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"bin": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"typescript": "^5"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@opencode-ai/sdk": "^1.2.
|
|
32
|
-
"allmark": "^1.0.
|
|
31
|
+
"@opencode-ai/sdk": "^1.2.15",
|
|
32
|
+
"allmark": "^1.0.1"
|
|
33
33
|
}
|
|
34
34
|
}
|
package/src/ansi.ts
CHANGED
|
@@ -9,12 +9,16 @@ export const CURSOR_UP = (lines: number) => `\x1b[${lines}A`;
|
|
|
9
9
|
export const RESET = "\x1b[0m";
|
|
10
10
|
export const BRIGHT_WHITE = "\x1b[97m";
|
|
11
11
|
export const BRIGHT_BLACK = "\x1b[90m";
|
|
12
|
+
export const BOLD_BRIGHT_BLACK = "\x1b[1;90m";
|
|
12
13
|
export const RED = "\x1b[31m";
|
|
13
14
|
export const GREEN = "\x1b[32m";
|
|
14
15
|
export const BLUE = "\x1b[34m";
|
|
15
16
|
export const CYAN = "\x1b[36m";
|
|
16
17
|
export const BOLD_MAGENTA = "\x1b[1;35m";
|
|
17
18
|
export const STRIKETHROUGH = "\x1b[9m";
|
|
19
|
+
export const WHITE_BACKGROUND = "\x1b[47m";
|
|
20
|
+
export const BRIGHT_BLACK_BACKGROUND = "\x1b[0;100m";
|
|
21
|
+
export const BOLD_BLACK = "\x1b[1;30m";
|
|
18
22
|
export const ANSI_CODE_PATTERN = /^\x1b\[[0-9;]*m/;
|
|
19
23
|
|
|
20
24
|
export function stripAnsiCodes(str: string): string {
|
package/src/commands/diff.ts
CHANGED
|
@@ -20,7 +20,8 @@ interface DiffLine {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
async function run(client: OpencodeClient, state: State): Promise<void> {
|
|
23
|
-
|
|
23
|
+
const cwd = process.cwd();
|
|
24
|
+
if (!config.sessionIDs[cwd]) {
|
|
24
25
|
console.log("No active session.\n");
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
@@ -28,7 +29,7 @@ async function run(client: OpencodeClient, state: State): Promise<void> {
|
|
|
28
29
|
console.log("Fetching file changes...");
|
|
29
30
|
|
|
30
31
|
const result = await client.session.diff({
|
|
31
|
-
path: { id: config.
|
|
32
|
+
path: { id: config.sessionIDs[cwd] },
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
if (result.error) {
|
package/src/commands/init.ts
CHANGED
|
@@ -14,11 +14,12 @@ let command: Command = {
|
|
|
14
14
|
export default command;
|
|
15
15
|
|
|
16
16
|
async function run(_client: OpencodeClient, _state: State): Promise<void> {
|
|
17
|
-
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
if (!config.sessionIDs[cwd]) return;
|
|
18
19
|
|
|
19
20
|
console.log("Running /init command (analyzing project and creating AGENTS.md)...");
|
|
20
21
|
const result = await _client.session.init({
|
|
21
|
-
path: { id: config.
|
|
22
|
+
path: { id: config.sessionIDs[cwd] },
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
if (result.error) {
|
package/src/commands/new.ts
CHANGED
|
@@ -16,7 +16,7 @@ export default command;
|
|
|
16
16
|
|
|
17
17
|
async function run(client: OpencodeClient, state: State): Promise<void> {
|
|
18
18
|
state.sessionID = await createSession(client);
|
|
19
|
-
config.
|
|
19
|
+
config.sessionIDs[process.cwd()] = state.sessionID;
|
|
20
20
|
saveConfig();
|
|
21
21
|
|
|
22
22
|
await updateSessionTitle();
|
package/src/commands/page.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { OpencodeClient } from "@opencode-ai/sdk";
|
|
2
2
|
import type { Key } from "node:readline";
|
|
3
|
+
import * as ansi from "../ansi";
|
|
3
4
|
import type { State } from "../index";
|
|
4
5
|
import { wrapText } from "../render";
|
|
5
6
|
import type { Command } from "../types";
|
|
@@ -24,18 +25,20 @@ function run(client: OpencodeClient, state: State): void {
|
|
|
24
25
|
if (!part || !part.text.trim()) continue;
|
|
25
26
|
|
|
26
27
|
if (part.title === "thinking") {
|
|
27
|
-
pages.push(
|
|
28
|
+
pages.push(
|
|
29
|
+
`${ansi.BOLD_BRIGHT_BLACK}~${ansi.RESET} ${ansi.BRIGHT_BLACK}${part.text.trimStart()}${ansi.RESET}`,
|
|
30
|
+
);
|
|
28
31
|
} else if (part.title === "response") {
|
|
29
|
-
pages.push(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} else
|
|
32
|
+
pages.push(
|
|
33
|
+
`${ansi.WHITE_BACKGROUND}${ansi.BOLD_BLACK}*${ansi.RESET} ${part.text.trimStart()}`,
|
|
34
|
+
);
|
|
35
|
+
} else {
|
|
33
36
|
pages.push(part.text);
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
if (pages.length === 0) {
|
|
38
|
-
console.log(
|
|
41
|
+
console.log(`${ansi.BRIGHT_BLACK}No parts to display yet.${ansi.RESET}\n`);
|
|
39
42
|
return;
|
|
40
43
|
}
|
|
41
44
|
|
package/src/commands/sessions.ts
CHANGED
|
@@ -44,7 +44,7 @@ async function run(client: OpencodeClient, state: State): Promise<void> {
|
|
|
44
44
|
if (sessions.length === 0) {
|
|
45
45
|
console.log("No sessions found. Creating a new session...");
|
|
46
46
|
state.sessionID = await createSession(client);
|
|
47
|
-
config.
|
|
47
|
+
config.sessionIDs[process.cwd()] = state.sessionID;
|
|
48
48
|
saveConfig();
|
|
49
49
|
console.log(`Created new session: ${state.sessionID}...\n`);
|
|
50
50
|
await updateSessionTitle();
|
|
@@ -135,7 +135,7 @@ async function handleKey(_client: OpencodeClient, key: Key, str?: string) {
|
|
|
135
135
|
readline.cursorTo(process.stdout, 0);
|
|
136
136
|
readline.clearScreenDown(process.stdout);
|
|
137
137
|
if (selected) {
|
|
138
|
-
config.
|
|
138
|
+
config.sessionIDs[process.cwd()] = selected.id;
|
|
139
139
|
saveConfig();
|
|
140
140
|
console.log(`Switched to session: ${selected.id.substring(0, 8)}...`);
|
|
141
141
|
if (selected.title) {
|
|
@@ -222,7 +222,7 @@ function renderSessionList(): void {
|
|
|
222
222
|
const globalIndex = sessionList.indexOf(session);
|
|
223
223
|
const filteredIndex = sessionFilteredIndices.indexOf(globalIndex);
|
|
224
224
|
const isSelected = filteredIndex === selectedSessionIndex;
|
|
225
|
-
const isActive = session.id === config.
|
|
225
|
+
const isActive = session.id === config.sessionIDs[process.cwd()];
|
|
226
226
|
const prefix = isSelected ? " >" : " -";
|
|
227
227
|
const title = session.title || "(no title)";
|
|
228
228
|
const name = isSelected ? `\x1b[33;1m${title}\x1b[0m` : title;
|
|
@@ -250,7 +250,7 @@ function updateSessionFilter(): void {
|
|
|
250
250
|
}
|
|
251
251
|
if (sessionFilteredIndices.length > 0) {
|
|
252
252
|
selectedSessionIndex = sessionFilteredIndices.indexOf(
|
|
253
|
-
sessionList.findIndex((s) => s.id === config.
|
|
253
|
+
sessionList.findIndex((s) => s.id === config.sessionIDs[process.cwd()]),
|
|
254
254
|
);
|
|
255
255
|
if (selectedSessionIndex === -1) selectedSessionIndex = 0;
|
|
256
256
|
}
|
package/src/commands/undo.ts
CHANGED
|
@@ -13,12 +13,13 @@ let command: Command = {
|
|
|
13
13
|
export default command;
|
|
14
14
|
|
|
15
15
|
async function run(client: OpencodeClient, _state: State): Promise<void> {
|
|
16
|
-
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
if (!config.sessionIDs[cwd]) return;
|
|
17
18
|
|
|
18
19
|
console.log("Fetching session messages...");
|
|
19
20
|
|
|
20
21
|
const messagesRes = await client.session.messages({
|
|
21
|
-
path: { id: config.
|
|
22
|
+
path: { id: config.sessionIDs[cwd] },
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
if (messagesRes.error) {
|
|
@@ -49,7 +50,7 @@ async function run(client: OpencodeClient, _state: State): Promise<void> {
|
|
|
49
50
|
console.log(`Reverting last assistant message (${lastMessage.info.id})...`);
|
|
50
51
|
|
|
51
52
|
const revertRes = await client.session.revert({
|
|
52
|
-
path: { id: config.
|
|
53
|
+
path: { id: config.sessionIDs[process.cwd()] },
|
|
53
54
|
body: {
|
|
54
55
|
messageID: lastMessage.info.id,
|
|
55
56
|
},
|
package/src/config.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface Config {
|
|
|
5
5
|
providerID: string;
|
|
6
6
|
modelID: string;
|
|
7
7
|
agentID: string;
|
|
8
|
-
|
|
8
|
+
sessionIDs: Record<string, string>;
|
|
9
9
|
loggingEnabled: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -15,6 +15,7 @@ export const config: Config = {
|
|
|
15
15
|
providerID: "opencode",
|
|
16
16
|
modelID: "big-pickle",
|
|
17
17
|
agentID: "build",
|
|
18
|
+
sessionIDs: {},
|
|
18
19
|
loggingEnabled: false,
|
|
19
20
|
};
|
|
20
21
|
|