ur-agent 1.45.3 → 1.45.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.45.4
4
+
5
+ - Added mandatory provider-first model selection for the first interactive run
6
+ in every workspace that has no project-local model. The validated provider
7
+ and model pair is saved to `.ur/settings.local.json` before the REPL starts.
8
+ - Prevented user-global and built-in defaults from silently choosing a model
9
+ for a fresh folder. Explicit CLI/environment, shared project, flag, managed,
10
+ agent, and restored-session model choices continue without interruption.
11
+ - Made fresh headless workspaces fail before model execution with actionable
12
+ guidance to run the picker or pass `--model <model>`; initialization-only and
13
+ resume flows remain non-blocking. AutoApprove behavior is unchanged.
14
+
3
15
  ## 1.45.3
4
16
 
5
17
  - Made slash-command resolution deterministic across bundled skills, plugins,
@@ -15,6 +27,10 @@
15
27
  guidance instead of invoking a fix agent repeatedly.
16
28
  - Serialized concurrent artifact-viewer startup so simultaneous callers share
17
29
  one server and one reported URL.
30
+ - Synchronized the user guides, static documentation site, and technical
31
+ specifications with the final command counts, source-priority rules,
32
+ `/skill` versus `/skills`, merged `/sandbox`, CI cwd behavior, and explicit
33
+ worktree publishing contract.
18
34
 
19
35
  ## 1.45.2
20
36
 
package/README.md CHANGED
@@ -214,16 +214,19 @@ Development build detected. To update, pull latest source or install from npm.
214
214
  Choose a model or Ollama host:
215
215
 
216
216
  ```sh
217
+ ur # first run opens provider/model selection
217
218
  ur --model qwen2.5-coder:7b
218
219
  ur --ollama-host http://192.168.1.50:11434
219
220
  ur --discover-ollama
220
221
  ```
221
222
 
222
- For Ollama sessions, model selection precedence is `OLLAMA_MODEL`, then
223
- `UR_MODEL`, then the model router over the configured Ollama host. Once a
224
- provider/model pair is selected with `/model` or `ur config set`, runtime
225
- requests use that provider backend; they do not fall back to Ollama unless
226
- `ollama` is the selected provider.
223
+ A fresh workspace never silently inherits a user-global or built-in model.
224
+ Interactive `ur` requires a provider/model choice and stores it in the
225
+ gitignored `.ur/settings.local.json`. Fresh print-mode runs require an explicit
226
+ `--model`, `OLLAMA_MODEL`, `UR_MODEL`, workspace setting, or managed setting.
227
+ For Ollama sessions, explicit environment precedence is `OLLAMA_MODEL`, then
228
+ `UR_MODEL`. Once selected, runtime requests use that provider backend; they do
229
+ not fall back to Ollama unless `ollama` is the selected provider.
227
230
 
228
231
  ### Legal Provider Auth
229
232
 
package/dist/cli.js CHANGED
@@ -61538,8 +61538,9 @@ function __resetOllamaRouteMemoForTests() {
61538
61538
  memoizedRoutedFastModel = undefined;
61539
61539
  }
61540
61540
  function getDefaultOllamaModel() {
61541
- if (process.env.OLLAMA_MODEL) {
61542
- return process.env.OLLAMA_MODEL;
61541
+ const explicitModel = process.env.OLLAMA_MODEL || process.env.UR_MODEL;
61542
+ if (explicitModel) {
61543
+ return explicitModel;
61543
61544
  }
61544
61545
  if (isOllamaAutoRouteEnabled()) {
61545
61546
  if (memoizedRoutedDefaultModel)
@@ -73086,7 +73087,7 @@ var init_auth = __esm(() => {
73086
73087
 
73087
73088
  // src/utils/userAgent.ts
73088
73089
  function getURCodeUserAgent() {
73089
- return `ur/${"1.45.3"}`;
73090
+ return `ur/${"1.45.4"}`;
73090
73091
  }
73091
73092
 
73092
73093
  // src/utils/workloadContext.ts
@@ -73108,7 +73109,7 @@ function getUserAgent() {
73108
73109
  const clientApp = process.env.UR_AGENT_SDK_CLIENT_APP ? `, client-app/${process.env.UR_AGENT_SDK_CLIENT_APP}` : "";
73109
73110
  const workload = getWorkload();
73110
73111
  const workloadSuffix = workload ? `, workload/${workload}` : "";
73111
- return `ur-cli/${"1.45.3"} (${process.env.USER_TYPE}, ${process.env.UR_CODE_ENTRYPOINT ?? "cli"}${agentSdkVersion}${clientApp}${workloadSuffix})`;
73112
+ return `ur-cli/${"1.45.4"} (${process.env.USER_TYPE}, ${process.env.UR_CODE_ENTRYPOINT ?? "cli"}${agentSdkVersion}${clientApp}${workloadSuffix})`;
73112
73113
  }
73113
73114
  function getMCPUserAgent() {
73114
73115
  const parts = [];
@@ -73122,7 +73123,7 @@ function getMCPUserAgent() {
73122
73123
  parts.push(`client-app/${process.env.UR_AGENT_SDK_CLIENT_APP}`);
73123
73124
  }
73124
73125
  const suffix = parts.length > 0 ? ` (${parts.join(", ")})` : "";
73125
- return `ur/${"1.45.3"}${suffix}`;
73126
+ return `ur/${"1.45.4"}${suffix}`;
73126
73127
  }
73127
73128
  function getWebFetchUserAgent() {
73128
73129
  return `UR-User (${getURCodeUserAgent()})`;
@@ -73260,7 +73261,7 @@ var init_user = __esm(() => {
73260
73261
  deviceId,
73261
73262
  sessionId: getSessionId(),
73262
73263
  email: getEmail(),
73263
- appVersion: "1.45.3",
73264
+ appVersion: "1.45.4",
73264
73265
  platform: getHostPlatformForAnalytics(),
73265
73266
  organizationUuid,
73266
73267
  accountUuid,
@@ -79835,7 +79836,7 @@ var init_metadata = __esm(() => {
79835
79836
  COMPOUND_OPERATOR_REGEX = /\s*(?:&&|\|\||[;|])\s*/;
79836
79837
  WHITESPACE_REGEX = /\s+/;
79837
79838
  getVersionBase = memoize_default(() => {
79838
- const match = "1.45.3".match(/^\d+\.\d+\.\d+(?:-[a-z]+)?/);
79839
+ const match = "1.45.4".match(/^\d+\.\d+\.\d+(?:-[a-z]+)?/);
79839
79840
  return match ? match[0] : undefined;
79840
79841
  });
79841
79842
  buildEnvContext = memoize_default(async () => {
@@ -79875,7 +79876,7 @@ var init_metadata = __esm(() => {
79875
79876
  isGithubAction: isEnvTruthy(process.env.GITHUB_ACTIONS),
79876
79877
  isURCodeAction: isEnvTruthy(process.env.UR_CODE_ACTION),
79877
79878
  isURAiAuth: isURAISubscriber(),
79878
- version: "1.45.3",
79879
+ version: "1.45.4",
79879
79880
  versionBase: getVersionBase(),
79880
79881
  buildTime: "",
79881
79882
  deploymentEnvironment: env2.detectDeploymentEnvironment(),
@@ -80545,7 +80546,7 @@ function initialize1PEventLogging() {
80545
80546
  const platform2 = getPlatform();
80546
80547
  const attributes = {
80547
80548
  [import_semantic_conventions4.ATTR_SERVICE_NAME]: "ur",
80548
- [import_semantic_conventions4.ATTR_SERVICE_VERSION]: "1.45.3"
80549
+ [import_semantic_conventions4.ATTR_SERVICE_VERSION]: "1.45.4"
80549
80550
  };
80550
80551
  if (platform2 === "wsl") {
80551
80552
  const wslVersion = getWslVersion();
@@ -80572,7 +80573,7 @@ function initialize1PEventLogging() {
80572
80573
  })
80573
80574
  ]
80574
80575
  });
80575
- firstPartyEventLogger = firstPartyEventLoggerProvider.getLogger("com.urhq.ur.events", "1.45.3");
80576
+ firstPartyEventLogger = firstPartyEventLoggerProvider.getLogger("com.urhq.ur.events", "1.45.4");
80576
80577
  }
80577
80578
  async function reinitialize1PEventLoggingIfConfigChanged() {
80578
80579
  if (!is1PEventLoggingEnabled() || !firstPartyEventLoggerProvider) {
@@ -86497,7 +86498,7 @@ function formatAgentTrendReport(report = buildAgentTrendReport()) {
86497
86498
  function formatA2AAgentCard(options = {}, pretty = true) {
86498
86499
  return JSON.stringify(buildA2AAgentCard(options), null, pretty ? 2 : 0);
86499
86500
  }
86500
- var urVersion = "1.45.3", coverage, priorityRoadmap;
86501
+ var urVersion = "1.45.4", coverage, priorityRoadmap;
86501
86502
  var init_trends = __esm(() => {
86502
86503
  coverage = [
86503
86504
  {
@@ -88363,7 +88364,7 @@ function getAttributionHeader(fingerprint) {
88363
88364
  if (!isAttributionHeaderEnabled()) {
88364
88365
  return "";
88365
88366
  }
88366
- const version2 = `${"1.45.3"}.${fingerprint}`;
88367
+ const version2 = `${"1.45.4"}.${fingerprint}`;
88367
88368
  const entrypoint = process.env.UR_CODE_ENTRYPOINT ?? "unknown";
88368
88369
  const cch = "";
88369
88370
  const workload = getWorkload();
@@ -196544,7 +196545,7 @@ function getTelemetryAttributes() {
196544
196545
  attributes["session.id"] = sessionId;
196545
196546
  }
196546
196547
  if (shouldIncludeAttribute("OTEL_METRICS_INCLUDE_VERSION")) {
196547
- attributes["app.version"] = "1.45.3";
196548
+ attributes["app.version"] = "1.45.4";
196548
196549
  }
196549
196550
  const oauthAccount = getOauthAccountInfo();
196550
196551
  if (oauthAccount) {
@@ -232025,7 +232026,7 @@ function getInstallationEnv() {
232025
232026
  return;
232026
232027
  }
232027
232028
  function getURCodeVersion() {
232028
- return "1.45.3";
232029
+ return "1.45.4";
232029
232030
  }
232030
232031
  async function getInstalledVSCodeExtensionVersion(command) {
232031
232032
  const { stdout } = await execFileNoThrow(command, ["--list-extensions", "--show-versions"], {
@@ -239407,7 +239408,7 @@ async function setupSdkMcpClients(sdkMcpConfigs, sendMcpMessage) {
239407
239408
  const client2 = new Client({
239408
239409
  name: "ur",
239409
239410
  title: "UR",
239410
- version: "1.45.3",
239411
+ version: "1.45.4",
239411
239412
  description: "UR-Nexus autonomous engineering workflow engine",
239412
239413
  websiteUrl: PRODUCT_URL
239413
239414
  }, {
@@ -239770,7 +239771,7 @@ var init_client5 = __esm(() => {
239770
239771
  const client2 = new Client({
239771
239772
  name: "ur",
239772
239773
  title: "UR",
239773
- version: "1.45.3",
239774
+ version: "1.45.4",
239774
239775
  description: "UR-Nexus autonomous engineering workflow engine",
239775
239776
  websiteUrl: PRODUCT_URL
239776
239777
  }, {
@@ -246807,9 +246808,9 @@ async function assertMinVersion() {
246807
246808
  if (false) {}
246808
246809
  try {
246809
246810
  const versionConfig = await getDynamicConfig_BLOCKS_ON_INIT("tengu_version_config", { minVersion: "0.0.0" });
246810
- if (versionConfig.minVersion && lt("1.45.3", versionConfig.minVersion)) {
246811
+ if (versionConfig.minVersion && lt("1.45.4", versionConfig.minVersion)) {
246811
246812
  console.error(`
246812
- It looks like your version of UR (${"1.45.3"}) needs an update.
246813
+ It looks like your version of UR (${"1.45.4"}) needs an update.
246813
246814
  A newer version (${versionConfig.minVersion} or higher) is required to continue.
246814
246815
 
246815
246816
  To update, please run:
@@ -247025,7 +247026,7 @@ async function installGlobalPackage(specificVersion) {
247025
247026
  logError2(new AutoUpdaterError("Another process is currently installing an update"));
247026
247027
  logEvent("tengu_auto_updater_lock_contention", {
247027
247028
  pid: process.pid,
247028
- currentVersion: "1.45.3"
247029
+ currentVersion: "1.45.4"
247029
247030
  });
247030
247031
  return "in_progress";
247031
247032
  }
@@ -247034,7 +247035,7 @@ async function installGlobalPackage(specificVersion) {
247034
247035
  if (!env2.isRunningWithBun() && env2.isNpmFromWindowsPath()) {
247035
247036
  logError2(new Error("Windows NPM detected in WSL environment"));
247036
247037
  logEvent("tengu_auto_updater_windows_npm_in_wsl", {
247037
- currentVersion: "1.45.3"
247038
+ currentVersion: "1.45.4"
247038
247039
  });
247039
247040
  console.error(`
247040
247041
  Error: Windows NPM detected in WSL
@@ -247569,7 +247570,7 @@ function detectLinuxGlobPatternWarnings() {
247569
247570
  }
247570
247571
  async function getDoctorDiagnostic() {
247571
247572
  const installationType = await getCurrentInstallationType();
247572
- const version2 = typeof MACRO !== "undefined" ? "1.45.3" : "unknown";
247573
+ const version2 = typeof MACRO !== "undefined" ? "1.45.4" : "unknown";
247573
247574
  const installationPath = await getInstallationPath();
247574
247575
  const invokedBinary = getInvokedBinary();
247575
247576
  const multipleInstallations = await detectMultipleInstallations();
@@ -248504,8 +248505,8 @@ async function updateLatest(channelOrVersion, forceReinstall = false) {
248504
248505
  const maxVersion = await getMaxVersion();
248505
248506
  if (maxVersion && gt(version2, maxVersion)) {
248506
248507
  logForDebugging(`Native installer: maxVersion ${maxVersion} is set, capping update from ${version2} to ${maxVersion}`);
248507
- if (gte("1.45.3", maxVersion)) {
248508
- logForDebugging(`Native installer: current version ${"1.45.3"} is already at or above maxVersion ${maxVersion}, skipping update`);
248508
+ if (gte("1.45.4", maxVersion)) {
248509
+ logForDebugging(`Native installer: current version ${"1.45.4"} is already at or above maxVersion ${maxVersion}, skipping update`);
248509
248510
  logEvent("tengu_native_update_skipped_max_version", {
248510
248511
  latency_ms: Date.now() - startTime,
248511
248512
  max_version: maxVersion,
@@ -248516,7 +248517,7 @@ async function updateLatest(channelOrVersion, forceReinstall = false) {
248516
248517
  version2 = maxVersion;
248517
248518
  }
248518
248519
  }
248519
- if (!forceReinstall && version2 === "1.45.3" && await versionIsAvailable(version2) && await isPossibleURBinary(executablePath)) {
248520
+ if (!forceReinstall && version2 === "1.45.4" && await versionIsAvailable(version2) && await isPossibleURBinary(executablePath)) {
248520
248521
  logForDebugging(`Found ${version2} at ${executablePath}, skipping install`);
248521
248522
  logEvent("tengu_native_update_complete", {
248522
248523
  latency_ms: Date.now() - startTime,
@@ -346376,7 +346377,7 @@ function Feedback({
346376
346377
  platform: env2.platform,
346377
346378
  gitRepo: envInfo.isGit,
346378
346379
  terminal: env2.terminal,
346379
- version: "1.45.3",
346380
+ version: "1.45.4",
346380
346381
  transcript: normalizeMessagesForAPI(messages),
346381
346382
  errors: sanitizedErrors,
346382
346383
  lastApiRequest: getLastAPIRequest(),
@@ -346568,7 +346569,7 @@ function Feedback({
346568
346569
  ", ",
346569
346570
  env2.terminal,
346570
346571
  ", v",
346571
- "1.45.3"
346572
+ "1.45.4"
346572
346573
  ]
346573
346574
  }, undefined, true, undefined, this)
346574
346575
  ]
@@ -346674,7 +346675,7 @@ ${sanitizedDescription}
346674
346675
  ` + `**Environment Info**
346675
346676
  ` + `- Platform: ${env2.platform}
346676
346677
  ` + `- Terminal: ${env2.terminal}
346677
- ` + `- Version: ${"1.45.3"}
346678
+ ` + `- Version: ${"1.45.4"}
346678
346679
  ` + `- Feedback ID: ${feedbackId}
346679
346680
  ` + `
346680
346681
  **Errors**
@@ -349785,7 +349786,7 @@ function buildPrimarySection() {
349785
349786
  }, undefined, false, undefined, this);
349786
349787
  return [{
349787
349788
  label: "Version",
349788
- value: "1.45.3"
349789
+ value: "1.45.4"
349789
349790
  }, {
349790
349791
  label: "Session name",
349791
349792
  value: nameValue
@@ -353115,7 +353116,7 @@ function Config({
353115
353116
  }
353116
353117
  }, undefined, false, undefined, this)
353117
353118
  }, undefined, false, undefined, this) : showSubmenu === "ChannelDowngrade" ? /* @__PURE__ */ jsx_dev_runtime178.jsxDEV(ChannelDowngradeDialog, {
353118
- currentVersion: "1.45.3",
353119
+ currentVersion: "1.45.4",
353119
353120
  onChoice: (choice) => {
353120
353121
  setShowSubmenu(null);
353121
353122
  setTabsHidden(false);
@@ -353127,7 +353128,7 @@ function Config({
353127
353128
  autoUpdatesChannel: "stable"
353128
353129
  };
353129
353130
  if (choice === "stay") {
353130
- newSettings.minimumVersion = "1.45.3";
353131
+ newSettings.minimumVersion = "1.45.4";
353131
353132
  }
353132
353133
  updateSettingsForSource("userSettings", newSettings);
353133
353134
  setSettingsData((prev_27) => ({
@@ -361197,7 +361198,7 @@ function HelpV2(t0) {
361197
361198
  let t6;
361198
361199
  if ($3[31] !== tabs) {
361199
361200
  t6 = /* @__PURE__ */ jsx_dev_runtime205.jsxDEV(Tabs, {
361200
- title: `UR v${"1.45.3"}`,
361201
+ title: `UR v${"1.45.4"}`,
361201
361202
  color: "professionalBlue",
361202
361203
  defaultTab: "general",
361203
361204
  children: tabs
@@ -361971,7 +361972,7 @@ function buildToolUseContext(tools, readFileStateCache) {
361971
361972
  async function handleInitialize(options2) {
361972
361973
  return {
361973
361974
  name: "UR",
361974
- version: "1.45.3",
361975
+ version: "1.45.4",
361975
361976
  protocolVersion: "0.1.0",
361976
361977
  workspaceRoot: options2.cwd,
361977
361978
  capabilities: {
@@ -382113,7 +382114,7 @@ function getAllReleaseNotes(changelogContent = getStoredChangelogFromMemory()) {
382113
382114
  return [];
382114
382115
  }
382115
382116
  }
382116
- async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.45.3") {
382117
+ async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.45.4") {
382117
382118
  if (process.env.USER_TYPE === "ant") {
382118
382119
  const changelog = "";
382119
382120
  if (changelog) {
@@ -382140,7 +382141,7 @@ async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.45.3")
382140
382141
  releaseNotes
382141
382142
  };
382142
382143
  }
382143
- function checkForReleaseNotesSync(lastSeenVersion, currentVersion = "1.45.3") {
382144
+ function checkForReleaseNotesSync(lastSeenVersion, currentVersion = "1.45.4") {
382144
382145
  if (process.env.USER_TYPE === "ant") {
382145
382146
  const changelog = "";
382146
382147
  if (changelog) {
@@ -385232,7 +385233,7 @@ function getRecentActivitySync() {
385232
385233
  return cachedActivity;
385233
385234
  }
385234
385235
  function getLogoDisplayData() {
385235
- const version2 = process.env.DEMO_VERSION ?? "1.45.3";
385236
+ const version2 = process.env.DEMO_VERSION ?? "1.45.4";
385236
385237
  const serverUrl = getDirectConnectServerUrl();
385237
385238
  const displayPath = process.env.DEMO_VERSION ? "/code/ur" : getDisplayPath(getCwd());
385238
385239
  const cwd2 = serverUrl ? `${displayPath} in ${serverUrl.replace(/^https?:\/\//, "")}` : displayPath;
@@ -386116,7 +386117,7 @@ function LogoV2() {
386116
386117
  if ($3[2] === Symbol.for("react.memo_cache_sentinel")) {
386117
386118
  t2 = () => {
386118
386119
  const currentConfig2 = getGlobalConfig();
386119
- if (currentConfig2.lastReleaseNotesSeen === "1.45.3") {
386120
+ if (currentConfig2.lastReleaseNotesSeen === "1.45.4") {
386120
386121
  return;
386121
386122
  }
386122
386123
  saveGlobalConfig(_temp327);
@@ -386801,12 +386802,12 @@ function LogoV2() {
386801
386802
  return t41;
386802
386803
  }
386803
386804
  function _temp327(current) {
386804
- if (current.lastReleaseNotesSeen === "1.45.3") {
386805
+ if (current.lastReleaseNotesSeen === "1.45.4") {
386805
386806
  return current;
386806
386807
  }
386807
386808
  return {
386808
386809
  ...current,
386809
- lastReleaseNotesSeen: "1.45.3"
386810
+ lastReleaseNotesSeen: "1.45.4"
386810
386811
  };
386811
386812
  }
386812
386813
  function _temp243(s_0) {
@@ -604849,7 +604850,7 @@ async function captureMemoryDiagnostics(trigger2, dumpNumber = 0) {
604849
604850
  smapsRollup,
604850
604851
  platform: process.platform,
604851
604852
  nodeVersion: process.version,
604852
- ccVersion: "1.45.3"
604853
+ ccVersion: "1.45.4"
604853
604854
  };
604854
604855
  }
604855
604856
  async function performHeapDump(trigger2 = "manual", dumpNumber = 0) {
@@ -605435,7 +605436,7 @@ var init_bridge_kick = __esm(() => {
605435
605436
  var call143 = async () => {
605436
605437
  return {
605437
605438
  type: "text",
605438
- value: "1.45.3"
605439
+ value: "1.45.4"
605439
605440
  };
605440
605441
  }, version2, version_default;
605441
605442
  var init_version = __esm(() => {
@@ -616545,7 +616546,7 @@ function generateHtmlReport(data, insights) {
616545
616546
  </html>`;
616546
616547
  }
616547
616548
  function buildExportData(data, insights, facets, remoteStats) {
616548
- const version3 = typeof MACRO !== "undefined" ? "1.45.3" : "unknown";
616549
+ const version3 = typeof MACRO !== "undefined" ? "1.45.4" : "unknown";
616549
616550
  const remote_hosts_collected = remoteStats?.hosts.filter((h2) => h2.sessionCount > 0).map((h2) => h2.name);
616550
616551
  const facets_summary = {
616551
616552
  total: facets.size,
@@ -620874,7 +620875,7 @@ var init_sessionStorage = __esm(() => {
620874
620875
  init_settings2();
620875
620876
  init_slowOperations();
620876
620877
  init_uuid();
620877
- VERSION5 = typeof MACRO !== "undefined" ? "1.45.3" : "unknown";
620878
+ VERSION5 = typeof MACRO !== "undefined" ? "1.45.4" : "unknown";
620878
620879
  MAX_TOMBSTONE_REWRITE_BYTES = 50 * 1024 * 1024;
620879
620880
  SKIP_FIRST_PROMPT_PATTERN = /^(?:\s*<[a-z][\w-]*[\s>]|\[Request interrupted by user[^\]]*\])/;
620880
620881
  EPHEMERAL_PROGRESS_TYPES = new Set([
@@ -622079,7 +622080,7 @@ var init_filesystem = __esm(() => {
622079
622080
  });
622080
622081
  getBundledSkillsRoot = memoize_default(function getBundledSkillsRoot2() {
622081
622082
  const nonce = randomBytes18(16).toString("hex");
622082
- return join211(getURTempDir(), "bundled-skills", "1.45.3", nonce);
622083
+ return join211(getURTempDir(), "bundled-skills", "1.45.4", nonce);
622083
622084
  });
622084
622085
  getResolvedWorkingDirPaths = memoize_default(getPathsForPermissionCheck);
622085
622086
  });
@@ -628374,7 +628375,7 @@ function computeFingerprint(messageText2, version3) {
628374
628375
  }
628375
628376
  function computeFingerprintFromMessages(messages) {
628376
628377
  const firstMessageText = extractFirstMessageText(messages);
628377
- return computeFingerprint(firstMessageText, "1.45.3");
628378
+ return computeFingerprint(firstMessageText, "1.45.4");
628378
628379
  }
628379
628380
  var FINGERPRINT_SALT = "59cf53e54c78";
628380
628381
  var init_fingerprint = () => {};
@@ -630248,7 +630249,7 @@ async function sideQuery(opts) {
630248
630249
  betas.push(STRUCTURED_OUTPUTS_BETA_HEADER);
630249
630250
  }
630250
630251
  const messageText2 = extractFirstUserMessageText(messages);
630251
- const fingerprint2 = computeFingerprint(messageText2, "1.45.3");
630252
+ const fingerprint2 = computeFingerprint(messageText2, "1.45.4");
630252
630253
  const attributionHeader = getAttributionHeader(fingerprint2);
630253
630254
  const systemBlocks = [
630254
630255
  attributionHeader ? { type: "text", text: attributionHeader } : null,
@@ -634985,7 +634986,7 @@ function buildSystemInitMessage(inputs) {
634985
634986
  slash_commands: inputs.commands.filter((c4) => c4.userInvocable !== false).map((c4) => c4.name),
634986
634987
  apiKeySource: getURHQApiKeyWithSource().source,
634987
634988
  betas: getSdkBetas(),
634988
- ur_version: "1.45.3",
634989
+ ur_version: "1.45.4",
634989
634990
  output_style: outputStyle2,
634990
634991
  agents: inputs.agents.map((agent) => agent.agentType),
634991
634992
  skills: inputs.skills.filter((s) => s.userInvocable !== false).map((skill2) => skill2.name),
@@ -648845,7 +648846,7 @@ var init_useVoiceEnabled = __esm(() => {
648845
648846
  function getSemverPart(version3) {
648846
648847
  return `${import_semver13.major(version3, { loose: true })}.${import_semver13.minor(version3, { loose: true })}.${import_semver13.patch(version3, { loose: true })}`;
648847
648848
  }
648848
- function useUpdateNotification(updatedVersion, initialVersion = "1.45.3") {
648849
+ function useUpdateNotification(updatedVersion, initialVersion = "1.45.4") {
648849
648850
  const [lastNotifiedSemver, setLastNotifiedSemver] = import_react228.useState(() => getSemverPart(initialVersion));
648850
648851
  if (!updatedVersion) {
648851
648852
  return null;
@@ -648894,7 +648895,7 @@ function AutoUpdater({
648894
648895
  return;
648895
648896
  }
648896
648897
  if (false) {}
648897
- const currentVersion = "1.45.3";
648898
+ const currentVersion = "1.45.4";
648898
648899
  const channel = getInitialSettings()?.autoUpdatesChannel ?? "latest";
648899
648900
  let latestVersion = await getLatestVersion(channel);
648900
648901
  const isDisabled = isAutoUpdaterDisabled();
@@ -649123,12 +649124,12 @@ function NativeAutoUpdater({
649123
649124
  logEvent("tengu_native_auto_updater_start", {});
649124
649125
  try {
649125
649126
  const maxVersion = await getMaxVersion();
649126
- if (maxVersion && gt("1.45.3", maxVersion)) {
649127
+ if (maxVersion && gt("1.45.4", maxVersion)) {
649127
649128
  const msg = await getMaxVersionMessage();
649128
649129
  setMaxVersionIssue(msg ?? "affects your version");
649129
649130
  }
649130
649131
  const result = await installLatest(channel);
649131
- const currentVersion = "1.45.3";
649132
+ const currentVersion = "1.45.4";
649132
649133
  const latencyMs = Date.now() - startTime;
649133
649134
  if (result.lockFailed) {
649134
649135
  logEvent("tengu_native_auto_updater_lock_contention", {
@@ -649265,17 +649266,17 @@ function PackageManagerAutoUpdater(t0) {
649265
649266
  const maxVersion = await getMaxVersion();
649266
649267
  if (maxVersion && latest && gt(latest, maxVersion)) {
649267
649268
  logForDebugging(`PackageManagerAutoUpdater: maxVersion ${maxVersion} is set, capping update from ${latest} to ${maxVersion}`);
649268
- if (gte("1.45.3", maxVersion)) {
649269
- logForDebugging(`PackageManagerAutoUpdater: current version ${"1.45.3"} is already at or above maxVersion ${maxVersion}, skipping update`);
649269
+ if (gte("1.45.4", maxVersion)) {
649270
+ logForDebugging(`PackageManagerAutoUpdater: current version ${"1.45.4"} is already at or above maxVersion ${maxVersion}, skipping update`);
649270
649271
  setUpdateAvailable(false);
649271
649272
  return;
649272
649273
  }
649273
649274
  latest = maxVersion;
649274
649275
  }
649275
- const hasUpdate = latest && !gte("1.45.3", latest) && !shouldSkipVersion(latest);
649276
+ const hasUpdate = latest && !gte("1.45.4", latest) && !shouldSkipVersion(latest);
649276
649277
  setUpdateAvailable(!!hasUpdate);
649277
649278
  if (hasUpdate) {
649278
- logForDebugging(`PackageManagerAutoUpdater: Update available ${"1.45.3"} -> ${latest}`);
649279
+ logForDebugging(`PackageManagerAutoUpdater: Update available ${"1.45.4"} -> ${latest}`);
649279
649280
  }
649280
649281
  };
649281
649282
  $3[0] = t1;
@@ -649309,7 +649310,7 @@ function PackageManagerAutoUpdater(t0) {
649309
649310
  wrap: "truncate",
649310
649311
  children: [
649311
649312
  "currentVersion: ",
649312
- "1.45.3"
649313
+ "1.45.4"
649313
649314
  ]
649314
649315
  }, undefined, true, undefined, this);
649315
649316
  $3[3] = verbose;
@@ -660006,7 +660007,7 @@ function buildStatusLineCommandInput(permissionMode, exceeds200kTokens, settings
660006
660007
  project_dir: getOriginalCwd(),
660007
660008
  added_dirs: addedDirs
660008
660009
  },
660009
- version: "1.45.3",
660010
+ version: "1.45.4",
660010
660011
  output_style: {
660011
660012
  name: outputStyleName
660012
660013
  },
@@ -660089,7 +660090,7 @@ function StatusLineInner({
660089
660090
  const taskValues = Object.values(tasks2);
660090
660091
  const taskRunningCount = taskValues.filter((task2) => task2.status === "running" || task2.status === "pending").length;
660091
660092
  const defaultStatusLineText = buildDefaultStatusBar({
660092
- version: "1.45.3",
660093
+ version: "1.45.4",
660093
660094
  providerLabel: providerRuntime.providerLabel,
660094
660095
  authMode: providerRuntime.authLabel,
660095
660096
  model: providerRuntime.model ?? renderModelName(mainLoopModel),
@@ -672082,7 +672083,7 @@ async function submitTranscriptShare(messages, trigger2, appearanceId) {
672082
672083
  } catch {}
672083
672084
  const data = {
672084
672085
  trigger: trigger2,
672085
- version: "1.45.3",
672086
+ version: "1.45.4",
672086
672087
  platform: process.platform,
672087
672088
  transcript,
672088
672089
  subagentTranscripts: Object.keys(subagentTranscripts).length > 0 ? subagentTranscripts : undefined,
@@ -684368,7 +684369,7 @@ function WelcomeV2() {
684368
684369
  dimColor: true,
684369
684370
  children: [
684370
684371
  "v",
684371
- "1.45.3"
684372
+ "1.45.4"
684372
684373
  ]
684373
684374
  }, undefined, true, undefined, this)
684374
684375
  ]
@@ -685628,7 +685629,7 @@ function completeOnboarding() {
685628
685629
  saveGlobalConfig((current) => ({
685629
685630
  ...current,
685630
685631
  hasCompletedOnboarding: true,
685631
- lastOnboardingVersion: "1.45.3"
685632
+ lastOnboardingVersion: "1.45.4"
685632
685633
  }));
685633
685634
  }
685634
685635
  function showDialog(root2, renderer) {
@@ -689975,6 +689976,23 @@ var init_ollamaDiscovery = __esm(() => {
689975
689976
  init_ollamaModels();
689976
689977
  });
689977
689978
 
689979
+ // src/services/providers/startupModelSelection.ts
689980
+ function isNonEmptyModel(value) {
689981
+ return typeof value === "string" && value.trim().length > 0;
689982
+ }
689983
+ function settingsSelectModel(settings) {
689984
+ return isNonEmptyModel(settings?.provider?.model) || isNonEmptyModel(settings?.model);
689985
+ }
689986
+ function shouldRequireStartupModelSelection(context4) {
689987
+ if (context4.isResume || context4.skipsModelExecution)
689988
+ return false;
689989
+ if (context4.explicitModels?.some(isNonEmptyModel))
689990
+ return false;
689991
+ if (context4.workspaceSettings?.some(settingsSelectModel))
689992
+ return false;
689993
+ return true;
689994
+ }
689995
+
689978
689996
  // src/utils/telemetry/skillLoadedEvent.ts
689979
689997
  async function logSkillsLoaded(cwd2, contextWindowTokens) {
689980
689998
  const skills2 = await getSkillToolCommands(cwd2);
@@ -690633,7 +690651,7 @@ function appendToLog(path24, message) {
690633
690651
  cwd: getFsImplementation().cwd(),
690634
690652
  userType: process.env.USER_TYPE,
690635
690653
  sessionId: getSessionId(),
690636
- version: "1.45.3"
690654
+ version: "1.45.4"
690637
690655
  };
690638
690656
  getLogWriter(path24).write(messageWithTimestamp);
690639
690657
  }
@@ -694792,8 +694810,8 @@ async function getEnvLessBridgeConfig() {
694792
694810
  }
694793
694811
  async function checkEnvLessBridgeMinVersion() {
694794
694812
  const cfg = await getEnvLessBridgeConfig();
694795
- if (cfg.min_version && lt("1.45.3", cfg.min_version)) {
694796
- return `Your version of UR (${"1.45.3"}) is too old for Remote Control.
694813
+ if (cfg.min_version && lt("1.45.4", cfg.min_version)) {
694814
+ return `Your version of UR (${"1.45.4"}) is too old for Remote Control.
694797
694815
  Version ${cfg.min_version} or higher is required. Run \`ur update\` to update.`;
694798
694816
  }
694799
694817
  return null;
@@ -695267,7 +695285,7 @@ async function initBridgeCore(params) {
695267
695285
  const rawApi = createBridgeApiClient({
695268
695286
  baseUrl,
695269
695287
  getAccessToken,
695270
- runnerVersion: "1.45.3",
695288
+ runnerVersion: "1.45.4",
695271
695289
  onDebug: logForDebugging,
695272
695290
  onAuth401,
695273
695291
  getTrustedDeviceToken
@@ -700949,7 +700967,7 @@ async function startMCPServer(cwd3, debug2, verbose) {
700949
700967
  setCwd(cwd3);
700950
700968
  const server2 = new Server({
700951
700969
  name: "ur/tengu",
700952
- version: "1.45.3"
700970
+ version: "1.45.4"
700953
700971
  }, {
700954
700972
  capabilities: {
700955
700973
  tools: {}
@@ -702991,7 +703009,7 @@ async function update() {
702991
703009
  logEvent("tengu_update_check", {});
702992
703010
  const diagnostic = await getDoctorDiagnostic();
702993
703011
  const result = await checkUpgradeStatus({
702994
- currentVersion: "1.45.3",
703012
+ currentVersion: "1.45.4",
702995
703013
  packageName: UR_AGENT_PACKAGE_NAME,
702996
703014
  installationType: diagnostic.installationType,
702997
703015
  latestVersion: () => getLatestNpmPackageVersion(UR_AGENT_PACKAGE_NAME)
@@ -704014,37 +704032,33 @@ ${inputPrompt}` : mainThreadAgentDefinition.initialPrompt;
704014
704032
  effectiveModel = parseUserSpecifiedModel(mainThreadAgentDefinition.model);
704015
704033
  }
704016
704034
  setMainLoopModelOverride(effectiveModel);
704017
- if (getAPIProvider() === "ollama" && !getUserSpecifiedModelSetting()) {
704035
+ const requiresStartupModelSelection = shouldRequireStartupModelSelection({
704036
+ explicitModels: [
704037
+ options2.model,
704038
+ process.env.URHQ_MODEL,
704039
+ process.env.OLLAMA_MODEL,
704040
+ process.env.UR_MODEL,
704041
+ mainThreadAgentDefinition?.model === "inherit" ? undefined : mainThreadAgentDefinition?.model
704042
+ ],
704043
+ workspaceSettings: [
704044
+ getSettingsForSource("projectSettings"),
704045
+ getSettingsForSource("localSettings"),
704046
+ getSettingsForSource("flagSettings"),
704047
+ getSettingsForSource("policySettings")
704048
+ ],
704049
+ isResume: Boolean(options2.continue || options2.resume || options2.fromPr || teleport || remote !== null),
704050
+ skipsModelExecution: initOnly
704051
+ });
704052
+ if (requiresStartupModelSelection && isNonInteractiveSession) {
704053
+ process.stderr.write(source_default.red("Error: No model has been selected for this workspace. Run `ur` interactively to choose a provider and model, or pass `--model <model>` for this run.\n"));
704054
+ process.exit(1);
704055
+ }
704056
+ if (!requiresStartupModelSelection && getAPIProvider() === "ollama" && !getUserSpecifiedModelSetting()) {
704018
704057
  await listOllamaModelNames(AbortSignal.timeout(750)).catch(() => {});
704019
704058
  }
704020
- setInitialMainLoopModel(getUserSpecifiedModelSetting() || null);
704021
- const initialMainLoopModel = getInitialMainLoopModel();
704022
- const resolvedInitialModel = parseUserSpecifiedModel(initialMainLoopModel ?? getDefaultMainLoopModel());
704023
- await refreshOllamaModelMetadata(resolvedInitialModel, {
704024
- timeoutMs: 750
704025
- });
704059
+ let initialMainLoopModel = getInitialMainLoopModel();
704060
+ let resolvedInitialModel;
704026
704061
  let advisorModel;
704027
- if (isAdvisorEnabled()) {
704028
- const advisorOption = canUserConfigureAdvisor() ? options2.advisor : undefined;
704029
- if (advisorOption) {
704030
- logForDebugging(`[AdvisorTool] --advisor ${advisorOption}`);
704031
- if (!modelSupportsAdvisor(resolvedInitialModel)) {
704032
- process.stderr.write(source_default.red(`Error: The model "${resolvedInitialModel}" does not support the advisor tool.
704033
- `));
704034
- process.exit(1);
704035
- }
704036
- const normalizedAdvisorModel = normalizeModelStringForAPI(parseUserSpecifiedModel(advisorOption));
704037
- if (!isValidAdvisorModel(normalizedAdvisorModel)) {
704038
- process.stderr.write(source_default.red(`Error: The model "${advisorOption}" cannot be used as an advisor.
704039
- `));
704040
- process.exit(1);
704041
- }
704042
- }
704043
- advisorModel = canUserConfigureAdvisor() ? advisorOption ?? getInitialAdvisorSetting() : advisorOption;
704044
- if (advisorModel) {
704045
- logForDebugging(`[AdvisorTool] Advisor model: ${advisorModel}`);
704046
- }
704047
- }
704048
704062
  if (isAgentSwarmsEnabled() && storedTeammateOpts?.agentId && storedTeammateOpts?.agentName && storedTeammateOpts?.teamName && storedTeammateOpts?.agentType) {
704049
704063
  const customAgent = agentDefinitions.activeAgents.find((a2) => a2.agentType === storedTeammateOpts.agentType);
704050
704064
  if (customAgent) {
@@ -704159,6 +704173,45 @@ ${customInstructions}` : customInstructions;
704159
704173
  });
704160
704174
  }
704161
704175
  }
704176
+ if (requiresStartupModelSelection) {
704177
+ const selectedModel = await showSetupDialog(root2, (done) => /* @__PURE__ */ jsx_dev_runtime495.jsxDEV(ProviderFirstModelPicker, {
704178
+ initial: null,
704179
+ headerText: "Choose a provider and model for this workspace. The validated choice is saved locally before the first session starts.",
704180
+ onSelect: (model) => {
704181
+ if (model)
704182
+ done(model);
704183
+ }
704184
+ }, undefined, false, undefined, this));
704185
+ effectiveModel = selectedModel;
704186
+ setMainLoopModelOverride(selectedModel);
704187
+ }
704188
+ setInitialMainLoopModel(getUserSpecifiedModelSetting() || null);
704189
+ initialMainLoopModel = getInitialMainLoopModel();
704190
+ resolvedInitialModel = parseUserSpecifiedModel(initialMainLoopModel ?? getDefaultMainLoopModel());
704191
+ await refreshOllamaModelMetadata(resolvedInitialModel, {
704192
+ timeoutMs: 750
704193
+ });
704194
+ if (isAdvisorEnabled()) {
704195
+ const advisorOption = canUserConfigureAdvisor() ? options2.advisor : undefined;
704196
+ if (advisorOption) {
704197
+ logForDebugging(`[AdvisorTool] --advisor ${advisorOption}`);
704198
+ if (!modelSupportsAdvisor(resolvedInitialModel)) {
704199
+ process.stderr.write(source_default.red(`Error: The model "${resolvedInitialModel}" does not support the advisor tool.
704200
+ `));
704201
+ process.exit(1);
704202
+ }
704203
+ const normalizedAdvisorModel = normalizeModelStringForAPI(parseUserSpecifiedModel(advisorOption));
704204
+ if (!isValidAdvisorModel(normalizedAdvisorModel)) {
704205
+ process.stderr.write(source_default.red(`Error: The model "${advisorOption}" cannot be used as an advisor.
704206
+ `));
704207
+ process.exit(1);
704208
+ }
704209
+ }
704210
+ advisorModel = canUserConfigureAdvisor() ? advisorOption ?? getInitialAdvisorSetting() : advisorOption;
704211
+ if (advisorModel) {
704212
+ logForDebugging(`[AdvisorTool] Advisor model: ${advisorModel}`);
704213
+ }
704214
+ }
704162
704215
  const bgRefreshThrottleMs = getFeatureValue_CACHED_MAY_BE_STALE("tengu_cicada_nap_ms", 0);
704163
704216
  const lastPrefetched = getGlobalConfig().startupPrefetchedAt ?? 0;
704164
704217
  const skipStartupPrefetches = isBareMode() || bgRefreshThrottleMs > 0 && Date.now() - lastPrefetched < bgRefreshThrottleMs;
@@ -704267,7 +704320,7 @@ ${customInstructions}` : customInstructions;
704267
704320
  }
704268
704321
  }
704269
704322
  logForDiagnosticsNoPII("info", "started", {
704270
- version: "1.45.3",
704323
+ version: "1.45.4",
704271
704324
  is_native_binary: isInBundledMode()
704272
704325
  });
704273
704326
  registerCleanup(async () => {
@@ -705053,7 +705106,7 @@ Usage: ur --remote "your task description"`, () => gracefulShutdown(1));
705053
705106
  pendingHookMessages
705054
705107
  }, renderAndRun);
705055
705108
  }
705056
- }).version("1.45.3 (UR-Nexus)", "-v, --version", "Output the version number");
705109
+ }).version("1.45.4 (UR-Nexus)", "-v, --version", "Output the version number");
705057
705110
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
705058
705111
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
705059
705112
  if (canUserConfigureAdvisor()) {
@@ -705954,6 +706007,7 @@ var init_main3 = __esm(() => {
705954
706007
  init_createDirectConnectSession();
705955
706008
  init_manager();
705956
706009
  init_promptSuggestion();
706010
+ init_ProviderFirstModelPicker();
705957
706011
  init_AppStateStore();
705958
706012
  init_onChangeAppState();
705959
706013
  init_ids();
@@ -705988,7 +706042,7 @@ if (false) {}
705988
706042
  async function main2() {
705989
706043
  const args = process.argv.slice(2);
705990
706044
  if (args.length === 1 && (args[0] === "--version" || args[0] === "-v" || args[0] === "-V")) {
705991
- console.log(`${"1.45.3"} (UR-Nexus)`);
706045
+ console.log(`${"1.45.4"} (UR-Nexus)`);
705992
706046
  return;
705993
706047
  }
705994
706048
  if (args[0] === "a2a" && args[1] === "serve" && !args.includes("--help") && !args.includes("-h")) {
@@ -81,6 +81,24 @@ The optional `provider.fallback` value is used only to print an explicit
81
81
  recovery recommendation in provider diagnostics. It never silently or
82
82
  automatically changes the active provider.
83
83
 
84
+ ## v1.45.4 Additions
85
+
86
+ - Fresh workspaces require a provider/model choice before their first
87
+ interactive session and persist the validated pair locally.
88
+ - Fresh headless workspaces fail before model execution unless a model is
89
+ supplied explicitly or by workspace/managed configuration.
90
+ - Resume, initialization-only, and explicit model paths remain uninterrupted;
91
+ AutoApprove behavior is unchanged.
92
+
93
+ ## v1.45.3 Additions
94
+
95
+ | Addition | Surface | What it adds |
96
+ | --- | --- | --- |
97
+ | Deterministic slash registry | `src/commands.ts`, `test/commandRegistryIntegrity.test.ts` | Resolves bundled, plugin, project, workflow, and built-in commands by explicit source priority; rejects duplicate canonical tokens, removes only conflicting aliases, validates every lazy loader, and keeps the technical command catalog complete. |
98
+ | Unified sandbox command | `/sandbox [status\|check\|init\|eval\|exclude]` | One interactive slash command now owns both the settings UI and text subcommands; the shell-facing `ur sandbox` implementation is shared rather than separately registered. |
99
+ | Actionable CI cwd handling | `ur ci-loop --cwd <path>` | Reports the absolute execution directory, retains assertion and stack context, and stops "No tests found" after one attempt without wasting a fix-agent run. |
100
+ | Explicit worktree completion | `/debug-v2`, `/refactor`, `/paper-implementation`, `/benchmark`, `/security-review`, `/dockerize`, `/latex-paper`, `/batch` | Keeps changes local, asks before the final full suite, and never commits, pushes, or opens a PR unless separately requested. |
101
+
84
102
  ## v1.25.x Additions
85
103
 
86
104
  | Addition | Surface | What it adds |
@@ -286,7 +304,7 @@ ur escalate plan "debug the race condition in the scheduler"
286
304
  ur escalate run "refactor the cache layer" --force-oracle
287
305
  ur escalate oracle "is this lock-free queue correct?"
288
306
  ur arena "implement the rate limiter" --agents 3 --apply
289
- ur ci-loop --command "bun test" --max-attempts 3
307
+ ur ci-loop --command "bun test" --cwd . --max-attempts 3
290
308
  ur artifacts capture-diff
291
309
  ur artifacts capture-tests --command "bun test"
292
310
  ur artifacts approve 1
@@ -48,7 +48,7 @@ ur context-pack remember --decision "Use manifest commands first"
48
48
  ur context-pack compress
49
49
  ur acp serve --port 8123
50
50
  ur exec "add tests for the parser" --concurrency 4 --json
51
- ur ci-loop --command "bun test" --dry-run
51
+ ur ci-loop --command "bun test" --cwd . --dry-run
52
52
  ur artifacts capture-diff
53
53
  ur artifacts capture-tests --command "bun test"
54
54
  ur claim-ledger validate
@@ -87,7 +87,7 @@ Inside an interactive session:
87
87
  | Spec-driven development | Covered | `ur spec` scaffolds requirements/design/tasks under `.ur/specs/`, tracks phase/approvals, and runs the Spec Kit / Kiro task list one task at a time | Add bidirectional sync with an external `specs/` directory |
88
88
  | Capability-aware model escalation | Covered | `ur escalate` selects fast/oracle tiers from `model-doctor`, runs routine work fast, and auto-escalates hard/failed work to the strong local model | Learn per-model success rates to tune the difficulty threshold |
89
89
  | Best-of-N agent judging | Covered | `ur arena` runs N agents per task in isolated worktrees and judges diffs with the self-review gate; winner is selectable/appliable | Add an optional model judge alongside the deterministic scorer |
90
- | Self-healing CI | Covered | `ur ci-loop` runs a command, summarizes failures, invokes a fix agent, and re-runs with bounded retries; commits/pushes are self-review gated | Wire to `ur trigger` so a failed CI webhook auto-launches the loop |
90
+ | Self-healing CI | Covered | `ur ci-loop` reports its resolved cwd, preserves assertion/stack context, stops no-test configuration failures before invoking a fixer, and re-runs real failures with bounded retries; commits/pushes require explicit flags and are self-review gated | Wire to `ur trigger` so a failed CI webhook can explicitly launch the loop |
91
91
  | Verifiable artifacts | Covered | `ur artifacts` records plans/diffs/test-runs with approve/reject/feedback under `.ur/artifacts/`; comments steer active background agents through stream-json inbox injection | Attach browser-QA screenshots and link artifacts to claim-ledger entries |
92
92
  | Native IDE review | Covered | `ur ide diff` writes `.ur/ide/diffs/` bundles and `extensions/vscode-ur-inline-diffs/` provides a VS Code tree/webview/comment surface | Add JetBrains packaging if demand appears |
93
93
  | ACP / IDE agent server | Covered | `ur acp serve|stop|status` exposes an HTTP+JSON-RPC agent server so VS Code/Cursor/Zed extensions can list tools, call tools, and submit tasks | Ship reference editor extensions |
@@ -105,7 +105,7 @@ ur spec run demo --all --dry-run
105
105
  ur arena "implement a debounce helper" --agents 2 --dry-run
106
106
  ur escalate run "refactor the cache layer" --force-oracle --dry-run
107
107
  ur test-first --dry-run
108
- ur ci-loop --command "bun test" --dry-run
108
+ ur ci-loop --command "bun test" --cwd . --dry-run
109
109
  ur artifacts capture-tests --command "bun test"
110
110
  ```
111
111
 
@@ -77,6 +77,15 @@ incompatible saved model instead of silently carrying it across providers. The
77
77
  saved provider/model pair controls the runtime backend for the next agent
78
78
  request; Ollama is only used when `ollama` is the selected provider.
79
79
 
80
+ The same provider-first picker is mandatory on the first interactive run in a
81
+ workspace with no model in `.ur/settings.json` or `.ur/settings.local.json`.
82
+ The result is validated and written to the gitignored local settings file.
83
+ User-global and built-in model defaults do not silently select a model for a
84
+ new folder. `--model`, `OLLAMA_MODEL`, `UR_MODEL`, agent configuration,
85
+ `--settings`, managed settings, and resumed sessions are deliberate selections
86
+ and therefore do not open the startup picker. Fresh `-p` runs without one of
87
+ those inputs fail with an actionable message before making a model request.
88
+
80
89
  Use this to inspect the active runtime path:
81
90
 
82
91
  ```sh
@@ -127,8 +136,8 @@ UR_MODEL=qwen2.5-coder:7b
127
136
  ```
128
137
 
129
138
  `OLLAMA_MODEL` selects the model name and takes precedence over `UR_MODEL` only
130
- for Ollama runtime sessions. If neither is set, UR lets its Ollama router choose
131
- from the model list advertised by the configured Ollama app.
139
+ for Ollama runtime sessions. If neither is set and the workspace has no saved
140
+ model, interactive startup asks and headless startup requires `--model`.
132
141
 
133
142
  ### Discovering LAN Ollama servers
134
143
 
@@ -56,6 +56,11 @@ context.
56
56
 
57
57
  The GitHub install path uses the bundled launcher in `dist/cli.js`, so `bun run bundle` must be run before packaging or pushing a release. `bun run release:check` verifies that `package.json`, `bunfig.toml`, the bundle, docs, and `node ./bin/ur.js --version` agree. The GitHub workflow keeps production bundle, release, package, and global-install checks behind the Bun test step; do not publish, tag, or push release artifacts until that workflow is green.
58
58
 
59
+ For a patch release, keep the version synchronized in `package.json`,
60
+ `bunfig.toml`, the VS Code extension manifest, the JetBrains Gradle build,
61
+ `documentation/index.html`, `technical/README.md`, and `CHANGELOG.md`. Rebuild
62
+ `dist/cli.js` after changing the version.
63
+
59
64
  ## Build
60
65
 
61
66
  ```sh
@@ -73,6 +78,7 @@ only the root README. Check:
73
78
  - `CHANGELOG.md`
74
79
  - `docs/`
75
80
  - `documentation/`
81
+ - `technical/`
76
82
  - `examples/`
77
83
  - extension and plugin README files when the feature affects them
78
84
 
@@ -80,6 +86,11 @@ For top-level commands, also update the static documentation site command data
80
86
  in `documentation/app.js` and any relevant tutorial section in
81
87
  `documentation/index.html`.
82
88
 
89
+ For slash-command changes, update `technical/03-slash-commands.md` and run
90
+ `bun test test/commandRegistryIntegrity.test.ts`. That test verifies unique
91
+ canonical names and aliases, non-empty descriptions, loadable implementations,
92
+ and coverage of every visible shipped command in the technical reference.
93
+
83
94
  For command surfaces that write `.ur/` state, update configuration and
84
95
  validation docs with the generated files and cleanup expectations.
85
96
 
@@ -182,12 +182,13 @@ ur sandbox check
182
182
  gates.
183
183
 
184
184
  ```sh
185
- ur ci-loop --command "bun test" --max-attempts 3
185
+ ur ci-loop --command "bun test" --cwd . --max-attempts 3
186
186
  ur test-first detect
187
187
  ```
188
188
 
189
189
  If the runner says "No tests found", check the working directory printed by
190
- the result and run from the test root or pass it explicitly:
190
+ the result and run from the test root or pass it explicitly. This configuration
191
+ failure stops after the first attempt and does not invoke a fix agent:
191
192
 
192
193
  ```sh
193
194
  ur ci-loop --command "bun test" --cwd ./packages/app --max-attempts 3
package/docs/USAGE.md CHANGED
@@ -8,6 +8,13 @@ UR is a terminal agent. Running `ur` opens an interactive session in the current
8
8
  ur
9
9
  ```
10
10
 
11
+ On the first interactive run in a folder without a workspace model, UR opens
12
+ the provider-first model picker before the REPL. A validated choice is saved to
13
+ `.ur/settings.local.json` and reused in that workspace. A global user model is
14
+ not silently copied into new folders. Shared `.ur/settings.json`, managed,
15
+ `--settings`, agent, CLI, environment, and resumed-session choices remain
16
+ explicit inputs and skip this one-time picker.
17
+
11
18
  Use interactive mode for iterative coding, debugging, research, and repository exploration. The session can read project instructions, use tools, call slash commands, and keep resumable conversation history.
12
19
 
13
20
  Useful options:
@@ -29,9 +36,13 @@ UR also accepts custom "Other" answers when the dialog includes one.
29
36
  Print mode is useful for scripts and shell pipelines:
30
37
 
31
38
  ```sh
32
- ur -p "write a changelog entry for the current diff"
39
+ ur -p --model qwen2.5-coder:7b "write a changelog entry for the current diff"
33
40
  ```
34
41
 
42
+ In a fresh workspace without a configured model, print mode exits before any
43
+ model request and tells the caller to pass `--model <model>` or run interactive
44
+ setup. This keeps automation deterministic instead of selecting a default.
45
+
35
46
  Output formats:
36
47
 
37
48
  ```sh
@@ -57,8 +68,9 @@ in this order:
57
68
  1. `OLLAMA_MODEL`
58
69
  2. `UR_MODEL`
59
70
 
60
- If neither variable is set and `ollama` is the selected provider, UR lets its
61
- Ollama router choose from the models exposed by your local Ollama app.
71
+ If neither variable is set, a fresh workspace requires an interactive choice.
72
+ After the provider/model pair has been stored locally, that exact pair is used
73
+ for subsequent sessions.
62
74
 
63
75
  You can also choose the model for a single session:
64
76
 
@@ -241,7 +253,9 @@ UR includes slash commands and CLI subcommands for common workflows:
241
253
  - `ur escalate ...` to plan, run, or ask an oracle model for hard tasks
242
254
  - `ur arena ...` to run multiple agents on the same task and select a winner
243
255
  - `ur test-first ...` to detect compile/test/lint commands, store failure traces, and install after-edit gates
244
- - `ur ci-loop ...` to run tests, repair failures, and rerun with a bounded loop
256
+ - `ur ci-loop ...` to run tests in an explicit working directory, repair real
257
+ failures, and rerun with a bounded loop. A "No tests found" result stops
258
+ after one attempt and reports how to correct `--cwd`.
245
259
  - `ur artifacts ...` to capture reviewable diffs, test runs, notes, and feedback
246
260
  - `ur ide diff ...` to capture editor-readable inline diff bundles
247
261
  - `ur acp ...` to start/stop/status the Agent Communication Protocol server for IDE extensions
@@ -334,7 +348,7 @@ ur context-pack remember --accepted "Use p-map for concurrency" --scope project
334
348
  ur context-pack compress
335
349
  ur acp serve --port 8123
336
350
  ur exec "add tests for the parser" --concurrency 4 --json
337
- ur ci-loop --command "bun test" --dry-run
351
+ ur ci-loop --command "bun test" --cwd . --dry-run
338
352
  ur artifacts capture-diff
339
353
  ur bg run "fix the flaky parser test" --worktree --dry-run
340
354
  ur worktree list
@@ -19,10 +19,28 @@ You need:
19
19
 
20
20
  ```sh
21
21
  ur --version
22
- # expected: the version from package.json, e.g. "1.35.1 (UR-Nexus)"
22
+ # expected for this release: "1.45.4 (UR-Nexus)"
23
23
  ```
24
24
 
25
- ## 0.1 Permission safety and context pack (1.19.0)
25
+ ## 0.1 First-workspace model selection (1.45.4)
26
+
27
+ In a new temporary directory, run `ur`. Expected: before the REPL appears, UR
28
+ opens the provider-first picker. After selecting a connected provider and one
29
+ of its models, `.ur/settings.local.json` contains both `provider.active` and
30
+ the selected model. A second `ur` run in the same directory reuses that local
31
+ pair without showing the startup picker.
32
+
33
+ Before making the interactive choice, the equivalent headless command must
34
+ exit non-zero without contacting a model:
35
+
36
+ ```sh
37
+ ur -p "say hi"
38
+ ```
39
+
40
+ Expected: `No model has been selected for this workspace`. Supplying
41
+ `--model <model>`, `OLLAMA_MODEL`, or `UR_MODEL` bypasses the gate for that run.
42
+
43
+ ## 0.2 Permission safety and context pack (1.19.0)
26
44
 
27
45
  In a project checkout:
28
46
 
@@ -47,7 +65,7 @@ Expected:
47
65
  - `remember` appends task memory entries under `.ur/context/task-memory.jsonl`.
48
66
  - `compress` writes `.ur/context/compressed.md`.
49
67
 
50
- ## 0.2 Test-first execution loop (1.18.0)
68
+ ## 0.3 Test-first execution loop (1.18.0)
51
69
 
52
70
  In a project checkout:
53
71
 
@@ -74,7 +92,7 @@ ur test-first --max-attempts 1
74
92
  Expected: a non-zero command creates a log under
75
93
  `.ur/test-first/traces/`, and the command reports `exhausted`, not `passed`.
76
94
 
77
- ## 0.3 Reliable repo editing (1.17.0)
95
+ ## 0.4 Reliable repo editing (1.17.0)
78
96
 
79
97
  In a disposable checkout:
80
98
 
@@ -92,7 +110,7 @@ Expected:
92
110
  - If the check command exits non-zero, every touched file is restored and the
93
111
  JSON result reports `"rolledBack": true`.
94
112
 
95
- ## 0.4 Network Ollama discovery (1.16.0)
113
+ ## 0.5 Network Ollama discovery (1.16.0)
96
114
 
97
115
  With at least one other Ollama server reachable on your LAN:
98
116
 
@@ -292,6 +310,9 @@ ur artifacts capture-tests --command "bun test"
292
310
  ```
293
311
 
294
312
  Expected: no `unknown option` or `too many arguments` parser errors.
313
+ The CI-loop result should include the resolved working directory. If that
314
+ directory has no matching tests, the run should stop after its first attempt
315
+ with `--cwd` guidance and must not launch a fix agent.
295
316
 
296
317
  ## What to do if any step fails
297
318
 
@@ -2,7 +2,7 @@ const featureGroups = [
2
2
  {
3
3
  title: 'Core agent runtime',
4
4
  tags: ['interactive', 'headless', 'models'],
5
- text: 'Interactive terminal sessions, one-shot print mode, JSON and stream-json output, resumable conversations, custom agents, model routing, local runtimes, and legal provider adapters.',
5
+ text: 'Interactive terminal sessions with first-workspace provider/model selection, deterministic one-shot print mode, JSON and stream-json output, resumable conversations, custom agents, model routing, local runtimes, and legal provider adapters.',
6
6
  commands: ['ur', 'ur -p', 'ur --resume', 'ur --continue', 'ur --model <model>', 'ur provider'],
7
7
  },
8
8
  {
@@ -72,15 +72,15 @@ const commands = [
72
72
  name: 'ur',
73
73
  category: 'Core',
74
74
  aliases: [],
75
- summary: 'Start an interactive UR-Nexus session in the current workspace.',
75
+ summary: 'Start an interactive session; a fresh workspace must choose and locally persist a validated provider/model pair first.',
76
76
  examples: ['ur', 'ur --model qwen3-coder:480b-cloud', 'ur --continue', 'ur --resume'],
77
77
  },
78
78
  {
79
79
  name: 'ur -p',
80
80
  category: 'Core',
81
81
  aliases: ['--print'],
82
- summary: 'Run one prompt headlessly and exit. This is the base mode for scripts, CI, evals, triggers, SDK calls, and A2A tasks.',
83
- examples: ['ur -p "Summarize this repository"', 'ur -p --output-format json "Review the current diff"', 'ur -p --json-schema \'{"type":"object"}\' "Return structured output"'],
82
+ summary: 'Run one prompt headlessly and exit. Fresh workspaces require an explicit or workspace-configured model instead of loading a default.',
83
+ examples: ['ur -p --model qwen3-coder:480b-cloud "Summarize this repository"', 'ur -p --model qwen3-coder:480b-cloud --output-format json "Review the current diff"', 'ur -p --model qwen3-coder:480b-cloud --json-schema \'{"type":"object"}\' "Return structured output"'],
84
84
  },
85
85
  {
86
86
  name: 'acp',
@@ -191,8 +191,8 @@ const commands = [
191
191
  name: 'ci-loop',
192
192
  category: 'Automation',
193
193
  aliases: ['heal'],
194
- summary: 'Run a build or test command, summarize failures, invoke a fix agent, and rerun with a bounded retry budget.',
195
- examples: ['ur ci-loop --command "bun test" --dry-run', 'ur ci-loop --command "bun test" --max-attempts 3', 'ur ci-loop --from-log failure.log --dry-run', 'ur ci-loop --command "bun test" --commit'],
194
+ summary: 'Run a build or test command in an explicit working directory, preserve useful failure context, and rerun real failures with a bounded fix budget. No-test configuration failures stop immediately.',
195
+ examples: ['ur ci-loop --command "bun test" --cwd . --dry-run', 'ur ci-loop --command "bun test" --cwd ./packages/app --max-attempts 3', 'ur ci-loop --from-log failure.log --cwd . --dry-run', 'ur ci-loop --command "bun test" --cwd . --json'],
196
196
  },
197
197
  {
198
198
  name: 'context-pack',
@@ -264,13 +264,6 @@ const commands = [
264
264
  summary: 'Track persistent long-horizon objectives with notes, linked workflows, and resumable execution.',
265
265
  examples: ['ur goal add release-docs --objective "Ship professional docs" --workflow docs', 'ur goal note release-docs --note "Command reference drafted"', 'ur goal resume release-docs --dry-run', 'ur goal done release-docs'],
266
266
  },
267
- {
268
- name: 'update',
269
- category: 'Ops',
270
- aliases: ['upgrade'],
271
- summary: 'Check npm for UR-Nexus updates.',
272
- examples: ['ur update', 'ur upgrade'],
273
- },
274
267
  {
275
268
  name: 'connect',
276
269
  category: 'Providers',
@@ -432,6 +425,41 @@ const commands = [
432
425
  summary: 'Parse GitHub, Slack, or generic webhook payloads and optionally launch a headless UR run.',
433
426
  examples: ['ur trigger parse --file payload.json --source github', 'ur trigger run --file payload.json --keyword /ur --dry-run', 'ur trigger run --file slack.json --max-turns 8'],
434
427
  },
428
+ {
429
+ name: 'audit',
430
+ category: 'Verification',
431
+ aliases: [],
432
+ summary: 'Export the hash-chained project audit trail or verify it for tampering.',
433
+ examples: ['ur audit export --format jsonl', 'ur audit export --format csv --out audit.csv', 'ur audit verify'],
434
+ },
435
+ {
436
+ name: 'cloud',
437
+ category: 'Agent Platform',
438
+ aliases: [],
439
+ summary: 'Run detached best-of-N tasks, inspect their results, and explicitly apply a selected winner.',
440
+ examples: ['ur cloud run "speed up parser" --attempts 3', 'ur cloud list', 'ur cloud show <id>', 'ur cloud apply <id>'],
441
+ },
442
+ {
443
+ name: 'recipe',
444
+ category: 'Automation',
445
+ aliases: ['recipes'],
446
+ summary: 'Create and run structured-output playbooks whose child result must satisfy the recipe schema.',
447
+ examples: ['ur recipe init triage', 'ur recipe list', 'ur recipe run triage "login returns 500"'],
448
+ },
449
+ {
450
+ name: 'thread',
451
+ category: 'Sessions',
452
+ aliases: ['threads'],
453
+ summary: 'Share a session transcript through the local artifacts server or list shared threads.',
454
+ examples: ['ur thread share', 'ur thread list', 'ur thread share <session-id>'],
455
+ },
456
+ {
457
+ name: 'wiki',
458
+ category: 'Knowledge',
459
+ aliases: ['repo-wiki'],
460
+ summary: 'Generate a living repository wiki and map, inspect status, or install its maintenance hook.',
461
+ examples: ['ur wiki generate', 'ur wiki map', 'ur wiki status', 'ur wiki install-hook'],
462
+ },
435
463
  {
436
464
  name: 'update',
437
465
  category: 'Ops',
@@ -472,7 +500,7 @@ const slashGroups = [
472
500
  {
473
501
  title: 'Agent skills',
474
502
  items: ['/debug-v2', '/refactor', '/paper-implementation', '/benchmark', '/security-review', '/dockerize', '/latex-paper', '/simplify', '/debug'],
475
- text: 'Bundled slash skills that dispatch focused agent work in isolated git worktrees with clean commits and PR output.',
503
+ text: 'Bundled slash skills that dispatch focused work in isolated git worktrees, keep changes local, ask before the final full suite, and publish only after a separate explicit request.',
476
504
  },
477
505
  {
478
506
  title: 'Memory and evidence',
@@ -486,8 +514,8 @@ const slashGroups = [
486
514
  },
487
515
  {
488
516
  title: 'Models, tools, and interop',
489
- items: ['/model', '/model-doctor', '/model-route', '/escalate', '/mcp', '/plugin', '/skills', '/sdk', '/a2a-card'],
490
- text: 'Pick models, inspect capabilities, escalate to oracle models, manage MCP/plugin extensions, and expose interop surfaces.',
517
+ items: ['/model', '/model-doctor', '/model-route', '/escalate', '/mcp', '/plugin', '/skills', '/skill', '/sdk', '/a2a-card'],
518
+ text: 'Pick models, inspect capabilities, manage MCP/plugin extensions, browse prompt skills with /skills, run executable workflows with /skill, and expose interop surfaces.',
491
519
  },
492
520
  {
493
521
  title: 'Security operations',
@@ -502,7 +530,7 @@ const slashGroups = [
502
530
  {
503
531
  title: 'Preferences and environment',
504
532
  items: ['/config', '/permissions', '/sandbox', '/mode', '/theme', '/vim', '/terminal-setup', '/usage', '/ide'],
505
- text: 'Configure permissions, sandboxing, UI preferences, IDE integration, and runtime environment details.',
533
+ text: 'Configure permissions and UI preferences; /sandbox combines its interactive settings with status, check, init, eval, and exclude operations.',
506
534
  },
507
535
  ];
508
536
 
@@ -662,8 +690,8 @@ const examples = [
662
690
  },
663
691
  {
664
692
  title: 'Self-healing CI',
665
- text: 'Run a test command, summarize failures, attempt a bounded fix loop, and rerun.',
666
- code: 'ur ci-loop --command "bun test" --dry-run\nur ci-loop --command "bun test" --max-attempts 3',
693
+ text: 'Run in an explicit cwd, preserve useful assertion and stack context, and attempt a bounded fix loop only for actionable failures.',
694
+ code: 'ur ci-loop --command "bun test" --cwd . --dry-run\nur ci-loop --command "bun test" --cwd ./packages/app --max-attempts 3',
667
695
  },
668
696
  {
669
697
  title: 'Test-first command evidence',
@@ -44,7 +44,7 @@
44
44
  <main id="content" class="content">
45
45
  <header class="topbar">
46
46
  <div>
47
- <p class="eyebrow">Version 1.45.3</p>
47
+ <p class="eyebrow">Version 1.45.4</p>
48
48
  <h1>UR-Nexus Documentation</h1>
49
49
  <p class="lead">A practical, tutorial-style reference for installing, configuring, automating, extending, and operating UR-Nexus.</p>
50
50
  </div>
@@ -89,6 +89,10 @@
89
89
  <strong>Test-first execution</strong>
90
90
  <span><code>ur test-first</code> detects compile/test/lint commands, stores failure traces, and installs edit-time verifier gates.</span>
91
91
  </article>
92
+ <article>
93
+ <strong>Deterministic commands</strong>
94
+ <span>The external runtime exposes 150 commands and 217 unique slash tokens; registry tests reject ambiguous names, broken loaders, and undocumented visible commands.</span>
95
+ </article>
92
96
  <article>
93
97
  <strong>Safety and context</strong>
94
98
  <span><code>ur safety</code> evaluates command risk. <code>ur context-pack</code> writes architecture context and task memory.</span>
@@ -122,13 +126,13 @@ ur --model qwen3-coder:480b-cloud</code></pre>
122
126
  <article class="step">
123
127
  <span>3</span>
124
128
  <h3>Run once in scripts</h3>
125
- <pre><code>ur -p "Summarize this repository"
126
- ur -p --output-format json "Review the current diff"</code></pre>
129
+ <pre><code>ur -p --model qwen3-coder:480b-cloud "Summarize this repository"
130
+ ur -p --model qwen3-coder:480b-cloud --output-format json "Review the current diff"</code></pre>
127
131
  </article>
128
132
  </div>
129
133
  <div class="callout">
130
134
  <strong>Runtime requirement</strong>
131
- <p>UR expects Bun. For local-first work, run a local Ollama app/server at <code>http://localhost:11434/api</code>. Set <code>OLLAMA_MODEL</code> or <code>UR_MODEL</code> to force a model route.</p>
135
+ <p>UR expects Bun. On the first interactive run in a workspace, choose a provider and model; UR validates and saves the pair locally before starting the session. Fresh print-mode workspaces require <code>--model</code> or another explicit model source.</p>
132
136
  </div>
133
137
  </section>
134
138
 
@@ -159,7 +163,7 @@ ur config set provider.fallback ollama</code></pre>
159
163
  </article>
160
164
  <article>
161
165
  <h3>Status bar and updates</h3>
162
- <pre><code>Ollama | llama3 | ask | main | update 1.37.3 available</code></pre>
166
+ <pre><code>Ollama | llama3 | ask | main | update 1.45.4 available</code></pre>
163
167
  <p>The interactive status bar shows only important runtime state: provider, model, mode, branch, active tasks, checks status when known, and update availability. It is hidden in CI, dumb terminals, and print mode.</p>
164
168
  </article>
165
169
  </div>
@@ -396,13 +400,14 @@ ur arena "fix the parser" --agents 3 --apply</code></pre>
396
400
  <article>
397
401
  <h3>Repair failing CI in a bounded loop</h3>
398
402
  <ol>
399
- <li>Run the build or test command.</li>
400
- <li>Summarize the failure and launch a fix attempt.</li>
403
+ <li>Run the build or test command in the printed working directory.</li>
404
+ <li>Preserve the assertion and stack context, then launch a fix attempt only for an actionable failure.</li>
401
405
  <li>Rerun until the command passes or the retry budget is exhausted.</li>
402
406
  </ol>
403
- <pre><code>ur ci-loop --command "bun test" --dry-run
404
- ur ci-loop --command "bun test" --max-attempts 3
405
- ur ci-loop --from-log failure.log --dry-run</code></pre>
407
+ <p>A <code>No tests found</code> result stops after the first attempt and points to <code>--cwd</code>; it does not invoke a fix agent.</p>
408
+ <pre><code>ur ci-loop --command "bun test" --cwd . --dry-run
409
+ ur ci-loop --command "bun test" --cwd ./packages/app --max-attempts 3
410
+ ur ci-loop --from-log failure.log --cwd . --dry-run</code></pre>
406
411
  </article>
407
412
 
408
413
  <article>
@@ -453,7 +458,7 @@ ur artifacts approve 1</code></pre>
453
458
  <pre><code>OLLAMA_MODEL=qwen3-coder:480b-cloud ur
454
459
  UR_MODEL=qwen3-coder:480b-cloud ur
455
460
  ur --model qwen2.5-coder:latest</code></pre>
456
- <p><code>OLLAMA_MODEL</code> wins over <code>UR_MODEL</code>. Without either, UR routes from local Ollama model inventory.</p>
461
+ <p><code>OLLAMA_MODEL</code> wins over <code>UR_MODEL</code>. Without an explicit or workspace model, interactive startup opens the provider/model picker and fresh print mode exits before model execution.</p>
457
462
  </article>
458
463
  <article>
459
464
  <h3>Permissions</h3>
@@ -554,6 +559,12 @@ ur agent-inspect --file session.jsonl
554
559
  ur artifacts list
555
560
  ur eval report starter
556
561
  ur claim-ledger validate</code></pre>
562
+ </article>
563
+ <article>
564
+ <h3>CI loop reports no tests</h3>
565
+ <p>Use the working directory printed in the result. The loop stops after one attempt because changing code cannot repair a test-discovery cwd error.</p>
566
+ <pre><code>ur ci-loop --command "bun test" --cwd . --max-attempts 3
567
+ ur ci-loop --command "bun test" --cwd ./packages/app --max-attempts 3</code></pre>
557
568
  </article>
558
569
  <article>
559
570
  <h3>New agent-platform command is missing</h3>
@@ -5,7 +5,7 @@ plugins {
5
5
  }
6
6
 
7
7
  group = "dev.urnexus"
8
- version = "1.45.3"
8
+ version = "1.45.4"
9
9
 
10
10
  repositories {
11
11
  mavenCentral()
@@ -2,7 +2,7 @@
2
2
  "name": "ur-inline-diffs",
3
3
  "displayName": "UR Inline Diffs",
4
4
  "description": "Review, apply, and reject UR inline diff bundles from .ur/ide/diffs inside VS Code.",
5
- "version": "1.45.3",
5
+ "version": "1.45.4",
6
6
  "publisher": "ur-nexus",
7
7
  "engines": {
8
8
  "vscode": "^1.92.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ur-agent",
3
- "version": "1.45.3",
3
+ "version": "1.45.4",
4
4
  "description": "UR-Nexus — autonomous engineering workflow engine (plan, execute, test, verify, document, benchmark, reproduce)",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.14",