ur-agent 1.34.0 → 1.35.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.
@@ -0,0 +1,45 @@
1
+ # Provider and model selection
2
+
3
+ Check what is connected, pick a provider, then pick a model scoped to it.
4
+
5
+ ```sh
6
+ ur provider list # all providers with access type and status
7
+ ur connect status # connection state for every provider
8
+ ur provider doctor # detailed checks for the selected provider
9
+ ```
10
+
11
+ Local (default, no account needed — requires a running Ollama app):
12
+
13
+ ```sh
14
+ ur config set provider ollama
15
+ ur --model qwen2.5-coder:latest
16
+ ```
17
+
18
+ API key (stored securely in the OS keychain):
19
+
20
+ ```sh
21
+ ur connect openai-api --key <KEY> # or: echo "$OPENAI_API_KEY" | ur connect openai-api
22
+ ur config set provider openai-api
23
+ ur config set model gpt-5.5
24
+ ```
25
+
26
+ Local OpenAI-compatible server (LM Studio, llama.cpp, vLLM):
27
+
28
+ ```sh
29
+ ur config set provider lmstudio
30
+ ur config set base_url http://localhost:1234/v1
31
+ ```
32
+
33
+ Subscription CLI (uses the vendor's official CLI and your subscription):
34
+
35
+ ```sh
36
+ ur auth chatgpt # official Codex CLI login
37
+ ur config set provider codex-cli
38
+ ```
39
+
40
+ Inside a session, `/model` gives the same flow interactively: provider first,
41
+ then only that provider's models. Verify the active pair any time:
42
+
43
+ ```sh
44
+ ur provider status
45
+ ```
@@ -52,13 +52,58 @@ function escapeHtml(text) {
52
52
  .replace(/"/g, '&quot;')
53
53
  }
54
54
 
55
+ function formatCount(count, singular, plural = `${singular}s`) {
56
+ return `${count} ${count === 1 ? singular : plural}`
57
+ }
58
+
59
+ function formatRelativeTime(value) {
60
+ if (!value) return 'unknown time'
61
+ const date = new Date(value)
62
+ if (Number.isNaN(date.getTime())) return String(value)
63
+ const deltaMs = Date.now() - date.getTime()
64
+ const minute = 60 * 1000
65
+ const hour = 60 * minute
66
+ const day = 24 * hour
67
+ if (deltaMs < minute) return 'just now'
68
+ if (deltaMs < hour) return `${Math.max(1, Math.floor(deltaMs / minute))}m ago`
69
+ if (deltaMs < day) return `${Math.floor(deltaMs / hour)}h ago`
70
+ if (deltaMs < 7 * day) return `${Math.floor(deltaMs / day)}d ago`
71
+ return date.toLocaleDateString()
72
+ }
73
+
74
+ function statusIcon(status) {
75
+ switch (status) {
76
+ case 'applied':
77
+ return new vscode.ThemeIcon('check', new vscode.ThemeColor('testing.iconPassed'))
78
+ case 'rejected':
79
+ return new vscode.ThemeIcon('circle-slash', new vscode.ThemeColor('testing.iconFailed'))
80
+ case 'commented':
81
+ return new vscode.ThemeIcon('comment-discussion', new vscode.ThemeColor('charts.yellow'))
82
+ default:
83
+ return new vscode.ThemeIcon('diff', new vscode.ThemeColor('charts.blue'))
84
+ }
85
+ }
86
+
55
87
  class DiffItem extends vscode.TreeItem {
56
88
  constructor(bundle) {
57
- super(`${bundle.id}: ${bundle.title}`, vscode.TreeItemCollapsibleState.None)
89
+ const title = bundle.title || bundle.id
90
+ super(title, vscode.TreeItemCollapsibleState.None)
58
91
  this.bundle = bundle
59
92
  this.contextValue = 'diff'
60
- this.description = `${bundle.status} · ${bundle.files?.length ?? 0} file(s)`
61
- this.tooltip = `${bundle.title}\n${bundle.patchFile}`
93
+ const fileCount = bundle.files?.length ?? 0
94
+ const changedAt = bundle.updatedAt ?? bundle.createdAt
95
+ this.description = `${bundle.status ?? 'captured'} · ${formatCount(fileCount, 'file')} · ${formatRelativeTime(changedAt)}`
96
+ this.iconPath = statusIcon(bundle.status)
97
+ this.tooltip = new vscode.MarkdownString(
98
+ [
99
+ `**${escapeHtml(title)}**`,
100
+ '',
101
+ `- ID: \`${escapeHtml(bundle.id)}\``,
102
+ `- Status: ${escapeHtml(bundle.status ?? 'captured')}`,
103
+ `- Files: ${fileCount}`,
104
+ `- Patch: \`${escapeHtml(bundle.patchFile)}\``,
105
+ ].join('\n'),
106
+ )
62
107
  this.command = {
63
108
  command: 'urInlineDiffs.open',
64
109
  title: 'Open Inline Diff',
@@ -67,6 +112,27 @@ class DiffItem extends vscode.TreeItem {
67
112
  }
68
113
  }
69
114
 
115
+ class ActionItem extends vscode.TreeItem {
116
+ constructor(label, description, icon, command, tooltip) {
117
+ super(label, vscode.TreeItemCollapsibleState.None)
118
+ this.contextValue = 'urAction'
119
+ this.description = description
120
+ this.iconPath = new vscode.ThemeIcon(icon)
121
+ this.tooltip = tooltip ?? `${label}${description ? ` — ${description}` : ''}`
122
+ this.command = command
123
+ }
124
+ }
125
+
126
+ class InfoItem extends vscode.TreeItem {
127
+ constructor(label, description, icon = 'info') {
128
+ super(label, vscode.TreeItemCollapsibleState.None)
129
+ this.contextValue = 'urInfo'
130
+ this.description = description
131
+ this.iconPath = new vscode.ThemeIcon(icon)
132
+ this.tooltip = `${label}${description ? ` — ${description}` : ''}`
133
+ }
134
+ }
135
+
70
136
  class DiffProvider {
71
137
  constructor() {
72
138
  this._onDidChangeTreeData = new vscode.EventEmitter()
@@ -83,12 +149,41 @@ class DiffProvider {
83
149
 
84
150
  getChildren() {
85
151
  const root = workspaceRoot()
86
- if (!root) return []
87
- return loadManifest(root)
152
+ if (!root) {
153
+ return [
154
+ new InfoItem('Open a workspace folder', 'UR inline diffs are scoped to the active project', 'folder-opened'),
155
+ ]
156
+ }
157
+
158
+ const manifest = loadManifest(root)
159
+ const diffs = manifest
88
160
  .diffs
89
161
  .slice()
90
162
  .sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)))
91
- .map(bundle => new DiffItem(bundle))
163
+
164
+ if (diffs.length === 0) {
165
+ return [
166
+ new InfoItem(
167
+ 'Ready for inline review',
168
+ fs.existsSync(manifestPath(root)) ? 'No pending diff bundles' : 'No diff bundles captured yet',
169
+ 'pass',
170
+ ),
171
+ new ActionItem(
172
+ 'Show UR status',
173
+ 'Provider, model, plugins',
174
+ 'pulse',
175
+ { command: 'urInlineDiffs.status', title: 'Show UR Status' },
176
+ ),
177
+ new ActionItem(
178
+ 'Refresh',
179
+ path.relative(root, manifestPath(root)),
180
+ 'refresh',
181
+ { command: 'urInlineDiffs.refresh', title: 'Refresh Inline Diffs' },
182
+ ),
183
+ ]
184
+ }
185
+
186
+ return diffs.map(bundle => new DiffItem(bundle))
92
187
  }
93
188
  }
94
189
 
@@ -103,18 +198,29 @@ function renderDiffHtml(root, bundle) {
103
198
  <meta charset="utf-8">
104
199
  <meta name="viewport" content="width=device-width, initial-scale=1">
105
200
  <style>
106
- body { font: 13px/1.45 var(--vscode-editor-font-family); color: var(--vscode-editor-foreground); padding: 16px; }
107
- h1 { font-size: 18px; margin: 0 0 4px; }
108
- .meta { color: var(--vscode-descriptionForeground); margin-bottom: 14px; }
109
- pre { background: var(--vscode-editor-background); border: 1px solid var(--vscode-panel-border); padding: 12px; overflow: auto; }
201
+ :root { color-scheme: light dark; }
202
+ body { font: 13px/1.5 var(--vscode-font-family); color: var(--vscode-foreground); padding: 20px; margin: 0; }
203
+ header { border-bottom: 1px solid var(--vscode-panel-border); padding-bottom: 14px; margin-bottom: 16px; }
204
+ h1 { font-size: 20px; font-weight: 600; margin: 0 0 6px; }
205
+ h2 { font-size: 14px; margin: 20px 0 10px; }
206
+ .meta, .where { color: var(--vscode-descriptionForeground); }
207
+ .chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
208
+ .chip { border: 1px solid var(--vscode-panel-border); border-radius: 4px; padding: 3px 8px; background: var(--vscode-sideBar-background); }
209
+ pre { background: var(--vscode-editor-background); border: 1px solid var(--vscode-panel-border); border-radius: 6px; padding: 14px; overflow: auto; font-family: var(--vscode-editor-font-family); }
110
210
  .comments { margin-top: 18px; }
111
- .comment { border-top: 1px solid var(--vscode-panel-border); padding: 8px 0; }
112
- .where { color: var(--vscode-descriptionForeground); }
211
+ .comment { border: 1px solid var(--vscode-panel-border); border-radius: 6px; padding: 10px 12px; margin-bottom: 10px; background: var(--vscode-sideBar-background); }
113
212
  </style>
114
213
  </head>
115
214
  <body>
116
- <h1>${escapeHtml(bundle.title)}</h1>
117
- <div class="meta">${escapeHtml(bundle.id)} · ${escapeHtml(bundle.status)} · ${escapeHtml(bundle.files?.length ?? 0)} file(s)</div>
215
+ <header>
216
+ <h1>${escapeHtml(bundle.title)}</h1>
217
+ <div class="meta">${escapeHtml(bundle.id)} · ${escapeHtml(formatRelativeTime(bundle.updatedAt ?? bundle.createdAt))}</div>
218
+ <div class="chips">
219
+ <span class="chip">${escapeHtml(bundle.status ?? 'captured')}</span>
220
+ <span class="chip">${escapeHtml(formatCount(bundle.files?.length ?? 0, 'file'))}</span>
221
+ <span class="chip">${escapeHtml(formatCount(comments.length, 'comment'))}</span>
222
+ </div>
223
+ </header>
118
224
  <pre>${escapeHtml(patch)}</pre>
119
225
  <section class="comments">
120
226
  <h2>Comments</h2>
@@ -256,9 +362,13 @@ async function showStatus(channel) {
256
362
  function activate(context) {
257
363
  const provider = new DiffProvider()
258
364
  const channel = vscode.window.createOutputChannel('UR')
365
+ const tree = vscode.window.createTreeView('urInlineDiffs', {
366
+ treeDataProvider: provider,
367
+ showCollapseAll: false,
368
+ })
259
369
  context.subscriptions.push(
260
370
  channel,
261
- vscode.window.registerTreeDataProvider('urInlineDiffs', provider),
371
+ tree,
262
372
  vscode.commands.registerCommand('urInlineDiffs.refresh', () => provider.refresh()),
263
373
  vscode.commands.registerCommand('urInlineDiffs.open', item => openDiff(item)),
264
374
  vscode.commands.registerCommand('urInlineDiffs.comment', item => commentDiff(item, provider)),
@@ -2,7 +2,7 @@
2
2
  "name": "ur-inline-diffs",
3
3
  "displayName": "UR Inline Diffs",
4
4
  "description": "Review, apply, and reject UR inline diff bundles from .ur/ide/diffs inside VS Code.",
5
- "version": "1.30.6",
5
+ "version": "1.35.1",
6
6
  "publisher": "ur-agent",
7
7
  "engines": {
8
8
  "vscode": "^1.92.0"
@@ -41,27 +41,39 @@
41
41
  "commands": [
42
42
  {
43
43
  "command": "urInlineDiffs.refresh",
44
- "title": "UR: Refresh Inline Diffs"
44
+ "title": "UR: Refresh Inline Diffs",
45
+ "icon": "$(refresh)"
45
46
  },
46
47
  {
47
48
  "command": "urInlineDiffs.open",
48
- "title": "UR: Open Inline Diff"
49
+ "title": "UR: Open Inline Diff",
50
+ "icon": "$(diff)"
49
51
  },
50
52
  {
51
53
  "command": "urInlineDiffs.comment",
52
- "title": "UR: Comment On Inline Diff"
54
+ "title": "UR: Comment On Inline Diff",
55
+ "icon": "$(comment-discussion)"
53
56
  },
54
57
  {
55
58
  "command": "urInlineDiffs.apply",
56
- "title": "UR: Apply Inline Diff"
59
+ "title": "UR: Apply Inline Diff",
60
+ "icon": "$(check)"
57
61
  },
58
62
  {
59
63
  "command": "urInlineDiffs.reject",
60
- "title": "UR: Reject Inline Diff"
64
+ "title": "UR: Reject Inline Diff",
65
+ "icon": "$(circle-slash)"
61
66
  },
62
67
  {
63
68
  "command": "urInlineDiffs.status",
64
- "title": "UR: Show Status (provider, model, plugins)"
69
+ "title": "UR: Show Status (provider, model, plugins)",
70
+ "icon": "$(pulse)"
71
+ }
72
+ ],
73
+ "viewsWelcome": [
74
+ {
75
+ "view": "urInlineDiffs",
76
+ "contents": "UR inline diffs appear here when a review bundle is captured.\n[Show Status](command:urInlineDiffs.status) [Refresh](command:urInlineDiffs.refresh)"
65
77
  }
66
78
  ],
67
79
  "menus": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ur-agent",
3
- "version": "1.34.0",
3
+ "version": "1.35.1",
4
4
  "description": "UR-AGENT — autonomous engineering workflow engine (plan, execute, test, verify, document, benchmark, reproduce)",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.14",
@@ -1,129 +0,0 @@
1
- # UR-AGENT 1.15.0 Upgrade Notes
2
-
3
- UR 1.15.0 keeps the agent local-first and Ollama-centered. The new agent
4
- platform surfaces do not add Anthropic, OpenAI, or other direct provider API
5
- dependencies. Network-facing behavior remains opt-in.
6
-
7
- ## New Local Agent Surfaces
8
-
9
- ### Background agents
10
-
11
- ```sh
12
- ur bg run "fix the flaky parser test" --worktree
13
- ur bg fanout "try three parser fixes" --agents 3 --worktree
14
- ur bg list
15
- ur bg status <id>
16
- ur bg logs <id> --tail 100
17
- ur bg attach <id>
18
- ur bg kill <id>
19
- ```
20
-
21
- State is stored under `.ur/background/`. Worktrees are stored under
22
- `.ur/worktrees/`. Pull requests are created only when `--pr` is passed and then
23
- use the existing local `gh` CLI path.
24
-
25
- ### Context and memory retention
26
-
27
- ```sh
28
- ur config set compaction.autoThreshold 80
29
- ur memory retention show
30
- ur memory retention set --ttl-days 90 --max-entries 5000 --decay-days 30
31
- ur memory retention prune
32
- ```
33
-
34
- `compaction.autoThreshold` is a global percentage threshold from 50 to 95. The
35
- retention command prunes project-local `.ur/memory/*.jsonl` files.
36
-
37
- ### Code-index watcher
38
-
39
- ```sh
40
- ur config set codeIndex.autoReindex true
41
- ur code-index watch --graph
42
- ur code-index watch --dry-run --json
43
- ```
44
-
45
- The watcher uses local filesystem events and the same local Ollama embedding
46
- path as `ur code-index build`.
47
-
48
- ### Artifact steering
49
-
50
- ```sh
51
- ur artifacts add --kind plan --title "Plan" --task <bg_id>
52
- ur artifacts comment <artifact_id> --feedback "Prefer the simpler parser path"
53
- ```
54
-
55
- Comments are written to the artifact and to the linked background task inbox so
56
- long-running work has durable steering feedback. Background workers now run in
57
- stream-json mode and inject new inbox comments into the child agent as
58
- `priority: "now"` user turns while the process is active.
59
-
60
- ### A2A task server
61
-
62
- ```sh
63
- ur a2a card
64
- ur a2a serve --host 127.0.0.1 --port 8765 --token "$UR_A2A_TOKEN"
65
- ur a2a token mint --secret "$UR_A2A_DELEGATION_SECRET" --scope coding-agent
66
- ```
67
-
68
- The server is opt-in. It refuses off-loopback binds unless a static bearer token
69
- or delegation secret is configured. Task execution is backed by UR background
70
- tasks and local `ur -p`; no external model provider API is introduced.
71
-
72
- Useful routes:
73
-
74
- - `GET /healthz`
75
- - `GET /.well-known/agent-card.json`
76
- - `POST /a2a/tasks`
77
- - `GET /a2a/tasks`
78
- - `GET /a2a/tasks/:id`
79
- - `GET /a2a/tasks/:id/output`
80
- - `POST /a2a/tasks/:id/cancel`
81
- - `DELETE /a2a/tasks/:id`
82
-
83
- ### IDE inline diff bundles
84
-
85
- ```sh
86
- ur ide diff capture --title "Parser fix"
87
- ur ide diff list
88
- ur ide diff show diff-1
89
- ur ide diff comment diff-1 --feedback "Inline note" --file src/parser.ts --line 42
90
- ur ide diff schema
91
- ```
92
-
93
- Bundles are stored under `.ur/ide/diffs/` as a manifest, per-diff metadata, and
94
- unified patch files. The repo also ships a native VS Code extension at
95
- `extensions/vscode-ur-inline-diffs/` that lists bundles, opens patch previews,
96
- and writes comments back into the UR metadata.
97
-
98
- ### Benchmark adapters
99
-
100
- ```sh
101
- ur eval bench list
102
- ur eval bench swe-bench --file swe.jsonl --name local-swe
103
- ur eval bench terminal-bench --file terminal.jsonl --name local-terminal
104
- ur eval bench aider-polyglot --file aider.jsonl --name local-polyglot
105
- ur eval run local-swe --dry-run
106
- ```
107
-
108
- Adapters import local JSON or JSONL exports into UR eval suites. They do not
109
- download datasets or call external services.
110
-
111
- ## Release Verification
112
-
113
- Run these before publishing:
114
-
115
- ```sh
116
- bun test test/agentFeatureCommands.test.ts test/agentDelegation.test.ts test/codeIndex.test.ts
117
- bun run typecheck
118
- npm pack --dry-run
119
- ```
120
-
121
- Optional local smoke checks:
122
-
123
- ```sh
124
- bun src/entrypoints/cli.tsx bg list
125
- bun src/entrypoints/cli.tsx memory retention show
126
- bun src/entrypoints/cli.tsx code-index watch --dry-run
127
- bun src/entrypoints/cli.tsx eval bench list
128
- bun src/entrypoints/cli.tsx ide diff schema
129
- ```
@@ -1,102 +0,0 @@
1
- # UR-AGENT 1.16.0 Upgrade Notes
2
-
3
- UR 1.16.0 adds local-network Ollama discovery. The agent can now find Ollama
4
- servers on your LAN, let you pick one at startup, and remember the choice for
5
- future sessions. The endpoint is no longer hardcoded to `localhost:11434`; it
6
- can be set via settings, environment, or a CLI flag.
7
-
8
- ## Network Ollama Discovery
9
-
10
- ### One-time discovery at startup
11
-
12
- ```sh
13
- ur --discover-ollama
14
- ```
15
-
16
- UR scans the active local subnets (wired Ethernet and Wi-Fi/WLAN) for hosts
17
- listening on port `11434`, verifies each one by fetching `/api/tags`, then shows
18
- a picker with:
19
-
20
- - `This computer` — your local `ollama serve` at `http://localhost:11434`
21
- - every discovered LAN host and the number of models it advertises
22
-
23
- Select a host and UR uses it for that session only. The choice is **not**
24
- persisted, so plain `ur` continues to use `localhost:11434`.
25
-
26
- ### Enable discovery on every startup
27
-
28
- Add to `~/.ur/settings.json`:
29
-
30
- ```json
31
- {
32
- "ollama": {
33
- "lanDiscovery": true
34
- }
35
- }
36
- ```
37
-
38
- The picker appears on every startup. The choice is still session-only and is
39
- not written to settings.
40
-
41
- ### Point to a specific host without scanning
42
-
43
- ```sh
44
- ur --ollama-host http://192.168.1.50:11434
45
- ```
46
-
47
- This is session-only and does not write settings. It takes precedence over
48
- settings and `OLLAMA_HOST`.
49
-
50
- ### Persistent host via settings
51
-
52
- ```json
53
- {
54
- "ollama": {
55
- "host": "http://192.168.1.50:11434"
56
- }
57
- }
58
- ```
59
-
60
- When `ollama.host` is set, UR uses it automatically. Precedence is:
61
-
62
- 1. `--ollama-host <url>` CLI flag
63
- 2. `OLLAMA_HOST` environment variable
64
- 3. `ollama.host` in user settings
65
- 4. fallback `http://localhost:11434`
66
-
67
- ## What Uses the Chosen Host
68
-
69
- The resolved host is used everywhere UR talks to Ollama:
70
-
71
- - interactive chat requests (`/api/chat`)
72
- - installed-model listing (`/api/tags`)
73
- - model metadata refresh (`/api/show`)
74
- - local embeddings (`/api/embed`)
75
- - `ur model-doctor`
76
- - `ur doctor` / `ur sysinfo`
77
- - startup preflight connectivity check
78
-
79
- ## Security Notes
80
-
81
- LAN scanning is opt-in only. It never runs automatically unless you pass
82
- `--discover-ollama` or set `ollama.lanDiscovery: true`. The scan is limited to
83
- active local IPv4 interfaces and ignores loopback and link-local addresses. It
84
- uses bounded concurrency and short timeouts so it finishes in a few seconds on a
85
- /24 subnet.
86
-
87
- ## Release Verification
88
-
89
- Run these before publishing:
90
-
91
- ```sh
92
- bun test test/ollamaDiscovery.test.ts test/ollamaModels.test.ts test/ollamaTimeout.test.ts
93
- bun run typecheck
94
- npm pack --dry-run
95
- ```
96
-
97
- Optional local smoke checks:
98
-
99
- ```sh
100
- bun src/entrypoints/cli.tsx --discover-ollama --help
101
- bun src/entrypoints/cli.tsx --ollama-host http://localhost:11434 -p "hello"
102
- ```
@@ -1,32 +0,0 @@
1
- # UR-AGENT 1.17.0 Upgrade Notes
2
-
3
- UR 1.17.0 adds the P0 reliable repo editing surface.
4
-
5
- ## Reliable Repo Editing
6
-
7
- ```sh
8
- ur repo-edit index
9
- ur repo-edit search checkoutTotal
10
- ur repo-edit plan rename oldName --to newName
11
- ur repo-edit preview rename oldName --to newName
12
- ur repo-edit apply rename oldName --to newName --check "bun test"
13
- ```
14
-
15
- `repo-edit` is designed for safer repository-wide code changes:
16
-
17
- - Builds `.ur/repo-edit/index.json` with file metadata, tokens, and
18
- JavaScript/TypeScript symbols.
19
- - Searches paths, indexed tokens, content lines, and symbols.
20
- - Plans JavaScript/TypeScript identifier renames from AST nodes instead of
21
- replacing arbitrary text.
22
- - Prints a unified patch preview before writing.
23
- - Applies all files transactionally and rolls back touched files if syntax
24
- validation or an optional check command fails.
25
-
26
- ## Validation
27
-
28
- ```sh
29
- bun test test/repoEdit.test.ts
30
- bun run typecheck
31
- node ./bin/ur.js repo-edit --help
32
- ```
@@ -1,45 +0,0 @@
1
- # UR-AGENT 1.18.0 Upgrade Notes
2
-
3
- UR 1.18.0 adds the P0 test-first execution loop.
4
-
5
- ## New Command
6
-
7
- ```sh
8
- ur test-first detect
9
- ur test-first --dry-run
10
- ur test-first --max-attempts 3
11
- ur test-first install
12
- ```
13
-
14
- `test-first` is designed for command-evidence-driven repo work:
15
-
16
- - Detects project languages, package managers, and quality commands from the
17
- existing project files.
18
- - Orders detected commands as compile, test, then lint.
19
- - Runs the command set and reports `passed` only when the commands exit 0.
20
- - On failure, stores a trace under `.ur/test-first/traces/` with the command,
21
- phase, exit code, stdout, and stderr.
22
- - Invokes a bounded fix agent between failed attempts.
23
- - Installs detected commands into `.ur/verify.json` with `ur test-first install`
24
- so the existing verifier can run them after future edits.
25
-
26
- Aliases:
27
-
28
- ```sh
29
- ur quality-loop --dry-run
30
- ur tf-loop detect
31
- ```
32
-
33
- ## Verification
34
-
35
- ```sh
36
- bun run typecheck
37
- bun run lint
38
- bun test test/testFirstLoop.test.ts
39
- node ./bin/ur.js test-first --help
40
- node ./bin/ur.js test-first detect
41
- ```
42
-
43
- If an external project has no lint script, `test-first` reports lint as a
44
- missing phase instead of inventing a command. UR itself now exposes
45
- `bun run lint`, so local quality detection includes compile, test, and lint.
@@ -1,41 +0,0 @@
1
- # UR-AGENT 1.19.0 Upgrade Notes
2
-
3
- UR 1.19.0 adds two P0 agent reliability surfaces: project safety policy and
4
- project context packing.
5
-
6
- ## What Changed
7
-
8
- - `ur safety status|init|check` evaluates shell command risk before execution.
9
- - Bash permission checks consult the project safety policy before broad allow
10
- rules and sandbox auto-allow.
11
- - The safety policy separates read, write, execute, and network permission
12
- classes.
13
- - Destructive commands require approval.
14
- - Write, execute, and network operations receive sandbox guidance.
15
- - Common secret-file and secret-like environment exfiltration paths are denied.
16
- - `ur context-pack scan|remember|compress` writes a manifest-backed repository
17
- architecture summary and durable task memory.
18
-
19
- ## New Project Files
20
-
21
- - `.ur/safety-policy.json` from `ur safety init`
22
- - `.ur/project-manifest.json` from `ur context-pack scan`
23
- - `.ur/context/architecture.md`
24
- - `.ur/context/task-memory.jsonl`
25
- - `.ur/context/compressed.md`
26
-
27
- Commit only shared policy and architecture files that are safe for teammates.
28
- Keep local task memory private when it contains local decisions, file paths, or
29
- operational notes that should not be shared.
30
-
31
- ## Validate
32
-
33
- ```sh
34
- ur safety status
35
- ur safety check --command "rm -rf build"
36
- ur context-pack scan
37
- ur context-pack remember --decision "Use manifest commands first"
38
- ur context-pack compress
39
- bun run typecheck
40
- bun test
41
- ```