ur-agent 1.45.6 → 1.47.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 +69 -0
- package/QUALITY.md +8 -3
- package/README.md +67 -13
- package/RELEASE.md +9 -6
- package/dist/cli.js +73656 -36080
- package/docs/A2A.md +180 -0
- package/docs/ACP.md +69 -17
- package/docs/AGENT_FEATURES.md +64 -7
- package/docs/AGENT_TRENDS.md +91 -26
- package/docs/AG_UI.md +132 -0
- package/docs/CONFIGURATION.md +123 -3
- package/docs/DEVELOPMENT.md +1 -0
- package/docs/IDE.md +20 -17
- package/docs/TROUBLESHOOTING.md +5 -3
- package/docs/USAGE.md +34 -4
- package/docs/VALIDATION.md +31 -1
- package/docs/providers.md +15 -1
- package/documentation/app.js +18 -6
- package/documentation/index.html +27 -8
- package/examples/agent_features.md +18 -0
- package/examples/agent_trends.md +5 -0
- package/examples/mcp.md +4 -0
- package/examples/memory.md +5 -2
- package/extensions/jetbrains-ur/README.md +12 -5
- package/extensions/jetbrains-ur/build.gradle.kts +22 -6
- package/extensions/jetbrains-ur/gradle.properties +1 -0
- package/extensions/jetbrains-ur/settings.gradle.kts +4 -0
- package/extensions/jetbrains-ur/src/main/kotlin/dev/urnexus/SendSelectionAction.kt +39 -5
- package/extensions/jetbrains-ur/src/main/kotlin/dev/urnexus/UrAcpClient.kt +52 -20
- package/extensions/jetbrains-ur/src/main/kotlin/dev/urnexus/UrToolWindowFactory.kt +7 -4
- package/extensions/jetbrains-ur/src/main/resources/META-INF/plugin.xml +1 -1
- package/extensions/vscode-ur-inline-diffs/README.md +6 -2
- package/extensions/vscode-ur-inline-diffs/out/extension.js +328 -157
- package/extensions/vscode-ur-inline-diffs/package.json +33 -5
- package/package.json +70 -56
- package/plugins/core/engineering-discipline/skills/reproducible-release/SKILL.md +2 -1
- package/plugins/core/github/skills/github-workflow/SKILL.md +2 -1
- package/plugins/core/gitlab/skills/gitlab-workflow/SKILL.md +2 -1
- package/plugins/core/huggingface/skills/huggingface-workflow/SKILL.md +2 -1
- package/plugins/core/miro/skills/miro-workflow/SKILL.md +2 -1
- package/plugins/core/obsidian/skills/second-brain/SKILL.md +2 -1
- package/plugins/core/powerpoint/skills/deck-craft/SKILL.md +2 -1
- package/plugins/core/skill-forge/skills/skill-authoring/SKILL.md +2 -1
- package/plugins/core/word/skills/document-craft/SKILL.md +2 -1
|
@@ -37,33 +37,15 @@ module.exports = __toCommonJS(extension_exports);
|
|
|
37
37
|
var vscode17 = __toESM(require("vscode"));
|
|
38
38
|
|
|
39
39
|
// src/actions/actions.ts
|
|
40
|
-
var
|
|
41
|
-
async function openBackgroundLog(item) {
|
|
42
|
-
const logFile = item?.task.logFile;
|
|
43
|
-
if (!logFile) {
|
|
44
|
-
vscode.window.showWarningMessage("No log file for this background task.");
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
try {
|
|
48
|
-
const doc = await vscode.workspace.openTextDocument(vscode.Uri.file(logFile));
|
|
49
|
-
await vscode.window.showTextDocument(doc, { preview: true });
|
|
50
|
-
} catch (error) {
|
|
51
|
-
vscode.window.showErrorMessage(
|
|
52
|
-
`Could not open background task log: ${error instanceof Error ? error.message : String(error)}`
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// src/actions/actionsTreeProvider.ts
|
|
58
|
-
var vscode4 = __toESM(require("vscode"));
|
|
40
|
+
var vscode2 = __toESM(require("vscode"));
|
|
59
41
|
|
|
60
42
|
// src/diffs/store.ts
|
|
61
43
|
var fs = __toESM(require("node:fs"));
|
|
62
44
|
var path = __toESM(require("node:path"));
|
|
63
|
-
var
|
|
45
|
+
var vscode = __toESM(require("vscode"));
|
|
64
46
|
function workspaceRoot() {
|
|
65
|
-
const activeUri =
|
|
66
|
-
return (activeUri ?
|
|
47
|
+
const activeUri = vscode.window.activeTextEditor?.document.uri;
|
|
48
|
+
return (activeUri ? vscode.workspace.getWorkspaceFolder(activeUri) : void 0)?.uri.fsPath ?? vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
|
67
49
|
}
|
|
68
50
|
function diffsRoot(root) {
|
|
69
51
|
return path.join(root, ".ur", "ide", "diffs");
|
|
@@ -132,120 +114,6 @@ function writeBundleMetadata(root, bundle) {
|
|
|
132
114
|
writeJson(metadataPath(root, bundle), bundle);
|
|
133
115
|
}
|
|
134
116
|
|
|
135
|
-
// src/diffs/treeProvider.ts
|
|
136
|
-
var vscode3 = __toESM(require("vscode"));
|
|
137
|
-
|
|
138
|
-
// src/util/format.ts
|
|
139
|
-
function escapeHtml(text) {
|
|
140
|
-
return String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
141
|
-
}
|
|
142
|
-
function formatCount(count, singular, plural = `${singular}s`) {
|
|
143
|
-
return `${count} ${count === 1 ? singular : plural}`;
|
|
144
|
-
}
|
|
145
|
-
function formatRelativeTime(value) {
|
|
146
|
-
if (!value) return "unknown time";
|
|
147
|
-
const date = new Date(value);
|
|
148
|
-
if (Number.isNaN(date.getTime())) return String(value);
|
|
149
|
-
const deltaMs = Date.now() - date.getTime();
|
|
150
|
-
const minute = 60 * 1e3;
|
|
151
|
-
const hour = 60 * minute;
|
|
152
|
-
const day = 24 * hour;
|
|
153
|
-
if (deltaMs < minute) return "just now";
|
|
154
|
-
if (deltaMs < hour) return `${Math.max(1, Math.floor(deltaMs / minute))}m ago`;
|
|
155
|
-
if (deltaMs < day) return `${Math.floor(deltaMs / hour)}h ago`;
|
|
156
|
-
if (deltaMs < 7 * day) return `${Math.floor(deltaMs / day)}d ago`;
|
|
157
|
-
return date.toLocaleDateString();
|
|
158
|
-
}
|
|
159
|
-
function errorMessage(error) {
|
|
160
|
-
return error instanceof Error ? error.message : String(error);
|
|
161
|
-
}
|
|
162
|
-
function processErrorMessage(error) {
|
|
163
|
-
if (typeof error === "object" && error !== null && "stderr" in error) {
|
|
164
|
-
const stderr = error.stderr;
|
|
165
|
-
if (typeof stderr === "string" && stderr.trim()) return stderr.trim();
|
|
166
|
-
}
|
|
167
|
-
return errorMessage(error);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// src/diffs/treeProvider.ts
|
|
171
|
-
function statusIcon(status) {
|
|
172
|
-
switch (status) {
|
|
173
|
-
case "approved":
|
|
174
|
-
return new vscode3.ThemeIcon("check", new vscode3.ThemeColor("testing.iconPassed"));
|
|
175
|
-
case "rejected":
|
|
176
|
-
return new vscode3.ThemeIcon("circle-slash", new vscode3.ThemeColor("testing.iconFailed"));
|
|
177
|
-
case "commented":
|
|
178
|
-
return new vscode3.ThemeIcon("comment-discussion", new vscode3.ThemeColor("charts.yellow"));
|
|
179
|
-
default:
|
|
180
|
-
return new vscode3.ThemeIcon("diff", new vscode3.ThemeColor("charts.blue"));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
var DiffTreeItem = class extends vscode3.TreeItem {
|
|
184
|
-
bundle;
|
|
185
|
-
constructor(bundle) {
|
|
186
|
-
const title = bundle.title || bundle.id;
|
|
187
|
-
super(title, vscode3.TreeItemCollapsibleState.None);
|
|
188
|
-
this.bundle = bundle;
|
|
189
|
-
this.contextValue = "diff";
|
|
190
|
-
const fileCount = bundle.files?.length ?? 0;
|
|
191
|
-
const changedAt = bundle.updatedAt ?? bundle.createdAt;
|
|
192
|
-
this.description = `${bundle.status ?? "captured"} \xB7 ${formatCount(fileCount, "file")} \xB7 ${formatRelativeTime(changedAt)}`;
|
|
193
|
-
this.iconPath = statusIcon(bundle.status);
|
|
194
|
-
this.tooltip = new vscode3.MarkdownString(
|
|
195
|
-
[
|
|
196
|
-
`**${escapeHtml(title)}**`,
|
|
197
|
-
"",
|
|
198
|
-
`- ID: \`${escapeHtml(bundle.id)}\``,
|
|
199
|
-
`- Status: ${escapeHtml(bundle.status ?? "captured")}`,
|
|
200
|
-
`- Files: ${fileCount}`,
|
|
201
|
-
`- Patch: \`${escapeHtml(bundle.patchFile)}\``
|
|
202
|
-
].join("\n")
|
|
203
|
-
);
|
|
204
|
-
this.command = {
|
|
205
|
-
command: "urInlineDiffs.open",
|
|
206
|
-
title: "Open Inline Diff",
|
|
207
|
-
arguments: [this]
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
var InfoItem = class extends vscode3.TreeItem {
|
|
212
|
-
constructor(label, description, icon = "info") {
|
|
213
|
-
super(label, vscode3.TreeItemCollapsibleState.None);
|
|
214
|
-
this.contextValue = "urInfo";
|
|
215
|
-
this.description = description;
|
|
216
|
-
this.iconPath = new vscode3.ThemeIcon(icon);
|
|
217
|
-
this.tooltip = `${label}${description ? ` \u2014 ${description}` : ""}`;
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
var DiffTreeProvider = class {
|
|
221
|
-
_onDidChangeTreeData = new vscode3.EventEmitter();
|
|
222
|
-
onDidChangeTreeData = this._onDidChangeTreeData.event;
|
|
223
|
-
refresh() {
|
|
224
|
-
this._onDidChangeTreeData.fire();
|
|
225
|
-
}
|
|
226
|
-
getTreeItem(item) {
|
|
227
|
-
return item;
|
|
228
|
-
}
|
|
229
|
-
getChildren() {
|
|
230
|
-
const root = workspaceRoot();
|
|
231
|
-
if (!root) {
|
|
232
|
-
return [
|
|
233
|
-
new InfoItem(
|
|
234
|
-
"Open a workspace folder",
|
|
235
|
-
"UR inline diffs are scoped to the active project",
|
|
236
|
-
"folder-opened"
|
|
237
|
-
)
|
|
238
|
-
];
|
|
239
|
-
}
|
|
240
|
-
const manifest = loadManifest(root);
|
|
241
|
-
const diffs = manifest.diffs.slice().sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)));
|
|
242
|
-
if (diffs.length === 0) {
|
|
243
|
-
return [];
|
|
244
|
-
}
|
|
245
|
-
return diffs.map((bundle) => new DiffTreeItem(bundle));
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
|
|
249
117
|
// src/bridge/urCli.ts
|
|
250
118
|
var import_node_child_process2 = require("node:child_process");
|
|
251
119
|
var import_node_util = require("node:util");
|
|
@@ -291,13 +159,25 @@ function isBunAvailable(commandName) {
|
|
|
291
159
|
|
|
292
160
|
// src/bridge/urCli.ts
|
|
293
161
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process2.execFile);
|
|
162
|
+
function boundedExecutionOptions(options) {
|
|
163
|
+
const timeout = Number.isSafeInteger(options.timeoutMs) && (options.timeoutMs ?? 0) > 0 ? Math.min(options.timeoutMs, 10 * 6e4) : 12e4;
|
|
164
|
+
const maxBuffer = Number.isSafeInteger(options.maxBufferBytes) && (options.maxBufferBytes ?? 0) > 0 ? Math.min(options.maxBufferBytes, 16 * 1024 * 1024) : 4 * 1024 * 1024;
|
|
165
|
+
return {
|
|
166
|
+
cwd: options.cwd,
|
|
167
|
+
shell: false,
|
|
168
|
+
timeout,
|
|
169
|
+
maxBuffer,
|
|
170
|
+
windowsHide: true
|
|
171
|
+
};
|
|
172
|
+
}
|
|
294
173
|
async function runUrCli(args, options) {
|
|
295
174
|
const executable = resolveUrCommand({ cwd: options.cwd, config: readUrCommandConfig() });
|
|
296
175
|
try {
|
|
297
|
-
const { stdout, stderr } = await execFileAsync(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
176
|
+
const { stdout, stderr } = await execFileAsync(
|
|
177
|
+
executable.command,
|
|
178
|
+
[...executable.args, ...args],
|
|
179
|
+
boundedExecutionOptions(options)
|
|
180
|
+
);
|
|
301
181
|
return { stdout, stderr };
|
|
302
182
|
} catch (error) {
|
|
303
183
|
throw new Error(formatUrCliError(args, error, executable, options.cwd));
|
|
@@ -306,10 +186,11 @@ async function runUrCli(args, options) {
|
|
|
306
186
|
async function runUrCliCapture(args, options) {
|
|
307
187
|
const executable = resolveUrCommand({ cwd: options.cwd, config: readUrCommandConfig() });
|
|
308
188
|
try {
|
|
309
|
-
const { stdout, stderr } = await execFileAsync(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
189
|
+
const { stdout, stderr } = await execFileAsync(
|
|
190
|
+
executable.command,
|
|
191
|
+
[...executable.args, ...args],
|
|
192
|
+
boundedExecutionOptions(options)
|
|
193
|
+
);
|
|
313
194
|
return { stdout, stderr, exitCode: 0 };
|
|
314
195
|
} catch (error) {
|
|
315
196
|
if (isCapturedNonZeroExit(error)) {
|
|
@@ -356,19 +237,20 @@ var VALID_STATUSES = ["queued", "running", "completed", "failed", "canceled"];
|
|
|
356
237
|
function isRecord(value) {
|
|
357
238
|
return typeof value === "object" && value !== null;
|
|
358
239
|
}
|
|
359
|
-
function
|
|
240
|
+
function tryParseBackgroundListJson(raw) {
|
|
360
241
|
let data;
|
|
361
242
|
try {
|
|
362
243
|
data = JSON.parse(raw);
|
|
363
244
|
} catch {
|
|
364
|
-
return
|
|
245
|
+
return null;
|
|
365
246
|
}
|
|
366
|
-
if (!isRecord(data) || !Array.isArray(data.tasks)) return
|
|
247
|
+
if (!isRecord(data) || !Array.isArray(data.tasks)) return null;
|
|
367
248
|
const summaries = [];
|
|
368
249
|
for (const entry of data.tasks) {
|
|
369
250
|
if (!isRecord(entry)) continue;
|
|
370
251
|
if (typeof entry.id !== "string" || typeof entry.task !== "string") continue;
|
|
371
|
-
|
|
252
|
+
if (!VALID_STATUSES.includes(entry.status)) continue;
|
|
253
|
+
const status = entry.status;
|
|
372
254
|
summaries.push({
|
|
373
255
|
id: entry.id,
|
|
374
256
|
task: entry.task,
|
|
@@ -378,14 +260,287 @@ function parseBackgroundListJson(raw) {
|
|
|
378
260
|
}
|
|
379
261
|
return summaries;
|
|
380
262
|
}
|
|
263
|
+
function buildBackgroundRunArgs(task, options) {
|
|
264
|
+
const normalized = task.trim();
|
|
265
|
+
if (!normalized || normalized.length > 64e3 || normalized.includes("\0")) {
|
|
266
|
+
throw new Error("Background task must contain 1 to 64,000 characters and no NUL bytes.");
|
|
267
|
+
}
|
|
268
|
+
return [
|
|
269
|
+
"bg",
|
|
270
|
+
"run",
|
|
271
|
+
normalized,
|
|
272
|
+
...options.worktree ? ["--worktree"] : [],
|
|
273
|
+
...options.offline ? ["--offline"] : [],
|
|
274
|
+
"--json"
|
|
275
|
+
];
|
|
276
|
+
}
|
|
277
|
+
function buildBackgroundCancelArgs(id) {
|
|
278
|
+
if (!id || id.length > 256 || id.includes("\0")) {
|
|
279
|
+
throw new Error("Background task id is invalid.");
|
|
280
|
+
}
|
|
281
|
+
return ["bg", "kill", id];
|
|
282
|
+
}
|
|
381
283
|
async function loadBackgroundTasks(cwd) {
|
|
284
|
+
const { stdout, stderr, exitCode } = await runUrCliCapture(
|
|
285
|
+
["bg", "list", "--json"],
|
|
286
|
+
{ cwd }
|
|
287
|
+
);
|
|
288
|
+
if (exitCode !== 0) {
|
|
289
|
+
throw new Error(stderr.trim() || `ur bg list exited with status ${exitCode}`);
|
|
290
|
+
}
|
|
291
|
+
const tasks = tryParseBackgroundListJson(stdout);
|
|
292
|
+
if (!tasks) throw new Error("ur bg list returned invalid JSON");
|
|
293
|
+
return tasks;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/actions/actions.ts
|
|
297
|
+
var LAUNCH_CHOICES = [
|
|
298
|
+
{
|
|
299
|
+
label: "$(git-branch) Isolated worktree",
|
|
300
|
+
description: "Recommended",
|
|
301
|
+
detail: "Keep the agent away from uncommitted changes in the active checkout.",
|
|
302
|
+
worktree: true,
|
|
303
|
+
offline: false
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
label: "$(device-desktop) Offline isolated worktree",
|
|
307
|
+
description: "Local models only",
|
|
308
|
+
detail: "Use an isolated worktree and disable cloud API dispatch.",
|
|
309
|
+
worktree: true,
|
|
310
|
+
offline: true
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
label: "$(folder-active) Current workspace",
|
|
314
|
+
description: "Edits the active checkout",
|
|
315
|
+
detail: "Run directly in this workspace without worktree isolation.",
|
|
316
|
+
worktree: false,
|
|
317
|
+
offline: false
|
|
318
|
+
}
|
|
319
|
+
];
|
|
320
|
+
async function startBackgroundTask(view) {
|
|
321
|
+
const root = workspaceRoot();
|
|
322
|
+
if (!root) {
|
|
323
|
+
await vscode2.window.showWarningMessage("Open a workspace folder before starting a UR task.");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const task = await vscode2.window.showInputBox({
|
|
327
|
+
title: "Start UR Background Task",
|
|
328
|
+
prompt: "Describe the outcome the background agent should deliver.",
|
|
329
|
+
placeHolder: "For example: add regression tests for the authentication flow",
|
|
330
|
+
ignoreFocusOut: true,
|
|
331
|
+
validateInput: (value) => {
|
|
332
|
+
const length = value.trim().length;
|
|
333
|
+
if (length === 0) return "Enter a task.";
|
|
334
|
+
if (length > 64e3) return "Task descriptions are limited to 64,000 characters.";
|
|
335
|
+
if (value.includes("\0")) return "Task descriptions cannot contain NUL bytes.";
|
|
336
|
+
return void 0;
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
if (task === void 0) return;
|
|
340
|
+
const choice = await vscode2.window.showQuickPick(LAUNCH_CHOICES, {
|
|
341
|
+
title: "Choose background task isolation",
|
|
342
|
+
placeHolder: "Isolated worktree (recommended)",
|
|
343
|
+
ignoreFocusOut: true
|
|
344
|
+
});
|
|
345
|
+
if (!choice) return;
|
|
346
|
+
const confirmation = await vscode2.window.showWarningMessage(
|
|
347
|
+
`Start this UR background task${choice.worktree ? " in an isolated worktree" : " in the current workspace"}?`,
|
|
348
|
+
{
|
|
349
|
+
modal: true,
|
|
350
|
+
detail: "The task may edit files and use the configured model provider. It will not push or open a pull request."
|
|
351
|
+
},
|
|
352
|
+
"Start Task"
|
|
353
|
+
);
|
|
354
|
+
if (confirmation !== "Start Task") return;
|
|
382
355
|
try {
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
356
|
+
const result = await vscode2.window.withProgress(
|
|
357
|
+
{
|
|
358
|
+
location: vscode2.ProgressLocation.Notification,
|
|
359
|
+
title: "Starting UR background task\u2026",
|
|
360
|
+
cancellable: false
|
|
361
|
+
},
|
|
362
|
+
() => runUrCli(buildBackgroundRunArgs(task, choice), { cwd: root })
|
|
363
|
+
);
|
|
364
|
+
let id;
|
|
365
|
+
try {
|
|
366
|
+
const parsed = JSON.parse(result.stdout);
|
|
367
|
+
if (typeof parsed.task?.id === "string") id = parsed.task.id;
|
|
368
|
+
} catch {
|
|
369
|
+
}
|
|
370
|
+
await vscode2.window.showInformationMessage(
|
|
371
|
+
id ? `Started UR background task ${id}.` : "Started UR background task."
|
|
372
|
+
);
|
|
373
|
+
view.refresh();
|
|
374
|
+
} catch (error) {
|
|
375
|
+
await vscode2.window.showErrorMessage(
|
|
376
|
+
`Could not start UR background task: ${error instanceof Error ? error.message : String(error)}`
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async function cancelBackgroundTask(item, view) {
|
|
381
|
+
if (!item || item.task.status !== "queued" && item.task.status !== "running") {
|
|
382
|
+
await vscode2.window.showWarningMessage("Select a queued or running UR background task to cancel.");
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const confirmation = await vscode2.window.showWarningMessage(
|
|
386
|
+
`Cancel background task ${item.task.id}?`,
|
|
387
|
+
{ modal: true, detail: item.task.task },
|
|
388
|
+
"Cancel Task"
|
|
389
|
+
);
|
|
390
|
+
if (confirmation !== "Cancel Task") return;
|
|
391
|
+
const root = workspaceRoot();
|
|
392
|
+
if (!root) return;
|
|
393
|
+
try {
|
|
394
|
+
await runUrCli(buildBackgroundCancelArgs(item.task.id), { cwd: root });
|
|
395
|
+
await vscode2.window.showInformationMessage(`Canceled UR background task ${item.task.id}.`);
|
|
396
|
+
view.refresh();
|
|
397
|
+
} catch (error) {
|
|
398
|
+
await vscode2.window.showErrorMessage(
|
|
399
|
+
`Could not cancel UR background task: ${error instanceof Error ? error.message : String(error)}`
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
async function openBackgroundLog(item) {
|
|
404
|
+
if (!item) {
|
|
405
|
+
await vscode2.window.showWarningMessage("Select a UR background task first.");
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const root = workspaceRoot();
|
|
409
|
+
if (!root) return;
|
|
410
|
+
try {
|
|
411
|
+
const { stdout } = await runUrCli(
|
|
412
|
+
["bg", "logs", item.task.id, "--tail", "2000"],
|
|
413
|
+
{ cwd: root }
|
|
414
|
+
);
|
|
415
|
+
const doc = await vscode2.workspace.openTextDocument({
|
|
416
|
+
language: "log",
|
|
417
|
+
content: stdout || `No log output is available for ${item.task.id}.
|
|
418
|
+
`
|
|
419
|
+
});
|
|
420
|
+
await vscode2.window.showTextDocument(doc, { preview: true });
|
|
421
|
+
} catch (error) {
|
|
422
|
+
await vscode2.window.showErrorMessage(
|
|
423
|
+
`Could not open background task log: ${error instanceof Error ? error.message : String(error)}`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// src/actions/actionsTreeProvider.ts
|
|
429
|
+
var vscode4 = __toESM(require("vscode"));
|
|
430
|
+
|
|
431
|
+
// src/diffs/treeProvider.ts
|
|
432
|
+
var vscode3 = __toESM(require("vscode"));
|
|
433
|
+
|
|
434
|
+
// src/util/format.ts
|
|
435
|
+
function escapeHtml(text) {
|
|
436
|
+
return String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
437
|
+
}
|
|
438
|
+
function formatCount(count, singular, plural = `${singular}s`) {
|
|
439
|
+
return `${count} ${count === 1 ? singular : plural}`;
|
|
440
|
+
}
|
|
441
|
+
function formatRelativeTime(value) {
|
|
442
|
+
if (!value) return "unknown time";
|
|
443
|
+
const date = new Date(value);
|
|
444
|
+
if (Number.isNaN(date.getTime())) return String(value);
|
|
445
|
+
const deltaMs = Date.now() - date.getTime();
|
|
446
|
+
const minute = 60 * 1e3;
|
|
447
|
+
const hour = 60 * minute;
|
|
448
|
+
const day = 24 * hour;
|
|
449
|
+
if (deltaMs < minute) return "just now";
|
|
450
|
+
if (deltaMs < hour) return `${Math.max(1, Math.floor(deltaMs / minute))}m ago`;
|
|
451
|
+
if (deltaMs < day) return `${Math.floor(deltaMs / hour)}h ago`;
|
|
452
|
+
if (deltaMs < 7 * day) return `${Math.floor(deltaMs / day)}d ago`;
|
|
453
|
+
return date.toLocaleDateString();
|
|
454
|
+
}
|
|
455
|
+
function errorMessage(error) {
|
|
456
|
+
return error instanceof Error ? error.message : String(error);
|
|
457
|
+
}
|
|
458
|
+
function processErrorMessage(error) {
|
|
459
|
+
if (typeof error === "object" && error !== null && "stderr" in error) {
|
|
460
|
+
const stderr = error.stderr;
|
|
461
|
+
if (typeof stderr === "string" && stderr.trim()) return stderr.trim();
|
|
462
|
+
}
|
|
463
|
+
return errorMessage(error);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// src/diffs/treeProvider.ts
|
|
467
|
+
function statusIcon(status) {
|
|
468
|
+
switch (status) {
|
|
469
|
+
case "approved":
|
|
470
|
+
return new vscode3.ThemeIcon("check", new vscode3.ThemeColor("testing.iconPassed"));
|
|
471
|
+
case "rejected":
|
|
472
|
+
return new vscode3.ThemeIcon("circle-slash", new vscode3.ThemeColor("testing.iconFailed"));
|
|
473
|
+
case "commented":
|
|
474
|
+
return new vscode3.ThemeIcon("comment-discussion", new vscode3.ThemeColor("charts.yellow"));
|
|
475
|
+
default:
|
|
476
|
+
return new vscode3.ThemeIcon("diff", new vscode3.ThemeColor("charts.blue"));
|
|
387
477
|
}
|
|
388
478
|
}
|
|
479
|
+
var DiffTreeItem = class extends vscode3.TreeItem {
|
|
480
|
+
bundle;
|
|
481
|
+
constructor(bundle) {
|
|
482
|
+
const title = bundle.title || bundle.id;
|
|
483
|
+
super(title, vscode3.TreeItemCollapsibleState.None);
|
|
484
|
+
this.bundle = bundle;
|
|
485
|
+
this.contextValue = "diff";
|
|
486
|
+
const fileCount = bundle.files?.length ?? 0;
|
|
487
|
+
const changedAt = bundle.updatedAt ?? bundle.createdAt;
|
|
488
|
+
this.description = `${bundle.status ?? "captured"} \xB7 ${formatCount(fileCount, "file")} \xB7 ${formatRelativeTime(changedAt)}`;
|
|
489
|
+
this.iconPath = statusIcon(bundle.status);
|
|
490
|
+
this.tooltip = new vscode3.MarkdownString(
|
|
491
|
+
[
|
|
492
|
+
`**${escapeHtml(title)}**`,
|
|
493
|
+
"",
|
|
494
|
+
`- ID: \`${escapeHtml(bundle.id)}\``,
|
|
495
|
+
`- Status: ${escapeHtml(bundle.status ?? "captured")}`,
|
|
496
|
+
`- Files: ${fileCount}`,
|
|
497
|
+
`- Patch: \`${escapeHtml(bundle.patchFile)}\``
|
|
498
|
+
].join("\n")
|
|
499
|
+
);
|
|
500
|
+
this.command = {
|
|
501
|
+
command: "urInlineDiffs.open",
|
|
502
|
+
title: "Open Inline Diff",
|
|
503
|
+
arguments: [this]
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
var InfoItem = class extends vscode3.TreeItem {
|
|
508
|
+
constructor(label, description, icon = "info") {
|
|
509
|
+
super(label, vscode3.TreeItemCollapsibleState.None);
|
|
510
|
+
this.contextValue = "urInfo";
|
|
511
|
+
this.description = description;
|
|
512
|
+
this.iconPath = new vscode3.ThemeIcon(icon);
|
|
513
|
+
this.tooltip = `${label}${description ? ` \u2014 ${description}` : ""}`;
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
var DiffTreeProvider = class {
|
|
517
|
+
_onDidChangeTreeData = new vscode3.EventEmitter();
|
|
518
|
+
onDidChangeTreeData = this._onDidChangeTreeData.event;
|
|
519
|
+
refresh() {
|
|
520
|
+
this._onDidChangeTreeData.fire();
|
|
521
|
+
}
|
|
522
|
+
getTreeItem(item) {
|
|
523
|
+
return item;
|
|
524
|
+
}
|
|
525
|
+
getChildren() {
|
|
526
|
+
const root = workspaceRoot();
|
|
527
|
+
if (!root) {
|
|
528
|
+
return [
|
|
529
|
+
new InfoItem(
|
|
530
|
+
"Open a workspace folder",
|
|
531
|
+
"UR inline diffs are scoped to the active project",
|
|
532
|
+
"folder-opened"
|
|
533
|
+
)
|
|
534
|
+
];
|
|
535
|
+
}
|
|
536
|
+
const manifest = loadManifest(root);
|
|
537
|
+
const diffs = manifest.diffs.slice().sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)));
|
|
538
|
+
if (diffs.length === 0) {
|
|
539
|
+
return [];
|
|
540
|
+
}
|
|
541
|
+
return diffs.map((bundle) => new DiffTreeItem(bundle));
|
|
542
|
+
}
|
|
543
|
+
};
|
|
389
544
|
|
|
390
545
|
// src/actions/actionsTreeProvider.ts
|
|
391
546
|
function backgroundStatusIcon(status) {
|
|
@@ -407,7 +562,7 @@ var BackgroundTaskItem = class extends vscode4.TreeItem {
|
|
|
407
562
|
constructor(task) {
|
|
408
563
|
super(task.task, vscode4.TreeItemCollapsibleState.None);
|
|
409
564
|
this.task = task;
|
|
410
|
-
this.contextValue = "backgroundTask";
|
|
565
|
+
this.contextValue = task.status === "queued" || task.status === "running" ? "backgroundTaskActive" : "backgroundTask";
|
|
411
566
|
this.description = task.status;
|
|
412
567
|
this.iconPath = backgroundStatusIcon(task.status);
|
|
413
568
|
this.tooltip = `${task.id} \u2014 ${task.status}${task.logFile ? `
|
|
@@ -440,6 +595,7 @@ var ActionsTreeProvider = class {
|
|
|
440
595
|
onDidChangeTreeData = this._onDidChangeTreeData.event;
|
|
441
596
|
diffs = [];
|
|
442
597
|
backgroundTasks = [];
|
|
598
|
+
backgroundError;
|
|
443
599
|
loaded = false;
|
|
444
600
|
refresh() {
|
|
445
601
|
this.loaded = false;
|
|
@@ -455,17 +611,29 @@ var ActionsTreeProvider = class {
|
|
|
455
611
|
}
|
|
456
612
|
if (!this.loaded) {
|
|
457
613
|
this.diffs = loadManifest(root).diffs;
|
|
458
|
-
|
|
614
|
+
try {
|
|
615
|
+
this.backgroundTasks = await loadBackgroundTasks(root);
|
|
616
|
+
this.backgroundError = void 0;
|
|
617
|
+
} catch (error) {
|
|
618
|
+
this.backgroundTasks = [];
|
|
619
|
+
this.backgroundError = error instanceof Error ? error.message : String(error);
|
|
620
|
+
}
|
|
459
621
|
this.loaded = true;
|
|
460
622
|
}
|
|
461
623
|
if (!element) {
|
|
462
|
-
if (this.diffs.length === 0 && this.backgroundTasks.length === 0) {
|
|
624
|
+
if (this.diffs.length === 0 && this.backgroundTasks.length === 0 && !this.backgroundError) {
|
|
463
625
|
return [];
|
|
464
626
|
}
|
|
465
|
-
|
|
627
|
+
const sections = [
|
|
466
628
|
new SectionItem("diffs", "Diff Bundles", this.diffs.length),
|
|
467
629
|
new SectionItem("background", "Background Tasks", this.backgroundTasks.length)
|
|
468
630
|
];
|
|
631
|
+
if (this.backgroundError) {
|
|
632
|
+
sections.push(
|
|
633
|
+
new InfoItem2("Could not load background tasks", this.backgroundError, "warning")
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
return sections;
|
|
469
637
|
}
|
|
470
638
|
if (element instanceof SectionItem && element.kind === "diffs") {
|
|
471
639
|
if (this.diffs.length === 0) {
|
|
@@ -2398,6 +2566,7 @@ var ACTION_REGISTRY = [
|
|
|
2398
2566
|
{ id: "openArtifacts", label: "Open Artifacts", commandId: "urInlineDiffs.openArtifacts", description: "Reveal the .ur workspace directory" },
|
|
2399
2567
|
{ id: "runSpec", label: "Run Spec", commandId: "urInlineDiffs.runSpec", description: "Ask UR to list and run specs (ur spec)" },
|
|
2400
2568
|
{ id: "runWorkflow", label: "Run Workflow", commandId: "urInlineDiffs.runWorkflow", description: "Ask UR to list and run workflows (ur workflow)" },
|
|
2569
|
+
{ id: "startBackgroundTask", label: "Start Background Task", commandId: "urActions.runBackground", description: "Launch an isolated or workspace-scoped UR background agent" },
|
|
2401
2570
|
{ id: "refreshActions", label: "Refresh IDE Actions", commandId: "urActions.refresh", description: "Refresh the UR actions panel" }
|
|
2402
2571
|
];
|
|
2403
2572
|
|
|
@@ -2552,7 +2721,7 @@ function renderStatusHtml(status) {
|
|
|
2552
2721
|
${boundary}
|
|
2553
2722
|
${row("Sandbox mode", knownText2(status.sandboxMode))}
|
|
2554
2723
|
${row("Verifier mode", knownText2(status.verifierMode))}
|
|
2555
|
-
${row("
|
|
2724
|
+
${row("UR HTTP server", acp)}
|
|
2556
2725
|
${row("Plugins loaded", String(status.pluginCount))}
|
|
2557
2726
|
<section>
|
|
2558
2727
|
<h2>Warnings</h2>
|
|
@@ -2704,6 +2873,8 @@ function activate(context) {
|
|
|
2704
2873
|
vscode17.commands.registerCommand("urInlineDiffs.runSpec", () => runSpecAction(chat)),
|
|
2705
2874
|
vscode17.commands.registerCommand("urInlineDiffs.runWorkflow", () => runWorkflowAction(chat)),
|
|
2706
2875
|
vscode17.commands.registerCommand("urActions.refresh", () => actionsTreeProvider.refresh()),
|
|
2876
|
+
vscode17.commands.registerCommand("urActions.runBackground", () => startBackgroundTask(actionsTreeProvider)),
|
|
2877
|
+
vscode17.commands.registerCommand("urActions.cancelBackground", (item) => cancelBackgroundTask(item, actionsTreeProvider)),
|
|
2707
2878
|
vscode17.commands.registerCommand("urActions.openBackgroundLog", (item) => openBackgroundLog(item))
|
|
2708
2879
|
);
|
|
2709
2880
|
}
|
|
@@ -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.
|
|
5
|
+
"version": "1.47.0",
|
|
6
6
|
"publisher": "ur-nexus",
|
|
7
7
|
"engines": {
|
|
8
8
|
"vscode": "^1.92.0"
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
"onCommand:urInlineDiffs.runSpec",
|
|
41
41
|
"onCommand:urInlineDiffs.runWorkflow",
|
|
42
42
|
"onCommand:urActions.refresh",
|
|
43
|
+
"onCommand:urActions.runBackground",
|
|
44
|
+
"onCommand:urActions.cancelBackground",
|
|
43
45
|
"onCommand:urActions.openBackgroundLog"
|
|
44
46
|
],
|
|
45
47
|
"main": "./out/extension.js",
|
|
@@ -219,9 +221,20 @@
|
|
|
219
221
|
"title": "UR: Refresh IDE Actions",
|
|
220
222
|
"icon": "$(refresh)"
|
|
221
223
|
},
|
|
224
|
+
{
|
|
225
|
+
"command": "urActions.runBackground",
|
|
226
|
+
"title": "UR: Start Background Task",
|
|
227
|
+
"icon": "$(play)"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"command": "urActions.cancelBackground",
|
|
231
|
+
"title": "UR: Cancel Background Task",
|
|
232
|
+
"icon": "$(stop-circle)"
|
|
233
|
+
},
|
|
222
234
|
{
|
|
223
235
|
"command": "urActions.openBackgroundLog",
|
|
224
|
-
"title": "UR: Open Background Task Log"
|
|
236
|
+
"title": "UR: Open Background Task Log",
|
|
237
|
+
"icon": "$(output)"
|
|
225
238
|
}
|
|
226
239
|
],
|
|
227
240
|
"viewsWelcome": [
|
|
@@ -235,7 +248,7 @@
|
|
|
235
248
|
},
|
|
236
249
|
{
|
|
237
250
|
"view": "urActions",
|
|
238
|
-
"contents": "Background tasks and diff actions will appear here.\n[Refresh](command:urActions.refresh) [Search Actions](command:urInlineDiffs.searchActions)"
|
|
251
|
+
"contents": "Background tasks and diff actions will appear here.\n[Start Task](command:urActions.runBackground) [Refresh](command:urActions.refresh) [Search Actions](command:urInlineDiffs.searchActions)"
|
|
239
252
|
}
|
|
240
253
|
],
|
|
241
254
|
"menus": {
|
|
@@ -280,15 +293,20 @@
|
|
|
280
293
|
"when": "view == urInlineDiffs",
|
|
281
294
|
"group": "navigation"
|
|
282
295
|
},
|
|
296
|
+
{
|
|
297
|
+
"command": "urActions.runBackground",
|
|
298
|
+
"when": "view == urActions",
|
|
299
|
+
"group": "navigation@1"
|
|
300
|
+
},
|
|
283
301
|
{
|
|
284
302
|
"command": "urActions.refresh",
|
|
285
303
|
"when": "view == urActions",
|
|
286
|
-
"group": "navigation"
|
|
304
|
+
"group": "navigation@2"
|
|
287
305
|
},
|
|
288
306
|
{
|
|
289
307
|
"command": "urInlineDiffs.agentStatus",
|
|
290
308
|
"when": "view == urActions",
|
|
291
|
-
"group": "navigation"
|
|
309
|
+
"group": "navigation@3"
|
|
292
310
|
}
|
|
293
311
|
],
|
|
294
312
|
"view/item/context": [
|
|
@@ -311,6 +329,16 @@
|
|
|
311
329
|
"command": "urInlineDiffs.comment",
|
|
312
330
|
"when": "(view == urInlineDiffs || view == urActions) && viewItem == diff",
|
|
313
331
|
"group": "2_review"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"command": "urActions.openBackgroundLog",
|
|
335
|
+
"when": "view == urActions && (viewItem == backgroundTask || viewItem == backgroundTaskActive)",
|
|
336
|
+
"group": "inline"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"command": "urActions.cancelBackground",
|
|
340
|
+
"when": "view == urActions && viewItem == backgroundTaskActive",
|
|
341
|
+
"group": "1_actions"
|
|
314
342
|
}
|
|
315
343
|
],
|
|
316
344
|
"editor/context": [
|