ur-agent 1.14.1 → 1.16.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.
@@ -4,22 +4,65 @@ UR reads configuration from CLI flags, environment variables, and project or use
4
4
 
5
5
  ## Model Provider
6
6
 
7
- UR runs models strictly through the local Ollama app. The request endpoint is fixed and cannot be reconfigured from UR:
7
+ UR runs models strictly through the local Ollama app. The default request endpoint is:
8
8
 
9
9
  ```text
10
10
  http://localhost:11434/api
11
11
  ```
12
12
 
13
- Any model exposed by that local Ollama app can be used, including local models and Ollama Cloud-backed models. UR does not call remote provider APIs directly and does not manage model API keys.
13
+ Any model exposed by that Ollama app can be used, including local models and Ollama Cloud-backed models. UR does not call remote provider APIs directly and does not manage model API keys.
14
14
 
15
- Model selection environment variables:
15
+ ### Reconfiguring the Ollama host
16
+
17
+ The endpoint can be changed from UR in three ways, in order of precedence:
18
+
19
+ 1. `--ollama-host <url>` CLI flag (session only)
20
+ 2. `OLLAMA_HOST` environment variable
21
+ 3. `ollama.host` in user settings (`~/.ur/settings.json`)
22
+
23
+ Examples:
24
+
25
+ ```sh
26
+ # Session-only
27
+ ur --ollama-host http://192.168.1.50:11434
28
+
29
+ # Via environment
30
+ OLLAMA_HOST=http://192.168.1.50:11434 ur
31
+
32
+ # Persistent setting
33
+ ur --settings '{"ollama":{"host":"http://192.168.1.50:11434"}}'
34
+ ```
35
+
36
+ Model selection environment variables still work the same way:
16
37
 
17
38
  ```sh
18
39
  OLLAMA_MODEL=qwen3-coder:480b-cloud
19
40
  UR_MODEL=qwen3-coder:480b-cloud
20
41
  ```
21
42
 
22
- `OLLAMA_MODEL` selects the model name and takes precedence over `UR_MODEL`. If neither is set, UR lets its Ollama router choose from the model list advertised by the local Ollama app. If that discovery fails, the built-in fallback is `qwen3-coder:480b-cloud`. Neither variable can change the endpoint.
43
+ `OLLAMA_MODEL` selects the model name and takes precedence over `UR_MODEL`. If neither is set, UR lets its Ollama router choose from the model list advertised by the configured Ollama app. If that discovery fails, the built-in fallback is `qwen3-coder:480b-cloud`.
44
+
45
+ ### Discovering LAN Ollama servers
46
+
47
+ UR can scan your active local subnets for other Ollama servers and show a picker. This works for both wired Ethernet and wireless (Wi-Fi/WLAN) interfaces:
48
+
49
+ ```sh
50
+ ur --discover-ollama
51
+ ```
52
+
53
+ To make the picker appear on every startup, enable it in user settings:
54
+
55
+ ```json
56
+ {
57
+ "ollama": {
58
+ "lanDiscovery": true
59
+ }
60
+ }
61
+ ```
62
+
63
+ The scan is limited to active local IPv4 interfaces, ignores loopback/link-local
64
+ addresses, and uses bounded concurrency with short timeouts. It is opt-in and
65
+ never runs automatically unless enabled.
23
66
 
24
67
  ## CLI Flags
25
68
 
package/docs/USAGE.md CHANGED
@@ -64,7 +64,22 @@ ur --model qwen3-coder:480b-cloud
64
64
  ur --model qwen2.5-coder:latest
65
65
  ```
66
66
 
67
- UR talks only to the local Ollama app at the fixed endpoint `http://localhost:11434/api`. The endpoint cannot be changed from UR. Models exposed by that local app are valid, including Ollama Cloud-backed models. UR does not call provider APIs directly or manage model API keys.
67
+ UR talks to the local Ollama app at `http://localhost:11434/api` by default, but you can point it at another Ollama server on your LAN or in another location:
68
+
69
+ ```sh
70
+ # Discover and pick a LAN Ollama server at startup
71
+ ur --discover-ollama
72
+
73
+ # Point to a specific Ollama server for this session
74
+ ur --ollama-host http://192.168.1.50:11434
75
+
76
+ # Persistent setting
77
+ ur --settings '{"ollama":{"host":"http://192.168.1.50:11434"}}'
78
+ ```
79
+
80
+ Precedence: `--ollama-host` > `OLLAMA_HOST` env > `ollama.host` setting > `localhost:11434`.
81
+
82
+ Models exposed by the chosen Ollama app are valid, including local models and Ollama Cloud-backed models. UR does not call provider APIs directly or manage model API keys.
68
83
 
69
84
  ## Project Instructions
70
85
 
@@ -84,11 +99,16 @@ UR includes slash commands and CLI subcommands for common workflows:
84
99
  - `ur agents` to list configured agents
85
100
  - `ur agent-trends` to inspect coverage for current agent technology trends
86
101
  - `ur a2a card` to print UR's Agent Card metadata for A2A discovery
102
+ - `ur bg ...` to run detached local background agents with optional worktrees and PRs
103
+ - `ur code-index watch` to keep the local semantic code index fresh
104
+ - `ur memory retention ...` to prune project-local memory by TTL, max entries, and decay
87
105
  - `ur spec ...` to scaffold requirements, design, and tasks, then run a spec task list
88
106
  - `ur escalate ...` to plan, run, or ask an oracle model for hard tasks
89
107
  - `ur arena ...` to run multiple agents on the same task and select a winner
90
108
  - `ur ci-loop ...` to run tests, repair failures, and rerun with a bounded loop
91
109
  - `ur artifacts ...` to capture reviewable diffs, test runs, notes, and feedback
110
+ - `ur ide diff ...` to capture editor-readable inline diff bundles
111
+ - `ur eval bench ...` to import local SWE-bench, Terminal-Bench, or Aider Polyglot exports
92
112
  - `ur doctor` to inspect CLI health
93
113
  - `ur update` or `ur upgrade` to check for updates
94
114
 
@@ -106,6 +126,9 @@ ur arena "implement a debounce helper" --agents 2 --dry-run
106
126
  ur escalate run "refactor the cache layer" --force-oracle --dry-run
107
127
  ur ci-loop --command "bun test" --dry-run
108
128
  ur artifacts capture-diff
129
+ ur bg run "fix the flaky parser test" --worktree --dry-run
130
+ ur ide diff capture --title "Working tree review"
131
+ ur eval bench list
109
132
  ```
110
133
 
111
134
  ## Permissions
@@ -8,7 +8,8 @@ You need:
8
8
 
9
9
  - A running Ollama server (`ollama serve`) with at least one model available
10
10
  in the local Ollama app. Local models and Ollama Cloud-backed models both
11
- work because UR talks to the local app.
11
+ work because UR talks to the configured Ollama host.
12
+ - A second Ollama server on the LAN if you want to test network discovery.
12
13
  - UR installed globally (`npm install -g ur-agent`) or this repo installed
13
14
  globally (`bun add -g github:Maitham16/UR-mapek`) or a
14
15
  local checkout (`bun run dev`).
@@ -17,7 +18,25 @@ You need:
17
18
 
18
19
  ```sh
19
20
  ur --version
20
- # expected: 1.14.1 (Ur)
21
+ # expected: 1.16.0 (Ur)
22
+ ```
23
+
24
+ ## 0.1 Network Ollama discovery (1.16.0)
25
+
26
+ With at least one other Ollama server reachable on your LAN:
27
+
28
+ ```sh
29
+ ur --discover-ollama
30
+ ```
31
+
32
+ Expected: a picker appears listing `This computer` plus the LAN host(s). Select
33
+ the LAN host, then run a prompt and confirm traffic goes to the selected host.
34
+
35
+ Without a LAN host, you can still verify host configuration:
36
+
37
+ ```sh
38
+ ur --ollama-host http://localhost:11434 -p "say hi"
39
+ ur --settings '{"ollama":{"host":"http://localhost:11434"}}' -p "say hi"
21
40
  ```
22
41
 
23
42
  ## 1. Marketplace tree resolves
@@ -0,0 +1,23 @@
1
+ # UR Inline Diffs for VS Code
2
+
3
+ Native VS Code surface for UR inline diff bundles.
4
+
5
+ ## Workflow
6
+
7
+ Create a bundle from the UR CLI:
8
+
9
+ ```sh
10
+ ur ide diff capture --title "Parser fix"
11
+ ```
12
+
13
+ Open VS Code in the same workspace. The UR activity-bar view lists bundles from
14
+ `.ur/ide/diffs/manifest.json`.
15
+
16
+ Supported actions:
17
+
18
+ - refresh the bundle list
19
+ - open a patch preview with metadata and comments
20
+ - add a comment that writes back to the UR metadata and manifest
21
+
22
+ The extension is local-only. It reads and writes files under the current
23
+ workspace and does not call any model provider or network service.
@@ -0,0 +1,186 @@
1
+ const fs = require('node:fs')
2
+ const path = require('node:path')
3
+ const vscode = require('vscode')
4
+
5
+ function workspaceRoot() {
6
+ return vscode.workspace.workspaceFolders?.[0]?.uri.fsPath
7
+ }
8
+
9
+ function diffsRoot(root) {
10
+ return path.join(root, '.ur', 'ide', 'diffs')
11
+ }
12
+
13
+ function manifestPath(root) {
14
+ return path.join(diffsRoot(root), 'manifest.json')
15
+ }
16
+
17
+ function readJson(file, fallback) {
18
+ try {
19
+ return JSON.parse(fs.readFileSync(file, 'utf8'))
20
+ } catch {
21
+ return fallback
22
+ }
23
+ }
24
+
25
+ function writeJson(file, value) {
26
+ fs.mkdirSync(path.dirname(file), { recursive: true })
27
+ fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`)
28
+ }
29
+
30
+ function loadManifest(root) {
31
+ const manifest = readJson(manifestPath(root), { version: 1, diffs: [] })
32
+ return Array.isArray(manifest.diffs) ? manifest : { version: 1, diffs: [] }
33
+ }
34
+
35
+ function patchPath(root, bundle) {
36
+ return path.join(diffsRoot(root), bundle.patchFile)
37
+ }
38
+
39
+ function metadataPath(root, bundle) {
40
+ return path.join(diffsRoot(root), bundle.metadataFile)
41
+ }
42
+
43
+ function escapeHtml(text) {
44
+ return String(text)
45
+ .replace(/&/g, '&amp;')
46
+ .replace(/</g, '&lt;')
47
+ .replace(/>/g, '&gt;')
48
+ .replace(/"/g, '&quot;')
49
+ }
50
+
51
+ class DiffItem extends vscode.TreeItem {
52
+ constructor(bundle) {
53
+ super(`${bundle.id}: ${bundle.title}`, vscode.TreeItemCollapsibleState.None)
54
+ this.bundle = bundle
55
+ this.contextValue = 'diff'
56
+ this.description = `${bundle.status} · ${bundle.files?.length ?? 0} file(s)`
57
+ this.tooltip = `${bundle.title}\n${bundle.patchFile}`
58
+ this.command = {
59
+ command: 'urInlineDiffs.open',
60
+ title: 'Open Inline Diff',
61
+ arguments: [this],
62
+ }
63
+ }
64
+ }
65
+
66
+ class DiffProvider {
67
+ constructor() {
68
+ this._onDidChangeTreeData = new vscode.EventEmitter()
69
+ this.onDidChangeTreeData = this._onDidChangeTreeData.event
70
+ }
71
+
72
+ refresh() {
73
+ this._onDidChangeTreeData.fire()
74
+ }
75
+
76
+ getTreeItem(item) {
77
+ return item
78
+ }
79
+
80
+ getChildren() {
81
+ const root = workspaceRoot()
82
+ if (!root) return []
83
+ return loadManifest(root)
84
+ .diffs
85
+ .slice()
86
+ .sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)))
87
+ .map(bundle => new DiffItem(bundle))
88
+ }
89
+ }
90
+
91
+ function renderDiffHtml(root, bundle) {
92
+ const patch = fs.existsSync(patchPath(root, bundle))
93
+ ? fs.readFileSync(patchPath(root, bundle), 'utf8')
94
+ : ''
95
+ const comments = bundle.comments ?? []
96
+ return `<!doctype html>
97
+ <html lang="en">
98
+ <head>
99
+ <meta charset="utf-8">
100
+ <meta name="viewport" content="width=device-width, initial-scale=1">
101
+ <style>
102
+ body { font: 13px/1.45 var(--vscode-editor-font-family); color: var(--vscode-editor-foreground); padding: 16px; }
103
+ h1 { font-size: 18px; margin: 0 0 4px; }
104
+ .meta { color: var(--vscode-descriptionForeground); margin-bottom: 14px; }
105
+ pre { background: var(--vscode-editor-background); border: 1px solid var(--vscode-panel-border); padding: 12px; overflow: auto; }
106
+ .comments { margin-top: 18px; }
107
+ .comment { border-top: 1px solid var(--vscode-panel-border); padding: 8px 0; }
108
+ .where { color: var(--vscode-descriptionForeground); }
109
+ </style>
110
+ </head>
111
+ <body>
112
+ <h1>${escapeHtml(bundle.title)}</h1>
113
+ <div class="meta">${escapeHtml(bundle.id)} · ${escapeHtml(bundle.status)} · ${escapeHtml(bundle.files?.length ?? 0)} file(s)</div>
114
+ <pre>${escapeHtml(patch)}</pre>
115
+ <section class="comments">
116
+ <h2>Comments</h2>
117
+ ${comments.length === 0 ? '<p class="meta">No comments yet.</p>' : comments.map(comment => {
118
+ const where = comment.file ? `${comment.file}${comment.line ? `:${comment.line}` : ''}` : 'General'
119
+ return `<div class="comment"><div class="where">${escapeHtml(where)} · ${escapeHtml(comment.at ?? '')}</div><div>${escapeHtml(comment.text)}</div></div>`
120
+ }).join('')}
121
+ </section>
122
+ </body>
123
+ </html>`
124
+ }
125
+
126
+ async function openDiff(item) {
127
+ const root = workspaceRoot()
128
+ const bundle = item?.bundle
129
+ if (!root || !bundle) {
130
+ vscode.window.showWarningMessage('No UR inline diff selected.')
131
+ return
132
+ }
133
+ const panel = vscode.window.createWebviewPanel(
134
+ 'urInlineDiff',
135
+ `UR ${bundle.id}`,
136
+ vscode.ViewColumn.Active,
137
+ { enableScripts: false },
138
+ )
139
+ const latest = readJson(metadataPath(root, bundle), bundle)
140
+ panel.webview.html = renderDiffHtml(root, latest)
141
+ }
142
+
143
+ async function commentDiff(item, provider) {
144
+ const root = workspaceRoot()
145
+ const bundle = item?.bundle
146
+ if (!root || !bundle) {
147
+ vscode.window.showWarningMessage('No UR inline diff selected.')
148
+ return
149
+ }
150
+ const text = await vscode.window.showInputBox({
151
+ title: `Comment on ${bundle.id}`,
152
+ prompt: 'Comment text',
153
+ ignoreFocusOut: true,
154
+ })
155
+ if (!text?.trim()) return
156
+
157
+ const manifest = loadManifest(root)
158
+ const manifestBundle = manifest.diffs.find(diff => diff.id === bundle.id)
159
+ if (!manifestBundle) {
160
+ vscode.window.showErrorMessage(`UR inline diff not found: ${bundle.id}`)
161
+ return
162
+ }
163
+ const at = new Date().toISOString()
164
+ const comment = { at, text: text.trim() }
165
+ manifestBundle.status = 'commented'
166
+ manifestBundle.updatedAt = at
167
+ manifestBundle.comments = [...(manifestBundle.comments ?? []), comment]
168
+ writeJson(manifestPath(root), manifest)
169
+ writeJson(metadataPath(root, manifestBundle), manifestBundle)
170
+ provider.refresh()
171
+ vscode.window.showInformationMessage(`Added UR comment to ${bundle.id}.`)
172
+ }
173
+
174
+ function activate(context) {
175
+ const provider = new DiffProvider()
176
+ context.subscriptions.push(
177
+ vscode.window.registerTreeDataProvider('urInlineDiffs', provider),
178
+ vscode.commands.registerCommand('urInlineDiffs.refresh', () => provider.refresh()),
179
+ vscode.commands.registerCommand('urInlineDiffs.open', item => openDiff(item)),
180
+ vscode.commands.registerCommand('urInlineDiffs.comment', item => commentDiff(item, provider)),
181
+ )
182
+ }
183
+
184
+ function deactivate() {}
185
+
186
+ module.exports = { activate, deactivate }
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="UR">
2
+ <rect width="64" height="64" rx="12" fill="#161616"/>
3
+ <path d="M16 16v18c0 9 6 15 16 15s16-6 16-15V16h-8v18c0 5-3 8-8 8s-8-3-8-8V16h-8z" fill="#f5f5f5"/>
4
+ <path d="M36 16h12v8h-7v7h-5V16z" fill="#64d2ff"/>
5
+ </svg>
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "ur-inline-diffs",
3
+ "displayName": "UR Inline Diffs",
4
+ "description": "Review UR inline diff bundles from .ur/ide/diffs inside VS Code.",
5
+ "version": "1.16.0",
6
+ "publisher": "ur-agent",
7
+ "engines": {
8
+ "vscode": "^1.92.0"
9
+ },
10
+ "categories": [
11
+ "Other"
12
+ ],
13
+ "activationEvents": [
14
+ "onView:urInlineDiffs",
15
+ "onCommand:urInlineDiffs.refresh",
16
+ "onCommand:urInlineDiffs.open",
17
+ "onCommand:urInlineDiffs.comment"
18
+ ],
19
+ "main": "./extension.js",
20
+ "contributes": {
21
+ "viewsContainers": {
22
+ "activitybar": [
23
+ {
24
+ "id": "ur",
25
+ "title": "UR",
26
+ "icon": "media/ur.svg"
27
+ }
28
+ ]
29
+ },
30
+ "views": {
31
+ "ur": [
32
+ {
33
+ "id": "urInlineDiffs",
34
+ "name": "Inline Diffs"
35
+ }
36
+ ]
37
+ },
38
+ "commands": [
39
+ {
40
+ "command": "urInlineDiffs.refresh",
41
+ "title": "UR: Refresh Inline Diffs"
42
+ },
43
+ {
44
+ "command": "urInlineDiffs.open",
45
+ "title": "UR: Open Inline Diff"
46
+ },
47
+ {
48
+ "command": "urInlineDiffs.comment",
49
+ "title": "UR: Comment On Inline Diff"
50
+ }
51
+ ],
52
+ "menus": {
53
+ "view/title": [
54
+ {
55
+ "command": "urInlineDiffs.refresh",
56
+ "when": "view == urInlineDiffs",
57
+ "group": "navigation"
58
+ }
59
+ ],
60
+ "view/item/context": [
61
+ {
62
+ "command": "urInlineDiffs.open",
63
+ "when": "view == urInlineDiffs && viewItem == diff",
64
+ "group": "inline"
65
+ },
66
+ {
67
+ "command": "urInlineDiffs.comment",
68
+ "when": "view == urInlineDiffs && viewItem == diff",
69
+ "group": "inline"
70
+ }
71
+ ]
72
+ }
73
+ }
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ur-agent",
3
- "version": "1.14.1",
3
+ "version": "1.16.0",
4
4
  "description": "UR terminal coding agent CLI",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.14",
@@ -28,6 +28,7 @@
28
28
  "dist",
29
29
  "docs",
30
30
  "documentation",
31
+ "extensions",
31
32
  "examples",
32
33
  "CHANGELOG.md",
33
34
  "QUALITY.md",