ur-agent 1.35.0 → 1.36.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.
- package/CHANGELOG.md +9 -0
- package/README.md +26 -8
- package/bin/ur.js +31 -178
- package/dist/cli.js +2645 -983
- package/docs/CONFIGURATION.md +45 -0
- package/docs/TROUBLESHOOTING.md +16 -5
- package/docs/USAGE.md +8 -0
- package/docs/VALIDATION.md +3 -2
- package/docs/providers.md +74 -26
- package/documentation/index.html +2 -2
- package/extensions/vscode-ur-inline-diffs/extension.js +125 -15
- package/extensions/vscode-ur-inline-diffs/package.json +19 -7
- package/package.json +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.35.1
|
|
4
|
+
|
|
5
|
+
- Polished the bundled VS Code inline-diffs view with native toolbar icons,
|
|
6
|
+
useful empty-state rows, clearer diff labels, and a cleaner review webview.
|
|
7
|
+
- Fixed `ur ide status` routing so the IDE extension status action reports
|
|
8
|
+
provider/model/plugin status instead of printing inline-diff usage.
|
|
9
|
+
- Kept model/provider selections project-local by default and made transient
|
|
10
|
+
Ollama gateway timeouts retry cleanly.
|
|
11
|
+
|
|
3
12
|
## 1.35.0
|
|
4
13
|
|
|
5
14
|
- New `ur connect` CLI command (same implementation as the `/connect` slash
|
package/README.md
CHANGED
|
@@ -68,8 +68,14 @@ handing work off to other tools or agents when needed.
|
|
|
68
68
|
|
|
69
69
|
### Requirements
|
|
70
70
|
|
|
71
|
-
- Bun.
|
|
72
|
-
|
|
71
|
+
- Bun `>=1.3.0` (this repository pins `bun@1.3.14`). Bun is mandatory: every
|
|
72
|
+
install path — npm, GitHub, or source checkout — runs the CLI through Bun,
|
|
73
|
+
not Node. UR-AGENT is not Node-native.
|
|
74
|
+
- Node.js `>=18.18` only to start the npm-installed launcher script
|
|
75
|
+
(`bin/ur.js`), which immediately checks for Bun and re-execs into it. If Bun
|
|
76
|
+
is missing, the launcher errors out instead of falling back to Node.
|
|
77
|
+
- `sharp` installs automatically as a native runtime dependency (image
|
|
78
|
+
resizing for file reads, pasted images, and multimodal provider input).
|
|
73
79
|
- For the default local setup: a running Ollama app or server
|
|
74
80
|
(`http://localhost:11434/api`). Any other supported provider (API key,
|
|
75
81
|
OpenAI-compatible server, or subscription CLI) works without Ollama.
|
|
@@ -252,7 +258,10 @@ identity line in the system prompt reflects it too:
|
|
|
252
258
|
for LM Studio/llama.cpp/vLLM; the native API for Ollama).
|
|
253
259
|
- **Subscription CLIs** (Codex, Claude Code, Gemini, Antigravity) are external
|
|
254
260
|
app bridges: selecting one dispatches the turn through the vendor's official
|
|
255
|
-
CLI using your subscription. Log in with `ur auth <provider>`.
|
|
261
|
+
CLI using your subscription. Log in with `ur auth <provider>`. UR-native
|
|
262
|
+
tool calling, UR-native streaming, UR Bash/File tool execution, and sandbox
|
|
263
|
+
guarantees apply to UR-run tools and final UR output — not to what the
|
|
264
|
+
external CLI does internally (see Provider Guide below).
|
|
256
265
|
- **Subscription** access does not list fake models. If no independent
|
|
257
266
|
subscription backend is configured, `/model` marks it unavailable and asks you
|
|
258
267
|
to choose a connected local, server, or API provider.
|
|
@@ -502,9 +511,10 @@ settings, generated indexes, memory, logs, and secrets out of Git.
|
|
|
502
511
|
|
|
503
512
|
## Architecture
|
|
504
513
|
|
|
505
|
-
- `bin/ur.js` is the global launcher
|
|
506
|
-
|
|
507
|
-
|
|
514
|
+
- `bin/ur.js` is the global launcher, invoked via Node's shebang. It always
|
|
515
|
+
executes the CLI through Bun — `bun dist/cli.js` when the bundle is present,
|
|
516
|
+
otherwise `bun run` against the TypeScript entrypoint — and exits with an
|
|
517
|
+
install error if Bun is not found. Node never runs the CLI itself.
|
|
508
518
|
- `src/entrypoints/cli.tsx` handles fast startup paths such as `--version`,
|
|
509
519
|
A2A serving, background sessions, bridge mode, and daemon paths before loading
|
|
510
520
|
the full CLI.
|
|
@@ -546,8 +556,16 @@ the permission boundary matters.
|
|
|
546
556
|
scripts, instruction files, `.ur/verify.json`, and safety config.
|
|
547
557
|
- The deep verification subagent is available through `/verify` and can be
|
|
548
558
|
auto-enabled with `UR_VERIFIER_AUTO_SUBAGENT=1`.
|
|
549
|
-
-
|
|
550
|
-
|
|
559
|
+
- UR enforces permission and sandbox policy before running UR Bash/File
|
|
560
|
+
tools, not after. Sandbox mode is `disabled` (default), `recommended`
|
|
561
|
+
(`sandbox.enabled: true`, best-effort), or `required`
|
|
562
|
+
(`sandbox.enabled: true` + `sandbox.failIfUnavailable: true`) — `required`
|
|
563
|
+
fails closed and refuses to start if OS sandbox support is unavailable.
|
|
564
|
+
OS confinement uses `sandbox-exec` (Seatbelt) on macOS or `bwrap`
|
|
565
|
+
(bubblewrap) on Linux/WSL2; see `ur sandbox status`.
|
|
566
|
+
- This sandbox wraps UR-run Bash/File tool commands only. It does not extend
|
|
567
|
+
to actions a subscription CLI provider performs internally — see
|
|
568
|
+
[Provider Guide](docs/providers.md).
|
|
551
569
|
- MCP servers can access external services; only enable servers you trust.
|
|
552
570
|
|
|
553
571
|
See [Configuration](docs/CONFIGURATION.md), [Validation](docs/VALIDATION.md),
|
package/bin/ur.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from 'node:child_process'
|
|
2
|
+
import { spawn, spawnSync } from 'node:child_process'
|
|
3
3
|
import { existsSync, readFileSync } from 'node:fs'
|
|
4
|
-
import { createServer } from 'node:http'
|
|
5
4
|
import { dirname, resolve } from 'node:path'
|
|
6
5
|
import { fileURLToPath } from 'node:url'
|
|
7
6
|
|
|
@@ -39,186 +38,40 @@ const bun = process.env.BUN_BIN || process.env.BUN_EXECUTABLE || 'bun'
|
|
|
39
38
|
const ollamaModel =
|
|
40
39
|
process.env.OLLAMA_MODEL || process.env.UR_MODEL
|
|
41
40
|
const userArgs = process.argv.slice(2)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
const requiredBun = packageMetadata.engines?.bun ?? '>=1.3.0'
|
|
42
|
+
|
|
43
|
+
function printBunRuntimeError(detail) {
|
|
44
|
+
const attempted = bun
|
|
45
|
+
const source =
|
|
46
|
+
process.env.BUN_BIN
|
|
47
|
+
? 'BUN_BIN'
|
|
48
|
+
: process.env.BUN_EXECUTABLE
|
|
49
|
+
? 'BUN_EXECUTABLE'
|
|
50
|
+
: 'PATH'
|
|
51
|
+
console.error(
|
|
52
|
+
[
|
|
53
|
+
`UR-AGENT requires Bun ${requiredBun} at runtime because the published CLI bundle is built with --target bun.`,
|
|
54
|
+
`Could not execute "${attempted}" from ${source}.${detail ? ` ${detail}` : ''}`,
|
|
55
|
+
'Install Bun from https://bun.sh, or set BUN_BIN to the absolute path of a Bun executable.',
|
|
56
|
+
].join('\n'),
|
|
57
|
+
)
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
req.on('end', () => {
|
|
62
|
-
try {
|
|
63
|
-
resolve(JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}'))
|
|
64
|
-
} catch {
|
|
65
|
-
resolve(null)
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
req.on('error', () => resolve(null))
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function buildAgentCard(baseUrl) {
|
|
73
|
-
return {
|
|
74
|
-
protocolVersion: '0.3.0',
|
|
75
|
-
name: 'UR-AGENT',
|
|
76
|
-
description:
|
|
77
|
-
'Local-first terminal coding agent powered through the local Ollama app, with MCP tools, custom agents, browser workflows, memory, verifier gates, and permission controls.',
|
|
78
|
-
url: `${baseUrl}/a2a`,
|
|
79
|
-
version,
|
|
80
|
-
documentationUrl:
|
|
81
|
-
'https://github.com/Maitham16/UR/blob/master/docs/AGENT_TRENDS.md',
|
|
82
|
-
capabilities: {
|
|
83
|
-
streaming: true,
|
|
84
|
-
pushNotifications: false,
|
|
85
|
-
stateTransitionHistory: true,
|
|
86
|
-
},
|
|
87
|
-
defaultInputModes: ['text/plain', 'text/markdown', 'application/json'],
|
|
88
|
-
defaultOutputModes: ['text/plain', 'text/markdown', 'application/json'],
|
|
89
|
-
provider: {
|
|
90
|
-
organization: 'Maitham Al-rubaye',
|
|
91
|
-
url: 'https://github.com/Maitham16/UR',
|
|
92
|
-
},
|
|
93
|
-
skills: [
|
|
94
|
-
{
|
|
95
|
-
id: 'coding-agent',
|
|
96
|
-
name: 'Coding Agent',
|
|
97
|
-
description:
|
|
98
|
-
'Read, edit, test, verify, and explain code inside a local workspace with permission controls.',
|
|
99
|
-
tags: ['coding', 'terminal', 'verification'],
|
|
100
|
-
examples: [
|
|
101
|
-
'Fix this failing test and run the relevant checks.',
|
|
102
|
-
'Review the current diff for behavioral regressions.',
|
|
103
|
-
],
|
|
104
|
-
inputModes: ['text/plain', 'text/markdown'],
|
|
105
|
-
outputModes: ['text/plain', 'text/markdown'],
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function runAgentPrompt(prompt) {
|
|
112
|
-
const childArgs = existsSync(bundledEntrypoint)
|
|
113
|
-
? [bundledEntrypoint, '-p', '--output-format', 'json', prompt]
|
|
114
|
-
: [
|
|
115
|
-
'run',
|
|
116
|
-
'--preload',
|
|
117
|
-
preload,
|
|
118
|
-
'--define',
|
|
119
|
-
defineMacro('MACRO.VERSION', version),
|
|
120
|
-
'--define',
|
|
121
|
-
defineMacro('MACRO.BUILD_TIME', ''),
|
|
122
|
-
'--define',
|
|
123
|
-
defineMacro('MACRO.PACKAGE_URL', packageName),
|
|
124
|
-
'--define',
|
|
125
|
-
defineMacro('MACRO.NATIVE_PACKAGE_URL', undefined),
|
|
126
|
-
'--define',
|
|
127
|
-
defineMacro('MACRO.FEEDBACK_CHANNEL', issuesUrl),
|
|
128
|
-
'--define',
|
|
129
|
-
defineMacro('MACRO.ISSUES_EXPLAINER', `file an issue at ${issuesUrl}`),
|
|
130
|
-
'--define',
|
|
131
|
-
defineMacro('MACRO.VERSION_CHANGELOG', ''),
|
|
132
|
-
entrypoint,
|
|
133
|
-
'-p',
|
|
134
|
-
'--output-format',
|
|
135
|
-
'json',
|
|
136
|
-
prompt,
|
|
137
|
-
]
|
|
138
|
-
|
|
139
|
-
return new Promise(resolve => {
|
|
140
|
-
const child = spawn(bun, childArgs, {
|
|
141
|
-
cwd: process.cwd(),
|
|
142
|
-
env: {
|
|
143
|
-
...process.env,
|
|
144
|
-
...(ollamaModel ? { OLLAMA_MODEL: ollamaModel } : {}),
|
|
145
|
-
},
|
|
146
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
147
|
-
})
|
|
148
|
-
const stdout = []
|
|
149
|
-
const stderr = []
|
|
150
|
-
child.stdout.on('data', chunk => stdout.push(Buffer.from(chunk)))
|
|
151
|
-
child.stderr.on('data', chunk => stderr.push(Buffer.from(chunk)))
|
|
152
|
-
child.on('error', error => {
|
|
153
|
-
resolve({ code: 1, stdout: '', stderr: error.message })
|
|
154
|
-
})
|
|
155
|
-
child.on('exit', code => {
|
|
156
|
-
resolve({
|
|
157
|
-
code: code ?? 1,
|
|
158
|
-
stdout: Buffer.concat(stdout).toString('utf8'),
|
|
159
|
-
stderr: Buffer.concat(stderr).toString('utf8'),
|
|
160
|
-
})
|
|
161
|
-
})
|
|
60
|
+
function assertBunAvailable() {
|
|
61
|
+
const result = spawnSync(bun, ['--version'], {
|
|
62
|
+
encoding: 'utf8',
|
|
63
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
162
64
|
})
|
|
163
|
-
}
|
|
164
65
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const port = Number(argValue('--port', '8765'))
|
|
168
|
-
const token = argValue('--token')
|
|
169
|
-
const dryRun = userArgs.includes('--dry-run')
|
|
170
|
-
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
171
|
-
console.error(`Invalid --port value: ${argValue('--port')}`)
|
|
66
|
+
if (result.error) {
|
|
67
|
+
printBunRuntimeError(result.error.message)
|
|
172
68
|
process.exit(1)
|
|
173
69
|
}
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
70
|
+
if (result.status !== 0) {
|
|
71
|
+
const detail = (result.stderr || result.stdout || '').trim()
|
|
72
|
+
printBunRuntimeError(detail || `Exited with status ${result.status}.`)
|
|
73
|
+
process.exit(result.status ?? 1)
|
|
177
74
|
}
|
|
178
|
-
|
|
179
|
-
const baseUrl = `http://${host}:${port}`
|
|
180
|
-
const server = createServer(async (req, res) => {
|
|
181
|
-
const url = new URL(req.url ?? '/', baseUrl)
|
|
182
|
-
if (req.method === 'GET' && url.pathname === '/healthz') {
|
|
183
|
-
sendJson(res, 200, { ok: true })
|
|
184
|
-
return
|
|
185
|
-
}
|
|
186
|
-
if (
|
|
187
|
-
req.method === 'GET' &&
|
|
188
|
-
(url.pathname === '/.well-known/agent-card.json' ||
|
|
189
|
-
url.pathname === '/agent-card.json')
|
|
190
|
-
) {
|
|
191
|
-
sendJson(res, 200, buildAgentCard(baseUrl))
|
|
192
|
-
return
|
|
193
|
-
}
|
|
194
|
-
if (req.method === 'POST' && url.pathname === '/a2a/tasks') {
|
|
195
|
-
if (token && req.headers.authorization !== `Bearer ${token}`) {
|
|
196
|
-
sendJson(res, 401, { error: 'unauthorized' })
|
|
197
|
-
return
|
|
198
|
-
}
|
|
199
|
-
const body = await readJson(req)
|
|
200
|
-
const prompt =
|
|
201
|
-
body && typeof body.prompt === 'string' ? body.prompt.trim() : ''
|
|
202
|
-
if (!prompt) {
|
|
203
|
-
sendJson(res, 400, { error: 'missing prompt' })
|
|
204
|
-
return
|
|
205
|
-
}
|
|
206
|
-
const command = [bun, bundledEntrypoint, '-p', '--output-format', 'json', prompt]
|
|
207
|
-
if (dryRun) {
|
|
208
|
-
sendJson(res, 200, { dryRun: true, command })
|
|
209
|
-
return
|
|
210
|
-
}
|
|
211
|
-
const result = await runAgentPrompt(prompt)
|
|
212
|
-
sendJson(res, result.code === 0 ? 200 : 500, result)
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
sendJson(res, 404, { error: 'not found' })
|
|
216
|
-
})
|
|
217
|
-
server.listen(port, host, () => {
|
|
218
|
-
const actual = server.address()
|
|
219
|
-
const actualPort = actual && typeof actual === 'object' ? actual.port : port
|
|
220
|
-
console.log(`A2A server listening on http://${host}:${actualPort}`)
|
|
221
|
-
})
|
|
222
75
|
}
|
|
223
76
|
|
|
224
77
|
const args =
|
|
@@ -246,6 +99,8 @@ const args =
|
|
|
246
99
|
...userArgs,
|
|
247
100
|
]
|
|
248
101
|
|
|
102
|
+
assertBunAvailable()
|
|
103
|
+
|
|
249
104
|
const child = spawn(bun, args, {
|
|
250
105
|
cwd: process.cwd(),
|
|
251
106
|
env: {
|
|
@@ -257,9 +112,7 @@ const child = spawn(bun, args, {
|
|
|
257
112
|
|
|
258
113
|
child.on('error', error => {
|
|
259
114
|
if (error.code === 'ENOENT') {
|
|
260
|
-
|
|
261
|
-
'UR-AGENT requires Bun to run. Install Bun from https://bun.sh, then retry.',
|
|
262
|
-
)
|
|
115
|
+
printBunRuntimeError(error.message)
|
|
263
116
|
process.exit(1)
|
|
264
117
|
}
|
|
265
118
|
|