@jungjaehoon/mama-os 0.78.0 → 0.79.1
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 +341 -0
- package/README.md +38 -24
- 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.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 +7 -0
- package/dist/api/viewer-server.d.ts.map +1 -1
- package/dist/api/viewer-server.js +32 -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 +15 -0
- package/dist/api/work-actions.js.map +1 -1
- package/dist/cli/commands/backup.d.ts +7 -6
- package/dist/cli/commands/backup.d.ts.map +1 -1
- package/dist/cli/commands/backup.js +44 -7
- package/dist/cli/commands/backup.js.map +1 -1
- package/dist/cli/commands/control.d.ts +22 -4
- package/dist/cli/commands/control.d.ts.map +1 -1
- package/dist/cli/commands/control.js +172 -11
- package/dist/cli/commands/control.js.map +1 -1
- package/dist/cli/commands/daemon.d.ts +13 -2
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/daemon.js +211 -5
- package/dist/cli/commands/daemon.js.map +1 -1
- package/dist/cli/commands/init-questions.d.ts +110 -0
- package/dist/cli/commands/init-questions.d.ts.map +1 -0
- package/dist/cli/commands/init-questions.js +445 -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 +439 -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 -351
- package/dist/cli/commands/init.js.map +1 -1
- 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 +2 -0
- package/dist/cli/commands/register-owner.js.map +1 -1
- package/dist/cli/commands/restore.d.ts +2 -0
- package/dist/cli/commands/restore.d.ts.map +1 -1
- package/dist/cli/commands/restore.js +7 -0
- package/dist/cli/commands/restore.js.map +1 -1
- package/dist/cli/commands/service.d.ts +16 -0
- package/dist/cli/commands/service.d.ts.map +1 -1
- package/dist/cli/commands/service.js +36 -8
- package/dist/cli/commands/service.js.map +1 -1
- 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.map +1 -1
- package/dist/cli/commands/uninstall.js +123 -15
- package/dist/cli/commands/uninstall.js.map +1 -1
- 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 +8 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/launch-files.d.ts +36 -0
- package/dist/cli/launch-files.d.ts.map +1 -1
- package/dist/cli/launch-files.js +94 -1
- 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/backup.d.ts +17 -1
- package/dist/cli/runtime/backup.d.ts.map +1 -1
- package/dist/cli/runtime/backup.js +32 -4
- package/dist/cli/runtime/backup.js.map +1 -1
- package/dist/cli/runtime/daemon-control.d.ts +92 -7
- package/dist/cli/runtime/daemon-control.d.ts.map +1 -1
- package/dist/cli/runtime/daemon-control.js +183 -8
- package/dist/cli/runtime/daemon-control.js.map +1 -1
- 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 +25 -0
- package/dist/cli/runtime/diagnostics.d.ts.map +1 -1
- package/dist/cli/runtime/diagnostics.js +250 -63
- package/dist/cli/runtime/diagnostics.js.map +1 -1
- 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/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/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 +5 -0
- package/dist/connectors/config-loader.d.ts.map +1 -1
- package/dist/connectors/config-loader.js +8 -0
- 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/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/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 +23 -2
- package/dist/runtime/backend-security.d.ts.map +1 -1
- package/dist/runtime/backend-security.js +50 -5
- package/dist/runtime/backend-security.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 +0 -1
- 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/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/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 +3 -4
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultRoots = defaultRoots;
|
|
4
|
+
exports.prepareRoot = prepareRoot;
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_os_1 = require("node:os");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const prompt_js_1 = require("../prompt.js");
|
|
9
|
+
/**
|
|
10
|
+
* Where a new install keeps its member folders and its document tools: outside HOME, one place
|
|
11
|
+
* per person on the machine (plan decision 3). On macOS a folder of this user's sits directly in
|
|
12
|
+
* the sticky Shared folder beside the home folders, so no account uses a parent another set up;
|
|
13
|
+
* on Linux it is /var/lib/mama/<user>, which the installer creates once with sudo.
|
|
14
|
+
*/
|
|
15
|
+
function defaultRoots(options = {}) {
|
|
16
|
+
const platform = options.platform ?? process.platform;
|
|
17
|
+
const user = options.user ?? (0, node_os_1.userInfo)().username;
|
|
18
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(user))
|
|
19
|
+
return undefined;
|
|
20
|
+
const base = platform === 'darwin'
|
|
21
|
+
? (0, node_path_1.join)((0, node_path_1.dirname)(options.home ?? (0, node_os_1.homedir)()), 'Shared', `mama-${user}`)
|
|
22
|
+
: platform === 'linux'
|
|
23
|
+
? (0, node_path_1.join)('/var/lib/mama', user)
|
|
24
|
+
: undefined;
|
|
25
|
+
return base === undefined
|
|
26
|
+
? undefined
|
|
27
|
+
: { memberRoot: (0, node_path_1.join)(base, 'members'), toolsRoot: (0, node_path_1.join)(base, 'tools') };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Make a root that this user alone owns and writes, or refuse one that is not: the agent runs
|
|
31
|
+
* what tools_root holds and reads what member_root holds, and the Shared folder lets any account
|
|
32
|
+
* create a folder first. `ownParent` also checks the per-user folder a default sits in. A root
|
|
33
|
+
* this account cannot create (Linux's /var/lib/mama) names the one sudo step that makes its
|
|
34
|
+
* per-user folder; the subfolders are made here.
|
|
35
|
+
*/
|
|
36
|
+
function prepareRoot(path, options = {}) {
|
|
37
|
+
const uid = options.uid ?? process.getuid?.();
|
|
38
|
+
if (!(0, node_fs_1.existsSync)(path)) {
|
|
39
|
+
try {
|
|
40
|
+
(0, node_fs_1.mkdirSync)(path, { recursive: true, mode: 0o700 });
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const code = error.code;
|
|
44
|
+
if (code !== 'EACCES' && code !== 'EPERM' && code !== 'EROFS')
|
|
45
|
+
throw error;
|
|
46
|
+
const folder = options.ownParent ? (0, node_path_1.dirname)(path) : path;
|
|
47
|
+
throw new prompt_js_1.CliInputError(`${path} cannot be created. Create ${folder} for this account once: sudo install -d -o "$USER" -m 0700 ${folder}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
for (const folder of options.ownParent ? [(0, node_path_1.dirname)(path), path] : [path]) {
|
|
51
|
+
const stat = (0, node_fs_1.lstatSync)(folder);
|
|
52
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
53
|
+
throw new prompt_js_1.CliInputError(`${folder} must be a folder, not a link or a file`);
|
|
54
|
+
if (uid !== undefined && stat.uid !== uid)
|
|
55
|
+
throw new prompt_js_1.CliInputError(`${folder} belongs to another account; choose another folder`);
|
|
56
|
+
if ((stat.mode & 0o022) !== 0)
|
|
57
|
+
throw new prompt_js_1.CliInputError(`${folder} can be written by other accounts; run chmod 700 on it`);
|
|
58
|
+
}
|
|
59
|
+
(0, node_fs_1.accessSync)(path, node_fs_1.constants.W_OK);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=default-roots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-roots.js","sourceRoot":"","sources":["../../../src/cli/runtime/default-roots.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,12 @@ export interface Check {
|
|
|
12
12
|
readonly context?: string;
|
|
13
13
|
/** What to do about a warn or fail. */
|
|
14
14
|
readonly fix?: string;
|
|
15
|
+
/**
|
|
16
|
+
* A stable name for this finding where its detail carries values that an update or a backend
|
|
17
|
+
* self-update changes (versions, schema numbers). A check without one is the same finding
|
|
18
|
+
* while its name and detail are; `mama update` compares failures before and after by these.
|
|
19
|
+
*/
|
|
20
|
+
readonly code?: string;
|
|
15
21
|
}
|
|
16
22
|
export interface DiagnosticsOptions {
|
|
17
23
|
home?: string;
|
|
@@ -24,6 +30,8 @@ export interface DiagnosticsOptions {
|
|
|
24
30
|
/** A Telegram Bot API call; tests replace it. */
|
|
25
31
|
telegramCall?: (token: string, method: string, params?: Record<string, string>) => Promise<Record<string, unknown>>;
|
|
26
32
|
findIn?: (name: string, dirs: string[]) => string | undefined;
|
|
33
|
+
/** Where this shell finds a command; tests replace it. */
|
|
34
|
+
findExecutable?: (name: string) => string | undefined;
|
|
27
35
|
/** Ask the install's daemon for its status; tests replace it. */
|
|
28
36
|
askStatus?: () => Promise<DaemonControlReply>;
|
|
29
37
|
/** Builds a source as boot does; tests replace it so no source reaches the network. */
|
|
@@ -33,6 +41,12 @@ export interface DiagnosticsOptions {
|
|
|
33
41
|
/** Whether something listens on the viewer's address; tests replace it. */
|
|
34
42
|
portInUse?: (port: number, host: string) => Promise<boolean>;
|
|
35
43
|
}
|
|
44
|
+
/** auth.env's assignments, unquoted as sh reads them; values are never printed. */
|
|
45
|
+
export declare function readAuthEnv(root: string): Record<string, string>;
|
|
46
|
+
export declare function defaultTelegramCall(token: string, method: string, params?: Record<string, string>, timeoutMs?: number): Promise<Record<string, unknown>>;
|
|
47
|
+
/** True when something listens; a refusal means free; any other error (a host that cannot be
|
|
48
|
+
* reached or bound) rejects, since the viewer would fail on it too. */
|
|
49
|
+
export declare function portAnswers(port: number, host: string): Promise<boolean>;
|
|
36
50
|
/**
|
|
37
51
|
* Check an install as its service would run it. Nothing here writes MAMA's files or starts a
|
|
38
52
|
* service; the database is opened read-only (which can leave its -wal and -shm beside it), and the
|
|
@@ -40,4 +54,15 @@ export interface DiagnosticsOptions {
|
|
|
40
54
|
* Each check names what it found and, when it is not ok, what to do.
|
|
41
55
|
*/
|
|
42
56
|
export declare function runDiagnostics(options?: DiagnosticsOptions): Promise<Check[]>;
|
|
57
|
+
/**
|
|
58
|
+
* start.sh's Node: still there, outside one version's folder, and able to load MAMA's SQLite. On
|
|
59
|
+
* an install the install command made (its Node in `<root>/node`), also the Node the installed
|
|
60
|
+
* release pins in its install/node.json: running the install command again moves to that one.
|
|
61
|
+
*/
|
|
62
|
+
export declare function nodeCheck(node: string, cli: string, run: ProbeRun, root: string): Check;
|
|
63
|
+
export declare function telegramCheck(token: string | undefined, commonChat: string | number | undefined, call: NonNullable<DiagnosticsOptions['telegramCall']>): Promise<Check>;
|
|
64
|
+
/** The environment start.sh gives the daemon: auth.env, then its own exports, then its PATH. */
|
|
65
|
+
export declare function serviceEnvironment(home: string, auth: Record<string, string>, exports: Record<string, string>, path: readonly string[]): NodeJS.ProcessEnv;
|
|
66
|
+
/** Run with process.env as the daemon's process has it, then put this shell's back. */
|
|
67
|
+
export declare function withEnvironment<T>(env: NodeJS.ProcessEnv, run: () => Promise<T>): Promise<T>;
|
|
43
68
|
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../../src/cli/runtime/diagnostics.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../../src/cli/runtime/diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readAuthEnv = readAuthEnv;
|
|
4
|
+
exports.defaultTelegramCall = defaultTelegramCall;
|
|
5
|
+
exports.portAnswers = portAnswers;
|
|
3
6
|
exports.runDiagnostics = runDiagnostics;
|
|
7
|
+
exports.nodeCheck = nodeCheck;
|
|
8
|
+
exports.telegramCheck = telegramCheck;
|
|
9
|
+
exports.serviceEnvironment = serviceEnvironment;
|
|
10
|
+
exports.withEnvironment = withEnvironment;
|
|
4
11
|
const node_fs_1 = require("node:fs");
|
|
5
12
|
const node_module_1 = require("node:module");
|
|
6
13
|
const node_net_1 = require("node:net");
|
|
@@ -15,28 +22,19 @@ const timezone_js_1 = require("../../runtime/timezone.js");
|
|
|
15
22
|
const document_toolkit_js_1 = require("../../tools/document-toolkit.js");
|
|
16
23
|
const launch_files_js_1 = require("../launch-files.js");
|
|
17
24
|
const rotating_log_js_1 = require("../../runtime/rotating-log.js");
|
|
18
|
-
const secrets_js_1 = require("../secrets.js");
|
|
19
25
|
const daemon_js_1 = require("../commands/daemon.js");
|
|
20
26
|
const backend_probe_js_1 = require("./backend-probe.js");
|
|
21
27
|
const daemon_control_js_1 = require("./daemon-control.js");
|
|
28
|
+
const release_check_js_1 = require("./release-check.js");
|
|
29
|
+
const install_kind_js_1 = require("./install-kind.js");
|
|
30
|
+
const source_tools_js_1 = require("./source-tools.js");
|
|
31
|
+
const node_move_journal_js_1 = require("./node-move-journal.js");
|
|
32
|
+
const update_journal_js_1 = require("./update-journal.js");
|
|
22
33
|
const db_manager_1 = require("@jungjaehoon/mama-core/db-manager");
|
|
23
34
|
const migrations_source_js_1 = require("../../storage/migrations-source.js");
|
|
24
35
|
const systemd_service_js_1 = require("./systemd-service.js");
|
|
25
|
-
/** The PATH a service manager gives a unit that does not set one ($PATH in start.sh). */
|
|
26
|
-
const SERVICE_DEFAULT_PATH = {
|
|
27
|
-
darwin: ['/usr/bin', '/bin', '/usr/sbin', '/sbin'],
|
|
28
|
-
linux: ['/usr/local/sbin', '/usr/local/bin', '/usr/sbin', '/usr/bin', '/sbin', '/bin'],
|
|
29
|
-
};
|
|
30
36
|
/** systemd states of an installed unit that can be started or is running. */
|
|
31
37
|
const SYSTEMD_USABLE = new Set(['active', 'inactive', 'activating', 'deactivating', 'reloading']);
|
|
32
|
-
function findIn(name, dirs) {
|
|
33
|
-
for (const dir of dirs) {
|
|
34
|
-
const path = (0, node_path_1.join)(dir, name);
|
|
35
|
-
if ((0, node_fs_1.existsSync)(path))
|
|
36
|
-
return path;
|
|
37
|
-
}
|
|
38
|
-
return undefined;
|
|
39
|
-
}
|
|
40
38
|
function message(error) {
|
|
41
39
|
return error instanceof Error ? error.message : String(error);
|
|
42
40
|
}
|
|
@@ -64,9 +62,9 @@ function readAuthEnv(root) {
|
|
|
64
62
|
});
|
|
65
63
|
return values;
|
|
66
64
|
}
|
|
67
|
-
async function defaultTelegramCall(token, method, params = {}) {
|
|
65
|
+
async function defaultTelegramCall(token, method, params = {}, timeoutMs = 8_000) {
|
|
68
66
|
const query = new URLSearchParams(params).toString();
|
|
69
|
-
const response = await fetch(`https://api.telegram.org/bot${token}/${method}${query ? `?${query}` : ''}`, { signal: AbortSignal.timeout(
|
|
67
|
+
const response = await fetch(`https://api.telegram.org/bot${token}/${method}${query ? `?${query}` : ''}`, { signal: AbortSignal.timeout(timeoutMs) });
|
|
70
68
|
return (await response.json());
|
|
71
69
|
}
|
|
72
70
|
/** True when something listens; a refusal means free; any other error (a host that cannot be
|
|
@@ -85,10 +83,18 @@ function portAnswers(port, host) {
|
|
|
85
83
|
socket.once('error', (error) => error.code === 'ECONNREFUSED' ? resolve(false) : reject(error));
|
|
86
84
|
});
|
|
87
85
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
/**
|
|
87
|
+
* A source's tokens are entered on the setup page by the sources section, run again for that
|
|
88
|
+
* source, which needs no terminal (install.md, W2.4.5e). Every token source is built only with
|
|
89
|
+
* the token name it reads, which auth.env holds. The page asks again for a `stored` token only
|
|
90
|
+
* when MAMA_INIT_REPLACE_SECRETS names it (#552).
|
|
91
|
+
*/
|
|
92
|
+
function sourceSecretFixes(source, names, mama, stored) {
|
|
93
|
+
return names.length === 0
|
|
94
|
+
? []
|
|
95
|
+
: [
|
|
96
|
+
`with MAMA stopped, run ${mama} init --section connectors --non-interactive with ${source}'s block from connectors.json in MAMA_INIT_CONNECTORS${stored ? ` and MAMA_INIT_REPLACE_SECRETS=${names.join(',')}` : ''}; its setup page takes ${names.join(' and ')}`,
|
|
97
|
+
];
|
|
92
98
|
}
|
|
93
99
|
/**
|
|
94
100
|
* Check an install as its service would run it. Nothing here writes MAMA's files or starts a
|
|
@@ -102,7 +108,7 @@ async function runDiagnostics(options = {}) {
|
|
|
102
108
|
const root = (0, node_path_1.dirname)(configPath);
|
|
103
109
|
const platform = options.platform ?? process.platform;
|
|
104
110
|
const run = options.run ?? backend_probe_js_1.defaultProbeRun;
|
|
105
|
-
const locate = options.findIn ?? findIn;
|
|
111
|
+
const locate = options.findIn ?? launch_files_js_1.findIn;
|
|
106
112
|
const checks = [];
|
|
107
113
|
if ((0, node_fs_1.existsSync)((0, daemon_control_js_1.restoreJournalPath)(root))) {
|
|
108
114
|
checks.push({
|
|
@@ -112,6 +118,7 @@ async function runDiagnostics(options = {}) {
|
|
|
112
118
|
fix: 'mama restore --rollback',
|
|
113
119
|
});
|
|
114
120
|
}
|
|
121
|
+
checks.push(...updateChecks(root, home));
|
|
115
122
|
let config = null;
|
|
116
123
|
// Setting names can be anything the owner typed, so they stay out of the report.
|
|
117
124
|
let ignored = [];
|
|
@@ -149,7 +156,10 @@ async function runDiagnostics(options = {}) {
|
|
|
149
156
|
}
|
|
150
157
|
// What the service runs: the start script's Node, PATH and exports, not this shell's.
|
|
151
158
|
const startPath = (0, node_path_1.join)(root, 'start.sh');
|
|
152
|
-
let servicePath =
|
|
159
|
+
let servicePath = (0, launch_files_js_1.startScriptPath)(null, home, platform);
|
|
160
|
+
// The Node start.sh runs: on an install the install command made, a source's tool installs
|
|
161
|
+
// beside MAMA with that Node (install.md, PR 3).
|
|
162
|
+
let serviceNode = null;
|
|
153
163
|
let exports = {};
|
|
154
164
|
// A script mama did not write is assumed to load auth.env; a generated one must still.
|
|
155
165
|
let loadsAuth = true;
|
|
@@ -186,13 +196,9 @@ async function runDiagnostics(options = {}) {
|
|
|
186
196
|
fix: 'mama service install --replace rewrites it',
|
|
187
197
|
});
|
|
188
198
|
}
|
|
189
|
-
|
|
190
|
-
servicePath = [
|
|
191
|
-
...(0, launch_files_js_1.startPathValue)(reading.path, home),
|
|
192
|
-
...(/\$\{?PATH\}?/.test(reading.path) ? servicePath : []),
|
|
193
|
-
];
|
|
194
|
-
}
|
|
199
|
+
servicePath = (0, launch_files_js_1.startScriptPath)(reading, home, platform);
|
|
195
200
|
const [, node, cli] = reading.exec === null ? [] : (0, launch_files_js_1.shellWords)(reading.exec);
|
|
201
|
+
serviceNode = node ?? null;
|
|
196
202
|
if (!reading.generated) {
|
|
197
203
|
checks.push({
|
|
198
204
|
name: 'start.sh',
|
|
@@ -210,7 +216,7 @@ async function runDiagnostics(options = {}) {
|
|
|
210
216
|
});
|
|
211
217
|
}
|
|
212
218
|
else {
|
|
213
|
-
checks.push(nodeCheck(node, cli, run));
|
|
219
|
+
checks.push(nodeCheck(node, cli, run, root));
|
|
214
220
|
}
|
|
215
221
|
}
|
|
216
222
|
catch (error) {
|
|
@@ -238,14 +244,7 @@ async function runDiagnostics(options = {}) {
|
|
|
238
244
|
fix: `correct the quoting in ${(0, node_path_1.join)(root, 'auth.env')}`,
|
|
239
245
|
});
|
|
240
246
|
}
|
|
241
|
-
const serviceEnv =
|
|
242
|
-
HOME: home,
|
|
243
|
-
USER: process.env.USER,
|
|
244
|
-
LOGNAME: process.env.LOGNAME,
|
|
245
|
-
...auth,
|
|
246
|
-
...exports,
|
|
247
|
-
PATH: servicePath.join(':'),
|
|
248
|
-
};
|
|
247
|
+
const serviceEnv = serviceEnvironment(home, auth, exports, servicePath);
|
|
249
248
|
const secret = (name) => Boolean(serviceEnv[name]?.trim());
|
|
250
249
|
if (config) {
|
|
251
250
|
const backend = config.agent.backend;
|
|
@@ -268,6 +267,7 @@ async function runDiagnostics(options = {}) {
|
|
|
268
267
|
name: 'backend',
|
|
269
268
|
status: 'fail',
|
|
270
269
|
detail: probe.problem ?? `${backend} ${probe.version} is older than ${probe.minimum}`,
|
|
270
|
+
...(probe.problem === null ? { code: 'backend.too_old' } : {}),
|
|
271
271
|
fix: `update ${backend} to ${probe.minimum} or newer`,
|
|
272
272
|
});
|
|
273
273
|
}
|
|
@@ -276,6 +276,7 @@ async function runDiagnostics(options = {}) {
|
|
|
276
276
|
name: 'backend',
|
|
277
277
|
status: 'fail',
|
|
278
278
|
detail: `${backend} ${probe.version} is not signed in for the service`,
|
|
279
|
+
code: 'backend.signed_out',
|
|
279
280
|
fix: backend === 'claude' ? 'claude auth login' : `CODEX_HOME='${codexHome}' codex login`,
|
|
280
281
|
});
|
|
281
282
|
}
|
|
@@ -299,7 +300,7 @@ async function runDiagnostics(options = {}) {
|
|
|
299
300
|
name: messenger,
|
|
300
301
|
status: 'fail',
|
|
301
302
|
detail: `${missing.join(' and ')} not set; boot stops at the messengers stage`,
|
|
302
|
-
fix: missing.map(
|
|
303
|
+
fix: missing.map((name) => `mama secret set ${name}`).join('; '),
|
|
303
304
|
});
|
|
304
305
|
}
|
|
305
306
|
else if (messenger === 'telegram' && !options.offline) {
|
|
@@ -309,7 +310,10 @@ async function runDiagnostics(options = {}) {
|
|
|
309
310
|
checks.push({ name: messenger, status: 'ok', detail: 'secrets set' });
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
|
-
checks.push(...(await sourceChecks(config, configPath,
|
|
313
|
+
checks.push(...(await sourceChecks(config, configPath, locate, secret, {
|
|
314
|
+
service: { path: servicePath, nodePath: serviceNode, exports },
|
|
315
|
+
findShell: options.findExecutable ?? launch_files_js_1.findExecutable,
|
|
316
|
+
home,
|
|
313
317
|
env: serviceEnv,
|
|
314
318
|
online: !options.offline,
|
|
315
319
|
load: options.loadSource ?? index_js_1.loadConnector,
|
|
@@ -332,6 +336,7 @@ async function runDiagnostics(options = {}) {
|
|
|
332
336
|
}
|
|
333
337
|
checks.push(...(await daemonChecks(options.askStatus ?? (() => (0, daemon_js_1.askDaemon)('status', { home, configPath })), port, serviceEnv.MAMA_API_HOST ?? '127.0.0.1', options.portInUse ?? portAnswers)));
|
|
334
338
|
checks.push(serviceCheck(platform, home, options.serviceRun ?? systemd_service_js_1.defaultServiceRun));
|
|
339
|
+
checks.push(releaseCheck(root, home));
|
|
335
340
|
// Each log against its own cap: the daemon rotates daemon.log and security-events.jsonl before
|
|
336
341
|
// they pass theirs, and start.sh empties crash.log at start past its own.
|
|
337
342
|
for (const [name, path, cap] of [
|
|
@@ -416,6 +421,7 @@ function schemaCheck(databasePath) {
|
|
|
416
421
|
name: 'schema',
|
|
417
422
|
status: 'fail',
|
|
418
423
|
detail: `the database is newer than this MAMA (${summary}); boot refuses it`,
|
|
424
|
+
code: 'schema.newer',
|
|
419
425
|
fix: 'install the version that wrote it, or mama restore a backup taken with this one',
|
|
420
426
|
};
|
|
421
427
|
}
|
|
@@ -436,8 +442,12 @@ function schemaCheck(databasePath) {
|
|
|
436
442
|
};
|
|
437
443
|
}
|
|
438
444
|
}
|
|
439
|
-
/**
|
|
440
|
-
|
|
445
|
+
/**
|
|
446
|
+
* start.sh's Node: still there, outside one version's folder, and able to load MAMA's SQLite. On
|
|
447
|
+
* an install the install command made (its Node in `<root>/node`), also the Node the installed
|
|
448
|
+
* release pins in its install/node.json: running the install command again moves to that one.
|
|
449
|
+
*/
|
|
450
|
+
function nodeCheck(node, cli, run, root) {
|
|
441
451
|
const rewrite = 'mama service install rewrites start.sh with a Node path that survives upgrades';
|
|
442
452
|
if (!(0, node_fs_1.existsSync)(node)) {
|
|
443
453
|
return {
|
|
@@ -497,6 +507,29 @@ function nodeCheck(node, cli, run) {
|
|
|
497
507
|
: 'run mama service install from a shell whose node is not an nvm, volta or fnm version',
|
|
498
508
|
};
|
|
499
509
|
}
|
|
510
|
+
if (node === (0, node_move_journal_js_1.managedNodePath)(root)) {
|
|
511
|
+
const packageRoot = (0, install_kind_js_1.packageRootOf)(cli);
|
|
512
|
+
if (packageRoot === null) {
|
|
513
|
+
return {
|
|
514
|
+
name: 'node',
|
|
515
|
+
status: 'fail',
|
|
516
|
+
detail: 'the MAMA command start.sh runs is not inside a MAMA OS package',
|
|
517
|
+
context: cli,
|
|
518
|
+
fix: 'run the install command again',
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
const pin = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(packageRoot, 'install', 'node.json'), 'utf8')).version;
|
|
522
|
+
if (version !== `v${pin}`) {
|
|
523
|
+
return {
|
|
524
|
+
name: 'node',
|
|
525
|
+
status: 'warn',
|
|
526
|
+
detail: `start.sh runs ${version}; this release pins Node.js ${pin}`,
|
|
527
|
+
code: 'node.pin',
|
|
528
|
+
context: node,
|
|
529
|
+
fix: `run the install command again, which moves it: ${node_move_journal_js_1.INSTALL_COMMAND}`,
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
}
|
|
500
533
|
return { name: 'node', status: 'ok', detail: `${version} loads SQLite`, context: node };
|
|
501
534
|
}
|
|
502
535
|
function sandboxCheck(platform, servicePath, locate, run) {
|
|
@@ -619,8 +652,12 @@ async function telegramCheck(token, commonChat, call) {
|
|
|
619
652
|
: 'token valid; a member of the common group that reads its messages',
|
|
620
653
|
};
|
|
621
654
|
}
|
|
655
|
+
/** The secrets a source's requirements name. */
|
|
656
|
+
function secretNames(needs) {
|
|
657
|
+
return needs.flatMap((need) => need.type === 'token' && need.tokenName !== undefined ? [need.tokenName] : []);
|
|
658
|
+
}
|
|
622
659
|
/** connectors.json as the connector runtime reads it, and what each enabled source needs. */
|
|
623
|
-
async function sourceChecks(config, configPath,
|
|
660
|
+
async function sourceChecks(config, configPath, locate, secret, start) {
|
|
624
661
|
const paths = (0, daemon_js_1.pathsFor)(configPath, config);
|
|
625
662
|
let plan;
|
|
626
663
|
try {
|
|
@@ -646,14 +683,17 @@ async function sourceChecks(config, configPath, servicePath, locate, secret, sta
|
|
|
646
683
|
}
|
|
647
684
|
const checks = [];
|
|
648
685
|
const timeZone = (0, timezone_js_1.createTimeZoneSetting)(config.timezone);
|
|
686
|
+
const loaded = [];
|
|
649
687
|
for (const name of plan.enabledConnectorNames) {
|
|
650
|
-
let connector;
|
|
651
688
|
try {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
689
|
+
loaded.push({
|
|
690
|
+
name,
|
|
691
|
+
connector: await start.load(name, plan.config.config[name], (0, connectors_js_1.connectorLoadPaths)(name, {
|
|
692
|
+
statePath: paths.connectorsRoot,
|
|
693
|
+
kagemushaDbPath: paths.kagemushaDbPath,
|
|
694
|
+
timeZone,
|
|
695
|
+
})),
|
|
696
|
+
});
|
|
657
697
|
}
|
|
658
698
|
catch (error) {
|
|
659
699
|
checks.push({
|
|
@@ -662,26 +702,39 @@ async function sourceChecks(config, configPath, servicePath, locate, secret, sta
|
|
|
662
702
|
detail: 'cannot be built from connectors.json; boot stops at the connectors stage',
|
|
663
703
|
context: message(error),
|
|
664
704
|
});
|
|
665
|
-
continue;
|
|
666
705
|
}
|
|
667
|
-
|
|
706
|
+
}
|
|
707
|
+
const enabled = loaded.map(({ name, connector }) => ({
|
|
708
|
+
name,
|
|
709
|
+
connector,
|
|
710
|
+
needs: connector.getAuthRequirements(),
|
|
711
|
+
}));
|
|
712
|
+
for (const { name, connector, needs } of enabled) {
|
|
668
713
|
// A secret's name can carry an owner's channel key (iCal), so it stays out of the report.
|
|
669
|
-
const secrets = needs.
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
714
|
+
const secrets = secretNames(needs).filter((tokenName) => !secret(tokenName));
|
|
715
|
+
const tools = (0, source_tools_js_1.sourceTools)([{ name, needs }], start.service, { root: (0, node_path_1.dirname)(configPath), home: start.home }, { inDirs: locate, shell: start.findShell },
|
|
716
|
+
// One login of a tool serves every source that runs it, so it names what all of them need.
|
|
717
|
+
enabled);
|
|
718
|
+
const missing = tools.filter((tool) => tool.servicePath === null);
|
|
719
|
+
// Paths stay out of `detail`, which --report shares.
|
|
720
|
+
const context = [
|
|
721
|
+
...(secrets.length > 0 ? [secrets.join(', ')] : []),
|
|
722
|
+
...missing.flatMap(({ tool, shellPath }) => shellPath === null ? [] : [`this shell finds ${tool.command} at ${shellPath}`]),
|
|
723
|
+
];
|
|
724
|
+
if (secrets.length > 0 || missing.length > 0) {
|
|
674
725
|
checks.push({
|
|
675
726
|
name: `source ${name}`,
|
|
676
727
|
status: 'fail',
|
|
677
728
|
detail: [
|
|
678
729
|
...(secrets.length > 0 ? [`${secrets.length} secret(s) it needs are not set`] : []),
|
|
679
|
-
...
|
|
730
|
+
...missing.map(({ tool }) => `the ${tool.command} command is not on the service's PATH`),
|
|
680
731
|
].join('; '),
|
|
681
|
-
...(
|
|
732
|
+
...(context.length > 0 ? { context: context.join('; ') } : {}),
|
|
682
733
|
fix: [
|
|
683
|
-
...secrets.
|
|
684
|
-
...
|
|
734
|
+
...sourceSecretFixes(name, secrets, (0, launch_files_js_1.mamaCommand)((0, node_path_1.dirname)(configPath)), false),
|
|
735
|
+
...missing.map(({ shellPath, install, login }) => shellPath === null
|
|
736
|
+
? `install it: ${install.join(' or ')}; then log in: ${login}`
|
|
737
|
+
: `mama service install adds ${(0, node_path_1.dirname)(shellPath)} to start.sh's PATH, mama service restart applies it; then log in: ${login}`),
|
|
685
738
|
].join('; '),
|
|
686
739
|
});
|
|
687
740
|
continue;
|
|
@@ -702,6 +755,9 @@ async function sourceChecks(config, configPath, servicePath, locate, secret, sta
|
|
|
702
755
|
status: 'fail',
|
|
703
756
|
detail: 'does not start; boot stops at the connectors stage',
|
|
704
757
|
context: message(error),
|
|
758
|
+
// The tool is on the service's PATH here, so a source that runs one most often
|
|
759
|
+
// lacks its sign-in or a scope (Calendar's read check).
|
|
760
|
+
...(tools.length > 0 ? { fix: tools.map(({ login }) => login).join('; ') } : {}),
|
|
705
761
|
};
|
|
706
762
|
return;
|
|
707
763
|
}
|
|
@@ -710,10 +766,10 @@ async function sourceChecks(config, configPath, servicePath, locate, secret, sta
|
|
|
710
766
|
name: `source ${name}`,
|
|
711
767
|
status: 'fail',
|
|
712
768
|
detail: 'starts, but its credentials or sign-in are refused, so its polls fail',
|
|
713
|
-
fix:
|
|
714
|
-
.map((
|
|
715
|
-
.
|
|
716
|
-
|
|
769
|
+
fix: [
|
|
770
|
+
...tools.map(({ login }) => login),
|
|
771
|
+
...sourceSecretFixes(name, secretNames(needs), (0, launch_files_js_1.mamaCommand)((0, node_path_1.dirname)(configPath)), true),
|
|
772
|
+
].join('; ') || undefined,
|
|
717
773
|
};
|
|
718
774
|
}
|
|
719
775
|
}));
|
|
@@ -745,6 +801,17 @@ function bounded(ms, run) {
|
|
|
745
801
|
}),
|
|
746
802
|
]).finally(() => clearTimeout(timer));
|
|
747
803
|
}
|
|
804
|
+
/** The environment start.sh gives the daemon: auth.env, then its own exports, then its PATH. */
|
|
805
|
+
function serviceEnvironment(home, auth, exports, path) {
|
|
806
|
+
return {
|
|
807
|
+
HOME: home,
|
|
808
|
+
USER: process.env.USER,
|
|
809
|
+
LOGNAME: process.env.LOGNAME,
|
|
810
|
+
...auth,
|
|
811
|
+
...exports,
|
|
812
|
+
PATH: path.join(':'),
|
|
813
|
+
};
|
|
814
|
+
}
|
|
748
815
|
/** Run with process.env as the daemon's process has it, then put this shell's back. */
|
|
749
816
|
async function withEnvironment(env, run) {
|
|
750
817
|
const saved = { ...process.env };
|
|
@@ -903,6 +970,126 @@ async function daemonChecks(ask, port, host, portInUse) {
|
|
|
903
970
|
}
|
|
904
971
|
return checks;
|
|
905
972
|
}
|
|
973
|
+
/**
|
|
974
|
+
* An unfinished `mama update --node` (docs/development/work/install.md, "Moving the managed
|
|
975
|
+
* Node"): its journal, which the install command finishes or undoes. It holds the install on
|
|
976
|
+
* update.hold, so it comes before the hold's own check.
|
|
977
|
+
*/
|
|
978
|
+
function nodeMoveCheck(root) {
|
|
979
|
+
const path = (0, node_move_journal_js_1.nodeMovePlaces)(root).journal;
|
|
980
|
+
let journal;
|
|
981
|
+
try {
|
|
982
|
+
journal = (0, node_move_journal_js_1.readNodeMoveJournal)(path);
|
|
983
|
+
}
|
|
984
|
+
catch (error) {
|
|
985
|
+
return {
|
|
986
|
+
name: 'update',
|
|
987
|
+
status: 'fail',
|
|
988
|
+
detail: 'an unfinished move of the managed Node left a journal that cannot be read',
|
|
989
|
+
code: 'node_move.open',
|
|
990
|
+
context: message(error),
|
|
991
|
+
fix: `read ${path}; the install command's recovery needs it`,
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
if (journal === null)
|
|
995
|
+
return null;
|
|
996
|
+
return {
|
|
997
|
+
name: 'update',
|
|
998
|
+
status: 'fail',
|
|
999
|
+
detail: journal.phase === 'committed'
|
|
1000
|
+
? `the move of the managed Node to ${journal.to} took effect, but its old folders are not removed yet`
|
|
1001
|
+
: `the move of the managed Node from ${journal.from} to ${journal.to} is unfinished (step ${journal.step}); the daemon may stay stopped until it is finished or undone`,
|
|
1002
|
+
code: 'node_move.open',
|
|
1003
|
+
context: path,
|
|
1004
|
+
fix: `run the install command again, which finishes or undoes it: ${node_move_journal_js_1.INSTALL_COMMAND}`,
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* An unfinished `mama update`: its journal (docs/development/work/update.md, PR 3), with the
|
|
1009
|
+
* command that resolves it by absolute paths, or a staging prefix an updater killed before it
|
|
1010
|
+
* wrote its journal left behind.
|
|
1011
|
+
*/
|
|
1012
|
+
function updateChecks(root, home) {
|
|
1013
|
+
const move = nodeMoveCheck(root);
|
|
1014
|
+
if (move !== null)
|
|
1015
|
+
return [move];
|
|
1016
|
+
const path = (0, update_journal_js_1.updatePaths)(root).journal;
|
|
1017
|
+
let journal;
|
|
1018
|
+
try {
|
|
1019
|
+
journal = (0, update_journal_js_1.readUpdateJournal)(path);
|
|
1020
|
+
}
|
|
1021
|
+
catch (error) {
|
|
1022
|
+
return [
|
|
1023
|
+
{
|
|
1024
|
+
name: 'update',
|
|
1025
|
+
status: 'fail',
|
|
1026
|
+
detail: 'an unfinished update left a journal that cannot be read',
|
|
1027
|
+
code: 'update.open',
|
|
1028
|
+
context: message(error),
|
|
1029
|
+
fix: `read ${path}; mama update --rollback needs it`,
|
|
1030
|
+
},
|
|
1031
|
+
];
|
|
1032
|
+
}
|
|
1033
|
+
if (journal !== null) {
|
|
1034
|
+
return [
|
|
1035
|
+
{
|
|
1036
|
+
name: 'update',
|
|
1037
|
+
status: 'fail',
|
|
1038
|
+
detail: journal.phase === 'committed'
|
|
1039
|
+
? `the update to ${journal.to} took effect, but it was not finished: its inputs may stay held, and nothing runs until the command below finishes it`
|
|
1040
|
+
: `the update from ${journal.from} to ${journal.to} is unfinished (${journal.phase}, step ${journal.step}); the daemon stays stopped or held until it is resolved`,
|
|
1041
|
+
code: 'update.open',
|
|
1042
|
+
fix: (0, update_journal_js_1.rollbackCommand)(journal),
|
|
1043
|
+
},
|
|
1044
|
+
];
|
|
1045
|
+
}
|
|
1046
|
+
const hold = (0, update_journal_js_1.updatePaths)(root).hold;
|
|
1047
|
+
if ((0, node_fs_1.existsSync)(hold)) {
|
|
1048
|
+
return [
|
|
1049
|
+
{
|
|
1050
|
+
name: 'update',
|
|
1051
|
+
status: 'fail',
|
|
1052
|
+
detail: 'an update hold file is in place with no update journal; start.sh exits at once, so the daemon does not start',
|
|
1053
|
+
code: 'update.hold',
|
|
1054
|
+
context: hold,
|
|
1055
|
+
fix: `rm ${hold}, then mama service start`,
|
|
1056
|
+
},
|
|
1057
|
+
];
|
|
1058
|
+
}
|
|
1059
|
+
const install = (0, install_kind_js_1.installKind)(root, home);
|
|
1060
|
+
const staging = install.kind === 'npm' ? (0, update_journal_js_1.leftoverStaging)((0, node_path_1.dirname)(install.packageRoot)) : [];
|
|
1061
|
+
return staging.length === 0
|
|
1062
|
+
? []
|
|
1063
|
+
: [
|
|
1064
|
+
{
|
|
1065
|
+
name: 'update',
|
|
1066
|
+
status: 'warn',
|
|
1067
|
+
detail: 'an interrupted mama update left its staging folder; the install runs as before',
|
|
1068
|
+
code: 'update.staging',
|
|
1069
|
+
context: staging.join(', '),
|
|
1070
|
+
fix: 'the next mama update removes it',
|
|
1071
|
+
},
|
|
1072
|
+
];
|
|
1073
|
+
}
|
|
1074
|
+
/** The daemon's last daily release check, from its file; doctor itself asks no registry. */
|
|
1075
|
+
function releaseCheck(root, home) {
|
|
1076
|
+
const report = (0, release_check_js_1.releaseReport)(root, home);
|
|
1077
|
+
if (report === null) {
|
|
1078
|
+
return {
|
|
1079
|
+
name: 'release',
|
|
1080
|
+
status: 'ok',
|
|
1081
|
+
detail: 'not checked yet; the running daemon checks once a day',
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
return {
|
|
1085
|
+
name: 'release',
|
|
1086
|
+
status: report.status,
|
|
1087
|
+
detail: report.detail,
|
|
1088
|
+
...(report.context === undefined ? {} : { context: report.context }),
|
|
1089
|
+
...(report.steps === undefined ? {} : { fix: report.steps.join('; then ') }),
|
|
1090
|
+
...(report.fix === undefined ? {} : { fix: report.fix }),
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
906
1093
|
function serviceCheck(platform, home, serviceRun) {
|
|
907
1094
|
let launchd;
|
|
908
1095
|
let unit;
|