@ouro.bot/cli 0.1.0-alpha.92 → 0.1.0-alpha.94

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.json CHANGED
@@ -1,6 +1,19 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.94",
6
+ "changes": [
7
+ "Fix stale CurrentVersion symlink not healing during `ouro up` — the daemon now detects and repairs dangling version symlinks before reading the active version.",
8
+ "Fix homedir regression in daemon-cli-defaults test and cover changelog-null branch."
9
+ ]
10
+ },
11
+ {
12
+ "version": "0.1.0-alpha.93",
13
+ "changes": [
14
+ "Final-answer truth checks now require fresh external-state verification (gh pr view, npm view, etc.) before allowing intent=complete when a live obligation is active, preventing stale or guessed merge/publish/deploy claims."
15
+ ]
16
+ },
4
17
  {
5
18
  "version": "0.1.0-alpha.92",
6
19
  "changes": [
@@ -7,6 +7,7 @@ exports.getModel = getModel;
7
7
  exports.getProvider = getProvider;
8
8
  exports.createSummarize = createSummarize;
9
9
  exports.getProviderDisplayLabel = getProviderDisplayLabel;
10
+ exports.isExternalStateQuery = isExternalStateQuery;
10
11
  exports.getFinalAnswerRetryError = getFinalAnswerRetryError;
11
12
  exports.stripLastToolCalls = stripLastToolCalls;
12
13
  exports.repairOrphanedToolCalls = repairOrphanedToolCalls;
@@ -228,7 +229,14 @@ function parseFinalAnswerPayload(argumentsText) {
228
229
  return {};
229
230
  }
230
231
  }
231
- function getFinalAnswerRetryError(mustResolveBeforeHandoff, intent, sawSteeringFollowUp, delegationDecision, sawSendMessageSelf, sawGoInward, sawQuerySession, currentObligation, innerJob) {
232
+ /** Returns true when a tool call queries external state (GitHub, npm registry). */
233
+ function isExternalStateQuery(toolName, args) {
234
+ if (toolName !== "shell")
235
+ return false;
236
+ const cmd = String(args.command ?? "");
237
+ return /\bgh\s+(pr|run|api|issue)\b/.test(cmd) || /\bnpm\s+(view|info|show)\b/.test(cmd);
238
+ }
239
+ function getFinalAnswerRetryError(mustResolveBeforeHandoff, intent, sawSteeringFollowUp, delegationDecision, sawSendMessageSelf, sawGoInward, sawQuerySession, currentObligation, innerJob, sawExternalStateQuery) {
232
240
  // 1. Delegation adherence: delegate-inward without evidence of inward action
233
241
  if (delegationDecision?.target === "delegate-inward" && !sawSendMessageSelf && !sawGoInward && !sawQuerySession) {
234
242
  (0, runtime_1.emitNervesEvent)({
@@ -258,6 +266,10 @@ function getFinalAnswerRetryError(mustResolveBeforeHandoff, intent, sawSteeringF
258
266
  if (mustResolveBeforeHandoff && intent === "complete" && currentObligation && !sawSteeringFollowUp) {
259
267
  return "you still owe the live session a visible return on this work. don't end the turn yet — continue until you've brought back the external-state update, or use intent=blocked with the concrete blocker.";
260
268
  }
269
+ // 6. External-state grounding: obligation + complete requires fresh external verification
270
+ if (intent === "complete" && currentObligation && !sawExternalStateQuery && !sawSteeringFollowUp) {
271
+ return "you're claiming this work is complete, but the external state hasn't been verified this turn. ground your claim with a fresh check (gh pr view, npm view, gh run view, etc.) before calling final_answer.";
272
+ }
261
273
  return null;
262
274
  }
263
275
  // Re-export kick utilities for backward compat
@@ -477,6 +489,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
477
489
  let sawGoInward = false;
478
490
  let sawQuerySession = false;
479
491
  let sawBridgeManage = false;
492
+ let sawExternalStateQuery = false;
480
493
  // Prevent MaxListenersExceeded warning — each iteration adds a listener
481
494
  try {
482
495
  require("events").setMaxListeners(50, signal);
@@ -585,7 +598,7 @@ async function runAgent(messages, callbacks, channel, signal, options) {
585
598
  // Extract answer from the tool call arguments.
586
599
  // Supports: {"answer":"text","intent":"..."} or "text" (JSON string).
587
600
  const { answer, intent } = parseFinalAnswerPayload(result.toolCalls[0].arguments);
588
- const retryError = getFinalAnswerRetryError(mustResolveBeforeHandoffActive, intent, sawSteeringFollowUp, options?.delegationDecision, sawSendMessageSelf, sawGoInward, sawQuerySession, options?.currentObligation ?? null, options?.activeWorkFrame?.inner?.job);
601
+ const retryError = getFinalAnswerRetryError(mustResolveBeforeHandoffActive, intent, sawSteeringFollowUp, options?.delegationDecision, sawSendMessageSelf, sawGoInward, sawQuerySession, options?.currentObligation ?? null, options?.activeWorkFrame?.inner?.job, sawExternalStateQuery);
589
602
  const validDirectReply = mustResolveBeforeHandoffActive && intent === "direct_reply" && sawSteeringFollowUp;
590
603
  const validTerminalIntent = intent === "complete" || intent === "blocked";
591
604
  const validClosure = answer != null
@@ -783,6 +796,9 @@ async function runAgent(messages, callbacks, channel, signal, options) {
783
796
  /* v8 ignore next -- flag tested via truth-check integration tests @preserve */
784
797
  if (tc.name === "bridge_manage")
785
798
  sawBridgeManage = true;
799
+ /* v8 ignore next -- flag tested via truth-check integration tests @preserve */
800
+ if (isExternalStateQuery(tc.name, args))
801
+ sawExternalStateQuery = true;
786
802
  const argSummary = (0, tools_1.summarizeArgs)(tc.name, args);
787
803
  // Confirmation check for mutate tools
788
804
  if ((0, tools_1.isConfirmationRequired)(tc.name) && !options?.skipConfirmation) {
@@ -1353,12 +1353,12 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
1353
1353
  runAuthFlow: auth_flow_1.runRuntimeAuthFlow,
1354
1354
  registerOuroBundleType: ouro_uti_1.registerOuroBundleUti,
1355
1355
  installOuroCommand: ouro_path_installer_1.installOuroCommand,
1356
- /* v8 ignore start -- self-healing: ensures versioned layout has current version installed @preserve */
1356
+ /* v8 ignore start -- self-healing: ensures active symlink matches running runtime version @preserve */
1357
1357
  ensureCurrentVersionInstalled: () => {
1358
- const currentVersion = (0, ouro_version_manager_1.getCurrentVersion)({});
1359
- if (currentVersion)
1360
- return; // Already installed and linked
1358
+ const linkedVersion = (0, ouro_version_manager_1.getCurrentVersion)({});
1361
1359
  const version = (0, bundle_manifest_1.getPackageVersion)();
1360
+ if (linkedVersion === version)
1361
+ return;
1362
1362
  (0, ouro_version_manager_1.ensureLayout)({});
1363
1363
  const cliHome = (0, ouro_version_manager_1.getOuroCliHome)();
1364
1364
  const versionEntry = path.join(cliHome, "versions", version, "node_modules", "@ouro.bot", "cli", "dist", "heart", "daemon", "ouro-entry.js");
@@ -1817,6 +1817,7 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
1817
1817
  meta: { kind: command.kind },
1818
1818
  });
1819
1819
  if (command.kind === "daemon.up") {
1820
+ const linkedVersionBeforeUp = deps.getCurrentCliVersion?.() ?? null;
1820
1821
  // ── versioned CLI update check ──
1821
1822
  if (deps.checkForCliUpdate) {
1822
1823
  let pendingReExec = false;
@@ -1824,7 +1825,7 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
1824
1825
  const updateResult = await deps.checkForCliUpdate();
1825
1826
  if (updateResult.available && updateResult.latestVersion) {
1826
1827
  /* v8 ignore next -- fallback: getCurrentCliVersion always injected in tests @preserve */
1827
- const currentVersion = deps.getCurrentCliVersion?.() ?? "unknown";
1828
+ const currentVersion = linkedVersionBeforeUp ?? "unknown";
1828
1829
  await deps.installCliVersion(updateResult.latestVersion);
1829
1830
  deps.activateCliVersion(updateResult.latestVersion);
1830
1831
  deps.writeStdout(`ouro updated to ${updateResult.latestVersion} (was ${currentVersion})`);
@@ -1852,6 +1853,15 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
1852
1853
  }
1853
1854
  }
1854
1855
  await performSystemSetup(deps);
1856
+ const linkedVersionAfterSetup = deps.getCurrentCliVersion?.() ?? null;
1857
+ const runtimeVersion = (0, bundle_manifest_1.getPackageVersion)();
1858
+ if (linkedVersionBeforeUp && linkedVersionBeforeUp !== runtimeVersion && linkedVersionAfterSetup === runtimeVersion) {
1859
+ deps.writeStdout(`ouro updated to ${runtimeVersion} (was ${linkedVersionBeforeUp})`);
1860
+ const changelogCommand = (0, ouro_version_manager_1.buildChangelogCommand)(linkedVersionBeforeUp, runtimeVersion);
1861
+ if (changelogCommand) {
1862
+ deps.writeStdout(`review changes with: ${changelogCommand}`);
1863
+ }
1864
+ }
1855
1865
  if (deps.ensureDaemonBootPersistence) {
1856
1866
  try {
1857
1867
  await Promise.resolve(deps.ensureDaemonBootPersistence(deps.socketPath));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.92",
3
+ "version": "0.1.0-alpha.94",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",