@ouro.bot/cli 0.1.0-alpha.674 → 0.1.0-alpha.675

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.
Files changed (63) hide show
  1. package/README.md +11 -5
  2. package/changelog.json +13 -0
  3. package/dist/arc/evolution.js +13 -10
  4. package/dist/arc/obligations.js +1 -1
  5. package/dist/heart/active-work.js +3 -3
  6. package/dist/heart/agent-entry.js +8 -8
  7. package/dist/heart/commitments.js +1 -1
  8. package/dist/heart/core.js +45 -23
  9. package/dist/heart/daemon/agent-config-check.js +24 -0
  10. package/dist/heart/daemon/agent-discovery.js +28 -17
  11. package/dist/heart/daemon/agent-service.js +6 -6
  12. package/dist/heart/daemon/await-private-wake.js +59 -0
  13. package/dist/heart/daemon/cli-exec.js +180 -24
  14. package/dist/heart/daemon/cli-help.js +20 -2
  15. package/dist/heart/daemon/cli-parse.js +45 -2
  16. package/dist/heart/daemon/cli-render.js +1 -0
  17. package/dist/heart/daemon/daemon-entry.js +122 -25
  18. package/dist/heart/daemon/daemon.js +223 -20
  19. package/dist/heart/daemon/habit-private-wake.js +56 -0
  20. package/dist/heart/daemon/inner-status.js +3 -3
  21. package/dist/heart/daemon/message-router.js +39 -3
  22. package/dist/heart/daemon/pulse.js +43 -7
  23. package/dist/heart/daemon/socket-client.js +14 -2
  24. package/dist/heart/daemon/startup-tui.js +9 -1
  25. package/dist/heart/daemon/thoughts.js +39 -39
  26. package/dist/heart/habits/habit-scheduler.js +24 -4
  27. package/dist/heart/mailbox/mailbox-view.js +1 -1
  28. package/dist/heart/mailbox/readers/agent-machine.js +7 -7
  29. package/dist/heart/primitives.js +1 -1
  30. package/dist/heart/private-runtime/decision-renderer.js +156 -0
  31. package/dist/heart/private-runtime/index.js +18 -0
  32. package/dist/heart/private-runtime/ledger.js +218 -0
  33. package/dist/heart/private-runtime/policy.js +205 -0
  34. package/dist/heart/private-runtime/types.js +2 -0
  35. package/dist/heart/progress-story.js +1 -1
  36. package/dist/heart/session-transcript.js +1 -1
  37. package/dist/heart/tool-activity-callbacks.js +1 -1
  38. package/dist/heart/tool-description.js +2 -2
  39. package/dist/heart/tool-loop.js +2 -2
  40. package/dist/heart/turn-context.js +5 -5
  41. package/dist/mailbox-ui/assets/index-J8zDwHmE.js +1 -0
  42. package/dist/mailbox-ui/index.html +1 -1
  43. package/dist/mailroom/attention.js +1 -1
  44. package/dist/mind/context.js +2 -2
  45. package/dist/mind/pending.js +12 -5
  46. package/dist/mind/prompt.js +32 -25
  47. package/dist/repertoire/coding/feedback.js +25 -4
  48. package/dist/repertoire/tools-awaiting.js +2 -2
  49. package/dist/repertoire/tools-flow.js +4 -4
  50. package/dist/repertoire/tools-record.js +1 -1
  51. package/dist/repertoire/tools-session.js +33 -67
  52. package/dist/repertoire/tools-surface.js +3 -3
  53. package/dist/senses/cli.js +2 -2
  54. package/dist/senses/inner-dialog-worker.js +13 -519
  55. package/dist/senses/inner-dialog.js +10 -961
  56. package/dist/senses/mail.js +21 -5
  57. package/dist/senses/pipeline.js +1 -1
  58. package/dist/senses/private-runtime-worker.js +578 -0
  59. package/dist/senses/private-runtime.js +1145 -0
  60. package/dist/senses/shared-turn.js +1 -1
  61. package/dist/senses/trust-gate.js +2 -2
  62. package/package.json +1 -1
  63. package/dist/mailbox-ui/assets/index-CaTIFDmv.js +0 -1
@@ -100,6 +100,7 @@ const core_2 = require("../../nerves/review/core");
100
100
  const cli_render_1 = require("./cli-render");
101
101
  const cli_defaults_1 = require("./cli-defaults");
102
102
  const agent_config_check_1 = require("./agent-config-check");
103
+ const private_runtime_1 = require("../private-runtime");
103
104
  const doctor_1 = require("./doctor");
104
105
  const cli_render_doctor_1 = require("./cli-render-doctor");
105
106
  const interactive_repair_1 = require("./interactive-repair");
@@ -312,10 +313,13 @@ function providerStatusRowsCoverAgents(rows, agents) {
312
313
  }
313
314
  return true;
314
315
  }
316
+ function providerRowNeedsLiveReadinessRefresh(row) {
317
+ return row.provider !== "unconfigured" && row.readiness === "unknown";
318
+ }
315
319
  async function checkAgentProvidersFromDaemonStatus(deps, agents, onProgress) {
316
320
  const uniqueAgents = [...new Set(agents)];
317
321
  if (uniqueAgents.length === 0)
318
- return [];
322
+ return { degraded: [], needsLiveReadinessRefresh: false };
319
323
  let response;
320
324
  try {
321
325
  response = await deps.sendCommand(deps.socketPath, { kind: "daemon.status" });
@@ -342,7 +346,10 @@ async function checkAgentProvidersFromDaemonStatus(deps, agents, onProgress) {
342
346
  onProgress?.(degraded.length === 0
343
347
  ? "provider readiness confirmed by daemon status"
344
348
  : "provider readiness reported by daemon status");
345
- return degraded;
349
+ return {
350
+ degraded,
351
+ needsLiveReadinessRefresh: rows.some(providerRowNeedsLiveReadinessRefresh),
352
+ };
346
353
  }
347
354
  async function checkAgentProviderHealth(agentName, bundlesRoot, deps, onProgress, options = {}) {
348
355
  const liveDeps = {};
@@ -425,11 +432,12 @@ function agentResolutionFailureMode(command) {
425
432
  case "attention.list":
426
433
  case "attention.show":
427
434
  case "attention.history":
435
+ case "private.decisions":
436
+ case "private.status":
428
437
  case "work.card":
429
438
  case "work.gauntlet":
430
439
  case "work.sentinel":
431
440
  case "work.sentinel.refresh":
432
- case "inner.status":
433
441
  case "session.list":
434
442
  return "return-message";
435
443
  case "a2a.card":
@@ -513,9 +521,57 @@ function managedAgentsSignature(agentNames) {
513
521
  async function checkAlreadyRunningAgentProviders(deps, onProgress) {
514
522
  const agents = await listCliAgents(deps);
515
523
  const statusResult = await checkAgentProvidersFromDaemonStatus(deps, agents, onProgress);
516
- if (statusResult)
517
- return statusResult;
518
- return checkAgentProviders(deps, agents, onProgress);
524
+ if (statusResult) {
525
+ const configResult = await checkAgentConfigsOffline(deps, agents);
526
+ if (configResult.length > 0) {
527
+ return { degraded: [...statusResult.degraded, ...configResult], source: "daemon-status" };
528
+ }
529
+ if (statusResult.needsLiveReadinessRefresh) {
530
+ return { degraded: await checkAgentProviders(deps, agents, onProgress), source: "live-provider-check" };
531
+ }
532
+ return { degraded: statusResult.degraded, source: "daemon-status" };
533
+ }
534
+ return { degraded: await checkAgentConfigsOffline(deps, agents, onProgress), source: "offline-config" };
535
+ }
536
+ async function checkAgentConfigsOffline(deps, agents, onProgress) {
537
+ const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
538
+ const degraded = [];
539
+ for (const agent of [...new Set(agents)]) {
540
+ try {
541
+ const result = (0, agent_config_check_1.checkAgentConfig)(agent, bundlesRoot);
542
+ if (result.ok)
543
+ continue;
544
+ const errorReason = result.error ?? "agent config validation failed";
545
+ const fixHint = result.fix ?? "";
546
+ degraded.push({ agent, errorReason, fixHint, ...(result.issue ? { issue: result.issue } : {}) });
547
+ (0, runtime_1.emitNervesEvent)({
548
+ level: "error",
549
+ component: "daemon",
550
+ event: "daemon.agent_config_invalid",
551
+ message: errorReason,
552
+ meta: { agent, fixProvided: fixHint.length > 0, source: "already-running-offline-config-check" },
553
+ });
554
+ }
555
+ catch (error) {
556
+ const errorReason = error instanceof Error ? error.message : String(error);
557
+ degraded.push({
558
+ agent,
559
+ errorReason,
560
+ fixHint: "Run 'ouro doctor' for diagnostics, then retry 'ouro up'.",
561
+ });
562
+ (0, runtime_1.emitNervesEvent)({
563
+ level: "error",
564
+ component: "daemon",
565
+ event: "daemon.agent_config_invalid",
566
+ message: errorReason,
567
+ meta: { agent, fixProvided: true, source: "already-running-offline-config-check" },
568
+ });
569
+ }
570
+ }
571
+ onProgress?.(degraded.length === 0
572
+ ? "agent config validated offline; provider readiness will refresh on explicit provider commands"
573
+ : "agent config validation reported by offline startup check");
574
+ return degraded;
519
575
  }
520
576
  function readinessIssueFromDegraded(entry) {
521
577
  return entry.issue ?? (0, readiness_repair_1.genericReadinessIssue)({
@@ -548,6 +604,23 @@ function providerRepairCountSummary(count) {
548
604
  return "selected providers answered live checks";
549
605
  return `${count} ${count === 1 ? "needs" : "need"} attention`;
550
606
  }
607
+ function startupConfigCheckSummary(count) {
608
+ if (count === 0)
609
+ return "agent config validated offline";
610
+ return `${count} ${count === 1 ? "needs" : "need"} attention`;
611
+ }
612
+ function startupProviderCheckSummary(result) {
613
+ if (result.source === "daemon-status" && result.degraded.length === 0) {
614
+ return "provider readiness confirmed by daemon status";
615
+ }
616
+ if (result.source === "daemon-status") {
617
+ return providerRepairCountSummary(result.degraded.length);
618
+ }
619
+ if (result.source === "live-provider-check") {
620
+ return providerRepairCountSummary(result.degraded.length);
621
+ }
622
+ return startupConfigCheckSummary(result.degraded.length);
623
+ }
551
624
  /**
552
625
  * Layer 2: human-readable summary of boot-sync-probe findings, written to
553
626
  * stdout when any non-clean finding surfaces. The order reads "blockers
@@ -910,7 +983,13 @@ async function ensureDaemonRunning(deps, options = {}) {
910
983
  }
911
984
  return null;
912
985
  };
913
- const alive = options.initialAlive ?? await deps.checkSocketAlive(deps.socketPath);
986
+ let alive;
987
+ if (typeof options.initialAlive === "boolean") {
988
+ alive = options.initialAlive;
989
+ }
990
+ else {
991
+ alive = await deps.checkSocketAlive(deps.socketPath);
992
+ }
914
993
  if (alive) {
915
994
  const localRuntime = (0, runtime_metadata_1.getRuntimeMetadata)();
916
995
  const localManagedAgents = managedAgentsSignature((0, agent_discovery_1.listEnabledBundleAgents)({
@@ -1362,6 +1441,12 @@ function writeAgentVaultConfig(agentName, configPath, config, vault) {
1362
1441
  function isJsonRecord(value) {
1363
1442
  return !!value && typeof value === "object" && !Array.isArray(value);
1364
1443
  }
1444
+ function daemonMessageReceiptId(response) {
1445
+ if (!isJsonRecord(response.data))
1446
+ return undefined;
1447
+ const id = response.data.id;
1448
+ return typeof id === "string" && id.trim().length > 0 ? id : undefined;
1449
+ }
1365
1450
  function cloneJsonRecord(value) {
1366
1451
  return JSON.parse(JSON.stringify(value));
1367
1452
  }
@@ -3850,6 +3935,22 @@ function makeBackgroundOperationId(kind) {
3850
3935
  const prefix = kind === "mail.import-mbox" ? "op_mail_import" : "op_mail_backfill";
3851
3936
  return `${prefix}_${(0, crypto_1.randomUUID)().slice(0, 8)}`;
3852
3937
  }
3938
+ function buildMailOperationPrivateWakeCommand(agentName, record) {
3939
+ const status = record.status === "failed" ? "failed" : "succeeded";
3940
+ return {
3941
+ kind: "private.wake",
3942
+ agent: agentName,
3943
+ reason: "mail background operation private attention",
3944
+ triggerSource: "mail-background-operation",
3945
+ budgetClass: "interactive",
3946
+ idempotencyKey: `mail-operation:${agentName}:${record.id}:${status}`,
3947
+ originRefs: [
3948
+ { kind: "background-operation", id: record.id },
3949
+ { kind: "mail-operation", id: record.kind },
3950
+ { kind: "mail-operation-status", id: status },
3951
+ ],
3952
+ };
3953
+ }
3853
3954
  async function notifyMailOperation(agentName, record, deps) {
3854
3955
  const lines = [
3855
3956
  "[Background Operation]",
@@ -3881,7 +3982,7 @@ async function notifyMailOperation(agentName, record, deps) {
3881
3982
  mode: "reflect",
3882
3983
  });
3883
3984
  await queueMailOperationTargetNotification(agentName, content, deps).catch(() => undefined);
3884
- await deps.sendCommand(deps.socketPath, { kind: "inner.wake", agent: agentName })
3985
+ await deps.sendCommand(deps.socketPath, buildMailOperationPrivateWakeCommand(agentName, record))
3885
3986
  .then(() => undefined)
3886
3987
  .catch(() => undefined);
3887
3988
  }
@@ -6159,9 +6260,10 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
6159
6260
  }
6160
6261
  }
6161
6262
  progress.startPhase("provider checks");
6162
- const providerDegraded = await checkAlreadyRunningAgentProviders(deps, (msg) => progress.updateDetail(msg));
6263
+ const providerCheck = await checkAlreadyRunningAgentProviders(deps, (msg) => progress.updateDetail(msg));
6264
+ const providerDegraded = providerCheck.degraded;
6163
6265
  daemonResult.stability = mergeStartupStability(daemonResult.stability, providerDegraded);
6164
- progress.completePhase("provider checks", providerRepairCountSummary(providerDegraded.length));
6266
+ progress.completePhase("provider checks", startupProviderCheckSummary(providerCheck));
6165
6267
  progress.startPhase("final daemon check");
6166
6268
  const finalDaemonCheck = await verifyDaemonReadyForHandoff(deps, {
6167
6269
  allowDegradedHealth: Boolean(command.noRepair
@@ -6616,7 +6718,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
6616
6718
  // when the daemon socket file doesn't exist — otherwise every
6617
6719
  // Claude Code lifecycle event during a daemon-down window logs two
6618
6720
  // ENOENT errors in ouro.ndjson (one for message.send, one for
6619
- // inner.wake) which makes it hard to read the log around outages.
6721
+ // private.wake) which makes it hard to read the log around outages.
6620
6722
  // The hook is best-effort: dropping notifications when the daemon
6621
6723
  // is down is the correct behavior; we just don't want to log spam
6622
6724
  // about it.
@@ -6627,14 +6729,25 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
6627
6729
  // single tool use. A long Claude Code working session can fire
6628
6730
  // dozens of post-tool-use hooks per minute; waking the agent
6629
6731
  // synchronously on each one creates a feedback storm where the
6630
- // inner loop is re-prompted faster than it can rest, the
6732
+ // private runtime is re-prompted faster than it can rest, the
6631
6733
  // "...time passing. anything stirring?" probe fires back-to-back,
6632
6734
  // and the agent burns its attention budget responding to wakes
6633
6735
  // instead of doing actual work. The message is still delivered
6634
6736
  // either way (above); the agent picks it up on its next natural
6635
6737
  // turn.
6636
6738
  if (eventType === "session-start" || eventType === "stop") {
6637
- await deps.sendCommand(deps.socketPath, { kind: "inner.wake", agent: command.agent }).catch(() => { });
6739
+ await deps.sendCommand(deps.socketPath, {
6740
+ kind: "private.wake",
6741
+ agent: command.agent,
6742
+ reason: `Claude Code ${eventType} hook`,
6743
+ triggerSource: "dev-tool-hook",
6744
+ budgetClass: "interactive",
6745
+ idempotencyKey: `dev-tool-hook:${command.agent}:${eventType}:${sessionId}`,
6746
+ originRefs: [
6747
+ { kind: "dev-tool-hook", id: eventType },
6748
+ { kind: "session", id: sessionId },
6749
+ ],
6750
+ }).catch(() => { });
6638
6751
  }
6639
6752
  }
6640
6753
  catch { /* daemon not running — silent */ }
@@ -6817,6 +6930,32 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
6817
6930
  return "";
6818
6931
  }
6819
6932
  /* v8 ignore stop */
6933
+ if (command.kind === "private.decisions") {
6934
+ let response;
6935
+ try {
6936
+ response = await deps.sendCommand(deps.socketPath, {
6937
+ kind: "private.decisions",
6938
+ agent: command.agent,
6939
+ limit: command.limit,
6940
+ });
6941
+ }
6942
+ catch {
6943
+ const message = "daemon unavailable — start with `ouro up` first";
6944
+ deps.writeStdout(message);
6945
+ return message;
6946
+ }
6947
+ if (!response.ok) {
6948
+ const message = response.error ?? "unknown error";
6949
+ deps.writeStdout(message);
6950
+ return message;
6951
+ }
6952
+ const payload = (0, private_runtime_1.privateDecisionReadPayloadFromDaemonData)(response.data, command.agent);
6953
+ const message = command.json
6954
+ ? (0, private_runtime_1.formatPrivateDecisionReadJson)(payload)
6955
+ : (0, private_runtime_1.formatPrivateDecisionReadText)(payload);
6956
+ deps.writeStdout(message);
6957
+ return message;
6958
+ }
6820
6959
  // ── mcp subcommands (routed through daemon socket) ──
6821
6960
  if (command.kind === "mcp.list" || command.kind === "mcp.call") {
6822
6961
  const daemonCommand = toDaemonCommand(command);
@@ -7371,7 +7510,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7371
7510
  /* v8 ignore next -- production fallback: tests always inject bundlesRoot via createTmpBundle @preserve */
7372
7511
  const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
7373
7512
  const agentRoot = path.join(bundlesRoot, `${command.agent}.ouro`);
7374
- const sessionFilePath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
7513
+ const sessionFilePath = (0, thoughts_1.getPrivateRuntimeSessionPath)(agentRoot);
7375
7514
  if (command.json) {
7376
7515
  try {
7377
7516
  const raw = fs.readFileSync(sessionFilePath, "utf-8");
@@ -7379,12 +7518,12 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7379
7518
  return raw;
7380
7519
  }
7381
7520
  catch {
7382
- const message = "no inner dialog session found";
7521
+ const message = "no private-runtime session found";
7383
7522
  deps.writeStdout(message);
7384
7523
  return message;
7385
7524
  }
7386
7525
  }
7387
- const turns = (0, thoughts_1.parseInnerDialogSession)(sessionFilePath);
7526
+ const turns = (0, thoughts_1.parsePrivateRuntimeSession)(sessionFilePath);
7388
7527
  const message = (0, thoughts_1.formatThoughtTurns)(turns, command.last ?? 10);
7389
7528
  deps.writeStdout(message);
7390
7529
  if (command.follow) {
@@ -7516,9 +7655,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7516
7655
  deps.writeStdout(message);
7517
7656
  return message;
7518
7657
  }
7519
- // ── inner dialog status (local, no daemon socket needed) ──
7520
- /* v8 ignore start -- inner status handler: requires real agent state on disk @preserve */
7521
- if (command.kind === "inner.status") {
7658
+ // ── private runtime status (local, no daemon socket needed) ──
7659
+ /* v8 ignore start -- private status handler: requires real agent state on disk @preserve */
7660
+ if (command.kind === "private.status") {
7522
7661
  try {
7523
7662
  const agentRoot = deps.agentBundleRoot ?? (0, identity_1.getAgentRoot)(command.agent);
7524
7663
  const { buildInnerStatusOutput } = await Promise.resolve().then(() => __importStar(require("./inner-status")));
@@ -7526,8 +7665,8 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7526
7665
  const { parseFrontmatter } = await Promise.resolve().then(() => __importStar(require("../../util/frontmatter")));
7527
7666
  const { listActiveReturnObligations } = await Promise.resolve().then(() => __importStar(require("../../arc/obligations")));
7528
7667
  const { resolveDeskRecordPaths } = await Promise.resolve().then(() => __importStar(require("../../mind/record-paths")));
7529
- // Read runtime state
7530
- const innerSessionPath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
7668
+ // Read runtime state from the persisted historical session location.
7669
+ const innerSessionPath = (0, thoughts_1.getPrivateRuntimeSessionPath)(agentRoot);
7531
7670
  const runtimeJsonPath = path.join(path.dirname(innerSessionPath), "runtime.json");
7532
7671
  let runtimeState = null;
7533
7672
  try {
@@ -7580,7 +7719,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7580
7719
  catch { /* no habits — heartbeat unknown */ }
7581
7720
  // Attention count
7582
7721
  const activeObligations = listActiveReturnObligations(command.agent);
7583
- const message = buildInnerStatusOutput({
7722
+ const statusOutput = buildInnerStatusOutput({
7584
7723
  agentName: command.agent,
7585
7724
  runtimeState,
7586
7725
  recordSummary,
@@ -7588,6 +7727,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7588
7727
  attentionCount: activeObligations.length,
7589
7728
  now: Date.now(),
7590
7729
  });
7730
+ const message = command.legacyAlias === "inner"
7731
+ ? [`legacy alias: use \`ouro private status --agent ${command.agent}\``, statusOutput].join("\n")
7732
+ : statusOutput;
7591
7733
  deps.writeStdout(message);
7592
7734
  return message;
7593
7735
  }
@@ -7901,11 +8043,25 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7901
8043
  response = await deps.sendCommand(deps.socketPath, daemonCommand);
7902
8044
  // `ouro msg` is operator-driven and expects the recipient to process the
7903
8045
  // message now (vs. on next natural turn). message.send is queue-only as
7904
- // of the 2026-05-11 fix; we explicitly fire inner.wake to preserve the
8046
+ // of the 2026-05-11 fix; we explicitly fire private.wake to preserve the
7905
8047
  // historical CLI UX. Background callers (hooks, API) deliberately omit
7906
8048
  // this and let the agent pick up notifications on its next turn.
7907
8049
  if (command.kind === "message.send" && command.from === "ouro-cli") {
7908
- await deps.sendCommand(deps.socketPath, { kind: "inner.wake", agent: command.to }).catch(() => { });
8050
+ const receiptId = daemonMessageReceiptId(response);
8051
+ await deps.sendCommand(deps.socketPath, {
8052
+ kind: "private.wake",
8053
+ agent: command.to,
8054
+ reason: "operator CLI message",
8055
+ triggerSource: "operator-cli",
8056
+ budgetClass: "interactive",
8057
+ idempotencyKey: receiptId
8058
+ ? `cli:message:${command.to}:${receiptId}`
8059
+ : `cli:message:${command.to}:unreceipted`,
8060
+ originRefs: [
8061
+ { kind: "cli-command", id: "ouro msg" },
8062
+ ...(receiptId ? [{ kind: "daemon-receipt", id: receiptId }] : []),
8063
+ ],
8064
+ }).catch(() => { });
7909
8065
  }
7910
8066
  }
7911
8067
  catch (error) {
@@ -273,15 +273,23 @@ exports.COMMAND_REGISTRY = {
273
273
  },
274
274
  thoughts: {
275
275
  category: "Internal",
276
- description: "View agent inner dialog thoughts",
276
+ description: "View private runtime transcript turns",
277
277
  usage: "ouro thoughts [--last <n>] [--json] [--follow] [--agent <name>]",
278
278
  example: "ouro thoughts --last 5 --follow",
279
279
  },
280
+ private: {
281
+ category: "Internal",
282
+ description: "Inspect private-runtime status and policy decisions",
283
+ usage: "ouro private status|decisions [--agent <name>] [--limit <n>] [--json]",
284
+ example: "ouro private status --agent ouroboros",
285
+ subcommands: ["status", "decisions"],
286
+ },
280
287
  inner: {
281
288
  category: "Internal",
282
- description: "Show inner dialog status",
289
+ description: "Legacy alias for `ouro private status`",
283
290
  usage: "ouro inner [--agent <name>]",
284
291
  example: "ouro inner",
292
+ hidden: true,
285
293
  },
286
294
  attention: {
287
295
  category: "Internal",
@@ -331,6 +339,16 @@ exports.COMMAND_REGISTRY = {
331
339
  },
332
340
  };
333
341
  const SUBCOMMAND_HELP = {
342
+ "private decisions": {
343
+ description: "Read recent private-runtime allow/deny decisions from the policy ledger",
344
+ usage: "ouro private decisions [--agent <name>] [--limit <n>] [--json]",
345
+ example: "ouro private decisions --agent ouroboros --json",
346
+ },
347
+ "private status": {
348
+ description: "Show private-runtime status from local agent state",
349
+ usage: "ouro private status [--agent <name>]",
350
+ example: "ouro private status --agent ouroboros",
351
+ },
334
352
  "auth verify": {
335
353
  description: "Verify agent provider credentials without changing provider/model lanes",
336
354
  usage: "ouro auth verify [--agent <name>] [--provider <provider>]",
@@ -118,9 +118,10 @@ function usage() {
118
118
  " ouro friend create --name <name> [--trust <level>] [--agent <name>]",
119
119
  " ouro friend update <id> --trust <level> [--agent <name>]",
120
120
  " ouro thoughts [--last <n>] [--json] [--follow] [--agent <name>]",
121
+ " ouro private decisions [--agent <name>] [--limit <n>] [--json]",
122
+ " ouro private status [--agent <name>]",
121
123
  " ouro work card|gauntlet|sentinel [refresh] [--agent <name>] [--format text|json|--json]",
122
124
  " ouro nerves-review [--agent <name>] [--process <name>] [--component <substr>] [--event <substr>] [--level <level>] [--since <duration>] [--limit <n>] [--json]",
123
- " ouro inner [--agent <name>]",
124
125
  " ouro friend link <agent> --friend <id> --provider <p> --external-id <eid>",
125
126
  " ouro friend unlink <agent> --friend <id> --provider <p> --external-id <eid>",
126
127
  " ouro a2a card [--agent <name>] [--base-url <url>] [--json]",
@@ -1637,6 +1638,46 @@ function parseNervesReviewCommand(args) {
1637
1638
  json,
1638
1639
  };
1639
1640
  }
1641
+ function parsePrivateCommand(args) {
1642
+ const [subcommand] = args;
1643
+ if (subcommand === "status") {
1644
+ const { agent, rest } = extractAgentFlag(args.slice(1));
1645
+ if (rest.length > 0) {
1646
+ throw new Error("Usage: ouro private status [--agent <name>]");
1647
+ }
1648
+ return { kind: "private.status", ...(agent ? { agent } : {}) };
1649
+ }
1650
+ if (subcommand !== "decisions") {
1651
+ throw new Error("Usage: ouro private decisions [--agent <name>] [--limit <n>] [--json] OR ouro private status [--agent <name>]");
1652
+ }
1653
+ const { agent, rest } = extractAgentFlag(args.slice(1));
1654
+ let limit = 20;
1655
+ let json = false;
1656
+ for (let i = 0; i < rest.length; i += 1) {
1657
+ const token = rest[i];
1658
+ const next = rest[i + 1];
1659
+ if (token === "--json") {
1660
+ json = true;
1661
+ continue;
1662
+ }
1663
+ if (token === "--limit" && next) {
1664
+ const parsed = Number.parseInt(next, 10);
1665
+ if (!Number.isInteger(parsed) || String(parsed) !== next || parsed < 1 || parsed > 1000) {
1666
+ throw new Error("private decisions --limit must be an integer between 1 and 1000");
1667
+ }
1668
+ limit = parsed;
1669
+ i += 1;
1670
+ continue;
1671
+ }
1672
+ throw new Error("Usage: ouro private decisions [--agent <name>] [--limit <n>] [--json]");
1673
+ }
1674
+ return {
1675
+ kind: "private.decisions",
1676
+ ...(agent ? { agent } : {}),
1677
+ limit,
1678
+ json,
1679
+ };
1680
+ }
1640
1681
  // ── Main dispatch ──
1641
1682
  function parseOuroCommand(args) {
1642
1683
  const [head, second] = args;
@@ -1787,13 +1828,15 @@ function parseOuroCommand(args) {
1787
1828
  }
1788
1829
  if (head === "thoughts")
1789
1830
  return parseThoughtsCommand(args.slice(1));
1831
+ if (head === "private")
1832
+ return parsePrivateCommand(args.slice(1));
1790
1833
  if (head === "attention")
1791
1834
  return parseAttentionCommand(args.slice(1));
1792
1835
  if (head === "work")
1793
1836
  return parseWorkCommand(args.slice(1));
1794
1837
  if (head === "inner") {
1795
1838
  const { agent } = extractAgentFlag(args.slice(1));
1796
- return { kind: "inner.status", ...(agent ? { agent } : {}) };
1839
+ return { kind: "private.status", ...(agent ? { agent } : {}), legacyAlias: "inner" };
1797
1840
  }
1798
1841
  if (head === "chat") {
1799
1842
  if (!second)
@@ -239,6 +239,7 @@ function parseStatusPayload(data) {
239
239
  return {
240
240
  agent,
241
241
  worker,
242
+ autoStart: booleanField(row.autoStart) ?? true,
242
243
  status,
243
244
  pid,
244
245
  restartCount,