@jungjaehoon/mama-os 0.77.0 → 0.79.0
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.md +446 -0
- package/README.md +59 -30
- package/db/migrations/002-model-runs-parent-index.sql +11 -0
- package/db/migrations/003-upkeep-settled.sql +15 -0
- package/dist/api/google-read-actions.d.ts +30 -0
- package/dist/api/google-read-actions.d.ts.map +1 -0
- package/dist/api/google-read-actions.js +256 -0
- package/dist/api/google-read-actions.js.map +1 -0
- package/dist/api/record-actions.d.ts.map +1 -1
- package/dist/api/record-actions.js +23 -5
- package/dist/api/record-actions.js.map +1 -1
- package/dist/api/report-handler.d.ts +0 -6
- package/dist/api/report-handler.d.ts.map +1 -1
- package/dist/api/report-handler.js +0 -54
- package/dist/api/report-handler.js.map +1 -1
- package/dist/api/security-events.d.ts +1 -1
- package/dist/api/security-events.d.ts.map +1 -1
- package/dist/api/security-events.js +10 -1
- package/dist/api/security-events.js.map +1 -1
- package/dist/api/source-actions.d.ts +9 -0
- package/dist/api/source-actions.d.ts.map +1 -1
- package/dist/api/source-actions.js +49 -0
- package/dist/api/source-actions.js.map +1 -1
- package/dist/api/viewer-request-security.d.ts +14 -1
- package/dist/api/viewer-request-security.d.ts.map +1 -1
- package/dist/api/viewer-request-security.js +26 -3
- package/dist/api/viewer-request-security.js.map +1 -1
- package/dist/api/viewer-server.d.ts +8 -0
- package/dist/api/viewer-server.d.ts.map +1 -1
- package/dist/api/viewer-server.js +66 -0
- package/dist/api/viewer-server.js.map +1 -1
- package/dist/api/work-actions.d.ts +19 -2
- package/dist/api/work-actions.d.ts.map +1 -1
- package/dist/api/work-actions.js +42 -2
- package/dist/api/work-actions.js.map +1 -1
- package/dist/cli/commands/backfill.d.ts.map +1 -1
- package/dist/cli/commands/backfill.js +1 -0
- package/dist/cli/commands/backfill.js.map +1 -1
- package/dist/cli/commands/backup.d.ts +14 -0
- package/dist/cli/commands/backup.d.ts.map +1 -0
- package/dist/cli/commands/backup.js +174 -0
- package/dist/cli/commands/backup.js.map +1 -0
- package/dist/cli/commands/control.d.ts +44 -0
- package/dist/cli/commands/control.d.ts.map +1 -0
- package/dist/cli/commands/control.js +354 -0
- package/dist/cli/commands/control.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +60 -3
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/daemon.js +454 -78
- package/dist/cli/commands/daemon.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +13 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +216 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init-questions.d.ts +98 -0
- package/dist/cli/commands/init-questions.d.ts.map +1 -0
- package/dist/cli/commands/init-questions.js +420 -0
- package/dist/cli/commands/init-questions.js.map +1 -0
- package/dist/cli/commands/init-section.d.ts +13 -0
- package/dist/cli/commands/init-section.d.ts.map +1 -0
- package/dist/cli/commands/init-section.js +375 -0
- package/dist/cli/commands/init-section.js.map +1 -0
- package/dist/cli/commands/init.d.ts +56 -2
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +562 -350
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/logs.d.ts +9 -0
- package/dist/cli/commands/logs.d.ts.map +1 -0
- package/dist/cli/commands/logs.js +109 -0
- package/dist/cli/commands/logs.js.map +1 -0
- package/dist/cli/commands/node-move.d.ts +20 -0
- package/dist/cli/commands/node-move.d.ts.map +1 -0
- package/dist/cli/commands/node-move.js +289 -0
- package/dist/cli/commands/node-move.js.map +1 -0
- package/dist/cli/commands/register-owner.d.ts +3 -0
- package/dist/cli/commands/register-owner.d.ts.map +1 -1
- package/dist/cli/commands/register-owner.js +14 -0
- package/dist/cli/commands/register-owner.js.map +1 -1
- package/dist/cli/commands/restore.d.ts +16 -0
- package/dist/cli/commands/restore.d.ts.map +1 -0
- package/dist/cli/commands/restore.js +137 -0
- package/dist/cli/commands/restore.js.map +1 -0
- package/dist/cli/commands/service.d.ts +44 -0
- package/dist/cli/commands/service.d.ts.map +1 -0
- package/dist/cli/commands/service.js +306 -0
- package/dist/cli/commands/service.js.map +1 -0
- package/dist/cli/commands/tools.d.ts +1 -1
- package/dist/cli/commands/tools.d.ts.map +1 -1
- package/dist/cli/commands/tools.js +8 -3
- package/dist/cli/commands/tools.js.map +1 -1
- package/dist/cli/commands/uninstall.d.ts +7 -0
- package/dist/cli/commands/uninstall.d.ts.map +1 -0
- package/dist/cli/commands/uninstall.js +335 -0
- package/dist/cli/commands/uninstall.js.map +1 -0
- package/dist/cli/commands/update.d.ts +59 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +948 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/index.js +74 -23
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/launch-files.d.ts +119 -0
- package/dist/cli/launch-files.d.ts.map +1 -1
- package/dist/cli/launch-files.js +324 -15
- package/dist/cli/launch-files.js.map +1 -1
- package/dist/cli/prompt.d.ts +2 -1
- package/dist/cli/prompt.d.ts.map +1 -1
- package/dist/cli/prompt.js +5 -2
- package/dist/cli/prompt.js.map +1 -1
- package/dist/cli/runtime/backend-probe.d.ts +34 -0
- package/dist/cli/runtime/backend-probe.d.ts.map +1 -0
- package/dist/cli/runtime/backend-probe.js +83 -0
- package/dist/cli/runtime/backend-probe.js.map +1 -0
- package/dist/cli/runtime/backup.d.ts +130 -0
- package/dist/cli/runtime/backup.d.ts.map +1 -0
- package/dist/cli/runtime/backup.js +592 -0
- package/dist/cli/runtime/backup.js.map +1 -0
- package/dist/cli/runtime/daemon-control.d.ts +169 -0
- package/dist/cli/runtime/daemon-control.d.ts.map +1 -0
- package/dist/cli/runtime/daemon-control.js +441 -0
- package/dist/cli/runtime/daemon-control.js.map +1 -0
- package/dist/cli/runtime/default-roots.d.ts +27 -0
- package/dist/cli/runtime/default-roots.d.ts.map +1 -0
- package/dist/cli/runtime/default-roots.js +61 -0
- package/dist/cli/runtime/default-roots.js.map +1 -0
- package/dist/cli/runtime/diagnostics.d.ts +68 -0
- package/dist/cli/runtime/diagnostics.d.ts.map +1 -0
- package/dist/cli/runtime/diagnostics.js +1139 -0
- package/dist/cli/runtime/diagnostics.js.map +1 -0
- package/dist/cli/runtime/init-state.d.ts +20 -0
- package/dist/cli/runtime/init-state.d.ts.map +1 -0
- package/dist/cli/runtime/init-state.js +51 -0
- package/dist/cli/runtime/init-state.js.map +1 -0
- package/dist/cli/runtime/install-kind.d.ts +54 -0
- package/dist/cli/runtime/install-kind.d.ts.map +1 -0
- package/dist/cli/runtime/install-kind.js +164 -0
- package/dist/cli/runtime/install-kind.js.map +1 -0
- package/dist/cli/runtime/node-move-journal.d.ts +44 -0
- package/dist/cli/runtime/node-move-journal.d.ts.map +1 -0
- package/dist/cli/runtime/node-move-journal.js +48 -0
- package/dist/cli/runtime/node-move-journal.js.map +1 -0
- package/dist/cli/runtime/release-check.d.ts +94 -0
- package/dist/cli/runtime/release-check.d.ts.map +1 -0
- package/dist/cli/runtime/release-check.js +316 -0
- package/dist/cli/runtime/release-check.js.map +1 -0
- package/dist/cli/runtime/restore.d.ts +98 -0
- package/dist/cli/runtime/restore.d.ts.map +1 -0
- package/dist/cli/runtime/restore.js +756 -0
- package/dist/cli/runtime/restore.js.map +1 -0
- package/dist/cli/runtime/setup-page.d.ts +57 -0
- package/dist/cli/runtime/setup-page.d.ts.map +1 -0
- package/dist/cli/runtime/setup-page.js +266 -0
- package/dist/cli/runtime/setup-page.js.map +1 -0
- package/dist/cli/runtime/source-tools.d.ts +60 -0
- package/dist/cli/runtime/source-tools.d.ts.map +1 -0
- package/dist/cli/runtime/source-tools.js +170 -0
- package/dist/cli/runtime/source-tools.js.map +1 -0
- package/dist/cli/runtime/systemd-service.d.ts +13 -0
- package/dist/cli/runtime/systemd-service.d.ts.map +1 -0
- package/dist/cli/runtime/systemd-service.js +32 -0
- package/dist/cli/runtime/systemd-service.js.map +1 -0
- package/dist/cli/runtime/telegram-pairing.d.ts +73 -0
- package/dist/cli/runtime/telegram-pairing.d.ts.map +1 -0
- package/dist/cli/runtime/telegram-pairing.js +184 -0
- package/dist/cli/runtime/telegram-pairing.js.map +1 -0
- package/dist/cli/runtime/update-journal.d.ts +135 -0
- package/dist/cli/runtime/update-journal.d.ts.map +1 -0
- package/dist/cli/runtime/update-journal.js +144 -0
- package/dist/cli/runtime/update-journal.js.map +1 -0
- package/dist/cli/runtime/update-progress.d.ts +95 -0
- package/dist/cli/runtime/update-progress.d.ts.map +1 -0
- package/dist/cli/runtime/update-progress.js +154 -0
- package/dist/cli/runtime/update-progress.js.map +1 -0
- package/dist/cli/runtime/update-request.d.ts +58 -0
- package/dist/cli/runtime/update-request.d.ts.map +1 -0
- package/dist/cli/runtime/update-request.js +172 -0
- package/dist/cli/runtime/update-request.js.map +1 -0
- package/dist/connectors/calendar/index.d.ts +5 -1
- package/dist/connectors/calendar/index.d.ts.map +1 -1
- package/dist/connectors/calendar/index.js +19 -28
- package/dist/connectors/calendar/index.js.map +1 -1
- package/dist/connectors/chatwork/index.d.ts.map +1 -1
- package/dist/connectors/chatwork/index.js +7 -3
- package/dist/connectors/chatwork/index.js.map +1 -1
- package/dist/connectors/config-loader.d.ts +7 -1
- package/dist/connectors/config-loader.d.ts.map +1 -1
- package/dist/connectors/config-loader.js +11 -2
- package/dist/connectors/config-loader.js.map +1 -1
- package/dist/connectors/discord/index.d.ts.map +1 -1
- package/dist/connectors/discord/index.js +4 -3
- package/dist/connectors/discord/index.js.map +1 -1
- package/dist/connectors/drive/index.d.ts.map +1 -1
- package/dist/connectors/drive/index.js +15 -13
- package/dist/connectors/drive/index.js.map +1 -1
- package/dist/connectors/framework/gws-utils.d.ts +62 -0
- package/dist/connectors/framework/gws-utils.d.ts.map +1 -1
- package/dist/connectors/framework/gws-utils.js +133 -3
- package/dist/connectors/framework/gws-utils.js.map +1 -1
- package/dist/connectors/framework/polling-scheduler.d.ts.map +1 -1
- package/dist/connectors/framework/polling-scheduler.js +12 -11
- package/dist/connectors/framework/polling-scheduler.js.map +1 -1
- package/dist/connectors/framework/types.d.ts +24 -0
- package/dist/connectors/framework/types.d.ts.map +1 -1
- package/dist/connectors/framework/types.js +9 -0
- package/dist/connectors/framework/types.js.map +1 -1
- package/dist/connectors/gmail/index.d.ts.map +1 -1
- package/dist/connectors/gmail/index.js +14 -13
- package/dist/connectors/gmail/index.js.map +1 -1
- package/dist/connectors/imessage/index.d.ts.map +1 -1
- package/dist/connectors/imessage/index.js +2 -1
- package/dist/connectors/imessage/index.js.map +1 -1
- package/dist/connectors/index.d.ts +4 -4
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/index.js +4 -10
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/notion/index.d.ts.map +1 -1
- package/dist/connectors/notion/index.js +5 -3
- package/dist/connectors/notion/index.js.map +1 -1
- package/dist/connectors/sheets/index.d.ts.map +1 -1
- package/dist/connectors/sheets/index.js +17 -12
- package/dist/connectors/sheets/index.js.map +1 -1
- package/dist/connectors/slack/index.d.ts.map +1 -1
- package/dist/connectors/slack/index.js +9 -3
- package/dist/connectors/slack/index.js.map +1 -1
- package/dist/connectors/telegram/index.d.ts.map +1 -1
- package/dist/connectors/telegram/index.js +4 -3
- package/dist/connectors/telegram/index.js.map +1 -1
- package/dist/connectors/trello/index.d.ts +1 -1
- package/dist/connectors/trello/index.d.ts.map +1 -1
- package/dist/connectors/trello/index.js +10 -5
- package/dist/connectors/trello/index.js.map +1 -1
- package/dist/gateways/discord.d.ts +6 -0
- package/dist/gateways/discord.d.ts.map +1 -1
- package/dist/gateways/discord.js +38 -27
- package/dist/gateways/discord.js.map +1 -1
- package/dist/gateways/slack.d.ts +6 -0
- package/dist/gateways/slack.d.ts.map +1 -1
- package/dist/gateways/slack.js +38 -27
- package/dist/gateways/slack.js.map +1 -1
- package/dist/gateways/telegram-commands.d.ts +124 -0
- package/dist/gateways/telegram-commands.d.ts.map +1 -0
- package/dist/gateways/telegram-commands.js +131 -0
- package/dist/gateways/telegram-commands.js.map +1 -0
- package/dist/gateways/telegram.d.ts +20 -0
- package/dist/gateways/telegram.d.ts.map +1 -1
- package/dist/gateways/telegram.js +138 -34
- package/dist/gateways/telegram.js.map +1 -1
- package/dist/gateways/turn-contract.d.ts +11 -0
- package/dist/gateways/turn-contract.d.ts.map +1 -1
- package/dist/runtime/action-surface.d.ts +1 -1
- package/dist/runtime/action-surface.d.ts.map +1 -1
- package/dist/runtime/action-surface.js +10 -0
- package/dist/runtime/action-surface.js.map +1 -1
- package/dist/runtime/backend-security.d.ts +26 -2
- package/dist/runtime/backend-security.d.ts.map +1 -1
- package/dist/runtime/backend-security.js +63 -10
- package/dist/runtime/backend-security.js.map +1 -1
- package/dist/runtime/config.d.ts +3 -0
- package/dist/runtime/config.d.ts.map +1 -1
- package/dist/runtime/config.js +4 -4
- package/dist/runtime/config.js.map +1 -1
- package/dist/runtime/connectors.d.ts +21 -1
- package/dist/runtime/connectors.d.ts.map +1 -1
- package/dist/runtime/connectors.js +28 -17
- package/dist/runtime/connectors.js.map +1 -1
- package/dist/runtime/core-db.d.ts.map +1 -1
- package/dist/runtime/core-db.js +2 -0
- package/dist/runtime/core-db.js.map +1 -1
- package/dist/runtime/member-paths.d.ts +15 -7
- package/dist/runtime/member-paths.d.ts.map +1 -1
- package/dist/runtime/member-paths.js +64 -12
- package/dist/runtime/member-paths.js.map +1 -1
- package/dist/runtime/member-session.d.ts +4 -0
- package/dist/runtime/member-session.d.ts.map +1 -1
- package/dist/runtime/member-session.js +23 -2
- package/dist/runtime/member-session.js.map +1 -1
- package/dist/runtime/native-session.d.ts +2 -0
- package/dist/runtime/native-session.d.ts.map +1 -1
- package/dist/runtime/native-session.js +1 -0
- package/dist/runtime/native-session.js.map +1 -1
- package/dist/runtime/owner-runtime.d.ts +63 -1
- package/dist/runtime/owner-runtime.d.ts.map +1 -1
- package/dist/runtime/owner-runtime.js +180 -3
- package/dist/runtime/owner-runtime.js.map +1 -1
- package/dist/runtime/owner-system-prompt.d.ts.map +1 -1
- package/dist/runtime/owner-system-prompt.js +6 -5
- package/dist/runtime/owner-system-prompt.js.map +1 -1
- package/dist/runtime/principal-access.d.ts +2 -0
- package/dist/runtime/principal-access.d.ts.map +1 -1
- package/dist/runtime/principal-access.js +7 -0
- package/dist/runtime/principal-access.js.map +1 -1
- package/dist/runtime/principal-sessions.d.ts.map +1 -1
- package/dist/runtime/principal-sessions.js +8 -1
- package/dist/runtime/principal-sessions.js.map +1 -1
- package/dist/runtime/record-orders.d.ts.map +1 -1
- package/dist/runtime/record-orders.js +3 -29
- package/dist/runtime/record-orders.js.map +1 -1
- package/dist/runtime/report-scheduler.d.ts +9 -2
- package/dist/runtime/report-scheduler.d.ts.map +1 -1
- package/dist/runtime/report-scheduler.js +37 -10
- package/dist/runtime/report-scheduler.js.map +1 -1
- package/dist/runtime/rotating-log.d.ts +44 -0
- package/dist/runtime/rotating-log.d.ts.map +1 -0
- package/dist/runtime/rotating-log.js +124 -0
- package/dist/runtime/rotating-log.js.map +1 -0
- package/dist/runtime/stimulus-delivery.d.ts +3 -0
- package/dist/runtime/stimulus-delivery.d.ts.map +1 -1
- package/dist/runtime/stimulus-delivery.js +19 -3
- package/dist/runtime/stimulus-delivery.js.map +1 -1
- package/dist/runtime/tools-paths.d.ts +7 -0
- package/dist/runtime/tools-paths.d.ts.map +1 -1
- package/dist/runtime/tools-paths.js +11 -5
- package/dist/runtime/tools-paths.js.map +1 -1
- package/dist/runtime/upkeep-close.d.ts +17 -0
- package/dist/runtime/upkeep-close.d.ts.map +1 -0
- package/dist/runtime/upkeep-close.js +127 -0
- package/dist/runtime/upkeep-close.js.map +1 -0
- package/dist/runtime/upkeep-orders.d.ts +124 -0
- package/dist/runtime/upkeep-orders.d.ts.map +1 -0
- package/dist/runtime/upkeep-orders.js +310 -0
- package/dist/runtime/upkeep-orders.js.map +1 -0
- package/dist/runtime/upkeep-reconcile.d.ts +25 -0
- package/dist/runtime/upkeep-reconcile.d.ts.map +1 -0
- package/dist/runtime/upkeep-reconcile.js +231 -0
- package/dist/runtime/upkeep-reconcile.js.map +1 -0
- package/dist/runtime/upkeep-writeback.d.ts +22 -0
- package/dist/runtime/upkeep-writeback.d.ts.map +1 -0
- package/dist/runtime/upkeep-writeback.js +203 -0
- package/dist/runtime/upkeep-writeback.js.map +1 -0
- package/dist/tools/document-toolkit.d.ts +2 -0
- package/dist/tools/document-toolkit.d.ts.map +1 -1
- package/dist/tools/document-toolkit.js +2 -0
- package/dist/tools/document-toolkit.js.map +1 -1
- package/dist/utils/untrusted-content.d.ts.map +1 -1
- package/dist/utils/untrusted-content.js +8 -1
- package/dist/utils/untrusted-content.js.map +1 -1
- package/install/install.sh +457 -0
- package/install/node.json +9 -0
- package/package.json +5 -5
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OWNER_PRINCIPAL_ID = void 0;
|
|
3
|
+
exports.MESSENGER_SECRETS = exports.BOOT_STAGES = exports.StopDuringBootError = exports.OWNER_PRINCIPAL_ID = void 0;
|
|
4
|
+
exports.pathsOverlap = pathsOverlap;
|
|
4
5
|
exports.validateDeliveryRoutes = validateDeliveryRoutes;
|
|
6
|
+
exports.upkeepCloseSince = upkeepCloseSince;
|
|
7
|
+
exports.pathsFor = pathsFor;
|
|
5
8
|
exports.ensureDaemonIsolation = ensureDaemonIsolation;
|
|
6
9
|
exports.loggedOwnerIntake = loggedOwnerIntake;
|
|
7
10
|
exports.bootDaemon = bootDaemon;
|
|
8
11
|
exports.runDaemon = runDaemon;
|
|
9
|
-
exports.
|
|
10
|
-
exports.
|
|
12
|
+
exports.installControlPaths = installControlPaths;
|
|
13
|
+
exports.askDaemon = askDaemon;
|
|
14
|
+
exports.launchdService = launchdService;
|
|
15
|
+
exports.bootoutLaunchdService = bootoutLaunchdService;
|
|
11
16
|
const mama_core_1 = require("@jungjaehoon/mama-core");
|
|
12
17
|
const document_toolkit_js_1 = require("../../tools/document-toolkit.js");
|
|
13
18
|
const node_fs_1 = require("node:fs");
|
|
@@ -24,6 +29,7 @@ const action_surface_js_1 = require("../../runtime/action-surface.js");
|
|
|
24
29
|
const connectors_js_1 = require("../../runtime/connectors.js");
|
|
25
30
|
const config_js_1 = require("../../runtime/config.js");
|
|
26
31
|
const model_cache_js_1 = require("../../runtime/model-cache.js");
|
|
32
|
+
const member_paths_js_1 = require("../../runtime/member-paths.js");
|
|
27
33
|
const backend_security_js_1 = require("../../runtime/backend-security.js");
|
|
28
34
|
const session_credential_js_1 = require("../../runtime/session-credential.js");
|
|
29
35
|
const action_mcp_config_js_1 = require("../runtime/action-mcp-config.js");
|
|
@@ -35,10 +41,16 @@ const viewer_data_js_1 = require("../../api/viewer-data.js");
|
|
|
35
41
|
const owner_authority_js_1 = require("../../runtime/owner-authority.js");
|
|
36
42
|
const principal_access_js_1 = require("../../runtime/principal-access.js");
|
|
37
43
|
const report_scheduler_js_1 = require("../../runtime/report-scheduler.js");
|
|
44
|
+
const release_check_js_1 = require("../runtime/release-check.js");
|
|
45
|
+
const install_kind_js_1 = require("../runtime/install-kind.js");
|
|
46
|
+
const update_request_js_1 = require("../runtime/update-request.js");
|
|
47
|
+
const systemd_service_js_1 = require("../runtime/systemd-service.js");
|
|
38
48
|
const wiki_read_js_1 = require("../../wiki/wiki-read.js");
|
|
39
49
|
const timezone_js_1 = require("../../runtime/timezone.js");
|
|
40
50
|
const security_events_js_1 = require("../../api/security-events.js");
|
|
41
51
|
const egress_proxy_js_1 = require("../../runtime/egress-proxy.js");
|
|
52
|
+
const daemon_control_js_1 = require("../runtime/daemon-control.js");
|
|
53
|
+
const update_journal_js_1 = require("../runtime/update-journal.js");
|
|
42
54
|
exports.OWNER_PRINCIPAL_ID = 'owner';
|
|
43
55
|
const OWNER_AGENT_ID = 'owner-agent';
|
|
44
56
|
const OWNER_MEMORY_SCOPES = (0, action_surface_js_1.ownerMemoryScopes)(exports.OWNER_PRINCIPAL_ID, index_js_1.LOADABLE_CONNECTORS);
|
|
@@ -56,9 +68,49 @@ function errorName(error) {
|
|
|
56
68
|
const name = error.name.trim() !== '' ? error.name : 'Error';
|
|
57
69
|
return `${name}: ${error.message}`;
|
|
58
70
|
}
|
|
59
|
-
|
|
71
|
+
class StopDuringBootError extends Error {
|
|
72
|
+
constructor() {
|
|
73
|
+
super('Stopped during boot');
|
|
74
|
+
this.name = 'StopDuringBootError';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.StopDuringBootError = StopDuringBootError;
|
|
78
|
+
/** Every stage boot logs as `boot stage=<name>`; `mama doctor` reports only these names. */
|
|
79
|
+
exports.BOOT_STAGES = [
|
|
80
|
+
'config',
|
|
81
|
+
'isolation',
|
|
82
|
+
'owner_runtime',
|
|
83
|
+
'viewer',
|
|
84
|
+
'replay',
|
|
85
|
+
'connectors',
|
|
86
|
+
'messengers',
|
|
87
|
+
'telegram',
|
|
88
|
+
'telegram:disabled',
|
|
89
|
+
'discord',
|
|
90
|
+
'slack',
|
|
91
|
+
'report_scheduler',
|
|
92
|
+
'report_scheduler:route_unavailable',
|
|
93
|
+
'personal_job_scheduler',
|
|
94
|
+
];
|
|
95
|
+
function stage(logger, name, signal) {
|
|
96
|
+
if (signal?.aborted)
|
|
97
|
+
throw new StopDuringBootError();
|
|
60
98
|
logger.info(`boot stage=${name}`);
|
|
61
99
|
}
|
|
100
|
+
/** The auth.env names each messenger needs before it starts; `mama doctor` checks the same. */
|
|
101
|
+
exports.MESSENGER_SECRETS = {
|
|
102
|
+
telegram: ['MAMA_TELEGRAM_TOKEN'],
|
|
103
|
+
discord: ['MAMA_DISCORD_TOKEN'],
|
|
104
|
+
slack: ['MAMA_SLACK_TOKEN', 'MAMA_SLACK_APP_TOKEN'],
|
|
105
|
+
};
|
|
106
|
+
function messengerSecrets(messenger) {
|
|
107
|
+
return exports.MESSENGER_SECRETS[messenger].map((name) => {
|
|
108
|
+
const value = process.env[name];
|
|
109
|
+
if (!value?.trim())
|
|
110
|
+
throw new Error(`${name} is required`);
|
|
111
|
+
return value;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
62
114
|
function stageFailed(logger, name, error) {
|
|
63
115
|
logger.error(`boot stage=${name} failed error=${errorName(error)}`);
|
|
64
116
|
}
|
|
@@ -107,6 +159,24 @@ function validateDeliveryRoutes(config) {
|
|
|
107
159
|
throw new Error(`delivery.${purpose} targets ${messenger}, which is disabled or has no allowlisted owner channel`);
|
|
108
160
|
}
|
|
109
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* The instant closing summaries start being ordered: written once, at the first start that runs
|
|
164
|
+
* upkeep, so items closed before it are left to the one-time summary script.
|
|
165
|
+
*/
|
|
166
|
+
function upkeepCloseSince(path, now = Date.now()) {
|
|
167
|
+
if ((0, node_fs_1.existsSync)(path)) {
|
|
168
|
+
const stored = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8')).closeSince;
|
|
169
|
+
if (typeof stored !== 'number' || !Number.isSafeInteger(stored))
|
|
170
|
+
throw new Error(`${path} has no closeSince epoch`);
|
|
171
|
+
return stored;
|
|
172
|
+
}
|
|
173
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(path), { recursive: true });
|
|
174
|
+
// Written once and read at every start: a partial file would stop each boot, so it appears whole.
|
|
175
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
176
|
+
(0, node_fs_1.writeFileSync)(temporary, `${JSON.stringify({ closeSince: now }, null, 2)}\n`, { mode: 0o600 });
|
|
177
|
+
(0, node_fs_1.renameSync)(temporary, path);
|
|
178
|
+
return now;
|
|
179
|
+
}
|
|
110
180
|
function pathsFor(configPath, config) {
|
|
111
181
|
const mamaRoot = (0, node_path_1.dirname)(configPath);
|
|
112
182
|
const runtimeRoot = (0, node_path_1.join)(mamaRoot, 'runtime');
|
|
@@ -129,6 +199,11 @@ function pathsFor(configPath, config) {
|
|
|
129
199
|
if (pathsOverlap(workspaceDir, runtimeRoot)) {
|
|
130
200
|
throw new Error(`agent.codex_cwd must not contain or sit inside ${runtimeRoot}`);
|
|
131
201
|
}
|
|
202
|
+
// Backups are denied to the agents; a workspace there could not be read by its own agent.
|
|
203
|
+
const backupsRoot = (0, node_path_1.join)(mamaRoot, 'backups');
|
|
204
|
+
if (pathsOverlap(workspaceDir, backupsRoot)) {
|
|
205
|
+
throw new Error(`agent.codex_cwd must not contain or sit inside ${backupsRoot}`);
|
|
206
|
+
}
|
|
132
207
|
return {
|
|
133
208
|
mamaRoot,
|
|
134
209
|
runtimeRoot,
|
|
@@ -148,6 +223,8 @@ function pathsFor(configPath, config) {
|
|
|
148
223
|
/** Create only the native-process isolation files; never remove product state. */
|
|
149
224
|
function ensureDaemonIsolation(options) {
|
|
150
225
|
const { config, paths } = options;
|
|
226
|
+
// Member temp data under the old machine-wide parents is no longer under any session deny.
|
|
227
|
+
(0, member_paths_js_1.removeRetiredMemberTemp)();
|
|
151
228
|
(0, node_fs_1.mkdirSync)(paths.downloadsDir, { recursive: true, mode: 0o700 });
|
|
152
229
|
(0, node_fs_1.mkdirSync)(paths.workspaceDir, { recursive: true });
|
|
153
230
|
const gitDir = (0, node_path_1.join)(paths.workspaceDir, '.git');
|
|
@@ -196,7 +273,15 @@ async function stopOne(logger, name, stop, errors) {
|
|
|
196
273
|
}
|
|
197
274
|
/** Open the W1 owner subject, then activate producers in their dependency order. */
|
|
198
275
|
async function bootDaemon(options = {}) {
|
|
199
|
-
const
|
|
276
|
+
const baseLogger = options.logger ?? defaultLogger;
|
|
277
|
+
let lastError = null;
|
|
278
|
+
const logger = {
|
|
279
|
+
info: (line) => baseLogger.info(line),
|
|
280
|
+
error: (line) => {
|
|
281
|
+
lastError = { at: Date.now(), line: line.slice(0, 500) };
|
|
282
|
+
baseLogger.error(line);
|
|
283
|
+
},
|
|
284
|
+
};
|
|
200
285
|
const dependencies = options.dependencies ?? {};
|
|
201
286
|
const configPath = options.configPath ?? (0, config_js_1.defaultConfigPath)(options.home ?? (0, node_os_1.homedir)());
|
|
202
287
|
let config;
|
|
@@ -208,15 +293,94 @@ async function bootDaemon(options = {}) {
|
|
|
208
293
|
let gateway = null;
|
|
209
294
|
const gateways = new Map();
|
|
210
295
|
let reportScheduler;
|
|
296
|
+
let releaseCheck;
|
|
211
297
|
let egressProxy;
|
|
212
298
|
let stopped = false;
|
|
213
299
|
let deliveryReady = options.mode === 'replay';
|
|
214
300
|
const startedAt = Date.now();
|
|
215
301
|
let currentStage = 'config';
|
|
216
|
-
|
|
302
|
+
let booted = false;
|
|
303
|
+
const command = options.command ?? (options.mode === 'replay' ? 'replay' : 'daemon');
|
|
304
|
+
// The install's one process: taken before anything opens the database or rewrites settings.
|
|
305
|
+
const control = (0, daemon_control_js_1.daemonControlPaths)((0, node_path_1.dirname)(configPath));
|
|
306
|
+
const lock = (0, daemon_control_js_1.acquireInstallLock)(control, command);
|
|
307
|
+
let controlServer = null;
|
|
308
|
+
// One per open drain connection; while any is open, nothing new is claimed.
|
|
309
|
+
const holds = new Set();
|
|
310
|
+
// An update candidate's hold, from boot until the updater's `release` (update.md, steps 13-14).
|
|
311
|
+
let updateHold = null;
|
|
312
|
+
const claimsHeld = () => holds.size > 0 || updateHold !== null;
|
|
313
|
+
// What a drain waits for: this process's own work. Runs and claims of an earlier boot are left
|
|
314
|
+
// out: their process is gone, and such a claim (a dispatch the crash cut off) resolves only in
|
|
315
|
+
// reconciliation, which the hold suspends. A claim is stamped when it is taken and renewed only
|
|
316
|
+
// by this process's deliveries, so its time tells which boot owns it. A claimed input whose
|
|
317
|
+
// native dispatch is uncertain is parked until reconciliation too; nothing starts from it.
|
|
318
|
+
const drainCounts = () => {
|
|
217
319
|
if (stopped)
|
|
218
|
-
|
|
219
|
-
|
|
320
|
+
throw new Error('MAMA is stopping');
|
|
321
|
+
if (!owner)
|
|
322
|
+
return { running: 0, claimed: 0, turns: 0 };
|
|
323
|
+
const adapter = owner.database.adapter;
|
|
324
|
+
const { running, unclaimed } = adapter
|
|
325
|
+
.prepare(`SELECT COUNT(*) AS running,
|
|
326
|
+
COUNT(CASE WHEN parent_model_run_id IS NULL
|
|
327
|
+
AND json_extract(input_refs_json, '$.nativeInputId') IS NULL
|
|
328
|
+
THEN 1 END) AS unclaimed
|
|
329
|
+
FROM model_runs WHERE status = 'running' AND created_at >= ?`)
|
|
330
|
+
.get(startedAt);
|
|
331
|
+
const { claimed } = adapter
|
|
332
|
+
.prepare(`SELECT COUNT(*) AS claimed FROM mailbox_inputs m
|
|
333
|
+
WHERE m.status = 'claimed' AND m.claimed_at >= ?
|
|
334
|
+
AND NOT EXISTS (SELECT 1 FROM native_input_deliveries n
|
|
335
|
+
WHERE n.input_id = m.id AND n.state = 'uncertain')`)
|
|
336
|
+
.get(startedAt);
|
|
337
|
+
// A turn either runs a claimed input or is a top-level run without one (a probe); subagent
|
|
338
|
+
// runs belong to their parent's turn.
|
|
339
|
+
return { running, claimed, turns: claimed + unclaimed };
|
|
340
|
+
};
|
|
341
|
+
const statusReport = async () => {
|
|
342
|
+
const report = {
|
|
343
|
+
pid: process.pid,
|
|
344
|
+
command,
|
|
345
|
+
version: (0, package_version_js_1.resolvePackageVersion)(),
|
|
346
|
+
// What `mama update --node` confirms after it moves the managed Node.
|
|
347
|
+
node: process.version,
|
|
348
|
+
startedAt,
|
|
349
|
+
stage: stopped ? 'stopping' : booted ? 'running' : currentStage,
|
|
350
|
+
lastError,
|
|
351
|
+
drain: holds.size === 0
|
|
352
|
+
? null
|
|
353
|
+
: { holds: holds.size, since: Math.min(...[...holds].map((hold) => hold.since)) },
|
|
354
|
+
update: updateHold,
|
|
355
|
+
};
|
|
356
|
+
// Stores close during a stop; what it reports then is that it is stopping.
|
|
357
|
+
if (stopped)
|
|
358
|
+
return report;
|
|
359
|
+
if (owner) {
|
|
360
|
+
const adapter = owner.database.adapter;
|
|
361
|
+
report.runningTurns = adapter
|
|
362
|
+
.prepare(`SELECT COALESCE(json_extract(input_refs_json, '$.sessionKey'), 'unknown') AS session,
|
|
363
|
+
COUNT(*) AS count
|
|
364
|
+
FROM model_runs WHERE status = 'running' AND created_at >= ? GROUP BY 1 ORDER BY 1`)
|
|
365
|
+
.all(startedAt);
|
|
366
|
+
report.inputs = adapter
|
|
367
|
+
.prepare(`SELECT status, COUNT(*) AS count FROM mailbox_inputs
|
|
368
|
+
WHERE status IN ('pending', 'claimed') GROUP BY status ORDER BY status`)
|
|
369
|
+
.all();
|
|
370
|
+
}
|
|
371
|
+
if (connectors) {
|
|
372
|
+
const connectorRuntime = connectors;
|
|
373
|
+
const health = await connectorRuntime.registry.healthCheckAll();
|
|
374
|
+
report.connectors = connectorRuntime.enabledConnectorNames.map((name) => ({
|
|
375
|
+
name,
|
|
376
|
+
healthy: health[name]?.healthy === true,
|
|
377
|
+
lastPoll: health[name]?.lastPollTime?.toISOString() ?? null,
|
|
378
|
+
error: health[name]?.error ?? null,
|
|
379
|
+
}));
|
|
380
|
+
}
|
|
381
|
+
return report;
|
|
382
|
+
};
|
|
383
|
+
const stopOwned = async () => {
|
|
220
384
|
const errors = [];
|
|
221
385
|
owner?.beginStop?.();
|
|
222
386
|
// Quiesce every producer before awaiting any one of them. Transports and the database
|
|
@@ -224,6 +388,8 @@ async function bootDaemon(options = {}) {
|
|
|
224
388
|
const producerStops = [...gateways].map(([name, active]) => stopOne(logger, `${name}_intake`, () => active.beginStop?.(), errors));
|
|
225
389
|
if (reportScheduler)
|
|
226
390
|
producerStops.push(stopOne(logger, 'report_scheduler', () => reportScheduler.stop(), errors));
|
|
391
|
+
if (releaseCheck)
|
|
392
|
+
producerStops.push(stopOne(logger, 'release_check', () => releaseCheck.stop(), errors));
|
|
227
393
|
if (connectors)
|
|
228
394
|
producerStops.push(stopOne(logger, 'connectors', () => connectors.stop(), errors));
|
|
229
395
|
if (viewer)
|
|
@@ -243,22 +409,101 @@ async function bootDaemon(options = {}) {
|
|
|
243
409
|
if (errors.length > 0)
|
|
244
410
|
throw new AggregateError(errors, 'Daemon shutdown failed');
|
|
245
411
|
};
|
|
412
|
+
const stopResources = async () => {
|
|
413
|
+
if (stopped)
|
|
414
|
+
return;
|
|
415
|
+
stopped = true;
|
|
416
|
+
let closed = false;
|
|
417
|
+
try {
|
|
418
|
+
await stopOwned();
|
|
419
|
+
closed = true;
|
|
420
|
+
}
|
|
421
|
+
finally {
|
|
422
|
+
if (controlServer) {
|
|
423
|
+
await controlServer
|
|
424
|
+
.close()
|
|
425
|
+
.catch((error) => logger.error(`shutdown stage=control failed error=${errorName(error)}`));
|
|
426
|
+
}
|
|
427
|
+
// Released only once every store closed: after a failed stop something may still run, so
|
|
428
|
+
// the install stays held until this process ends and the operating system lets it go.
|
|
429
|
+
if (closed)
|
|
430
|
+
lock.release();
|
|
431
|
+
}
|
|
432
|
+
};
|
|
246
433
|
try {
|
|
247
434
|
currentStage = 'config';
|
|
248
|
-
|
|
435
|
+
// A half-switched install is neither the old one nor the restored one.
|
|
436
|
+
(0, daemon_control_js_1.refuseWhileRestoring)((0, node_path_1.dirname)(configPath));
|
|
437
|
+
controlServer = await (0, daemon_control_js_1.startDaemonControl)(control, {
|
|
438
|
+
status: statusReport,
|
|
439
|
+
stop: () => {
|
|
440
|
+
if (!options.requestStop)
|
|
441
|
+
throw new Error(`${command} stops when it finishes`);
|
|
442
|
+
options.requestStop();
|
|
443
|
+
},
|
|
444
|
+
probe: async () => {
|
|
445
|
+
if (!booted || stopped || !owner)
|
|
446
|
+
throw new Error('MAMA has not finished starting');
|
|
447
|
+
// After the drain is idle the stop comes next, and it would cut the probe's turn off.
|
|
448
|
+
if (holds.size > 0)
|
|
449
|
+
throw new Error('A drain holds new work; probe after the restart');
|
|
450
|
+
try {
|
|
451
|
+
const probed = await owner.probeBackend();
|
|
452
|
+
logger.info(`backend probe: ${config.agent.backend} answered in ${probed.ms} ms (model run ${probed.modelRunId ?? 'none'})`);
|
|
453
|
+
return { backend: config.agent.backend, model: config.agent.model, ...probed };
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
// The turn's own failure is wrapped by the dispatch layer; its causes name what failed.
|
|
457
|
+
const reason = (0, stimulus_delivery_js_1.stimulusFailureReason)(error);
|
|
458
|
+
logger.error(`backend probe: ${config.agent.backend} failed: ${reason}`);
|
|
459
|
+
throw new Error(reason);
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
hold: () => {
|
|
463
|
+
const at = drainCounts();
|
|
464
|
+
// Each turn that may still run takes at most max_turn_ms; nothing new starts.
|
|
465
|
+
const perTurn = owner ? config.agent.max_turn_ms : 0;
|
|
466
|
+
const hold = { since: Date.now() };
|
|
467
|
+
holds.add(hold);
|
|
468
|
+
logger.info(`drain: claims held running=${at.running} claimed=${at.claimed}`);
|
|
469
|
+
return {
|
|
470
|
+
boundMs: at.turns * perTurn + 60_000,
|
|
471
|
+
counts: () => {
|
|
472
|
+
const { running, claimed } = drainCounts();
|
|
473
|
+
return { running, claimed };
|
|
474
|
+
},
|
|
475
|
+
release: () => {
|
|
476
|
+
holds.delete(hold);
|
|
477
|
+
logger.info('drain: claims released');
|
|
478
|
+
},
|
|
479
|
+
};
|
|
480
|
+
},
|
|
481
|
+
release: () => {
|
|
482
|
+
const held = updateHold !== null;
|
|
483
|
+
if (held)
|
|
484
|
+
logger.info(`update: ${updateHold.to} confirmed; claims released`);
|
|
485
|
+
updateHold = null;
|
|
486
|
+
return { held };
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
if (options.signal?.aborted)
|
|
490
|
+
throw new StopDuringBootError();
|
|
249
491
|
config = options.config ?? (0, config_js_1.loadConfig)({ path: configPath, home: options.home });
|
|
492
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(config.logging.file), { recursive: true });
|
|
493
|
+
// The service manager redirects only what comes before this point, to the crash log. From here
|
|
494
|
+
// on the daemon's own log holds everything, from the first boot stage on.
|
|
495
|
+
options.captureOutput?.(config.logging.file);
|
|
496
|
+
stage(logger, 'config', options.signal);
|
|
497
|
+
// An update candidate runs nothing until the updater has seen it boot and confirmed it: its
|
|
498
|
+
// boot recovery claims nothing, so a rollback finds every input as it was (update.md step 13).
|
|
499
|
+
const update = (0, update_journal_js_1.readUpdateJournal)((0, update_journal_js_1.updatePaths)((0, node_path_1.dirname)(configPath)).journal);
|
|
500
|
+
if (update?.phase === 'candidate') {
|
|
501
|
+
updateHold = { since: Date.now(), to: update.to };
|
|
502
|
+
logger.info(`update: booted as the candidate for ${update.to}; claims held until confirmed`);
|
|
503
|
+
}
|
|
250
504
|
logger.info(`document toolkit: ${(0, document_toolkit_js_1.readDocumentToolkit)(config.tools_root, (error) => logger.error(error.message)) ? 'present' : 'absent (run mama tools install)'}`);
|
|
251
505
|
const timeZone = (0, timezone_js_1.createTimeZoneSetting)(config.timezone);
|
|
252
506
|
validateDeliveryRoutes(config);
|
|
253
|
-
// launchd may have created the redirected log already; preserve its contents and tighten it.
|
|
254
|
-
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(config.logging.file), { recursive: true });
|
|
255
|
-
const logDescriptor = (0, node_fs_1.openSync)(config.logging.file, 'a', 0o600);
|
|
256
|
-
try {
|
|
257
|
-
(0, node_fs_1.fchmodSync)(logDescriptor, 0o600);
|
|
258
|
-
}
|
|
259
|
-
finally {
|
|
260
|
-
(0, node_fs_1.closeSync)(logDescriptor);
|
|
261
|
-
}
|
|
262
507
|
(0, model_cache_js_1.declareModelCache)();
|
|
263
508
|
paths = pathsFor(configPath, config);
|
|
264
509
|
currentStage = 'isolation';
|
|
@@ -268,7 +513,7 @@ async function bootDaemon(options = {}) {
|
|
|
268
513
|
paths,
|
|
269
514
|
...(options.mcpServerPath ? { mcpServerPath: options.mcpServerPath } : {}),
|
|
270
515
|
});
|
|
271
|
-
stage(logger, 'isolation');
|
|
516
|
+
stage(logger, 'isolation', options.signal);
|
|
272
517
|
currentStage = 'owner_runtime';
|
|
273
518
|
const ownerPolicyProvider = (0, owner_policy_js_1.createOwnerPolicyProvider)(paths.mamaRoot);
|
|
274
519
|
const ownerPolicy = ownerPolicyProvider();
|
|
@@ -445,6 +690,7 @@ async function bootDaemon(options = {}) {
|
|
|
445
690
|
},
|
|
446
691
|
ownerPolicyProvider,
|
|
447
692
|
deliveryReady: () => deliveryReady,
|
|
693
|
+
claimsHeld,
|
|
448
694
|
onPersonalJobError: (error) => logger.error(`personal job scheduler failed reason=${(0, stimulus_delivery_js_1.stimulusFailureReason)(error)}`),
|
|
449
695
|
...(options.mode === 'replay'
|
|
450
696
|
? {}
|
|
@@ -458,7 +704,9 @@ async function bootDaemon(options = {}) {
|
|
|
458
704
|
const selected = gateways.get(sourceForRef(row.stimulusId));
|
|
459
705
|
if (!selected)
|
|
460
706
|
throw new Error('Owner messenger is not available for an interrupted response');
|
|
461
|
-
|
|
707
|
+
// Only this message: a sweep would tell messages still in flight that they were
|
|
708
|
+
// interrupted, and their answers would then be dropped as already delivered.
|
|
709
|
+
await selected.recoverResponse(row.stimulusId);
|
|
462
710
|
},
|
|
463
711
|
closeUncertain: {
|
|
464
712
|
ownerAnswered: (row) => gateways.get(sourceForRef(row.stimulusId))?.answered(row.stimulusId) ?? false,
|
|
@@ -491,10 +739,26 @@ async function bootDaemon(options = {}) {
|
|
|
491
739
|
else
|
|
492
740
|
logger.info(line);
|
|
493
741
|
},
|
|
742
|
+
// Upkeep orders write the ledger from live state: a replay places none, but still serves an
|
|
743
|
+
// order a live run left in the mailbox.
|
|
744
|
+
upkeep: {
|
|
745
|
+
closeSince: upkeepCloseSince((0, node_path_1.join)(paths.runtimeRoot, 'upkeep-state.json')),
|
|
746
|
+
fullReportHours: () => config.reports.full_report_hours,
|
|
747
|
+
scan: options.mode !== 'replay',
|
|
748
|
+
onEvent: (event) => {
|
|
749
|
+
const line = `upkeep ${event.kind} ${event.type}${event.type === 'ordered'
|
|
750
|
+
? ` order=${event.order} subjects=${event.subjects}`
|
|
751
|
+
: ` subject=${event.subject}`}${'attempt' in event ? ` attempt=${event.attempt}` : ''}${'reason' in event ? ` reason=${(0, stimulus_delivery_js_1.stimulusFailureReason)(event.reason)}` : ''}`;
|
|
752
|
+
if (event.type === 'lost')
|
|
753
|
+
logger.error(line);
|
|
754
|
+
else
|
|
755
|
+
logger.info(line);
|
|
756
|
+
},
|
|
757
|
+
},
|
|
494
758
|
onStimulusDelivered: (row, modelRunId) => stimulusDelivered(logger, row, modelRunId),
|
|
495
759
|
onStimulusFailed: (row, reason, modelRunId) => stimulusFailed(logger, row.kind ?? 'unknown', row.stimulusId, reason, modelRunId),
|
|
496
760
|
});
|
|
497
|
-
stage(logger, 'owner_runtime');
|
|
761
|
+
stage(logger, 'owner_runtime', options.signal);
|
|
498
762
|
currentStage = 'viewer';
|
|
499
763
|
const viewerFactory = dependencies.createViewerServer ?? viewer_server_js_1.createViewerServer;
|
|
500
764
|
viewer = viewerFactory({
|
|
@@ -545,14 +809,14 @@ async function bootDaemon(options = {}) {
|
|
|
545
809
|
});
|
|
546
810
|
await viewer.start();
|
|
547
811
|
logger.info(`viewer server listening on port=${String(viewer.port)}`);
|
|
548
|
-
stage(logger, 'viewer');
|
|
812
|
+
stage(logger, 'viewer', options.signal);
|
|
549
813
|
if (options.mode === 'replay') {
|
|
550
814
|
logger.info('replay collectors: disabled');
|
|
551
815
|
currentStage = 'replay';
|
|
552
816
|
if (!options.replay)
|
|
553
817
|
throw new Error('Replay mode requires a replay feeder');
|
|
554
818
|
await options.replay({ config, paths, owner, logger, timeZone });
|
|
555
|
-
stage(logger, 'replay');
|
|
819
|
+
stage(logger, 'replay', options.signal);
|
|
556
820
|
return {
|
|
557
821
|
config,
|
|
558
822
|
paths,
|
|
@@ -589,16 +853,14 @@ async function bootDaemon(options = {}) {
|
|
|
589
853
|
coreAdapter: owner.database?.adapter,
|
|
590
854
|
acceptSourceDelta,
|
|
591
855
|
});
|
|
592
|
-
stage(logger, 'connectors');
|
|
856
|
+
stage(logger, 'connectors', options.signal);
|
|
593
857
|
currentStage = 'messengers';
|
|
594
858
|
const intake = loggedOwnerIntake(owner.intake, logger);
|
|
595
859
|
const ledgerPath = paths.ownerMessageLedgerPath;
|
|
596
860
|
messageLedger = new telegram_message_ledger_js_1.OwnerMessageLedger(ledgerPath, { log: (line) => logger.info(line) });
|
|
597
861
|
const filesRoot = (0, node_path_1.join)(paths.workspaceDir, 'files');
|
|
598
862
|
if (config.telegram.enabled) {
|
|
599
|
-
const token =
|
|
600
|
-
if (!token?.trim())
|
|
601
|
-
throw new Error('MAMA_TELEGRAM_TOKEN is required');
|
|
863
|
+
const [token] = messengerSecrets('telegram');
|
|
602
864
|
const factory = dependencies.createTelegramGateway ?? ((options) => new telegram_js_1.TelegramGateway(options));
|
|
603
865
|
gateway = factory({
|
|
604
866
|
token,
|
|
@@ -612,6 +874,59 @@ async function bootDaemon(options = {}) {
|
|
|
612
874
|
principalPaths: (principalId, room) => owner.principalPaths(principalId, room),
|
|
613
875
|
onMemberSelection: (selection) => owner.completeMemberEnrollment(selection),
|
|
614
876
|
recordMemberSelection: (exchange) => owner.recordHostExchange(exchange),
|
|
877
|
+
hostCommands: {
|
|
878
|
+
status: async (target, ownerView) => {
|
|
879
|
+
const report = await statusReport();
|
|
880
|
+
const adapter = owner.database.adapter;
|
|
881
|
+
// A group reads the reply, so a member's count there is that group's inputs only.
|
|
882
|
+
const waiting = (0, owner_runtime_js_1.countInputsNotDone)(adapter, ownerView
|
|
883
|
+
? {}
|
|
884
|
+
: target.kind === 'common'
|
|
885
|
+
? { principalId: exports.OWNER_PRINCIPAL_ID }
|
|
886
|
+
: {
|
|
887
|
+
principalId: target.principalId,
|
|
888
|
+
...(target.room === undefined ? {} : { channel: target.room }),
|
|
889
|
+
});
|
|
890
|
+
const turns = (report.runningTurns ?? []);
|
|
891
|
+
const sources = (report.connectors ?? []);
|
|
892
|
+
return {
|
|
893
|
+
version: String(report.version),
|
|
894
|
+
since: (0, timezone_js_1.localNow)(startedAt, timeZone.get()),
|
|
895
|
+
conversationRunning: owner.turnRunning(target),
|
|
896
|
+
inputsWaiting: waiting,
|
|
897
|
+
...(ownerView
|
|
898
|
+
? {
|
|
899
|
+
owner: {
|
|
900
|
+
turnsRunning: turns.reduce((sum, turn) => sum + turn.count, 0),
|
|
901
|
+
sources: sources.map(({ name, healthy }) => ({ name, healthy })),
|
|
902
|
+
},
|
|
903
|
+
}
|
|
904
|
+
: {}),
|
|
905
|
+
};
|
|
906
|
+
},
|
|
907
|
+
startOver: (target) => owner.startOver(target),
|
|
908
|
+
stopTurn: (target) => owner.stopTurn(target),
|
|
909
|
+
update: async (origin) => {
|
|
910
|
+
const result = (0, update_request_js_1.requestUpdate)({
|
|
911
|
+
mamaRoot: paths.mamaRoot,
|
|
912
|
+
home: options.home ?? (0, node_os_1.homedir)(),
|
|
913
|
+
origin,
|
|
914
|
+
version: (0, package_version_js_1.resolvePackageVersion)(),
|
|
915
|
+
platform: process.platform,
|
|
916
|
+
run: systemd_service_js_1.defaultServiceRun,
|
|
917
|
+
uid: process.getuid(),
|
|
918
|
+
log: (line) => logger.info(line),
|
|
919
|
+
});
|
|
920
|
+
logger.info(`update requested result=${result.kind}`);
|
|
921
|
+
if (result.kind !== 'busy')
|
|
922
|
+
return result;
|
|
923
|
+
return {
|
|
924
|
+
kind: 'busy',
|
|
925
|
+
source: result.source,
|
|
926
|
+
since: result.since === null ? 'an unknown time' : (0, timezone_js_1.localNow)(result.since, timeZone.get()),
|
|
927
|
+
};
|
|
928
|
+
},
|
|
929
|
+
},
|
|
615
930
|
config: {
|
|
616
931
|
enabled: true,
|
|
617
932
|
allowedChats: config.telegram.allowed_chats,
|
|
@@ -633,14 +948,12 @@ async function bootDaemon(options = {}) {
|
|
|
633
948
|
});
|
|
634
949
|
gateways.set('telegram', gateway);
|
|
635
950
|
await gateway.start();
|
|
636
|
-
stage(logger, 'telegram');
|
|
951
|
+
stage(logger, 'telegram', options.signal);
|
|
637
952
|
}
|
|
638
953
|
else
|
|
639
|
-
stage(logger, 'telegram:disabled');
|
|
954
|
+
stage(logger, 'telegram:disabled', options.signal);
|
|
640
955
|
if (config.discord?.enabled) {
|
|
641
|
-
const token =
|
|
642
|
-
if (!token?.trim())
|
|
643
|
-
throw new Error('MAMA_DISCORD_TOKEN is required');
|
|
956
|
+
const [token] = messengerSecrets('discord');
|
|
644
957
|
const factory = dependencies.createDiscordGateway ?? ((options) => new discord_js_1.DiscordGateway(options));
|
|
645
958
|
const active = factory({
|
|
646
959
|
token,
|
|
@@ -662,15 +975,10 @@ async function bootDaemon(options = {}) {
|
|
|
662
975
|
});
|
|
663
976
|
gateways.set('discord', active);
|
|
664
977
|
await active.start();
|
|
665
|
-
stage(logger, 'discord');
|
|
978
|
+
stage(logger, 'discord', options.signal);
|
|
666
979
|
}
|
|
667
980
|
if (config.slack?.enabled) {
|
|
668
|
-
const token =
|
|
669
|
-
const appToken = process.env.MAMA_SLACK_APP_TOKEN;
|
|
670
|
-
if (!token?.trim())
|
|
671
|
-
throw new Error('MAMA_SLACK_TOKEN is required');
|
|
672
|
-
if (!appToken?.trim())
|
|
673
|
-
throw new Error('MAMA_SLACK_APP_TOKEN is required');
|
|
981
|
+
const [token, appToken] = messengerSecrets('slack');
|
|
674
982
|
const factory = dependencies.createSlackGateway ?? ((options) => new slack_js_1.SlackGateway(options));
|
|
675
983
|
const active = factory({
|
|
676
984
|
token,
|
|
@@ -693,7 +1001,7 @@ async function bootDaemon(options = {}) {
|
|
|
693
1001
|
});
|
|
694
1002
|
gateways.set('slack', active);
|
|
695
1003
|
await active.start();
|
|
696
|
-
stage(logger, 'slack');
|
|
1004
|
+
stage(logger, 'slack', options.signal);
|
|
697
1005
|
}
|
|
698
1006
|
const reportRoute = config.delivery?.reports ?? 'telegram';
|
|
699
1007
|
if (gateways.has(reportRoute)) {
|
|
@@ -717,25 +1025,40 @@ async function bootDaemon(options = {}) {
|
|
|
717
1025
|
return receipt;
|
|
718
1026
|
},
|
|
719
1027
|
},
|
|
720
|
-
hasPendingReport: () => Boolean(owner.database.adapter
|
|
721
|
-
.prepare(`SELECT 1 FROM mailbox_inputs m LEFT JOIN native_input_deliveries n ON n.input_id = m.id WHERE m.principal_id = ? AND m.kind = 'scheduled' AND m.channel_key = 'schedule' AND m.status IN ('pending', 'claimed') AND (n.state IS NULL OR n.state != 'uncertain') LIMIT 1`)
|
|
722
|
-
.get(exports.OWNER_PRINCIPAL_ID)),
|
|
1028
|
+
hasPendingReport: (report, hourKey) => Boolean(owner.database.adapter
|
|
1029
|
+
.prepare(`SELECT 1 FROM mailbox_inputs m LEFT JOIN native_input_deliveries n ON n.input_id = m.id WHERE m.principal_id = ? AND m.kind = 'scheduled' AND m.channel_key = 'schedule' AND m.status IN ('pending', 'claimed') AND (n.state IS NULL OR n.state != 'uncertain' OR (json_extract(m.payload_json, '$.report') = ? AND json_extract(m.payload_json, '$.hourKey') = ? AND EXISTS (SELECT 1 FROM native_turn_results r WHERE r.receipt_json = n.receipt_json AND r.principal_id = m.principal_id))) LIMIT 1`)
|
|
1030
|
+
.get(exports.OWNER_PRINCIPAL_ID, report, hourKey)),
|
|
723
1031
|
sendToOwner: (text, key) => gateways.get(reportRoute).sendToOwner(text, key),
|
|
1032
|
+
// Every messenger keys outbound text the same way in the one shared ledger.
|
|
1033
|
+
retireUndelivered: (key) => messageLedger.retireUndelivered((0, telegram_message_ledger_js_1.outboundLedgerKey)(key)),
|
|
1034
|
+
log: (line) => logger.info(line),
|
|
724
1035
|
onError: (error) => logger.error(`report scheduler failed reason=${(0, stimulus_delivery_js_1.stimulusFailureReason)(error)}`),
|
|
725
1036
|
});
|
|
726
1037
|
reportScheduler.start();
|
|
727
|
-
stage(logger, 'report_scheduler');
|
|
1038
|
+
stage(logger, 'report_scheduler', options.signal);
|
|
728
1039
|
}
|
|
729
1040
|
else
|
|
730
|
-
stage(logger, 'report_scheduler:route_unavailable');
|
|
1041
|
+
stage(logger, 'report_scheduler:route_unavailable', options.signal);
|
|
731
1042
|
if (gateway?.sendMemberText) {
|
|
732
1043
|
owner.personalJobs.start();
|
|
733
1044
|
await owner.personalJobs
|
|
734
1045
|
.tick()
|
|
735
1046
|
.catch((error) => logger.error(`personal job scheduler failed reason=${(0, stimulus_delivery_js_1.stimulusFailureReason)(error)}`));
|
|
736
|
-
stage(logger, 'personal_job_scheduler');
|
|
1047
|
+
stage(logger, 'personal_job_scheduler', options.signal);
|
|
737
1048
|
}
|
|
1049
|
+
// Live only: a replay or backfill returned above, and never asks the registry.
|
|
1050
|
+
releaseCheck = (dependencies.createReleaseCheck ?? release_check_js_1.createReleaseCheck)({
|
|
1051
|
+
statePath: (0, release_check_js_1.releaseCheckPath)(paths.mamaRoot),
|
|
1052
|
+
current: (0, package_version_js_1.resolvePackageVersion)(),
|
|
1053
|
+
packageKind: (0, install_kind_js_1.packageKind)((0, install_kind_js_1.runningPackageRoot)()),
|
|
1054
|
+
npmPath: (0, release_check_js_1.npmBesideNode)(),
|
|
1055
|
+
timeZone,
|
|
1056
|
+
log: (line) => logger.info(line),
|
|
1057
|
+
onError: (error) => logger.error(`release check failed error=${errorName(error)}`),
|
|
1058
|
+
});
|
|
1059
|
+
releaseCheck.start();
|
|
738
1060
|
deliveryReady = true;
|
|
1061
|
+
booted = true;
|
|
739
1062
|
return {
|
|
740
1063
|
config,
|
|
741
1064
|
paths,
|
|
@@ -748,7 +1071,16 @@ async function bootDaemon(options = {}) {
|
|
|
748
1071
|
};
|
|
749
1072
|
}
|
|
750
1073
|
catch (error) {
|
|
751
|
-
|
|
1074
|
+
if (error instanceof StopDuringBootError) {
|
|
1075
|
+
logger.info(`boot stopped before stage=${currentStage}`);
|
|
1076
|
+
}
|
|
1077
|
+
else {
|
|
1078
|
+
stageFailed(logger, currentStage, error);
|
|
1079
|
+
// A frozen error keeps its own shape; the stage is still in the log line above.
|
|
1080
|
+
if (error !== null && typeof error === 'object' && Object.isExtensible(error)) {
|
|
1081
|
+
Object.defineProperty(error, 'bootStage', { value: currentStage, enumerable: false });
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
752
1084
|
try {
|
|
753
1085
|
await stopResources();
|
|
754
1086
|
}
|
|
@@ -758,48 +1090,92 @@ async function bootDaemon(options = {}) {
|
|
|
758
1090
|
throw error;
|
|
759
1091
|
}
|
|
760
1092
|
}
|
|
761
|
-
/**
|
|
1093
|
+
/**
|
|
1094
|
+
* Foreground entry for launchd, systemd, Docker or a terminal. Signals are taken before boot, so a
|
|
1095
|
+
* stop during boot unwinds what has started; `mama stop` asks through the control socket.
|
|
1096
|
+
*/
|
|
762
1097
|
async function runDaemon(options = {}) {
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
1098
|
+
const controller = new AbortController();
|
|
1099
|
+
// A stop asked for through `mama stop` exits 0; one by a signal exits 128 + its number, as an
|
|
1100
|
+
// unhandled signal would, so a service that restarts only after a failure brings back a daemon
|
|
1101
|
+
// that was killed (a service manager's own stop does not restart it whatever the code).
|
|
1102
|
+
let signalExit;
|
|
1103
|
+
const requestStop = () => controller.abort();
|
|
1104
|
+
const onSigterm = () => {
|
|
1105
|
+
signalExit = 143;
|
|
1106
|
+
controller.abort();
|
|
1107
|
+
};
|
|
1108
|
+
const onSigint = () => {
|
|
1109
|
+
signalExit = 130;
|
|
1110
|
+
controller.abort();
|
|
1111
|
+
};
|
|
1112
|
+
// Once each: a second signal falls to Node's default and ends the process at once, a force stop;
|
|
1113
|
+
// the operating system releases the install lock with it.
|
|
1114
|
+
process.once('SIGTERM', onSigterm);
|
|
1115
|
+
process.once('SIGINT', onSigint);
|
|
1116
|
+
try {
|
|
1117
|
+
let daemon;
|
|
1118
|
+
try {
|
|
1119
|
+
daemon = await bootDaemon({ ...options, signal: controller.signal, requestStop });
|
|
1120
|
+
}
|
|
1121
|
+
catch (error) {
|
|
1122
|
+
if (error instanceof StopDuringBootError) {
|
|
1123
|
+
if (signalExit !== undefined)
|
|
1124
|
+
process.exitCode = signalExit;
|
|
768
1125
|
return;
|
|
769
|
-
finished = true;
|
|
770
|
-
try {
|
|
771
|
-
await daemon.stop();
|
|
772
|
-
resolve();
|
|
773
|
-
}
|
|
774
|
-
catch (error) {
|
|
775
|
-
reject(error);
|
|
776
1126
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1127
|
+
throw error;
|
|
1128
|
+
}
|
|
1129
|
+
if (!controller.signal.aborted) {
|
|
1130
|
+
await new Promise((resolve) => controller.signal.addEventListener('abort', () => resolve(), { once: true }));
|
|
1131
|
+
}
|
|
1132
|
+
await daemon.stop();
|
|
1133
|
+
if (signalExit !== undefined)
|
|
1134
|
+
process.exitCode = signalExit;
|
|
1135
|
+
}
|
|
1136
|
+
finally {
|
|
1137
|
+
process.off('SIGTERM', onSigterm);
|
|
1138
|
+
process.off('SIGINT', onSigint);
|
|
1139
|
+
}
|
|
781
1140
|
}
|
|
782
|
-
|
|
783
|
-
|
|
1141
|
+
/** The install's control paths from its config path, as boot derives them. */
|
|
1142
|
+
function installControlPaths(options = {}) {
|
|
1143
|
+
const configPath = options.configPath ?? (0, config_js_1.defaultConfigPath)(options.home ?? (0, node_os_1.homedir)());
|
|
1144
|
+
return (0, daemon_control_js_1.daemonControlPaths)((0, node_path_1.dirname)(configPath));
|
|
1145
|
+
}
|
|
1146
|
+
async function askDaemon(op, options = {}) {
|
|
1147
|
+
return await (0, daemon_control_js_1.requestDaemonControl)(installControlPaths(options), op, options.timeoutMs);
|
|
1148
|
+
}
|
|
1149
|
+
/** macOS only: this user's LaunchAgent (`launchctl print` exits 113 when it is not loaded). */
|
|
1150
|
+
function launchdService() {
|
|
1151
|
+
if (process.platform !== 'darwin')
|
|
1152
|
+
return { loaded: false, pid: null };
|
|
1153
|
+
const result = (0, node_child_process_1.spawnSync)('launchctl', ['print', `gui/${process.getuid()}/com.mama.server`], {
|
|
784
1154
|
encoding: 'utf8',
|
|
785
1155
|
});
|
|
786
1156
|
if (result.error)
|
|
787
1157
|
throw result.error;
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
1158
|
+
if (result.status === 113)
|
|
1159
|
+
return { loaded: false, pid: null };
|
|
1160
|
+
if (result.status !== 0) {
|
|
1161
|
+
throw Object.assign(new Error('launchctl print failed'), {
|
|
791
1162
|
code: `LAUNCHCTL_${result.status ?? result.signal ?? 'UNKNOWN'}`,
|
|
792
1163
|
});
|
|
793
1164
|
}
|
|
794
|
-
|
|
795
|
-
}
|
|
796
|
-
function daemonStatus() {
|
|
797
|
-
const result = launchdService('print');
|
|
798
|
-
return result.status === 0 && /^\s*state = running\s*$/m.test(result.stdout)
|
|
799
|
-
? 'running'
|
|
800
|
-
: 'stopped';
|
|
1165
|
+
const pid = /^\s*pid = (\d+)\s*$/m.exec(result.stdout)?.[1];
|
|
1166
|
+
return { loaded: true, pid: pid === undefined ? null : Number(pid) };
|
|
801
1167
|
}
|
|
802
|
-
|
|
803
|
-
|
|
1168
|
+
/** Unload the LaunchAgent so KeepAlive cannot restart it; launchd sends the stop signal. */
|
|
1169
|
+
function bootoutLaunchdService() {
|
|
1170
|
+
const result = (0, node_child_process_1.spawnSync)('launchctl', ['bootout', `gui/${process.getuid()}/com.mama.server`], {
|
|
1171
|
+
encoding: 'utf8',
|
|
1172
|
+
});
|
|
1173
|
+
if (result.error)
|
|
1174
|
+
throw result.error;
|
|
1175
|
+
if (result.status !== 0) {
|
|
1176
|
+
throw Object.assign(new Error('launchctl bootout failed'), {
|
|
1177
|
+
code: `LAUNCHCTL_${result.status ?? result.signal ?? 'UNKNOWN'}`,
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
804
1180
|
}
|
|
805
1181
|
//# sourceMappingURL=daemon.js.map
|