@link-assistant/agent 0.0.9 → 0.0.12
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/EXAMPLES.md +36 -0
- package/MODELS.md +72 -24
- package/README.md +59 -2
- package/TOOLS.md +20 -0
- package/package.json +35 -2
- package/src/agent/agent.ts +68 -54
- package/src/auth/claude-oauth.ts +426 -0
- package/src/auth/index.ts +28 -26
- package/src/auth/plugins.ts +876 -0
- package/src/bun/index.ts +53 -43
- package/src/bus/global.ts +5 -5
- package/src/bus/index.ts +59 -53
- package/src/cli/bootstrap.js +12 -12
- package/src/cli/bootstrap.ts +6 -6
- package/src/cli/cmd/agent.ts +97 -92
- package/src/cli/cmd/auth.ts +469 -0
- package/src/cli/cmd/cmd.ts +2 -2
- package/src/cli/cmd/export.ts +41 -41
- package/src/cli/cmd/mcp.ts +144 -119
- package/src/cli/cmd/models.ts +30 -29
- package/src/cli/cmd/run.ts +269 -213
- package/src/cli/cmd/stats.ts +185 -146
- package/src/cli/error.ts +17 -13
- package/src/cli/ui.ts +39 -24
- package/src/command/index.ts +26 -26
- package/src/config/config.ts +528 -288
- package/src/config/markdown.ts +15 -15
- package/src/file/ripgrep.ts +201 -169
- package/src/file/time.ts +21 -18
- package/src/file/watcher.ts +51 -42
- package/src/file.ts +1 -1
- package/src/flag/flag.ts +26 -11
- package/src/format/formatter.ts +206 -162
- package/src/format/index.ts +61 -61
- package/src/global/index.ts +21 -21
- package/src/id/id.ts +47 -33
- package/src/index.js +346 -199
- package/src/json-standard/index.ts +67 -51
- package/src/mcp/index.ts +135 -128
- package/src/patch/index.ts +336 -267
- package/src/project/bootstrap.ts +15 -15
- package/src/project/instance.ts +43 -36
- package/src/project/project.ts +47 -47
- package/src/project/state.ts +37 -33
- package/src/provider/models-macro.ts +5 -5
- package/src/provider/models.ts +32 -32
- package/src/provider/opencode.js +19 -19
- package/src/provider/provider.ts +518 -277
- package/src/provider/transform.ts +143 -102
- package/src/server/project.ts +21 -21
- package/src/server/server.ts +111 -105
- package/src/session/agent.js +66 -60
- package/src/session/compaction.ts +136 -111
- package/src/session/index.ts +189 -156
- package/src/session/message-v2.ts +312 -268
- package/src/session/message.ts +73 -57
- package/src/session/processor.ts +180 -166
- package/src/session/prompt.ts +678 -533
- package/src/session/retry.ts +26 -23
- package/src/session/revert.ts +76 -62
- package/src/session/status.ts +26 -26
- package/src/session/summary.ts +97 -76
- package/src/session/system.ts +77 -63
- package/src/session/todo.ts +22 -16
- package/src/snapshot/index.ts +92 -76
- package/src/storage/storage.ts +157 -120
- package/src/tool/bash.ts +116 -106
- package/src/tool/batch.ts +73 -59
- package/src/tool/codesearch.ts +60 -53
- package/src/tool/edit.ts +319 -263
- package/src/tool/glob.ts +32 -28
- package/src/tool/grep.ts +72 -53
- package/src/tool/invalid.ts +7 -7
- package/src/tool/ls.ts +77 -64
- package/src/tool/multiedit.ts +30 -21
- package/src/tool/patch.ts +121 -94
- package/src/tool/read.ts +140 -122
- package/src/tool/registry.ts +38 -38
- package/src/tool/task.ts +93 -60
- package/src/tool/todo.ts +16 -16
- package/src/tool/tool.ts +45 -36
- package/src/tool/webfetch.ts +97 -74
- package/src/tool/websearch.ts +78 -64
- package/src/tool/write.ts +21 -15
- package/src/util/binary.ts +27 -19
- package/src/util/context.ts +8 -8
- package/src/util/defer.ts +7 -5
- package/src/util/error.ts +24 -19
- package/src/util/eventloop.ts +16 -10
- package/src/util/filesystem.ts +37 -33
- package/src/util/fn.ts +11 -8
- package/src/util/iife.ts +1 -1
- package/src/util/keybind.ts +44 -44
- package/src/util/lazy.ts +7 -7
- package/src/util/locale.ts +20 -16
- package/src/util/lock.ts +43 -38
- package/src/util/log.ts +95 -85
- package/src/util/queue.ts +8 -8
- package/src/util/rpc.ts +35 -23
- package/src/util/scrap.ts +4 -4
- package/src/util/signal.ts +5 -5
- package/src/util/timeout.ts +6 -6
- package/src/util/token.ts +2 -2
- package/src/util/wildcard.ts +38 -27
package/src/cli/cmd/run.ts
CHANGED
|
@@ -1,359 +1,415 @@
|
|
|
1
|
-
import type { Argv } from
|
|
2
|
-
import path from
|
|
3
|
-
import { UI } from
|
|
4
|
-
import { cmd } from
|
|
5
|
-
import { Flag } from
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
1
|
+
import type { Argv } from 'yargs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { UI } from '../ui';
|
|
4
|
+
import { cmd } from './cmd';
|
|
5
|
+
import { Flag } from '../../flag/flag';
|
|
6
|
+
import { Log } from '../../util/log';
|
|
7
|
+
import { bootstrap } from '../bootstrap';
|
|
8
|
+
import { Command } from '../../command';
|
|
9
|
+
import { EOL } from 'os';
|
|
10
|
+
import { select } from '@clack/prompts';
|
|
11
|
+
import { createOpencodeClient, type OpencodeClient } from '@opencode-ai/sdk';
|
|
12
|
+
import { Provider } from '../../provider/provider';
|
|
12
13
|
|
|
13
14
|
const TOOL: Record<string, [string, string]> = {
|
|
14
|
-
todowrite: [
|
|
15
|
-
todoread: [
|
|
16
|
-
bash: [
|
|
17
|
-
edit: [
|
|
18
|
-
glob: [
|
|
19
|
-
grep: [
|
|
20
|
-
list: [
|
|
21
|
-
read: [
|
|
22
|
-
write: [
|
|
23
|
-
websearch: [
|
|
24
|
-
}
|
|
15
|
+
todowrite: ['Todo', UI.Style.TEXT_WARNING_BOLD],
|
|
16
|
+
todoread: ['Todo', UI.Style.TEXT_WARNING_BOLD],
|
|
17
|
+
bash: ['Bash', UI.Style.TEXT_DANGER_BOLD],
|
|
18
|
+
edit: ['Edit', UI.Style.TEXT_SUCCESS_BOLD],
|
|
19
|
+
glob: ['Glob', UI.Style.TEXT_INFO_BOLD],
|
|
20
|
+
grep: ['Grep', UI.Style.TEXT_INFO_BOLD],
|
|
21
|
+
list: ['List', UI.Style.TEXT_INFO_BOLD],
|
|
22
|
+
read: ['Read', UI.Style.TEXT_HIGHLIGHT_BOLD],
|
|
23
|
+
write: ['Write', UI.Style.TEXT_SUCCESS_BOLD],
|
|
24
|
+
websearch: ['Search', UI.Style.TEXT_DIM_BOLD],
|
|
25
|
+
};
|
|
25
26
|
|
|
26
27
|
export const RunCommand = cmd({
|
|
27
|
-
command:
|
|
28
|
-
describe:
|
|
28
|
+
command: 'run [message..]',
|
|
29
|
+
describe: 'run opencode with a message',
|
|
29
30
|
builder: (yargs: Argv) => {
|
|
30
31
|
return yargs
|
|
31
|
-
.positional(
|
|
32
|
-
describe:
|
|
33
|
-
type:
|
|
32
|
+
.positional('message', {
|
|
33
|
+
describe: 'message to send',
|
|
34
|
+
type: 'string',
|
|
34
35
|
array: true,
|
|
35
36
|
default: [],
|
|
36
37
|
})
|
|
37
|
-
.option(
|
|
38
|
-
describe:
|
|
39
|
-
type:
|
|
38
|
+
.option('command', {
|
|
39
|
+
describe: 'the command to run, use message for args',
|
|
40
|
+
type: 'string',
|
|
40
41
|
})
|
|
41
|
-
.option(
|
|
42
|
-
alias: [
|
|
43
|
-
describe:
|
|
44
|
-
type:
|
|
42
|
+
.option('continue', {
|
|
43
|
+
alias: ['c'],
|
|
44
|
+
describe: 'continue the last session',
|
|
45
|
+
type: 'boolean',
|
|
45
46
|
})
|
|
46
|
-
.option(
|
|
47
|
-
alias: [
|
|
48
|
-
describe:
|
|
49
|
-
type:
|
|
47
|
+
.option('session', {
|
|
48
|
+
alias: ['s'],
|
|
49
|
+
describe: 'session id to continue',
|
|
50
|
+
type: 'string',
|
|
50
51
|
})
|
|
51
|
-
.option(
|
|
52
|
-
type:
|
|
53
|
-
alias: [
|
|
54
|
-
describe:
|
|
52
|
+
.option('model', {
|
|
53
|
+
type: 'string',
|
|
54
|
+
alias: ['m'],
|
|
55
|
+
describe: 'model to use in the format of provider/model',
|
|
55
56
|
})
|
|
56
|
-
.option(
|
|
57
|
-
type:
|
|
58
|
-
describe:
|
|
57
|
+
.option('agent', {
|
|
58
|
+
type: 'string',
|
|
59
|
+
describe: 'agent to use',
|
|
59
60
|
})
|
|
60
|
-
.option(
|
|
61
|
-
type:
|
|
62
|
-
choices: [
|
|
63
|
-
default:
|
|
64
|
-
describe:
|
|
61
|
+
.option('format', {
|
|
62
|
+
type: 'string',
|
|
63
|
+
choices: ['default', 'json'],
|
|
64
|
+
default: 'default',
|
|
65
|
+
describe: 'format: default (formatted) or json (raw JSON events)',
|
|
65
66
|
})
|
|
66
|
-
.option(
|
|
67
|
-
alias: [
|
|
68
|
-
type:
|
|
67
|
+
.option('file', {
|
|
68
|
+
alias: ['f'],
|
|
69
|
+
type: 'string',
|
|
69
70
|
array: true,
|
|
70
|
-
describe:
|
|
71
|
+
describe: 'file(s) to attach to message',
|
|
71
72
|
})
|
|
72
|
-
.option(
|
|
73
|
-
type:
|
|
74
|
-
describe:
|
|
73
|
+
.option('title', {
|
|
74
|
+
type: 'string',
|
|
75
|
+
describe:
|
|
76
|
+
'title for the session (uses truncated prompt if no value provided)',
|
|
75
77
|
})
|
|
76
|
-
.option(
|
|
77
|
-
type:
|
|
78
|
-
describe:
|
|
78
|
+
.option('attach', {
|
|
79
|
+
type: 'string',
|
|
80
|
+
describe:
|
|
81
|
+
'attach to a running opencode server (e.g., http://localhost:4096)',
|
|
79
82
|
})
|
|
80
|
-
.option(
|
|
81
|
-
type:
|
|
82
|
-
describe:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
83
|
+
.option('port', {
|
|
84
|
+
type: 'number',
|
|
85
|
+
describe:
|
|
86
|
+
'port for the local server (defaults to random port if no value provided)',
|
|
87
|
+
})
|
|
88
|
+
.option('system-message', {
|
|
89
|
+
type: 'string',
|
|
90
|
+
describe: 'full override of the system message',
|
|
91
|
+
})
|
|
92
|
+
.option('system-message-file', {
|
|
93
|
+
type: 'string',
|
|
94
|
+
describe: 'full override of the system message from file',
|
|
95
|
+
})
|
|
96
|
+
.option('append-system-message', {
|
|
97
|
+
type: 'string',
|
|
98
|
+
describe: 'append to the default system message',
|
|
99
|
+
})
|
|
100
|
+
.option('append-system-message-file', {
|
|
101
|
+
type: 'string',
|
|
102
|
+
describe: 'append to the default system message from file',
|
|
103
|
+
})
|
|
104
|
+
.option('verbose', {
|
|
105
|
+
type: 'boolean',
|
|
106
|
+
describe:
|
|
107
|
+
'enable verbose mode to debug API requests (shows system prompt, token counts, etc.)',
|
|
108
|
+
default: false,
|
|
109
|
+
});
|
|
100
110
|
},
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
handler: async (args) => {
|
|
112
|
+
// Set verbose mode if requested
|
|
113
|
+
if (args.verbose) {
|
|
114
|
+
Flag.setVerbose(true);
|
|
115
|
+
await Log.init({ print: true, level: 'DEBUG' });
|
|
116
|
+
}
|
|
117
|
+
let message = args.message.join(' ');
|
|
103
118
|
|
|
104
|
-
const fileParts: any[] = []
|
|
119
|
+
const fileParts: any[] = [];
|
|
105
120
|
if (args.file) {
|
|
106
|
-
const files = Array.isArray(args.file) ? args.file : [args.file]
|
|
121
|
+
const files = Array.isArray(args.file) ? args.file : [args.file];
|
|
107
122
|
|
|
108
123
|
for (const filePath of files) {
|
|
109
|
-
const resolvedPath = path.resolve(process.cwd(), filePath)
|
|
110
|
-
const file = Bun.file(resolvedPath)
|
|
111
|
-
const stats = await file.stat().catch(() => {})
|
|
124
|
+
const resolvedPath = path.resolve(process.cwd(), filePath);
|
|
125
|
+
const file = Bun.file(resolvedPath);
|
|
126
|
+
const stats = await file.stat().catch(() => {});
|
|
112
127
|
if (!stats) {
|
|
113
|
-
UI.error(`File not found: ${filePath}`)
|
|
114
|
-
process.exit(1)
|
|
128
|
+
UI.error(`File not found: ${filePath}`);
|
|
129
|
+
process.exit(1);
|
|
115
130
|
}
|
|
116
131
|
if (!(await file.exists())) {
|
|
117
|
-
UI.error(`File not found: ${filePath}`)
|
|
118
|
-
process.exit(1)
|
|
132
|
+
UI.error(`File not found: ${filePath}`);
|
|
133
|
+
process.exit(1);
|
|
119
134
|
}
|
|
120
135
|
|
|
121
|
-
const stat = await file.stat()
|
|
122
|
-
const mime = stat.isDirectory()
|
|
136
|
+
const stat = await file.stat();
|
|
137
|
+
const mime = stat.isDirectory()
|
|
138
|
+
? 'application/x-directory'
|
|
139
|
+
: 'text/plain';
|
|
123
140
|
|
|
124
141
|
fileParts.push({
|
|
125
|
-
type:
|
|
142
|
+
type: 'file',
|
|
126
143
|
url: `file://${resolvedPath}`,
|
|
127
144
|
filename: path.basename(resolvedPath),
|
|
128
145
|
mime,
|
|
129
|
-
})
|
|
146
|
+
});
|
|
130
147
|
}
|
|
131
148
|
}
|
|
132
149
|
|
|
133
150
|
// Read system message files
|
|
134
|
-
if (args[
|
|
135
|
-
const resolvedPath = path.resolve(
|
|
136
|
-
|
|
151
|
+
if (args['system-message-file']) {
|
|
152
|
+
const resolvedPath = path.resolve(
|
|
153
|
+
process.cwd(),
|
|
154
|
+
args['system-message-file']
|
|
155
|
+
);
|
|
156
|
+
const file = Bun.file(resolvedPath);
|
|
137
157
|
if (!(await file.exists())) {
|
|
138
|
-
UI.error(
|
|
139
|
-
|
|
158
|
+
UI.error(
|
|
159
|
+
`System message file not found: ${args['system-message-file']}`
|
|
160
|
+
);
|
|
161
|
+
process.exit(1);
|
|
140
162
|
}
|
|
141
|
-
args[
|
|
163
|
+
args['system-message'] = await file.text();
|
|
142
164
|
}
|
|
143
165
|
|
|
144
|
-
if (args[
|
|
145
|
-
const resolvedPath = path.resolve(
|
|
146
|
-
|
|
166
|
+
if (args['append-system-message-file']) {
|
|
167
|
+
const resolvedPath = path.resolve(
|
|
168
|
+
process.cwd(),
|
|
169
|
+
args['append-system-message-file']
|
|
170
|
+
);
|
|
171
|
+
const file = Bun.file(resolvedPath);
|
|
147
172
|
if (!(await file.exists())) {
|
|
148
|
-
UI.error(
|
|
149
|
-
|
|
173
|
+
UI.error(
|
|
174
|
+
`Append system message file not found: ${args['append-system-message-file']}`
|
|
175
|
+
);
|
|
176
|
+
process.exit(1);
|
|
150
177
|
}
|
|
151
|
-
args[
|
|
178
|
+
args['append-system-message'] = await file.text();
|
|
152
179
|
}
|
|
153
180
|
|
|
154
|
-
if (!process.stdin.isTTY) message +=
|
|
181
|
+
if (!process.stdin.isTTY) message += '\n' + (await Bun.stdin.text());
|
|
155
182
|
|
|
156
183
|
if (message.trim().length === 0 && !args.command) {
|
|
157
|
-
UI.error(
|
|
158
|
-
process.exit(1)
|
|
184
|
+
UI.error('You must provide a message or a command');
|
|
185
|
+
process.exit(1);
|
|
159
186
|
}
|
|
160
187
|
|
|
161
188
|
const execute = async (sdk: OpencodeClient, sessionID: string) => {
|
|
162
189
|
const printEvent = (color: string, type: string, title: string) => {
|
|
163
190
|
UI.println(
|
|
164
191
|
color + `|`,
|
|
165
|
-
UI.Style.TEXT_NORMAL + UI.Style.TEXT_DIM + ` ${type.padEnd(7,
|
|
166
|
-
|
|
167
|
-
UI.Style.TEXT_NORMAL + title
|
|
168
|
-
)
|
|
169
|
-
}
|
|
192
|
+
UI.Style.TEXT_NORMAL + UI.Style.TEXT_DIM + ` ${type.padEnd(7, ' ')}`,
|
|
193
|
+
'',
|
|
194
|
+
UI.Style.TEXT_NORMAL + title
|
|
195
|
+
);
|
|
196
|
+
};
|
|
170
197
|
|
|
171
198
|
const outputJsonEvent = (type: string, data: any) => {
|
|
172
|
-
if (args.format ===
|
|
173
|
-
process.stdout.write(
|
|
174
|
-
|
|
199
|
+
if (args.format === 'json') {
|
|
200
|
+
process.stdout.write(
|
|
201
|
+
JSON.stringify({
|
|
202
|
+
type,
|
|
203
|
+
timestamp: Date.now(),
|
|
204
|
+
sessionID,
|
|
205
|
+
...data,
|
|
206
|
+
}) + EOL
|
|
207
|
+
);
|
|
208
|
+
return true;
|
|
175
209
|
}
|
|
176
|
-
return false
|
|
177
|
-
}
|
|
210
|
+
return false;
|
|
211
|
+
};
|
|
178
212
|
|
|
179
|
-
const events = await sdk.event.subscribe()
|
|
180
|
-
let errorMsg: string | undefined
|
|
213
|
+
const events = await sdk.event.subscribe();
|
|
214
|
+
let errorMsg: string | undefined;
|
|
181
215
|
|
|
182
216
|
const eventProcessor = (async () => {
|
|
183
217
|
for await (const event of events.stream) {
|
|
184
|
-
if (event.type ===
|
|
185
|
-
const part = event.properties.part
|
|
186
|
-
if (part.sessionID !== sessionID) continue
|
|
187
|
-
|
|
188
|
-
if (part.type ===
|
|
189
|
-
if (outputJsonEvent(
|
|
190
|
-
const [tool, color] = TOOL[part.tool] ?? [
|
|
218
|
+
if (event.type === 'message.part.updated') {
|
|
219
|
+
const part = event.properties.part;
|
|
220
|
+
if (part.sessionID !== sessionID) continue;
|
|
221
|
+
|
|
222
|
+
if (part.type === 'tool' && part.state.status === 'completed') {
|
|
223
|
+
if (outputJsonEvent('tool_use', { part })) continue;
|
|
224
|
+
const [tool, color] = TOOL[part.tool] ?? [
|
|
225
|
+
part.tool,
|
|
226
|
+
UI.Style.TEXT_INFO_BOLD,
|
|
227
|
+
];
|
|
191
228
|
const title =
|
|
192
229
|
part.state.title ||
|
|
193
|
-
(Object.keys(part.state.input).length > 0
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
230
|
+
(Object.keys(part.state.input).length > 0
|
|
231
|
+
? JSON.stringify(part.state.input)
|
|
232
|
+
: 'Unknown');
|
|
233
|
+
printEvent(color, tool, title);
|
|
234
|
+
if (part.tool === 'bash' && part.state.output?.trim()) {
|
|
235
|
+
UI.println();
|
|
236
|
+
UI.println(part.state.output);
|
|
198
237
|
}
|
|
199
238
|
}
|
|
200
239
|
|
|
201
|
-
if (part.type ===
|
|
202
|
-
if (outputJsonEvent(
|
|
240
|
+
if (part.type === 'step-start') {
|
|
241
|
+
if (outputJsonEvent('step_start', { part })) continue;
|
|
203
242
|
}
|
|
204
243
|
|
|
205
|
-
if (part.type ===
|
|
206
|
-
if (outputJsonEvent(
|
|
244
|
+
if (part.type === 'step-finish') {
|
|
245
|
+
if (outputJsonEvent('step_finish', { part })) continue;
|
|
207
246
|
}
|
|
208
247
|
|
|
209
|
-
if (part.type ===
|
|
210
|
-
if (outputJsonEvent(
|
|
211
|
-
const isPiped = !process.stdout.isTTY
|
|
212
|
-
if (!isPiped) UI.println()
|
|
213
|
-
process.stdout.write(
|
|
214
|
-
|
|
248
|
+
if (part.type === 'text' && part.time?.end) {
|
|
249
|
+
if (outputJsonEvent('text', { part })) continue;
|
|
250
|
+
const isPiped = !process.stdout.isTTY;
|
|
251
|
+
if (!isPiped) UI.println();
|
|
252
|
+
process.stdout.write(
|
|
253
|
+
(isPiped ? part.text : UI.markdown(part.text)) + EOL
|
|
254
|
+
);
|
|
255
|
+
if (!isPiped) UI.println();
|
|
215
256
|
}
|
|
216
257
|
}
|
|
217
258
|
|
|
218
|
-
if (event.type ===
|
|
219
|
-
const props = event.properties
|
|
220
|
-
if (props.sessionID !== sessionID || !props.error) continue
|
|
221
|
-
let err = String(props.error.name)
|
|
222
|
-
if (
|
|
223
|
-
|
|
259
|
+
if (event.type === 'session.error') {
|
|
260
|
+
const props = event.properties;
|
|
261
|
+
if (props.sessionID !== sessionID || !props.error) continue;
|
|
262
|
+
let err = String(props.error.name);
|
|
263
|
+
if (
|
|
264
|
+
'data' in props.error &&
|
|
265
|
+
props.error.data &&
|
|
266
|
+
'message' in props.error.data
|
|
267
|
+
) {
|
|
268
|
+
err = String(props.error.data.message);
|
|
224
269
|
}
|
|
225
|
-
errorMsg = errorMsg ? errorMsg + EOL + err : err
|
|
226
|
-
if (outputJsonEvent(
|
|
227
|
-
UI.error(err)
|
|
270
|
+
errorMsg = errorMsg ? errorMsg + EOL + err : err;
|
|
271
|
+
if (outputJsonEvent('error', { error: props.error })) continue;
|
|
272
|
+
UI.error(err);
|
|
228
273
|
}
|
|
229
274
|
|
|
230
|
-
if (
|
|
231
|
-
|
|
275
|
+
if (
|
|
276
|
+
event.type === 'session.idle' &&
|
|
277
|
+
event.properties.sessionID === sessionID
|
|
278
|
+
) {
|
|
279
|
+
break;
|
|
232
280
|
}
|
|
233
281
|
|
|
234
|
-
if (event.type ===
|
|
235
|
-
const permission = event.properties
|
|
236
|
-
if (permission.sessionID !== sessionID) continue
|
|
282
|
+
if (event.type === 'permission.updated') {
|
|
283
|
+
const permission = event.properties;
|
|
284
|
+
if (permission.sessionID !== sessionID) continue;
|
|
237
285
|
const result = await select({
|
|
238
286
|
message: `Permission required to run: ${permission.title}`,
|
|
239
287
|
options: [
|
|
240
|
-
{ value:
|
|
241
|
-
{ value:
|
|
242
|
-
{ value:
|
|
288
|
+
{ value: 'once', label: 'Allow once' },
|
|
289
|
+
{ value: 'always', label: 'Always allow' },
|
|
290
|
+
{ value: 'reject', label: 'Reject' },
|
|
243
291
|
],
|
|
244
|
-
initialValue:
|
|
245
|
-
}).catch(() =>
|
|
246
|
-
const response = (
|
|
292
|
+
initialValue: 'once',
|
|
293
|
+
}).catch(() => 'reject');
|
|
294
|
+
const response = (
|
|
295
|
+
result.toString().includes('cancel') ? 'reject' : result
|
|
296
|
+
) as 'once' | 'always' | 'reject';
|
|
247
297
|
await sdk.postSessionIdPermissionsPermissionId({
|
|
248
298
|
path: { id: sessionID, permissionID: permission.id },
|
|
249
299
|
body: { response },
|
|
250
|
-
})
|
|
300
|
+
});
|
|
251
301
|
}
|
|
252
302
|
}
|
|
253
|
-
})()
|
|
303
|
+
})();
|
|
254
304
|
|
|
255
305
|
if (args.command) {
|
|
256
306
|
await sdk.session.command({
|
|
257
307
|
path: { id: sessionID },
|
|
258
308
|
body: {
|
|
259
|
-
agent: args.agent ||
|
|
309
|
+
agent: args.agent || 'build',
|
|
260
310
|
model: args.model,
|
|
261
|
-
system: args[
|
|
262
|
-
appendSystem: args[
|
|
311
|
+
system: args['system-message'],
|
|
312
|
+
appendSystem: args['append-system-message'],
|
|
263
313
|
command: args.command,
|
|
264
314
|
arguments: message,
|
|
265
315
|
},
|
|
266
|
-
})
|
|
316
|
+
});
|
|
267
317
|
} else {
|
|
268
|
-
const modelParam = args.model
|
|
318
|
+
const modelParam = args.model
|
|
319
|
+
? Provider.parseModel(args.model)
|
|
320
|
+
: undefined;
|
|
269
321
|
await sdk.session.prompt({
|
|
270
322
|
path: { id: sessionID },
|
|
271
323
|
body: {
|
|
272
|
-
agent: args.agent ||
|
|
324
|
+
agent: args.agent || 'build',
|
|
273
325
|
model: modelParam,
|
|
274
|
-
system: args[
|
|
275
|
-
appendSystem: args[
|
|
276
|
-
parts: [...fileParts, { type:
|
|
326
|
+
system: args['system-message'],
|
|
327
|
+
appendSystem: args['append-system-message'],
|
|
328
|
+
parts: [...fileParts, { type: 'text', text: message }],
|
|
277
329
|
},
|
|
278
|
-
})
|
|
330
|
+
});
|
|
279
331
|
}
|
|
280
332
|
|
|
281
|
-
await eventProcessor
|
|
282
|
-
if (errorMsg) process.exit(1)
|
|
283
|
-
}
|
|
333
|
+
await eventProcessor;
|
|
334
|
+
if (errorMsg) process.exit(1);
|
|
335
|
+
};
|
|
284
336
|
|
|
285
337
|
if (args.attach) {
|
|
286
|
-
const sdk = createOpencodeClient({ baseUrl: args.attach })
|
|
338
|
+
const sdk = createOpencodeClient({ baseUrl: args.attach });
|
|
287
339
|
|
|
288
340
|
const sessionID = await (async () => {
|
|
289
341
|
if (args.continue) {
|
|
290
|
-
const result = await sdk.session.list()
|
|
291
|
-
return result.data?.find((s) => !s.parentID)?.id
|
|
342
|
+
const result = await sdk.session.list();
|
|
343
|
+
return result.data?.find((s) => !s.parentID)?.id;
|
|
292
344
|
}
|
|
293
|
-
if (args.session) return args.session
|
|
345
|
+
if (args.session) return args.session;
|
|
294
346
|
|
|
295
347
|
const title =
|
|
296
348
|
args.title !== undefined
|
|
297
|
-
? args.title ===
|
|
298
|
-
? message.slice(0, 50) + (message.length > 50 ?
|
|
349
|
+
? args.title === ''
|
|
350
|
+
? message.slice(0, 50) + (message.length > 50 ? '...' : '')
|
|
299
351
|
: args.title
|
|
300
|
-
: undefined
|
|
352
|
+
: undefined;
|
|
301
353
|
|
|
302
|
-
const result = await sdk.session.create({
|
|
303
|
-
|
|
304
|
-
|
|
354
|
+
const result = await sdk.session.create({
|
|
355
|
+
body: title ? { title } : {},
|
|
356
|
+
});
|
|
357
|
+
return result.data?.id;
|
|
358
|
+
})();
|
|
305
359
|
|
|
306
360
|
if (!sessionID) {
|
|
307
|
-
UI.error(
|
|
308
|
-
process.exit(1)
|
|
361
|
+
UI.error('Session not found');
|
|
362
|
+
process.exit(1);
|
|
309
363
|
}
|
|
310
364
|
|
|
311
365
|
// Share not supported - removed auto-share logic
|
|
312
366
|
|
|
313
|
-
return await execute(sdk, sessionID)
|
|
367
|
+
return await execute(sdk, sessionID);
|
|
314
368
|
}
|
|
315
369
|
|
|
316
370
|
await bootstrap(process.cwd(), async () => {
|
|
317
371
|
// Server not supported - this code path should not be reached
|
|
318
|
-
throw new Error(
|
|
372
|
+
throw new Error('Server mode not supported in agent-cli');
|
|
319
373
|
|
|
320
374
|
if (args.command) {
|
|
321
|
-
const exists = await Command.get(args.command)
|
|
375
|
+
const exists = await Command.get(args.command);
|
|
322
376
|
if (!exists) {
|
|
323
|
-
server.stop()
|
|
324
|
-
UI.error(`Command "${args.command}" not found`)
|
|
325
|
-
process.exit(1)
|
|
377
|
+
server.stop();
|
|
378
|
+
UI.error(`Command "${args.command}" not found`);
|
|
379
|
+
process.exit(1);
|
|
326
380
|
}
|
|
327
381
|
}
|
|
328
382
|
|
|
329
383
|
const sessionID = await (async () => {
|
|
330
384
|
if (args.continue) {
|
|
331
|
-
const result = await sdk.session.list()
|
|
332
|
-
return result.data?.find((s) => !s.parentID)?.id
|
|
385
|
+
const result = await sdk.session.list();
|
|
386
|
+
return result.data?.find((s) => !s.parentID)?.id;
|
|
333
387
|
}
|
|
334
|
-
if (args.session) return args.session
|
|
388
|
+
if (args.session) return args.session;
|
|
335
389
|
|
|
336
390
|
const title =
|
|
337
391
|
args.title !== undefined
|
|
338
|
-
? args.title ===
|
|
339
|
-
? message.slice(0, 50) + (message.length > 50 ?
|
|
392
|
+
? args.title === ''
|
|
393
|
+
? message.slice(0, 50) + (message.length > 50 ? '...' : '')
|
|
340
394
|
: args.title
|
|
341
|
-
: undefined
|
|
395
|
+
: undefined;
|
|
342
396
|
|
|
343
|
-
const result = await sdk.session.create({
|
|
344
|
-
|
|
345
|
-
|
|
397
|
+
const result = await sdk.session.create({
|
|
398
|
+
body: title ? { title } : {},
|
|
399
|
+
});
|
|
400
|
+
return result.data?.id;
|
|
401
|
+
})();
|
|
346
402
|
|
|
347
403
|
if (!sessionID) {
|
|
348
|
-
server.stop()
|
|
349
|
-
UI.error(
|
|
350
|
-
process.exit(1)
|
|
404
|
+
server.stop();
|
|
405
|
+
UI.error('Session not found');
|
|
406
|
+
process.exit(1);
|
|
351
407
|
}
|
|
352
408
|
|
|
353
409
|
// Share not supported - removed auto-share logic
|
|
354
410
|
|
|
355
|
-
await execute(sdk, sessionID)
|
|
356
|
-
server.stop()
|
|
357
|
-
})
|
|
411
|
+
await execute(sdk, sessionID);
|
|
412
|
+
server.stop();
|
|
413
|
+
});
|
|
358
414
|
},
|
|
359
|
-
})
|
|
415
|
+
});
|