ur-agent 1.12.2 → 1.12.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/CHANGELOG.md +28 -0
- package/README.md +2 -1
- package/bin/ur.js +192 -0
- package/dist/cli.js +45333 -43377
- package/docs/AGENT_FEATURES.md +56 -0
- package/docs/AGENT_TRENDS.md +11 -0
- package/docs/VALIDATION.md +1 -1
- package/examples/agent_features.md +48 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.12.3
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Agent feature expansion commands.** Added `ur agent-features`,
|
|
7
|
+
`ur agent-templates`, `ur automation`, `ur agent-task`, `ur model-doctor`,
|
|
8
|
+
`ur semantic-memory`, `ur claim-ledger`, and `ur browser-qa` so the agent
|
|
9
|
+
platform roadmap is visible and executable from both CLI and slash command
|
|
10
|
+
surfaces.
|
|
11
|
+
- **Opt-in A2A task server.** `ur a2a serve` now exposes loopback Agent Card,
|
|
12
|
+
health, and dry-run task endpoints from the launcher, with off-loopback binds
|
|
13
|
+
requiring a bearer token.
|
|
14
|
+
- **Project scaffolds and examples.** `ur agent-features init` creates reusable
|
|
15
|
+
project assets for agents, automations, GitHub workflow entrypoints, A2A,
|
|
16
|
+
memory, provenance, and browser QA, with `examples/agent_features.md`
|
|
17
|
+
documenting the workflow.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **Agent template typo safety.** `ur agent-templates install <name>` now
|
|
21
|
+
rejects unknown template names instead of interpreting a misspelling as
|
|
22
|
+
"install all templates."
|
|
23
|
+
- **Ollama model inspection request.** `ur model-doctor` now uses the preferred
|
|
24
|
+
`/api/show` request body key (`model`) when inspecting local Ollama models.
|
|
25
|
+
|
|
26
|
+
### Verified
|
|
27
|
+
- Added focused Bun tests for feature scaffolds, template installation,
|
|
28
|
+
automations, PR dry-run generation, local memory/provenance/browser QA
|
|
29
|
+
commands, and the model-doctor Ollama request body.
|
|
30
|
+
|
|
3
31
|
## 1.12.2
|
|
4
32
|
|
|
5
33
|
### Changed
|
package/README.md
CHANGED
|
@@ -104,9 +104,10 @@ ur plugin --help
|
|
|
104
104
|
- [Usage Guide](docs/USAGE.md)
|
|
105
105
|
- [Configuration](docs/CONFIGURATION.md)
|
|
106
106
|
- [Agent Trend Coverage](docs/AGENT_TRENDS.md)
|
|
107
|
+
- [Agent Feature Expansion](docs/AGENT_FEATURES.md)
|
|
107
108
|
- [Development Guide](docs/DEVELOPMENT.md)
|
|
108
109
|
|
|
109
|
-
The `examples/` directory also contains prompt examples for coding, research, browser, image, video, MCP, memory, and agent-
|
|
110
|
+
The `examples/` directory also contains prompt examples for coding, research, browser, image, video, MCP, memory, agent-trend, and agent-feature workflows.
|
|
110
111
|
|
|
111
112
|
## License And Responsibility
|
|
112
113
|
|
package/bin/ur.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from 'node:child_process'
|
|
3
3
|
import { existsSync, readFileSync } from 'node:fs'
|
|
4
|
+
import { createServer } from 'node:http'
|
|
4
5
|
import { dirname, resolve } from 'node:path'
|
|
5
6
|
import { fileURLToPath } from 'node:url'
|
|
6
7
|
|
|
@@ -38,6 +39,196 @@ const bun = process.env.BUN_BIN || process.env.BUN_EXECUTABLE || 'bun'
|
|
|
38
39
|
const ollamaModel =
|
|
39
40
|
process.env.OLLAMA_MODEL || process.env.UR_MODEL
|
|
40
41
|
const userArgs = process.argv.slice(2)
|
|
42
|
+
|
|
43
|
+
function argValue(flag, fallback) {
|
|
44
|
+
const index = userArgs.indexOf(flag)
|
|
45
|
+
return index === -1 ? fallback : (userArgs[index + 1] ?? fallback)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isLoopback(host) {
|
|
49
|
+
return host === '127.0.0.1' || host === 'localhost' || host === '::1'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function sendJson(res, status, body) {
|
|
53
|
+
res.writeHead(status, { 'content-type': 'application/json' })
|
|
54
|
+
res.end(JSON.stringify(body, null, 2))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function readJson(req) {
|
|
58
|
+
return new Promise(resolve => {
|
|
59
|
+
const chunks = []
|
|
60
|
+
req.on('data', chunk => chunks.push(Buffer.from(chunk)))
|
|
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-mapek/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-mapek',
|
|
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
|
+
})
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function runA2AServer() {
|
|
166
|
+
const host = argValue('--host', '127.0.0.1')
|
|
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')}`)
|
|
172
|
+
process.exit(1)
|
|
173
|
+
}
|
|
174
|
+
if (!isLoopback(host) && !token) {
|
|
175
|
+
console.error('Refusing to bind a2a server off-loopback without --token')
|
|
176
|
+
process.exit(1)
|
|
177
|
+
}
|
|
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
|
+
}
|
|
223
|
+
|
|
224
|
+
if (
|
|
225
|
+
userArgs[0] === 'a2a' &&
|
|
226
|
+
userArgs[1] === 'serve' &&
|
|
227
|
+
!userArgs.includes('--help') &&
|
|
228
|
+
!userArgs.includes('-h')
|
|
229
|
+
) {
|
|
230
|
+
runA2AServer()
|
|
231
|
+
} else {
|
|
41
232
|
const args =
|
|
42
233
|
existsSync(bundledEntrypoint)
|
|
43
234
|
? [bundledEntrypoint, ...userArgs]
|
|
@@ -92,3 +283,4 @@ child.on('exit', (code, signal) => {
|
|
|
92
283
|
|
|
93
284
|
process.exit(code ?? 1)
|
|
94
285
|
})
|
|
286
|
+
}
|