@ouro.bot/cli 0.1.0-alpha.695 → 0.1.0-alpha.697
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 +15 -0
- package/dist/arc/flight-recorder.js +139 -21
- package/dist/arc/obligations.js +28 -6
- package/dist/arc/packets.js +48 -0
- package/dist/heart/autonomy-budget.js +434 -0
- package/dist/heart/core.js +11 -0
- package/dist/heart/daemon/cadence.js +110 -0
- package/dist/heart/daemon/cli-exec.js +20 -0
- package/dist/heart/daemon/cli-help.js +74 -0
- package/dist/heart/daemon/cli-parse.js +466 -0
- package/dist/heart/daemon/daemon.js +24 -3
- package/dist/heart/daemon/doctor.js +151 -0
- package/dist/heart/daemon/stale-bundle-prune.js +23 -6
- package/dist/heart/habits/habit-parser.js +4 -1
- package/dist/heart/habits/habit-scheduler.js +46 -38
- package/dist/heart/habits/habit-session.js +2 -3
- package/dist/heart/run-ledger.js +247 -0
- package/dist/heart/runtime-credentials.js +12 -3
- package/dist/heart/work-card.js +1 -11
- package/dist/mind/prompt-budget.js +380 -0
- package/dist/repertoire/tools-base.js +2 -0
- package/dist/repertoire/tools-obligations.js +39 -0
- package/dist/repertoire/tools-rsvp.js +139 -0
- package/dist/rsvp/aisleplanner-client.js +354 -0
- package/dist/rsvp/cli.js +679 -0
- package/dist/rsvp/config.js +327 -0
- package/dist/rsvp/cutover.js +431 -0
- package/dist/rsvp/diagnostics.js +222 -0
- package/dist/rsvp/diff-renderer.js +159 -0
- package/dist/rsvp/habit-policy.js +85 -0
- package/dist/rsvp/habit-stage.js +93 -0
- package/dist/rsvp/incident-bundle.js +97 -0
- package/dist/rsvp/migration.js +204 -0
- package/dist/rsvp/outbound-state.js +254 -0
- package/dist/rsvp/query.js +118 -0
- package/dist/rsvp/replay.js +233 -0
- package/dist/rsvp/snapshot.js +232 -0
- package/dist/senses/bluebubbles/client.js +13 -7
- package/dist/senses/bluebubbles/index.js +227 -22
- package/dist/senses/bluebubbles/outbound-state.js +304 -0
- package/dist/senses/bluebubbles/replay.js +147 -0
- package/dist/senses/context-packet-ledger.js +245 -0
- package/dist/senses/context-packets.js +154 -0
- package/dist/senses/pipeline.js +92 -12
- package/dist/senses/private-runtime-worker.js +170 -31
- package/dist/senses/private-runtime.js +13 -1
- package/dist/senses/voice/twilio-phone.js +9 -5
- package/package.json +1 -1
|
@@ -144,6 +144,25 @@ exports.COMMAND_REGISTRY = {
|
|
|
144
144
|
example: "ouro habit list",
|
|
145
145
|
subcommands: ["list", "create", "runs", "inspect", "summary", "poke"],
|
|
146
146
|
},
|
|
147
|
+
rsvp: {
|
|
148
|
+
category: "Habits",
|
|
149
|
+
description: "AislePlanner-backed RSVP habit operations, triage, receipts, ledgers, migration checks, refreshes, and smoke tests",
|
|
150
|
+
usage: "ouro rsvp <doctor|incident|cutover|legacy-render|replay|config|habit|import-legacy|refresh|compare|smoke> ...",
|
|
151
|
+
example: "ouro rsvp doctor --agent slugger --json",
|
|
152
|
+
subcommands: [
|
|
153
|
+
"doctor",
|
|
154
|
+
"incident",
|
|
155
|
+
"cutover",
|
|
156
|
+
"legacy-render",
|
|
157
|
+
"replay",
|
|
158
|
+
"config import-legacy",
|
|
159
|
+
"habit stage",
|
|
160
|
+
"import-legacy",
|
|
161
|
+
"refresh",
|
|
162
|
+
"compare",
|
|
163
|
+
"smoke",
|
|
164
|
+
],
|
|
165
|
+
},
|
|
147
166
|
desk: {
|
|
148
167
|
category: "Tasks",
|
|
149
168
|
description: "Manage the agent's desk — tasks, tracks, friction, lessons, search, and recall (routes through the desk MCP server).",
|
|
@@ -431,6 +450,61 @@ const SUBCOMMAND_HELP = {
|
|
|
431
450
|
usage: "ouro habit summary [--agent <name>] (--run-id <id>|--habit <name>|--operation-id <id>) [--which latest|previous|latest-success|latest-failure] [--json]",
|
|
432
451
|
example: "ouro habit summary --agent slugger --operation-id habit:standup --which latest --json",
|
|
433
452
|
},
|
|
453
|
+
"rsvp doctor": {
|
|
454
|
+
description: "Check native RSVP configuration, credentials, BlueBubbles attachment, ledgers, receipts, and migration readiness without sending messages; use --json --strict in triage",
|
|
455
|
+
usage: "ouro rsvp doctor [--agent <name>] [--strict] [--output <path>] [--json]",
|
|
456
|
+
example: "ouro rsvp doctor --agent slugger --strict --json",
|
|
457
|
+
},
|
|
458
|
+
"rsvp incident": {
|
|
459
|
+
description: "Collect a redacted local RSVP diagnostic incident bundle with doctor status, receipts, and ledger pointers without contacting the daemon",
|
|
460
|
+
usage: "ouro rsvp incident [--agent <name>] [--output <path>] [--json]",
|
|
461
|
+
example: "ouro rsvp incident --agent slugger --output /tmp/rsvp-incident.json",
|
|
462
|
+
},
|
|
463
|
+
"rsvp cutover": {
|
|
464
|
+
description: "Inspect or retire legacy RSVP sender state before native live send",
|
|
465
|
+
usage: "ouro rsvp cutover [--agent <name>] --legacy-root <path> --action check|quarantine-launchd|retire-legacy-send-config [--yes] [--output <path>] [--json]",
|
|
466
|
+
example: "ouro rsvp cutover --agent slugger --legacy-root ~/Projects/rsvp-tracker --action check --json",
|
|
467
|
+
},
|
|
468
|
+
"rsvp legacy-render": {
|
|
469
|
+
description: "Render the legacy RSVP script's local snapshot/report shape for comparison without mutating native state",
|
|
470
|
+
usage: "ouro rsvp legacy-render --legacy-root <path> [--agent <name>] [--output <path>] [--json]",
|
|
471
|
+
example: "ouro rsvp legacy-render --legacy-root ~/Projects/rsvp-tracker --output /tmp/legacy.json",
|
|
472
|
+
},
|
|
473
|
+
"rsvp replay": {
|
|
474
|
+
description: "Replay an offline fixture through deterministic native RSVP report/query logic without live BlueBubbles or AislePlanner access",
|
|
475
|
+
usage: "ouro rsvp replay [--agent <name>] --fixture <path> [--output <path>] [--json]",
|
|
476
|
+
example: "ouro rsvp replay --agent slugger --fixture /tmp/rsvp-replay.json --json",
|
|
477
|
+
},
|
|
478
|
+
"rsvp config import-legacy": {
|
|
479
|
+
description: "Import legacy RSVP coordinates into native config and vault-backed runtime/config; mutates only with --yes",
|
|
480
|
+
usage: "ouro rsvp config import-legacy [--agent <name>] --legacy-root <path> --mode shadow|live [--yes] [--output <path>] [--json]",
|
|
481
|
+
example: "ouro rsvp config import-legacy --agent slugger --legacy-root ~/Projects/rsvp-tracker --mode shadow --yes",
|
|
482
|
+
},
|
|
483
|
+
"rsvp habit stage": {
|
|
484
|
+
description: "Stage the daily RSVP refresh habit with a fixed cron cadence, usually the 10 AM dogfood run",
|
|
485
|
+
usage: "ouro rsvp habit stage [--agent <name>] --mode shadow|live --cadence '<cron>' [--output <path>] [--json]",
|
|
486
|
+
example: "ouro rsvp habit stage --agent slugger --mode shadow --cadence '0 10 * * *'",
|
|
487
|
+
},
|
|
488
|
+
"rsvp import-legacy": {
|
|
489
|
+
description: "Compatibility alias for `ouro rsvp config import-legacy`; mutates only with --yes",
|
|
490
|
+
usage: "ouro rsvp import-legacy [--agent <name>] --legacy-root <path> --mode shadow|live [--yes] [--output <path>] [--json]",
|
|
491
|
+
example: "ouro rsvp import-legacy --agent slugger --legacy-root ~/Projects/rsvp-tracker --mode shadow --yes",
|
|
492
|
+
},
|
|
493
|
+
"rsvp refresh": {
|
|
494
|
+
description: "Run the native RSVP refresh path and write receipts; defaults to dry-run behavior unless --allow-send is explicit",
|
|
495
|
+
usage: "ouro rsvp refresh [--agent <name>] --mode shadow|live [--no-send|--allow-send] [--output <path>] [--json]",
|
|
496
|
+
example: "ouro rsvp refresh --agent slugger --mode shadow --no-send --json",
|
|
497
|
+
},
|
|
498
|
+
"rsvp compare": {
|
|
499
|
+
description: "Compare native and legacy RSVP render outputs for migration verification",
|
|
500
|
+
usage: "ouro rsvp compare [--agent <name>] --native <path> --legacy <path> [--output <path>] [--json]",
|
|
501
|
+
example: "ouro rsvp compare --agent slugger --native /tmp/native.json --legacy /tmp/legacy.json",
|
|
502
|
+
},
|
|
503
|
+
"rsvp smoke": {
|
|
504
|
+
description: "Smoke-test RSVP follow-up behavior through a target sense; preflight is no-send and live mode requires --allow-send",
|
|
505
|
+
usage: "ouro rsvp smoke [--agent <name>] --mode preflight|live --surface bluebubbles [--question <text>] [--allow-send] [--output <path>] [--replay-output <path>] [--json]",
|
|
506
|
+
example: "ouro rsvp smoke --agent slugger --mode preflight --surface bluebubbles --question 'who is pending?'",
|
|
507
|
+
},
|
|
434
508
|
"mail import-mbox": {
|
|
435
509
|
description: "Import a HEY or other MBOX export into an existing delegated Mailroom source grant",
|
|
436
510
|
usage: "ouro mail import-mbox (--file <path>|--discover) [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]",
|
|
@@ -114,6 +114,7 @@ function usage() {
|
|
|
114
114
|
" ouro habit summary [--agent <name>] (--run-id <id>|--habit <name>|--operation-id <id>) [--which latest|previous|latest-success|latest-failure] [--json]",
|
|
115
115
|
" ouro link <agent> --friend <id> --provider <provider> --external-id <external-id>",
|
|
116
116
|
" ouro bluebubbles replay [--agent <name>] --message-guid <guid> [--event-type new-message|updated-message] [--json]",
|
|
117
|
+
" ouro rsvp <doctor|incident|cutover|legacy-render|replay|config|habit|import-legacy|refresh|compare|smoke> ...",
|
|
117
118
|
" ouro friend list [--agent <name>]",
|
|
118
119
|
" ouro friend show <id> [--agent <name>]",
|
|
119
120
|
" ouro friend create --name <name> [--trust <level>] [--agent <name>]",
|
|
@@ -1681,6 +1682,469 @@ function parseBlueBubblesCommand(args) {
|
|
|
1681
1682
|
...(json ? { json: true } : {}),
|
|
1682
1683
|
};
|
|
1683
1684
|
}
|
|
1685
|
+
const RSVP_USAGE = "Usage: ouro rsvp <doctor|incident|cutover|legacy-render|replay|config|habit|import-legacy|refresh|compare|smoke> ...";
|
|
1686
|
+
function isRsvpMode(value) {
|
|
1687
|
+
return value === "shadow" || value === "live";
|
|
1688
|
+
}
|
|
1689
|
+
function isRsvpCutoverAction(value) {
|
|
1690
|
+
return value === "check" || value === "quarantine-launchd" || value === "retire-legacy-send-config";
|
|
1691
|
+
}
|
|
1692
|
+
function isRsvpSmokeMode(value) {
|
|
1693
|
+
return value === "preflight" || value === "live";
|
|
1694
|
+
}
|
|
1695
|
+
function isRsvpSmokeSurface(value) {
|
|
1696
|
+
return value === "bluebubbles";
|
|
1697
|
+
}
|
|
1698
|
+
function rsvpPath(value, label) {
|
|
1699
|
+
const trimmed = value.trim();
|
|
1700
|
+
if (!trimmed || /[\r\n\t]/.test(trimmed))
|
|
1701
|
+
throw new Error(`rsvp ${label} requires a non-empty path`);
|
|
1702
|
+
return trimmed;
|
|
1703
|
+
}
|
|
1704
|
+
function validRsvpCronCadence(value) {
|
|
1705
|
+
const fields = value.trim().split(/\s+/);
|
|
1706
|
+
return fields.length === 5 && fields.every((field) => field.length > 0);
|
|
1707
|
+
}
|
|
1708
|
+
function parseRsvpCommand(args) {
|
|
1709
|
+
const subcommand = args[0];
|
|
1710
|
+
if (!subcommand)
|
|
1711
|
+
throw new Error(RSVP_USAGE);
|
|
1712
|
+
if (subcommand === "config") {
|
|
1713
|
+
const nested = args[1];
|
|
1714
|
+
if (nested !== "import-legacy")
|
|
1715
|
+
throw new Error("Usage: ouro rsvp config import-legacy [--agent <name>] --legacy-root <path> --mode shadow|live [--yes] [--output <path>] [--json]");
|
|
1716
|
+
return parseRsvpImportLegacyCommand(args.slice(2), "rsvp.config.import-legacy");
|
|
1717
|
+
}
|
|
1718
|
+
if (subcommand === "habit") {
|
|
1719
|
+
const nested = args[1];
|
|
1720
|
+
if (nested !== "stage")
|
|
1721
|
+
throw new Error("Usage: ouro rsvp habit stage [--agent <name>] --mode shadow|live --cadence '<cron>' [--output <path>] [--json]");
|
|
1722
|
+
return parseRsvpHabitStageCommand(args.slice(2));
|
|
1723
|
+
}
|
|
1724
|
+
if (subcommand === "doctor")
|
|
1725
|
+
return parseRsvpDoctorCommand(args.slice(1));
|
|
1726
|
+
if (subcommand === "incident")
|
|
1727
|
+
return parseRsvpIncidentCommand(args.slice(1));
|
|
1728
|
+
if (subcommand === "cutover")
|
|
1729
|
+
return parseRsvpCutoverCommand(args.slice(1));
|
|
1730
|
+
if (subcommand === "legacy-render")
|
|
1731
|
+
return parseRsvpLegacyRenderCommand(args.slice(1));
|
|
1732
|
+
if (subcommand === "replay")
|
|
1733
|
+
return parseRsvpReplayCommand(args.slice(1));
|
|
1734
|
+
if (subcommand === "import-legacy")
|
|
1735
|
+
return parseRsvpImportLegacyCommand(args.slice(1), "rsvp.import-legacy");
|
|
1736
|
+
if (subcommand === "refresh")
|
|
1737
|
+
return parseRsvpRefreshCommand(args.slice(1));
|
|
1738
|
+
if (subcommand === "compare")
|
|
1739
|
+
return parseRsvpCompareCommand(args.slice(1));
|
|
1740
|
+
if (subcommand === "smoke")
|
|
1741
|
+
return parseRsvpSmokeCommand(args.slice(1));
|
|
1742
|
+
throw new Error(RSVP_USAGE);
|
|
1743
|
+
}
|
|
1744
|
+
function parseRsvpDoctorCommand(args) {
|
|
1745
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
1746
|
+
let json = false;
|
|
1747
|
+
let strict = false;
|
|
1748
|
+
let outputPath;
|
|
1749
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
1750
|
+
const token = rest[i];
|
|
1751
|
+
if (token === "--json") {
|
|
1752
|
+
json = true;
|
|
1753
|
+
continue;
|
|
1754
|
+
}
|
|
1755
|
+
if (token === "--strict") {
|
|
1756
|
+
strict = true;
|
|
1757
|
+
continue;
|
|
1758
|
+
}
|
|
1759
|
+
if (token === "--output" && rest[i + 1]) {
|
|
1760
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
1761
|
+
continue;
|
|
1762
|
+
}
|
|
1763
|
+
throw new Error("Usage: ouro rsvp doctor [--agent <name>] [--strict] [--output <path>] [--json]");
|
|
1764
|
+
}
|
|
1765
|
+
return {
|
|
1766
|
+
kind: "rsvp.doctor",
|
|
1767
|
+
...(agent ? { agent } : {}),
|
|
1768
|
+
...(json ? { json: true } : {}),
|
|
1769
|
+
...(strict ? { strict: true } : {}),
|
|
1770
|
+
...(outputPath ? { outputPath } : {}),
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
function parseRsvpIncidentCommand(args) {
|
|
1774
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
1775
|
+
let json = false;
|
|
1776
|
+
let outputPath;
|
|
1777
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
1778
|
+
const token = rest[i];
|
|
1779
|
+
if (token === "--json") {
|
|
1780
|
+
json = true;
|
|
1781
|
+
continue;
|
|
1782
|
+
}
|
|
1783
|
+
if (token === "--output" && rest[i + 1]) {
|
|
1784
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
1785
|
+
continue;
|
|
1786
|
+
}
|
|
1787
|
+
throw new Error("Usage: ouro rsvp incident [--agent <name>] [--output <path>] [--json]");
|
|
1788
|
+
}
|
|
1789
|
+
return {
|
|
1790
|
+
kind: "rsvp.incident",
|
|
1791
|
+
...(agent ? { agent } : {}),
|
|
1792
|
+
...(json ? { json: true } : {}),
|
|
1793
|
+
...(outputPath ? { outputPath } : {}),
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
function parseRsvpCutoverCommand(args) {
|
|
1797
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
1798
|
+
let legacyRoot;
|
|
1799
|
+
let action;
|
|
1800
|
+
let yes = false;
|
|
1801
|
+
let json = false;
|
|
1802
|
+
let outputPath;
|
|
1803
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
1804
|
+
const token = rest[i];
|
|
1805
|
+
if (token === "--legacy-root" && rest[i + 1]) {
|
|
1806
|
+
legacyRoot = rsvpPath(rest[++i], "--legacy-root");
|
|
1807
|
+
continue;
|
|
1808
|
+
}
|
|
1809
|
+
if (token === "--action" && rest[i + 1]) {
|
|
1810
|
+
const value = rest[++i];
|
|
1811
|
+
if (!isRsvpCutoverAction(value))
|
|
1812
|
+
throw new Error("rsvp cutover --action must be check, quarantine-launchd, or retire-legacy-send-config");
|
|
1813
|
+
action = value;
|
|
1814
|
+
continue;
|
|
1815
|
+
}
|
|
1816
|
+
if (token === "--yes") {
|
|
1817
|
+
yes = true;
|
|
1818
|
+
continue;
|
|
1819
|
+
}
|
|
1820
|
+
if (token === "--json") {
|
|
1821
|
+
json = true;
|
|
1822
|
+
continue;
|
|
1823
|
+
}
|
|
1824
|
+
if (token === "--output" && rest[i + 1]) {
|
|
1825
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
1826
|
+
continue;
|
|
1827
|
+
}
|
|
1828
|
+
throw new Error("Usage: ouro rsvp cutover [--agent <name>] --legacy-root <path> --action check|quarantine-launchd|retire-legacy-send-config [--yes] [--output <path>] [--json]");
|
|
1829
|
+
}
|
|
1830
|
+
if (!legacyRoot)
|
|
1831
|
+
throw new Error("rsvp cutover requires --legacy-root <path>");
|
|
1832
|
+
if (!action)
|
|
1833
|
+
throw new Error("rsvp cutover requires --action check|quarantine-launchd|retire-legacy-send-config");
|
|
1834
|
+
return {
|
|
1835
|
+
kind: "rsvp.cutover",
|
|
1836
|
+
...(agent ? { agent } : {}),
|
|
1837
|
+
legacyRoot,
|
|
1838
|
+
action,
|
|
1839
|
+
...(yes ? { yes: true } : {}),
|
|
1840
|
+
...(json ? { json: true } : {}),
|
|
1841
|
+
...(outputPath ? { outputPath } : {}),
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
function parseRsvpLegacyRenderCommand(args) {
|
|
1845
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
1846
|
+
let legacyRoot;
|
|
1847
|
+
let json = false;
|
|
1848
|
+
let outputPath;
|
|
1849
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
1850
|
+
const token = rest[i];
|
|
1851
|
+
if (token === "--legacy-root" && rest[i + 1]) {
|
|
1852
|
+
legacyRoot = rsvpPath(rest[++i], "--legacy-root");
|
|
1853
|
+
continue;
|
|
1854
|
+
}
|
|
1855
|
+
if (token === "--json") {
|
|
1856
|
+
json = true;
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1859
|
+
if (token === "--output" && rest[i + 1]) {
|
|
1860
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
1861
|
+
continue;
|
|
1862
|
+
}
|
|
1863
|
+
throw new Error("Usage: ouro rsvp legacy-render --legacy-root <path> [--agent <name>] [--output <path>] [--json]");
|
|
1864
|
+
}
|
|
1865
|
+
if (!legacyRoot)
|
|
1866
|
+
throw new Error("rsvp legacy-render requires --legacy-root <path>");
|
|
1867
|
+
return {
|
|
1868
|
+
kind: "rsvp.legacy-render",
|
|
1869
|
+
...(agent ? { agent } : {}),
|
|
1870
|
+
legacyRoot,
|
|
1871
|
+
...(json ? { json: true } : {}),
|
|
1872
|
+
...(outputPath ? { outputPath } : {}),
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1875
|
+
function parseRsvpReplayCommand(args) {
|
|
1876
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
1877
|
+
let fixturePath;
|
|
1878
|
+
let json = false;
|
|
1879
|
+
let outputPath;
|
|
1880
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
1881
|
+
const token = rest[i];
|
|
1882
|
+
if (token === "--fixture" && rest[i + 1]) {
|
|
1883
|
+
fixturePath = rsvpPath(rest[++i], "--fixture");
|
|
1884
|
+
continue;
|
|
1885
|
+
}
|
|
1886
|
+
if (token === "--json") {
|
|
1887
|
+
json = true;
|
|
1888
|
+
continue;
|
|
1889
|
+
}
|
|
1890
|
+
if (token === "--output" && rest[i + 1]) {
|
|
1891
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
1892
|
+
continue;
|
|
1893
|
+
}
|
|
1894
|
+
throw new Error("Usage: ouro rsvp replay [--agent <name>] --fixture <path> [--output <path>] [--json]");
|
|
1895
|
+
}
|
|
1896
|
+
if (!fixturePath)
|
|
1897
|
+
throw new Error("rsvp replay requires --fixture <path>");
|
|
1898
|
+
return {
|
|
1899
|
+
kind: "rsvp.replay",
|
|
1900
|
+
...(agent ? { agent } : {}),
|
|
1901
|
+
fixturePath,
|
|
1902
|
+
...(json ? { json: true } : {}),
|
|
1903
|
+
...(outputPath ? { outputPath } : {}),
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
function parseRsvpImportLegacyCommand(args, kind) {
|
|
1907
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
1908
|
+
let legacyRoot;
|
|
1909
|
+
let mode;
|
|
1910
|
+
let yes = false;
|
|
1911
|
+
let json = false;
|
|
1912
|
+
let outputPath;
|
|
1913
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
1914
|
+
const token = rest[i];
|
|
1915
|
+
if (token === "--legacy-root" && rest[i + 1]) {
|
|
1916
|
+
legacyRoot = rsvpPath(rest[++i], "--legacy-root");
|
|
1917
|
+
continue;
|
|
1918
|
+
}
|
|
1919
|
+
if (token === "--mode" && rest[i + 1]) {
|
|
1920
|
+
const value = rest[++i];
|
|
1921
|
+
if (!isRsvpMode(value))
|
|
1922
|
+
throw new Error("rsvp import-legacy --mode must be shadow or live");
|
|
1923
|
+
mode = value;
|
|
1924
|
+
continue;
|
|
1925
|
+
}
|
|
1926
|
+
if (token === "--yes") {
|
|
1927
|
+
yes = true;
|
|
1928
|
+
continue;
|
|
1929
|
+
}
|
|
1930
|
+
if (token === "--json") {
|
|
1931
|
+
json = true;
|
|
1932
|
+
continue;
|
|
1933
|
+
}
|
|
1934
|
+
if (token === "--output" && rest[i + 1]) {
|
|
1935
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
1936
|
+
continue;
|
|
1937
|
+
}
|
|
1938
|
+
throw new Error("Usage: ouro rsvp config import-legacy [--agent <name>] --legacy-root <path> --mode shadow|live [--yes] [--output <path>] [--json]");
|
|
1939
|
+
}
|
|
1940
|
+
if (!legacyRoot)
|
|
1941
|
+
throw new Error("rsvp import-legacy requires --legacy-root <path>");
|
|
1942
|
+
if (!mode)
|
|
1943
|
+
throw new Error("rsvp import-legacy requires --mode shadow|live");
|
|
1944
|
+
return {
|
|
1945
|
+
kind,
|
|
1946
|
+
...(agent ? { agent } : {}),
|
|
1947
|
+
legacyRoot,
|
|
1948
|
+
mode,
|
|
1949
|
+
...(yes ? { yes: true } : {}),
|
|
1950
|
+
...(json ? { json: true } : {}),
|
|
1951
|
+
...(outputPath ? { outputPath } : {}),
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
function parseRsvpHabitStageCommand(args) {
|
|
1955
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
1956
|
+
let mode;
|
|
1957
|
+
let cadence;
|
|
1958
|
+
let json = false;
|
|
1959
|
+
let outputPath;
|
|
1960
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
1961
|
+
const token = rest[i];
|
|
1962
|
+
if (token === "--mode" && rest[i + 1]) {
|
|
1963
|
+
const value = rest[++i];
|
|
1964
|
+
if (!isRsvpMode(value))
|
|
1965
|
+
throw new Error("rsvp habit stage --mode must be shadow or live");
|
|
1966
|
+
mode = value;
|
|
1967
|
+
continue;
|
|
1968
|
+
}
|
|
1969
|
+
if (token === "--cadence" && rest[i + 1]) {
|
|
1970
|
+
cadence = rest[++i];
|
|
1971
|
+
continue;
|
|
1972
|
+
}
|
|
1973
|
+
if (token === "--json") {
|
|
1974
|
+
json = true;
|
|
1975
|
+
continue;
|
|
1976
|
+
}
|
|
1977
|
+
if (token === "--output" && rest[i + 1]) {
|
|
1978
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
1979
|
+
continue;
|
|
1980
|
+
}
|
|
1981
|
+
throw new Error("Usage: ouro rsvp habit stage [--agent <name>] --mode shadow|live --cadence '<cron>' [--output <path>] [--json]");
|
|
1982
|
+
}
|
|
1983
|
+
if (!mode)
|
|
1984
|
+
throw new Error("rsvp habit stage requires --mode shadow|live");
|
|
1985
|
+
if (!cadence || !validRsvpCronCadence(cadence))
|
|
1986
|
+
throw new Error("rsvp habit stage --cadence must be a five-field cron cadence");
|
|
1987
|
+
return {
|
|
1988
|
+
kind: "rsvp.habit.stage",
|
|
1989
|
+
...(agent ? { agent } : {}),
|
|
1990
|
+
mode,
|
|
1991
|
+
cadence,
|
|
1992
|
+
...(json ? { json: true } : {}),
|
|
1993
|
+
...(outputPath ? { outputPath } : {}),
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
function parseRsvpRefreshCommand(args) {
|
|
1997
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
1998
|
+
let mode = "shadow";
|
|
1999
|
+
let noSend = false;
|
|
2000
|
+
let allowSend = false;
|
|
2001
|
+
let json = false;
|
|
2002
|
+
let outputPath;
|
|
2003
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
2004
|
+
const token = rest[i];
|
|
2005
|
+
if (token === "--mode" && rest[i + 1]) {
|
|
2006
|
+
const value = rest[++i];
|
|
2007
|
+
if (!isRsvpMode(value))
|
|
2008
|
+
throw new Error("rsvp refresh --mode must be shadow or live");
|
|
2009
|
+
mode = value;
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
if (token === "--no-send") {
|
|
2013
|
+
noSend = true;
|
|
2014
|
+
continue;
|
|
2015
|
+
}
|
|
2016
|
+
if (token === "--allow-send") {
|
|
2017
|
+
allowSend = true;
|
|
2018
|
+
continue;
|
|
2019
|
+
}
|
|
2020
|
+
if (token === "--json") {
|
|
2021
|
+
json = true;
|
|
2022
|
+
continue;
|
|
2023
|
+
}
|
|
2024
|
+
if (token === "--output" && rest[i + 1]) {
|
|
2025
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
2026
|
+
continue;
|
|
2027
|
+
}
|
|
2028
|
+
throw new Error("Usage: ouro rsvp refresh [--agent <name>] --mode shadow|live [--no-send|--allow-send] [--output <path>] [--json]");
|
|
2029
|
+
}
|
|
2030
|
+
if (noSend && allowSend)
|
|
2031
|
+
throw new Error("rsvp refresh cannot combine --allow-send and --no-send");
|
|
2032
|
+
if (mode === "shadow" && allowSend)
|
|
2033
|
+
throw new Error("rsvp refresh --mode shadow cannot use --allow-send; use --no-send or omit send flags");
|
|
2034
|
+
if (mode === "live" && !allowSend)
|
|
2035
|
+
throw new Error("rsvp refresh --mode live requires --allow-send, or use --no-send for a dry run");
|
|
2036
|
+
return {
|
|
2037
|
+
kind: "rsvp.refresh",
|
|
2038
|
+
...(agent ? { agent } : {}),
|
|
2039
|
+
mode,
|
|
2040
|
+
...(noSend ? { noSend: true } : {}),
|
|
2041
|
+
...(allowSend ? { allowSend: true } : {}),
|
|
2042
|
+
...(json ? { json: true } : {}),
|
|
2043
|
+
...(outputPath ? { outputPath } : {}),
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
function parseRsvpCompareCommand(args) {
|
|
2047
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
2048
|
+
let nativePath;
|
|
2049
|
+
let legacyPath;
|
|
2050
|
+
let json = false;
|
|
2051
|
+
let outputPath;
|
|
2052
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
2053
|
+
const token = rest[i];
|
|
2054
|
+
if (token === "--native" && rest[i + 1]) {
|
|
2055
|
+
nativePath = rsvpPath(rest[++i], "--native");
|
|
2056
|
+
continue;
|
|
2057
|
+
}
|
|
2058
|
+
if (token === "--legacy" && rest[i + 1]) {
|
|
2059
|
+
legacyPath = rsvpPath(rest[++i], "--legacy");
|
|
2060
|
+
continue;
|
|
2061
|
+
}
|
|
2062
|
+
if (token === "--json") {
|
|
2063
|
+
json = true;
|
|
2064
|
+
continue;
|
|
2065
|
+
}
|
|
2066
|
+
if (token === "--output" && rest[i + 1]) {
|
|
2067
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
2068
|
+
continue;
|
|
2069
|
+
}
|
|
2070
|
+
throw new Error("Usage: ouro rsvp compare [--agent <name>] --native <path> --legacy <path> [--output <path>] [--json]");
|
|
2071
|
+
}
|
|
2072
|
+
if (!nativePath)
|
|
2073
|
+
throw new Error("rsvp compare requires --native <path>");
|
|
2074
|
+
if (!legacyPath)
|
|
2075
|
+
throw new Error("rsvp compare requires --legacy <path>");
|
|
2076
|
+
return {
|
|
2077
|
+
kind: "rsvp.compare",
|
|
2078
|
+
...(agent ? { agent } : {}),
|
|
2079
|
+
nativePath,
|
|
2080
|
+
legacyPath,
|
|
2081
|
+
...(json ? { json: true } : {}),
|
|
2082
|
+
...(outputPath ? { outputPath } : {}),
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
function parseRsvpSmokeCommand(args) {
|
|
2086
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
2087
|
+
let mode = "preflight";
|
|
2088
|
+
let surface;
|
|
2089
|
+
let question;
|
|
2090
|
+
let allowSend = false;
|
|
2091
|
+
let json = false;
|
|
2092
|
+
let outputPath;
|
|
2093
|
+
let replayOutputPath;
|
|
2094
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
2095
|
+
const token = rest[i];
|
|
2096
|
+
if (token === "--mode" && rest[i + 1]) {
|
|
2097
|
+
const value = rest[++i];
|
|
2098
|
+
if (!isRsvpSmokeMode(value))
|
|
2099
|
+
throw new Error("rsvp smoke --mode must be preflight or live");
|
|
2100
|
+
mode = value;
|
|
2101
|
+
continue;
|
|
2102
|
+
}
|
|
2103
|
+
if (token === "--surface" && rest[i + 1]) {
|
|
2104
|
+
const value = rest[++i];
|
|
2105
|
+
if (!isRsvpSmokeSurface(value))
|
|
2106
|
+
throw new Error("rsvp smoke --surface must be bluebubbles");
|
|
2107
|
+
surface = value;
|
|
2108
|
+
continue;
|
|
2109
|
+
}
|
|
2110
|
+
if (token === "--question" && rest[i + 1]) {
|
|
2111
|
+
question = rest[++i];
|
|
2112
|
+
continue;
|
|
2113
|
+
}
|
|
2114
|
+
if (token === "--allow-send") {
|
|
2115
|
+
allowSend = true;
|
|
2116
|
+
continue;
|
|
2117
|
+
}
|
|
2118
|
+
if (token === "--json") {
|
|
2119
|
+
json = true;
|
|
2120
|
+
continue;
|
|
2121
|
+
}
|
|
2122
|
+
if (token === "--output" && rest[i + 1]) {
|
|
2123
|
+
outputPath = rsvpPath(rest[++i], "--output");
|
|
2124
|
+
continue;
|
|
2125
|
+
}
|
|
2126
|
+
if (token === "--replay-output" && rest[i + 1]) {
|
|
2127
|
+
replayOutputPath = rsvpPath(rest[++i], "--replay-output");
|
|
2128
|
+
continue;
|
|
2129
|
+
}
|
|
2130
|
+
throw new Error("Usage: ouro rsvp smoke [--agent <name>] --mode preflight|live --surface bluebubbles [--question <text>] [--allow-send] [--output <path>] [--replay-output <path>] [--json]");
|
|
2131
|
+
}
|
|
2132
|
+
if (!surface)
|
|
2133
|
+
throw new Error("rsvp smoke requires --surface bluebubbles");
|
|
2134
|
+
if (mode === "live" && !allowSend)
|
|
2135
|
+
throw new Error("rsvp smoke --mode live requires --allow-send");
|
|
2136
|
+
return {
|
|
2137
|
+
kind: "rsvp.smoke",
|
|
2138
|
+
...(agent ? { agent } : {}),
|
|
2139
|
+
mode,
|
|
2140
|
+
surface,
|
|
2141
|
+
...(question ? { question } : {}),
|
|
2142
|
+
...(allowSend ? { allowSend: true } : {}),
|
|
2143
|
+
...(json ? { json: true } : {}),
|
|
2144
|
+
...(outputPath ? { outputPath } : {}),
|
|
2145
|
+
...(replayOutputPath ? { replayOutputPath } : {}),
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
1684
2148
|
function parseNervesReviewCommand(args) {
|
|
1685
2149
|
const { agent, rest } = extractAgentFlag(args);
|
|
1686
2150
|
let processName = "daemon";
|
|
@@ -1989,6 +2453,8 @@ function parseOuroCommand(args) {
|
|
|
1989
2453
|
}
|
|
1990
2454
|
if (head === "bluebubbles")
|
|
1991
2455
|
return parseBlueBubblesCommand(args.slice(1));
|
|
2456
|
+
if (head === "rsvp")
|
|
2457
|
+
return parseRsvpCommand(args.slice(1));
|
|
1992
2458
|
const suggestion = (0, cli_help_1.suggestCommand)(head);
|
|
1993
2459
|
const hint = suggestion ? ` Did you mean '${suggestion}'?` : "";
|
|
1994
2460
|
throw new Error(`Unknown command '${args.join(" ")}'.${hint}\n${usage()}`);
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.OuroDaemon = void 0;
|
|
37
|
+
exports.messageFromHabitPokeError = messageFromHabitPokeError;
|
|
37
38
|
exports.parseOrphanPidsFromPs = parseOrphanPidsFromPs;
|
|
38
39
|
exports.filterPidfilePidsToActualOrphans = filterPidfilePidsToActualOrphans;
|
|
39
40
|
exports.mergeUniqueOrphanPids = mergeUniqueOrphanPids;
|
|
@@ -74,6 +75,7 @@ const habit_private_wake_1 = require("./habit-private-wake");
|
|
|
74
75
|
const habit_parser_1 = require("../habits/habit-parser");
|
|
75
76
|
const habit_runtime_state_1 = require("../habits/habit-runtime-state");
|
|
76
77
|
const router_1 = require("../external-events/router");
|
|
78
|
+
const habit_policy_1 = require("../../rsvp/habit-policy");
|
|
77
79
|
const PIDFILE_PATH = path.join(os.homedir(), ".ouro-cli", "daemon.pids");
|
|
78
80
|
/**
|
|
79
81
|
* Defense-in-depth: detect if we're running under vitest. The pidfile lives
|
|
@@ -95,6 +97,12 @@ function isVitestProcess() {
|
|
|
95
97
|
return false;
|
|
96
98
|
return process.argv.some((arg) => typeof arg === "string" && arg.includes("vitest"));
|
|
97
99
|
}
|
|
100
|
+
function messageFromHabitPokeError(error) {
|
|
101
|
+
if (error instanceof Error)
|
|
102
|
+
return error.message;
|
|
103
|
+
/* v8 ignore next -- defensive fallback for hostile/non-Error throws from filesystem or parsers @preserve */
|
|
104
|
+
return String(error);
|
|
105
|
+
}
|
|
98
106
|
/**
|
|
99
107
|
* Scan `ps -eo pid,ppid,command` output for daemon-owned entry points whose
|
|
100
108
|
* parent has died (PPID reparented to init/PID 1). Returns the list of PIDs
|
|
@@ -1180,13 +1188,26 @@ class OuroDaemon {
|
|
|
1180
1188
|
};
|
|
1181
1189
|
}
|
|
1182
1190
|
resolveHabitPokeOccurrenceId(command, trigger) {
|
|
1183
|
-
if (trigger === "poke" || trigger === "manual")
|
|
1184
|
-
return undefined;
|
|
1185
1191
|
const agentRoot = path.join(this.bundlesRoot, `${command.agent}.ouro`);
|
|
1186
1192
|
const habitPath = path.join(agentRoot, "habits", `${command.habitName}.md`);
|
|
1193
|
+
let parsedHabit = null;
|
|
1194
|
+
if ((0, habit_policy_1.isRsvpHabitName)(command.habitName)) {
|
|
1195
|
+
if (!fs.existsSync(habitPath))
|
|
1196
|
+
return { skipReason: "RSVP habit file not found" };
|
|
1197
|
+
try {
|
|
1198
|
+
parsedHabit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(fs.readFileSync(habitPath, "utf-8"), habitPath));
|
|
1199
|
+
}
|
|
1200
|
+
catch (error) {
|
|
1201
|
+
return { skipReason: `RSVP habit metadata invalid: ${messageFromHabitPokeError(error)}` };
|
|
1202
|
+
}
|
|
1203
|
+
if (!parsedHabit.rsvp)
|
|
1204
|
+
return { skipReason: "RSVP habit metadata is required before private runtime wake" };
|
|
1205
|
+
}
|
|
1206
|
+
if (trigger === "poke" || trigger === "manual")
|
|
1207
|
+
return undefined;
|
|
1187
1208
|
if (!fs.existsSync(habitPath))
|
|
1188
1209
|
return { skipReason: "habit file not found" };
|
|
1189
|
-
const habit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(fs.readFileSync(habitPath, "utf-8"), habitPath));
|
|
1210
|
+
const habit = parsedHabit ?? (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(fs.readFileSync(habitPath, "utf-8"), habitPath));
|
|
1190
1211
|
if (habit.cadence === null)
|
|
1191
1212
|
return { skipReason: "habit has no cadence" };
|
|
1192
1213
|
const cadence = habit.cadence;
|