@ouro.bot/cli 0.1.0-alpha.724 → 0.1.0-alpha.726

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 (54) hide show
  1. package/changelog.json +18 -0
  2. package/dist/heart/active-work.js +10 -3
  3. package/dist/heart/core.js +343 -77
  4. package/dist/heart/daemon/cli-exec.js +72 -14
  5. package/dist/heart/daemon/cli-help.js +13 -2
  6. package/dist/heart/daemon/cli-parse.js +82 -1
  7. package/dist/heart/daemon/daemon.js +286 -33
  8. package/dist/heart/daemon/doctor.js +21 -6
  9. package/dist/heart/daemon/habit-private-wake.js +6 -1
  10. package/dist/heart/habits/habit-cancel.js +810 -0
  11. package/dist/heart/habits/habit-lifecycle.js +1327 -0
  12. package/dist/heart/habits/habit-migration.js +28 -23
  13. package/dist/heart/habits/habit-parser.js +72 -8
  14. package/dist/heart/habits/habit-runtime-state.js +3 -24
  15. package/dist/heart/habits/habit-scheduler.js +268 -50
  16. package/dist/heart/habits/habit-session.js +16 -0
  17. package/dist/heart/hatch/hatch-flow.js +6 -4
  18. package/dist/heart/mailbox/readers/runtime-readers.js +26 -27
  19. package/dist/heart/orientation-frame.js +58 -1
  20. package/dist/heart/provider-attempt.js +4 -1
  21. package/dist/heart/providers/anthropic.js +23 -2
  22. package/dist/heart/start-of-turn-packet.js +14 -11
  23. package/dist/heart/streaming.js +565 -185
  24. package/dist/mind/obligation-steering.js +15 -9
  25. package/dist/mind/prompt.js +58 -26
  26. package/dist/nerves/coverage/run-artifacts.js +55 -35
  27. package/dist/nerves/review/cli.js +2 -2
  28. package/dist/nerves/review/core.js +14 -7
  29. package/dist/repertoire/tools-base.js +2 -0
  30. package/dist/repertoire/tools-habits.js +103 -0
  31. package/dist/repertoire/tools.js +18 -3
  32. package/dist/rsvp/cli.js +126 -20
  33. package/dist/rsvp/diagnostics.js +12 -2
  34. package/dist/rsvp/habit-policy.js +7 -0
  35. package/dist/rsvp/habit-stage.js +19 -4
  36. package/dist/rsvp/native-habit-runner.js +151 -11
  37. package/dist/rsvp/outbound-state.js +360 -0
  38. package/dist/senses/bluebubbles/client.js +90 -17
  39. package/dist/senses/bluebubbles/inbound-log.js +1 -0
  40. package/dist/senses/bluebubbles/index.js +662 -425
  41. package/dist/senses/bluebubbles/model.js +57 -13
  42. package/dist/senses/bluebubbles/mutation-log.js +21 -10
  43. package/dist/senses/bluebubbles/reaction-policy.js +55 -0
  44. package/dist/senses/bluebubbles/semantic-receipts.js +1818 -0
  45. package/dist/senses/cli/tui-store.js +1 -0
  46. package/dist/senses/cli.js +1 -0
  47. package/dist/senses/habit-lifecycle-guard.js +24 -0
  48. package/dist/senses/ingress-evidence.js +2 -0
  49. package/dist/senses/pipeline.js +90 -24
  50. package/dist/senses/private-runtime-worker.js +21 -20
  51. package/dist/senses/private-runtime.js +79 -29
  52. package/dist/senses/shared-turn.js +1 -0
  53. package/dist/senses/teams.js +1 -0
  54. package/package.json +6 -1
@@ -1444,8 +1444,41 @@ async function checkManualCloneBundles(deps) {
1444
1444
  }
1445
1445
  // ── toDaemonCommand ──
1446
1446
  function toDaemonCommand(command) {
1447
+ if (command.kind === "habit.probe") {
1448
+ return {
1449
+ kind: "habit.probe",
1450
+ agent: command.agent,
1451
+ habitName: command.habitName,
1452
+ noSend: true,
1453
+ };
1454
+ }
1447
1455
  return command;
1448
1456
  }
1457
+ function habitProbeJsonResponse(response) {
1458
+ const data = response.data && typeof response.data === "object" && !Array.isArray(response.data)
1459
+ ? response.data
1460
+ : null;
1461
+ const status = typeof data?.status === "string" ? data.status : "degraded";
1462
+ if (response.ok
1463
+ && data?.noSend === true
1464
+ && typeof data.transportInvocationCount === "number"
1465
+ && data.transportInvocationCount === 0) {
1466
+ return JSON.stringify({
1467
+ noSend: true,
1468
+ status,
1469
+ transportInvocationCount: 0,
1470
+ }, null, 2);
1471
+ }
1472
+ return JSON.stringify({
1473
+ ok: false,
1474
+ noSend: true,
1475
+ status,
1476
+ transportInvocationCount: null,
1477
+ error: response.error
1478
+ ?? (!response.ok ? response.message : undefined)
1479
+ ?? "habit probe did not produce verified zero-transport evidence",
1480
+ }, null, 2);
1481
+ }
1449
1482
  // ── Hatch input resolution ──
1450
1483
  async function resolveHatchInput(command, deps) {
1451
1484
  const prompt = deps.promptInput;
@@ -7218,8 +7251,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7218
7251
  return result.summary;
7219
7252
  }
7220
7253
  // ── habit subcommands (local, no daemon socket needed) ──
7221
- if (command.kind === "habit.list" || command.kind === "habit.create" || command.kind === "habit.runs" || command.kind === "habit.inspect" || command.kind === "habit.summary") {
7222
- const { parseHabitFile, renderHabitFile } = await Promise.resolve().then(() => __importStar(require("../habits/habit-parser")));
7254
+ if (command.kind === "habit.list" || command.kind === "habit.create" || command.kind === "habit.runs" || command.kind === "habit.inspect" || command.kind === "habit.summary" || command.kind === "habit.cancel") {
7255
+ const { createDegradedHabitFile, parseHabitFile, renderHabitFile } = await Promise.resolve().then(() => __importStar(require("../habits/habit-parser")));
7256
+ const { publishNewHabitDefinition } = await Promise.resolve().then(() => __importStar(require("../habits/habit-lifecycle")));
7223
7257
  const { applyHabitRuntimeState } = await Promise.resolve().then(() => __importStar(require("../habits/habit-runtime-state")));
7224
7258
  const { listHabitRunReceipts, readHabitRunReceipt } = await Promise.resolve().then(() => __importStar(require("../../arc/flight-recorder")));
7225
7259
  const { readHabitSessionSummary } = await Promise.resolve().then(() => __importStar(require("../habits/habit-session-summary")));
@@ -7227,10 +7261,21 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7227
7261
  const bundleRoot = deps.agentBundleRoot ?? path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), `${command.agent}.ouro`);
7228
7262
  /* v8 ignore stop */
7229
7263
  const habitsDir = path.join(bundleRoot, "habits");
7264
+ if (command.kind === "habit.cancel") {
7265
+ const { cancelHabit } = await Promise.resolve().then(() => __importStar(require("../habits/habit-cancel")));
7266
+ const receipt = await cancelHabit({
7267
+ agentRoot: bundleRoot,
7268
+ habitId: command.habitName,
7269
+ evidenceLocator: command.evidenceLocator,
7270
+ authority: { kind: "offline_bridge" },
7271
+ }, deps.habitCancelDeps);
7272
+ deps.writeStdout(receipt.acknowledgement);
7273
+ return receipt.acknowledgement;
7274
+ }
7230
7275
  if (command.kind === "habit.list") {
7231
7276
  let files;
7232
7277
  try {
7233
- files = fs.readdirSync(habitsDir).filter((f) => f.endsWith(".md") && f !== "README.md");
7278
+ files = fs.readdirSync(habitsDir).filter((f) => f.endsWith(".md") && f !== "README.md").sort();
7234
7279
  }
7235
7280
  catch {
7236
7281
  const message = "no habits found";
@@ -7244,10 +7289,18 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7244
7289
  }
7245
7290
  const lines = [];
7246
7291
  for (const file of files) {
7247
- const fileContent = fs.readFileSync(path.join(habitsDir, file), "utf-8");
7248
- const habit = applyHabitRuntimeState(bundleRoot, parseHabitFile(fileContent, path.join(habitsDir, file)));
7292
+ const filePath = path.join(habitsDir, file);
7293
+ let habit;
7294
+ try {
7295
+ const fileContent = fs.readFileSync(filePath, "utf-8");
7296
+ habit = applyHabitRuntimeState(bundleRoot, parseHabitFile(fileContent, filePath));
7297
+ }
7298
+ catch (error) {
7299
+ habit = createDegradedHabitFile(filePath, "read_error", "", error instanceof Error ? error.message : String(error));
7300
+ }
7249
7301
  const lastRunStr = habit.lastRun ?? "never";
7250
- lines.push(`${habit.name} cadence=${habit.cadence ?? "none"} status=${habit.status} lastRun=${lastRunStr}`);
7302
+ const degradedReason = habit.status === "degraded" ? ` degradedReason=${habit.degradedReason}` : "";
7303
+ lines.push(`${habit.name} cadence=${habit.cadence ?? "none"} status=${habit.status}${degradedReason} lastRun=${lastRunStr}`);
7251
7304
  }
7252
7305
  const message = lines.join("\n");
7253
7306
  deps.writeStdout(message);
@@ -7331,12 +7384,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7331
7384
  }
7332
7385
  // habit.create
7333
7386
  const filePath = path.join(habitsDir, `${command.name}.md`);
7334
- if (fs.existsSync(filePath)) {
7335
- const message = `error: habit '${command.name}' already exists`;
7336
- deps.writeStdout(message);
7337
- return message;
7338
- }
7339
- fs.mkdirSync(habitsDir, { recursive: true });
7340
7387
  const now = new Date().toISOString();
7341
7388
  const habitContent = renderHabitFile({
7342
7389
  title: command.name,
@@ -7344,7 +7391,16 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
7344
7391
  status: "active",
7345
7392
  created: now,
7346
7393
  }, `Habit: ${command.name}`);
7347
- fs.writeFileSync(filePath, habitContent, "utf-8");
7394
+ const publication = publishNewHabitDefinition({
7395
+ agentRoot: bundleRoot,
7396
+ habitId: command.name,
7397
+ bytes: habitContent,
7398
+ });
7399
+ if (publication === "exists") {
7400
+ const message = `error: habit '${command.name}' already exists`;
7401
+ deps.writeStdout(message);
7402
+ return message;
7403
+ }
7348
7404
  const message = `created: ${filePath}`;
7349
7405
  deps.writeStdout(message);
7350
7406
  return message;
@@ -8317,7 +8373,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
8317
8373
  ? command.json
8318
8374
  ? formatDaemonStatusJsonOutput(response)
8319
8375
  : (0, cli_render_1.formatDaemonStatusOutput)(response, fallbackMessage)
8320
- : fallbackMessage;
8376
+ : command.kind === "habit.probe" && command.json
8377
+ ? habitProbeJsonResponse(response)
8378
+ : fallbackMessage;
8321
8379
  deps.writeStdout(message);
8322
8380
  return message;
8323
8381
  }
@@ -10,6 +10,7 @@ exports.levenshteinDistance = levenshteinDistance;
10
10
  exports.suggestCommand = suggestCommand;
11
11
  exports.getGroupedHelp = getGroupedHelp;
12
12
  exports.getCommandHelp = getCommandHelp;
13
+ const core_1 = require("../../nerves/review/core");
13
14
  // ── Registry ──
14
15
  exports.COMMAND_REGISTRY = {
15
16
  up: {
@@ -142,7 +143,7 @@ exports.COMMAND_REGISTRY = {
142
143
  description: "Manage agent habits",
143
144
  usage: "ouro habit <subcommand> [--agent <name>]",
144
145
  example: "ouro habit list",
145
- subcommands: ["list", "create", "runs", "inspect", "summary", "poke"],
146
+ subcommands: ["list", "create", "runs", "inspect", "summary", "poke", "cancel", "probe"],
146
147
  },
147
148
  rsvp: {
148
149
  category: "Habits",
@@ -186,7 +187,7 @@ exports.COMMAND_REGISTRY = {
186
187
  },
187
188
  "nerves-review": {
188
189
  category: "Internal",
189
- description: "Read-only review of recent nerves events from an agent log stream",
190
+ description: `Read-only review of recent nerves events from one agent log stream (default: ${core_1.DEFAULT_NERVES_PROCESS})`,
190
191
  usage: "ouro nerves-review [--agent <name>] [--process <name>] [--component <substr>] [--event <substr>] [--level <level>] [--since <duration>] [--limit <n>] [--json]",
191
192
  example: "ouro nerves-review --agent slugger --component daemon --event habit --since 30m --json",
192
193
  },
@@ -368,6 +369,16 @@ exports.COMMAND_REGISTRY = {
368
369
  },
369
370
  };
370
371
  const SUBCOMMAND_HELP = {
372
+ "habit probe": {
373
+ description: "Probe one habit through its real dispatch path with an irrevocable no-send boundary; it cannot send and reports zero transport invocations",
374
+ usage: "ouro habit probe --agent <name> --habit <name> --no-send [--json]",
375
+ example: "ouro habit probe --agent slugger --habit report-name --no-send --json",
376
+ },
377
+ "habit cancel": {
378
+ description: "Cancel a habit offline from a previously verified evidence bridge",
379
+ usage: "ouro habit cancel --agent <name> --habit <name> --evidence <bridge-id>",
380
+ example: "ouro habit cancel --agent slugger --habit report-name --evidence pre-v1-bluebubbles-event-id",
381
+ },
371
382
  "private decisions": {
372
383
  description: "Read recent private-runtime allow/deny decisions from the policy ledger",
373
384
  usage: "ouro private decisions [--agent <name>] [--limit <n>] [--json]",
@@ -18,6 +18,7 @@ const friends_1 = require("@ouro.bot/friends");
18
18
  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
+ const core_1 = require("../../nerves/review/core");
21
22
  const vault_items_1 = require("./vault-items");
22
23
  // ── Shared helpers ──
23
24
  function extractAgentFlag(args) {
@@ -112,6 +113,8 @@ function usage() {
112
113
  " ouro habit runs [--agent <name>] [--limit <n>]",
113
114
  " ouro habit inspect [--agent <name>] <runId>",
114
115
  " ouro habit summary [--agent <name>] (--run-id <id>|--habit <name>|--operation-id <id>) [--which latest|previous|latest-success|latest-failure] [--json]",
116
+ " ouro habit cancel --agent <name> --habit <name> --evidence <bridge-id>",
117
+ " ouro habit probe --agent <name> --habit <name> --no-send [--json]",
115
118
  " ouro link <agent> --friend <id> --provider <provider> --external-id <external-id>",
116
119
  " ouro bluebubbles replay [--agent <name>] --message-guid <guid> [--event-type new-message|updated-message] [--json]",
117
120
  " ouro bluebubbles context-smoke [--agent <name>] --message-guid <guid> [--persist] [--json]",
@@ -314,6 +317,84 @@ function parsePokeCommand(args) {
314
317
  function parseHabitCommand(args) {
315
318
  const { agent, rest } = extractAgentFlag(args);
316
319
  const sub = rest[0];
320
+ if (sub === "probe") {
321
+ if (args.includes("--allow-send")) {
322
+ throw new Error("habit probe cannot allow send");
323
+ }
324
+ if (args.filter((value) => value === "--agent").length !== 1
325
+ || !agent
326
+ || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(agent))
327
+ throw new Error("habit probe requires --agent <name>");
328
+ let habitName;
329
+ let json = false;
330
+ let sawNoSend = false;
331
+ const options = rest.slice(1);
332
+ for (let index = 0; index < options.length; index += 1) {
333
+ const option = options[index];
334
+ if (option === "--json") {
335
+ if (json)
336
+ throw new Error("habit probe received duplicate --json");
337
+ json = true;
338
+ continue;
339
+ }
340
+ if (option === "--no-send") {
341
+ if (sawNoSend)
342
+ throw new Error("habit probe received duplicate --no-send");
343
+ sawNoSend = true;
344
+ continue;
345
+ }
346
+ if (option === "--habit" && options[index + 1]) {
347
+ if (habitName !== undefined)
348
+ throw new Error("habit probe received duplicate --habit");
349
+ habitName = options[index + 1];
350
+ index += 1;
351
+ continue;
352
+ }
353
+ throw new Error("Usage: ouro habit probe --agent <name> --habit <name> --no-send [--json]");
354
+ }
355
+ if (!habitName)
356
+ throw new Error("habit probe requires --habit <name>");
357
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(habitName)) {
358
+ throw new Error("habit probe requires a valid --habit name");
359
+ }
360
+ return { kind: "habit.probe", agent, habitName, noSend: true, json };
361
+ }
362
+ if (sub === "cancel") {
363
+ if (args.filter((value) => value === "--agent").length !== 1
364
+ || !agent
365
+ || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(agent)) {
366
+ throw new Error(`Usage\n${usage()}`);
367
+ }
368
+ let habitName;
369
+ let evidenceLocator;
370
+ const options = rest.slice(1);
371
+ for (let index = 0; index < options.length; index += 1) {
372
+ const option = options[index];
373
+ const value = options[index + 1];
374
+ if ((option !== "--habit" && option !== "--evidence") || value === undefined) {
375
+ throw new Error(`Usage\n${usage()}`);
376
+ }
377
+ if (option === "--habit") {
378
+ if (habitName !== undefined)
379
+ throw new Error(`Usage\n${usage()}`);
380
+ habitName = value;
381
+ }
382
+ else {
383
+ if (evidenceLocator !== undefined)
384
+ throw new Error(`Usage\n${usage()}`);
385
+ evidenceLocator = value;
386
+ }
387
+ index += 1;
388
+ }
389
+ if (!habitName || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(habitName)) {
390
+ throw new Error("habit cancellation requires a valid --habit name");
391
+ }
392
+ if (!evidenceLocator
393
+ || evidenceLocator.startsWith("capture:")
394
+ || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(evidenceLocator))
395
+ throw new Error("habit cancellation requires an offline evidence bridge ID");
396
+ return { kind: "habit.cancel", agent, habitName, evidenceLocator };
397
+ }
317
398
  if (sub === "list") {
318
399
  return { kind: "habit.list", ...(agent ? { agent } : {}) };
319
400
  }
@@ -2225,7 +2306,7 @@ function parseRsvpSmokeCommand(args) {
2225
2306
  }
2226
2307
  function parseNervesReviewCommand(args) {
2227
2308
  const { agent, rest } = extractAgentFlag(args);
2228
- let processName = "daemon";
2309
+ let processName = core_1.DEFAULT_NERVES_PROCESS;
2229
2310
  let component;
2230
2311
  let event;
2231
2312
  let level;