@ouro.bot/cli 0.1.0-alpha.454 → 0.1.0-alpha.456

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.
@@ -50,6 +50,10 @@ function textField(value, key) {
50
50
  const raw = value[key];
51
51
  return typeof raw === "string" && raw.trim() ? raw.trim() : undefined;
52
52
  }
53
+ function numberField(value, key) {
54
+ const raw = value[key];
55
+ return typeof raw === "number" && Number.isFinite(raw) ? raw : undefined;
56
+ }
53
57
  function parseMailroomConfig(value) {
54
58
  if (!isRecord(value))
55
59
  return null;
@@ -63,16 +67,28 @@ function parseMailroomConfig(value) {
63
67
  }));
64
68
  if (Object.keys(privateKeys).length === 0)
65
69
  return null;
70
+ const registryPath = textField(value, "registryPath");
66
71
  const storePath = textField(value, "storePath");
67
72
  const azureAccountUrl = textField(value, "azureAccountUrl");
68
73
  const azureContainer = textField(value, "azureContainer");
69
74
  const azureManagedIdentityClientId = textField(value, "azureManagedIdentityClientId");
75
+ const smtpPort = numberField(value, "smtpPort");
76
+ const httpPort = numberField(value, "httpPort");
77
+ const host = textField(value, "host");
78
+ const attentionIntervalMs = numberField(value, "attentionIntervalMs");
79
+ const outbound = isRecord(value.outbound) ? { ...value.outbound } : undefined;
70
80
  return {
71
81
  mailboxAddress,
82
+ ...(registryPath ? { registryPath } : {}),
72
83
  ...(storePath ? { storePath } : {}),
73
84
  ...(azureAccountUrl ? { azureAccountUrl } : {}),
74
85
  ...(azureContainer ? { azureContainer } : {}),
75
86
  ...(azureManagedIdentityClientId ? { azureManagedIdentityClientId } : {}),
87
+ ...(smtpPort !== undefined ? { smtpPort } : {}),
88
+ ...(httpPort !== undefined ? { httpPort } : {}),
89
+ ...(host ? { host } : {}),
90
+ ...(attentionIntervalMs !== undefined ? { attentionIntervalMs } : {}),
91
+ ...(outbound ? { outbound } : {}),
76
92
  privateKeys,
77
93
  };
78
94
  }
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractTravelFactsFromMail = extractTravelFactsFromMail;
4
+ const runtime_1 = require("../nerves/runtime");
5
+ function firstMatch(text, pattern) {
6
+ const match = pattern.exec(text);
7
+ return match?.[1]?.trim() ?? null;
8
+ }
9
+ function flightFact(message) {
10
+ const text = `${message.private.subject}\n${message.private.text}`;
11
+ const flightNumber = firstMatch(text, /\bflight\s+([A-Z]{2}\s?\d{1,4})\b/i);
12
+ const routeMatch = /\b([A-Z]{3})\s*(?:->|to)\s*([A-Z]{3})\b/.exec(text);
13
+ const confirmationCode = firstMatch(text, /confirmation code:\s*([A-Z0-9-]+)/i);
14
+ const departure = firstMatch(text, /departure:\s*([^\n]+)/i);
15
+ if (!flightNumber && !routeMatch && !departure)
16
+ return null;
17
+ const fields = {};
18
+ if (flightNumber)
19
+ fields.flightNumber = flightNumber.toUpperCase().replace(/\s+/, " ");
20
+ if (routeMatch)
21
+ fields.route = `${routeMatch[1]} -> ${routeMatch[2]}`;
22
+ if (departure)
23
+ fields.departure = departure;
24
+ if (confirmationCode)
25
+ fields.confirmationCode = confirmationCode;
26
+ return {
27
+ kind: "flight",
28
+ messageId: message.id,
29
+ subject: message.private.subject,
30
+ source: message.source ?? null,
31
+ ownerEmail: message.ownerEmail ?? null,
32
+ summary: [
33
+ fields.flightNumber ? `flight ${fields.flightNumber}` : "flight",
34
+ fields.route ? fields.route : null,
35
+ fields.departure ? `departing ${fields.departure}` : null,
36
+ ].filter(Boolean).join(" "),
37
+ fields,
38
+ };
39
+ }
40
+ function lodgingFact(message) {
41
+ const text = `${message.private.subject}\n${message.private.text}`;
42
+ const hotel = firstMatch(text, /hotel:\s*([^\n]+)/i);
43
+ const checkIn = firstMatch(text, /check-?in:\s*([^\n]+)/i);
44
+ const checkOut = firstMatch(text, /check-?out:\s*([^\n]+)/i);
45
+ const confirmationCode = firstMatch(text, /confirmation code:\s*([A-Z0-9-]+)/i);
46
+ if (!hotel && !checkIn && !/hotel|lodging|booking/i.test(message.private.subject))
47
+ return null;
48
+ const fields = {};
49
+ if (hotel)
50
+ fields.hotel = hotel;
51
+ if (checkIn)
52
+ fields.checkIn = checkIn;
53
+ if (checkOut)
54
+ fields.checkOut = checkOut;
55
+ if (confirmationCode)
56
+ fields.confirmationCode = confirmationCode;
57
+ return {
58
+ kind: "lodging",
59
+ messageId: message.id,
60
+ subject: message.private.subject,
61
+ source: message.source ?? null,
62
+ ownerEmail: message.ownerEmail ?? null,
63
+ summary: [
64
+ hotel ?? "lodging",
65
+ checkIn ? `check-in ${checkIn}` : null,
66
+ checkOut ? `check-out ${checkOut}` : null,
67
+ ].filter(Boolean).join(" "),
68
+ fields,
69
+ };
70
+ }
71
+ function extractTravelFactsFromMail(messages) {
72
+ const facts = messages.flatMap((message) => {
73
+ const results = [];
74
+ const flight = flightFact(message);
75
+ if (flight)
76
+ results.push(flight);
77
+ const lodging = lodgingFact(message);
78
+ if (lodging)
79
+ results.push(lodging);
80
+ return results;
81
+ });
82
+ (0, runtime_1.emitNervesEvent)({
83
+ component: "senses",
84
+ event: "senses.mail_travel_facts_extracted",
85
+ message: "travel facts extracted from mail",
86
+ meta: { messages: messages.length, facts: facts.length },
87
+ });
88
+ return facts;
89
+ }
@@ -464,7 +464,7 @@ function senseRuntimeGuidance(channel, preReadStatusLines) {
464
464
  lines.push("If asked how to enable another sense, I explain the relevant agent.json senses entry and required agent-vault runtime/config fields instead of guessing.");
465
465
  lines.push("teams setup truth: run `ouro connect teams --agent <agent>` from the connect bay; it stores Teams runtime/config fields and enables `senses.teams.enabled`.");
466
466
  lines.push("bluebubbles setup truth: run `ouro connect bluebubbles --agent <agent>` from the connect bay; it stores this machine's BlueBubbles URL/password/listener config in the agent vault machine runtime item.");
467
- lines.push("mail setup truth: Agent Mail uses Mailroom, not HEY OAuth/IMAP. To provision, run `ouro connect mail --agent <agent>`; use the human's owner email when asked so Mailroom creates the delegated source alias.");
467
+ lines.push("mail setup truth: Agent Mail uses Mailroom, not HEY OAuth/IMAP. For the full work substrate account, run `ouro account ensure --agent <agent>`; use `ouro connect mail --agent <agent>` for mail-only repair/provisioning. Use the human's owner email when asked so Mailroom creates the delegated source alias. The detailed runbook is `docs/agent-mail-setup.md`.");
468
468
  lines.push("mail setup truth: HEY archive bootstrap is human-exported MBOX only. Ask for the browser-downloaded MBOX path, then run `ouro mail import-mbox --file <path> --owner-email <email> --source hey --agent <agent>`.");
469
469
  lines.push("mail setup truth: verify with `ouro status`, `ouro doctor --agent <agent>`, bounded mail tools (`mail_recent`, `mail_search`, `mail_thread`, `mail_access_log`), and the read-only Outlook Mailbox tab.");
470
470
  lines.push("mail setup boundaries: do not invent `ouro auth verify --provider mail`, HEY OAuth, HEY IMAP, `ouro mcp call mail ...`, policy flags, autonomous sending, destructive mail actions, or production MX/DNS/forwarding changes. HEY export, HEY forwarding, DNS, MX cutover, sending, and destructive actions require explicit human confirmation.");