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.
@@ -34,7 +34,7 @@ __export(extension_exports, {
34
34
  deactivate: () => deactivate
35
35
  });
36
36
  module.exports = __toCommonJS(extension_exports);
37
- var vscode15 = __toESM(require("vscode"));
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 import_node_child_process = require("node:child_process");
224
+ var import_node_child_process2 = require("node:child_process");
251
225
  var import_node_util = require("node:util");
252
- var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
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("ur", args, {
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("ur", args, {
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 formatUrCliError(args, error) {
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 `Failed to run \`ur ${args.join(" ")}\`: ${detail}. Ensure the UR CLI is installed and on PATH.`;
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 [new InfoItem2("No actions yet", "Diff bundles and background tasks will appear here", "pass")];
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 import_node_child_process2 = require("node:child_process");
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 = (command, args, options) => (0, import_node_child_process2.spawn)(command, args, options);
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 command = deps.command ?? "ur";
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: `Failed to start \`${command}\`: ${errorMessage2(error)}. Ensure the UR CLI is installed and on PATH.`
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(null, `Failed to run \`${command}\`: ${errorMessage2(error)}. Ensure the UR CLI is installed and on PATH.`);
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
- if (sawResult && resultIsError) return "UR reported an error completing this turn.";
601
- const trimmedStderr = stderr.trim();
602
- if (trimmedStderr) return trimmedStderr;
603
- return `UR exited with code ${exitCode ?? "unknown"} and produced no result.`;
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 path3 = __toESM(require("node:path"));
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 vscode16 = require("vscode");
650
- const workspaceRoot2 = vscode16.workspace.workspaceFolders?.[0]?.uri.fsPath;
651
- const editor = vscode16.window.activeTextEditor;
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 ? path3.relative(workspaceRoot2, absolutePath) : absolutePath;
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 fs3 = __toESM(require("node:fs"));
672
- var path4 = __toESM(require("node:path"));
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 path4.join(root, ".ur", "ide", "chat");
750
+ return path3.join(root, ".ur", "ide", "chat");
678
751
  }
679
752
  function manifestPath2(root) {
680
- return path4.join(chatRoot(root), "manifest.json");
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 = path4.join(chatRoot(root), "sessions");
688
- const target = path4.join(sessionsDir, `${id}.json`);
689
- const resolvedDir = path4.resolve(sessionsDir) + path4.sep;
690
- const resolvedTarget = path4.resolve(target);
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(fs3.readFileSync(file, "utf8"));
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
- fs3.mkdirSync(path4.dirname(file), { recursive: true });
703
- fs3.writeFileSync(file, `${JSON.stringify(value, null, 2)}
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 || !fs3.existsSync(file)) return null;
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 import_node_child_process3 = require("node:child_process");
1508
- var fs4 = __toESM(require("node:fs"));
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 vscode7 = __toESM(require("vscode"));
1511
- var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process3.execFile);
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
- vscode7.window.showWarningMessage("No UR inline diff selected.");
1679
+ vscode8.window.showWarningMessage("No UR inline diff selected.");
1517
1680
  return;
1518
1681
  }
1519
- const text = await vscode7.window.showInputBox({
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
- vscode7.window.showErrorMessage(`UR inline diff not found: ${bundle.id}`);
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
- vscode7.window.showInformationMessage(`Added UR comment to ${bundle.id}.`);
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
- vscode7.window.showWarningMessage("No UR inline diff selected.");
1707
+ vscode8.window.showWarningMessage("No UR inline diff selected.");
1545
1708
  return;
1546
1709
  }
1547
1710
  const patch = patchPath(root, bundle);
1548
- if (!fs4.existsSync(patch)) {
1549
- vscode7.window.showErrorMessage(`UR patch file missing for ${bundle.id}.`);
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 vscode7.window.showWarningMessage(
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
- vscode7.window.showErrorMessage(`Failed to apply UR patch ${bundle.id}: ${processErrorMessage(error)}`);
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
- vscode7.window.showWarningMessage(
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
- vscode7.window.showInformationMessage(`Applied UR patch ${bundle.id}.`);
1736
+ vscode8.window.showInformationMessage(`Applied UR patch ${bundle.id}.`);
1574
1737
  } catch (error) {
1575
- vscode7.window.showErrorMessage(
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
- vscode7.window.showWarningMessage("No UR inline diff selected.");
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
- vscode7.window.showErrorMessage(`UR inline diff not found: ${bundle.id}`);
1754
+ vscode8.window.showErrorMessage(`UR inline diff not found: ${bundle.id}`);
1592
1755
  return;
1593
1756
  }
1594
- vscode7.window.showInformationMessage(`Rejected UR patch ${bundle.id} (no files changed).`);
1757
+ vscode8.window.showInformationMessage(`Rejected UR patch ${bundle.id} (no files changed).`);
1595
1758
  } catch (error) {
1596
- vscode7.window.showErrorMessage(errorMessage(error));
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
- vscode7.window.showWarningMessage("Open a workspace folder to query UR status.");
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 vscode8 = __toESM(require("vscode"));
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
- vscode8.window.showWarningMessage("No UR inline diff selected.");
1831
+ vscode9.window.showWarningMessage("No UR inline diff selected.");
1669
1832
  return;
1670
1833
  }
1671
- const panel = vscode8.window.createWebviewPanel("urInlineDiff", `UR ${bundle.id}`, vscode8.ViewColumn.Active, {
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 vscode9 = __toESM(require("vscode"));
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 vscode9.commands.executeCommand("workbench.action.openSettings", "UR");
2009
+ await vscode11.commands.executeCommand("workbench.action.openSettings", "UR");
1683
2010
  }
1684
2011
  async function openDocs() {
1685
- await vscode9.env.openExternal(vscode9.Uri.parse(UR_DOCS_URL));
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
- vscode9.window.showWarningMessage("Open a workspace folder to view UR artifacts.");
2017
+ vscode11.window.showWarningMessage("Open a workspace folder to view UR artifacts.");
1691
2018
  return;
1692
2019
  }
1693
- const uri = vscode9.Uri.joinPath(vscode9.Uri.file(root), ".ur");
2020
+ const uri = vscode11.Uri.joinPath(vscode11.Uri.file(root), ".ur");
1694
2021
  try {
1695
- await vscode9.commands.executeCommand("revealInExplorer", uri);
2022
+ await vscode11.commands.executeCommand("revealInExplorer", uri);
1696
2023
  } catch {
1697
- vscode9.window.showInformationMessage("No .ur directory yet \u2014 it is created the first time UR runs in this workspace.");
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 vscode10 = __toESM(require("vscode"));
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 isRecord2(value) {
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 (!isRecord2(entry)) continue;
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(vscode10.ViewColumn.Active);
2248
+ _AgentOptionsPanel.current.panel.reveal(vscode12.ViewColumn.Active);
1922
2249
  return _AgentOptionsPanel.current;
1923
2250
  }
1924
- const panel = vscode10.window.createWebviewPanel("urAgentOptions", "UR Agent Options", vscode10.ViewColumn.Active, {
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
- vscode10.window.showWarningMessage("Open a workspace folder to view UR agent options.");
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 import_node_child_process4 = require("node:child_process");
2284
+ var import_node_child_process5 = require("node:child_process");
1958
2285
  var import_node_util3 = require("node:util");
1959
- var vscode11 = __toESM(require("vscode"));
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)(import_node_child_process4.execFile);
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
- vscode11.window.showWarningMessage("Open a workspace folder to review a diff.");
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
- vscode11.window.showErrorMessage(`Could not read the current git diff: ${processErrorMessage(error)}`);
2317
+ vscode13.window.showErrorMessage(`Could not read the current git diff: ${processErrorMessage(error)}`);
1991
2318
  return;
1992
2319
  }
1993
2320
  if (!diff.trim()) {
1994
- vscode11.window.showInformationMessage("No changes to review (working tree matches HEAD).");
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 vscode11.window.showWarningMessage(
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 vscode12 = __toESM(require("vscode"));
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 vscode12.window.showQuickPick(items, {
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 vscode12.commands.executeCommand(picked.commandId);
2372
+ await vscode14.commands.executeCommand(picked.commandId);
2045
2373
  }
2046
2374
 
2047
2375
  // src/status/statusPanel.ts
2048
- var vscode13 = __toESM(require("vscode"));
2376
+ var vscode15 = __toESM(require("vscode"));
2049
2377
 
2050
2378
  // src/status/statusData.ts
2051
- function isRecord3(value) {
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 isRecord3(parsed) ? parsed : {};
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 = isRecord3(data.acp) ? data.acp : {};
2071
- const providerRaw = isRecord3(data.provider) ? data.provider : {};
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(vscode13.ViewColumn.Active);
2545
+ _StatusPanel.current.panel.reveal(vscode15.ViewColumn.Active);
2218
2546
  return _StatusPanel.current;
2219
2547
  }
2220
- const panel = vscode13.window.createWebviewPanel("urAgentStatus", "UR Agent Status", vscode13.ViewColumn.Active, {
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
- vscode13.window.showWarningMessage("Open a workspace folder to view UR agent status.");
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 vscode14 = __toESM(require("vscode"));
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
- vscode14.window.showWarningMessage("Open a workspace folder to run the UR verifier.");
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 = vscode15.window.createOutputChannel("UR");
2279
- const diffTree = vscode15.window.createTreeView("urInlineDiffs", {
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 = vscode15.window.createTreeView("urActions", {
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
- vscode15.commands.registerCommand("urInlineDiffs.refresh", () => diffTreeProvider.refresh()),
2300
- vscode15.commands.registerCommand("urInlineDiffs.open", (item) => openDiff(item)),
2301
- vscode15.commands.registerCommand("urInlineDiffs.comment", (item) => commentDiff(item, bothDiffViews)),
2302
- vscode15.commands.registerCommand("urInlineDiffs.apply", (item) => applyDiff(item, bothDiffViews)),
2303
- vscode15.commands.registerCommand("urInlineDiffs.reject", (item) => rejectDiff(item, bothDiffViews)),
2304
- vscode15.commands.registerCommand("urInlineDiffs.status", () => showStatus(channel)),
2305
- vscode15.commands.registerCommand("urInlineDiffs.chat.new", () => chat.newChat()),
2306
- vscode15.commands.registerCommand("urInlineDiffs.chat.open", () => chat.openChat()),
2307
- vscode15.commands.registerCommand("urInlineDiffs.chat.cancel", () => chat.cancelCurrentRequest()),
2308
- vscode15.commands.registerCommand("urInlineDiffs.chat.addFile", () => chat.addCurrentFileToChat()),
2309
- vscode15.commands.registerCommand("urInlineDiffs.chat.addSelection", () => chat.addSelectionToChat()),
2310
- vscode15.commands.registerCommand("urInlineDiffs.chat.explainSelection", () => chat.explainSelection()),
2311
- vscode15.commands.registerCommand("urInlineDiffs.chat.fixSelection", () => chat.fixSelection()),
2312
- vscode15.commands.registerCommand("urInlineDiffs.chat.generateTests", () => chat.generateTestsForSelection()),
2313
- vscode15.commands.registerCommand("urInlineDiffs.agentStatus", () => showAgentStatus(workspaceRoot())),
2314
- vscode15.commands.registerCommand("urInlineDiffs.agentOptions", () => showAgentOptions(workspaceRoot())),
2315
- vscode15.commands.registerCommand("urInlineDiffs.reviewCurrentDiff", () => reviewCurrentDiff(chat)),
2316
- vscode15.commands.registerCommand("urInlineDiffs.runVerifier", () => runVerifier(chat)),
2317
- vscode15.commands.registerCommand("urInlineDiffs.searchActions", () => showSearchActions()),
2318
- vscode15.commands.registerCommand("urInlineDiffs.openSettings", () => openSettings()),
2319
- vscode15.commands.registerCommand("urInlineDiffs.openDocs", () => openDocs()),
2320
- vscode15.commands.registerCommand("urInlineDiffs.openArtifacts", () => openArtifacts()),
2321
- vscode15.commands.registerCommand("urInlineDiffs.runSpec", () => runSpecAction(chat)),
2322
- vscode15.commands.registerCommand("urInlineDiffs.runWorkflow", () => runWorkflowAction(chat)),
2323
- vscode15.commands.registerCommand("urActions.refresh", () => actionsTreeProvider.refresh()),
2324
- vscode15.commands.registerCommand("urActions.openBackgroundLog", (item) => openBackgroundLog(item))
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() {