@ouro.bot/cli 0.1.0-alpha.423 → 0.1.0-alpha.426

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,36 @@
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.426",
6
+ "changes": [
7
+ "`ouro up` no longer marks `starting daemon` complete when a replacement daemon still is not answering; it now narrates replacement progress in plain language and reports replacement timeout as an incomplete replacement instead of a fake success.",
8
+ "Root `ouro connect --agent <agent>` now prints a short `checking current connections` preflight while it reads portable and machine-local runtime settings before showing the connect bay menu.",
9
+ "Auth/provider/setup docs now codify the human CLI rule that waits longer than about three seconds should show current work, and they describe the new daemon replacement wording and connect-bay preflight.",
10
+ "`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the daemon replacement and connect-bay progress release."
11
+ ]
12
+ },
13
+ {
14
+ "version": "0.1.0-alpha.425",
15
+ "changes": [
16
+ "Human-facing single-agent CLI commands now resolve an omitted `--agent` through one shared path: use the explicit flag when present, otherwise use runtime identity when it can name the current agent, otherwise use the only discovered local agent, otherwise ask which agent to use, and otherwise explain how to hatch or clone one.",
17
+ "`ouro auth`, `ouro auth verify`, `ouro auth switch`, `ouro use`, `ouro provider` commands, `ouro vault` commands, `ouro connect`, `ouro config model`, `ouro config models`, `ouro setup`, `ouro bluebubbles replay`, `ouro thoughts`, `ouro attention`, `ouro inner`, `ouro task`, `ouro reminder create`, `ouro friend` management commands, `ouro habit`, and `ouro session list` now share that missing-agent contract instead of quietly depending on argv or ambient context.",
18
+ "Task/reminder execution now builds agent-scoped task modules directly from the selected bundle, session scanning now accepts an explicit agent name, and local friend/habit flows now read the selected agent bundle instead of falling back to hidden global defaults.",
19
+ "`ouro whoami` keeps its richer runtime identity output but now shares the same no-agent fallback behavior when runtime identity is unavailable, and the runtime seam no longer grabs unrelated ambient repo identity behind the human's back.",
20
+ "CLI help and execution coverage now protect single-agent auto-selection, multi-agent prompting, no-agent guidance, noninteractive ambiguity handling, and the newly covered local task/reminder/friend/habit/session flows.",
21
+ "`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the complete missing-agent resolution release."
22
+ ]
23
+ },
24
+ {
25
+ "version": "0.1.0-alpha.424",
26
+ "changes": [
27
+ "Human-facing single-agent CLI commands now resolve an omitted `--agent` through one shared path: use the explicit flag when present, otherwise use the only installed agent, otherwise ask which agent to use, and otherwise explain how to hatch or clone one.",
28
+ "`ouro auth`, `ouro auth verify`, `ouro auth switch`, `ouro use`, `ouro provider refresh`, `ouro provider check`, `ouro provider status`, `ouro vault` commands, `ouro connect`, `ouro config model`, `ouro config models`, `ouro setup`, and `ouro bluebubbles replay` now accept `[--agent <name>]` instead of failing during parse before Ouro has a chance to help.",
29
+ "`ouro whoami` keeps its richer runtime identity output but now shares the same no-agent fallback behavior when runtime identity is unavailable, and the runtime seam no longer grabs unrelated ambient repo identity behind the human's back.",
30
+ "CLI help text now tells the truth about optional-agent behavior, and focused parser/execution/help coverage protects single-agent auto-selection, multi-agent prompting, no-agent guidance, and noninteractive ambiguity handling.",
31
+ "`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the missing-agent resolution release."
32
+ ]
33
+ },
4
34
  {
5
35
  "version": "0.1.0-alpha.423",
6
36
  "changes": [
@@ -587,8 +587,7 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
587
587
  const { main } = await Promise.resolve().then(() => __importStar(require("../../senses/cli")));
588
588
  await main(agentName);
589
589
  },
590
- scanSessions: async () => {
591
- const agentName = (0, identity_1.getAgentName)();
590
+ scanSessions: async (agentName) => {
592
591
  const agentRoot = (0, identity_1.getAgentRoot)(agentName);
593
592
  return (0, session_activity_1.listSessionActivity)({
594
593
  sessionsDir: path.join(agentRoot, "state", "sessions"),
@@ -158,6 +158,132 @@ async function listCliAgents(deps) {
158
158
  }
159
159
  return [];
160
160
  }
161
+ function runtimeContextAgentName(deps) {
162
+ try {
163
+ return deps.whoamiInfo?.().agentName.trim() || undefined;
164
+ }
165
+ catch {
166
+ return undefined;
167
+ }
168
+ }
169
+ function normalizeCliAgentNames(agentNames) {
170
+ return [...new Set(agentNames.map((agent) => agent.trim()).filter((agent) => agent.length > 0))];
171
+ }
172
+ function resolveSelectedCliAgent(answer, agentNames) {
173
+ const trimmed = answer.trim();
174
+ if (!trimmed)
175
+ return undefined;
176
+ const byName = agentNames.find((agent) => agent.toLowerCase() === trimmed.toLowerCase());
177
+ if (byName)
178
+ return byName;
179
+ const parsedIndex = Number.parseInt(trimmed, 10);
180
+ if (Number.isNaN(parsedIndex))
181
+ return undefined;
182
+ return agentNames[parsedIndex - 1];
183
+ }
184
+ function noAgentsFoundMessage() {
185
+ return "no agents found. Run `ouro` to hatch one or `ouro clone <remote>` to add an existing agent.";
186
+ }
187
+ function multipleAgentsFoundMessage(agentNames) {
188
+ return [
189
+ `multiple agents found: ${agentNames.join(", ")}`,
190
+ "Re-run with --agent <name>.",
191
+ ].join("\n");
192
+ }
193
+ function invalidAgentSelectionMessage(agentNames) {
194
+ return [
195
+ `invalid agent selection. Available agents: ${agentNames.join(", ")}`,
196
+ "Re-run with --agent <name>.",
197
+ ].join("\n");
198
+ }
199
+ function agentResolutionFailureMode(command) {
200
+ switch (command.kind) {
201
+ case "task.board":
202
+ case "task.create":
203
+ case "task.update":
204
+ case "task.show":
205
+ case "task.actionable":
206
+ case "task.deps":
207
+ case "task.sessions":
208
+ case "task.fix":
209
+ case "reminder.create":
210
+ case "friend.list":
211
+ case "friend.show":
212
+ case "friend.create":
213
+ case "friend.update":
214
+ case "habit.list":
215
+ case "habit.create":
216
+ case "thoughts":
217
+ case "attention.list":
218
+ case "attention.show":
219
+ case "attention.history":
220
+ case "inner.status":
221
+ case "session.list":
222
+ return "return-message";
223
+ case "provider.use":
224
+ case "provider.check":
225
+ case "provider.status":
226
+ case "provider.refresh":
227
+ case "vault.create":
228
+ case "vault.replace":
229
+ case "vault.recover":
230
+ case "vault.unlock":
231
+ case "vault.status":
232
+ case "vault.config.set":
233
+ case "vault.config.status":
234
+ case "connect":
235
+ case "auth.run":
236
+ case "auth.verify":
237
+ case "auth.switch":
238
+ case "config.model":
239
+ case "config.models":
240
+ case "setup":
241
+ case "bluebubbles.replay":
242
+ return "throw";
243
+ default:
244
+ return undefined;
245
+ }
246
+ }
247
+ async function resolveMissingAgentName(deps, failureMode) {
248
+ const runtimeAgent = runtimeContextAgentName(deps);
249
+ if (runtimeAgent) {
250
+ return { ok: true, agent: runtimeAgent };
251
+ }
252
+ const discoveredAgents = normalizeCliAgentNames(await listCliAgents(deps));
253
+ if (discoveredAgents.length === 0) {
254
+ return { ok: false, message: noAgentsFoundMessage(), failureMode };
255
+ }
256
+ if (discoveredAgents.length === 1) {
257
+ return { ok: true, agent: discoveredAgents[0] };
258
+ }
259
+ if (!deps.promptInput) {
260
+ return { ok: false, message: multipleAgentsFoundMessage(discoveredAgents), failureMode };
261
+ }
262
+ const answer = await deps.promptInput([
263
+ "Which agent should this use?",
264
+ ...discoveredAgents.map((agent, index) => `${index + 1}. ${agent}`),
265
+ `Choose [1-${discoveredAgents.length}] or type a name: `,
266
+ ].join("\n"));
267
+ const selectedAgent = resolveSelectedCliAgent(answer, discoveredAgents);
268
+ if (!selectedAgent) {
269
+ return { ok: false, message: invalidAgentSelectionMessage(discoveredAgents), failureMode };
270
+ }
271
+ return { ok: true, agent: selectedAgent };
272
+ }
273
+ async function resolveCommandAgent(command, deps) {
274
+ const failureMode = agentResolutionFailureMode(command);
275
+ if (!failureMode) {
276
+ return { ok: true, command: command };
277
+ }
278
+ const explicitAgent = "agent" in command && typeof command.agent === "string" ? command.agent.trim() : "";
279
+ if (explicitAgent) {
280
+ return { ok: true, command: { ...command, agent: explicitAgent } };
281
+ }
282
+ const resolvedAgent = await resolveMissingAgentName(deps, failureMode);
283
+ if (!resolvedAgent.ok)
284
+ return resolvedAgent;
285
+ return { ok: true, command: { ...command, agent: resolvedAgent.agent } };
286
+ }
161
287
  function managedAgentsSignature(agentNames) {
162
288
  const unique = [...new Set(agentNames.map((agent) => agent.trim()).filter((agent) => agent.length > 0))].sort();
163
289
  return unique.length > 0 ? unique.join(",") : "(none)";
@@ -203,12 +329,10 @@ async function runCommandProgressPhase(progress, label, run, detail) {
203
329
  }
204
330
  }
205
331
  function daemonProgressSummary(result) {
206
- if (result.verifyStartupStatus === false)
207
- return "not answering yet";
208
332
  if (result.alreadyRunning)
209
333
  return "already running";
210
- if (result.message.includes("restarted"))
211
- return "restarted and ready";
334
+ if (result.message.includes("replaced"))
335
+ return "replacement ready";
212
336
  return "ready";
213
337
  }
214
338
  async function reportPostRepairProviderHealth(deps, repairedAgents, onProgress) {
@@ -338,6 +462,7 @@ async function ensureDaemonRunning(deps, options = {}) {
338
462
  cleanupStaleSocket: deps.cleanupStaleSocket,
339
463
  startDaemonProcess: deps.startDaemonProcess,
340
464
  checkSocketAlive: deps.checkSocketAlive,
465
+ onProgress: deps.reportDaemonStartupPhase,
341
466
  });
342
467
  if (!runtimeResult.verifyStartupStatus) {
343
468
  return runtimeResult;
@@ -1500,7 +1625,7 @@ function enableAgentSense(agent, sense, deps) {
1500
1625
  };
1501
1626
  fs.writeFileSync(configPath, `${JSON.stringify(raw, null, 2)}\n`, "utf-8");
1502
1627
  }
1503
- async function buildConnectMenu(agent, deps) {
1628
+ async function buildConnectMenu(agent, deps, onProgress) {
1504
1629
  const providerVisibility = (0, provider_visibility_1.buildAgentProviderVisibility)({
1505
1630
  agentName: agent,
1506
1631
  agentRoot: providerCliAgentRoot({ agent }, deps),
@@ -1516,7 +1641,9 @@ async function buildConnectMenu(agent, deps) {
1516
1641
  const providerDetail = providerVisibility.lanes.map((lane) => lane.status === "configured"
1517
1642
  ? `${lane.lane}: ${lane.provider} / ${lane.model}`
1518
1643
  : `${lane.lane}: choose provider/model`).join(" | ");
1644
+ onProgress?.("loading portable settings");
1519
1645
  const runtimeConfig = await (0, runtime_credentials_1.refreshRuntimeCredentialConfig)(agent, { preserveCachedOnFailure: true });
1646
+ onProgress?.("loading this machine's settings");
1520
1647
  const machineRuntime = await (0, runtime_credentials_1.refreshMachineRuntimeCredentialConfig)(agent, currentMachineId(deps), { preserveCachedOnFailure: true });
1521
1648
  const agentConfig = (0, auth_flow_1.readAgentConfigForAgent)(agent, deps.bundlesRoot).config;
1522
1649
  const teamsEnabled = agentConfig.senses?.teams?.enabled === true;
@@ -1825,7 +1952,14 @@ async function executeConnect(command, deps) {
1825
1952
  return executeConnectTeams(command.agent, deps);
1826
1953
  if (command.target === "bluebubbles")
1827
1954
  return executeConnectBlueBubbles(command.agent, deps);
1828
- const menu = await buildConnectMenu(command.agent, deps);
1955
+ const progress = createHumanCommandProgress(deps, "connect");
1956
+ let menu;
1957
+ try {
1958
+ menu = await runCommandProgressPhase(progress, "checking current connections", () => buildConnectMenu(command.agent, deps, (message) => progress.updateDetail(message)), () => "ready");
1959
+ }
1960
+ finally {
1961
+ progress.end();
1962
+ }
1829
1963
  const promptInput = deps.promptInput;
1830
1964
  if (!promptInput) {
1831
1965
  const message = [
@@ -2887,9 +3021,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
2887
3021
  deps.writeStdout(text);
2888
3022
  return text;
2889
3023
  }
2890
- let command;
3024
+ let parsedCommand;
2891
3025
  try {
2892
- command = (0, cli_parse_1.parseOuroCommand)(args);
3026
+ parsedCommand = (0, cli_parse_1.parseOuroCommand)(args);
2893
3027
  }
2894
3028
  catch (parseError) {
2895
3029
  if (deps.startChat && deps.listDiscoveredAgents && args.length === 1) {
@@ -2902,6 +3036,15 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
2902
3036
  }
2903
3037
  throw parseError;
2904
3038
  }
3039
+ const resolvedCommand = await resolveCommandAgent(parsedCommand, deps);
3040
+ if (!resolvedCommand.ok) {
3041
+ if (resolvedCommand.failureMode === "return-message") {
3042
+ deps.writeStdout(resolvedCommand.message);
3043
+ return resolvedCommand.message;
3044
+ }
3045
+ throw new Error(resolvedCommand.message);
3046
+ }
3047
+ let command = resolvedCommand.command;
2905
3048
  if (args.length === 0) {
2906
3049
  const discovered = await Promise.resolve(deps.listDiscoveredAgents ? deps.listDiscoveredAgents() : (0, cli_defaults_1.defaultListDiscoveredAgents)());
2907
3050
  if (discovered.length === 0 && deps.runSerpentGuide) {
@@ -3213,12 +3356,14 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
3213
3356
  progress.announceStep?.(label);
3214
3357
  },
3215
3358
  }, { initialAlive: daemonAliveBeforeStart });
3216
- progress.completePhase("starting daemon", daemonProgressSummary(daemonResult));
3217
3359
  if (daemonResult.verifyStartupStatus === false) {
3360
+ ;
3361
+ progress.announceStep?.("replacement daemon did not answer in time");
3218
3362
  progress.end();
3219
3363
  deps.writeStdout(daemonResult.message);
3220
3364
  return daemonResult.message;
3221
3365
  }
3366
+ progress.completePhase("starting daemon", daemonProgressSummary(daemonResult));
3222
3367
  if (!providerChecksAlreadyRun || daemonResult.alreadyRunning) {
3223
3368
  progress.startPhase("provider checks");
3224
3369
  const providerDegraded = await checkAlreadyRunningAgentProviders(deps, (msg) => progress.updateDetail(msg));
@@ -3781,7 +3926,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
3781
3926
  command.kind === "task.show" || command.kind === "task.actionable" || command.kind === "task.deps" ||
3782
3927
  command.kind === "task.sessions" || command.kind === "task.fix") {
3783
3928
  /* v8 ignore start -- production default: requires full identity setup @preserve */
3784
- const taskMod = deps.taskModule ?? (0, tasks_1.getTaskModule)();
3929
+ const taskMod = deps.taskModule ?? (0, tasks_1.createTaskModule)(path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), `${command.agent}.ouro`, "tasks"));
3785
3930
  /* v8 ignore stop */
3786
3931
  const message = executeTaskCommand(command, taskMod);
3787
3932
  deps.writeStdout(message);
@@ -3790,7 +3935,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
3790
3935
  // ── reminder subcommands (local, no daemon socket needed) ──
3791
3936
  if (command.kind === "reminder.create") {
3792
3937
  /* v8 ignore start -- production default: requires full identity setup @preserve */
3793
- const taskMod = deps.taskModule ?? (0, tasks_1.getTaskModule)();
3938
+ const taskMod = deps.taskModule ?? (0, tasks_1.createTaskModule)(path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), `${command.agent}.ouro`, "tasks"));
3794
3939
  /* v8 ignore stop */
3795
3940
  const message = executeReminderCommand(command, taskMod);
3796
3941
  deps.writeStdout(message);
@@ -3800,8 +3945,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
3800
3945
  if (command.kind === "habit.list" || command.kind === "habit.create") {
3801
3946
  const { parseHabitFile, renderHabitFile } = await Promise.resolve().then(() => __importStar(require("../habits/habit-parser")));
3802
3947
  /* v8 ignore start -- production default: uses real bundle root @preserve */
3803
- const agentName = command.agent ?? (0, identity_1.getAgentName)();
3804
- const bundleRoot = deps.agentBundleRoot ?? path.join((0, identity_1.getAgentBundlesRoot)(), `${agentName}.ouro`);
3948
+ const bundleRoot = deps.agentBundleRoot ?? path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), `${command.agent}.ouro`);
3805
3949
  /* v8 ignore stop */
3806
3950
  const habitsDir = path.join(bundleRoot, "habits");
3807
3951
  if (command.kind === "habit.list") {
@@ -3860,8 +4004,8 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
3860
4004
  // Derive agent-scoped friends dir from --agent flag or link/unlink's agent field
3861
4005
  const agentName = ("agent" in command && command.agent) ? command.agent : undefined;
3862
4006
  const friendsDir = agentName
3863
- ? path.join((0, identity_1.getAgentBundlesRoot)(), `${agentName}.ouro`, "friends")
3864
- : path.join((0, identity_1.getAgentBundlesRoot)(), "friends");
4007
+ ? path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), `${agentName}.ouro`, "friends")
4008
+ : path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), "friends");
3865
4009
  store = new store_file_1.FileFriendStore(friendsDir);
3866
4010
  }
3867
4011
  /* v8 ignore stop */
@@ -4044,29 +4188,41 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
4044
4188
  deps.writeStdout(message);
4045
4189
  return message;
4046
4190
  }
4047
- /* v8 ignore start -- production default: requires full identity setup @preserve */
4048
4191
  try {
4049
- const info = deps.whoamiInfo
4050
- ? deps.whoamiInfo()
4051
- : {
4052
- agentName: (0, identity_1.getAgentName)(),
4053
- homePath: path.join((0, identity_1.getAgentBundlesRoot)(), `${(0, identity_1.getAgentName)()}.ouro`),
4054
- bonesVersion: (0, runtime_metadata_1.getRuntimeMetadata)().version,
4055
- };
4192
+ if (deps.whoamiInfo) {
4193
+ try {
4194
+ const info = deps.whoamiInfo();
4195
+ const message = [
4196
+ `agent: ${info.agentName}`,
4197
+ `home: ${info.homePath}`,
4198
+ `bones: ${info.bonesVersion}`,
4199
+ ].join("\n");
4200
+ deps.writeStdout(message);
4201
+ return message;
4202
+ }
4203
+ catch {
4204
+ // Fall through to shared agent selection when no runtime identity is available.
4205
+ }
4206
+ }
4207
+ const resolvedAgent = await resolveMissingAgentName(deps, "return-message");
4208
+ if (!resolvedAgent.ok) {
4209
+ deps.writeStdout(resolvedAgent.message);
4210
+ return resolvedAgent.message;
4211
+ }
4212
+ const agentRoot = path.join((0, identity_1.getAgentBundlesRoot)(), `${resolvedAgent.agent}.ouro`);
4056
4213
  const message = [
4057
- `agent: ${info.agentName}`,
4058
- `home: ${info.homePath}`,
4059
- `bones: ${info.bonesVersion}`,
4214
+ `agent: ${resolvedAgent.agent}`,
4215
+ `home: ${agentRoot}`,
4216
+ `bones: ${(0, runtime_metadata_1.getRuntimeMetadata)().version}`,
4060
4217
  ].join("\n");
4061
4218
  deps.writeStdout(message);
4062
4219
  return message;
4063
4220
  }
4064
4221
  catch {
4065
- const message = "error: no agent context — use --agent <name> to specify";
4222
+ const message = noAgentsFoundMessage();
4066
4223
  deps.writeStdout(message);
4067
4224
  return message;
4068
4225
  }
4069
- /* v8 ignore stop */
4070
4226
  }
4071
4227
  // ── changelog (local, no daemon socket needed) ──
4072
4228
  if (command.kind === "changelog") {
@@ -4110,10 +4266,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
4110
4266
  // ── thoughts (local, no daemon socket needed) ──
4111
4267
  if (command.kind === "thoughts") {
4112
4268
  try {
4113
- const agentName = command.agent ?? (0, identity_1.getAgentName)();
4114
4269
  /* v8 ignore next -- production fallback: tests always inject bundlesRoot via createTmpBundle @preserve */
4115
4270
  const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
4116
- const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
4271
+ const agentRoot = path.join(bundlesRoot, `${command.agent}.ouro`);
4117
4272
  const sessionFilePath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
4118
4273
  if (command.json) {
4119
4274
  try {
@@ -4156,10 +4311,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
4156
4311
  /* v8 ignore start -- CLI attention handler: requires real obligation store on disk @preserve */
4157
4312
  if (command.kind === "attention.list" || command.kind === "attention.show" || command.kind === "attention.history") {
4158
4313
  try {
4159
- const agentName = command.agent ?? (0, identity_1.getAgentName)();
4160
4314
  const { listActiveReturnObligations, readReturnObligation } = await Promise.resolve().then(() => __importStar(require("../../arc/obligations")));
4161
4315
  if (command.kind === "attention.list") {
4162
- const obligations = listActiveReturnObligations(agentName);
4316
+ const obligations = listActiveReturnObligations(command.agent);
4163
4317
  if (obligations.length === 0) {
4164
4318
  const message = "nothing held — attention queue is empty";
4165
4319
  deps.writeStdout(message);
@@ -4171,7 +4325,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
4171
4325
  return message;
4172
4326
  }
4173
4327
  if (command.kind === "attention.show") {
4174
- const obligation = readReturnObligation(agentName, command.id);
4328
+ const obligation = readReturnObligation(command.agent, command.id);
4175
4329
  if (!obligation) {
4176
4330
  const message = `no obligation found with id ${command.id}`;
4177
4331
  deps.writeStdout(message);
@@ -4183,7 +4337,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
4183
4337
  }
4184
4338
  // attention.history: show returned obligations
4185
4339
  const { getReturnObligationsDir } = await Promise.resolve().then(() => __importStar(require("../../arc/obligations")));
4186
- const obligationsDir = getReturnObligationsDir(agentName);
4340
+ const obligationsDir = getReturnObligationsDir(command.agent);
4187
4341
  let attEntries = [];
4188
4342
  try {
4189
4343
  attEntries = fs.readdirSync(obligationsDir);
@@ -4224,8 +4378,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
4224
4378
  /* v8 ignore start -- inner status handler: requires real agent state on disk @preserve */
4225
4379
  if (command.kind === "inner.status") {
4226
4380
  try {
4227
- const agentName = command.agent ?? (0, identity_1.getAgentName)();
4228
- const agentRoot = (0, identity_1.getAgentRoot)(agentName);
4381
+ const agentRoot = (0, identity_1.getAgentRoot)(command.agent);
4229
4382
  const { buildInnerStatusOutput } = await Promise.resolve().then(() => __importStar(require("./inner-status")));
4230
4383
  const { sessionPath: getSessionPath } = await Promise.resolve().then(() => __importStar(require("../config")));
4231
4384
  const { parseCadenceToMs: parseCadenceMs, DEFAULT_CADENCE_MS } = await Promise.resolve().then(() => __importStar(require("./cadence")));
@@ -4283,9 +4436,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
4283
4436
  }
4284
4437
  catch { /* no habits — heartbeat unknown */ }
4285
4438
  // Attention count
4286
- const activeObligations = listActiveReturnObligations(agentName);
4439
+ const activeObligations = listActiveReturnObligations(command.agent);
4287
4440
  const message = buildInnerStatusOutput({
4288
- agentName,
4441
+ agentName: command.agent,
4289
4442
  runtimeState,
4290
4443
  journalFiles,
4291
4444
  heartbeat,
@@ -4307,7 +4460,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
4307
4460
  /* v8 ignore start -- production default: requires full identity setup @preserve */
4308
4461
  const scanner = deps.scanSessions ?? (async () => []);
4309
4462
  /* v8 ignore stop */
4310
- const sessions = await scanner();
4463
+ const sessions = await scanner(command.agent);
4311
4464
  if (sessions.length === 0) {
4312
4465
  const message = "no active sessions";
4313
4466
  deps.writeStdout(message);
@@ -94,8 +94,8 @@ exports.COMMAND_REGISTRY = {
94
94
  config: {
95
95
  category: "Agents",
96
96
  description: "View or change agent configuration",
97
- usage: "ouro config <subcommand> --agent <name>",
98
- example: "ouro config models --agent ouroboros",
97
+ usage: "ouro config <subcommand> [--agent <name>]",
98
+ example: "ouro config models",
99
99
  subcommands: ["model", "models"],
100
100
  },
101
101
  changelog: {
@@ -159,27 +159,27 @@ exports.COMMAND_REGISTRY = {
159
159
  auth: {
160
160
  category: "Auth",
161
161
  description: "Set up, verify, or switch agent credentials",
162
- usage: "ouro auth [verify|switch] --agent <name> [--provider <provider>]",
163
- example: "ouro auth --agent ouroboros",
162
+ usage: "ouro auth [verify|switch] [--agent <name>] [--provider <provider>]",
163
+ example: "ouro auth",
164
164
  subcommands: ["verify", "switch"],
165
165
  },
166
166
  connect: {
167
167
  category: "Auth",
168
168
  description: "Connect providers, portable integrations, and local senses from one guided bay",
169
- usage: "ouro connect [providers|perplexity|embeddings|teams|bluebubbles] --agent <name>",
170
- example: "ouro connect --agent ouroboros",
169
+ usage: "ouro connect [providers|perplexity|embeddings|teams|bluebubbles] [--agent <name>]",
170
+ example: "ouro connect",
171
171
  subcommands: ["providers", "perplexity", "embeddings", "teams", "bluebubbles"],
172
172
  },
173
173
  use: {
174
174
  category: "Auth",
175
175
  description: "Choose this machine's provider/model lane for an agent",
176
- usage: "ouro use --agent <name> --lane outward|inner --provider <provider> --model <model> [--force]",
176
+ usage: "ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]",
177
177
  example: "ouro use --agent ouroboros --lane outward --provider minimax --model MiniMax-M2.5",
178
178
  },
179
179
  check: {
180
180
  category: "Auth",
181
181
  description: "Run a live check for this machine's selected provider/model lane",
182
- usage: "ouro check --agent <name> --lane outward|inner",
182
+ usage: "ouro check [--agent <name>] --lane outward|inner",
183
183
  example: "ouro check --agent ouroboros --lane outward",
184
184
  },
185
185
  repair: {
@@ -191,15 +191,15 @@ exports.COMMAND_REGISTRY = {
191
191
  provider: {
192
192
  category: "Auth",
193
193
  description: "Refresh daemon provider credentials from an agent vault",
194
- usage: "ouro provider refresh --agent <name>",
194
+ usage: "ouro provider refresh [--agent <name>]",
195
195
  example: "ouro provider refresh --agent ouroboros",
196
196
  subcommands: ["refresh"],
197
197
  },
198
198
  vault: {
199
199
  category: "Auth",
200
200
  description: "Create, replace, recover, unlock, inspect, and populate the agent credential vault",
201
- usage: "ouro vault <create|replace|recover|unlock|status|config> --agent <name>",
202
- example: "ouro vault status --agent ouroboros",
201
+ usage: "ouro vault <create|replace|recover|unlock|status|config> [--agent <name>]",
202
+ example: "ouro vault status",
203
203
  subcommands: ["create", "replace", "recover", "unlock", "status", "config set", "config status"],
204
204
  },
205
205
  thoughts: {
@@ -244,8 +244,8 @@ exports.COMMAND_REGISTRY = {
244
244
  setup: {
245
245
  category: "System",
246
246
  description: "Register MCP server and hooks for a dev tool",
247
- usage: "ouro setup --tool <claude-code|codex> --agent <name>",
248
- example: "ouro setup --tool claude-code --agent ouroboros",
247
+ usage: "ouro setup --tool <claude-code|codex> [--agent <name>]",
248
+ example: "ouro setup --tool claude-code",
249
249
  },
250
250
  hook: {
251
251
  category: "System",
@@ -256,86 +256,86 @@ exports.COMMAND_REGISTRY = {
256
256
  bluebubbles: {
257
257
  category: "System",
258
258
  description: "BlueBubbles integration commands",
259
- usage: "ouro bluebubbles replay --agent <name> --message-guid <guid> [--event-type <type>] [--json]",
260
- example: "ouro bluebubbles replay --agent ouroboros --message-guid abc123",
259
+ usage: "ouro bluebubbles replay [--agent <name>] --message-guid <guid> [--event-type <type>] [--json]",
260
+ example: "ouro bluebubbles replay --message-guid abc123",
261
261
  subcommands: ["replay"],
262
262
  },
263
263
  };
264
264
  const SUBCOMMAND_HELP = {
265
265
  "auth verify": {
266
266
  description: "Verify agent provider credentials without changing provider/model lanes",
267
- usage: "ouro auth verify --agent <name> [--provider <provider>]",
268
- example: "ouro auth verify --agent ouroboros --provider openai-codex",
267
+ usage: "ouro auth verify [--agent <name>] [--provider <provider>]",
268
+ example: "ouro auth verify --provider openai-codex",
269
269
  },
270
270
  "auth switch": {
271
271
  description: "Switch local provider/model lanes after credentials are available",
272
- usage: "ouro auth switch --agent <name> --provider <provider> [--facing human|agent]",
273
- example: "ouro auth switch --agent ouroboros --provider minimax",
272
+ usage: "ouro auth switch [--agent <name>] --provider <provider> [--facing human|agent]",
273
+ example: "ouro auth switch --provider minimax",
274
274
  },
275
275
  "connect perplexity": {
276
276
  description: "Connect Perplexity search for this agent",
277
- usage: "ouro connect perplexity --agent <name>",
278
- example: "ouro connect perplexity --agent ouroboros",
277
+ usage: "ouro connect perplexity [--agent <name>]",
278
+ example: "ouro connect perplexity",
279
279
  },
280
280
  "connect providers": {
281
281
  description: "Open provider auth from the connect bay without remembering the auth command",
282
- usage: "ouro connect providers --agent <name>",
283
- example: "ouro connect providers --agent ouroboros",
282
+ usage: "ouro connect providers [--agent <name>]",
283
+ example: "ouro connect providers",
284
284
  },
285
285
  "connect embeddings": {
286
286
  description: "Connect memory embeddings for this agent",
287
- usage: "ouro connect embeddings --agent <name>",
288
- example: "ouro connect embeddings --agent ouroboros",
287
+ usage: "ouro connect embeddings [--agent <name>]",
288
+ example: "ouro connect embeddings",
289
289
  },
290
290
  "connect teams": {
291
291
  description: "Connect Microsoft Teams credentials and enable the Teams sense",
292
- usage: "ouro connect teams --agent <name>",
293
- example: "ouro connect teams --agent ouroboros",
292
+ usage: "ouro connect teams [--agent <name>]",
293
+ example: "ouro connect teams",
294
294
  },
295
295
  "connect bluebubbles": {
296
296
  description: "Attach BlueBubbles iMessage to this machine only",
297
- usage: "ouro connect bluebubbles --agent <name>",
298
- example: "ouro connect bluebubbles --agent ouroboros",
297
+ usage: "ouro connect bluebubbles [--agent <name>]",
298
+ example: "ouro connect bluebubbles",
299
299
  },
300
300
  "provider refresh": {
301
301
  description: "Reload this agent's provider credentials from its vault into daemon memory",
302
- usage: "ouro provider refresh --agent <name>",
303
- example: "ouro provider refresh --agent ouroboros",
302
+ usage: "ouro provider refresh [--agent <name>]",
303
+ example: "ouro provider refresh",
304
304
  },
305
305
  "vault create": {
306
306
  description: "Create an agent credential vault and store local unlock material",
307
- usage: "ouro vault create --agent <name> --email <email> [--server <url>] [--store <store>]",
308
- example: "ouro vault create --agent ouroboros --email ouroboros@ouro.bot",
307
+ usage: "ouro vault create [--agent <name>] --email <email> [--server <url>] [--store <store>]",
308
+ example: "ouro vault create --email ouroboros@ouro.bot",
309
309
  },
310
310
  "vault replace": {
311
311
  description: "Create an empty agent vault at the stable agent email when no unlock secret or JSON export exists",
312
- usage: "ouro vault replace --agent <name> [--email <email>] [--server <url>] [--store <store>]",
313
- example: "ouro vault replace --agent ouroboros",
312
+ usage: "ouro vault replace [--agent <name>] [--email <email>] [--server <url>] [--store <store>]",
313
+ example: "ouro vault replace",
314
314
  },
315
315
  "vault recover": {
316
316
  description: "Create an agent vault at the stable agent email and import local JSON credential exports",
317
- usage: "ouro vault recover --agent <name> --from <json> [--from <json> ...] [--email <email>] [--server <url>] [--store <store>]",
318
- example: "ouro vault recover --agent ouroboros --from ./credentials.json",
317
+ usage: "ouro vault recover [--agent <name>] --from <json> [--from <json> ...] [--email <email>] [--server <url>] [--store <store>]",
318
+ example: "ouro vault recover --from ./credentials.json",
319
319
  },
320
320
  "vault unlock": {
321
321
  description: "Unlock an existing agent credential vault on this machine",
322
- usage: "ouro vault unlock --agent <name> [--store <store>]",
323
- example: "ouro vault unlock --agent ouroboros",
322
+ usage: "ouro vault unlock [--agent <name>] [--store <store>]",
323
+ example: "ouro vault unlock",
324
324
  },
325
325
  "vault status": {
326
326
  description: "Show whether this machine can unlock an agent credential vault",
327
- usage: "ouro vault status --agent <name> [--store <store>]",
328
- example: "ouro vault status --agent ouroboros",
327
+ usage: "ouro vault status [--agent <name>] [--store <store>]",
328
+ example: "ouro vault status",
329
329
  },
330
330
  "vault config set": {
331
331
  description: "Write runtime configuration into the agent credential vault without printing values",
332
- usage: "ouro vault config set --agent <name> --key <path> [--value <value>] [--scope agent|machine]",
333
- example: "ouro vault config set --agent ouroboros --key teams.clientSecret",
332
+ usage: "ouro vault config set [--agent <name>] --key <path> [--value <value>] [--scope agent|machine]",
333
+ example: "ouro vault config set --key teams.clientSecret",
334
334
  },
335
335
  "vault config status": {
336
336
  description: "List runtime configuration keys stored in the agent credential vault",
337
- usage: "ouro vault config status --agent <name> [--scope agent|machine|all]",
338
- example: "ouro vault config status --agent ouroboros --scope all",
337
+ usage: "ouro vault config status [--agent <name>] [--scope agent|machine|all]",
338
+ example: "ouro vault config status --scope all",
339
339
  },
340
340
  };
341
341
  // ── Levenshtein distance ──
@@ -74,25 +74,25 @@ function usage() {
74
74
  " ouro dev [--repo-path <path>] [--clone [--clone-path <path>]]",
75
75
  " ouro stop|down|status|logs|hatch",
76
76
  " ouro status --agent <name>",
77
- " ouro use --agent <name> --lane outward|inner --provider <provider> --model <model> [--force]",
78
- " ouro check --agent <name> --lane outward|inner",
77
+ " ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]",
78
+ " ouro check [--agent <name>] --lane outward|inner",
79
79
  " ouro repair [--agent <name>]",
80
- " ouro provider refresh --agent <name>",
80
+ " ouro provider refresh [--agent <name>]",
81
81
  " ouro outlook [--json]",
82
82
  " ouro -v|--version",
83
- " ouro config model --agent <name> <model-name>",
84
- " ouro config models --agent <name>",
85
- " ouro auth --agent <name> [--provider <provider>]",
86
- " ouro connect [providers|perplexity|embeddings|teams|bluebubbles] --agent <name>",
87
- " ouro auth verify --agent <name> [--provider <provider>]",
88
- " ouro auth switch --agent <name> --provider <provider>",
89
- " ouro vault create --agent <name> --email <email> [--server <url>] [--store <store>]",
90
- " ouro vault replace --agent <name> [--email <email>] [--server <url>] [--store <store>]",
91
- " ouro vault recover --agent <name> --from <json> [--from <json>] [--email <email>] [--server <url>] [--store <store>]",
92
- " ouro vault unlock --agent <name> [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
93
- " ouro vault status --agent <name> [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
94
- " ouro vault config set --agent <name> --key <path> [--value <value>] [--scope agent|machine]",
95
- " ouro vault config status --agent <name> [--scope agent|machine|all]",
83
+ " ouro config model [--agent <name>] <model-name>",
84
+ " ouro config models [--agent <name>]",
85
+ " ouro auth [--agent <name>] [--provider <provider>]",
86
+ " ouro connect [providers|perplexity|embeddings|teams|bluebubbles] [--agent <name>]",
87
+ " ouro auth verify [--agent <name>] [--provider <provider>]",
88
+ " ouro auth switch [--agent <name>] --provider <provider>",
89
+ " ouro vault create [--agent <name>] --email <email> [--server <url>] [--store <store>]",
90
+ " ouro vault replace [--agent <name>] [--email <email>] [--server <url>] [--store <store>]",
91
+ " ouro vault recover [--agent <name>] --from <json> [--from <json>] [--email <email>] [--server <url>] [--store <store>]",
92
+ " ouro vault unlock [--agent <name>] [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
93
+ " ouro vault status [--agent <name>] [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
94
+ " ouro vault config set [--agent <name>] --key <path> [--value <value>] [--scope agent|machine]",
95
+ " ouro vault config status [--agent <name>] [--scope agent|machine|all]",
96
96
  " ouro chat <agent>",
97
97
  " ouro msg --to <agent> [--session <id>] [--task <ref>] <message>",
98
98
  " ouro poke <agent> --task <task-id>",
@@ -100,7 +100,7 @@ function usage() {
100
100
  " ouro habit list [--agent <name>]",
101
101
  " ouro habit create [--agent <name>] <name> [--cadence <interval>]",
102
102
  " ouro link <agent> --friend <id> --provider <provider> --external-id <external-id>",
103
- " ouro bluebubbles replay --agent <name> --message-guid <guid> [--event-type new-message|updated-message] [--json]",
103
+ " ouro bluebubbles replay [--agent <name>] --message-guid <guid> [--event-type new-message|updated-message] [--json]",
104
104
  " ouro task board [<status>] [--agent <name>]",
105
105
  " ouro task create <title> [--type <type>] [--agent <name>]",
106
106
  " ouro task update <id> <status> [--agent <name>]",
@@ -415,15 +415,21 @@ function parseAuthCommand(args) {
415
415
  }
416
416
  }
417
417
  /* v8 ignore stop */
418
- /* v8 ignore next -- defensive: agent always provided in tests @preserve */
419
- if (!agent)
420
- throw new Error(`Usage\n${usage()}`);
421
418
  if (subcommand === "switch") {
422
419
  if (!provider)
423
420
  throw new Error(`auth switch requires --provider.\n${usage()}`);
424
- return facing ? { kind: "auth.switch", agent, provider, facing } : { kind: "auth.switch", agent, provider };
421
+ return {
422
+ kind: "auth.switch",
423
+ ...(agent ? { agent } : {}),
424
+ provider,
425
+ ...(facing ? { facing } : {}),
426
+ };
425
427
  }
426
- return provider ? { kind: "auth.verify", agent, provider } : { kind: "auth.verify", agent };
428
+ return {
429
+ kind: "auth.verify",
430
+ ...(agent ? { agent } : {}),
431
+ ...(provider ? { provider } : {}),
432
+ };
427
433
  }
428
434
  const { agent, rest } = extractAgentFlag(args);
429
435
  let provider;
@@ -437,15 +443,11 @@ function parseAuthCommand(args) {
437
443
  continue;
438
444
  }
439
445
  }
440
- if (!agent) {
441
- throw new Error([
442
- "Usage:",
443
- " ouro auth --agent <name> [--provider <provider>] Set up credentials",
444
- " ouro auth verify --agent <name> [--provider <p>] Verify credentials work",
445
- " ouro auth switch --agent <name> --provider <p> Switch active provider",
446
- ].join("\n"));
447
- }
448
- return provider ? { kind: "auth.run", agent, provider } : { kind: "auth.run", agent };
446
+ return {
447
+ kind: "auth.run",
448
+ ...(agent ? { agent } : {}),
449
+ ...(provider ? { provider } : {}),
450
+ };
449
451
  }
450
452
  function isVaultUnlockStoreKind(value) {
451
453
  return value === "auto" || value === "macos-keychain" || value === "windows-dpapi" || value === "linux-secret-service" || value === "plaintext-file";
@@ -487,7 +489,7 @@ function parseVaultCommand(args) {
487
489
  }
488
490
  const value = rest[i + 1];
489
491
  if (!value)
490
- throw new Error("Usage: ouro vault recover --agent <name> --from <json> [--from <json> ...]");
492
+ throw new Error("Usage: ouro vault recover [--agent <name>] --from <json> [--from <json> ...]");
491
493
  sources.push(value);
492
494
  i += 1;
493
495
  continue;
@@ -496,15 +498,15 @@ function parseVaultCommand(args) {
496
498
  generateUnlockSecret = true;
497
499
  continue;
498
500
  }
499
- throw new Error("Usage: ouro vault create|replace|recover|unlock|status --agent <name>");
501
+ throw new Error("Usage: ouro vault create|replace|recover|unlock|status [--agent <name>]");
500
502
  }
501
- if (!agent || (sub !== "create" && sub !== "replace" && sub !== "recover" && sub !== "unlock" && sub !== "status")) {
502
- throw new Error("Usage: ouro vault create|replace|recover|unlock|status --agent <name>");
503
+ if (sub !== "create" && sub !== "replace" && sub !== "recover" && sub !== "unlock" && sub !== "status") {
504
+ throw new Error("Usage: ouro vault create|replace|recover|unlock|status [--agent <name>]");
503
505
  }
504
506
  if (sub === "create") {
505
507
  return {
506
508
  kind: "vault.create",
507
- agent,
509
+ ...(agent ? { agent } : {}),
508
510
  ...(email ? { email } : {}),
509
511
  ...(serverUrl ? { serverUrl } : {}),
510
512
  ...(store ? { store } : {}),
@@ -514,7 +516,7 @@ function parseVaultCommand(args) {
514
516
  if (sub === "replace") {
515
517
  return {
516
518
  kind: "vault.replace",
517
- agent,
519
+ ...(agent ? { agent } : {}),
518
520
  ...(email ? { email } : {}),
519
521
  ...(serverUrl ? { serverUrl } : {}),
520
522
  ...(store ? { store } : {}),
@@ -523,11 +525,11 @@ function parseVaultCommand(args) {
523
525
  }
524
526
  if (sub === "recover") {
525
527
  if (sources.length === 0) {
526
- throw new Error("Usage: ouro vault recover --agent <name> --from <json> [--from <json> ...]");
528
+ throw new Error("Usage: ouro vault recover [--agent <name>] --from <json> [--from <json> ...]");
527
529
  }
528
530
  return {
529
531
  kind: "vault.recover",
530
- agent,
532
+ ...(agent ? { agent } : {}),
531
533
  sources,
532
534
  ...(email ? { email } : {}),
533
535
  ...(serverUrl ? { serverUrl } : {}),
@@ -536,9 +538,9 @@ function parseVaultCommand(args) {
536
538
  };
537
539
  }
538
540
  if (sub === "unlock") {
539
- return { kind: "vault.unlock", agent, ...(store ? { store } : {}) };
541
+ return { kind: "vault.unlock", ...(agent ? { agent } : {}), ...(store ? { store } : {}) };
540
542
  }
541
- return { kind: "vault.status", agent, ...(store ? { store } : {}) };
543
+ return { kind: "vault.status", ...(agent ? { agent } : {}), ...(store ? { store } : {}) };
542
544
  }
543
545
  function parseVaultConfigCommand(args) {
544
546
  const sub = args[0];
@@ -567,23 +569,23 @@ function parseVaultConfigCommand(args) {
567
569
  i += 1;
568
570
  continue;
569
571
  }
570
- throw new Error("Usage: ouro vault config set --agent <name> --key <path> [--value <value>] OR ouro vault config status --agent <name>");
572
+ throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>] OR ouro vault config status [--agent <name>]");
571
573
  }
572
- if (!agent || (sub !== "set" && sub !== "status")) {
573
- throw new Error("Usage: ouro vault config set --agent <name> --key <path> [--value <value>] OR ouro vault config status --agent <name>");
574
+ if (sub !== "set" && sub !== "status") {
575
+ throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>] OR ouro vault config status [--agent <name>]");
574
576
  }
575
577
  if (sub === "status") {
576
578
  if (key || value) {
577
- throw new Error("Usage: ouro vault config status --agent <name>");
579
+ throw new Error("Usage: ouro vault config status [--agent <name>]");
578
580
  }
579
- return { kind: "vault.config.status", agent, ...(scope ? { scope } : {}) };
581
+ return { kind: "vault.config.status", ...(agent ? { agent } : {}), ...(scope ? { scope } : {}) };
580
582
  }
581
583
  if (scope === "all")
582
584
  throw new Error("vault config --scope all is only valid for status");
583
585
  if (!key) {
584
- throw new Error("Usage: ouro vault config set --agent <name> --key <path> [--value <value>]");
586
+ throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>]");
585
587
  }
586
- return { kind: "vault.config.set", agent, key, ...(value !== undefined ? { value } : {}), ...(scope ? { scope } : {}) };
588
+ return { kind: "vault.config.set", ...(agent ? { agent } : {}), key, ...(value !== undefined ? { value } : {}), ...(scope ? { scope } : {}) };
587
589
  }
588
590
  function normalizeConnectTarget(value) {
589
591
  if (!value)
@@ -598,16 +600,14 @@ function normalizeConnectTarget(value) {
598
600
  return "teams";
599
601
  if (value === "bluebubbles" || value === "imessage" || value === "messages")
600
602
  return "bluebubbles";
601
- throw new Error("Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles] --agent <name>");
603
+ throw new Error("Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles] [--agent <name>]");
602
604
  }
603
605
  function parseConnectCommand(args) {
604
606
  const { agent, rest } = extractAgentFlag(args);
605
- if (!agent)
606
- throw new Error("Usage: ouro connect --agent <name> [providers|perplexity|embeddings|teams|bluebubbles]");
607
607
  if (rest.length > 1)
608
- throw new Error("Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles] --agent <name>");
608
+ throw new Error("Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles] [--agent <name>]");
609
609
  const target = normalizeConnectTarget(rest[0]);
610
- return { kind: "connect", agent, ...(target ? { target } : {}) };
610
+ return { kind: "connect", ...(agent ? { agent } : {}), ...(target ? { target } : {}) };
611
611
  }
612
612
  function parseProviderUseCommand(args) {
613
613
  const { agent, rest: afterAgent } = extractAgentFlag(args);
@@ -621,7 +621,7 @@ function parseProviderUseCommand(args) {
621
621
  if (token === "--provider") {
622
622
  const value = rest[i + 1];
623
623
  if (!isAgentProvider(value))
624
- throw new Error(`Usage: ouro use --agent <name> --lane outward|inner --provider <provider> --model <model>`);
624
+ throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model>");
625
625
  provider = value;
626
626
  i += 1;
627
627
  continue;
@@ -635,15 +635,15 @@ function parseProviderUseCommand(args) {
635
635
  force = true;
636
636
  continue;
637
637
  }
638
- throw new Error("Usage: ouro use --agent <name> --lane outward|inner --provider <provider> --model <model> [--force]");
638
+ throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]");
639
639
  }
640
640
  const resolvedLane = lane ?? (facing ? facingToProviderLane(facing) : undefined);
641
- if (!agent || !resolvedLane || !provider || !model) {
642
- throw new Error("Usage: ouro use --agent <name> --lane outward|inner --provider <provider> --model <model> [--force]");
641
+ if (!resolvedLane || !provider || !model) {
642
+ throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]");
643
643
  }
644
644
  return {
645
645
  kind: "provider.use",
646
- agent,
646
+ ...(agent ? { agent } : {}),
647
647
  lane: resolvedLane,
648
648
  provider,
649
649
  model,
@@ -656,12 +656,12 @@ function parseProviderCheckCommand(args) {
656
656
  const { facing, rest: afterFacing } = extractFacingFlag(afterAgent);
657
657
  const { lane, rest } = extractLaneFlag(afterFacing);
658
658
  const resolvedLane = lane ?? (facing ? facingToProviderLane(facing) : undefined);
659
- if (!agent || !resolvedLane || rest.length > 0) {
660
- throw new Error("Usage: ouro check --agent <name> --lane outward|inner");
659
+ if (!resolvedLane || rest.length > 0) {
660
+ throw new Error("Usage: ouro check [--agent <name>] --lane outward|inner");
661
661
  }
662
662
  return {
663
663
  kind: "provider.check",
664
- agent,
664
+ ...(agent ? { agent } : {}),
665
665
  lane: resolvedLane,
666
666
  ...(facing ? { legacyFacing: facing } : {}),
667
667
  };
@@ -669,10 +669,10 @@ function parseProviderCheckCommand(args) {
669
669
  function parseProviderCommand(args) {
670
670
  const sub = args[0];
671
671
  const { agent, rest } = extractAgentFlag(args.slice(1));
672
- if (sub === "refresh" && agent && rest.length === 0) {
673
- return { kind: "provider.refresh", agent };
672
+ if (sub === "refresh" && rest.length === 0) {
673
+ return { kind: "provider.refresh", ...(agent ? { agent } : {}) };
674
674
  }
675
- throw new Error("Usage: ouro provider refresh --agent <name>");
675
+ throw new Error("Usage: ouro provider refresh [--agent <name>]");
676
676
  }
677
677
  function parseReminderCommand(args) {
678
678
  const { agent, rest: cleaned } = extractAgentFlag(args);
@@ -836,17 +836,18 @@ function parseConfigCommand(args) {
836
836
  if (!sub)
837
837
  throw new Error(`Usage\n${usage()}`);
838
838
  if (sub === "model") {
839
- if (!agent)
840
- throw new Error("--agent is required for config model");
841
839
  const modelName = rest[0];
842
840
  if (!modelName)
843
- throw new Error(`Usage: ouro config model --agent <name> <model-name>`);
844
- return facing ? { kind: "config.model", agent, modelName, facing } : { kind: "config.model", agent, modelName };
841
+ throw new Error("Usage: ouro config model [--agent <name>] <model-name>");
842
+ return {
843
+ kind: "config.model",
844
+ ...(agent ? { agent } : {}),
845
+ modelName,
846
+ ...(facing ? { facing } : {}),
847
+ };
845
848
  }
846
849
  if (sub === "models") {
847
- if (!agent)
848
- throw new Error("--agent is required for config models");
849
- return { kind: "config.models", agent };
850
+ return { kind: "config.models", ...(agent ? { agent } : {}) };
850
851
  }
851
852
  throw new Error(`Usage\n${usage()}`);
852
853
  }
@@ -937,13 +938,13 @@ function parseSetupCommand(args) {
937
938
  continue;
938
939
  }
939
940
  }
941
+ if (args.includes("--agent") && !agent)
942
+ throw new Error("setup requires --agent <name>");
940
943
  if (!tool)
941
944
  throw new Error("setup requires --tool (claude-code | codex)");
942
945
  if (tool !== "claude-code" && tool !== "codex")
943
946
  throw new Error(`Unknown tool: ${tool}. Supported: claude-code, codex`);
944
- if (!agent)
945
- throw new Error("setup requires --agent <name>");
946
- return { kind: "setup", tool, agent };
947
+ return { kind: "setup", tool, ...(agent ? { agent } : {}) };
947
948
  }
948
949
  function parseBlueBubblesCommand(args) {
949
950
  const subcommand = args[0];
@@ -976,13 +977,11 @@ function parseBlueBubblesCommand(args) {
976
977
  continue;
977
978
  }
978
979
  }
979
- if (!agent)
980
- throw new Error("bluebubbles replay requires --agent <name>");
981
980
  if (!messageGuid)
982
981
  throw new Error("bluebubbles replay requires --message-guid <guid>");
983
982
  return {
984
983
  kind: "bluebubbles.replay",
985
- agent,
984
+ ...(agent ? { agent } : {}),
986
985
  messageGuid,
987
986
  eventType,
988
987
  ...(json ? { json: true } : {}),
@@ -9,6 +9,7 @@ async function verifyDaemonStarted(deps) {
9
9
  const maxWaitMs = 10_000;
10
10
  const pollIntervalMs = 500;
11
11
  const deadline = Date.now() + maxWaitMs;
12
+ deps.onProgress?.("waiting for the replacement daemon to answer");
12
13
  while (Date.now() < deadline) {
13
14
  await new Promise((r) => setTimeout(r, pollIntervalMs));
14
15
  if (await deps.checkSocketAlive(deps.socketPath))
@@ -102,7 +103,9 @@ async function ensureCurrentDaemonRuntime(deps) {
102
103
  if (driftReasons.length > 0) {
103
104
  const includesVersionDrift = driftReasons.some((entry) => entry.key === "version");
104
105
  const publicDriftSummary = formatRuntimeDriftPublicSummary(driftReasons);
106
+ deps.onProgress?.("preparing a replacement for the running background service");
105
107
  try {
108
+ deps.onProgress?.("stopping the running background service");
106
109
  await deps.stopDaemon();
107
110
  }
108
111
  catch (error) {
@@ -110,8 +113,8 @@ async function ensureCurrentDaemonRuntime(deps) {
110
113
  result = {
111
114
  alreadyRunning: true,
112
115
  message: includesVersionDrift
113
- ? `daemon already running (${deps.socketPath}; could not replace stale daemon ${runningVersion} -> ${deps.localVersion}: ${reason})`
114
- : `daemon already running (${deps.socketPath}; could not replace runtime drift ${publicDriftSummary}: ${reason})`,
116
+ ? `daemon already running (${deps.socketPath}; could not replace the running background service ${runningVersion} -> ${deps.localVersion}: ${reason})`
117
+ : `daemon already running (${deps.socketPath}; could not replace the running background service after runtime drift ${publicDriftSummary}: ${reason})`,
115
118
  };
116
119
  (0, runtime_1.emitNervesEvent)({
117
120
  level: "warn",
@@ -138,16 +141,17 @@ async function ensureCurrentDaemonRuntime(deps) {
138
141
  return result;
139
142
  }
140
143
  deps.cleanupStaleSocket(deps.socketPath);
144
+ deps.onProgress?.("starting the replacement background service");
141
145
  const started = await deps.startDaemonProcess(deps.socketPath);
142
146
  const pid = started.pid ?? "unknown";
143
147
  const verified = await verifyDaemonStarted(deps);
144
148
  /* v8 ignore next -- daemon liveness failure: requires real daemon crash timing @preserve */
145
- const suffix = verified ? "" : "\ndaemon restart has not answered yet; check logs with `ouro logs` or run `ouro doctor`.";
149
+ const suffix = verified ? "" : "\nreplacement daemon did not answer in time; check logs with `ouro logs` or run `ouro doctor`.";
146
150
  result = {
147
151
  alreadyRunning: false,
148
152
  message: includesVersionDrift
149
- ? `restarted stale daemon ${runningVersion} -> ${deps.localVersion} (pid ${pid})${suffix}`
150
- : `restarted daemon after runtime drift: ${publicDriftSummary} (pid ${pid})${suffix}`,
153
+ ? `replaced the running background service ${runningVersion} -> ${deps.localVersion} (pid ${pid})${suffix}`
154
+ : `replaced the running background service after runtime drift: ${publicDriftSummary} (pid ${pid})${suffix}`,
151
155
  verifyStartupStatus: verified,
152
156
  startedPid: started.pid ?? null,
153
157
  };
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createTaskModule = createTaskModule;
36
37
  exports.getTaskModule = getTaskModule;
37
38
  exports.resetTaskModule = resetTaskModule;
38
39
  const fs = __importStar(require("fs"));
@@ -67,8 +68,12 @@ function removeRuntimeFrontmatter(frontmatter) {
67
68
  return clean;
68
69
  }
69
70
  class FileTaskModule {
71
+ root;
72
+ constructor(root = (0, scanner_1.getTaskRoot)()) {
73
+ this.root = root;
74
+ }
70
75
  scan() {
71
- return (0, scanner_1.scanTasks)((0, scanner_1.getTaskRoot)());
76
+ return (0, scanner_1.scanTasks)(this.root);
72
77
  }
73
78
  getBoard() {
74
79
  return (0, board_1.buildTaskBoard)(this.scan());
@@ -94,7 +99,7 @@ class FileTaskModule {
94
99
  const collection = (0, transitions_1.canonicalCollectionForTaskType)(type);
95
100
  const stem = `${formatStemTimestamp()}-${(0, config_1.slugify)(input.title).slice(0, 64) || "task"}`;
96
101
  const filename = `${stem}.md`;
97
- const root = (0, scanner_1.getTaskRoot)();
102
+ const root = this.root;
98
103
  const filePath = path.join(root, collection, filename);
99
104
  const today = formatDate();
100
105
  const frontmatter = {
@@ -194,7 +199,7 @@ class FileTaskModule {
194
199
  return (0, middleware_1.validateSpawn)(task, spawnType);
195
200
  }
196
201
  fix(options) {
197
- return (0, fix_1.applyFixes)(options, (0, scanner_1.getTaskRoot)());
202
+ return (0, fix_1.applyFixes)(options, this.root);
198
203
  }
199
204
  detectStale(thresholdDays) {
200
205
  return (0, lifecycle_1.detectStaleTasks)(this.scan(), thresholdDays);
@@ -216,9 +221,12 @@ class FileTaskModule {
216
221
  }
217
222
  }
218
223
  let taskModule = null;
224
+ function createTaskModule(root = (0, scanner_1.getTaskRoot)()) {
225
+ return new FileTaskModule(root);
226
+ }
219
227
  function getTaskModule() {
220
228
  if (!taskModule) {
221
- taskModule = new FileTaskModule();
229
+ taskModule = createTaskModule();
222
230
  }
223
231
  return taskModule;
224
232
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.423",
3
+ "version": "0.1.0-alpha.426",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",