@ouro.bot/cli 0.1.0-alpha.894 → 0.1.0-alpha.897

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 (35) hide show
  1. package/changelog.json +18 -0
  2. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
  3. package/deploy/unraid/sanctuary.xml +1 -1
  4. package/dist/heart/daemon/runtime-logging.js +1 -1
  5. package/dist/heart/daemon/sense-manager.js +20 -20
  6. package/dist/heart/identity.js +4 -4
  7. package/dist/heart/private-runtime/policy.js +4 -4
  8. package/dist/heart/sense-truth.js +2 -2
  9. package/dist/heart/{cmux-config.js → shepherd-config.js} +24 -24
  10. package/dist/heart/steward-policy.js +0 -26
  11. package/dist/heart/turn-context.js +5 -5
  12. package/dist/mind/prompt.js +5 -5
  13. package/dist/repertoire/bitwarden-store.js +153 -7
  14. package/dist/repertoire/credential-access.js +27 -23
  15. package/dist/repertoire/guardrails.js +4 -4
  16. package/dist/repertoire/tools-shepherd.js +181 -0
  17. package/dist/repertoire/tools.js +4 -4
  18. package/dist/repertoire/vault-unlock.js +59 -1
  19. package/dist/senses/{cmux → shepherd}/client.js +3 -3
  20. package/dist/senses/shepherd/cmux.js +332 -0
  21. package/dist/senses/shepherd/host.js +2 -0
  22. package/dist/senses/shepherd/judge.js +98 -0
  23. package/dist/senses/{cmux → shepherd}/redact.js +3 -3
  24. package/dist/senses/shepherd/returns.js +79 -0
  25. package/dist/senses/shepherd/sense.js +288 -0
  26. package/dist/senses/{cmux-entry.js → shepherd-entry.js} +10 -9
  27. package/npm-shrinkwrap.json +2 -2
  28. package/package.json +1 -1
  29. package/dist/repertoire/tools-cmux.js +0 -396
  30. package/dist/senses/cmux/answer.js +0 -191
  31. package/dist/senses/cmux/attention.js +0 -265
  32. package/dist/senses/cmux/casebook.js +0 -416
  33. package/dist/senses/cmux/floor.js +0 -407
  34. package/dist/senses/cmux/principles.js +0 -72
  35. package/dist/senses/cmux/sense.js +0 -287
package/changelog.json CHANGED
@@ -1,6 +1,24 @@
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.897",
6
+ "changes": [
7
+ "The cmux sense is now Ouro Shepherd (sense 'shepherd', tools shepherd_overview, shepherd_read and shepherd_signal; agent.json key senses.shepherd). Shepherd is agent-agnostic: every time a coding agent in a terminal hands control back, a cheap judge on the agent's own agent lane decides whether it should have, using the same rubric for Claude Code, Codex, Copilot CLI, Agency or any other agent.",
8
+ "A return is the terminal host's own stop signal: cmux's agent.hook.Stop after a 3-second grace period (dropped when the agent resumed), keyed by cmux's event id, with the agent's last message from cmux's session store (keyed by the agent's own session id; hook events name it '<agent>-<id>'). Terminals no cmux hook speaks for are polled; output that changed and then held still for 8 seconds is one return.",
9
+ "A premature return is answered visibly: one line typed as '[Ouro for <human>] <reply>' (pasted, then Enter, never starting with / ! or #, with no @, backslash or line break, at most 240 characters) or one menu key, and the status line says so. Shepherd first re-reads the screen and skips a session the human focused in the last minute. A loop guard stops after three answers in a row without a human focus, or ten in an hour, and escalates.",
10
+ "A stop while the agent's own background work runs (subagents, background shells, watchers) is not a return of control. The judge's new 'working' kind, and cmux's hadPendingBackgroundWorkAtStop (which also earns the stop a 30-second longer wait), mean Shepherd never answers it and never escalates it as a gate: it logs the last message as a progress update and sets the status line to '<agent> waiting on its background work: ...'. Only an update the judge flags as news reaches the Ouro agent, queued with no wake. The session is judged afresh at its next real stop.",
11
+ "Gates, finished work and loop-guard stops are escalated to the Ouro agent through a pending message and a private wake (trigger 'shepherd'); unclear returns and errors are only logged. Every judgment is one line in state/senses/shepherd/returns.jsonl with latency and input tokens.",
12
+ "Removed: the cmux Feed polling, the permission-prompt floor, casebook, standing-grant check (inspectStandingActionGrant), cmux_reply_once and cmux_correct, and the Claude-specific decision constants. The cmux machine config record (cmux.socketCapability and friends) is unchanged.",
13
+ "Review fixes: Shepherd never types into the terminal the human is in, read from cmux's system.tree just before sending (not only from focus events); the loop guard escalates once per trip and stops calling the judge until the human focuses the terminal; with background work reported every verdict is 'working' (a gate becomes news); a repeated background stop with the same last message is not judged again; a quiet terminal judged working or not an agent is checked less often (doubling up to 5 minutes); Shepherd's status is one cmux entry per terminal, cleared when the agent resumes; replies may not contain shell syntax (; $ ` | < > &) or invisible formatting characters."
14
+ ]
15
+ },
16
+ {
17
+ "version": "0.1.0-alpha.895",
18
+ "changes": [
19
+ "The vault unlocks once per machine. Each agent's folder under ~/.ouro-cli/bitwarden/ now keeps one disposable bw profile per installed bw version (bw-<version>/), so machines with several bw installs never migrate or share one profile. When a local step fails on an authenticated profile (a null KdfConfig or missing master-password unlock data after a newer bw half-migrated it, or a missing session), Ouro moves the profile aside as data.json.discarded and logs in fresh once with the saved unlock secret, without asking the human. Server steps (login, sync), network errors, rate limits (429), gateway errors (502/504), connection resets, DNS and unreachable-network failures, lock contention and rejected secrets never discard a profile, and those network failures now count as transient. Ouro no longer deletes the saved Keychain/DPAPI/Secret Service/plaintext unlock entry when the vault rejects it: it keeps the entry and writes a private rejection record (mode 0600) in the agent's bw folder that every process honors, so no process retries a rejected secret against the server; `ouro vault unlock` (even with the same secret) or any successful login clears it. A store's terminal login failure is retried after 15 minutes instead of being held until restart. The locked-vault message also names a macOS password reset, which replaces the login keychain, as a cause. The Unraid template and the Sanctuary bundle runtime move to this version."
20
+ ]
21
+ },
4
22
  {
5
23
  "version": "0.1.0-alpha.894",
6
24
  "changes": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "runtimeVersion": "0.1.0-alpha.894",
2
+ "runtimeVersion": "0.1.0-alpha.897",
3
3
  "bundleSchemaVersion": 3,
4
4
  "lastUpdated": "2026-09-03T00:00:00.000Z"
5
5
  }
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0"?>
2
2
  <Container version="2">
3
3
  <Name>ouro-butler</Name>
4
- <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.894</Repository>
4
+ <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.897</Repository>
5
5
  <Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
6
6
  <Network>host</Network>
7
7
  <Shell>sh</Shell>
@@ -58,7 +58,7 @@ function defaultLoggingForProcess(processName) {
58
58
  sinks: ["terminal", "ndjson"],
59
59
  };
60
60
  }
61
- if (processName === "bluebubbles" || processName === "mail" || processName === "voice" || processName === "a2a" || processName === "cmux") {
61
+ if (processName === "bluebubbles" || processName === "mail" || processName === "voice" || processName === "a2a" || processName === "shepherd") {
62
62
  return {
63
63
  level: "warn",
64
64
  sinks: ["terminal", "ndjson"],
@@ -43,7 +43,7 @@ const runtime_credentials_1 = require("../runtime-credentials");
43
43
  const provider_credentials_1 = require("../provider-credentials");
44
44
  const sense_truth_1 = require("../sense-truth");
45
45
  const machine_identity_1 = require("../machine-identity");
46
- const cmux_config_1 = require("../cmux-config");
46
+ const shepherd_config_1 = require("../shepherd-config");
47
47
  const process_manager_1 = require("./process-manager");
48
48
  const config_1 = require("../../a2a/config");
49
49
  const DEFAULT_TEAMS_PORT = 3978;
@@ -63,7 +63,7 @@ function defaultSenses() {
63
63
  a2a: { ...identity_1.DEFAULT_AGENT_SENSES.a2a },
64
64
  telegram: { ...identity_1.DEFAULT_AGENT_SENSES.telegram },
65
65
  workbench: { ...identity_1.DEFAULT_AGENT_SENSES.workbench },
66
- cmux: { ...identity_1.DEFAULT_AGENT_SENSES.cmux },
66
+ shepherd: { ...identity_1.DEFAULT_AGENT_SENSES.shepherd },
67
67
  };
68
68
  }
69
69
  function readAgentSenses(agentJsonPath) {
@@ -103,7 +103,7 @@ function readAgentSenses(agentJsonPath) {
103
103
  && !Array.isArray(rawMcpServers)
104
104
  && Object.prototype.hasOwnProperty.call(rawMcpServers, "ouro_workbench");
105
105
  const workbenchHasStaleBundleEntry = workbenchSensePresent || workbenchMcpPresent;
106
- for (const sense of ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "workbench", "cmux"]) {
106
+ for (const sense of ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "workbench", "shepherd"]) {
107
107
  const rawSense = rawSenses[sense];
108
108
  if (!rawSense || typeof rawSense !== "object" || Array.isArray(rawSense)) {
109
109
  continue;
@@ -164,7 +164,7 @@ function runtimeConfigUnavailableDetail(agent, runtimeConfig) {
164
164
  return `vault ${itemName} unavailable (${compactRuntimeConfigError(agent, runtimeConfig.error)})`;
165
165
  }
166
166
  function needsMachineRuntimeConfig(agent, sense) {
167
- return sense === "bluebubbles" || sense === "voice" || sense === "a2a" || sense === "cmux" || (agent === "sanctuary" && sense === "telegram");
167
+ return sense === "bluebubbles" || sense === "voice" || sense === "a2a" || sense === "shepherd" || (agent === "sanctuary" && sense === "telegram");
168
168
  }
169
169
  function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig, machineRuntimeConfig = (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(agent), workbenchHasStaleBundleEntry = false) {
170
170
  const base = {
@@ -176,7 +176,7 @@ function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig, machineRuntim
176
176
  a2a: { configured: false, detail: "not enabled in agent.json" },
177
177
  telegram: { configured: false, detail: "not enabled in agent.json" },
178
178
  workbench: { configured: false, detail: "not enabled in agent.json" },
179
- cmux: { configured: false, detail: "not enabled in agent.json" },
179
+ shepherd: { configured: false, detail: "not enabled in agent.json" },
180
180
  };
181
181
  const payload = runtimeConfig.ok ? runtimeConfig.config : {};
182
182
  const unavailableDetail = runtimeConfigUnavailableDetail(agent, runtimeConfig);
@@ -345,10 +345,10 @@ function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig, machineRuntim
345
345
  detail: publicUrl ? `${publicUrl}${endpointPath}` : `:${port} ${endpointPath}`,
346
346
  };
347
347
  }
348
- if (senses.cmux.enabled) {
349
- base.cmux = !machineRuntimeConfig.ok && machineRuntimeConfig.reason !== "missing"
348
+ if (senses.shepherd.enabled) {
349
+ base.shepherd = !machineRuntimeConfig.ok && machineRuntimeConfig.reason !== "missing"
350
350
  ? { configured: false, detail: runtimeConfigUnavailableDetail(agent, machineRuntimeConfig) }
351
- : (0, cmux_config_1.cmuxConfigFacts)(machinePayload);
351
+ : (0, shepherd_config_1.shepherdConfigFacts)(machinePayload);
352
352
  }
353
353
  if (workbenchHasStaleBundleEntry || senses.workbench.enabled) {
354
354
  base.workbench = {
@@ -377,8 +377,8 @@ function senseRepairHint(agent, sense) {
377
377
  ? "Agent-runnable: complete or recover the root authority migration; do not restore a resident Telegram token."
378
378
  : `Agent-runnable: store Telegram bot/user/chat coordinates with 'ouro connect telegram --agent ${agent}', then restart with 'ouro up'.`;
379
379
  }
380
- if (sense === "cmux")
381
- return (0, cmux_config_1.cmuxRepairHint)(agent);
380
+ if (sense === "shepherd")
381
+ return (0, shepherd_config_1.shepherdRepairHint)(agent);
382
382
  /* v8 ignore next -- Workbench is deliberately not daemon-managed, so getSenseInventory never asks the daemon manager for a repair hint @preserve */
383
383
  if (sense === "workbench") {
384
384
  return `Agent-runnable: install Ouro Workbench.app, then launch the boss through Workbench or run 'ouro acp-serve --agent ${agent} --workbench-mcp'; 'ouro connect workbench --agent ${agent}' only cleans stale bundle entries.`;
@@ -393,7 +393,7 @@ function parseSenseSnapshotName(name) {
393
393
  if (parts.length !== 2)
394
394
  return null;
395
395
  const [agent, sense] = parts;
396
- if (sense !== "teams" && sense !== "bluebubbles" && sense !== "mail" && sense !== "voice" && sense !== "a2a" && sense !== "telegram" && sense !== "cmux")
396
+ if (sense !== "teams" && sense !== "bluebubbles" && sense !== "mail" && sense !== "voice" && sense !== "a2a" && sense !== "telegram" && sense !== "shepherd")
397
397
  return null;
398
398
  return { agent, sense };
399
399
  }
@@ -413,13 +413,13 @@ function managedSenseEntry(sense) {
413
413
  return "senses/a2a-entry.js";
414
414
  if (sense === "telegram")
415
415
  return "senses/telegram-entry.js";
416
- if (sense === "cmux")
417
- return "senses/cmux-entry.js";
416
+ if (sense === "shepherd")
417
+ return "senses/shepherd-entry.js";
418
418
  return "senses/mail-entry.js";
419
419
  }
420
420
  function runtimeCredentialBootstrapFor(agent, sense) {
421
421
  const runtime = (0, runtime_credentials_1.readRuntimeCredentialConfig)(agent);
422
- const usesMachineConfig = sense === "bluebubbles" || sense === "voice" || sense === "a2a" || sense === "telegram" || sense === "cmux";
422
+ const usesMachineConfig = sense === "bluebubbles" || sense === "voice" || sense === "a2a" || sense === "telegram" || sense === "shepherd";
423
423
  const machineId = usesMachineConfig ? currentMachineId() : undefined;
424
424
  const machine = usesMachineConfig ? (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(agent) : null;
425
425
  const providerPool = (0, provider_credentials_1.readProviderCredentialPool)(agent);
@@ -590,7 +590,7 @@ class DaemonSenseManager {
590
590
  return [agent, { senses, workbenchHasStaleBundleEntry, facts }];
591
591
  }));
592
592
  const managedSenseAgents = [...this.contexts.entries()].flatMap(([agent, context]) => {
593
- return ["teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "cmux"]
593
+ return ["teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "shepherd"]
594
594
  .filter((sense) => context.senses[sense].enabled)
595
595
  .map((sense) => ({
596
596
  name: `${agent}:${sense}`,
@@ -742,7 +742,7 @@ class DaemonSenseManager {
742
742
  }
743
743
  async refreshEnabledSenseConfigs() {
744
744
  const refreshes = [...this.contexts.entries()].map(async ([agent, context]) => {
745
- const enabledManagedSenses = ["teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "cmux"]
745
+ const enabledManagedSenses = ["teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "shepherd"]
746
746
  .filter((sense) => context.senses[sense].enabled);
747
747
  /* v8 ignore next -- periodic refresh work only exists when a managed background sense is enabled @preserve */
748
748
  if (enabledManagedSenses.length === 0)
@@ -916,10 +916,10 @@ class DaemonSenseManager {
916
916
  workbench: {
917
917
  configured: context.facts.workbench.configured,
918
918
  },
919
- cmux: {
920
- configured: context.facts.cmux.configured,
921
- optional: context.facts.cmux.optional,
922
- ...(runtime.get(agent)?.cmux ?? {}),
919
+ shepherd: {
920
+ configured: context.facts.shepherd.configured,
921
+ optional: context.facts.shepherd.optional,
922
+ ...(runtime.get(agent)?.shepherd ?? {}),
923
923
  },
924
924
  };
925
925
  const inventory = (0, sense_truth_1.getSenseInventory)({ senses: context.senses }, runtimeInfo);
@@ -145,7 +145,7 @@ exports.DEFAULT_AGENT_SENSES = {
145
145
  a2a: { enabled: false },
146
146
  telegram: { enabled: false },
147
147
  workbench: { enabled: false },
148
- cmux: { enabled: false },
148
+ shepherd: { enabled: false },
149
149
  };
150
150
  function normalizeSenses(value, configFile) {
151
151
  const defaults = {
@@ -157,7 +157,7 @@ function normalizeSenses(value, configFile) {
157
157
  a2a: { ...exports.DEFAULT_AGENT_SENSES.a2a },
158
158
  telegram: { ...exports.DEFAULT_AGENT_SENSES.telegram },
159
159
  workbench: { ...exports.DEFAULT_AGENT_SENSES.workbench },
160
- cmux: { ...exports.DEFAULT_AGENT_SENSES.cmux },
160
+ shepherd: { ...exports.DEFAULT_AGENT_SENSES.shepherd },
161
161
  };
162
162
  if (value === undefined) {
163
163
  return defaults;
@@ -173,7 +173,7 @@ function normalizeSenses(value, configFile) {
173
173
  throw new Error(`agent.json at ${configFile} must include senses as an object when present.`);
174
174
  }
175
175
  const raw = value;
176
- const senseNames = ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "workbench", "cmux"];
176
+ const senseNames = ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "workbench", "shepherd"];
177
177
  for (const senseName of senseNames) {
178
178
  const rawSense = raw[senseName];
179
179
  if (rawSense === undefined) {
@@ -221,7 +221,7 @@ function buildDefaultAgentTemplate(_agentName) {
221
221
  a2a: { ...exports.DEFAULT_AGENT_SENSES.a2a },
222
222
  telegram: { ...exports.DEFAULT_AGENT_SENSES.telegram },
223
223
  workbench: { ...exports.DEFAULT_AGENT_SENSES.workbench },
224
- cmux: { ...exports.DEFAULT_AGENT_SENSES.cmux },
224
+ shepherd: { ...exports.DEFAULT_AGENT_SENSES.shepherd },
225
225
  },
226
226
  phrases: {
227
227
  thinking: [...exports.DEFAULT_AGENT_PHRASES.thinking],
@@ -150,12 +150,12 @@ async function evaluatePolicy(request, context, deps) {
150
150
  reason: "verified daemon external event",
151
151
  };
152
152
  }
153
- if (request.triggerSource === "cmux-feed"
154
- && hasNonEmptyOriginRef(originRefs, "cmux-feed")
155
- && hasOriginRef(originRefs, "sense", "cmux")) {
153
+ if (request.triggerSource === "shepherd"
154
+ && hasNonEmptyOriginRef(originRefs, "shepherd-return")
155
+ && hasOriginRef(originRefs, "sense", "shepherd")) {
156
156
  return {
157
157
  result: "allow",
158
- reason: "cmux sense escalation",
158
+ reason: "Shepherd escalation",
159
159
  };
160
160
  }
161
161
  if (request.triggerSource === "operator-cli"
@@ -12,7 +12,7 @@ const SENSES = [
12
12
  { sense: "a2a", label: "A2A", daemonManaged: true },
13
13
  { sense: "telegram", label: "Telegram", daemonManaged: true },
14
14
  { sense: "workbench", label: "Workbench", daemonManaged: false },
15
- { sense: "cmux", label: "cmux", daemonManaged: true },
15
+ { sense: "shepherd", label: "shepherd", daemonManaged: true },
16
16
  ];
17
17
  function configuredSenses(senses) {
18
18
  const configured = senses ?? {};
@@ -26,7 +26,7 @@ function configuredSenses(senses) {
26
26
  a2a: configured.a2a ?? { ...identity_1.DEFAULT_AGENT_SENSES.a2a },
27
27
  telegram: configured.telegram ?? { ...identity_1.DEFAULT_AGENT_SENSES.telegram },
28
28
  workbench: configured.workbench ?? { ...identity_1.DEFAULT_AGENT_SENSES.workbench },
29
- cmux: configured.cmux ?? { ...identity_1.DEFAULT_AGENT_SENSES.cmux },
29
+ shepherd: configured.shepherd ?? { ...identity_1.DEFAULT_AGENT_SENSES.shepherd },
30
30
  };
31
31
  }
32
32
  function resolveStatus(enabled, daemonManaged, runtimeInfo) {
@@ -33,27 +33,27 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.cmuxRepairHint = cmuxRepairHint;
37
- exports.cmuxConfigFacts = cmuxConfigFacts;
38
- exports.cmuxSenseStatus = cmuxSenseStatus;
36
+ exports.shepherdRepairHint = shepherdRepairHint;
37
+ exports.shepherdConfigFacts = shepherdConfigFacts;
38
+ exports.shepherdSenseStatus = shepherdSenseStatus;
39
39
  exports.defaultCmuxSocketPath = defaultCmuxSocketPath;
40
- exports.resolveCmuxConnection = resolveCmuxConnection;
40
+ exports.resolveShepherdConnection = resolveShepherdConnection;
41
41
  const fs = __importStar(require("node:fs"));
42
42
  const os = __importStar(require("node:os"));
43
43
  const path = __importStar(require("node:path"));
44
44
  const runtime_1 = require("../nerves/runtime");
45
- function cmuxRepairHint(agent) {
45
+ function shepherdRepairHint(agent) {
46
46
  return `human-required: in a cmux terminal run 'ouro vault config set --agent ${agent} --scope machine --key cmux.socketCapability --value "$CMUX_SOCKET_CAPABILITY"' (or set cmux.socketPassword when cmux is in password mode), then 'ouro up'.`;
47
47
  }
48
48
  function text(record, key) {
49
49
  const value = record?.[key];
50
50
  return typeof value === "string" ? value.trim() : "";
51
51
  }
52
- function cmuxRecord(machinePayload) {
53
- const value = machinePayload.cmux;
52
+ function hostRecord(machinePayload, key) {
53
+ const value = machinePayload[key];
54
54
  return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
55
55
  }
56
- function authFrom(cmux) {
56
+ function cmuxAuth(cmux) {
57
57
  const token = text(cmux, "socketCapability");
58
58
  if (token)
59
59
  return { kind: "capability", token };
@@ -64,18 +64,18 @@ function authFrom(cmux) {
64
64
  return { kind: "none" };
65
65
  return null;
66
66
  }
67
- function cmuxConfigFacts(machinePayload) {
68
- const cmux = cmuxRecord(machinePayload);
69
- const auth = authFrom(cmux);
67
+ function shepherdConfigFacts(machinePayload) {
68
+ const cmux = hostRecord(machinePayload, "cmux");
69
+ const auth = cmuxAuth(cmux);
70
70
  if (!auth)
71
- return cmux ? { configured: false, detail: "missing cmux.socketCapability" } : { configured: false, optional: true, detail: "not attached on this machine" };
72
- return { configured: true, detail: `socket auth: ${auth.kind === "none" ? "automation mode" : auth.kind}` };
71
+ return cmux ? { configured: false, detail: "missing cmux.socketCapability" } : { configured: false, optional: true, detail: "no terminal host attached on this machine" };
72
+ return { configured: true, detail: `cmux socket auth: ${auth.kind === "none" ? "automation mode" : auth.kind}` };
73
73
  }
74
- /** The one-word status the prompt and turn context show for the cmux sense, matching the daemon's sense rows. */
75
- function cmuxSenseStatus(enabled, machinePayload) {
74
+ /** The one-word status the prompt and turn context show for Shepherd, matching the daemon's sense rows. */
75
+ function shepherdSenseStatus(enabled, machinePayload) {
76
76
  if (!enabled)
77
77
  return "disabled";
78
- const facts = cmuxConfigFacts(machinePayload);
78
+ const facts = shepherdConfigFacts(machinePayload);
79
79
  if (facts.configured)
80
80
  return "ready";
81
81
  return facts.optional ? "not_attached" : "needs_config";
@@ -87,16 +87,16 @@ function defaultCmuxSocketPath(homeDir = os.homedir(), uid = process.getuid?.()
87
87
  const unscoped = path.join(dir, "cmux.sock");
88
88
  return !exists(scoped) && exists(unscoped) ? unscoped : scoped;
89
89
  }
90
- function resolveCmuxConnection(agent, machinePayload, defaultSocketPath = defaultCmuxSocketPath) {
91
- const cmux = cmuxRecord(machinePayload);
92
- const auth = authFrom(cmux);
90
+ function resolveShepherdConnection(agent, machinePayload, defaultSocketPath = defaultCmuxSocketPath) {
91
+ const cmux = hostRecord(machinePayload, "cmux");
92
+ const auth = cmuxAuth(cmux);
93
93
  (0, runtime_1.emitNervesEvent)({
94
94
  component: "senses",
95
- event: "senses.cmux_connection_resolved",
96
- message: "resolved cmux socket connection settings",
97
- meta: { agent, auth: auth?.kind ?? "missing" },
95
+ event: "senses.shepherd_connection_resolved",
96
+ message: "resolved Shepherd terminal host connection settings",
97
+ meta: { agent, host: auth ? "cmux" : "none", auth: auth?.kind ?? "missing" },
98
98
  });
99
99
  if (!auth)
100
- return { ok: false, error: `cmux socket auth is not configured on this machine; ${cmuxRepairHint(agent)}` };
101
- return { ok: true, connection: { socketPath: text(cmux, "socketPath") || defaultSocketPath(), auth } };
100
+ return { ok: false, error: `no terminal host is attached on this machine; ${shepherdRepairHint(agent)}` };
101
+ return { ok: true, connection: { host: "cmux", socketPath: text(cmux, "socketPath") || defaultSocketPath(), auth } };
102
102
  }
@@ -38,7 +38,6 @@ exports.assertNotReplayIdentity = assertNotReplayIdentity;
38
38
  exports.updateStewardPolicy = updateStewardPolicy;
39
39
  exports.readRoutineActionReceipts = readRoutineActionReceipts;
40
40
  exports.inspectRoutineActionGrant = inspectRoutineActionGrant;
41
- exports.inspectStandingActionGrant = inspectStandingActionGrant;
42
41
  exports.consumeRoutineActionGrant = consumeRoutineActionGrant;
43
42
  exports.withStewardPolicyLease = withStewardPolicyLease;
44
43
  exports.withRoutineActionAttempt = withRoutineActionAttempt;
@@ -525,31 +524,6 @@ function inspectRoutineActionGrant(agentRoot, input) {
525
524
  return { allowed: false, reason: error instanceof Error ? error.message : "routine action policy is unavailable" };
526
525
  }
527
526
  }
528
- function inspectStandingActionGrant(agentRoot, input) {
529
- try {
530
- const { policy, rows } = readPolicyState(agentRoot);
531
- const now = input.now ?? new Date().toISOString();
532
- const grant = policy.routineActionGrants[input.key];
533
- if (!grant)
534
- return { allowed: false, reason: "standing grant is missing" };
535
- if (grant.provenance !== "stated")
536
- return { allowed: false, reason: "standing grant must be owner-stated" };
537
- if (!appliedEntry(rows, ["grant_routine_action"], input.key, grant))
538
- return { allowed: false, reason: "standing grant has no applied owner authorization" };
539
- if (grant.action !== input.action)
540
- return { allowed: false, reason: "action does not match the standing grant" };
541
- if (!grant.targets.includes(input.target) || grant.exclusions.includes(input.target))
542
- return { allowed: false, reason: "target is not covered by the standing grant" };
543
- if (grant.expiresAt && Date.parse(grant.expiresAt) <= Date.parse(now))
544
- return { allowed: false, reason: "standing grant expired" };
545
- if (input.usesInWindow(grant.windowMs) >= grant.maxCount)
546
- return { allowed: false, reason: "standing grant count cap reached" };
547
- return { allowed: true, grantVersion: grant.version, maxCount: grant.maxCount, windowMs: grant.windowMs };
548
- }
549
- catch (error) {
550
- return { allowed: false, reason: error instanceof Error ? error.message : "steward policy is unavailable" };
551
- }
552
- }
553
527
  function consumeRoutineActionGrant(agentRoot, input) {
554
528
  if (!text(input.authorizationReceiptId))
555
529
  throw new Error("routine action requires a current authorization receipt");
@@ -63,7 +63,7 @@ const provider_visibility_1 = require("./provider-visibility");
63
63
  const mail_import_discovery_1 = require("./mail-import-discovery");
64
64
  const flight_recorder_1 = require("../arc/flight-recorder");
65
65
  const context_loss_sentinel_1 = require("./context-loss-sentinel");
66
- const cmux_config_1 = require("./cmux-config");
66
+ const shepherd_config_1 = require("./shepherd-config");
67
67
  // ── Helpers ─────────────────────────────────────────────────────────
68
68
  const DAEMON_SOCKET_PATH = "/tmp/ouroboros-daemon.sock";
69
69
  function isLiveCodingSessionStatus(status) {
@@ -168,7 +168,7 @@ function readSenseStatusLines() {
168
168
  a2a: configuredSenses.a2a ?? { enabled: false },
169
169
  telegram: configuredSenses.telegram ?? { enabled: false },
170
170
  workbench: configuredSenses.workbench ?? { enabled: false },
171
- cmux: configuredSenses.cmux ?? { enabled: false },
171
+ shepherd: configuredSenses.shepherd ?? { enabled: false },
172
172
  };
173
173
  const payload = (0, config_1.loadConfig)();
174
174
  const agentName = (0, identity_1.getAgentName)();
@@ -223,7 +223,7 @@ function readSenseStatusLines() {
223
223
  && hasTextField(runtimePayload, "telegramAuthorizedUserId")
224
224
  && hasTextField(runtimePayload, "telegramAuthorizedChatId"),
225
225
  workbench: false,
226
- cmux: (0, cmux_config_1.cmuxSenseStatus)(true, machinePayload) === "ready",
226
+ shepherd: (0, shepherd_config_1.shepherdSenseStatus)(true, machinePayload) === "ready",
227
227
  };
228
228
  const rows = [
229
229
  { label: "CLI", status: "interactive" },
@@ -252,8 +252,8 @@ function readSenseStatusLines() {
252
252
  status: !senses.telegram.enabled ? "disabled" : configured.telegram ? "ready" : "needs_config",
253
253
  },
254
254
  {
255
- label: "cmux",
256
- status: (0, cmux_config_1.cmuxSenseStatus)(senses.cmux.enabled, machinePayload),
255
+ label: "shepherd",
256
+ status: (0, shepherd_config_1.shepherdSenseStatus)(senses.shepherd.enabled, machinePayload),
257
257
  },
258
258
  {
259
259
  label: "Workbench",
@@ -86,7 +86,7 @@ const daemon_health_1 = require("../heart/daemon/daemon-health");
86
86
  const scrutiny_1 = require("./scrutiny");
87
87
  const pulse_1 = require("../heart/daemon/pulse");
88
88
  const provider_visibility_1 = require("../heart/provider-visibility");
89
- const cmux_config_1 = require("../heart/cmux-config");
89
+ const shepherd_config_1 = require("../heart/shepherd-config");
90
90
  const store_1 = require("../trips/store");
91
91
  const orientation_frame_1 = require("../heart/orientation-frame");
92
92
  const flight_recorder_1 = require("../arc/flight-recorder");
@@ -479,7 +479,7 @@ function localSenseStatusLines() {
479
479
  a2a: configuredSenses.a2a ?? { enabled: false },
480
480
  telegram: configuredSenses.telegram ?? { enabled: false },
481
481
  workbench: configuredSenses.workbench ?? { enabled: false },
482
- cmux: configuredSenses.cmux ?? { enabled: false },
482
+ shepherd: configuredSenses.shepherd ?? { enabled: false },
483
483
  };
484
484
  const payload = (0, config_1.loadConfig)();
485
485
  const runtimeConfig = (0, runtime_credentials_1.readRuntimeCredentialConfig)((0, identity_1.getAgentName)());
@@ -508,7 +508,7 @@ function localSenseStatusLines() {
508
508
  && hasTextField(runtimePayload, "telegramAuthorizedUserId")
509
509
  && hasTextField(runtimePayload, "telegramAuthorizedChatId"),
510
510
  workbench: false,
511
- cmux: (0, cmux_config_1.cmuxSenseStatus)(true, machinePayload) === "ready",
511
+ shepherd: (0, shepherd_config_1.shepherdSenseStatus)(true, machinePayload) === "ready",
512
512
  };
513
513
  const rows = [
514
514
  { label: "CLI", status: "interactive" },
@@ -537,8 +537,8 @@ function localSenseStatusLines() {
537
537
  status: !senses.telegram.enabled ? "disabled" : configured.telegram ? "ready" : "needs_config",
538
538
  },
539
539
  {
540
- label: "cmux",
541
- status: (0, cmux_config_1.cmuxSenseStatus)(senses.cmux.enabled, machinePayload),
540
+ label: "shepherd",
541
+ status: (0, shepherd_config_1.shepherdSenseStatus)(senses.shepherd.enabled, machinePayload),
542
542
  },
543
543
  {
544
544
  label: "Workbench",