ur-agent 1.80.1 → 1.80.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.80.3
4
+
5
+ - Restored visible task planning with a strict-hybrid default. Atomic,
6
+ low-risk requests still execute directly; requests with multiple outcomes,
7
+ sequencing, plan mode, delegation, project-sized work, or release/security/
8
+ migration/production risk must create an actionable task before the first
9
+ mutation. Read-only investigation remains unrestricted.
10
+ - The task gate now uses deterministic user-turn classification instead of
11
+ treating conversation length as complexity. It fails closed when task state
12
+ is unreadable, rechecks permission-rewritten tool input, preserves active
13
+ interrupted boards, and never deadlocks a custom tool profile that omits
14
+ `TaskCreate`.
15
+ - Operators can keep task tracking advisory with
16
+ `tasks.requireBeforeChanges.enabled=false`, or set `freeReads=0` to require a
17
+ task before every mutation. Approve All remains unchanged.
18
+
19
+ ## 1.80.2
20
+
21
+ - Repaired repeated `AskUserQuestion` validation loops when a model emits one
22
+ flattened `{label, header, description}` suggestion, one ordinary option, or
23
+ duplicate-only options. UR preserves the model's suggestion and adds only a
24
+ neutral `Different answer` rejection path; it never fabricates a second
25
+ domain choice or selects an answer for the user. Zero-option questions still
26
+ fail closed.
27
+
3
28
  ## 1.80.1
4
29
 
5
30
  - Removed the complete unreachable `ultraplan` implementation after its public
package/README.md CHANGED
@@ -81,6 +81,13 @@ useful. Each task records id, order, title, description, status, dependencies,
81
81
  assigned logical agent role, input, expected output, verification criteria, file
82
82
  targets, risk level, and whether approval is required.
83
83
 
84
+ Inside the interactive agent, task tracking uses a strict-hybrid default:
85
+ atomic low-risk work stays direct, while multi-outcome, sequenced, planned,
86
+ delegated, project-sized, and high-risk lifecycle work must create a visible
87
+ task before the first mutation. Reads stay unrestricted. Configure the gate
88
+ with `tasks.requireBeforeChanges`; `enabled=false` makes it advisory and
89
+ `freeReads=0` requires a task before every mutation.
90
+
84
91
  During real `ur exec` runs the task board streams when a task status changes,
85
92
  then appears again in the final report. Quiet/non-interactive runs can suppress
86
93
  streaming while preserving the final board. Public status labels are
package/dist/cli.js CHANGED
@@ -87675,6 +87675,33 @@ function dedupeQuestions(questions) {
87675
87675
  }
87676
87676
  return out;
87677
87677
  }
87678
+ function repairSingleOptionQuestions(questions) {
87679
+ return dedupeQuestions(questions).map((question) => {
87680
+ if (!isRecord2(question) || !Array.isArray(question.options))
87681
+ return question;
87682
+ if (question.options.length !== 1)
87683
+ return question;
87684
+ const onlyOption = question.options[0];
87685
+ if (!isRecord2(onlyOption) || typeof onlyOption.label !== "string") {
87686
+ return question;
87687
+ }
87688
+ const onlyLabel = duplicateKey(onlyOption.label);
87689
+ if (!onlyLabel)
87690
+ return question;
87691
+ const fallbackLabels = ["Different answer", "Reject suggestion"];
87692
+ const fallbackLabel = fallbackLabels.find((label) => duplicateKey(label) !== onlyLabel);
87693
+ return {
87694
+ ...question,
87695
+ options: [
87696
+ onlyOption,
87697
+ {
87698
+ label: fallbackLabel,
87699
+ description: "Reject the suggested option so the agent can ask for a different answer."
87700
+ }
87701
+ ]
87702
+ };
87703
+ });
87704
+ }
87678
87705
  function describeQuestionPayloadProblems(value) {
87679
87706
  const problems = [];
87680
87707
  if (!isRecord2(value)) {
@@ -87921,7 +87948,7 @@ function looksLikeOptionEntry(value) {
87921
87948
  return typeof entry.label === "string" || typeof entry.value === "string" || typeof entry.header === "string" || typeof entry.description === "string";
87922
87949
  }
87923
87950
  function recoverFlattenedOptions(input, entries) {
87924
- if (entries.length < 2 || !entries.every(looksLikeOptionEntry))
87951
+ if (entries.length < 1 || !entries.every(looksLikeOptionEntry))
87925
87952
  return null;
87926
87953
  const questionText = stringField(input, [
87927
87954
  "question",
@@ -88010,7 +88037,7 @@ function normalizeAskUserQuestionInput(value) {
88010
88037
  const entry = typeof raw === "string" || Array.isArray(raw) || objectValue(raw) ? normalizeQuestionInput({ question: questionText, options: raw }, index2) : null;
88011
88038
  return entry;
88012
88039
  });
88013
- const normalized = dedupeQuestions(questions.filter((entry) => entry !== null && typeof entry === "object"));
88040
+ const normalized = repairSingleOptionQuestions(questions.filter((entry) => entry !== null && typeof entry === "object"));
88014
88041
  if (normalized.length > 0) {
88015
88042
  return {
88016
88043
  questions: normalized.slice(0, 4),
@@ -88023,14 +88050,14 @@ function normalizeAskUserQuestionInput(value) {
88023
88050
  const normalized = input.questions.map((entry, index2) => normalizeQuestionInput(entry, index2)).filter((entry) => entry !== null && typeof entry === "object");
88024
88051
  if (normalized.length > 0) {
88025
88052
  return {
88026
- questions: dedupeQuestions(normalized),
88053
+ questions: repairSingleOptionQuestions(normalized),
88027
88054
  ...commonFields
88028
88055
  };
88029
88056
  }
88030
88057
  const recovered = recoverFlattenedOptions(input, input.questions);
88031
88058
  if (recovered && typeof recovered === "object") {
88032
88059
  return {
88033
- questions: dedupeQuestions([recovered]),
88060
+ questions: repairSingleOptionQuestions([recovered]),
88034
88061
  ...commonFields
88035
88062
  };
88036
88063
  }
@@ -88040,7 +88067,7 @@ function normalizeAskUserQuestionInput(value) {
88040
88067
  const singleQuestion = normalizeQuestionInput(input, 0);
88041
88068
  if (singleQuestion && singleQuestion !== input) {
88042
88069
  return {
88043
- questions: dedupeQuestions([singleQuestion]),
88070
+ questions: repairSingleOptionQuestions([singleQuestion]),
88044
88071
  ...commonFields
88045
88072
  };
88046
88073
  }
@@ -107757,7 +107784,7 @@ var init_auth = __esm(() => {
107757
107784
 
107758
107785
  // src/utils/userAgent.ts
107759
107786
  function getURCodeUserAgent() {
107760
- return `ur/${"1.80.1"}`;
107787
+ return `ur/${"1.80.3"}`;
107761
107788
  }
107762
107789
 
107763
107790
  // src/utils/workloadContext.ts
@@ -107779,7 +107806,7 @@ function getUserAgent() {
107779
107806
  const clientApp = process.env.UR_AGENT_SDK_CLIENT_APP ? `, client-app/${process.env.UR_AGENT_SDK_CLIENT_APP}` : "";
107780
107807
  const workload = getWorkload();
107781
107808
  const workloadSuffix = workload ? `, workload/${workload}` : "";
107782
- return `ur-cli/${"1.80.1"} (${process.env.USER_TYPE}, ${process.env.UR_CODE_ENTRYPOINT ?? "cli"}${agentSdkVersion}${clientApp}${workloadSuffix})`;
107809
+ return `ur-cli/${"1.80.3"} (${process.env.USER_TYPE}, ${process.env.UR_CODE_ENTRYPOINT ?? "cli"}${agentSdkVersion}${clientApp}${workloadSuffix})`;
107783
107810
  }
107784
107811
  function getMCPUserAgent() {
107785
107812
  const parts = [];
@@ -107793,7 +107820,7 @@ function getMCPUserAgent() {
107793
107820
  parts.push(`client-app/${process.env.UR_AGENT_SDK_CLIENT_APP}`);
107794
107821
  }
107795
107822
  const suffix = parts.length > 0 ? ` (${parts.join(", ")})` : "";
107796
- return `ur/${"1.80.1"}${suffix}`;
107823
+ return `ur/${"1.80.3"}${suffix}`;
107797
107824
  }
107798
107825
  function getWebFetchUserAgent() {
107799
107826
  return `UR-User (${getURCodeUserAgent()})`;
@@ -107931,7 +107958,7 @@ var init_user = __esm(() => {
107931
107958
  deviceId,
107932
107959
  sessionId: getSessionId(),
107933
107960
  email: getEmail(),
107934
- appVersion: "1.80.1",
107961
+ appVersion: "1.80.3",
107935
107962
  platform: getHostPlatformForAnalytics(),
107936
107963
  organizationUuid,
107937
107964
  accountUuid,
@@ -115818,7 +115845,7 @@ var init_metadata = __esm(() => {
115818
115845
  COMPOUND_OPERATOR_REGEX = /\s*(?:&&|\|\||[;|])\s*/;
115819
115846
  WHITESPACE_REGEX = /\s+/;
115820
115847
  getVersionBase = memoize_default(() => {
115821
- const match = "1.80.1".match(/^\d+\.\d+\.\d+(?:-[a-z]+)?/);
115848
+ const match = "1.80.3".match(/^\d+\.\d+\.\d+(?:-[a-z]+)?/);
115822
115849
  return match ? match[0] : undefined;
115823
115850
  });
115824
115851
  buildEnvContext = memoize_default(async () => {
@@ -115858,7 +115885,7 @@ var init_metadata = __esm(() => {
115858
115885
  isGithubAction: isEnvTruthy(process.env.GITHUB_ACTIONS),
115859
115886
  isURCodeAction: isEnvTruthy(process.env.UR_CODE_ACTION),
115860
115887
  isURAiAuth: isURAISubscriber(),
115861
- version: "1.80.1",
115888
+ version: "1.80.3",
115862
115889
  versionBase: getVersionBase(),
115863
115890
  buildTime: "",
115864
115891
  deploymentEnvironment: env2.detectDeploymentEnvironment(),
@@ -116528,7 +116555,7 @@ function initialize1PEventLogging() {
116528
116555
  const platform2 = getPlatform();
116529
116556
  const attributes = {
116530
116557
  [import_semantic_conventions4.ATTR_SERVICE_NAME]: "ur",
116531
- [import_semantic_conventions4.ATTR_SERVICE_VERSION]: "1.80.1"
116558
+ [import_semantic_conventions4.ATTR_SERVICE_VERSION]: "1.80.3"
116532
116559
  };
116533
116560
  if (platform2 === "wsl") {
116534
116561
  const wslVersion = getWslVersion();
@@ -116556,7 +116583,7 @@ function initialize1PEventLogging() {
116556
116583
  })
116557
116584
  ]
116558
116585
  });
116559
- firstPartyEventLogger = firstPartyEventLoggerProvider.getLogger("com.urhq.ur.events", "1.80.1");
116586
+ firstPartyEventLogger = firstPartyEventLoggerProvider.getLogger("com.urhq.ur.events", "1.80.3");
116560
116587
  }
116561
116588
  async function reinitialize1PEventLoggingIfConfigChanged() {
116562
116589
  if (!is1PEventLoggingEnabled() || !firstPartyEventLoggerProvider) {
@@ -119041,7 +119068,7 @@ var init_types2 = __esm(() => {
119041
119068
  requireBeforeChanges: exports_external.object({
119042
119069
  enabled: exports_external.boolean().optional(),
119043
119070
  freeReads: exports_external.number().optional()
119044
- }).optional().describe("Require a task list before any tool that changes the workspace (Edit, Write, Bash, ...). " + "Reads are never blocked, so the agent can investigate before planning; freeReads is how many " + "tool calls may run before the gate applies at all. Set enabled=false to make the task list advisory again.")
119071
+ }).optional().describe("Require a task list before any tool that changes the workspace (Edit, Write, Bash, ...). " + "The default strict-hybrid policy enforces classified multi-step, risky, delegated, and release work " + "while allowing positively classified atomic changes to proceed directly. Reads are never blocked. " + "Set freeReads=0 to require a task before every mutation, or enabled=false to make task tracking advisory.")
119045
119072
  }).optional().describe("Task list behaviour."),
119046
119073
  context: exports_external.object({
119047
119074
  pruneToolResults: exports_external.object({
@@ -126515,7 +126542,7 @@ function formatAgentTrendReport(report = buildAgentTrendReport()) {
126515
126542
  function formatA2AAgentCard(options = {}, pretty = true) {
126516
126543
  return JSON.stringify(buildA2AAgentCard(options), null, pretty ? 2 : 0);
126517
126544
  }
126518
- var urVersion = "1.80.1", researchSnapshotDate = "2026-08-10", coverage, priorityRoadmap;
126545
+ var urVersion = "1.80.3", researchSnapshotDate = "2026-08-10", coverage, priorityRoadmap;
126519
126546
  var init_trends = __esm(() => {
126520
126547
  init_a2aCardSignature();
126521
126548
  coverage = [
@@ -129405,7 +129432,7 @@ function getAttributionHeader(fingerprint) {
129405
129432
  if (!isAttributionHeaderEnabled()) {
129406
129433
  return "";
129407
129434
  }
129408
- const version2 = `${"1.80.1"}.${fingerprint}`;
129435
+ const version2 = `${"1.80.3"}.${fingerprint}`;
129409
129436
  const entrypoint = process.env.UR_CODE_ENTRYPOINT ?? "unknown";
129410
129437
  const cch = "";
129411
129438
  const workload = getWorkload();
@@ -184598,7 +184625,7 @@ var init_projectSafety = __esm(() => {
184598
184625
  function getInstruments() {
184599
184626
  if (instruments)
184600
184627
  return instruments;
184601
- const meter = import_api10.metrics.getMeter("ur-agent.gen_ai", "1.80.1");
184628
+ const meter = import_api10.metrics.getMeter("ur-agent.gen_ai", "1.80.3");
184602
184629
  instruments = {
184603
184630
  operationDuration: meter.createHistogram("gen_ai.client.operation.duration", {
184604
184631
  description: "GenAI operation duration.",
@@ -184696,7 +184723,7 @@ function genAiAgentAttributes() {
184696
184723
  "gen_ai.operation.name": GEN_AI_OPERATION_INVOKE_AGENT,
184697
184724
  "gen_ai.provider.name": "ur",
184698
184725
  "gen_ai.agent.name": "UR-Nexus",
184699
- "gen_ai.agent.version": "1.80.1"
184726
+ "gen_ai.agent.version": "1.80.3"
184700
184727
  };
184701
184728
  }
184702
184729
  function genAiWorkflowAttributes(workflowName, workflowRunId) {
@@ -184717,7 +184744,7 @@ function genAiWorkflowAttributes(workflowName, workflowRunId) {
184717
184744
  function startGenAiWorkflowSpan(workflowName, workflowRunId) {
184718
184745
  const attributes = genAiWorkflowAttributes(workflowName, workflowRunId);
184719
184746
  const name = typeof attributes["gen_ai.workflow.name"] === "string" ? `invoke_workflow ${attributes["gen_ai.workflow.name"]}` : GEN_AI_OPERATION_INVOKE_WORKFLOW;
184720
- return import_api10.trace.getTracer("ur-agent.gen_ai", "1.80.1").startSpan(name, { kind: import_api10.SpanKind.INTERNAL, attributes });
184747
+ return import_api10.trace.getTracer("ur-agent.gen_ai", "1.80.3").startSpan(name, { kind: import_api10.SpanKind.INTERNAL, attributes });
184721
184748
  }
184722
184749
  function endGenAiWorkflowSpan(span, options2 = {}) {
184723
184750
  try {
@@ -184755,7 +184782,7 @@ function startGenAiMemorySpan(operation, options2 = {}) {
184755
184782
  if (options2.recordCount !== undefined && Number.isInteger(options2.recordCount) && options2.recordCount >= 0) {
184756
184783
  attributes["gen_ai.memory.record.count"] = options2.recordCount;
184757
184784
  }
184758
- return import_api10.trace.getTracer("ur-agent.gen_ai", "1.80.1").startSpan(operation, { kind: import_api10.SpanKind.INTERNAL, attributes });
184785
+ return import_api10.trace.getTracer("ur-agent.gen_ai", "1.80.3").startSpan(operation, { kind: import_api10.SpanKind.INTERNAL, attributes });
184759
184786
  }
184760
184787
  function endGenAiMemorySpan(span, options2 = {}) {
184761
184788
  try {
@@ -278470,7 +278497,7 @@ function getTelemetryAttributes() {
278470
278497
  attributes["session.id"] = sessionId;
278471
278498
  }
278472
278499
  if (shouldIncludeAttribute("OTEL_METRICS_INCLUDE_VERSION")) {
278473
- attributes["app.version"] = "1.80.1";
278500
+ attributes["app.version"] = "1.80.3";
278474
278501
  }
278475
278502
  const oauthAccount = getOauthAccountInfo();
278476
278503
  if (oauthAccount) {
@@ -319461,7 +319488,7 @@ function getInstallationEnv() {
319461
319488
  return;
319462
319489
  }
319463
319490
  function getURCodeVersion() {
319464
- return "1.80.1";
319491
+ return "1.80.3";
319465
319492
  }
319466
319493
  async function getInstalledVSCodeExtensionVersion(command) {
319467
319494
  const { stdout } = await execFileNoThrow(command, ["--list-extensions", "--show-versions"], {
@@ -326831,7 +326858,7 @@ async function setupSdkMcpClients(sdkMcpConfigs, sendMcpMessage) {
326831
326858
  const client2 = new Client({
326832
326859
  name: "ur",
326833
326860
  title: "UR",
326834
- version: "1.80.1",
326861
+ version: "1.80.3",
326835
326862
  description: "UR-Nexus autonomous engineering workflow engine",
326836
326863
  websiteUrl: PRODUCT_URL
326837
326864
  }, {
@@ -327192,7 +327219,7 @@ var init_client5 = __esm(() => {
327192
327219
  const client2 = new Client({
327193
327220
  name: "ur",
327194
327221
  title: "UR",
327195
- version: "1.80.1",
327222
+ version: "1.80.3",
327196
327223
  description: "UR-Nexus autonomous engineering workflow engine",
327197
327224
  websiteUrl: PRODUCT_URL
327198
327225
  }, {
@@ -339930,7 +339957,7 @@ async function createRuntime() {
339930
339957
  bootstrapTelemetry();
339931
339958
  const resource = defaultResource().merge(detectResources({ detectors: [envDetector] })).merge(resourceFromAttributes({
339932
339959
  [import_semantic_conventions7.ATTR_SERVICE_NAME]: "ur-agent",
339933
- [import_semantic_conventions7.ATTR_SERVICE_VERSION]: "1.80.1"
339960
+ [import_semantic_conventions7.ATTR_SERVICE_VERSION]: "1.80.3"
339934
339961
  }));
339935
339962
  const tracerProvider = exporters.traces.length > 0 ? new BasicTracerProvider({
339936
339963
  resource,
@@ -339963,11 +339990,11 @@ async function createRuntime() {
339963
339990
  setMeterProvider(meterProvider);
339964
339991
  setLoggerProvider(loggerProvider);
339965
339992
  if (meterProvider) {
339966
- const meter = meterProvider.getMeter("ur-agent", "1.80.1");
339993
+ const meter = meterProvider.getMeter("ur-agent", "1.80.3");
339967
339994
  setMeter(meter, (name, options2) => meter.createCounter(name, options2));
339968
339995
  }
339969
339996
  if (loggerProvider) {
339970
- setEventLogger(loggerProvider.getLogger("ur-agent.events", "1.80.1"));
339997
+ setEventLogger(loggerProvider.getLogger("ur-agent.events", "1.80.3"));
339971
339998
  }
339972
339999
  if (!cleanupRegistered3) {
339973
340000
  cleanupRegistered3 = true;
@@ -340629,9 +340656,9 @@ async function assertMinVersion() {
340629
340656
  if (false) {}
340630
340657
  try {
340631
340658
  const versionConfig = await getDynamicConfig_BLOCKS_ON_INIT("tengu_version_config", { minVersion: "0.0.0" });
340632
- if (versionConfig.minVersion && lt("1.80.1", versionConfig.minVersion)) {
340659
+ if (versionConfig.minVersion && lt("1.80.3", versionConfig.minVersion)) {
340633
340660
  console.error(`
340634
- It looks like your version of UR (${"1.80.1"}) needs an update.
340661
+ It looks like your version of UR (${"1.80.3"}) needs an update.
340635
340662
  A newer version (${versionConfig.minVersion} or higher) is required to continue.
340636
340663
 
340637
340664
  To update, please run:
@@ -340847,7 +340874,7 @@ async function installGlobalPackage(specificVersion) {
340847
340874
  logError2(new AutoUpdaterError("Another process is currently installing an update"));
340848
340875
  logEvent("tengu_auto_updater_lock_contention", {
340849
340876
  pid: process.pid,
340850
- currentVersion: "1.80.1"
340877
+ currentVersion: "1.80.3"
340851
340878
  });
340852
340879
  return "in_progress";
340853
340880
  }
@@ -340856,7 +340883,7 @@ async function installGlobalPackage(specificVersion) {
340856
340883
  if (!env2.isRunningWithBun() && env2.isNpmFromWindowsPath()) {
340857
340884
  logError2(new Error("Windows NPM detected in WSL environment"));
340858
340885
  logEvent("tengu_auto_updater_windows_npm_in_wsl", {
340859
- currentVersion: "1.80.1"
340886
+ currentVersion: "1.80.3"
340860
340887
  });
340861
340888
  console.error(`
340862
340889
  Error: Windows NPM detected in WSL
@@ -341391,7 +341418,7 @@ function detectLinuxGlobPatternWarnings() {
341391
341418
  }
341392
341419
  async function getDoctorDiagnostic() {
341393
341420
  const installationType = await getCurrentInstallationType();
341394
- const version2 = typeof MACRO !== "undefined" ? "1.80.1" : "unknown";
341421
+ const version2 = typeof MACRO !== "undefined" ? "1.80.3" : "unknown";
341395
341422
  const installationPath = await getInstallationPath();
341396
341423
  const invokedBinary = getInvokedBinary();
341397
341424
  const multipleInstallations = await detectMultipleInstallations();
@@ -342326,8 +342353,8 @@ async function updateLatest(channelOrVersion, forceReinstall = false) {
342326
342353
  const maxVersion = await getMaxVersion();
342327
342354
  if (maxVersion && gt(version2, maxVersion)) {
342328
342355
  logForDebugging(`Native installer: maxVersion ${maxVersion} is set, capping update from ${version2} to ${maxVersion}`);
342329
- if (gte("1.80.1", maxVersion)) {
342330
- logForDebugging(`Native installer: current version ${"1.80.1"} is already at or above maxVersion ${maxVersion}, skipping update`);
342356
+ if (gte("1.80.3", maxVersion)) {
342357
+ logForDebugging(`Native installer: current version ${"1.80.3"} is already at or above maxVersion ${maxVersion}, skipping update`);
342331
342358
  logEvent("tengu_native_update_skipped_max_version", {
342332
342359
  latency_ms: Date.now() - startTime,
342333
342360
  max_version: maxVersion,
@@ -342338,7 +342365,7 @@ async function updateLatest(channelOrVersion, forceReinstall = false) {
342338
342365
  version2 = maxVersion;
342339
342366
  }
342340
342367
  }
342341
- if (!forceReinstall && version2 === "1.80.1" && await versionIsAvailable(version2) && await isPossibleURBinary(executablePath)) {
342368
+ if (!forceReinstall && version2 === "1.80.3" && await versionIsAvailable(version2) && await isPossibleURBinary(executablePath)) {
342342
342369
  logForDebugging(`Found ${version2} at ${executablePath}, skipping install`);
342343
342370
  logEvent("tengu_native_update_complete", {
342344
342371
  latency_ms: Date.now() - startTime,
@@ -402074,6 +402101,52 @@ function requestsRevisionOfCurrentTaskList(input) {
402074
402101
  function shouldKeepCurrentTaskList(input) {
402075
402102
  return requestsAppendToCurrentTaskList(input) || requestsContinueCurrentTaskList(input) || requestsRevisionOfCurrentTaskList(input);
402076
402103
  }
402104
+ function withoutCode(input) {
402105
+ return input.replace(/```[\s\S]*?```/gu, " ").replace(/`[^`\n]*`/gu, " ");
402106
+ }
402107
+ function proseOnly(input) {
402108
+ return withoutCode(input).replace(/\s+/gu, " ").trim();
402109
+ }
402110
+ function taskListRequirementReason(input) {
402111
+ const text2 = proseOnly(input);
402112
+ if (!text2)
402113
+ return;
402114
+ const optsOut = /\b(?:do not|don't)\s+(?:(?:create|make|maintain|show|start|use)\s+)?(?:a\s+)?(?:task|todo)(?:\s+(?:list|board))?\b/iu.test(text2) || /\bwithout\s+(?:(?:creating|making|maintaining|showing|starting|using)\s+)?(?:a\s+)?(?:task|todo)(?:\s+(?:list|board))?\b/iu.test(text2) || /\b(?:skip|no)\s+(?:the\s+|a\s+)?(?:task|todo)(?:\s+(?:list|board))?\b/iu.test(text2);
402115
+ if (optsOut)
402116
+ return;
402117
+ if (/\b(?:create|make|maintain|show|start|use|keep|track|add|append|put|queue)\b[^.!?]{0,100}\b(?:task|todo)\s+(?:list|board)\b/iu.test(text2) || /\b(?:add|append|put|queue)\s+(?:this|it)?\s*(?:to|on)?\s*(?:my|the|your)?\s*(?:tasks?|todos?)\b/iu.test(text2) || /\b(?:add|append|put|queue)\s+(?:this|it)\s+(?:to|on)\s+(?:the\s+|your\s+|my\s+)?(?:current|existing)\s+list\b/iu.test(text2) || /\b(?:create|make|use|track)\s+(?:the\s+|a\s+|your\s+)?(?:tasks?|todos?)\b/iu.test(text2) || /\b(?:tasks?|todos?)\s+first\b/iu.test(text2)) {
402118
+ return "explicit task tracking request";
402119
+ }
402120
+ if (/^\/plan(?:\s|$)/iu.test(text2) || /\b(?:enter|start|use|switch\s+to)\s+plan\s+mode\b/iu.test(text2) || /\bplan\s+(?:this|the\s+work|first)\b/iu.test(text2)) {
402121
+ return "planning workflow";
402122
+ }
402123
+ if (/\b(?:delegate|delegation|sub[ -]?agents?|parallel\s+agents?|agent\s+team|team\s+of\s+agents?|fan[ -]?out)\b/iu.test(text2)) {
402124
+ return "delegation or parallel agent work";
402125
+ }
402126
+ const hasAction = new RegExp(String.raw`\b${ACTION_WORD}\b`, "iu").test(text2);
402127
+ if (hasAction && /\b(?:publish|release|deploy|production|migrat(?:e|ion)|database\s+schema|credentials?|secrets?|permissions?|sandbox|security|authentication|authorization|payments?|billing|version\s+bump|git\s+tag)\b/iu.test(text2)) {
402128
+ return "release, security, migration, or production risk";
402129
+ }
402130
+ const structuralText = withoutCode(input);
402131
+ const enumeratedItems = structuralText.match(/(?:^|\n)\s*(?:[-*+]\s+|\d+[.)]\s+)\S/gu);
402132
+ const actionLines = structuralText.split(/\r?\n/gu).filter((line) => new RegExp(String.raw`\b${ACTION_WORD}\b`, "iu").test(line));
402133
+ if ((enumeratedItems?.length ?? 0) >= 2 || actionLines.length >= 2 || SEQUENCED_ACTION_RE.test(text2)) {
402134
+ return "multiple requested outcomes";
402135
+ }
402136
+ const targetList = new RegExp(String.raw`\b${ACTION_WORD}\b[^.!?]{0,120}\b(?:docs?|tests?|code|implementation|configuration|config|workflow|release notes?|technical docs?|readme|ui|api|cli|database|schema|sandbox|permissions?)\b[^.!?]{0,80}(?:,|\band\b|\bplus\b)[^.!?]{0,80}\b(?:docs?|tests?|code|implementation|configuration|config|workflow|release notes?|technical docs?|readme|ui|api|cli|database|schema|sandbox|permissions?)\b`, "iu");
402137
+ if (targetList.test(text2))
402138
+ return "multiple requested outcomes";
402139
+ const projectScope = /\b(?:app|application|agent|system|platform|website|dashboard|service|integration|workflow|codebase|project|plugin|extension|3d\s+(?:scene|design|pipeline))\b/iu;
402140
+ const projectAction = /\b(?:build(?:ing|s)?|built|creat(?:e|ed|es|ing)|design(?:ed|ing|s)?|implement(?:ed|ing|s)?|integrat(?:e|ed|es|ing)|refactor(?:ed|ing|s)?|rewrit(?:e|ing|ten)|overhaul(?:ed|ing|s)?|audit(?:ed|ing|s)?|research(?:ed|es|ing)?)\b/iu;
402141
+ if (projectScope.test(text2) && projectAction.test(text2)) {
402142
+ return "large project scope";
402143
+ }
402144
+ ACTION_RE.lastIndex = 0;
402145
+ if (text2.length >= 600 && ACTION_RE.test(text2)) {
402146
+ return "detailed multi-step request";
402147
+ }
402148
+ return;
402149
+ }
402077
402150
  function getTaskListRunForCommand(command, options2 = {}) {
402078
402151
  if (!command || command.mode !== "prompt" || command.isMeta)
402079
402152
  return;
@@ -402081,9 +402154,12 @@ function getTaskListRunForCommand(command, options2 = {}) {
402081
402154
  if (!options2.allowSlashCommand && !command.skipSlashCommands && text2.trimStart().startsWith("/")) {
402082
402155
  return;
402083
402156
  }
402157
+ const requirementReason = taskListRequirementReason(text2);
402084
402158
  return {
402085
402159
  generationId: String(command.uuid ?? randomUUID40()),
402086
- appendToCurrent: shouldKeepCurrentTaskList(text2)
402160
+ appendToCurrent: shouldKeepCurrentTaskList(text2),
402161
+ requiresTaskList: requirementReason !== undefined,
402162
+ ...requirementReason ? { requirementReason } : {}
402087
402163
  };
402088
402164
  }
402089
402165
  function getTaskListRunFromMessages(messages) {
@@ -402091,14 +402167,21 @@ function getTaskListRunFromMessages(messages) {
402091
402167
  if (!message || typeof message.uuid !== "string" || !message.uuid) {
402092
402168
  return;
402093
402169
  }
402170
+ const text2 = textFromMessage(message);
402171
+ const requirementReason = taskListRequirementReason(text2);
402094
402172
  return {
402095
402173
  generationId: message.uuid,
402096
- appendToCurrent: shouldKeepCurrentTaskList(textFromMessage(message))
402174
+ appendToCurrent: shouldKeepCurrentTaskList(text2),
402175
+ requiresTaskList: requirementReason !== undefined,
402176
+ ...requirementReason ? { requirementReason } : {}
402097
402177
  };
402098
402178
  }
402099
- var taskListRunStorage;
402179
+ var taskListRunStorage, ACTION_WORD, ACTION_RE, SEQUENCED_ACTION_RE;
402100
402180
  var init_taskListRunContext = __esm(() => {
402101
402181
  taskListRunStorage = new AsyncLocalStorage5;
402182
+ ACTION_WORD = String.raw`(?:add(?:ed|ing|s)?|audit(?:ed|ing|s)?|build(?:ing|s)?|built|bump(?:ed|ing|s)?|chang(?:e|ed|es|ing)|clean(?:ed|ing|s)?|creat(?:e|ed|es|ing)|debug(?:ged|ging|s)?|delet(?:e|ed|es|ing)|deploy(?:ed|ing|s)?|design(?:ed|ing|s)?|document(?:ed|ing|s)?|fix(?:ed|es|ing)?|implement(?:ed|ing|s)?|integrat(?:e|ed|es|ing)|migrat(?:e|ed|es|ing)|publish(?:ed|es|ing)?|push(?:ed|es|ing)?|refactor(?:ed|ing|s)?|releas(?:e|ed|es|ing)|remov(?:e|ed|es|ing)|renam(?:e|ed|es|ing)|repair(?:ed|ing|s)?|research(?:ed|es|ing)?|review(?:ed|ing|s)?|secur(?:e|ed|es|ing)|test(?:ed|ing|s)?|updat(?:e|ed|es|ing)|upgrad(?:e|ed|es|ing)|verif(?:y|ied|ies|ying)|writ(?:e|es|ing)|wrote)`;
402183
+ ACTION_RE = new RegExp(String.raw`\b${ACTION_WORD}\b`, "giu");
402184
+ SEQUENCED_ACTION_RE = new RegExp(String.raw`\b${ACTION_WORD}\b[^.!?\n]{0,180}(?:\band\b|\bthen\b|\balso\b|\bplus\b|;|\n)[^.!?\n]{0,100}\b${ACTION_WORD}\b`, "iu");
402102
402185
  });
402103
402186
 
402104
402187
  // src/tools/TaskCreateTool/prompt.ts
@@ -402114,9 +402197,11 @@ It also helps the user understand the progress of the task and overall progress
402114
402197
 
402115
402198
  Use this tool proactively in these scenarios:
402116
402199
 
402117
- - Complex multi-step tasks - When a request requires 3 or more distinct steps or actions
402200
+ - Multi-outcome work - When a request has 2 or more distinct requested outcomes, deliverables, or sequenced actions
402118
402201
  - Non-trivial and complex tasks - Tasks that require careful planning or multiple operations${teammateContext}
402119
402202
  - Multiple independently verifiable outcomes, dependency ordering, delegation, or parallel work
402203
+ - High-risk lifecycle work - Releases, publishing, deployment, migrations, security, credentials, permissions, sandboxing, or production changes
402204
+ - Project-sized builds, integrations, workflows, refactors, and audits
402120
402205
  - Plan mode - When using plan mode, create a task list to track the work
402121
402206
  - User explicitly requests todo list - When the user directly asks you to use the todo list
402122
402207
  - User asks to queue work - When the user says "add to your tasks", "add this to your task list", "put this on the list", "queue this up", or anything similar, IMMEDIATELY call this tool with that request \u2014 even if you are in the middle of other work and even if the item sounds small. The user is watching the live task panel and expects the item to appear there right away. Acknowledge briefly and continue what you were doing unless asked to switch.
@@ -402127,7 +402212,7 @@ Use this tool proactively in these scenarios:
402127
402212
 
402128
402213
  Skip using this tool when:
402129
402214
  - The task is purely conversational or informational
402130
- - The request is one direct, low-risk action that can be completed and verified as one operation
402215
+ - The request is one genuinely atomic, low-risk action with one outcome that can be completed and verified directly
402131
402216
  - The user sends a short acknowledgement, correction, or clarification that does not add a distinct outcome to an existing board
402132
402217
 
402133
402218
  Do not create a task merely because a user sent a message or because the request is actionable. Task subjects must describe concrete outcomes chosen after understanding the work; never copy the raw prompt into a task title.
@@ -412358,7 +412443,7 @@ function isAnyTracingEnabled() {
412358
412443
  return isTelemetryEnabled() || isEnhancedTelemetryEnabled() || isBetaTracingEnabled();
412359
412444
  }
412360
412445
  function getTracer() {
412361
- return import_api39.trace.getTracer("ur-agent.gen_ai", "1.80.1");
412446
+ return import_api39.trace.getTracer("ur-agent.gen_ai", "1.80.3");
412362
412447
  }
412363
412448
  function createSpanAttributes(spanType, customAttributes = {}) {
412364
412449
  const baseAttributes = getTelemetryAttributes();
@@ -413039,6 +413124,8 @@ function checkTaskListGate(input) {
413039
413124
  const config3 = input.config ?? getTaskListGateConfig();
413040
413125
  if (!config3.enabled)
413041
413126
  return { allowed: true };
413127
+ if (input.taskListWriterAvailable === false)
413128
+ return { allowed: true };
413042
413129
  if (isTaskListGateExempt(input.toolName))
413043
413130
  return { allowed: true };
413044
413131
  const isMutating = input.isMutating ?? isMutatingTool2(input.toolName);
@@ -413047,23 +413134,29 @@ function checkTaskListGate(input) {
413047
413134
  if (input.taskCount !== null && input.taskCount > 0) {
413048
413135
  return { allowed: true };
413049
413136
  }
413137
+ const inherentlyRequiresTaskList = input.isSubagent || ALWAYS_REQUIRE_PLAN_TOOLS.has(input.toolName);
413138
+ const classifiedRequirement = input.requiresTaskList === true;
413139
+ const forceEveryMutation = config3.freeReads === 0;
413140
+ const unclassifiedAllowanceExpired = input.requiresTaskList === undefined && input.readsSoFar >= config3.freeReads;
413141
+ const gateRequired = inherentlyRequiresTaskList || classifiedRequirement || forceEveryMutation || unclassifiedAllowanceExpired;
413142
+ const requirementContext = input.requirementReason ? ` This turn requires task tracking because it contains ${input.requirementReason}.` : "";
413050
413143
  if (input.taskCount === null) {
413051
413144
  return {
413052
413145
  allowed: false,
413053
- reason: `The task list could not be read, so ${input.toolName} was not allowed ` + `to change state without a verifiable plan. Retry TaskList or ` + `TaskCreate, then retry this call. Disable with ` + `tasks.requireBeforeChanges.enabled=false in settings.`
413146
+ reason: `The task list could not be read, so ${input.toolName} was not allowed ` + `to change state without a verifiable plan.${requirementContext} Retry TaskList or ` + `TaskCreate, then retry this call. Disable with ` + `tasks.requireBeforeChanges.enabled=false in settings.`
413054
413147
  };
413055
413148
  }
413056
- if (input.isSubagent || ALWAYS_REQUIRE_PLAN_TOOLS.has(input.toolName)) {
413149
+ if (!gateRequired)
413150
+ return { allowed: true };
413151
+ if (inherentlyRequiresTaskList) {
413057
413152
  return {
413058
413153
  allowed: false,
413059
413154
  reason: `No actionable parent task exists for ${input.toolName}. Call ` + `TaskCreate before delegating or changing state, then retry this call. ` + `Disable with tasks.requireBeforeChanges.enabled=false in settings.`
413060
413155
  };
413061
413156
  }
413062
- if (input.readsSoFar < config3.freeReads)
413063
- return { allowed: true };
413064
413157
  return {
413065
413158
  allowed: false,
413066
- reason: `No task list exists, and ${input.toolName} changes the workspace. ` + `Call TaskCreate first with the steps you intend to take, then retry ` + `this call. Reads are unrestricted, so investigate as much as you need ` + `before writing the list. ` + `Disable with tasks.requireBeforeChanges.enabled=false in settings.`
413159
+ reason: `No task list exists, and ${input.toolName} changes the workspace. ` + `${requirementContext.trim()}${requirementContext ? " " : ""}` + `Call TaskCreate first with the steps you intend to take, then retry ` + `this call. Reads are unrestricted, so investigate as much as you need ` + `before writing the list. ` + `Disable with tasks.requireBeforeChanges.enabled=false in settings.`
413067
413160
  };
413068
413161
  }
413069
413162
  var TASK_LIST_GATE_DEFAULTS, KNOWN_MUTATING_TOOLS, GATE_EXEMPT_TOOLS, ALWAYS_REQUIRE_PLAN_TOOLS;
@@ -413071,7 +413164,7 @@ var init_taskListGate = __esm(() => {
413071
413164
  init_settings2();
413072
413165
  init_tasks();
413073
413166
  TASK_LIST_GATE_DEFAULTS = {
413074
- enabled: false,
413167
+ enabled: true,
413075
413168
  freeReads: 3
413076
413169
  };
413077
413170
  KNOWN_MUTATING_TOOLS = new Set([
@@ -414611,12 +414704,16 @@ async function checkPermissionsAndCallTool(tool, toolUseID, input, toolUseContex
414611
414704
  } catch {
414612
414705
  isMutating = true;
414613
414706
  }
414707
+ const taskListRun = getTaskListRunContext() ?? (toolUseContext.agentId ? undefined : getTaskListRunFromMessages(toolUseContext.messages ?? []));
414614
414708
  const gate = checkTaskListGate({
414615
414709
  toolName: tool.name,
414616
414710
  taskCount: await countTasksForGate(),
414617
414711
  readsSoFar: countToolCallsBeforeCurrent(toolUseContext.messages, assistantMessage, toolUseID),
414618
414712
  isSubagent: Boolean(toolUseContext.agentId),
414619
- isMutating
414713
+ isMutating,
414714
+ requiresTaskList: taskListRun?.requiresTaskList,
414715
+ requirementReason: taskListRun?.requirementReason,
414716
+ taskListWriterAvailable: toolUseContext.options.tools.some((candidate) => candidate.name === "TaskCreate")
414620
414717
  });
414621
414718
  if (gate.allowed === false) {
414622
414719
  recordCallFailure(callSig);
@@ -414973,7 +415070,10 @@ async function checkPermissionsAndCallTool(tool, toolUseID, input, toolUseContex
414973
415070
  taskCount: await countTasksForGate(),
414974
415071
  readsSoFar: countToolCallsBeforeCurrent(toolUseContext.messages, assistantMessage, toolUseID),
414975
415072
  isSubagent: Boolean(toolUseContext.agentId),
414976
- isMutating: finalIsMutating
415073
+ isMutating: finalIsMutating,
415074
+ requiresTaskList: taskListRun?.requiresTaskList,
415075
+ requirementReason: taskListRun?.requirementReason,
415076
+ taskListWriterAvailable: toolUseContext.options.tools.some((candidate) => candidate.name === "TaskCreate")
414977
415077
  });
414978
415078
  if (finalGate.allowed === false) {
414979
415079
  recordCallFailure(callSig);
@@ -415411,6 +415511,7 @@ var init_toolExecution = __esm(() => {
415411
415511
  init_genAiSemantics();
415412
415512
  init_toolErrors();
415413
415513
  init_toolResultStorage();
415514
+ init_taskListRunContext();
415414
415515
  init_toolSearch();
415415
415516
  init_taskListGate();
415416
415517
  init_repeatedFailureGuard();
@@ -442790,7 +442891,7 @@ function Feedback({
442790
442891
  platform: env2.platform,
442791
442892
  gitRepo: envInfo.isGit,
442792
442893
  terminal: env2.terminal,
442793
- version: "1.80.1",
442894
+ version: "1.80.3",
442794
442895
  transcript: normalizeMessagesForAPI(messages),
442795
442896
  errors: sanitizedErrors,
442796
442897
  lastApiRequest: getLastAPIRequest(),
@@ -442982,7 +443083,7 @@ function Feedback({
442982
443083
  ", ",
442983
443084
  env2.terminal,
442984
443085
  ", v",
442985
- "1.80.1"
443086
+ "1.80.3"
442986
443087
  ]
442987
443088
  }, undefined, true, undefined, this)
442988
443089
  ]
@@ -443088,7 +443189,7 @@ ${sanitizedDescription}
443088
443189
  ` + `**Environment Info**
443089
443190
  ` + `- Platform: ${env2.platform}
443090
443191
  ` + `- Terminal: ${env2.terminal}
443091
- ` + `- Version: ${"1.80.1"}
443192
+ ` + `- Version: ${"1.80.3"}
443092
443193
  ` + `- Feedback ID: ${feedbackId}
443093
443194
  ` + `
443094
443195
  **Errors**
@@ -446198,7 +446299,7 @@ function buildPrimarySection() {
446198
446299
  }, undefined, false, undefined, this);
446199
446300
  return [{
446200
446301
  label: "Version",
446201
- value: "1.80.1"
446302
+ value: "1.80.3"
446202
446303
  }, {
446203
446304
  label: "Session name",
446204
446305
  value: nameValue
@@ -449580,7 +449681,7 @@ function Config({
449580
449681
  }
449581
449682
  }, undefined, false, undefined, this)
449582
449683
  }, undefined, false, undefined, this) : showSubmenu === "ChannelDowngrade" ? /* @__PURE__ */ jsx_dev_runtime179.jsxDEV(ChannelDowngradeDialog, {
449583
- currentVersion: "1.80.1",
449684
+ currentVersion: "1.80.3",
449584
449685
  onChoice: (choice) => {
449585
449686
  setShowSubmenu(null);
449586
449687
  setTabsHidden(false);
@@ -449592,7 +449693,7 @@ function Config({
449592
449693
  autoUpdatesChannel: "stable"
449593
449694
  };
449594
449695
  if (choice === "stay") {
449595
- newSettings.minimumVersion = "1.80.1";
449696
+ newSettings.minimumVersion = "1.80.3";
449596
449697
  }
449597
449698
  updateSettingsForSource("userSettings", newSettings);
449598
449699
  setSettingsData((prev_27) => ({
@@ -457850,7 +457951,7 @@ function HelpV2(t0) {
457850
457951
  let t6;
457851
457952
  if ($2[31] !== tabs) {
457852
457953
  t6 = /* @__PURE__ */ jsx_dev_runtime206.jsxDEV(Tabs, {
457853
- title: `UR v${"1.80.1"}`,
457954
+ title: `UR v${"1.80.3"}`,
457854
457955
  color: "professionalBlue",
457855
457956
  defaultTab: "general",
457856
457957
  children: tabs
@@ -458783,7 +458884,7 @@ function buildToolUseContext(tools, readFileStateCache, toolPermissionContext, a
458783
458884
  async function handleInitialize(options2) {
458784
458885
  return {
458785
458886
  name: "UR",
458786
- version: "1.80.1",
458887
+ version: "1.80.3",
458787
458888
  protocolVersion: "0.1.0",
458788
458889
  workspaceRoot: options2.cwd,
458789
458890
  capabilities: {
@@ -475891,7 +475992,7 @@ function getAllReleaseNotes(changelogContent = getStoredChangelogFromMemory()) {
475891
475992
  return [];
475892
475993
  }
475893
475994
  }
475894
- async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.80.1") {
475995
+ async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.80.3") {
475895
475996
  if (process.env.USER_TYPE === "ant") {
475896
475997
  const changelog = "";
475897
475998
  if (changelog) {
@@ -475918,7 +476019,7 @@ async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.80.1")
475918
476019
  releaseNotes
475919
476020
  };
475920
476021
  }
475921
- function checkForReleaseNotesSync(lastSeenVersion, currentVersion = "1.80.1") {
476022
+ function checkForReleaseNotesSync(lastSeenVersion, currentVersion = "1.80.3") {
475922
476023
  if (process.env.USER_TYPE === "ant") {
475923
476024
  const changelog = "";
475924
476025
  if (changelog) {
@@ -478823,7 +478924,7 @@ function getRecentActivitySync() {
478823
478924
  return cachedActivity;
478824
478925
  }
478825
478926
  function getLogoDisplayData() {
478826
- const version2 = process.env.DEMO_VERSION ?? "1.80.1";
478927
+ const version2 = process.env.DEMO_VERSION ?? "1.80.3";
478827
478928
  const serverUrl = getDirectConnectServerUrl();
478828
478929
  const displayPath = process.env.DEMO_VERSION ? "/code/ur" : getDisplayPath(getCwd());
478829
478930
  const cwd2 = serverUrl ? `${displayPath} in ${serverUrl.replace(/^https?:\/\//, "")}` : displayPath;
@@ -479691,7 +479792,7 @@ function LogoV2() {
479691
479792
  if ($2[2] === Symbol.for("react.memo_cache_sentinel")) {
479692
479793
  t2 = () => {
479693
479794
  const currentConfig = getGlobalConfig();
479694
- if (currentConfig.lastReleaseNotesSeen === "1.80.1") {
479795
+ if (currentConfig.lastReleaseNotesSeen === "1.80.3") {
479695
479796
  return;
479696
479797
  }
479697
479798
  saveGlobalConfig(_temp325);
@@ -480376,12 +480477,12 @@ function LogoV2() {
480376
480477
  return t41;
480377
480478
  }
480378
480479
  function _temp325(current) {
480379
- if (current.lastReleaseNotesSeen === "1.80.1") {
480480
+ if (current.lastReleaseNotesSeen === "1.80.3") {
480380
480481
  return current;
480381
480482
  }
480382
480483
  return {
480383
480484
  ...current,
480384
- lastReleaseNotesSeen: "1.80.1"
480485
+ lastReleaseNotesSeen: "1.80.3"
480385
480486
  };
480386
480487
  }
480387
480488
  function _temp241(s_0) {
@@ -496473,7 +496574,7 @@ function compileAgenticCiWorkflow(specName = "default", options2 = {}) {
496473
496574
  if (spec.name !== specName) {
496474
496575
  throw new Error("Agentic CI workflow spec name does not match");
496475
496576
  }
496476
- const packageVersion = options2.packageVersion ?? (typeof MACRO !== "undefined" ? "1.80.1" : "1.80.1");
496577
+ const packageVersion = options2.packageVersion ?? (typeof MACRO !== "undefined" ? "1.80.3" : "1.80.3");
496477
496578
  if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(packageVersion)) {
496478
496579
  throw new Error("invalid ur-agent package version");
496479
496580
  }
@@ -497466,7 +497567,7 @@ runner; \`ur trigger\` is the inbound parser that decides what to run.
497466
497567
  path: ".github/workflows/ur.yml",
497467
497568
  root: "project",
497468
497569
  content: compileAgenticCiWorkflow("default", {
497469
- packageVersion: typeof MACRO !== "undefined" ? "1.80.1" : "1.80.1"
497570
+ packageVersion: typeof MACRO !== "undefined" ? "1.80.3" : "1.80.3"
497470
497571
  })
497471
497572
  },
497472
497573
  {
@@ -497529,7 +497630,7 @@ function value(tokens, flag) {
497529
497630
  return index2 >= 0 ? tokens[index2 + 1] : undefined;
497530
497631
  }
497531
497632
  function cliVersion() {
497532
- return typeof MACRO !== "undefined" ? "1.80.1" : "1.80.1";
497633
+ return typeof MACRO !== "undefined" ? "1.80.3" : "1.80.3";
497533
497634
  }
497534
497635
  function workflowPath(cwd2) {
497535
497636
  return join168(cwd2, ".github", "workflows", "ur-agentic-ci.yml");
@@ -503385,7 +503486,7 @@ function createAcpStdioApp(deps) {
503385
503486
  }
503386
503487
  },
503387
503488
  authMethods: [],
503388
- agentInfo: { name: "UR-Nexus", version: "1.80.1" }
503489
+ agentInfo: { name: "UR-Nexus", version: "1.80.3" }
503389
503490
  })).onRequest("authenticate", () => ({})).onRequest("session/new", async (context6) => {
503390
503491
  const result = runtime2.newSession(context6.params.cwd, context6.params.mcpServers, context6.params.additionalDirectories);
503391
503492
  await runtime2.announce({
@@ -503482,7 +503583,7 @@ function createAcpStdioAgent(deps) {
503482
503583
  }
503483
503584
  },
503484
503585
  authMethods: [],
503485
- agentInfo: { name: "UR-Nexus", version: "1.80.1" }
503586
+ agentInfo: { name: "UR-Nexus", version: "1.80.3" }
503486
503587
  });
503487
503588
  return;
503488
503589
  case "authenticate":
@@ -714708,7 +714809,7 @@ async function captureMemoryDiagnostics(trigger2, dumpNumber = 0) {
714708
714809
  smapsRollup,
714709
714810
  platform: process.platform,
714710
714811
  nodeVersion: process.version,
714711
- ccVersion: "1.80.1"
714812
+ ccVersion: "1.80.3"
714712
714813
  };
714713
714814
  }
714714
714815
  async function performHeapDump(trigger2 = "manual", dumpNumber = 0) {
@@ -715297,7 +715398,7 @@ var init_bridge_kick = __esm(() => {
715297
715398
  var call154 = async () => {
715298
715399
  return {
715299
715400
  type: "text",
715300
- value: "1.80.1"
715401
+ value: "1.80.3"
715301
715402
  };
715302
715403
  }, version2, version_default;
715303
715404
  var init_version = __esm(() => {
@@ -726540,7 +726641,7 @@ function generateHtmlReport(data, insights) {
726540
726641
  </html>`;
726541
726642
  }
726542
726643
  function buildExportData(data, insights, facets, remoteStats) {
726543
- const version3 = typeof MACRO !== "undefined" ? "1.80.1" : "unknown";
726644
+ const version3 = typeof MACRO !== "undefined" ? "1.80.3" : "unknown";
726544
726645
  const remote_hosts_collected = remoteStats?.hosts.filter((h2) => h2.sessionCount > 0).map((h2) => h2.name);
726545
726646
  const facets_summary = {
726546
726647
  total: facets.size,
@@ -730853,7 +730954,7 @@ var init_sessionStorage = __esm(() => {
730853
730954
  init_settings2();
730854
730955
  init_slowOperations();
730855
730956
  init_uuid();
730856
- VERSION7 = typeof MACRO !== "undefined" ? "1.80.1" : "unknown";
730957
+ VERSION7 = typeof MACRO !== "undefined" ? "1.80.3" : "unknown";
730857
730958
  MAX_TOMBSTONE_REWRITE_BYTES = 50 * 1024 * 1024;
730858
730959
  SKIP_FIRST_PROMPT_PATTERN = /^(?:\s*<[a-z][\w-]*[\s>]|\[Request interrupted by user[^\]]*\])/;
730859
730960
  EPHEMERAL_PROGRESS_TYPES = new Set([
@@ -732068,7 +732169,7 @@ var init_filesystem = __esm(() => {
732068
732169
  });
732069
732170
  getBundledSkillsRoot = memoize_default(function getBundledSkillsRoot2() {
732070
732171
  const nonce = randomBytes24(16).toString("hex");
732071
- return join243(getURTempDir(), "bundled-skills", "1.80.1", nonce);
732172
+ return join243(getURTempDir(), "bundled-skills", "1.80.3", nonce);
732072
732173
  });
732073
732174
  getResolvedWorkingDirPaths = memoize_default(getPathsForPermissionCheck);
732074
732175
  });
@@ -737524,13 +737625,13 @@ function getTaskToolGuidance(enabledTools) {
737524
737625
  const canUpdate = enabledTools.has(TASK_UPDATE_TOOL_NAME);
737525
737626
  const canList = enabledTools.has(TASK_LIST_TOOL_NAME);
737526
737627
  if (canCreate && canUpdate) {
737527
- return `For a request with 3+ distinct steps, multiple independently verifiable outcomes, delegation, dependency ordering, or an explicit user request for a task list, you MUST use ${TASK_CREATE_TOOL_NAME} to maintain the visible task list. Do not create a task merely because a message is actionable: a direct one-step change, informational answer, acknowledgement, or small correction can proceed without a board. Decompose a large request into 2-8 bounded outcomes (never more than 12), each with one observable result, likely file scope, and acceptance evidence; never copy the raw user prompt as a task title. Create tasks first without guessed or forward dependency IDs. After each real ID is returned, use ${TASK_UPDATE_TOOL_NAME} to add dependencies only to tasks that already exist; never reference a future task, and never create a self-dependency. Keep the final graph dependency-ordered; independent branches stay dependency-free. If the user interrupts while tasks are pending or in progress, inspect the active list, preserve still-relevant work, update the affected task, add a task only for a genuinely distinct new outcome, and mark superseded work skipped rather than starting from an empty list. Mark each unblocked task in_progress when work starts and completed immediately after implementation and relevant verification succeed; use failed for attempted work that did not finish, skipped only for explicitly inapplicable work, and leave dependency-blocked work open with its blocker recorded.${canList ? ` Use ${TASK_LIST_TOOL_NAME} after every interruption and to select the next unblocked task; when all work succeeds, show the final list with every task completed before finishing.` : ""}`;
737628
+ return `UR uses a strict-hybrid task policy. Before the first mutation, you MUST use ${TASK_CREATE_TOOL_NAME} for 2+ distinct requested outcomes, enumerated or sequenced work, multiple independently verifiable deliverables, plan-mode implementation, delegation or parallel agents, dependency ordering, project-sized builds/refactors, and release, publishing, deployment, migration, security, credential, permission, sandbox, production, or other high-risk work. An explicit user request for tasks always wins. Only a genuinely atomic, low-risk change with one outcome may proceed directly; informational answers, acknowledgements, and small corrections need no board. Read-only investigation is always allowed before planning. Decompose tracked work into 2-8 bounded outcomes (never more than 12), each with one observable result, likely file scope, and acceptance evidence; never copy the raw user prompt as a task title. Create tasks first without guessed or forward dependency IDs. After each real ID is returned, use ${TASK_UPDATE_TOOL_NAME} to add dependencies only to tasks that already exist; never reference a future task, and never create a self-dependency. Keep the final graph dependency-ordered; independent branches stay dependency-free. If the user interrupts while tasks are pending or in progress, inspect the active list, preserve still-relevant work, update the affected task, add a task only for a genuinely distinct new outcome, and mark superseded work skipped rather than starting from an empty list. Mark each unblocked task in_progress when work starts and completed immediately after implementation and relevant verification succeed; use failed for attempted work that did not finish, skipped only for explicitly inapplicable work, and leave dependency-blocked work open with its blocker recorded.${canList ? ` Use ${TASK_LIST_TOOL_NAME} after every interruption and to select the next unblocked task; when all work succeeds, show the final list with every task completed before finishing.` : ""}`;
737528
737629
  }
737529
737630
  if (canUpdate) {
737530
737631
  return `Keep assigned tasks current with ${TASK_UPDATE_TOOL_NAME}: mark the task in_progress when starting, completed only after implementation and relevant verification succeed, and leave blocked or partial work open with its blocker recorded.${canList ? ` Use ${TASK_LIST_TOOL_NAME} to select the next unblocked task.` : ""}`;
737531
737632
  }
737532
737633
  if (canCreate) {
737533
- return `Use ${TASK_CREATE_TOOL_NAME} for 3+ distinct steps, multiple independently verifiable outcomes, delegation, dependency ordering, or an explicit user request for a task list. A large request should have 2-8 bounded outcomes (never more than 12). Do not create a task merely because a message is actionable; skip a board for direct one-step work, informational answers, acknowledgements, and small corrections. Never copy the raw prompt as a task title. Create tasks without guessed or forward IDs; dependencies may name only tasks whose real IDs have already been returned. Preserve pending or in-progress work after an interruption, update affected work, and add only genuinely distinct new outcomes.`;
737634
+ return `Use ${TASK_CREATE_TOOL_NAME} before mutation for 2+ distinct outcomes, sequenced work, project-sized changes, delegation, dependencies, releases/deployments/migrations, security-sensitive work, or an explicit task-list request. Only a genuinely atomic low-risk change may proceed directly. A tracked request should have 2-8 bounded outcomes (never more than 12). Never copy the raw prompt as a task title. Create tasks without guessed or forward IDs; dependencies may name only tasks whose real IDs have already been returned. Preserve pending or in-progress work after an interruption, update affected work, and add only genuinely distinct new outcomes.`;
737534
737635
  }
737535
737636
  if (enabledTools.has(TODO_WRITE_TOOL_NAME)) {
737536
737637
  return `Track multi-step work with ${TODO_WRITE_TOOL_NAME}. Keep items dependency-ordered and mark each item completed immediately after its implementation and relevant verification succeed.`;
@@ -738457,7 +738558,7 @@ function computeFingerprint(messageText2, version3) {
738457
738558
  }
738458
738559
  function computeFingerprintFromMessages(messages) {
738459
738560
  const firstMessageText = extractFirstMessageText(messages);
738460
- return computeFingerprint(firstMessageText, "1.80.1");
738561
+ return computeFingerprint(firstMessageText, "1.80.3");
738461
738562
  }
738462
738563
  var FINGERPRINT_SALT = "59cf53e54c78";
738463
738564
  var init_fingerprint = () => {};
@@ -740382,7 +740483,7 @@ async function sideQuery(opts) {
740382
740483
  betas.push(STRUCTURED_OUTPUTS_BETA_HEADER);
740383
740484
  }
740384
740485
  const messageText2 = extractFirstUserMessageText(messages);
740385
- const fingerprint2 = computeFingerprint(messageText2, "1.80.1");
740486
+ const fingerprint2 = computeFingerprint(messageText2, "1.80.3");
740386
740487
  const attributionHeader = getAttributionHeader(fingerprint2);
740387
740488
  const systemBlocks = [
740388
740489
  attributionHeader ? { type: "text", text: attributionHeader } : null,
@@ -745216,7 +745317,7 @@ function buildSystemInitMessage(inputs) {
745216
745317
  slash_commands: inputs.commands.filter((c4) => c4.userInvocable !== false).map((c4) => c4.name),
745217
745318
  apiKeySource: getURHQApiKeyWithSource().source,
745218
745319
  betas: getSdkBetas(),
745219
- ur_version: "1.80.1",
745320
+ ur_version: "1.80.3",
745220
745321
  output_style: outputStyle,
745221
745322
  agents: inputs.agents.map((agent2) => agent2.agentType),
745222
745323
  skills: inputs.skills.filter((s) => s.userInvocable !== false).map((skill2) => skill2.name),
@@ -759052,7 +759153,7 @@ var init_useVoiceEnabled = __esm(() => {
759052
759153
  function getSemverPart(version3) {
759053
759154
  return `${import_semver13.major(version3, { loose: true })}.${import_semver13.minor(version3, { loose: true })}.${import_semver13.patch(version3, { loose: true })}`;
759054
759155
  }
759055
- function useUpdateNotification(updatedVersion, initialVersion = "1.80.1") {
759156
+ function useUpdateNotification(updatedVersion, initialVersion = "1.80.3") {
759056
759157
  const [lastNotifiedSemver, setLastNotifiedSemver] = import_react225.useState(() => getSemverPart(initialVersion));
759057
759158
  if (!updatedVersion) {
759058
759159
  return null;
@@ -759101,7 +759202,7 @@ function AutoUpdater({
759101
759202
  return;
759102
759203
  }
759103
759204
  if (false) {}
759104
- const currentVersion = "1.80.1";
759205
+ const currentVersion = "1.80.3";
759105
759206
  const channel = getInitialSettings()?.autoUpdatesChannel ?? "latest";
759106
759207
  let latestVersion = await getLatestVersion(channel);
759107
759208
  const isDisabled = isAutoUpdaterDisabled();
@@ -759330,12 +759431,12 @@ function NativeAutoUpdater({
759330
759431
  logEvent("tengu_native_auto_updater_start", {});
759331
759432
  try {
759332
759433
  const maxVersion = await getMaxVersion();
759333
- if (maxVersion && gt("1.80.1", maxVersion)) {
759434
+ if (maxVersion && gt("1.80.3", maxVersion)) {
759334
759435
  const msg = await getMaxVersionMessage();
759335
759436
  setMaxVersionIssue(msg ?? "affects your version");
759336
759437
  }
759337
759438
  const result = await installLatest(channel);
759338
- const currentVersion = "1.80.1";
759439
+ const currentVersion = "1.80.3";
759339
759440
  const latencyMs = Date.now() - startTime;
759340
759441
  if (result.lockFailed) {
759341
759442
  logEvent("tengu_native_auto_updater_lock_contention", {
@@ -759472,17 +759573,17 @@ function PackageManagerAutoUpdater(t0) {
759472
759573
  const maxVersion = await getMaxVersion();
759473
759574
  if (maxVersion && latest && gt(latest, maxVersion)) {
759474
759575
  logForDebugging(`PackageManagerAutoUpdater: maxVersion ${maxVersion} is set, capping update from ${latest} to ${maxVersion}`);
759475
- if (gte("1.80.1", maxVersion)) {
759476
- logForDebugging(`PackageManagerAutoUpdater: current version ${"1.80.1"} is already at or above maxVersion ${maxVersion}, skipping update`);
759576
+ if (gte("1.80.3", maxVersion)) {
759577
+ logForDebugging(`PackageManagerAutoUpdater: current version ${"1.80.3"} is already at or above maxVersion ${maxVersion}, skipping update`);
759477
759578
  setUpdateAvailable(false);
759478
759579
  return;
759479
759580
  }
759480
759581
  latest = maxVersion;
759481
759582
  }
759482
- const hasUpdate = latest && !gte("1.80.1", latest) && !shouldSkipVersion(latest);
759583
+ const hasUpdate = latest && !gte("1.80.3", latest) && !shouldSkipVersion(latest);
759483
759584
  setUpdateAvailable(!!hasUpdate);
759484
759585
  if (hasUpdate) {
759485
- logForDebugging(`PackageManagerAutoUpdater: Update available ${"1.80.1"} -> ${latest}`);
759586
+ logForDebugging(`PackageManagerAutoUpdater: Update available ${"1.80.3"} -> ${latest}`);
759486
759587
  }
759487
759588
  };
759488
759589
  $2[0] = t1;
@@ -759516,7 +759617,7 @@ function PackageManagerAutoUpdater(t0) {
759516
759617
  wrap: "truncate",
759517
759618
  children: [
759518
759619
  "currentVersion: ",
759519
- "1.80.1"
759620
+ "1.80.3"
759520
759621
  ]
759521
759622
  }, undefined, true, undefined, this);
759522
759623
  $2[3] = verbose;
@@ -770369,7 +770470,7 @@ function buildStatusLineCommandInput(permissionMode, exceeds200kTokens, settings
770369
770470
  project_dir: getOriginalCwd(),
770370
770471
  added_dirs: addedDirs
770371
770472
  },
770372
- version: "1.80.1",
770473
+ version: "1.80.3",
770373
770474
  output_style: {
770374
770475
  name: outputStyleName
770375
770476
  },
@@ -770504,7 +770605,7 @@ function StatusLineInner({
770504
770605
  const attention = customStatusError ?? taskAttention;
770505
770606
  const terminalSize = React133.useContext(TerminalSizeContext);
770506
770607
  const defaultStatusLineText = buildDefaultStatusBar({
770507
- version: "1.80.1",
770608
+ version: "1.80.3",
770508
770609
  providerLabel: providerRuntime.providerLabel,
770509
770610
  authMode: providerRuntime.authLabel,
770510
770611
  model: renderModelName(mainLoopModel) || providerRuntime.model || "",
@@ -782759,7 +782860,7 @@ async function submitTranscriptShare(messages, trigger2, appearanceId) {
782759
782860
  } catch {}
782760
782861
  const data = {
782761
782862
  trigger: trigger2,
782762
- version: "1.80.1",
782863
+ version: "1.80.3",
782763
782864
  platform: process.platform,
782764
782865
  transcript,
782765
782866
  subagentTranscripts: Object.keys(subagentTranscripts).length > 0 ? subagentTranscripts : undefined,
@@ -795128,7 +795229,7 @@ function WelcomeV2() {
795128
795229
  dimColor: true,
795129
795230
  children: [
795130
795231
  "v",
795131
- "1.80.1"
795232
+ "1.80.3"
795132
795233
  ]
795133
795234
  }, undefined, true, undefined, this)
795134
795235
  ]
@@ -796388,7 +796489,7 @@ function completeOnboarding() {
796388
796489
  saveGlobalConfig((current) => ({
796389
796490
  ...current,
796390
796491
  hasCompletedOnboarding: true,
796391
- lastOnboardingVersion: "1.80.1"
796492
+ lastOnboardingVersion: "1.80.3"
796392
796493
  }));
796393
796494
  }
796394
796495
  function showDialog(root2, renderer) {
@@ -801534,7 +801635,7 @@ function appendToLog(path28, message) {
801534
801635
  cwd: getFsImplementation().cwd(),
801535
801636
  userType: process.env.USER_TYPE,
801536
801637
  sessionId: getSessionId(),
801537
- version: "1.80.1"
801638
+ version: "1.80.3"
801538
801639
  };
801539
801640
  getLogWriter(path28).write(messageWithTimestamp);
801540
801641
  }
@@ -805698,8 +805799,8 @@ async function getEnvLessBridgeConfig() {
805698
805799
  }
805699
805800
  async function checkEnvLessBridgeMinVersion() {
805700
805801
  const cfg = await getEnvLessBridgeConfig();
805701
- if (cfg.min_version && lt("1.80.1", cfg.min_version)) {
805702
- return `Your version of UR (${"1.80.1"}) is too old for Remote Control.
805802
+ if (cfg.min_version && lt("1.80.3", cfg.min_version)) {
805803
+ return `Your version of UR (${"1.80.3"}) is too old for Remote Control.
805703
805804
  Version ${cfg.min_version} or higher is required. Run \`ur update\` to update.`;
805704
805805
  }
805705
805806
  return null;
@@ -806173,7 +806274,7 @@ async function initBridgeCore(params) {
806173
806274
  const rawApi = createBridgeApiClient({
806174
806275
  baseUrl,
806175
806276
  getAccessToken,
806176
- runnerVersion: "1.80.1",
806277
+ runnerVersion: "1.80.3",
806177
806278
  onDebug: logForDebugging,
806178
806279
  onAuth401,
806179
806280
  getTrustedDeviceToken
@@ -815646,7 +815747,7 @@ function getAgUiCapabilities() {
815646
815747
  name: "UR-Nexus",
815647
815748
  type: "ur-nexus",
815648
815749
  description: "Provider-flexible, local-first autonomous engineering workflow agent.",
815649
- version: "1.80.1",
815750
+ version: "1.80.3",
815650
815751
  provider: "UR",
815651
815752
  documentationUrl: "https://github.com/Maitham16/UR/blob/master/docs/AG_UI.md"
815652
815753
  },
@@ -816777,7 +816878,7 @@ function createMCPServer(cwd4, debug2, verbose) {
816777
816878
  };
816778
816879
  const server2 = new Server({
816779
816880
  name: "ur-nexus",
816780
- version: "1.80.1"
816881
+ version: "1.80.3"
816781
816882
  }, {
816782
816883
  capabilities: {
816783
816884
  tools: {}
@@ -817981,7 +818082,7 @@ function thrownResponse(error40) {
817981
818082
  }
817982
818083
  async function createUrMcp2026Runtime(options5) {
817983
818084
  const server2 = createMCPServer(options5.cwd, options5.debug === true, options5.verbose === true);
817984
- const client2 = new Client({ name: "ur-mcp-2026-adapter", version: "1.80.1" }, { capabilities: {} });
818085
+ const client2 = new Client({ name: "ur-mcp-2026-adapter", version: "1.80.3" }, { capabilities: {} });
817985
818086
  const [clientTransport, serverTransport] = createLinkedTransportPair();
817986
818087
  try {
817987
818088
  await server2.connect(serverTransport);
@@ -817992,7 +818093,7 @@ async function createUrMcp2026Runtime(options5) {
817992
818093
  }
817993
818094
  const runtime2 = new Mcp2026Runtime({
817994
818095
  cwd: options5.cwd,
817995
- version: "1.80.1",
818096
+ version: "1.80.3",
817996
818097
  backend: {
817997
818098
  listTools: async () => {
817998
818099
  const listed = await client2.listTools();
@@ -820594,7 +820695,7 @@ async function update() {
820594
820695
  logEvent("tengu_update_check", {});
820595
820696
  const diagnostic2 = await getDoctorDiagnostic();
820596
820697
  const result = await checkUpgradeStatus({
820597
- currentVersion: "1.80.1",
820698
+ currentVersion: "1.80.3",
820598
820699
  packageName: UR_AGENT_PACKAGE_NAME,
820599
820700
  installationType: diagnostic2.installationType,
820600
820701
  latestVersion: () => getLatestNpmPackageVersion(UR_AGENT_PACKAGE_NAME)
@@ -821922,7 +822023,7 @@ ${customInstructions}` : customInstructions;
821922
822023
  }
821923
822024
  }
821924
822025
  logForDiagnosticsNoPII("info", "started", {
821925
- version: "1.80.1",
822026
+ version: "1.80.3",
821926
822027
  is_native_binary: isInBundledMode()
821927
822028
  });
821928
822029
  registerCleanup(async () => {
@@ -822709,7 +822810,7 @@ Usage: ur --remote "your task description"`, () => gracefulShutdown(1));
822709
822810
  pendingHookMessages
822710
822811
  }, renderAndRun);
822711
822812
  }
822712
- }).version("1.80.1 (UR-Nexus)", "-v, --version", "Output the version number");
822813
+ }).version("1.80.3 (UR-Nexus)", "-v, --version", "Output the version number");
822713
822814
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
822714
822815
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
822715
822816
  if (canUserConfigureAdvisor()) {
@@ -823817,7 +823918,7 @@ if (false) {}
823817
823918
  async function main2() {
823818
823919
  const args = process.argv.slice(2);
823819
823920
  if (args.length === 1 && (args[0] === "--version" || args[0] === "-v" || args[0] === "-V")) {
823820
- console.log(`${"1.80.1"} (UR-Nexus)`);
823921
+ console.log(`${"1.80.3"} (UR-Nexus)`);
823821
823922
  return;
823822
823923
  }
823823
823924
  if (args[0] === "a2a" && args[1] === "serve" && !args.includes("--help") && !args.includes("-h")) {
@@ -9,6 +9,12 @@ reproducible autonomous software engineering agent: every substantial task can
9
9
  be driven as `spec -> plan -> patch -> test -> report -> rollback`, with the
10
10
  spec as the durable source of truth and command evidence as the success gate.
11
11
 
12
+ ## v1.80.3 Addition
13
+
14
+ | Addition | Surface | What it adds |
15
+ | --- | --- | --- |
16
+ | Strict-hybrid task planning | Interactive `TaskCreate` lifecycle, `tasks.requireBeforeChanges` | Keeps atomic low-risk work direct, but requires a visible actionable task before mutation for multi-outcome, sequenced, planned, delegated, project-sized, and high-risk lifecycle work. Reads stay open, custom profiles without `TaskCreate` cannot deadlock, and operators retain advisory and fully strict modes. |
17
+
12
18
  ## v1.80.0 Additions
13
19
 
14
20
  | Addition | Surface | What it adds |
@@ -265,7 +271,7 @@ automatically changes the active provider.
265
271
  | Provider-aware status bar | Interactive bottom status bar, `src/components/StatusLine.tsx`, `src/utils/statusBar.ts` | Shows only important runtime state: active provider, selected model, mode, git branch, active task state, checks/build state when known, and update availability. Hidden in CI, dumb terminals, and non-interactive mode; custom status-line hooks still override it. |
266
272
  | Clean update checks | `ur upgrade`, `ur update`, `src/cli/update.ts` | Detects development/source checkouts and prints a short pull-or-install message instead of attempting self-mutation. npm-installed builds compare the local version with `ur-agent` on npm and print update, latest, registry failure, and malformed-response states without stale planning text. |
267
273
  | Bundled IDE extension install | `extensions/vscode-ur-inline-diffs/`, `src/utils/ide.ts`, `ur ide diff` | Public VS Code install now packages the repo's bundled inline-diffs extension as a local VSIX instead of trying an unpublished marketplace ID. The extension remains local-only and reviews `.ur/ide/diffs` bundles from the current workspace. |
268
- | Professional clarification dialogs | `AskUserQuestion`, `src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx` | Supports up to eight concrete options, infers labels from description-only option objects, accepts prompt aliases, rejects duplicate inferred labels, and is loaded without ToolSearch preloading so typed schemas are available before use. |
274
+ | Professional clarification dialogs | `AskUserQuestion`, `src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx` | Supports up to eight concrete options, infers labels from description-only option objects, accepts prompt aliases, deduplicates equivalent labels, safely repairs single-suggestion payloads with a neutral rejection choice, and is loaded without ToolSearch preloading so typed schemas are available before use. |
269
275
  | Documentation release sync | `README.md`, `docs/`, `documentation/`, `CHANGELOG.md` | Keeps the npm README, static documentation site, provider guide, usage guide, feature ledger, validation runbook, and release notes aligned with current release behavior. |
270
276
 
271
277
  ## v1.24.0 Additions
@@ -17,6 +17,31 @@ Start UR with `--screen-reader`, set `UR_SCREEN_READER=1`, or use
17
17
  edits, and reduced animation. `vimEscape` accepts 2–8 printable non-whitespace
18
18
  characters or `off`.
19
19
 
20
+ ## Interactive task planning
21
+
22
+ UR uses strict-hybrid task tracking by default: one atomic, low-risk outcome
23
+ can proceed directly, while multi-outcome, sequenced, planned, delegated,
24
+ project-sized, release, migration, security, sandbox, and production work must
25
+ create a visible task before the first mutation. Read-only investigation is
26
+ never blocked.
27
+
28
+ ```jsonc
29
+ {
30
+ "tasks": {
31
+ "requireBeforeChanges": {
32
+ "enabled": true,
33
+ "freeReads": 3
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ `freeReads` is a compatibility allowance for non-interactive integrations that
40
+ do not carry a classified user turn; it is not a limit on investigation. Set
41
+ it to `0` to require a task before every mutation. Set `enabled` to `false` to
42
+ return to advisory task tracking. Profiles that omit `TaskCreate` are not
43
+ gated, because they could not satisfy the requirement.
44
+
20
45
  ## Model Providers
21
46
 
22
47
  UR-Nexus supports official provider access paths only:
package/docs/USAGE.md CHANGED
@@ -50,7 +50,9 @@ application. Use Blender locally, or run the 3ds Max project on a Windows host.
50
50
 
51
51
  When UR needs a focused clarification, it uses the `AskUserQuestion` dialog.
52
52
  Professional clarification prompts can provide up to eight concrete options;
53
- UR also accepts custom "Other" answers when the dialog includes one.
53
+ UR also accepts custom "Other" answers. If a model supplies only one concrete
54
+ suggestion, UR keeps it and adds a neutral `Different answer` rejection path
55
+ instead of showing an internal validation error or inventing another choice.
54
56
 
55
57
  ## Print Mode
56
58
 
@@ -426,6 +428,33 @@ in dependency order. `ur exec` materializes this graph deterministically; the
426
428
  interactive agent follows the same lifecycle and its task/agent tools enforce
427
429
  the concurrency boundary.
428
430
 
431
+ Interactive work uses a strict-hybrid task policy by default. One atomic,
432
+ low-risk outcome can be implemented directly. Before the first mutation, UR
433
+ requires a visible task for requests with two or more outcomes, enumerated or
434
+ sequenced work, plan mode, delegation, dependencies, project-sized work, and
435
+ release, publishing, deployment, migration, security, credential, permission,
436
+ sandbox, or production risk. Read-only inspection never needs a task, so the
437
+ agent can understand the repository before it creates the board. A custom tool
438
+ profile without `TaskCreate` remains usable and does not deadlock.
439
+
440
+ The default can be tuned in `.ur/settings.json` or user settings:
441
+
442
+ ```json
443
+ {
444
+ "tasks": {
445
+ "requireBeforeChanges": {
446
+ "enabled": true,
447
+ "freeReads": 3
448
+ }
449
+ }
450
+ }
451
+ ```
452
+
453
+ Set `enabled` to `false` for advisory task tracking. Set `freeReads` to `0` for
454
+ the fully strict policy that requires a task before every mutation, including
455
+ an atomic change. The positive atomic classification otherwise stays direct
456
+ regardless of how many read-only tools were needed.
457
+
429
458
  A user prompt does not create a placeholder task. The task panel stays quiet
430
459
  for informational conversation, direct one-step changes, acknowledgements, and
431
460
  small corrections. For genuinely multi-step work, multiple independently
@@ -19,7 +19,7 @@ You need:
19
19
 
20
20
  ```sh
21
21
  ur --version
22
- # expected for this release: "1.80.1 (UR-Nexus)"
22
+ # expected for this release: "1.80.3 (UR-Nexus)"
23
23
  ```
24
24
 
25
25
  ## 0.1 First-workspace model selection (1.45.4)
@@ -45,7 +45,7 @@
45
45
  <main id="content" class="content">
46
46
  <header class="topbar">
47
47
  <div>
48
- <p class="eyebrow">Version 1.80.1</p>
48
+ <p class="eyebrow">Version 1.80.3</p>
49
49
  <h1>UR-Nexus Documentation</h1>
50
50
  <p class="lead">A practical, tutorial-style reference for installing, configuring, automating, extending, and operating UR-Nexus.</p>
51
51
  </div>
@@ -7,7 +7,7 @@ plugins {
7
7
  }
8
8
 
9
9
  group = "dev.urnexus"
10
- version = "1.80.1"
10
+ version = "1.80.3"
11
11
 
12
12
  repositories {
13
13
  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.80.1",
5
+ "version": "1.80.3",
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.80.1",
3
+ "version": "1.80.3",
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",