ur-agent 1.37.0 → 1.37.2
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/README.md +2 -0
- package/bin/ur.js +56 -4
- package/dist/cli.js +143 -67
- package/docs/CONFIGURATION.md +2 -0
- package/docs/IDE.md +17 -5
- package/docs/providers.md +2 -0
- package/extensions/vscode-ur-inline-diffs/README.md +18 -3
- package/extensions/vscode-ur-inline-diffs/media/ur.svg +3 -4
- package/extensions/vscode-ur-inline-diffs/out/extension.js +496 -158
- package/extensions/vscode-ur-inline-diffs/package.json +59 -2
- package/package.json +1 -1
|
@@ -34,7 +34,7 @@ __export(extension_exports, {
|
|
|
34
34
|
deactivate: () => deactivate
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(extension_exports);
|
|
37
|
-
var
|
|
37
|
+
var vscode17 = __toESM(require("vscode"));
|
|
38
38
|
|
|
39
39
|
// src/actions/actions.ts
|
|
40
40
|
var vscode = __toESM(require("vscode"));
|
|
@@ -107,8 +107,6 @@ function writeBundleMetadata(root, bundle) {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// src/diffs/treeProvider.ts
|
|
110
|
-
var fs2 = __toESM(require("node:fs"));
|
|
111
|
-
var path2 = __toESM(require("node:path"));
|
|
112
110
|
var vscode3 = __toESM(require("vscode"));
|
|
113
111
|
|
|
114
112
|
// src/util/format.ts
|
|
@@ -184,16 +182,6 @@ var DiffTreeItem = class extends vscode3.TreeItem {
|
|
|
184
182
|
};
|
|
185
183
|
}
|
|
186
184
|
};
|
|
187
|
-
var ActionItem = class extends vscode3.TreeItem {
|
|
188
|
-
constructor(label, description, icon, command, tooltip) {
|
|
189
|
-
super(label, vscode3.TreeItemCollapsibleState.None);
|
|
190
|
-
this.contextValue = "urAction";
|
|
191
|
-
this.description = description;
|
|
192
|
-
this.iconPath = new vscode3.ThemeIcon(icon);
|
|
193
|
-
this.tooltip = tooltip ?? `${label}${description ? ` \u2014 ${description}` : ""}`;
|
|
194
|
-
this.command = command;
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
185
|
var InfoItem = class extends vscode3.TreeItem {
|
|
198
186
|
constructor(label, description, icon = "info") {
|
|
199
187
|
super(label, vscode3.TreeItemCollapsibleState.None);
|
|
@@ -226,44 +214,73 @@ var DiffTreeProvider = class {
|
|
|
226
214
|
const manifest = loadManifest(root);
|
|
227
215
|
const diffs = manifest.diffs.slice().sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)));
|
|
228
216
|
if (diffs.length === 0) {
|
|
229
|
-
return [
|
|
230
|
-
new InfoItem(
|
|
231
|
-
"Ready for inline review",
|
|
232
|
-
fs2.existsSync(manifestPath(root)) ? "No pending diff bundles" : "No diff bundles captured yet",
|
|
233
|
-
"pass"
|
|
234
|
-
),
|
|
235
|
-
new ActionItem("Show UR status", "Provider, model, plugins", "pulse", {
|
|
236
|
-
command: "urInlineDiffs.status",
|
|
237
|
-
title: "Show UR Status"
|
|
238
|
-
}),
|
|
239
|
-
new ActionItem("Refresh", path2.relative(root, manifestPath(root)), "refresh", {
|
|
240
|
-
command: "urInlineDiffs.refresh",
|
|
241
|
-
title: "Refresh Inline Diffs"
|
|
242
|
-
})
|
|
243
|
-
];
|
|
217
|
+
return [];
|
|
244
218
|
}
|
|
245
219
|
return diffs.map((bundle) => new DiffTreeItem(bundle));
|
|
246
220
|
}
|
|
247
221
|
};
|
|
248
222
|
|
|
249
223
|
// src/bridge/urCli.ts
|
|
250
|
-
var
|
|
224
|
+
var import_node_child_process2 = require("node:child_process");
|
|
251
225
|
var import_node_util = require("node:util");
|
|
252
|
-
|
|
226
|
+
|
|
227
|
+
// src/bridge/urCommand.ts
|
|
228
|
+
var import_node_child_process = require("node:child_process");
|
|
229
|
+
var import_node_fs = require("node:fs");
|
|
230
|
+
var import_node_path = require("node:path");
|
|
231
|
+
function resolveUrCommand(options) {
|
|
232
|
+
const config = options.config ?? {};
|
|
233
|
+
const configuredPath = config.executablePath?.trim();
|
|
234
|
+
const configuredArgs = normalizeExecutableArgs(config.executableArgs);
|
|
235
|
+
if (configuredPath) {
|
|
236
|
+
return command(configuredPath, configuredArgs, "configured");
|
|
237
|
+
}
|
|
238
|
+
const pathExists = options.pathExists ?? import_node_fs.existsSync;
|
|
239
|
+
const bunCommand = options.bunCommand ?? "bun";
|
|
240
|
+
const nodeCommand = options.nodeCommand ?? "node";
|
|
241
|
+
const distEntrypoint = (0, import_node_path.join)(options.cwd, "dist", "cli.js");
|
|
242
|
+
if (pathExists(distEntrypoint) && (options.bunAvailable ?? isBunAvailable)(bunCommand)) {
|
|
243
|
+
return command(bunCommand, [distEntrypoint], "workspace-dist");
|
|
244
|
+
}
|
|
245
|
+
const launcherEntrypoint = (0, import_node_path.join)(options.cwd, "bin", "ur.js");
|
|
246
|
+
if (pathExists(launcherEntrypoint)) {
|
|
247
|
+
return command(nodeCommand, [launcherEntrypoint], "workspace-launcher");
|
|
248
|
+
}
|
|
249
|
+
return command("ur", [], "path");
|
|
250
|
+
}
|
|
251
|
+
function formatResolvedUrCommand(resolved) {
|
|
252
|
+
return [resolved.command, ...resolved.args].join(" ");
|
|
253
|
+
}
|
|
254
|
+
function command(commandName, args, source) {
|
|
255
|
+
const resolved = { command: commandName, args, source, display: "" };
|
|
256
|
+
return { ...resolved, display: formatResolvedUrCommand(resolved) };
|
|
257
|
+
}
|
|
258
|
+
function normalizeExecutableArgs(args) {
|
|
259
|
+
return Array.isArray(args) ? args.filter((arg) => typeof arg === "string" && arg.length > 0) : [];
|
|
260
|
+
}
|
|
261
|
+
function isBunAvailable(commandName) {
|
|
262
|
+
const result = (0, import_node_child_process.spawnSync)(commandName, ["--version"], { stdio: "ignore" });
|
|
263
|
+
return !result.error && result.status === 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/bridge/urCli.ts
|
|
267
|
+
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process2.execFile);
|
|
253
268
|
async function runUrCli(args, options) {
|
|
269
|
+
const executable = resolveUrCommand({ cwd: options.cwd, config: readUrCommandConfig() });
|
|
254
270
|
try {
|
|
255
|
-
const { stdout, stderr } = await execFileAsync(
|
|
271
|
+
const { stdout, stderr } = await execFileAsync(executable.command, [...executable.args, ...args], {
|
|
256
272
|
cwd: options.cwd,
|
|
257
273
|
shell: false
|
|
258
274
|
});
|
|
259
275
|
return { stdout, stderr };
|
|
260
276
|
} catch (error) {
|
|
261
|
-
throw new Error(formatUrCliError(args, error));
|
|
277
|
+
throw new Error(formatUrCliError(args, error, executable, options.cwd));
|
|
262
278
|
}
|
|
263
279
|
}
|
|
264
280
|
async function runUrCliCapture(args, options) {
|
|
281
|
+
const executable = resolveUrCommand({ cwd: options.cwd, config: readUrCommandConfig() });
|
|
265
282
|
try {
|
|
266
|
-
const { stdout, stderr } = await execFileAsync(
|
|
283
|
+
const { stdout, stderr } = await execFileAsync(executable.command, [...executable.args, ...args], {
|
|
267
284
|
cwd: options.cwd,
|
|
268
285
|
shell: false
|
|
269
286
|
});
|
|
@@ -272,13 +289,34 @@ async function runUrCliCapture(args, options) {
|
|
|
272
289
|
if (isCapturedNonZeroExit(error)) {
|
|
273
290
|
return { stdout: error.stdout, stderr: error.stderr, exitCode: error.code };
|
|
274
291
|
}
|
|
275
|
-
throw new Error(formatUrCliError(args, error));
|
|
292
|
+
throw new Error(formatUrCliError(args, error, executable, options.cwd));
|
|
276
293
|
}
|
|
277
294
|
}
|
|
278
|
-
function
|
|
295
|
+
function readUrCommandConfig() {
|
|
296
|
+
try {
|
|
297
|
+
const vscode18 = require("vscode");
|
|
298
|
+
const config = vscode18.workspace.getConfiguration("ur");
|
|
299
|
+
const executablePath = config.get("executablePath")?.trim();
|
|
300
|
+
const executableArgs = config.get("executableArgs") ?? [];
|
|
301
|
+
return {
|
|
302
|
+
executablePath: executablePath || void 0,
|
|
303
|
+
executableArgs: executableArgs.filter((arg) => typeof arg === "string" && arg.length > 0)
|
|
304
|
+
};
|
|
305
|
+
} catch {
|
|
306
|
+
return {};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function formatUrCliError(args, error, executable, cwd) {
|
|
279
310
|
const stderr = hasStderr(error) ? error.stderr.trim() : "";
|
|
280
311
|
const detail = stderr || (error instanceof Error ? error.message : String(error));
|
|
281
|
-
return
|
|
312
|
+
return [
|
|
313
|
+
`Failed to run UR command.`,
|
|
314
|
+
`Executable: ${executable.display}`,
|
|
315
|
+
`cwd: ${cwd}`,
|
|
316
|
+
`Args: ${args.join(" ")}`,
|
|
317
|
+
`Error: ${detail}`,
|
|
318
|
+
`Hint: Set ur.executablePath in VS Code settings if the extension is using the wrong UR binary.`
|
|
319
|
+
].join("\n");
|
|
282
320
|
}
|
|
283
321
|
function hasStderr(error) {
|
|
284
322
|
return typeof error === "object" && error !== null && "stderr" in error && typeof error.stderr === "string";
|
|
@@ -396,7 +434,7 @@ var ActionsTreeProvider = class {
|
|
|
396
434
|
}
|
|
397
435
|
if (!element) {
|
|
398
436
|
if (this.diffs.length === 0 && this.backgroundTasks.length === 0) {
|
|
399
|
-
return [
|
|
437
|
+
return [];
|
|
400
438
|
}
|
|
401
439
|
return [
|
|
402
440
|
new SectionItem("diffs", "Diff Bundles", this.diffs.length),
|
|
@@ -435,7 +473,7 @@ function isCanUseToolRequest(message) {
|
|
|
435
473
|
}
|
|
436
474
|
|
|
437
475
|
// src/bridge/urProcess.ts
|
|
438
|
-
var
|
|
476
|
+
var import_node_child_process3 = require("node:child_process");
|
|
439
477
|
var NdjsonBuffer = class {
|
|
440
478
|
buffer = "";
|
|
441
479
|
/** Feed a raw chunk (may contain zero, one, or many complete lines, and may
|
|
@@ -503,14 +541,14 @@ function buildControlResponse(requestId, decision) {
|
|
|
503
541
|
}
|
|
504
542
|
};
|
|
505
543
|
}
|
|
506
|
-
var defaultSpawn = (
|
|
544
|
+
var defaultSpawn = (command2, args, options) => (0, import_node_child_process3.spawn)(command2, args, options);
|
|
507
545
|
function runUrTurn(request, handlers, deps = {}) {
|
|
508
546
|
const spawnFn = deps.spawn ?? defaultSpawn;
|
|
509
|
-
const
|
|
510
|
-
const args = buildUrArgs(request);
|
|
547
|
+
const executable = deps.executable ?? (deps.command ? { command: deps.command, args: [], source: "configured", display: deps.command } : resolveUrCommand({ cwd: request.cwd }));
|
|
548
|
+
const args = [...executable.args, ...buildUrArgs(request)];
|
|
511
549
|
let child;
|
|
512
550
|
try {
|
|
513
|
-
child = spawnFn(command, args, {
|
|
551
|
+
child = spawnFn(executable.command, args, {
|
|
514
552
|
cwd: request.cwd,
|
|
515
553
|
shell: false,
|
|
516
554
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -519,10 +557,18 @@ function runUrTurn(request, handlers, deps = {}) {
|
|
|
519
557
|
handlers.onExit({
|
|
520
558
|
ok: false,
|
|
521
559
|
exitCode: null,
|
|
560
|
+
signal: null,
|
|
522
561
|
canceled: false,
|
|
523
562
|
sawResult: false,
|
|
524
563
|
stderr: "",
|
|
525
|
-
error:
|
|
564
|
+
error: formatTurnFailure({
|
|
565
|
+
executable,
|
|
566
|
+
cwd: request.cwd,
|
|
567
|
+
exitCode: null,
|
|
568
|
+
signal: null,
|
|
569
|
+
stderr: "",
|
|
570
|
+
reason: `Failed to start: ${errorMessage2(error)}`
|
|
571
|
+
})
|
|
526
572
|
});
|
|
527
573
|
return { cancel: () => {
|
|
528
574
|
} };
|
|
@@ -533,7 +579,7 @@ function runUrTurn(request, handlers, deps = {}) {
|
|
|
533
579
|
let resultIsError = false;
|
|
534
580
|
let canceled = false;
|
|
535
581
|
let settled = false;
|
|
536
|
-
const finish = (exitCode, spawnError) => {
|
|
582
|
+
const finish = (exitCode, signal, spawnError) => {
|
|
537
583
|
if (settled) return;
|
|
538
584
|
settled = true;
|
|
539
585
|
const stderr = stderrChunks.join("");
|
|
@@ -541,10 +587,11 @@ function runUrTurn(request, handlers, deps = {}) {
|
|
|
541
587
|
handlers.onExit({
|
|
542
588
|
ok,
|
|
543
589
|
exitCode,
|
|
590
|
+
signal,
|
|
544
591
|
canceled,
|
|
545
592
|
sawResult,
|
|
546
593
|
stderr,
|
|
547
|
-
error: spawnError ?? (!ok && !canceled ? deriveErrorMessage(sawResult, resultIsError, exitCode, stderr) : void 0)
|
|
594
|
+
error: spawnError ?? (!ok && !canceled ? deriveErrorMessage(executable, request.cwd, sawResult, resultIsError, exitCode, signal, stderr) : void 0)
|
|
548
595
|
});
|
|
549
596
|
};
|
|
550
597
|
const handleMessage = (message) => {
|
|
@@ -573,13 +620,24 @@ function runUrTurn(request, handlers, deps = {}) {
|
|
|
573
620
|
stderrChunks.push(chunk.toString("utf8"));
|
|
574
621
|
});
|
|
575
622
|
child.on("error", (error) => {
|
|
576
|
-
finish(
|
|
623
|
+
finish(
|
|
624
|
+
null,
|
|
625
|
+
null,
|
|
626
|
+
formatTurnFailure({
|
|
627
|
+
executable,
|
|
628
|
+
cwd: request.cwd,
|
|
629
|
+
exitCode: null,
|
|
630
|
+
signal: null,
|
|
631
|
+
stderr: stderrChunks.join(""),
|
|
632
|
+
reason: `Failed to run: ${errorMessage2(error)}`
|
|
633
|
+
})
|
|
634
|
+
);
|
|
577
635
|
});
|
|
578
|
-
child.on("exit", (code) => {
|
|
636
|
+
child.on("exit", (code, signal) => {
|
|
579
637
|
for (const message of stdoutBuffer.flush()) {
|
|
580
638
|
handleMessage(message);
|
|
581
639
|
}
|
|
582
|
-
finish(code);
|
|
640
|
+
finish(code, signal);
|
|
583
641
|
});
|
|
584
642
|
return {
|
|
585
643
|
cancel: () => {
|
|
@@ -596,18 +654,33 @@ function writeControlResponse(child, requestId, decision) {
|
|
|
596
654
|
} catch {
|
|
597
655
|
}
|
|
598
656
|
}
|
|
599
|
-
function deriveErrorMessage(sawResult, resultIsError, exitCode, stderr) {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
657
|
+
function deriveErrorMessage(executable, cwd, sawResult, resultIsError, exitCode, signal, stderr) {
|
|
658
|
+
const reason = sawResult && resultIsError ? "UR reported an error completing this turn." : "UR exited without producing a successful result.";
|
|
659
|
+
return formatTurnFailure({ executable, cwd, exitCode, signal, stderr, reason });
|
|
660
|
+
}
|
|
661
|
+
function formatTurnFailure(options) {
|
|
662
|
+
const stderr = summarizeStderr(options.stderr);
|
|
663
|
+
return [
|
|
664
|
+
`UR chat backend failed.`,
|
|
665
|
+
`Executable: ${options.executable.display}`,
|
|
666
|
+
`cwd: ${options.cwd}`,
|
|
667
|
+
`Exit: code ${options.exitCode ?? "unknown"}, signal ${options.signal ?? "none"}`,
|
|
668
|
+
`stderr: ${stderr || "<empty>"}`,
|
|
669
|
+
options.reason,
|
|
670
|
+
`Hint: Set ur.executablePath in VS Code settings if the extension is using the wrong UR binary.`
|
|
671
|
+
].join("\n");
|
|
672
|
+
}
|
|
673
|
+
function summarizeStderr(stderr) {
|
|
674
|
+
const trimmed = stderr.trim();
|
|
675
|
+
if (trimmed.length <= 2e3) return trimmed;
|
|
676
|
+
return `${trimmed.slice(0, 2e3)}\u2026`;
|
|
604
677
|
}
|
|
605
678
|
function errorMessage2(error) {
|
|
606
679
|
return error instanceof Error ? error.message : String(error);
|
|
607
680
|
}
|
|
608
681
|
|
|
609
682
|
// src/context/ideContext.ts
|
|
610
|
-
var
|
|
683
|
+
var path2 = __toESM(require("node:path"));
|
|
611
684
|
function formatAttachmentLabel(attachment) {
|
|
612
685
|
if (attachment.kind === "file") return `@${attachment.file.path}`;
|
|
613
686
|
const { path: filePath, startLine, endLine } = attachment.selection;
|
|
@@ -646,12 +719,12 @@ function languageIdToFence(languageId) {
|
|
|
646
719
|
return FENCE_OVERRIDES[languageId] ?? languageId;
|
|
647
720
|
}
|
|
648
721
|
function captureEditorSnapshot() {
|
|
649
|
-
const
|
|
650
|
-
const workspaceRoot2 =
|
|
651
|
-
const editor =
|
|
722
|
+
const vscode18 = require("vscode");
|
|
723
|
+
const workspaceRoot2 = vscode18.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
|
724
|
+
const editor = vscode18.window.activeTextEditor;
|
|
652
725
|
if (!editor) return { workspaceRoot: workspaceRoot2 };
|
|
653
726
|
const absolutePath = editor.document.uri.fsPath;
|
|
654
|
-
const relativePath = workspaceRoot2 ?
|
|
727
|
+
const relativePath = workspaceRoot2 ? path2.relative(workspaceRoot2, absolutePath) : absolutePath;
|
|
655
728
|
const activeFile = { path: relativePath, languageId: editor.document.languageId };
|
|
656
729
|
const selection = editor.selection;
|
|
657
730
|
if (selection.isEmpty) return { workspaceRoot: workspaceRoot2, activeFile };
|
|
@@ -668,39 +741,39 @@ function captureEditorSnapshot() {
|
|
|
668
741
|
|
|
669
742
|
// src/sessions/sessionStore.ts
|
|
670
743
|
var import_node_crypto = require("node:crypto");
|
|
671
|
-
var
|
|
672
|
-
var
|
|
744
|
+
var fs2 = __toESM(require("node:fs"));
|
|
745
|
+
var path3 = __toESM(require("node:path"));
|
|
673
746
|
var SESSION_ID_PATTERN = /^[a-zA-Z0-9-]{1,128}$/;
|
|
674
747
|
var TITLE_MAX_LENGTH = 60;
|
|
675
748
|
var DEFAULT_TITLE = "New Chat";
|
|
676
749
|
function chatRoot(root) {
|
|
677
|
-
return
|
|
750
|
+
return path3.join(root, ".ur", "ide", "chat");
|
|
678
751
|
}
|
|
679
752
|
function manifestPath2(root) {
|
|
680
|
-
return
|
|
753
|
+
return path3.join(chatRoot(root), "manifest.json");
|
|
681
754
|
}
|
|
682
755
|
function isValidSessionId(id) {
|
|
683
756
|
return SESSION_ID_PATTERN.test(id);
|
|
684
757
|
}
|
|
685
758
|
function sessionFilePath(root, id) {
|
|
686
759
|
if (!isValidSessionId(id)) return null;
|
|
687
|
-
const sessionsDir =
|
|
688
|
-
const target =
|
|
689
|
-
const resolvedDir =
|
|
690
|
-
const resolvedTarget =
|
|
760
|
+
const sessionsDir = path3.join(chatRoot(root), "sessions");
|
|
761
|
+
const target = path3.join(sessionsDir, `${id}.json`);
|
|
762
|
+
const resolvedDir = path3.resolve(sessionsDir) + path3.sep;
|
|
763
|
+
const resolvedTarget = path3.resolve(target);
|
|
691
764
|
if (!resolvedTarget.startsWith(resolvedDir)) return null;
|
|
692
765
|
return target;
|
|
693
766
|
}
|
|
694
767
|
function readJson2(file, fallback) {
|
|
695
768
|
try {
|
|
696
|
-
return JSON.parse(
|
|
769
|
+
return JSON.parse(fs2.readFileSync(file, "utf8"));
|
|
697
770
|
} catch {
|
|
698
771
|
return fallback;
|
|
699
772
|
}
|
|
700
773
|
}
|
|
701
774
|
function writeJson2(file, value) {
|
|
702
|
-
|
|
703
|
-
|
|
775
|
+
fs2.mkdirSync(path3.dirname(file), { recursive: true });
|
|
776
|
+
fs2.writeFileSync(file, `${JSON.stringify(value, null, 2)}
|
|
704
777
|
`);
|
|
705
778
|
}
|
|
706
779
|
function readManifest(root) {
|
|
@@ -743,7 +816,7 @@ function listSessions(root, options = {}) {
|
|
|
743
816
|
}
|
|
744
817
|
function readSession(root, id) {
|
|
745
818
|
const file = sessionFilePath(root, id);
|
|
746
|
-
if (!file || !
|
|
819
|
+
if (!file || !fs2.existsSync(file)) return null;
|
|
747
820
|
return readJson2(file, null);
|
|
748
821
|
}
|
|
749
822
|
function appendMessage(root, id, message) {
|
|
@@ -1214,6 +1287,8 @@ function buildRunWorkflowPrompt() {
|
|
|
1214
1287
|
|
|
1215
1288
|
// src/chat/chatController.ts
|
|
1216
1289
|
var ChatController = class {
|
|
1290
|
+
_onDidChangeState = new vscode6.EventEmitter();
|
|
1291
|
+
onDidChangeState = this._onDidChangeState.event;
|
|
1217
1292
|
panel;
|
|
1218
1293
|
record;
|
|
1219
1294
|
attachments = [];
|
|
@@ -1228,6 +1303,7 @@ var ChatController = class {
|
|
|
1228
1303
|
this.record = createSession(root);
|
|
1229
1304
|
this.attachments = [];
|
|
1230
1305
|
this.status = "idle";
|
|
1306
|
+
this._onDidChangeState.fire();
|
|
1231
1307
|
this.ensurePanel();
|
|
1232
1308
|
this.syncFullState();
|
|
1233
1309
|
}
|
|
@@ -1273,6 +1349,9 @@ var ChatController = class {
|
|
|
1273
1349
|
addSelectionToChat() {
|
|
1274
1350
|
this.stageAttachment("selection");
|
|
1275
1351
|
}
|
|
1352
|
+
isRequestRunning() {
|
|
1353
|
+
return this.status === "running";
|
|
1354
|
+
}
|
|
1276
1355
|
async explainSelection() {
|
|
1277
1356
|
await this.runEditorAction(buildExplainPrompt);
|
|
1278
1357
|
}
|
|
@@ -1299,6 +1378,7 @@ var ChatController = class {
|
|
|
1299
1378
|
dispose() {
|
|
1300
1379
|
this.turnHandle?.cancel();
|
|
1301
1380
|
this.denyAllPending("Extension is shutting down.");
|
|
1381
|
+
this._onDidChangeState.dispose();
|
|
1302
1382
|
}
|
|
1303
1383
|
// --- internals ---
|
|
1304
1384
|
requireWorkspaceRoot() {
|
|
@@ -1377,6 +1457,7 @@ var ChatController = class {
|
|
|
1377
1457
|
this.record.messages.push(userMessage);
|
|
1378
1458
|
this.panel?.post({ type: "messageAppended", message: userMessage });
|
|
1379
1459
|
this.status = "running";
|
|
1460
|
+
this._onDidChangeState.fire();
|
|
1380
1461
|
this.panel?.post({ type: "statusChanged", status: this.status });
|
|
1381
1462
|
const resumeSessionId = this.record.session.cliSessionId;
|
|
1382
1463
|
this.turnHandle = runUrTurn(
|
|
@@ -1385,7 +1466,8 @@ var ChatController = class {
|
|
|
1385
1466
|
onMessage: (message) => this.handleStreamMessage(root, sessionId, message),
|
|
1386
1467
|
onControlRequest: (request) => this.handlePermissionRequest(request),
|
|
1387
1468
|
onExit: (result) => this.handleTurnExit(root, result)
|
|
1388
|
-
}
|
|
1469
|
+
},
|
|
1470
|
+
{ executable: resolveUrCommand({ cwd: root, config: readUrCommandConfig() }) }
|
|
1389
1471
|
);
|
|
1390
1472
|
}
|
|
1391
1473
|
handleStreamMessage(root, sessionId, message) {
|
|
@@ -1448,6 +1530,7 @@ var ChatController = class {
|
|
|
1448
1530
|
} else {
|
|
1449
1531
|
this.status = "idle";
|
|
1450
1532
|
}
|
|
1533
|
+
this._onDidChangeState.fire();
|
|
1451
1534
|
this.panel?.post({ type: "statusChanged", status: this.status });
|
|
1452
1535
|
}
|
|
1453
1536
|
resolvePermission(requestId, decision) {
|
|
@@ -1503,20 +1586,100 @@ var ChatController = class {
|
|
|
1503
1586
|
}
|
|
1504
1587
|
};
|
|
1505
1588
|
|
|
1589
|
+
// src/chat/chatTreeProvider.ts
|
|
1590
|
+
var vscode7 = __toESM(require("vscode"));
|
|
1591
|
+
var ActionItem = class extends vscode7.TreeItem {
|
|
1592
|
+
constructor(label, description, icon, command2, tooltip) {
|
|
1593
|
+
super(label, vscode7.TreeItemCollapsibleState.None);
|
|
1594
|
+
this.contextValue = "urChatAction";
|
|
1595
|
+
this.description = description;
|
|
1596
|
+
this.iconPath = new vscode7.ThemeIcon(icon);
|
|
1597
|
+
this.tooltip = tooltip ?? `${label}${description ? ` - ${description}` : ""}`;
|
|
1598
|
+
this.command = command2;
|
|
1599
|
+
}
|
|
1600
|
+
};
|
|
1601
|
+
var InfoItem3 = class extends vscode7.TreeItem {
|
|
1602
|
+
constructor(label, description, icon = "comment-discussion") {
|
|
1603
|
+
super(label, vscode7.TreeItemCollapsibleState.None);
|
|
1604
|
+
this.contextValue = "urInfo";
|
|
1605
|
+
this.description = description;
|
|
1606
|
+
this.iconPath = new vscode7.ThemeIcon(icon);
|
|
1607
|
+
this.tooltip = `${label}${description ? ` - ${description}` : ""}`;
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
var ChatTreeProvider = class {
|
|
1611
|
+
constructor(chat) {
|
|
1612
|
+
this.chat = chat;
|
|
1613
|
+
}
|
|
1614
|
+
chat;
|
|
1615
|
+
_onDidChangeTreeData = new vscode7.EventEmitter();
|
|
1616
|
+
onDidChangeTreeData = this._onDidChangeTreeData.event;
|
|
1617
|
+
refresh() {
|
|
1618
|
+
this._onDidChangeTreeData.fire();
|
|
1619
|
+
}
|
|
1620
|
+
getTreeItem(item) {
|
|
1621
|
+
return item;
|
|
1622
|
+
}
|
|
1623
|
+
getChildren() {
|
|
1624
|
+
const snapshot = captureEditorSnapshot();
|
|
1625
|
+
const items = [
|
|
1626
|
+
new InfoItem3("Start a UR chat", "Ask about this workspace or attach editor context."),
|
|
1627
|
+
new ActionItem("New Chat", "Start a fresh UR session", "comment-add", {
|
|
1628
|
+
command: "urInlineDiffs.chat.new",
|
|
1629
|
+
title: "New Chat"
|
|
1630
|
+
}),
|
|
1631
|
+
new ActionItem("Open Chat", "Resume an existing session", "comment", {
|
|
1632
|
+
command: "urInlineDiffs.chat.open",
|
|
1633
|
+
title: "Open Chat"
|
|
1634
|
+
}),
|
|
1635
|
+
new ActionItem("Pick Model", "Choose provider and model", "symbol-variable", {
|
|
1636
|
+
command: "urInlineDiffs.pickModel",
|
|
1637
|
+
title: "Pick Model"
|
|
1638
|
+
})
|
|
1639
|
+
];
|
|
1640
|
+
if (snapshot.activeFile) {
|
|
1641
|
+
items.push(
|
|
1642
|
+
new ActionItem("Add Current File to Chat", snapshot.activeFile.path, "file-add", {
|
|
1643
|
+
command: "urInlineDiffs.chat.addFile",
|
|
1644
|
+
title: "Add Current File to Chat"
|
|
1645
|
+
})
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1648
|
+
if (snapshot.selection) {
|
|
1649
|
+
const lineRange = snapshot.selection.startLine === snapshot.selection.endLine ? `${snapshot.selection.path}:${snapshot.selection.startLine}` : `${snapshot.selection.path}:${snapshot.selection.startLine}-${snapshot.selection.endLine}`;
|
|
1650
|
+
items.push(
|
|
1651
|
+
new ActionItem("Add Selection to Chat", lineRange, "selection", {
|
|
1652
|
+
command: "urInlineDiffs.chat.addSelection",
|
|
1653
|
+
title: "Add Selection to Chat"
|
|
1654
|
+
})
|
|
1655
|
+
);
|
|
1656
|
+
}
|
|
1657
|
+
if (this.chat.isRequestRunning()) {
|
|
1658
|
+
items.push(
|
|
1659
|
+
new ActionItem("Cancel Current Chat Request", "Stop the running request", "stop-circle", {
|
|
1660
|
+
command: "urInlineDiffs.chat.cancel",
|
|
1661
|
+
title: "Cancel Current Chat Request"
|
|
1662
|
+
})
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
return items;
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1506
1669
|
// src/diffs/actions.ts
|
|
1507
|
-
var
|
|
1508
|
-
var
|
|
1670
|
+
var import_node_child_process4 = require("node:child_process");
|
|
1671
|
+
var fs3 = __toESM(require("node:fs"));
|
|
1509
1672
|
var import_node_util2 = require("node:util");
|
|
1510
|
-
var
|
|
1511
|
-
var execFileAsync2 = (0, import_node_util2.promisify)(
|
|
1673
|
+
var vscode8 = __toESM(require("vscode"));
|
|
1674
|
+
var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process4.execFile);
|
|
1512
1675
|
async function commentDiff(item, provider) {
|
|
1513
1676
|
const root = workspaceRoot();
|
|
1514
1677
|
const bundle = item?.bundle;
|
|
1515
1678
|
if (!root || !bundle) {
|
|
1516
|
-
|
|
1679
|
+
vscode8.window.showWarningMessage("No UR inline diff selected.");
|
|
1517
1680
|
return;
|
|
1518
1681
|
}
|
|
1519
|
-
const text = await
|
|
1682
|
+
const text = await vscode8.window.showInputBox({
|
|
1520
1683
|
title: `Comment on ${bundle.id}`,
|
|
1521
1684
|
prompt: "Comment text",
|
|
1522
1685
|
ignoreFocusOut: true
|
|
@@ -1525,7 +1688,7 @@ async function commentDiff(item, provider) {
|
|
|
1525
1688
|
const manifest = loadManifest(root);
|
|
1526
1689
|
const manifestBundle = manifest.diffs.find((diff) => diff.id === bundle.id);
|
|
1527
1690
|
if (!manifestBundle) {
|
|
1528
|
-
|
|
1691
|
+
vscode8.window.showErrorMessage(`UR inline diff not found: ${bundle.id}`);
|
|
1529
1692
|
return;
|
|
1530
1693
|
}
|
|
1531
1694
|
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1535,21 +1698,21 @@ async function commentDiff(item, provider) {
|
|
|
1535
1698
|
writeManifest(root, manifest);
|
|
1536
1699
|
writeBundleMetadata(root, manifestBundle);
|
|
1537
1700
|
provider.refresh();
|
|
1538
|
-
|
|
1701
|
+
vscode8.window.showInformationMessage(`Added UR comment to ${bundle.id}.`);
|
|
1539
1702
|
}
|
|
1540
1703
|
async function applyDiff(item, provider) {
|
|
1541
1704
|
const root = workspaceRoot();
|
|
1542
1705
|
const bundle = item?.bundle;
|
|
1543
1706
|
if (!root || !bundle) {
|
|
1544
|
-
|
|
1707
|
+
vscode8.window.showWarningMessage("No UR inline diff selected.");
|
|
1545
1708
|
return;
|
|
1546
1709
|
}
|
|
1547
1710
|
const patch = patchPath(root, bundle);
|
|
1548
|
-
if (!
|
|
1549
|
-
|
|
1711
|
+
if (!fs3.existsSync(patch)) {
|
|
1712
|
+
vscode8.window.showErrorMessage(`UR patch file missing for ${bundle.id}.`);
|
|
1550
1713
|
return;
|
|
1551
1714
|
}
|
|
1552
|
-
const choice = await
|
|
1715
|
+
const choice = await vscode8.window.showWarningMessage(
|
|
1553
1716
|
`Apply UR patch ${bundle.id} to your working tree? This modifies ${bundle.files?.length ?? 0} file(s).`,
|
|
1554
1717
|
{ modal: true },
|
|
1555
1718
|
"Apply"
|
|
@@ -1558,21 +1721,21 @@ async function applyDiff(item, provider) {
|
|
|
1558
1721
|
try {
|
|
1559
1722
|
await execFileAsync2("git", ["apply", "--whitespace=nowarn", patch], { cwd: root, shell: false });
|
|
1560
1723
|
} catch (error) {
|
|
1561
|
-
|
|
1724
|
+
vscode8.window.showErrorMessage(`Failed to apply UR patch ${bundle.id}: ${processErrorMessage(error)}`);
|
|
1562
1725
|
return;
|
|
1563
1726
|
}
|
|
1564
1727
|
try {
|
|
1565
1728
|
const { stdout } = await runUrCli(["ide", "diff", "approve", bundle.id], { cwd: root });
|
|
1566
1729
|
provider.refresh();
|
|
1567
1730
|
if (isNotFoundResult(stdout)) {
|
|
1568
|
-
|
|
1731
|
+
vscode8.window.showWarningMessage(
|
|
1569
1732
|
`Applied ${bundle.id} to disk, but no matching diff record was found to mark it approved.`
|
|
1570
1733
|
);
|
|
1571
1734
|
return;
|
|
1572
1735
|
}
|
|
1573
|
-
|
|
1736
|
+
vscode8.window.showInformationMessage(`Applied UR patch ${bundle.id}.`);
|
|
1574
1737
|
} catch (error) {
|
|
1575
|
-
|
|
1738
|
+
vscode8.window.showErrorMessage(
|
|
1576
1739
|
`Applied ${bundle.id} to disk, but failed to record approval: ${errorMessage(error)}`
|
|
1577
1740
|
);
|
|
1578
1741
|
}
|
|
@@ -1581,25 +1744,25 @@ async function rejectDiff(item, provider) {
|
|
|
1581
1744
|
const root = workspaceRoot();
|
|
1582
1745
|
const bundle = item?.bundle;
|
|
1583
1746
|
if (!root || !bundle) {
|
|
1584
|
-
|
|
1747
|
+
vscode8.window.showWarningMessage("No UR inline diff selected.");
|
|
1585
1748
|
return;
|
|
1586
1749
|
}
|
|
1587
1750
|
try {
|
|
1588
1751
|
const { stdout } = await runUrCli(["ide", "diff", "reject", bundle.id], { cwd: root });
|
|
1589
1752
|
provider.refresh();
|
|
1590
1753
|
if (isNotFoundResult(stdout)) {
|
|
1591
|
-
|
|
1754
|
+
vscode8.window.showErrorMessage(`UR inline diff not found: ${bundle.id}`);
|
|
1592
1755
|
return;
|
|
1593
1756
|
}
|
|
1594
|
-
|
|
1757
|
+
vscode8.window.showInformationMessage(`Rejected UR patch ${bundle.id} (no files changed).`);
|
|
1595
1758
|
} catch (error) {
|
|
1596
|
-
|
|
1759
|
+
vscode8.window.showErrorMessage(errorMessage(error));
|
|
1597
1760
|
}
|
|
1598
1761
|
}
|
|
1599
1762
|
async function showStatus(channel) {
|
|
1600
1763
|
const root = workspaceRoot();
|
|
1601
1764
|
if (!root) {
|
|
1602
|
-
|
|
1765
|
+
vscode8.window.showWarningMessage("Open a workspace folder to query UR status.");
|
|
1603
1766
|
return;
|
|
1604
1767
|
}
|
|
1605
1768
|
channel.clear();
|
|
@@ -1617,7 +1780,7 @@ function isNotFoundResult(stdout) {
|
|
|
1617
1780
|
}
|
|
1618
1781
|
|
|
1619
1782
|
// src/diffs/webview.ts
|
|
1620
|
-
var
|
|
1783
|
+
var vscode9 = __toESM(require("vscode"));
|
|
1621
1784
|
function renderDiffHtml(root, bundle) {
|
|
1622
1785
|
const patch = readPatch(root, bundle);
|
|
1623
1786
|
const comments = bundle.comments ?? [];
|
|
@@ -1665,36 +1828,200 @@ async function openDiff(item) {
|
|
|
1665
1828
|
const root = workspaceRoot();
|
|
1666
1829
|
const bundle = item?.bundle;
|
|
1667
1830
|
if (!root || !bundle) {
|
|
1668
|
-
|
|
1831
|
+
vscode9.window.showWarningMessage("No UR inline diff selected.");
|
|
1669
1832
|
return;
|
|
1670
1833
|
}
|
|
1671
|
-
const panel =
|
|
1834
|
+
const panel = vscode9.window.createWebviewPanel("urInlineDiff", `UR ${bundle.id}`, vscode9.ViewColumn.Active, {
|
|
1672
1835
|
enableScripts: false
|
|
1673
1836
|
});
|
|
1674
1837
|
const latest = loadBundleMetadata(root, bundle);
|
|
1675
1838
|
panel.webview.html = renderDiffHtml(root, latest);
|
|
1676
1839
|
}
|
|
1677
1840
|
|
|
1841
|
+
// src/model/modelPicker.ts
|
|
1842
|
+
var vscode10 = __toESM(require("vscode"));
|
|
1843
|
+
function isRecord2(value) {
|
|
1844
|
+
return typeof value === "object" && value !== null;
|
|
1845
|
+
}
|
|
1846
|
+
function parseProviderList(raw) {
|
|
1847
|
+
try {
|
|
1848
|
+
const data = JSON.parse(raw);
|
|
1849
|
+
if (!Array.isArray(data)) return [];
|
|
1850
|
+
return data.flatMap((entry) => {
|
|
1851
|
+
if (!isRecord2(entry) || typeof entry.id !== "string" || typeof entry.name !== "string") return [];
|
|
1852
|
+
return [
|
|
1853
|
+
{
|
|
1854
|
+
id: entry.id,
|
|
1855
|
+
name: entry.name,
|
|
1856
|
+
accessTypeLabel: typeof entry.accessTypeLabel === "string" ? entry.accessTypeLabel : void 0,
|
|
1857
|
+
providerKind: typeof entry.providerKind === "string" ? entry.providerKind : void 0,
|
|
1858
|
+
runtimeBackend: typeof entry.runtimeBackend === "string" ? entry.runtimeBackend : void 0
|
|
1859
|
+
}
|
|
1860
|
+
];
|
|
1861
|
+
});
|
|
1862
|
+
} catch {
|
|
1863
|
+
return [];
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
function parseProviderModels(raw) {
|
|
1867
|
+
try {
|
|
1868
|
+
const data = JSON.parse(raw);
|
|
1869
|
+
if (!isRecord2(data) || typeof data.provider !== "string" || !Array.isArray(data.models)) return void 0;
|
|
1870
|
+
const source = data.source === "live" || data.source === "cache" || data.source === "static" ? data.source : "static";
|
|
1871
|
+
return {
|
|
1872
|
+
provider: data.provider,
|
|
1873
|
+
source,
|
|
1874
|
+
warning: typeof data.warning === "string" ? data.warning : void 0,
|
|
1875
|
+
models: data.models.flatMap((model) => {
|
|
1876
|
+
if (!isRecord2(model) || typeof model.id !== "string") return [];
|
|
1877
|
+
return [
|
|
1878
|
+
{
|
|
1879
|
+
id: model.id,
|
|
1880
|
+
displayName: typeof model.displayName === "string" ? model.displayName : void 0,
|
|
1881
|
+
description: typeof model.description === "string" ? model.description : void 0,
|
|
1882
|
+
isDefault: Boolean(model.isDefault)
|
|
1883
|
+
}
|
|
1884
|
+
];
|
|
1885
|
+
})
|
|
1886
|
+
};
|
|
1887
|
+
} catch {
|
|
1888
|
+
return void 0;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
function parseProviderStatus(raw) {
|
|
1892
|
+
try {
|
|
1893
|
+
const data = JSON.parse(raw);
|
|
1894
|
+
if (!isRecord2(data)) return {};
|
|
1895
|
+
return {
|
|
1896
|
+
provider: typeof data.provider === "string" ? data.provider : void 0,
|
|
1897
|
+
model: typeof data.model === "string" ? data.model : void 0
|
|
1898
|
+
};
|
|
1899
|
+
} catch {
|
|
1900
|
+
return {};
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
function parseIdeStatus(raw) {
|
|
1904
|
+
try {
|
|
1905
|
+
const data = JSON.parse(raw);
|
|
1906
|
+
if (!isRecord2(data)) return {};
|
|
1907
|
+
const provider = isRecord2(data.provider) ? data.provider : {};
|
|
1908
|
+
return {
|
|
1909
|
+
model: typeof provider.model === "string" ? provider.model : void 0
|
|
1910
|
+
};
|
|
1911
|
+
} catch {
|
|
1912
|
+
return {};
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
function selectionError(error) {
|
|
1916
|
+
if (error instanceof Error) return error.message;
|
|
1917
|
+
return String(error);
|
|
1918
|
+
}
|
|
1919
|
+
async function pickProviderModel(cwd) {
|
|
1920
|
+
if (!cwd) {
|
|
1921
|
+
vscode10.window.showWarningMessage("Open a workspace folder to pick a UR model.");
|
|
1922
|
+
return;
|
|
1923
|
+
}
|
|
1924
|
+
const [{ stdout: providerStdout }, statusResult, ideStatusResult] = await Promise.all([
|
|
1925
|
+
runUrCliCapture(["provider", "list", "--json"], { cwd }),
|
|
1926
|
+
runUrCliCapture(["provider", "status", "--json"], { cwd }).catch(() => ({ stdout: "" })),
|
|
1927
|
+
runUrCliCapture(["ide", "status", "--json"], { cwd }).catch(() => ({ stdout: "" }))
|
|
1928
|
+
]);
|
|
1929
|
+
const providers = parseProviderList(providerStdout);
|
|
1930
|
+
if (providers.length === 0) {
|
|
1931
|
+
vscode10.window.showWarningMessage("No UR providers were reported by `ur provider list`.");
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1934
|
+
const providerStatus = parseProviderStatus(statusResult.stdout);
|
|
1935
|
+
const ideStatus = parseIdeStatus(ideStatusResult.stdout);
|
|
1936
|
+
const status = { provider: providerStatus.provider, model: providerStatus.model ?? ideStatus.model };
|
|
1937
|
+
const pickedProvider = await vscode10.window.showQuickPick(
|
|
1938
|
+
providers.map((provider) => ({
|
|
1939
|
+
label: provider.name,
|
|
1940
|
+
description: provider.id === status.provider ? "current" : provider.id,
|
|
1941
|
+
detail: [provider.accessTypeLabel, provider.providerKind, provider.runtimeBackend].filter(Boolean).join(" \xB7 "),
|
|
1942
|
+
provider
|
|
1943
|
+
})),
|
|
1944
|
+
{
|
|
1945
|
+
title: "UR: Pick Model",
|
|
1946
|
+
placeHolder: "Choose a provider first"
|
|
1947
|
+
}
|
|
1948
|
+
);
|
|
1949
|
+
if (!pickedProvider) return;
|
|
1950
|
+
let modelsStdout = "";
|
|
1951
|
+
try {
|
|
1952
|
+
const result = await runUrCliCapture(["provider", "models", pickedProvider.provider.id, "--json"], { cwd });
|
|
1953
|
+
modelsStdout = result.stdout;
|
|
1954
|
+
} catch (error) {
|
|
1955
|
+
vscode10.window.showWarningMessage(
|
|
1956
|
+
`UR could not list models for ${pickedProvider.provider.name}: ${selectionError(error)}`
|
|
1957
|
+
);
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
const modelResult = parseProviderModels(modelsStdout);
|
|
1961
|
+
if (!modelResult || modelResult.models.length === 0) {
|
|
1962
|
+
vscode10.window.showWarningMessage(
|
|
1963
|
+
modelResult?.warning ?? `No models are available for ${pickedProvider.provider.name}. Run "ur provider doctor ${pickedProvider.provider.id}" to troubleshoot.`
|
|
1964
|
+
);
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
if (modelResult.warning) {
|
|
1968
|
+
vscode10.window.showWarningMessage(modelResult.warning);
|
|
1969
|
+
}
|
|
1970
|
+
const pickedModel = await vscode10.window.showQuickPick(
|
|
1971
|
+
modelResult.models.map((model) => ({
|
|
1972
|
+
label: model.displayName ?? model.id,
|
|
1973
|
+
description: [
|
|
1974
|
+
model.id === status.model ? "current" : model.id,
|
|
1975
|
+
model.isDefault ? "default" : "",
|
|
1976
|
+
modelResult.source
|
|
1977
|
+
].filter(Boolean).join(" \xB7 "),
|
|
1978
|
+
detail: model.description,
|
|
1979
|
+
model
|
|
1980
|
+
})),
|
|
1981
|
+
{
|
|
1982
|
+
title: `UR: Pick Model for ${pickedProvider.provider.name}`,
|
|
1983
|
+
placeHolder: "Choose a model for this provider"
|
|
1984
|
+
}
|
|
1985
|
+
);
|
|
1986
|
+
if (!pickedModel) return;
|
|
1987
|
+
try {
|
|
1988
|
+
const { stdout } = await runUrCliCapture(
|
|
1989
|
+
["provider", "select-model", pickedProvider.provider.id, pickedModel.model.id, "--json"],
|
|
1990
|
+
{ cwd }
|
|
1991
|
+
);
|
|
1992
|
+
const parsed = JSON.parse(stdout);
|
|
1993
|
+
if (parsed.ok) {
|
|
1994
|
+
vscode10.window.showInformationMessage(
|
|
1995
|
+
`UR model set to ${parsed.model ?? pickedModel.model.id} for ${parsed.provider ?? pickedProvider.provider.id}.`
|
|
1996
|
+
);
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
vscode10.window.showErrorMessage(parsed.message ?? "UR could not save the selected model.");
|
|
2000
|
+
} catch (error) {
|
|
2001
|
+
vscode10.window.showErrorMessage(`UR could not save the selected model: ${selectionError(error)}`);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
|
|
1678
2005
|
// src/misc/quickCommands.ts
|
|
1679
|
-
var
|
|
2006
|
+
var vscode11 = __toESM(require("vscode"));
|
|
1680
2007
|
var UR_DOCS_URL = "https://github.com/Maitham16/UR#readme";
|
|
1681
2008
|
async function openSettings() {
|
|
1682
|
-
await
|
|
2009
|
+
await vscode11.commands.executeCommand("workbench.action.openSettings", "UR");
|
|
1683
2010
|
}
|
|
1684
2011
|
async function openDocs() {
|
|
1685
|
-
await
|
|
2012
|
+
await vscode11.env.openExternal(vscode11.Uri.parse(UR_DOCS_URL));
|
|
1686
2013
|
}
|
|
1687
2014
|
async function openArtifacts() {
|
|
1688
2015
|
const root = workspaceRoot();
|
|
1689
2016
|
if (!root) {
|
|
1690
|
-
|
|
2017
|
+
vscode11.window.showWarningMessage("Open a workspace folder to view UR artifacts.");
|
|
1691
2018
|
return;
|
|
1692
2019
|
}
|
|
1693
|
-
const uri =
|
|
2020
|
+
const uri = vscode11.Uri.joinPath(vscode11.Uri.file(root), ".ur");
|
|
1694
2021
|
try {
|
|
1695
|
-
await
|
|
2022
|
+
await vscode11.commands.executeCommand("revealInExplorer", uri);
|
|
1696
2023
|
} catch {
|
|
1697
|
-
|
|
2024
|
+
vscode11.window.showInformationMessage("No .ur directory yet \u2014 it is created the first time UR runs in this workspace.");
|
|
1698
2025
|
}
|
|
1699
2026
|
}
|
|
1700
2027
|
async function runSpecAction(chat) {
|
|
@@ -1705,7 +2032,7 @@ async function runWorkflowAction(chat) {
|
|
|
1705
2032
|
}
|
|
1706
2033
|
|
|
1707
2034
|
// src/options/agentOptionsPanel.ts
|
|
1708
|
-
var
|
|
2035
|
+
var vscode12 = __toESM(require("vscode"));
|
|
1709
2036
|
|
|
1710
2037
|
// src/options/agentOptions.ts
|
|
1711
2038
|
function ids(options) {
|
|
@@ -1793,7 +2120,7 @@ function deriveMultimodalSupport(providerId) {
|
|
|
1793
2120
|
// src/options/providerOptionsLoader.ts
|
|
1794
2121
|
var PROVIDER_KINDS = ["ur-native", "subscription-cli", "subscription-placeholder"];
|
|
1795
2122
|
var ACCESS_TYPES = ["subscription", "api", "local", "server"];
|
|
1796
|
-
function
|
|
2123
|
+
function isRecord3(value) {
|
|
1797
2124
|
return typeof value === "object" && value !== null;
|
|
1798
2125
|
}
|
|
1799
2126
|
function parseProviderListJson(raw) {
|
|
@@ -1806,7 +2133,7 @@ function parseProviderListJson(raw) {
|
|
|
1806
2133
|
if (!Array.isArray(data)) return [];
|
|
1807
2134
|
const options = [];
|
|
1808
2135
|
for (const entry of data) {
|
|
1809
|
-
if (!
|
|
2136
|
+
if (!isRecord3(entry)) continue;
|
|
1810
2137
|
if (typeof entry.id !== "string" || typeof entry.name !== "string") continue;
|
|
1811
2138
|
const providerKind = PROVIDER_KINDS.includes(entry.providerKind) ? entry.providerKind : "subscription-placeholder";
|
|
1812
2139
|
const accessType = ACCESS_TYPES.includes(entry.accessType) ? entry.accessType : "api";
|
|
@@ -1918,10 +2245,10 @@ var AgentOptionsPanel = class _AgentOptionsPanel {
|
|
|
1918
2245
|
}
|
|
1919
2246
|
static createOrShow(onRefresh) {
|
|
1920
2247
|
if (_AgentOptionsPanel.current && !_AgentOptionsPanel.current.disposed) {
|
|
1921
|
-
_AgentOptionsPanel.current.panel.reveal(
|
|
2248
|
+
_AgentOptionsPanel.current.panel.reveal(vscode12.ViewColumn.Active);
|
|
1922
2249
|
return _AgentOptionsPanel.current;
|
|
1923
2250
|
}
|
|
1924
|
-
const panel =
|
|
2251
|
+
const panel = vscode12.window.createWebviewPanel("urAgentOptions", "UR Agent Options", vscode12.ViewColumn.Active, {
|
|
1925
2252
|
enableScripts: true
|
|
1926
2253
|
});
|
|
1927
2254
|
const instance = new _AgentOptionsPanel(panel, onRefresh);
|
|
@@ -1939,7 +2266,7 @@ var AgentOptionsPanel = class _AgentOptionsPanel {
|
|
|
1939
2266
|
};
|
|
1940
2267
|
async function showAgentOptions(cwd) {
|
|
1941
2268
|
if (!cwd) {
|
|
1942
|
-
|
|
2269
|
+
vscode12.window.showWarningMessage("Open a workspace folder to view UR agent options.");
|
|
1943
2270
|
return;
|
|
1944
2271
|
}
|
|
1945
2272
|
let panel;
|
|
@@ -1954,9 +2281,9 @@ async function showAgentOptions(cwd) {
|
|
|
1954
2281
|
}
|
|
1955
2282
|
|
|
1956
2283
|
// src/review/reviewDiff.ts
|
|
1957
|
-
var
|
|
2284
|
+
var import_node_child_process5 = require("node:child_process");
|
|
1958
2285
|
var import_node_util3 = require("node:util");
|
|
1959
|
-
var
|
|
2286
|
+
var vscode13 = __toESM(require("vscode"));
|
|
1960
2287
|
|
|
1961
2288
|
// src/review/reviewPrompt.ts
|
|
1962
2289
|
var LARGE_DIFF_THRESHOLD = 2e4;
|
|
@@ -1972,7 +2299,7 @@ function buildReviewPrompt(diff) {
|
|
|
1972
2299
|
}
|
|
1973
2300
|
|
|
1974
2301
|
// src/review/reviewDiff.ts
|
|
1975
|
-
var execFileAsync3 = (0, import_node_util3.promisify)(
|
|
2302
|
+
var execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process5.execFile);
|
|
1976
2303
|
async function captureGitDiff(cwd) {
|
|
1977
2304
|
const { stdout } = await execFileAsync3("git", ["diff", "HEAD"], { cwd, shell: false });
|
|
1978
2305
|
return stdout;
|
|
@@ -1980,22 +2307,22 @@ async function captureGitDiff(cwd) {
|
|
|
1980
2307
|
async function reviewCurrentDiff(chat) {
|
|
1981
2308
|
const root = workspaceRoot();
|
|
1982
2309
|
if (!root) {
|
|
1983
|
-
|
|
2310
|
+
vscode13.window.showWarningMessage("Open a workspace folder to review a diff.");
|
|
1984
2311
|
return;
|
|
1985
2312
|
}
|
|
1986
2313
|
let diff;
|
|
1987
2314
|
try {
|
|
1988
2315
|
diff = await captureGitDiff(root);
|
|
1989
2316
|
} catch (error) {
|
|
1990
|
-
|
|
2317
|
+
vscode13.window.showErrorMessage(`Could not read the current git diff: ${processErrorMessage(error)}`);
|
|
1991
2318
|
return;
|
|
1992
2319
|
}
|
|
1993
2320
|
if (!diff.trim()) {
|
|
1994
|
-
|
|
2321
|
+
vscode13.window.showInformationMessage("No changes to review (working tree matches HEAD).");
|
|
1995
2322
|
return;
|
|
1996
2323
|
}
|
|
1997
2324
|
if (diff.length > LARGE_DIFF_THRESHOLD) {
|
|
1998
|
-
const choice = await
|
|
2325
|
+
const choice = await vscode13.window.showWarningMessage(
|
|
1999
2326
|
`The current diff is large (${diff.length.toLocaleString()} characters). Send it to UR for review?`,
|
|
2000
2327
|
{ modal: true },
|
|
2001
2328
|
"Send"
|
|
@@ -2006,7 +2333,7 @@ async function reviewCurrentDiff(chat) {
|
|
|
2006
2333
|
}
|
|
2007
2334
|
|
|
2008
2335
|
// src/search/searchQuickPick.ts
|
|
2009
|
-
var
|
|
2336
|
+
var vscode14 = __toESM(require("vscode"));
|
|
2010
2337
|
|
|
2011
2338
|
// src/search/actionRegistry.ts
|
|
2012
2339
|
var ACTION_REGISTRY = [
|
|
@@ -2020,6 +2347,7 @@ var ACTION_REGISTRY = [
|
|
|
2020
2347
|
{ id: "providerStatus", label: "Provider Status", commandId: "urInlineDiffs.status", description: "Show provider, model, and plugin status" },
|
|
2021
2348
|
{ id: "agentStatus", label: "Agent Status", commandId: "urInlineDiffs.agentStatus", description: "Open the UR agent status card" },
|
|
2022
2349
|
{ id: "agentOptions", label: "Agent Options", commandId: "urInlineDiffs.agentOptions", description: "Open curated provider recommendations" },
|
|
2350
|
+
{ id: "pickModel", label: "Pick Model", commandId: "urInlineDiffs.pickModel", description: "Choose a provider-scoped UR model" },
|
|
2023
2351
|
{ id: "openSettings", label: "Open Settings", commandId: "urInlineDiffs.openSettings", description: "Open VS Code settings filtered to UR" },
|
|
2024
2352
|
{ id: "openDocs", label: "Open Docs", commandId: "urInlineDiffs.openDocs", description: "Open the UR documentation" },
|
|
2025
2353
|
{ id: "openArtifacts", label: "Open Artifacts", commandId: "urInlineDiffs.openArtifacts", description: "Reveal the .ur workspace directory" },
|
|
@@ -2035,26 +2363,26 @@ async function showSearchActions() {
|
|
|
2035
2363
|
detail: action.description,
|
|
2036
2364
|
commandId: action.commandId
|
|
2037
2365
|
}));
|
|
2038
|
-
const picked = await
|
|
2366
|
+
const picked = await vscode14.window.showQuickPick(items, {
|
|
2039
2367
|
title: "UR: Search Actions",
|
|
2040
2368
|
placeHolder: "Search UR actions",
|
|
2041
2369
|
matchOnDetail: true
|
|
2042
2370
|
});
|
|
2043
2371
|
if (!picked) return;
|
|
2044
|
-
await
|
|
2372
|
+
await vscode14.commands.executeCommand(picked.commandId);
|
|
2045
2373
|
}
|
|
2046
2374
|
|
|
2047
2375
|
// src/status/statusPanel.ts
|
|
2048
|
-
var
|
|
2376
|
+
var vscode15 = __toESM(require("vscode"));
|
|
2049
2377
|
|
|
2050
2378
|
// src/status/statusData.ts
|
|
2051
|
-
function
|
|
2379
|
+
function isRecord4(value) {
|
|
2052
2380
|
return typeof value === "object" && value !== null;
|
|
2053
2381
|
}
|
|
2054
2382
|
function safeParseRecord(raw) {
|
|
2055
2383
|
try {
|
|
2056
2384
|
const parsed = JSON.parse(raw);
|
|
2057
|
-
return
|
|
2385
|
+
return isRecord4(parsed) ? parsed : {};
|
|
2058
2386
|
} catch {
|
|
2059
2387
|
return {};
|
|
2060
2388
|
}
|
|
@@ -2067,8 +2395,8 @@ function asKnownBoolean(value) {
|
|
|
2067
2395
|
}
|
|
2068
2396
|
function parseIdeStatusJson(raw, fallbackWorkspaceRoot = "") {
|
|
2069
2397
|
const data = safeParseRecord(raw);
|
|
2070
|
-
const acpRaw =
|
|
2071
|
-
const providerRaw =
|
|
2398
|
+
const acpRaw = isRecord4(data.acp) ? data.acp : {};
|
|
2399
|
+
const providerRaw = isRecord4(data.provider) ? data.provider : {};
|
|
2072
2400
|
return {
|
|
2073
2401
|
workspaceRoot: typeof data.workspaceRoot === "string" && data.workspaceRoot ? data.workspaceRoot : fallbackWorkspaceRoot,
|
|
2074
2402
|
acp: {
|
|
@@ -2214,10 +2542,10 @@ var StatusPanel = class _StatusPanel {
|
|
|
2214
2542
|
}
|
|
2215
2543
|
static createOrShow(onRefresh) {
|
|
2216
2544
|
if (_StatusPanel.current && !_StatusPanel.current.disposed) {
|
|
2217
|
-
_StatusPanel.current.panel.reveal(
|
|
2545
|
+
_StatusPanel.current.panel.reveal(vscode15.ViewColumn.Active);
|
|
2218
2546
|
return _StatusPanel.current;
|
|
2219
2547
|
}
|
|
2220
|
-
const panel =
|
|
2548
|
+
const panel = vscode15.window.createWebviewPanel("urAgentStatus", "UR Agent Status", vscode15.ViewColumn.Active, {
|
|
2221
2549
|
enableScripts: true
|
|
2222
2550
|
});
|
|
2223
2551
|
const instance = new _StatusPanel(panel, onRefresh);
|
|
@@ -2235,7 +2563,7 @@ var StatusPanel = class _StatusPanel {
|
|
|
2235
2563
|
};
|
|
2236
2564
|
async function showAgentStatus(cwd) {
|
|
2237
2565
|
if (!cwd) {
|
|
2238
|
-
|
|
2566
|
+
vscode15.window.showWarningMessage("Open a workspace folder to view UR agent status.");
|
|
2239
2567
|
return;
|
|
2240
2568
|
}
|
|
2241
2569
|
let panel;
|
|
@@ -2250,7 +2578,7 @@ async function showAgentStatus(cwd) {
|
|
|
2250
2578
|
}
|
|
2251
2579
|
|
|
2252
2580
|
// src/verify/runVerifier.ts
|
|
2253
|
-
var
|
|
2581
|
+
var vscode16 = __toESM(require("vscode"));
|
|
2254
2582
|
|
|
2255
2583
|
// src/verify/verifierPrompt.ts
|
|
2256
2584
|
function buildVerifierPrompt() {
|
|
@@ -2265,7 +2593,7 @@ function buildVerifierPrompt() {
|
|
|
2265
2593
|
async function runVerifier(chat) {
|
|
2266
2594
|
const root = workspaceRoot();
|
|
2267
2595
|
if (!root) {
|
|
2268
|
-
|
|
2596
|
+
vscode16.window.showWarningMessage("Open a workspace folder to run the UR verifier.");
|
|
2269
2597
|
return;
|
|
2270
2598
|
}
|
|
2271
2599
|
await chat.runStructuredPrompt(buildVerifierPrompt());
|
|
@@ -2275,16 +2603,21 @@ async function runVerifier(chat) {
|
|
|
2275
2603
|
function activate(context) {
|
|
2276
2604
|
const diffTreeProvider = new DiffTreeProvider();
|
|
2277
2605
|
const actionsTreeProvider = new ActionsTreeProvider();
|
|
2278
|
-
const channel =
|
|
2279
|
-
const
|
|
2606
|
+
const channel = vscode17.window.createOutputChannel("UR");
|
|
2607
|
+
const chat = new ChatController();
|
|
2608
|
+
const chatTreeProvider = new ChatTreeProvider(chat);
|
|
2609
|
+
const chatTree = vscode17.window.createTreeView("urChat", {
|
|
2610
|
+
treeDataProvider: chatTreeProvider,
|
|
2611
|
+
showCollapseAll: false
|
|
2612
|
+
});
|
|
2613
|
+
const diffTree = vscode17.window.createTreeView("urInlineDiffs", {
|
|
2280
2614
|
treeDataProvider: diffTreeProvider,
|
|
2281
2615
|
showCollapseAll: false
|
|
2282
2616
|
});
|
|
2283
|
-
const actionsTree =
|
|
2617
|
+
const actionsTree = vscode17.window.createTreeView("urActions", {
|
|
2284
2618
|
treeDataProvider: actionsTreeProvider,
|
|
2285
2619
|
showCollapseAll: false
|
|
2286
2620
|
});
|
|
2287
|
-
const chat = new ChatController();
|
|
2288
2621
|
const bothDiffViews = {
|
|
2289
2622
|
refresh: () => {
|
|
2290
2623
|
diffTreeProvider.refresh();
|
|
@@ -2293,35 +2626,40 @@ function activate(context) {
|
|
|
2293
2626
|
};
|
|
2294
2627
|
context.subscriptions.push(
|
|
2295
2628
|
channel,
|
|
2629
|
+
chatTree,
|
|
2296
2630
|
diffTree,
|
|
2297
2631
|
actionsTree,
|
|
2298
2632
|
chat,
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2633
|
+
chat.onDidChangeState(() => chatTreeProvider.refresh()),
|
|
2634
|
+
vscode17.window.onDidChangeActiveTextEditor(() => chatTreeProvider.refresh()),
|
|
2635
|
+
vscode17.window.onDidChangeTextEditorSelection(() => chatTreeProvider.refresh()),
|
|
2636
|
+
vscode17.commands.registerCommand("urInlineDiffs.refresh", () => diffTreeProvider.refresh()),
|
|
2637
|
+
vscode17.commands.registerCommand("urInlineDiffs.open", (item) => openDiff(item)),
|
|
2638
|
+
vscode17.commands.registerCommand("urInlineDiffs.comment", (item) => commentDiff(item, bothDiffViews)),
|
|
2639
|
+
vscode17.commands.registerCommand("urInlineDiffs.apply", (item) => applyDiff(item, bothDiffViews)),
|
|
2640
|
+
vscode17.commands.registerCommand("urInlineDiffs.reject", (item) => rejectDiff(item, bothDiffViews)),
|
|
2641
|
+
vscode17.commands.registerCommand("urInlineDiffs.status", () => showStatus(channel)),
|
|
2642
|
+
vscode17.commands.registerCommand("urInlineDiffs.chat.new", () => chat.newChat()),
|
|
2643
|
+
vscode17.commands.registerCommand("urInlineDiffs.chat.open", () => chat.openChat()),
|
|
2644
|
+
vscode17.commands.registerCommand("urInlineDiffs.chat.cancel", () => chat.cancelCurrentRequest()),
|
|
2645
|
+
vscode17.commands.registerCommand("urInlineDiffs.chat.addFile", () => chat.addCurrentFileToChat()),
|
|
2646
|
+
vscode17.commands.registerCommand("urInlineDiffs.chat.addSelection", () => chat.addSelectionToChat()),
|
|
2647
|
+
vscode17.commands.registerCommand("urInlineDiffs.chat.explainSelection", () => chat.explainSelection()),
|
|
2648
|
+
vscode17.commands.registerCommand("urInlineDiffs.chat.fixSelection", () => chat.fixSelection()),
|
|
2649
|
+
vscode17.commands.registerCommand("urInlineDiffs.chat.generateTests", () => chat.generateTestsForSelection()),
|
|
2650
|
+
vscode17.commands.registerCommand("urInlineDiffs.agentStatus", () => showAgentStatus(workspaceRoot())),
|
|
2651
|
+
vscode17.commands.registerCommand("urInlineDiffs.agentOptions", () => showAgentOptions(workspaceRoot())),
|
|
2652
|
+
vscode17.commands.registerCommand("urInlineDiffs.reviewCurrentDiff", () => reviewCurrentDiff(chat)),
|
|
2653
|
+
vscode17.commands.registerCommand("urInlineDiffs.runVerifier", () => runVerifier(chat)),
|
|
2654
|
+
vscode17.commands.registerCommand("urInlineDiffs.searchActions", () => showSearchActions()),
|
|
2655
|
+
vscode17.commands.registerCommand("urInlineDiffs.pickModel", () => pickProviderModel(workspaceRoot())),
|
|
2656
|
+
vscode17.commands.registerCommand("urInlineDiffs.openSettings", () => openSettings()),
|
|
2657
|
+
vscode17.commands.registerCommand("urInlineDiffs.openDocs", () => openDocs()),
|
|
2658
|
+
vscode17.commands.registerCommand("urInlineDiffs.openArtifacts", () => openArtifacts()),
|
|
2659
|
+
vscode17.commands.registerCommand("urInlineDiffs.runSpec", () => runSpecAction(chat)),
|
|
2660
|
+
vscode17.commands.registerCommand("urInlineDiffs.runWorkflow", () => runWorkflowAction(chat)),
|
|
2661
|
+
vscode17.commands.registerCommand("urActions.refresh", () => actionsTreeProvider.refresh()),
|
|
2662
|
+
vscode17.commands.registerCommand("urActions.openBackgroundLog", (item) => openBackgroundLog(item))
|
|
2325
2663
|
);
|
|
2326
2664
|
}
|
|
2327
2665
|
function deactivate() {
|