@ouro.bot/cli 0.1.0-alpha.730 → 0.1.0-alpha.731

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/README.md CHANGED
@@ -187,6 +187,8 @@ ouro dev --repo-path /path # start from a specific repo checkout
187
187
  ouro dev --clone # clone repo to ~/Projects/ouroboros, build, start
188
188
  ouro status
189
189
  ouro logs
190
+ ouro logs prune --agent <name>
191
+ ouro mail sync-cache --agent <name>
190
192
  ouro stop
191
193
  ouro vault unlock --agent <name>
192
194
  ouro vault status --agent <name>
@@ -232,8 +234,14 @@ The generic secret primitive is a vault item / credential in the owning agent va
232
234
 
233
235
  `ouro connect bluebubbles --agent <name>` is the standard local-Mac setup path. Besides saving the machine-scoped attachment, it installs or verifies the native-compatible BlueBubbles LaunchAgent for a same-user bridge and reconciles one Ouro-owned `[*]` webhook after the listener is bound. The daemon repairs that owned callback every 180 seconds, preserves unrelated callbacks, and creates the desired callback before removing a stale owned one. If the listener or BlueBubbles API is unavailable, connect says the attachment was saved but setup is incomplete; `ouro doctor` and `ouro bluebubbles host status --json` separate app, service, process, HTTP, and webhook failures.
234
236
 
237
+ Doctor keeps transport proof separate from conversation activity. When the BlueBubbles upstream and exact owned webhook are healthy but no recent inbound event exists, the result is quiet/unverified: quiet is not delivery-failure proof, and Ouro does not invent a message to test it. Standard recovery remains `ouro connect bluebubbles --agent <name>` when host or webhook evidence is unhealthy.
238
+
235
239
  When BlueBubbles runs in another logged-in macOS account, standard setup installs a generic helper and returns one nonce-bound `human-required` Terminal command for that account plus `ouro bluebubbles host collect --request-id <id>`. Ouro never asks for or stores the other account's login password. The receipt proves that one handoff and reports launchd only as point-in-time evidence; current process and HTTP health are checked separately.
236
240
 
241
+ ### Bounded doctor repairs
242
+
243
+ Doctor may recommend two local, agent-qualified repairs. `ouro mail sync-cache --agent <name>` compares read-only hosted authority with the reconstructible local cache, then rebuilds only that cache; it does not mutate hosted mail. `ouro logs prune --agent <name>` rotates only the validated agent bundle's regular log streams. Ouro offers the prune command only for a canonical direct `<name>.ouro` bundle with a present `agent.json`; task-only `.ouro` work directories are not agents.
244
+
237
245
  ## Setting Up On Another Machine
238
246
 
239
247
  To clone an existing agent onto a new machine (macOS, Linux, or Windows via WSL2), see **[docs/cross-machine-setup.md](docs/cross-machine-setup.md)**. The short version is bundle plus vault: `npx ouro.bot@latest`, open the home deck, choose clone, enter the bundle's git remote URL, unlock the agent vault, refresh/verify credentials, and start with `ouro up`.
package/changelog.json CHANGED
@@ -1,6 +1,18 @@
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.731",
6
+ "changes": [
7
+ "Keep doctor grounded: ignore task-only bundle directories and distinguish quiet BlueBubbles activity from verified transport faults.",
8
+ "Add read-only hosted-mail authority comparison and a fail-closed foreground command that reconstructs only the local search cache.",
9
+ "Make daemon log pruning explicitly agent-scoped, shell-safe, and fail closed on unknown, symlinked, non-regular, or containment-escaping targets.",
10
+ "Keep doctor repair guidance on the same canonical target preflight enforced by log execution.",
11
+ "Require hosted-mail cache coverage and liveness to follow fresh current authority, keep quiet old state healthy, treat transient or empty authority as unverified, and refuse empty-authority convergence before local mutation.",
12
+ "Keep delegated cache repair family-only across shell quote concatenation, compound grammar, ordered scalar/array expansion (including fail-closed malformed, wildcard, and dependency-rejection paths), path-qualified executables, wrappers, encoded scripts, and ambiguous ANSI-C escape synthesis without blocking unrelated argument data; bound recursive and large-input classification, reject malformed or duplicate cache-sync agent flags, and emit paired lifecycle evidence for every local repair success or failure.",
13
+ "Document BlueBubbles, mail-cache, and targeted-log recovery as standard Ouro setup and diagnostic behavior."
14
+ ]
15
+ },
4
16
  {
5
17
  "version": "0.1.0-alpha.730",
6
18
  "changes": [
@@ -118,6 +118,7 @@ const provider_ping_progress_1 = require("./provider-ping-progress");
118
118
  const provider_ping_1 = require("../provider-ping");
119
119
  const provider_readiness_cache_1 = require("../provider-readiness-cache");
120
120
  const agent_discovery_1 = require("./agent-discovery");
121
+ const prunable_bundle_1 = require("./prunable-bundle");
121
122
  const boot_sync_probe_1 = require("./boot-sync-probe");
122
123
  const connect_bay_1 = require("./connect-bay");
123
124
  const runtime_capability_check_1 = require("../runtime-capability-check");
@@ -495,6 +496,7 @@ function invalidAgentSelectionMessage(agentNames) {
495
496
  }
496
497
  function agentResolutionFailureMode(command) {
497
498
  switch (command.kind) {
499
+ case "daemon.logs.prune":
498
500
  case "friend.list":
499
501
  case "friend.show":
500
502
  case "friend.create":
@@ -539,6 +541,7 @@ function agentResolutionFailureMode(command) {
539
541
  case "connect":
540
542
  case "account.ensure":
541
543
  case "mail.import-mbox":
544
+ case "mail.sync-cache":
542
545
  case "auth.run":
543
546
  case "auth.verify":
544
547
  case "auth.switch":
@@ -552,12 +555,12 @@ function agentResolutionFailureMode(command) {
552
555
  return undefined;
553
556
  }
554
557
  }
555
- async function resolveMissingAgentName(deps, failureMode) {
558
+ async function resolveMissingAgentName(deps, failureMode, candidateOverride) {
556
559
  const runtimeAgent = runtimeContextAgentName(deps);
557
560
  if (runtimeAgent) {
558
561
  return { ok: true, agent: runtimeAgent };
559
562
  }
560
- const discoveredAgents = normalizeCliAgentNames(await listCliAgents(deps));
563
+ const discoveredAgents = normalizeCliAgentNames(candidateOverride ?? await listCliAgents(deps));
561
564
  if (discoveredAgents.length === 0) {
562
565
  return { ok: false, message: noAgentsFoundMessage(), failureMode };
563
566
  }
@@ -587,7 +590,9 @@ async function resolveCommandAgent(command, deps) {
587
590
  if (explicitAgent) {
588
591
  return { ok: true, command: { ...command, agent: explicitAgent } };
589
592
  }
590
- const resolvedAgent = await resolveMissingAgentName(deps, failureMode);
593
+ const resolvedAgent = await resolveMissingAgentName(deps, failureMode, command.kind === "daemon.logs.prune"
594
+ ? (0, prunable_bundle_1.listPrunableAgentBundles)({ bundlesRoot: deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)() })
595
+ : undefined);
591
596
  if (!resolvedAgent.ok)
592
597
  return resolvedAgent;
593
598
  return { ok: true, command: { ...command, agent: resolvedAgent.agent } };
@@ -6399,6 +6404,12 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
6399
6404
  if (command.kind === "mail.backfill-indexes") {
6400
6405
  return executeMailBackfillIndexes(command, deps);
6401
6406
  }
6407
+ if (command.kind === "mail.sync-cache") {
6408
+ const { runHostedMailCacheSync } = await Promise.resolve().then(() => __importStar(require("../../mailroom/cache-sync-cli")));
6409
+ const text = await runHostedMailCacheSync(command.agent);
6410
+ deps.writeStdout(text);
6411
+ return text;
6412
+ }
6402
6413
  if (command.kind === "daemon.up") {
6403
6414
  // ── dev mode cleanup: delete dev-config.json so the wrapper stops dispatching to dev repo ──
6404
6415
  /* v8 ignore start -- dev-config cleanup: requires real filesystem state @preserve */
@@ -7048,7 +7059,10 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7048
7059
  deps.writeStdout(message);
7049
7060
  return message;
7050
7061
  }
7051
- const result = deps.pruneDaemonLogs();
7062
+ const result = deps.pruneDaemonLogs({
7063
+ agentName: command.agent,
7064
+ bundlesRoot: deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(),
7065
+ });
7052
7066
  const message = `compacted ${result.filesCompacted} file${result.filesCompacted === 1 ? "" : "s"}, freed ${result.bytesFreed} bytes`;
7053
7067
  deps.writeStdout(message);
7054
7068
  return message;
@@ -8354,6 +8368,8 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
8354
8368
  readFileSync: (p) => fs.readFileSync(p, "utf-8"),
8355
8369
  readdirSync: (p) => fs.readdirSync(p),
8356
8370
  statSync: (p) => fs.statSync(p),
8371
+ lstatSync: (p) => fs.lstatSync(p),
8372
+ realpathSync: (p) => fs.realpathSync(p),
8357
8373
  /* v8 ignore stop */
8358
8374
  checkSocketAlive: deps.checkSocketAlive,
8359
8375
  fetchImpl: deps.fetchImpl ?? fetch,
@@ -8363,6 +8379,24 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
8363
8379
  homedir: os.homedir(),
8364
8380
  envPath: process.env.PATH ?? "",
8365
8381
  platform: process.platform,
8382
+ observeHostedMailAuthority: async (agentName) => {
8383
+ const resolved = (0, reader_1.resolveHostedMailAuthority)(agentName);
8384
+ if (!resolved.ok)
8385
+ return { ok: false, definitive: true, detail: resolved.error };
8386
+ try {
8387
+ return { ok: true, observation: await resolved.authority.observeMessageIndexAuthority(agentName) };
8388
+ }
8389
+ catch (error) {
8390
+ const statusCode = typeof error === "object" && error !== null && "statusCode" in error
8391
+ ? error.statusCode
8392
+ : undefined;
8393
+ return {
8394
+ ok: false,
8395
+ definitive: statusCode === 401 || statusCode === 403 || statusCode === 404,
8396
+ detail: error instanceof Error ? error.message : String(error),
8397
+ };
8398
+ }
8399
+ },
8366
8400
  };
8367
8401
  const doctorResult = command.category
8368
8402
  ? await (0, doctor_1.runDoctorChecks)(doctorDeps, { category: command.category })
@@ -40,7 +40,7 @@ exports.COMMAND_REGISTRY = {
40
40
  logs: {
41
41
  category: "Lifecycle",
42
42
  description: "View or prune daemon logs",
43
- usage: "ouro logs [prune]",
43
+ usage: "ouro logs | ouro logs prune --agent <name>",
44
44
  example: "ouro logs",
45
45
  subcommands: ["prune"],
46
46
  },
@@ -261,10 +261,10 @@ exports.COMMAND_REGISTRY = {
261
261
  },
262
262
  mail: {
263
263
  category: "Auth",
264
- description: "Import delegated mail and repair hosted Mailroom mailbox indexes",
265
- usage: "ouro mail <import-mbox|backfill-indexes> [--agent <name>]",
264
+ description: "Import delegated mail and repair hosted Mailroom indexes or local search cache",
265
+ usage: "ouro mail <import-mbox|backfill-indexes|sync-cache> [--agent <name>]",
266
266
  example: "ouro mail import-mbox --discover --owner-email you@example.com --source hey --agent <agent>",
267
- subcommands: ["import-mbox", "backfill-indexes"],
267
+ subcommands: ["import-mbox", "backfill-indexes", "sync-cache"],
268
268
  },
269
269
  use: {
270
270
  category: "Auth",
@@ -540,6 +540,11 @@ const SUBCOMMAND_HELP = {
540
540
  usage: "ouro mail backfill-indexes [--agent <name>] [--foreground]",
541
541
  example: "ouro mail backfill-indexes --agent <agent>",
542
542
  },
543
+ "mail sync-cache": {
544
+ description: "Converge the local decrypted search cache against complete hosted Mailroom authority in the foreground.",
545
+ usage: "ouro mail sync-cache [--agent <name>]",
546
+ example: "ouro mail sync-cache --agent <agent>",
547
+ },
543
548
  "provider refresh": {
544
549
  description: "Reload this agent's provider credentials from its vault into the running daemon",
545
550
  usage: "ouro provider refresh [--agent <name>]",
@@ -19,6 +19,7 @@ const cli_help_1 = require("./cli-help");
19
19
  const cli_desk_1 = require("./cli-desk");
20
20
  const flight_recorder_1 = require("../../arc/flight-recorder");
21
21
  const core_1 = require("../../nerves/review/core");
22
+ const prunable_bundle_1 = require("./prunable-bundle");
22
23
  const vault_items_1 = require("./vault-items");
23
24
  // ── Shared helpers ──
24
25
  function extractAgentFlag(args) {
@@ -29,6 +30,22 @@ function extractAgentFlag(args) {
29
30
  const rest = [...args.slice(0, idx), ...args.slice(idx + 2)];
30
31
  return { agent, rest };
31
32
  }
33
+ function parseLogsCommand(args) {
34
+ if (args.length === 0)
35
+ return { kind: "daemon.logs" };
36
+ if (args[0] !== "prune")
37
+ throw new Error("Usage: ouro logs prune [--agent <name>]");
38
+ const tail = args.slice(1);
39
+ const agentFlagCount = tail.filter((token) => token === "--agent").length;
40
+ const { agent, rest } = extractAgentFlag(tail);
41
+ if (agentFlagCount > 1 ||
42
+ rest.length > 0 ||
43
+ (agentFlagCount === 1 && !agent) ||
44
+ (agent !== undefined && !(0, prunable_bundle_1.isSafePrunableAgentName)(agent))) {
45
+ throw new Error("Usage: ouro logs prune [--agent <name>]");
46
+ }
47
+ return { kind: "daemon.logs.prune", ...(agent ? { agent } : {}) };
48
+ }
32
49
  function extractFacingFlag(args) {
33
50
  const idx = args.indexOf("--facing");
34
51
  if (idx === -1 || idx + 1 >= args.length)
@@ -1094,7 +1111,17 @@ function parseConnectCommand(args) {
1094
1111
  }
1095
1112
  function parseMailCommand(args) {
1096
1113
  const [sub, ...subArgs] = args;
1097
- const usageText = "Usage: ouro mail import-mbox (--file <path>|--discover) [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]\n ouro mail backfill-indexes [--agent <name>] [--foreground]";
1114
+ const usageText = "Usage: ouro mail import-mbox (--file <path>|--discover) [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]\n ouro mail backfill-indexes [--agent <name>] [--foreground]\n ouro mail sync-cache [--agent <name>]";
1115
+ if (sub === "sync-cache") {
1116
+ const agentFlagCount = subArgs.filter((token) => token === "--agent").length;
1117
+ const { agent, rest } = extractAgentFlag(subArgs);
1118
+ if (agentFlagCount > 1 ||
1119
+ rest.length > 0 ||
1120
+ (agentFlagCount === 1 && (!agent || agent.trim().length === 0 || agent.trim().startsWith("--")))) {
1121
+ throw new Error("Usage: ouro mail sync-cache [--agent <name>]");
1122
+ }
1123
+ return { kind: "mail.sync-cache", ...(agent ? { agent } : {}) };
1124
+ }
1098
1125
  if (sub === "backfill-indexes") {
1099
1126
  const { agent, rest } = extractAgentFlag(subArgs);
1100
1127
  let foreground = false;
@@ -2568,11 +2595,8 @@ function parseOuroCommand(args) {
2568
2595
  return parseMailCommand(args.slice(1));
2569
2596
  if (head === "dns")
2570
2597
  return parseDnsCommand(args.slice(1));
2571
- if (head === "logs") {
2572
- if (second === "prune")
2573
- return { kind: "daemon.logs.prune" };
2574
- return { kind: "daemon.logs" };
2575
- }
2598
+ if (head === "logs")
2599
+ return parseLogsCommand(args.slice(1));
2576
2600
  if (head === "mailbox" || head === "outlook")
2577
2601
  return { kind: "mailbox", ...(args.includes("--json") ? { json: true } : {}) };
2578
2602
  if (head === "hatch")