@ouro.bot/cli 0.1.0-alpha.727 → 0.1.0-alpha.729
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 +14 -1
- package/assets/bluebubbles-host +264 -0
- package/changelog.json +16 -0
- package/dist/heart/config.js +1 -2
- package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
- package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
- package/dist/heart/daemon/bluebubbles-host.js +273 -0
- package/dist/heart/daemon/cli-defaults.js +8 -1
- package/dist/heart/daemon/cli-exec.js +239 -34
- package/dist/heart/daemon/cli-help.js +17 -6
- package/dist/heart/daemon/cli-parse.js +69 -1
- package/dist/heart/daemon/cli-render.js +7 -0
- package/dist/heart/daemon/doctor.js +21 -1
- package/dist/heart/daemon/mcp-canary.js +160 -29
- package/dist/heart/daemon/process-manager.js +24 -22
- package/dist/heart/daemon/sense-manager.js +1 -1
- package/dist/heart/daemon/socket-client.js +28 -19
- package/dist/heart/versioning/ouro-path-installer.js +30 -24
- package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
- package/dist/heart/versioning/version-intent.js +114 -0
- package/dist/senses/bluebubbles/index.js +16 -0
- package/dist/senses/bluebubbles/webhook-registration.js +228 -0
- package/package.json +4 -2
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.BLUEBUBBLES_LAUNCH_AGENT_LABEL = exports.BLUEBUBBLES_EXECUTABLE_PATH = exports.BLUEBUBBLES_APP_PATH = void 0;
|
|
40
|
+
exports.blueBubblesLaunchAgentPlist = blueBubblesLaunchAgentPlist;
|
|
41
|
+
exports.blueBubblesLaunchAgentPath = blueBubblesLaunchAgentPath;
|
|
42
|
+
exports.inspectBlueBubblesHost = inspectBlueBubblesHost;
|
|
43
|
+
exports.runBlueBubblesHostAction = runBlueBubblesHostAction;
|
|
44
|
+
exports.createDefaultBlueBubblesHostDeps = createDefaultBlueBubblesHostDeps;
|
|
45
|
+
const child_process_1 = require("child_process");
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const os = __importStar(require("os"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
50
|
+
exports.BLUEBUBBLES_APP_PATH = "/Applications/BlueBubbles.app";
|
|
51
|
+
exports.BLUEBUBBLES_EXECUTABLE_PATH = `${exports.BLUEBUBBLES_APP_PATH}/Contents/MacOS/BlueBubbles`;
|
|
52
|
+
exports.BLUEBUBBLES_LAUNCH_AGENT_LABEL = "com.bluebubbles.server";
|
|
53
|
+
function blueBubblesLaunchAgentPlist(appExecutablePath = exports.BLUEBUBBLES_EXECUTABLE_PATH) {
|
|
54
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
55
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
56
|
+
<plist version="1.0">
|
|
57
|
+
<dict>
|
|
58
|
+
<key>AssociatedBundleIdentifiers</key>
|
|
59
|
+
<array>
|
|
60
|
+
<string>com.BlueBubbles.BlueBubbles-Server</string>
|
|
61
|
+
</array>
|
|
62
|
+
<key>Label</key>
|
|
63
|
+
<string>com.bluebubbles.server</string>
|
|
64
|
+
<key>Program</key>
|
|
65
|
+
<string>${appExecutablePath}</string>
|
|
66
|
+
<key>RunAtLoad</key>
|
|
67
|
+
<true/>
|
|
68
|
+
<key>KeepAlive</key>
|
|
69
|
+
<dict>
|
|
70
|
+
<key>SuccessfulExit</key>
|
|
71
|
+
<false/>
|
|
72
|
+
<key>Crashed</key>
|
|
73
|
+
<true/>
|
|
74
|
+
</dict>
|
|
75
|
+
</dict>
|
|
76
|
+
</plist>`;
|
|
77
|
+
}
|
|
78
|
+
function blueBubblesLaunchAgentPath(homeDir) {
|
|
79
|
+
return path.join(homeDir, "Library", "LaunchAgents", `${exports.BLUEBUBBLES_LAUNCH_AGENT_LABEL}.plist`);
|
|
80
|
+
}
|
|
81
|
+
function requireMacOS(deps) {
|
|
82
|
+
if (deps.platform !== "darwin")
|
|
83
|
+
throw new Error("BlueBubbles host lifecycle requires macOS");
|
|
84
|
+
}
|
|
85
|
+
function launchdDomain(deps) {
|
|
86
|
+
return `gui/${deps.uid}`;
|
|
87
|
+
}
|
|
88
|
+
function serviceTarget(deps) {
|
|
89
|
+
return `${launchdDomain(deps)}/${exports.BLUEBUBBLES_LAUNCH_AGENT_LABEL}`;
|
|
90
|
+
}
|
|
91
|
+
function requireLaunchctl(result, operation) {
|
|
92
|
+
if (!result.ok)
|
|
93
|
+
throw new Error(`launchctl ${operation} failed: ${result.detail}`);
|
|
94
|
+
}
|
|
95
|
+
async function inspectBlueBubblesHost(deps) {
|
|
96
|
+
requireMacOS(deps);
|
|
97
|
+
const plistPath = blueBubblesLaunchAgentPath(deps.homeDir);
|
|
98
|
+
const expectedPlist = blueBubblesLaunchAgentPlist();
|
|
99
|
+
let plist = "missing";
|
|
100
|
+
if (deps.existsSync(plistPath)) {
|
|
101
|
+
try {
|
|
102
|
+
plist = deps.readFileSync(plistPath) === expectedPlist ? "current" : "drifted";
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
plist = "drifted";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const launchd = deps.launchctl(["print", serviceTarget(deps)]);
|
|
109
|
+
const http = deps.probeHttp
|
|
110
|
+
? await deps.probeHttp()
|
|
111
|
+
: { ok: null, detail: "HTTP health was not configured for this host inspection" };
|
|
112
|
+
const state = {
|
|
113
|
+
app: deps.existsSync(exports.BLUEBUBBLES_APP_PATH) ? "present" : "missing",
|
|
114
|
+
plist,
|
|
115
|
+
service: launchd.ok ? "loaded" : "not-loaded",
|
|
116
|
+
serviceDetail: launchd.detail,
|
|
117
|
+
process: deps.isProcessRunning() ? "running" : "not-running",
|
|
118
|
+
http,
|
|
119
|
+
plistPath,
|
|
120
|
+
launchdDomain: launchdDomain(deps),
|
|
121
|
+
launchAgentLabel: exports.BLUEBUBBLES_LAUNCH_AGENT_LABEL,
|
|
122
|
+
};
|
|
123
|
+
(0, runtime_1.emitNervesEvent)({
|
|
124
|
+
component: "daemon",
|
|
125
|
+
event: "daemon.bluebubbles_host_inspected",
|
|
126
|
+
message: "inspected native BlueBubbles host lifecycle",
|
|
127
|
+
meta: {
|
|
128
|
+
app: state.app,
|
|
129
|
+
plist: state.plist,
|
|
130
|
+
service: state.service,
|
|
131
|
+
process: state.process,
|
|
132
|
+
httpOk: state.http.ok,
|
|
133
|
+
launchdDomain: state.launchdDomain,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
return state;
|
|
137
|
+
}
|
|
138
|
+
function writeNativePlist(deps, plistPath) {
|
|
139
|
+
deps.mkdirSync(path.dirname(plistPath), { recursive: true });
|
|
140
|
+
deps.writeFileSync(plistPath, blueBubblesLaunchAgentPlist(), { mode: 0o644 });
|
|
141
|
+
}
|
|
142
|
+
function reloadNativeService(deps, plistPath, wasLoaded) {
|
|
143
|
+
const target = serviceTarget(deps);
|
|
144
|
+
const domain = launchdDomain(deps);
|
|
145
|
+
if (wasLoaded)
|
|
146
|
+
requireLaunchctl(deps.launchctl(["bootout", target]), "bootout");
|
|
147
|
+
requireLaunchctl(deps.launchctl(["disable", target]), "disable");
|
|
148
|
+
requireLaunchctl(deps.launchctl(["enable", target]), "enable");
|
|
149
|
+
requireLaunchctl(deps.launchctl(["bootstrap", domain, plistPath]), "bootstrap");
|
|
150
|
+
}
|
|
151
|
+
async function runBlueBubblesHostAction(action, deps) {
|
|
152
|
+
requireMacOS(deps);
|
|
153
|
+
(0, runtime_1.emitNervesEvent)({
|
|
154
|
+
component: "daemon",
|
|
155
|
+
event: "daemon.bluebubbles_host_action_start",
|
|
156
|
+
message: "starting native BlueBubbles host lifecycle action",
|
|
157
|
+
meta: { action, uid: deps.uid },
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
const before = await inspectBlueBubblesHost(deps);
|
|
161
|
+
let changed = false;
|
|
162
|
+
if (action === "status") {
|
|
163
|
+
(0, runtime_1.emitNervesEvent)({
|
|
164
|
+
component: "daemon",
|
|
165
|
+
event: "daemon.bluebubbles_host_action_end",
|
|
166
|
+
message: "completed native BlueBubbles host lifecycle action",
|
|
167
|
+
meta: { action, changed: false, service: before.service },
|
|
168
|
+
});
|
|
169
|
+
return { action, changed: false, state: before };
|
|
170
|
+
}
|
|
171
|
+
if (action === "remove") {
|
|
172
|
+
if (before.service === "loaded") {
|
|
173
|
+
requireLaunchctl(deps.launchctl(["disable", serviceTarget(deps)]), "disable");
|
|
174
|
+
requireLaunchctl(deps.launchctl(["bootout", serviceTarget(deps)]), "bootout");
|
|
175
|
+
changed = true;
|
|
176
|
+
}
|
|
177
|
+
if (before.plist !== "missing") {
|
|
178
|
+
deps.unlinkSync(before.plistPath);
|
|
179
|
+
changed = true;
|
|
180
|
+
}
|
|
181
|
+
const state = changed ? await inspectBlueBubblesHost(deps) : before;
|
|
182
|
+
(0, runtime_1.emitNervesEvent)({
|
|
183
|
+
component: "daemon",
|
|
184
|
+
event: "daemon.bluebubbles_host_action_end",
|
|
185
|
+
message: "completed native BlueBubbles host lifecycle action",
|
|
186
|
+
meta: { action, changed, service: state.service },
|
|
187
|
+
});
|
|
188
|
+
return { action, changed, state };
|
|
189
|
+
}
|
|
190
|
+
if (before.app === "missing") {
|
|
191
|
+
throw new Error(`BlueBubbles app is missing at ${exports.BLUEBUBBLES_APP_PATH}`);
|
|
192
|
+
}
|
|
193
|
+
const needsPlist = before.plist !== "current";
|
|
194
|
+
if (needsPlist) {
|
|
195
|
+
writeNativePlist(deps, before.plistPath);
|
|
196
|
+
changed = true;
|
|
197
|
+
}
|
|
198
|
+
if (needsPlist || before.service !== "loaded") {
|
|
199
|
+
reloadNativeService(deps, before.plistPath, before.service === "loaded");
|
|
200
|
+
changed = true;
|
|
201
|
+
}
|
|
202
|
+
const state = changed ? await inspectBlueBubblesHost(deps) : before;
|
|
203
|
+
if (state.plist !== "current" || state.service !== "loaded") {
|
|
204
|
+
throw new Error(`BlueBubbles host postcondition failed: plist=${state.plist}, service=${state.service}`);
|
|
205
|
+
}
|
|
206
|
+
(0, runtime_1.emitNervesEvent)({
|
|
207
|
+
component: "daemon",
|
|
208
|
+
event: "daemon.bluebubbles_host_action_end",
|
|
209
|
+
message: "completed native BlueBubbles host lifecycle action",
|
|
210
|
+
meta: { action, changed, service: state.service },
|
|
211
|
+
});
|
|
212
|
+
return { action, changed, state };
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
(0, runtime_1.emitNervesEvent)({
|
|
216
|
+
component: "daemon",
|
|
217
|
+
event: "daemon.bluebubbles_host_action_error",
|
|
218
|
+
level: "error",
|
|
219
|
+
message: "native BlueBubbles host lifecycle action failed",
|
|
220
|
+
meta: { action, uid: deps.uid, error: error instanceof Error ? error.message : String(error) },
|
|
221
|
+
});
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function createDefaultBlueBubblesHostDeps(input = {}) {
|
|
226
|
+
const serverUrl = input.serverUrl ?? "http://127.0.0.1:1234/";
|
|
227
|
+
const requestTimeoutMs = input.requestTimeoutMs ?? 30_000;
|
|
228
|
+
/* v8 ignore next -- production uses global fetch; unit tests inject the adapter @preserve */
|
|
229
|
+
const fetchImpl = input.fetchImpl ?? fetch;
|
|
230
|
+
const probeHttp = input.probeHttp ?? (async () => {
|
|
231
|
+
try {
|
|
232
|
+
const response = await fetchImpl(serverUrl, {
|
|
233
|
+
method: "GET",
|
|
234
|
+
signal: AbortSignal.timeout(requestTimeoutMs),
|
|
235
|
+
});
|
|
236
|
+
return { ok: true, detail: `HTTP server responded with ${response.status}` };
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
return { ok: false, detail: error instanceof Error ? error.message : String(error) };
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
return {
|
|
243
|
+
platform: process.platform,
|
|
244
|
+
homeDir: os.homedir(),
|
|
245
|
+
uid: process.getuid?.() ?? 0,
|
|
246
|
+
existsSync: fs.existsSync,
|
|
247
|
+
readFileSync: (filePath) => fs.readFileSync(filePath, "utf8"),
|
|
248
|
+
mkdirSync: fs.mkdirSync,
|
|
249
|
+
writeFileSync: (filePath, content, options) => fs.writeFileSync(filePath, content, options),
|
|
250
|
+
unlinkSync: fs.unlinkSync,
|
|
251
|
+
launchctl: (args) => {
|
|
252
|
+
try {
|
|
253
|
+
const stdout = (0, child_process_1.execFileSync)("launchctl", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
254
|
+
return { ok: true, detail: stdout.trim() || "ok" };
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
258
|
+
return { ok: false, detail };
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
isProcessRunning: () => {
|
|
262
|
+
try {
|
|
263
|
+
(0, child_process_1.execFileSync)("pgrep", ["-f", exports.BLUEBUBBLES_EXECUTABLE_PATH], { stdio: "ignore" });
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
probeHttp,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
__exportStar(require("./bluebubbles-host-protocol"), exports);
|
|
@@ -65,6 +65,7 @@ const runtime_mode_1 = require("./runtime-mode");
|
|
|
65
65
|
const agent_discovery_1 = require("./agent-discovery");
|
|
66
66
|
const bundle_manifest_1 = require("../../mind/bundle-manifest");
|
|
67
67
|
const ouro_bot_global_installer_1 = require("../versioning/ouro-bot-global-installer");
|
|
68
|
+
const version_intent_1 = require("../versioning/version-intent");
|
|
68
69
|
const logs_prune_1 = require("./logs-prune");
|
|
69
70
|
const daemon_health_1 = require("./daemon-health");
|
|
70
71
|
const log_tailer_1 = require("./log-tailer");
|
|
@@ -702,7 +703,11 @@ async function defaultRunSerpentGuide() {
|
|
|
702
703
|
function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SOCKET_PATH) {
|
|
703
704
|
return {
|
|
704
705
|
socketPath,
|
|
705
|
-
sendCommand: socket_client_1.sendDaemonCommand,
|
|
706
|
+
sendCommand: (commandSocketPath, command) => (0, socket_client_1.sendDaemonCommand)(commandSocketPath, command, {
|
|
707
|
+
timeoutMs: command.kind === "daemon.status"
|
|
708
|
+
? socket_client_1.DEFAULT_DAEMON_STATUS_TIMEOUT_MS
|
|
709
|
+
: socket_client_1.DEFAULT_DAEMON_COMMAND_TIMEOUT_MS,
|
|
710
|
+
}),
|
|
706
711
|
startDaemonProcess: defaultStartDaemonProcess,
|
|
707
712
|
writeStdout: defaultWriteStdout,
|
|
708
713
|
setExitCode: (code) => {
|
|
@@ -766,6 +771,8 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
|
|
|
766
771
|
distTag: update_checker_1.CLI_UPDATE_DIST_TAG,
|
|
767
772
|
});
|
|
768
773
|
},
|
|
774
|
+
readVersionIntent: () => (0, version_intent_1.readVersionIntent)(),
|
|
775
|
+
writeVersionIntent: (intent) => (0, version_intent_1.writeVersionIntent)(intent),
|
|
769
776
|
installCliVersion: async (version) => { (0, ouro_version_manager_1.installVersion)(version, {}); },
|
|
770
777
|
validateCliVersionForActivation: (version) => (0, ouro_version_manager_1.validateInstalledVersionForActivation)(version, {}),
|
|
771
778
|
activateCliVersion: (version) => {
|