@metamask-previews/wallet-cli 0.0.0-preview-43e6d6596 → 0.0.0-preview-d7951629b

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/README.md +27 -0
  3. package/bin/dev.cmd +3 -0
  4. package/bin/dev.mjs +3 -0
  5. package/dist/commands/daemon/call.cjs +83 -0
  6. package/dist/commands/daemon/call.cjs.map +1 -0
  7. package/dist/commands/daemon/call.d.cts +14 -0
  8. package/dist/commands/daemon/call.d.cts.map +1 -0
  9. package/dist/commands/daemon/call.d.mts +14 -0
  10. package/dist/commands/daemon/call.d.mts.map +1 -0
  11. package/dist/commands/daemon/call.mjs +81 -0
  12. package/dist/commands/daemon/call.mjs.map +1 -0
  13. package/dist/commands/daemon/purge.cjs +58 -0
  14. package/dist/commands/daemon/purge.cjs.map +1 -0
  15. package/dist/commands/daemon/purge.d.cts +10 -0
  16. package/dist/commands/daemon/purge.d.cts.map +1 -0
  17. package/dist/commands/daemon/purge.d.mts +10 -0
  18. package/dist/commands/daemon/purge.d.mts.map +1 -0
  19. package/dist/commands/daemon/purge.mjs +56 -0
  20. package/dist/commands/daemon/purge.mjs.map +1 -0
  21. package/dist/commands/daemon/start.cjs +48 -0
  22. package/dist/commands/daemon/start.cjs.map +1 -0
  23. package/dist/commands/daemon/start.d.cts +12 -0
  24. package/dist/commands/daemon/start.d.cts.map +1 -0
  25. package/dist/commands/daemon/start.d.mts +12 -0
  26. package/dist/commands/daemon/start.d.mts.map +1 -0
  27. package/dist/commands/daemon/start.mjs +46 -0
  28. package/dist/commands/daemon/start.mjs.map +1 -0
  29. package/dist/commands/daemon/status.cjs +59 -0
  30. package/dist/commands/daemon/status.cjs.map +1 -0
  31. package/dist/commands/daemon/status.d.cts +7 -0
  32. package/dist/commands/daemon/status.d.cts.map +1 -0
  33. package/dist/commands/daemon/status.d.mts +7 -0
  34. package/dist/commands/daemon/status.d.mts.map +1 -0
  35. package/dist/commands/daemon/status.mjs +57 -0
  36. package/dist/commands/daemon/status.mjs.map +1 -0
  37. package/dist/commands/daemon/stop.cjs +26 -0
  38. package/dist/commands/daemon/stop.cjs.map +1 -0
  39. package/dist/commands/daemon/stop.d.cts +7 -0
  40. package/dist/commands/daemon/stop.d.cts.map +1 -0
  41. package/dist/commands/daemon/stop.d.mts +7 -0
  42. package/dist/commands/daemon/stop.d.mts.map +1 -0
  43. package/dist/commands/daemon/stop.mjs +24 -0
  44. package/dist/commands/daemon/stop.mjs.map +1 -0
  45. package/dist/test/run-command.cjs +73 -0
  46. package/dist/test/run-command.cjs.map +1 -0
  47. package/dist/test/run-command.d.cts +27 -0
  48. package/dist/test/run-command.d.cts.map +1 -0
  49. package/dist/test/run-command.d.mts +27 -0
  50. package/dist/test/run-command.d.mts.map +1 -0
  51. package/dist/test/run-command.mjs +69 -0
  52. package/dist/test/run-command.mjs.map +1 -0
  53. package/package.json +3 -1
package/CHANGELOG.md CHANGED
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Added
11
11
 
12
+ - Add the `mm daemon` command suite (`start`, `stop`, `status`, `purge`, and `call`) for running the wallet daemon and dispatching messenger actions over its socket ([#9255](https://github.com/MetaMask/core/pull/9255))
12
13
  - Add a wallet factory and daemon entry point that construct a `@metamask/wallet` `Wallet` backed by the SQLite key-value store, hydrate it from persisted state, run controller initialization (aborting startup if any step fails), import the secret recovery phrase on first run, and expose a `dispose` teardown handle ([#9226](https://github.com/MetaMask/core/pull/9226))
13
14
  - Add a daemon transport layer: a JSON-RPC client and server over a Unix socket, plus daemon spawn/stop lifecycle helpers ([#9108](https://github.com/MetaMask/core/pull/9108))
14
15
  - Add SQLite-backed persistence for wallet controller state ([#9067](https://github.com/MetaMask/core/pull/9067))
package/README.md CHANGED
@@ -10,6 +10,33 @@ or
10
10
 
11
11
  `npm install @metamask/wallet-cli`
12
12
 
13
+ ## Usage
14
+
15
+ The CLI drives a long-lived background **daemon** that holds an unlocked `@metamask/wallet` in memory and exposes its messenger over a per-user Unix socket. All commands live under the `mm daemon` topic; run `mm --help` (or `mm daemon <command> --help`) for the full reference.
16
+
17
+ Start the daemon (flags may also be supplied as the `INFURA_PROJECT_ID`, `MM_WALLET_PASSWORD`, and `MM_WALLET_SRP` environment variables — preferred for secrets):
18
+
19
+ ```sh
20
+ mm daemon start --infura-project-id <key> --password <pw> --srp "<phrase>"
21
+ ```
22
+
23
+ Call any messenger action on the running wallet (positional JSON array for arguments, optional `--timeout`):
24
+
25
+ ```sh
26
+ mm daemon call AccountsController:listAccounts
27
+ mm daemon call KeyringController:getState --timeout 10000
28
+ ```
29
+
30
+ Inspect or tear it down:
31
+
32
+ ```sh
33
+ mm daemon status # PID + uptime, or why the socket is unreachable
34
+ mm daemon stop # graceful shutdown (falls back to SIGTERM/SIGKILL)
35
+ mm daemon purge # stop, then delete all daemon state files (--force to skip the prompt)
36
+ ```
37
+
38
+ State (socket, PID file, log, and the SQLite database) lives in the per-user oclif data directory; override it with `MM_DATA_DIR`.
39
+
13
40
  ## Troubleshooting
14
41
 
15
42
  ### Rebuilding `better-sqlite3`
package/bin/dev.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node --import tsx --no-warnings=ExperimentalWarning "%~dp0\dev.mjs" %*
package/bin/dev.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { execute } from '@oclif/core';
2
+
3
+ await execute({ development: true, dir: import.meta.url });
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@metamask/utils");
4
+ const core_1 = require("@oclif/core");
5
+ const daemon_client_1 = require("../../daemon/daemon-client.cjs");
6
+ const paths_1 = require("../../daemon/paths.cjs");
7
+ const utils_2 = require("../../daemon/utils.cjs");
8
+ class DaemonCall extends core_1.Command {
9
+ async run() {
10
+ const { args, flags } = await this.parse(DaemonCall);
11
+ const { action } = args;
12
+ const timeoutMs = flags.timeout;
13
+ // The daemon's `call` RPC expects `[action, ...args]`. `JSON.parse` returns
14
+ // `unknown`, but anything it produces is structurally `Json`, so we cast to
15
+ // `Json[]` once we've confirmed the parsed payload is an array.
16
+ const rpcParams = [action];
17
+ if (args.params !== undefined) {
18
+ let parsed;
19
+ try {
20
+ parsed = JSON.parse(args.params);
21
+ }
22
+ catch {
23
+ this.error('params must be valid JSON');
24
+ }
25
+ if (!Array.isArray(parsed)) {
26
+ this.error('params must be a JSON array');
27
+ }
28
+ rpcParams.push(...parsed);
29
+ }
30
+ const { socketPath } = (0, paths_1.getDaemonPaths)(this.config.dataDir);
31
+ let response;
32
+ try {
33
+ response = await (0, daemon_client_1.sendCommand)({
34
+ socketPath,
35
+ method: 'call',
36
+ params: rpcParams,
37
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
38
+ });
39
+ }
40
+ catch (error) {
41
+ if ((0, utils_2.isErrorWithCode)(error, 'ENOENT') ||
42
+ (0, utils_2.isErrorWithCode)(error, 'ECONNREFUSED')) {
43
+ this.error('Daemon is not running. Start it with `mm daemon start`.');
44
+ }
45
+ this.error(error instanceof Error ? error.message : String(error));
46
+ }
47
+ if ((0, utils_1.isJsonRpcFailure)(response)) {
48
+ this.error(`${response.error.message} (code ${String(response.error.code)})`);
49
+ }
50
+ const isTTY = process.stdout.isTTY ?? false;
51
+ if (isTTY) {
52
+ this.log(JSON.stringify(response.result, null, 2));
53
+ }
54
+ else {
55
+ process.stdout.write(`${JSON.stringify(response.result)}\n`);
56
+ }
57
+ }
58
+ }
59
+ DaemonCall.description = 'Call a messenger action on the wallet daemon';
60
+ DaemonCall.examples = [
61
+ '<%= config.bin %> daemon call KeyringController:getState',
62
+ '<%= config.bin %> daemon call NetworkController:getState',
63
+ '<%= config.bin %> daemon call ApprovalController:getState --timeout 10000',
64
+ ];
65
+ DaemonCall.args = {
66
+ action: core_1.Args.string({
67
+ description: 'The messenger action name (e.g. AccountsController:listAccounts)',
68
+ required: true,
69
+ }),
70
+ params: core_1.Args.string({
71
+ description: 'JSON-encoded arguments array (e.g. \'["arg1", "arg2"]\')',
72
+ required: false,
73
+ }),
74
+ };
75
+ DaemonCall.flags = {
76
+ timeout: core_1.Flags.integer({
77
+ char: 't',
78
+ description: 'Response timeout in milliseconds',
79
+ required: false,
80
+ }),
81
+ };
82
+ exports.default = DaemonCall;
83
+ //# sourceMappingURL=call.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.cjs","sourceRoot":"","sources":["../../../src/commands/daemon/call.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Json } from '@metamask/utils';\nimport { isJsonRpcFailure } from '@metamask/utils';\nimport { Args, Command, Flags } from '@oclif/core';\n\nimport { sendCommand } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport { isErrorWithCode } from '../../daemon/utils';\n\nexport default class DaemonCall extends Command {\n static override description = 'Call a messenger action on the wallet daemon';\n\n static override examples = [\n '<%= config.bin %> daemon call KeyringController:getState',\n '<%= config.bin %> daemon call NetworkController:getState',\n '<%= config.bin %> daemon call ApprovalController:getState --timeout 10000',\n ];\n\n static override args = {\n action: Args.string({\n description:\n 'The messenger action name (e.g. AccountsController:listAccounts)',\n required: true,\n }),\n params: Args.string({\n description: 'JSON-encoded arguments array (e.g. \\'[\"arg1\", \"arg2\"]\\')',\n required: false,\n }),\n };\n\n static override flags = {\n timeout: Flags.integer({\n char: 't',\n description: 'Response timeout in milliseconds',\n required: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { args, flags } = await this.parse(DaemonCall);\n const { action } = args;\n const timeoutMs = flags.timeout;\n\n // The daemon's `call` RPC expects `[action, ...args]`. `JSON.parse` returns\n // `unknown`, but anything it produces is structurally `Json`, so we cast to\n // `Json[]` once we've confirmed the parsed payload is an array.\n const rpcParams: Json[] = [action];\n if (args.params !== undefined) {\n let parsed: unknown;\n try {\n parsed = JSON.parse(args.params);\n } catch {\n this.error('params must be valid JSON');\n }\n\n if (!Array.isArray(parsed)) {\n this.error('params must be a JSON array');\n }\n\n rpcParams.push(...(parsed as Json[]));\n }\n\n const { socketPath } = getDaemonPaths(this.config.dataDir);\n\n let response;\n try {\n response = await sendCommand({\n socketPath,\n method: 'call',\n params: rpcParams,\n ...(timeoutMs === undefined ? {} : { timeoutMs }),\n });\n } catch (error) {\n if (\n isErrorWithCode(error, 'ENOENT') ||\n isErrorWithCode(error, 'ECONNREFUSED')\n ) {\n this.error('Daemon is not running. Start it with `mm daemon start`.');\n }\n this.error(error instanceof Error ? error.message : String(error));\n }\n\n if (isJsonRpcFailure(response)) {\n this.error(\n `${response.error.message} (code ${String(response.error.code)})`,\n );\n }\n\n const isTTY = process.stdout.isTTY ?? false;\n if (isTTY) {\n this.log(JSON.stringify(response.result, null, 2));\n } else {\n process.stdout.write(`${JSON.stringify(response.result)}\\n`);\n }\n }\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonCall extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ action: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ params: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ timeout: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=call.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.d.cts","sourceRoot":"","sources":["../../../src/commands/daemon/call.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,OAAO,EAAS,oBAAoB;AAMnD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,OAAO;IAC7C,OAAgB,WAAW,SAAkD;IAE7E,OAAgB,QAAQ,WAItB;IAEF,OAAgB,IAAI;;;MAUlB;IAEF,OAAgB,KAAK;;MAMnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAyDlC"}
@@ -0,0 +1,14 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonCall extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ action: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ params: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ timeout: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=call.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.d.mts","sourceRoot":"","sources":["../../../src/commands/daemon/call.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,OAAO,EAAS,oBAAoB;AAMnD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,OAAO;IAC7C,OAAgB,WAAW,SAAkD;IAE7E,OAAgB,QAAQ,WAItB;IAEF,OAAgB,IAAI;;;MAUlB;IAEF,OAAgB,KAAK;;MAMnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAyDlC"}
@@ -0,0 +1,81 @@
1
+ import { isJsonRpcFailure } from "@metamask/utils";
2
+ import { Args, Command, Flags } from "@oclif/core";
3
+ import { sendCommand } from "../../daemon/daemon-client.mjs";
4
+ import { getDaemonPaths } from "../../daemon/paths.mjs";
5
+ import { isErrorWithCode } from "../../daemon/utils.mjs";
6
+ class DaemonCall extends Command {
7
+ async run() {
8
+ const { args, flags } = await this.parse(DaemonCall);
9
+ const { action } = args;
10
+ const timeoutMs = flags.timeout;
11
+ // The daemon's `call` RPC expects `[action, ...args]`. `JSON.parse` returns
12
+ // `unknown`, but anything it produces is structurally `Json`, so we cast to
13
+ // `Json[]` once we've confirmed the parsed payload is an array.
14
+ const rpcParams = [action];
15
+ if (args.params !== undefined) {
16
+ let parsed;
17
+ try {
18
+ parsed = JSON.parse(args.params);
19
+ }
20
+ catch {
21
+ this.error('params must be valid JSON');
22
+ }
23
+ if (!Array.isArray(parsed)) {
24
+ this.error('params must be a JSON array');
25
+ }
26
+ rpcParams.push(...parsed);
27
+ }
28
+ const { socketPath } = getDaemonPaths(this.config.dataDir);
29
+ let response;
30
+ try {
31
+ response = await sendCommand({
32
+ socketPath,
33
+ method: 'call',
34
+ params: rpcParams,
35
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
36
+ });
37
+ }
38
+ catch (error) {
39
+ if (isErrorWithCode(error, 'ENOENT') ||
40
+ isErrorWithCode(error, 'ECONNREFUSED')) {
41
+ this.error('Daemon is not running. Start it with `mm daemon start`.');
42
+ }
43
+ this.error(error instanceof Error ? error.message : String(error));
44
+ }
45
+ if (isJsonRpcFailure(response)) {
46
+ this.error(`${response.error.message} (code ${String(response.error.code)})`);
47
+ }
48
+ const isTTY = process.stdout.isTTY ?? false;
49
+ if (isTTY) {
50
+ this.log(JSON.stringify(response.result, null, 2));
51
+ }
52
+ else {
53
+ process.stdout.write(`${JSON.stringify(response.result)}\n`);
54
+ }
55
+ }
56
+ }
57
+ DaemonCall.description = 'Call a messenger action on the wallet daemon';
58
+ DaemonCall.examples = [
59
+ '<%= config.bin %> daemon call KeyringController:getState',
60
+ '<%= config.bin %> daemon call NetworkController:getState',
61
+ '<%= config.bin %> daemon call ApprovalController:getState --timeout 10000',
62
+ ];
63
+ DaemonCall.args = {
64
+ action: Args.string({
65
+ description: 'The messenger action name (e.g. AccountsController:listAccounts)',
66
+ required: true,
67
+ }),
68
+ params: Args.string({
69
+ description: 'JSON-encoded arguments array (e.g. \'["arg1", "arg2"]\')',
70
+ required: false,
71
+ }),
72
+ };
73
+ DaemonCall.flags = {
74
+ timeout: Flags.integer({
75
+ char: 't',
76
+ description: 'Response timeout in milliseconds',
77
+ required: false,
78
+ }),
79
+ };
80
+ export default DaemonCall;
81
+ //# sourceMappingURL=call.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.mjs","sourceRoot":"","sources":["../../../src/commands/daemon/call.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Json } from '@metamask/utils';\nimport { isJsonRpcFailure } from '@metamask/utils';\nimport { Args, Command, Flags } from '@oclif/core';\n\nimport { sendCommand } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport { isErrorWithCode } from '../../daemon/utils';\n\nexport default class DaemonCall extends Command {\n static override description = 'Call a messenger action on the wallet daemon';\n\n static override examples = [\n '<%= config.bin %> daemon call KeyringController:getState',\n '<%= config.bin %> daemon call NetworkController:getState',\n '<%= config.bin %> daemon call ApprovalController:getState --timeout 10000',\n ];\n\n static override args = {\n action: Args.string({\n description:\n 'The messenger action name (e.g. AccountsController:listAccounts)',\n required: true,\n }),\n params: Args.string({\n description: 'JSON-encoded arguments array (e.g. \\'[\"arg1\", \"arg2\"]\\')',\n required: false,\n }),\n };\n\n static override flags = {\n timeout: Flags.integer({\n char: 't',\n description: 'Response timeout in milliseconds',\n required: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { args, flags } = await this.parse(DaemonCall);\n const { action } = args;\n const timeoutMs = flags.timeout;\n\n // The daemon's `call` RPC expects `[action, ...args]`. `JSON.parse` returns\n // `unknown`, but anything it produces is structurally `Json`, so we cast to\n // `Json[]` once we've confirmed the parsed payload is an array.\n const rpcParams: Json[] = [action];\n if (args.params !== undefined) {\n let parsed: unknown;\n try {\n parsed = JSON.parse(args.params);\n } catch {\n this.error('params must be valid JSON');\n }\n\n if (!Array.isArray(parsed)) {\n this.error('params must be a JSON array');\n }\n\n rpcParams.push(...(parsed as Json[]));\n }\n\n const { socketPath } = getDaemonPaths(this.config.dataDir);\n\n let response;\n try {\n response = await sendCommand({\n socketPath,\n method: 'call',\n params: rpcParams,\n ...(timeoutMs === undefined ? {} : { timeoutMs }),\n });\n } catch (error) {\n if (\n isErrorWithCode(error, 'ENOENT') ||\n isErrorWithCode(error, 'ECONNREFUSED')\n ) {\n this.error('Daemon is not running. Start it with `mm daemon start`.');\n }\n this.error(error instanceof Error ? error.message : String(error));\n }\n\n if (isJsonRpcFailure(response)) {\n this.error(\n `${response.error.message} (code ${String(response.error.code)})`,\n );\n }\n\n const isTTY = process.stdout.isTTY ?? false;\n if (isTTY) {\n this.log(JSON.stringify(response.result, null, 2));\n } else {\n process.stdout.write(`${JSON.stringify(response.result)}\\n`);\n }\n }\n}\n"]}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const promises_1 = require("node:fs/promises");
5
+ const daemon_client_1 = require("../../daemon/daemon-client.cjs");
6
+ const paths_1 = require("../../daemon/paths.cjs");
7
+ const prompts_1 = require("../../daemon/prompts.cjs");
8
+ const stop_daemon_1 = require("../../daemon/stop-daemon.cjs");
9
+ class DaemonPurge extends core_1.Command {
10
+ async run() {
11
+ const { flags } = await this.parse(DaemonPurge);
12
+ if (!flags.force) {
13
+ const confirmed = await (0, prompts_1.confirmPurge)();
14
+ if (!confirmed) {
15
+ this.log('Aborted.');
16
+ return;
17
+ }
18
+ }
19
+ const paths = (0, paths_1.getDaemonPaths)(this.config.dataDir);
20
+ const stopped = await (0, stop_daemon_1.stopDaemon)(paths.socketPath, paths.pidPath, (message) => this.log(message));
21
+ if (!stopped) {
22
+ // Purge is the escape hatch for a daemon that wouldn't shut down cleanly,
23
+ // so proceed once we've confirmed it isn't responsive — deleting state
24
+ // out from under a live daemon would risk corrupting it.
25
+ const ping = await (0, daemon_client_1.pingDaemon)(paths.socketPath);
26
+ if (ping.status === 'responsive') {
27
+ this.error('Refusing to delete state while the daemon is still responsive.');
28
+ }
29
+ this.log('Could not confirm clean shutdown; proceeding to delete state anyway.');
30
+ }
31
+ // Whitelist only the daemon-owned files rather than rm'ing the entire
32
+ // oclif dataDir, which may hold unrelated state (caches, oclif lock
33
+ // files, future config). `force: true` makes ENOENT a no-op for any
34
+ // file already removed by stopDaemon.
35
+ await Promise.all([
36
+ paths.pidPath,
37
+ paths.socketPath,
38
+ paths.logPath,
39
+ paths.dbPath,
40
+ `${paths.dbPath}-wal`,
41
+ `${paths.dbPath}-shm`,
42
+ ].map(async (path) => (0, promises_1.rm)(path, { force: true })));
43
+ this.log('All daemon state deleted.');
44
+ }
45
+ }
46
+ DaemonPurge.description = 'Stop the daemon and delete all daemon state files';
47
+ DaemonPurge.examples = [
48
+ '<%= config.bin %> daemon purge',
49
+ '<%= config.bin %> daemon purge --force',
50
+ ];
51
+ DaemonPurge.flags = {
52
+ force: core_1.Flags.boolean({
53
+ char: 'f',
54
+ description: 'Skip confirmation prompt',
55
+ }),
56
+ };
57
+ exports.default = DaemonPurge;
58
+ //# sourceMappingURL=purge.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purge.cjs","sourceRoot":"","sources":["../../../src/commands/daemon/purge.ts"],"names":[],"mappings":";;AAAA,sCAA6C;AAC7C,+CAAsC;AAEtC,kEAAwD;AACxD,kDAAoD;AACpD,sDAAoD;AACpD,8DAAsD;AAEtD,MAAqB,WAAY,SAAQ,cAAO;IAgBvC,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAEhD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,IAAA,sBAAY,GAAE,CAAC;YACvC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG,IAAA,sBAAc,EAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAElD,MAAM,OAAO,GAAG,MAAM,IAAA,wBAAU,EAC9B,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,OAAO,EACb,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAC/B,CAAC;QAEF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,0EAA0E;YAC1E,uEAAuE;YACvE,yDAAyD;YACzD,MAAM,IAAI,GAAG,MAAM,IAAA,0BAAU,EAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAChD,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBACjC,IAAI,CAAC,KAAK,CACR,gEAAgE,CACjE,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,GAAG,CACN,sEAAsE,CACvE,CAAC;QACJ,CAAC;QAED,sEAAsE;QACtE,oEAAoE;QACpE,oEAAoE;QACpE,sCAAsC;QACtC,MAAM,OAAO,CAAC,GAAG,CACf;YACE,KAAK,CAAC,OAAO;YACb,KAAK,CAAC,UAAU;YAChB,KAAK,CAAC,OAAO;YACb,KAAK,CAAC,MAAM;YACZ,GAAG,KAAK,CAAC,MAAM,MAAM;YACrB,GAAG,KAAK,CAAC,MAAM,MAAM;SACtB,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAA,aAAE,EAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CACjD,CAAC;QAEF,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACxC,CAAC;;AAjEe,uBAAW,GACzB,mDAAmD,CAAC;AAEtC,oBAAQ,GAAG;IACzB,gCAAgC;IAChC,wCAAwC;CACzC,CAAC;AAEc,iBAAK,GAAG;IACtB,KAAK,EAAE,YAAK,CAAC,OAAO,CAAC;QACnB,IAAI,EAAE,GAAG;QACT,WAAW,EAAE,0BAA0B;KACxC,CAAC;CACH,CAAC;kBAdiB,WAAW","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport { rm } from 'node:fs/promises';\n\nimport { pingDaemon } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport { confirmPurge } from '../../daemon/prompts';\nimport { stopDaemon } from '../../daemon/stop-daemon';\n\nexport default class DaemonPurge extends Command {\n static override description =\n 'Stop the daemon and delete all daemon state files';\n\n static override examples = [\n '<%= config.bin %> daemon purge',\n '<%= config.bin %> daemon purge --force',\n ];\n\n static override flags = {\n force: Flags.boolean({\n char: 'f',\n description: 'Skip confirmation prompt',\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(DaemonPurge);\n\n if (!flags.force) {\n const confirmed = await confirmPurge();\n if (!confirmed) {\n this.log('Aborted.');\n return;\n }\n }\n\n const paths = getDaemonPaths(this.config.dataDir);\n\n const stopped = await stopDaemon(\n paths.socketPath,\n paths.pidPath,\n (message) => this.log(message),\n );\n\n if (!stopped) {\n // Purge is the escape hatch for a daemon that wouldn't shut down cleanly,\n // so proceed once we've confirmed it isn't responsive — deleting state\n // out from under a live daemon would risk corrupting it.\n const ping = await pingDaemon(paths.socketPath);\n if (ping.status === 'responsive') {\n this.error(\n 'Refusing to delete state while the daemon is still responsive.',\n );\n }\n this.log(\n 'Could not confirm clean shutdown; proceeding to delete state anyway.',\n );\n }\n\n // Whitelist only the daemon-owned files rather than rm'ing the entire\n // oclif dataDir, which may hold unrelated state (caches, oclif lock\n // files, future config). `force: true` makes ENOENT a no-op for any\n // file already removed by stopDaemon.\n await Promise.all(\n [\n paths.pidPath,\n paths.socketPath,\n paths.logPath,\n paths.dbPath,\n `${paths.dbPath}-wal`,\n `${paths.dbPath}-shm`,\n ].map(async (path) => rm(path, { force: true })),\n );\n\n this.log('All daemon state deleted.');\n }\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonPurge extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=purge.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purge.d.cts","sourceRoot":"","sources":["../../../src/commands/daemon/purge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,oBAAoB;AAQ7C,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,OAAO;IAC9C,OAAgB,WAAW,SAC2B;IAEtD,OAAgB,QAAQ,WAGtB;IAEF,OAAgB,KAAK;;MAKnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAmDlC"}
@@ -0,0 +1,10 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonPurge extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=purge.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purge.d.mts","sourceRoot":"","sources":["../../../src/commands/daemon/purge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,oBAAoB;AAQ7C,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,OAAO;IAC9C,OAAgB,WAAW,SAC2B;IAEtD,OAAgB,QAAQ,WAGtB;IAEF,OAAgB,KAAK;;MAKnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAmDlC"}
@@ -0,0 +1,56 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import { rm } from "node:fs/promises";
3
+ import { pingDaemon } from "../../daemon/daemon-client.mjs";
4
+ import { getDaemonPaths } from "../../daemon/paths.mjs";
5
+ import { confirmPurge } from "../../daemon/prompts.mjs";
6
+ import { stopDaemon } from "../../daemon/stop-daemon.mjs";
7
+ class DaemonPurge extends Command {
8
+ async run() {
9
+ const { flags } = await this.parse(DaemonPurge);
10
+ if (!flags.force) {
11
+ const confirmed = await confirmPurge();
12
+ if (!confirmed) {
13
+ this.log('Aborted.');
14
+ return;
15
+ }
16
+ }
17
+ const paths = getDaemonPaths(this.config.dataDir);
18
+ const stopped = await stopDaemon(paths.socketPath, paths.pidPath, (message) => this.log(message));
19
+ if (!stopped) {
20
+ // Purge is the escape hatch for a daemon that wouldn't shut down cleanly,
21
+ // so proceed once we've confirmed it isn't responsive — deleting state
22
+ // out from under a live daemon would risk corrupting it.
23
+ const ping = await pingDaemon(paths.socketPath);
24
+ if (ping.status === 'responsive') {
25
+ this.error('Refusing to delete state while the daemon is still responsive.');
26
+ }
27
+ this.log('Could not confirm clean shutdown; proceeding to delete state anyway.');
28
+ }
29
+ // Whitelist only the daemon-owned files rather than rm'ing the entire
30
+ // oclif dataDir, which may hold unrelated state (caches, oclif lock
31
+ // files, future config). `force: true` makes ENOENT a no-op for any
32
+ // file already removed by stopDaemon.
33
+ await Promise.all([
34
+ paths.pidPath,
35
+ paths.socketPath,
36
+ paths.logPath,
37
+ paths.dbPath,
38
+ `${paths.dbPath}-wal`,
39
+ `${paths.dbPath}-shm`,
40
+ ].map(async (path) => rm(path, { force: true })));
41
+ this.log('All daemon state deleted.');
42
+ }
43
+ }
44
+ DaemonPurge.description = 'Stop the daemon and delete all daemon state files';
45
+ DaemonPurge.examples = [
46
+ '<%= config.bin %> daemon purge',
47
+ '<%= config.bin %> daemon purge --force',
48
+ ];
49
+ DaemonPurge.flags = {
50
+ force: Flags.boolean({
51
+ char: 'f',
52
+ description: 'Skip confirmation prompt',
53
+ }),
54
+ };
55
+ export default DaemonPurge;
56
+ //# sourceMappingURL=purge.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purge.mjs","sourceRoot":"","sources":["../../../src/commands/daemon/purge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB;AAC7C,OAAO,EAAE,EAAE,EAAE,yBAAyB;AAEtC,OAAO,EAAE,UAAU,EAAE,uCAAmC;AACxD,OAAO,EAAE,cAAc,EAAE,+BAA2B;AACpD,OAAO,EAAE,YAAY,EAAE,iCAA6B;AACpD,OAAO,EAAE,UAAU,EAAE,qCAAiC;AAEtD,MAAqB,WAAY,SAAQ,OAAO;IAgBvC,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAEhD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,YAAY,EAAE,CAAC;YACvC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAElD,MAAM,OAAO,GAAG,MAAM,UAAU,CAC9B,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,OAAO,EACb,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAC/B,CAAC;QAEF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,0EAA0E;YAC1E,uEAAuE;YACvE,yDAAyD;YACzD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAChD,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBACjC,IAAI,CAAC,KAAK,CACR,gEAAgE,CACjE,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,GAAG,CACN,sEAAsE,CACvE,CAAC;QACJ,CAAC;QAED,sEAAsE;QACtE,oEAAoE;QACpE,oEAAoE;QACpE,sCAAsC;QACtC,MAAM,OAAO,CAAC,GAAG,CACf;YACE,KAAK,CAAC,OAAO;YACb,KAAK,CAAC,UAAU;YAChB,KAAK,CAAC,OAAO;YACb,KAAK,CAAC,MAAM;YACZ,GAAG,KAAK,CAAC,MAAM,MAAM;YACrB,GAAG,KAAK,CAAC,MAAM,MAAM;SACtB,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CACjD,CAAC;QAEF,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACxC,CAAC;;AAjEe,uBAAW,GACzB,mDAAmD,CAAC;AAEtC,oBAAQ,GAAG;IACzB,gCAAgC;IAChC,wCAAwC;CACzC,CAAC;AAEc,iBAAK,GAAG;IACtB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;QACnB,IAAI,EAAE,GAAG;QACT,WAAW,EAAE,0BAA0B;KACxC,CAAC;CACH,CAAC;eAdiB,WAAW","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport { rm } from 'node:fs/promises';\n\nimport { pingDaemon } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport { confirmPurge } from '../../daemon/prompts';\nimport { stopDaemon } from '../../daemon/stop-daemon';\n\nexport default class DaemonPurge extends Command {\n static override description =\n 'Stop the daemon and delete all daemon state files';\n\n static override examples = [\n '<%= config.bin %> daemon purge',\n '<%= config.bin %> daemon purge --force',\n ];\n\n static override flags = {\n force: Flags.boolean({\n char: 'f',\n description: 'Skip confirmation prompt',\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(DaemonPurge);\n\n if (!flags.force) {\n const confirmed = await confirmPurge();\n if (!confirmed) {\n this.log('Aborted.');\n return;\n }\n }\n\n const paths = getDaemonPaths(this.config.dataDir);\n\n const stopped = await stopDaemon(\n paths.socketPath,\n paths.pidPath,\n (message) => this.log(message),\n );\n\n if (!stopped) {\n // Purge is the escape hatch for a daemon that wouldn't shut down cleanly,\n // so proceed once we've confirmed it isn't responsive — deleting state\n // out from under a live daemon would risk corrupting it.\n const ping = await pingDaemon(paths.socketPath);\n if (ping.status === 'responsive') {\n this.error(\n 'Refusing to delete state while the daemon is still responsive.',\n );\n }\n this.log(\n 'Could not confirm clean shutdown; proceeding to delete state anyway.',\n );\n }\n\n // Whitelist only the daemon-owned files rather than rm'ing the entire\n // oclif dataDir, which may hold unrelated state (caches, oclif lock\n // files, future config). `force: true` makes ENOENT a no-op for any\n // file already removed by stopDaemon.\n await Promise.all(\n [\n paths.pidPath,\n paths.socketPath,\n paths.logPath,\n paths.dbPath,\n `${paths.dbPath}-wal`,\n `${paths.dbPath}-shm`,\n ].map(async (path) => rm(path, { force: true })),\n );\n\n this.log('All daemon state deleted.');\n }\n}\n"]}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const daemon_spawn_1 = require("../../daemon/daemon-spawn.cjs");
5
+ class DaemonStart extends core_1.Command {
6
+ async run() {
7
+ const { flags } = await this.parse(DaemonStart);
8
+ const infuraProjectId = flags['infura-project-id'];
9
+ const { password, srp } = flags;
10
+ const { state, socketPath } = await (0, daemon_spawn_1.ensureDaemon)({
11
+ dataDir: this.config.dataDir,
12
+ infuraProjectId,
13
+ password,
14
+ srp,
15
+ packageRoot: this.config.root,
16
+ });
17
+ if (state === 'already-running') {
18
+ this.log(`Daemon already running. Socket: ${socketPath}. ` +
19
+ `The provided flags were not applied; run \`mm daemon stop\` and start again to change them.`);
20
+ return;
21
+ }
22
+ this.log(`Daemon running. Socket: ${socketPath}`);
23
+ }
24
+ }
25
+ DaemonStart.description = 'Start the wallet daemon';
26
+ DaemonStart.examples = [
27
+ '<%= config.bin %> daemon start --infura-project-id <key> --password <pw> --srp <phrase>',
28
+ 'INFURA_PROJECT_ID=<key> MM_WALLET_PASSWORD=<pw> MM_WALLET_SRP=<phrase> <%= config.bin %> daemon start',
29
+ ];
30
+ DaemonStart.flags = {
31
+ 'infura-project-id': core_1.Flags.string({
32
+ description: 'Infura project ID for network access',
33
+ env: 'INFURA_PROJECT_ID',
34
+ required: true,
35
+ }),
36
+ password: core_1.Flags.string({
37
+ description: 'Wallet password (testing only — use MM_WALLET_PASSWORD env var in production)',
38
+ env: 'MM_WALLET_PASSWORD',
39
+ required: true,
40
+ }),
41
+ srp: core_1.Flags.string({
42
+ description: 'Secret recovery phrase (testing only — use MM_WALLET_SRP env var in production)',
43
+ env: 'MM_WALLET_SRP',
44
+ required: true,
45
+ }),
46
+ };
47
+ exports.default = DaemonStart;
48
+ //# sourceMappingURL=start.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.cjs","sourceRoot":"","sources":["../../../src/commands/daemon/start.ts"],"names":[],"mappings":";;AAAA,sCAA6C;AAE7C,gEAAyD;AAEzD,MAAqB,WAAY,SAAQ,cAAO;IA4BvC,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,eAAe,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACnD,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QAEhC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,2BAAY,EAAC;YAC/C,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;YAC5B,eAAe;YACf,QAAQ;YACR,GAAG;YACH,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;SAC9B,CAAC,CAAC;QAEH,IAAI,KAAK,KAAK,iBAAiB,EAAE,CAAC;YAChC,IAAI,CAAC,GAAG,CACN,mCAAmC,UAAU,IAAI;gBAC/C,6FAA6F,CAChG,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,2BAA2B,UAAU,EAAE,CAAC,CAAC;IACpD,CAAC;;AAjDe,uBAAW,GAAG,yBAAyB,CAAC;AAExC,oBAAQ,GAAG;IACzB,yFAAyF;IACzF,uGAAuG;CACxG,CAAC;AAEc,iBAAK,GAAG;IACtB,mBAAmB,EAAE,YAAK,CAAC,MAAM,CAAC;QAChC,WAAW,EAAE,sCAAsC;QACnD,GAAG,EAAE,mBAAmB;QACxB,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,QAAQ,EAAE,YAAK,CAAC,MAAM,CAAC;QACrB,WAAW,EACT,+EAA+E;QACjF,GAAG,EAAE,oBAAoB;QACzB,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,GAAG,EAAE,YAAK,CAAC,MAAM,CAAC;QAChB,WAAW,EACT,iFAAiF;QACnF,GAAG,EAAE,eAAe;QACpB,QAAQ,EAAE,IAAI;KACf,CAAC;CACH,CAAC;kBA1BiB,WAAW","sourcesContent":["import { Command, Flags } from '@oclif/core';\n\nimport { ensureDaemon } from '../../daemon/daemon-spawn';\n\nexport default class DaemonStart extends Command {\n static override description = 'Start the wallet daemon';\n\n static override examples = [\n '<%= config.bin %> daemon start --infura-project-id <key> --password <pw> --srp <phrase>',\n 'INFURA_PROJECT_ID=<key> MM_WALLET_PASSWORD=<pw> MM_WALLET_SRP=<phrase> <%= config.bin %> daemon start',\n ];\n\n static override flags = {\n 'infura-project-id': Flags.string({\n description: 'Infura project ID for network access',\n env: 'INFURA_PROJECT_ID',\n required: true,\n }),\n password: Flags.string({\n description:\n 'Wallet password (testing only — use MM_WALLET_PASSWORD env var in production)',\n env: 'MM_WALLET_PASSWORD',\n required: true,\n }),\n srp: Flags.string({\n description:\n 'Secret recovery phrase (testing only — use MM_WALLET_SRP env var in production)',\n env: 'MM_WALLET_SRP',\n required: true,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(DaemonStart);\n const infuraProjectId = flags['infura-project-id'];\n const { password, srp } = flags;\n\n const { state, socketPath } = await ensureDaemon({\n dataDir: this.config.dataDir,\n infuraProjectId,\n password,\n srp,\n packageRoot: this.config.root,\n });\n\n if (state === 'already-running') {\n this.log(\n `Daemon already running. Socket: ${socketPath}. ` +\n `The provided flags were not applied; run \\`mm daemon stop\\` and start again to change them.`,\n );\n return;\n }\n\n this.log(`Daemon running. Socket: ${socketPath}`);\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonStart extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ 'infura-project-id': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ password: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ srp: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=start.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.cts","sourceRoot":"","sources":["../../../src/commands/daemon/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,oBAAoB;AAI7C,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,OAAO;IAC9C,OAAgB,WAAW,SAA6B;IAExD,OAAgB,QAAQ,WAGtB;IAEF,OAAgB,KAAK;;;;MAkBnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAuBlC"}
@@ -0,0 +1,12 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonStart extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ 'infura-project-id': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ password: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ srp: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=start.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.mts","sourceRoot":"","sources":["../../../src/commands/daemon/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,oBAAoB;AAI7C,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,OAAO;IAC9C,OAAgB,WAAW,SAA6B;IAExD,OAAgB,QAAQ,WAGtB;IAEF,OAAgB,KAAK;;;;MAkBnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAuBlC"}
@@ -0,0 +1,46 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import { ensureDaemon } from "../../daemon/daemon-spawn.mjs";
3
+ class DaemonStart extends Command {
4
+ async run() {
5
+ const { flags } = await this.parse(DaemonStart);
6
+ const infuraProjectId = flags['infura-project-id'];
7
+ const { password, srp } = flags;
8
+ const { state, socketPath } = await ensureDaemon({
9
+ dataDir: this.config.dataDir,
10
+ infuraProjectId,
11
+ password,
12
+ srp,
13
+ packageRoot: this.config.root,
14
+ });
15
+ if (state === 'already-running') {
16
+ this.log(`Daemon already running. Socket: ${socketPath}. ` +
17
+ `The provided flags were not applied; run \`mm daemon stop\` and start again to change them.`);
18
+ return;
19
+ }
20
+ this.log(`Daemon running. Socket: ${socketPath}`);
21
+ }
22
+ }
23
+ DaemonStart.description = 'Start the wallet daemon';
24
+ DaemonStart.examples = [
25
+ '<%= config.bin %> daemon start --infura-project-id <key> --password <pw> --srp <phrase>',
26
+ 'INFURA_PROJECT_ID=<key> MM_WALLET_PASSWORD=<pw> MM_WALLET_SRP=<phrase> <%= config.bin %> daemon start',
27
+ ];
28
+ DaemonStart.flags = {
29
+ 'infura-project-id': Flags.string({
30
+ description: 'Infura project ID for network access',
31
+ env: 'INFURA_PROJECT_ID',
32
+ required: true,
33
+ }),
34
+ password: Flags.string({
35
+ description: 'Wallet password (testing only — use MM_WALLET_PASSWORD env var in production)',
36
+ env: 'MM_WALLET_PASSWORD',
37
+ required: true,
38
+ }),
39
+ srp: Flags.string({
40
+ description: 'Secret recovery phrase (testing only — use MM_WALLET_SRP env var in production)',
41
+ env: 'MM_WALLET_SRP',
42
+ required: true,
43
+ }),
44
+ };
45
+ export default DaemonStart;
46
+ //# sourceMappingURL=start.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.mjs","sourceRoot":"","sources":["../../../src/commands/daemon/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB;AAE7C,OAAO,EAAE,YAAY,EAAE,sCAAkC;AAEzD,MAAqB,WAAY,SAAQ,OAAO;IA4BvC,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,eAAe,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACnD,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QAEhC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,YAAY,CAAC;YAC/C,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;YAC5B,eAAe;YACf,QAAQ;YACR,GAAG;YACH,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;SAC9B,CAAC,CAAC;QAEH,IAAI,KAAK,KAAK,iBAAiB,EAAE,CAAC;YAChC,IAAI,CAAC,GAAG,CACN,mCAAmC,UAAU,IAAI;gBAC/C,6FAA6F,CAChG,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,2BAA2B,UAAU,EAAE,CAAC,CAAC;IACpD,CAAC;;AAjDe,uBAAW,GAAG,yBAAyB,CAAC;AAExC,oBAAQ,GAAG;IACzB,yFAAyF;IACzF,uGAAuG;CACxG,CAAC;AAEc,iBAAK,GAAG;IACtB,mBAAmB,EAAE,KAAK,CAAC,MAAM,CAAC;QAChC,WAAW,EAAE,sCAAsC;QACnD,GAAG,EAAE,mBAAmB;QACxB,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC;QACrB,WAAW,EACT,+EAA+E;QACjF,GAAG,EAAE,oBAAoB;QACzB,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC;QAChB,WAAW,EACT,iFAAiF;QACnF,GAAG,EAAE,eAAe;QACpB,QAAQ,EAAE,IAAI;KACf,CAAC;CACH,CAAC;eA1BiB,WAAW","sourcesContent":["import { Command, Flags } from '@oclif/core';\n\nimport { ensureDaemon } from '../../daemon/daemon-spawn';\n\nexport default class DaemonStart extends Command {\n static override description = 'Start the wallet daemon';\n\n static override examples = [\n '<%= config.bin %> daemon start --infura-project-id <key> --password <pw> --srp <phrase>',\n 'INFURA_PROJECT_ID=<key> MM_WALLET_PASSWORD=<pw> MM_WALLET_SRP=<phrase> <%= config.bin %> daemon start',\n ];\n\n static override flags = {\n 'infura-project-id': Flags.string({\n description: 'Infura project ID for network access',\n env: 'INFURA_PROJECT_ID',\n required: true,\n }),\n password: Flags.string({\n description:\n 'Wallet password (testing only — use MM_WALLET_PASSWORD env var in production)',\n env: 'MM_WALLET_PASSWORD',\n required: true,\n }),\n srp: Flags.string({\n description:\n 'Secret recovery phrase (testing only — use MM_WALLET_SRP env var in production)',\n env: 'MM_WALLET_SRP',\n required: true,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(DaemonStart);\n const infuraProjectId = flags['infura-project-id'];\n const { password, srp } = flags;\n\n const { state, socketPath } = await ensureDaemon({\n dataDir: this.config.dataDir,\n infuraProjectId,\n password,\n srp,\n packageRoot: this.config.root,\n });\n\n if (state === 'already-running') {\n this.log(\n `Daemon already running. Socket: ${socketPath}. ` +\n `The provided flags were not applied; run \\`mm daemon stop\\` and start again to change them.`,\n );\n return;\n }\n\n this.log(`Daemon running. Socket: ${socketPath}`);\n }\n}\n"]}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@metamask/utils");
4
+ const core_1 = require("@oclif/core");
5
+ const daemon_client_1 = require("../../daemon/daemon-client.cjs");
6
+ const paths_1 = require("../../daemon/paths.cjs");
7
+ const utils_2 = require("../../daemon/utils.cjs");
8
+ class DaemonStatus extends core_1.Command {
9
+ async run() {
10
+ const { socketPath, pidPath } = (0, paths_1.getDaemonPaths)(this.config.dataDir);
11
+ const pid = await (0, utils_2.readPidFile)(pidPath);
12
+ const ping = await (0, daemon_client_1.pingDaemon)(socketPath);
13
+ if (ping.status === 'absent') {
14
+ // A missing socket alone does not prove the daemon is gone: stopDaemon
15
+ // treats an absent socket plus an alive recorded PID as a daemon that
16
+ // outlived its socket. Surface that orphan here rather than reporting a
17
+ // clean "not running".
18
+ if (pid !== undefined && (0, utils_2.isProcessAlive)(pid)) {
19
+ this.log(`Daemon socket is missing at ${socketPath} but recorded PID ${pid} is still alive. ` +
20
+ `The daemon may be running without its socket; run \`mm daemon stop\` or \`mm daemon purge\`.`);
21
+ return;
22
+ }
23
+ this.log('Daemon is not running.');
24
+ return;
25
+ }
26
+ if (ping.status === 'unreachable') {
27
+ const pidPart = pid === undefined ? '' : ` (recorded PID: ${pid})`;
28
+ this.log(`Daemon socket exists at ${socketPath} but is unresponsive${pidPart} ` +
29
+ `[${ping.reason}]: ${ping.error.message}`);
30
+ return;
31
+ }
32
+ let response;
33
+ try {
34
+ response = await (0, daemon_client_1.sendCommand)({
35
+ socketPath,
36
+ method: 'getStatus',
37
+ timeoutMs: 5000,
38
+ });
39
+ }
40
+ catch (error) {
41
+ this.log(`Daemon socket is responsive but status request failed: ${error instanceof Error ? error.message : String(error)}`);
42
+ return;
43
+ }
44
+ if ((0, utils_1.isJsonRpcFailure)(response)) {
45
+ this.log(`Daemon is running but returned an error: ${response.error.message}`);
46
+ return;
47
+ }
48
+ const status = response.result;
49
+ if (pid !== undefined && pid !== status.pid) {
50
+ this.log(`Warning: PID file records ${pid} but the running daemon reports ${status.pid}. ` +
51
+ `Local state may be stale; consider \`mm daemon purge\`.`);
52
+ }
53
+ this.log(`Daemon is running. PID: ${status.pid}, Uptime: ${status.uptime}s`);
54
+ }
55
+ }
56
+ DaemonStatus.description = 'Check the status of the wallet daemon';
57
+ DaemonStatus.examples = ['<%= config.bin %> daemon status'];
58
+ exports.default = DaemonStatus;
59
+ //# sourceMappingURL=status.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.cjs","sourceRoot":"","sources":["../../../src/commands/daemon/status.ts"],"names":[],"mappings":";;AAAA,2CAAmD;AACnD,sCAAsC;AAEtC,kEAAqE;AACrE,kDAAoD;AAEpD,kDAAiE;AAEjE,MAAqB,YAAa,SAAQ,cAAO;IAKxC,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,IAAA,sBAAc,EAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEpE,MAAM,GAAG,GAAG,MAAM,IAAA,mBAAW,EAAC,OAAO,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,IAAA,0BAAU,EAAC,UAAU,CAAC,CAAC;QAE1C,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC7B,uEAAuE;YACvE,sEAAsE;YACtE,wEAAwE;YACxE,uBAAuB;YACvB,IAAI,GAAG,KAAK,SAAS,IAAI,IAAA,sBAAc,EAAC,GAAG,CAAC,EAAE,CAAC;gBAC7C,IAAI,CAAC,GAAG,CACN,+BAA+B,UAAU,qBAAqB,GAAG,mBAAmB;oBAClF,8FAA8F,CACjG,CAAC;gBACF,OAAO;YACT,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB,GAAG,GAAG,CAAC;YACnE,IAAI,CAAC,GAAG,CACN,2BAA2B,UAAU,uBAAuB,OAAO,GAAG;gBACpE,IAAI,IAAI,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAC5C,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAA,2BAAW,EAAC;gBAC3B,UAAU;gBACV,MAAM,EAAE,WAAW;gBACnB,SAAS,EAAE,IAAK;aACjB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CACN,0DAA0D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACnH,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,IAAA,wBAAgB,EAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,GAAG,CACN,4CAA4C,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,CACrE,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAA0B,CAAC;QACnD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC;YAC5C,IAAI,CAAC,GAAG,CACN,6BAA6B,GAAG,mCAAmC,MAAM,CAAC,GAAG,IAAI;gBAC/E,yDAAyD,CAC5D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CACN,2BAA2B,MAAM,CAAC,GAAG,aAAa,MAAM,CAAC,MAAM,GAAG,CACnE,CAAC;IACJ,CAAC;;AAlEe,wBAAW,GAAG,uCAAuC,CAAC;AAEtD,qBAAQ,GAAG,CAAC,iCAAiC,CAAC,CAAC;kBAH5C,YAAY","sourcesContent":["import { isJsonRpcFailure } from '@metamask/utils';\nimport { Command } from '@oclif/core';\n\nimport { pingDaemon, sendCommand } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport type { DaemonStatusInfo } from '../../daemon/types';\nimport { isProcessAlive, readPidFile } from '../../daemon/utils';\n\nexport default class DaemonStatus extends Command {\n static override description = 'Check the status of the wallet daemon';\n\n static override examples = ['<%= config.bin %> daemon status'];\n\n public async run(): Promise<void> {\n const { socketPath, pidPath } = getDaemonPaths(this.config.dataDir);\n\n const pid = await readPidFile(pidPath);\n const ping = await pingDaemon(socketPath);\n\n if (ping.status === 'absent') {\n // A missing socket alone does not prove the daemon is gone: stopDaemon\n // treats an absent socket plus an alive recorded PID as a daemon that\n // outlived its socket. Surface that orphan here rather than reporting a\n // clean \"not running\".\n if (pid !== undefined && isProcessAlive(pid)) {\n this.log(\n `Daemon socket is missing at ${socketPath} but recorded PID ${pid} is still alive. ` +\n `The daemon may be running without its socket; run \\`mm daemon stop\\` or \\`mm daemon purge\\`.`,\n );\n return;\n }\n this.log('Daemon is not running.');\n return;\n }\n\n if (ping.status === 'unreachable') {\n const pidPart = pid === undefined ? '' : ` (recorded PID: ${pid})`;\n this.log(\n `Daemon socket exists at ${socketPath} but is unresponsive${pidPart} ` +\n `[${ping.reason}]: ${ping.error.message}`,\n );\n return;\n }\n\n let response;\n try {\n response = await sendCommand({\n socketPath,\n method: 'getStatus',\n timeoutMs: 5_000,\n });\n } catch (error) {\n this.log(\n `Daemon socket is responsive but status request failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n return;\n }\n\n if (isJsonRpcFailure(response)) {\n this.log(\n `Daemon is running but returned an error: ${response.error.message}`,\n );\n return;\n }\n\n const status = response.result as DaemonStatusInfo;\n if (pid !== undefined && pid !== status.pid) {\n this.log(\n `Warning: PID file records ${pid} but the running daemon reports ${status.pid}. ` +\n `Local state may be stale; consider \\`mm daemon purge\\`.`,\n );\n }\n this.log(\n `Daemon is running. PID: ${status.pid}, Uptime: ${status.uptime}s`,\n );\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonStatus extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=status.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.cts","sourceRoot":"","sources":["../../../src/commands/daemon/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAOtC,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,OAAO;IAC/C,OAAgB,WAAW,SAA2C;IAEtE,OAAgB,QAAQ,WAAuC;IAElD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA+DlC"}
@@ -0,0 +1,7 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonStatus extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=status.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.mts","sourceRoot":"","sources":["../../../src/commands/daemon/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAOtC,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,OAAO;IAC/C,OAAgB,WAAW,SAA2C;IAEtE,OAAgB,QAAQ,WAAuC;IAElD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA+DlC"}
@@ -0,0 +1,57 @@
1
+ import { isJsonRpcFailure } from "@metamask/utils";
2
+ import { Command } from "@oclif/core";
3
+ import { pingDaemon, sendCommand } from "../../daemon/daemon-client.mjs";
4
+ import { getDaemonPaths } from "../../daemon/paths.mjs";
5
+ import { isProcessAlive, readPidFile } from "../../daemon/utils.mjs";
6
+ class DaemonStatus extends Command {
7
+ async run() {
8
+ const { socketPath, pidPath } = getDaemonPaths(this.config.dataDir);
9
+ const pid = await readPidFile(pidPath);
10
+ const ping = await pingDaemon(socketPath);
11
+ if (ping.status === 'absent') {
12
+ // A missing socket alone does not prove the daemon is gone: stopDaemon
13
+ // treats an absent socket plus an alive recorded PID as a daemon that
14
+ // outlived its socket. Surface that orphan here rather than reporting a
15
+ // clean "not running".
16
+ if (pid !== undefined && isProcessAlive(pid)) {
17
+ this.log(`Daemon socket is missing at ${socketPath} but recorded PID ${pid} is still alive. ` +
18
+ `The daemon may be running without its socket; run \`mm daemon stop\` or \`mm daemon purge\`.`);
19
+ return;
20
+ }
21
+ this.log('Daemon is not running.');
22
+ return;
23
+ }
24
+ if (ping.status === 'unreachable') {
25
+ const pidPart = pid === undefined ? '' : ` (recorded PID: ${pid})`;
26
+ this.log(`Daemon socket exists at ${socketPath} but is unresponsive${pidPart} ` +
27
+ `[${ping.reason}]: ${ping.error.message}`);
28
+ return;
29
+ }
30
+ let response;
31
+ try {
32
+ response = await sendCommand({
33
+ socketPath,
34
+ method: 'getStatus',
35
+ timeoutMs: 5000,
36
+ });
37
+ }
38
+ catch (error) {
39
+ this.log(`Daemon socket is responsive but status request failed: ${error instanceof Error ? error.message : String(error)}`);
40
+ return;
41
+ }
42
+ if (isJsonRpcFailure(response)) {
43
+ this.log(`Daemon is running but returned an error: ${response.error.message}`);
44
+ return;
45
+ }
46
+ const status = response.result;
47
+ if (pid !== undefined && pid !== status.pid) {
48
+ this.log(`Warning: PID file records ${pid} but the running daemon reports ${status.pid}. ` +
49
+ `Local state may be stale; consider \`mm daemon purge\`.`);
50
+ }
51
+ this.log(`Daemon is running. PID: ${status.pid}, Uptime: ${status.uptime}s`);
52
+ }
53
+ }
54
+ DaemonStatus.description = 'Check the status of the wallet daemon';
55
+ DaemonStatus.examples = ['<%= config.bin %> daemon status'];
56
+ export default DaemonStatus;
57
+ //# sourceMappingURL=status.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.mjs","sourceRoot":"","sources":["../../../src/commands/daemon/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,wBAAwB;AACnD,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAEtC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,uCAAmC;AACrE,OAAO,EAAE,cAAc,EAAE,+BAA2B;AAEpD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,+BAA2B;AAEjE,MAAqB,YAAa,SAAQ,OAAO;IAKxC,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEpE,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;QAE1C,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC7B,uEAAuE;YACvE,sEAAsE;YACtE,wEAAwE;YACxE,uBAAuB;YACvB,IAAI,GAAG,KAAK,SAAS,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7C,IAAI,CAAC,GAAG,CACN,+BAA+B,UAAU,qBAAqB,GAAG,mBAAmB;oBAClF,8FAA8F,CACjG,CAAC;gBACF,OAAO;YACT,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB,GAAG,GAAG,CAAC;YACnE,IAAI,CAAC,GAAG,CACN,2BAA2B,UAAU,uBAAuB,OAAO,GAAG;gBACpE,IAAI,IAAI,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAC5C,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,WAAW,CAAC;gBAC3B,UAAU;gBACV,MAAM,EAAE,WAAW;gBACnB,SAAS,EAAE,IAAK;aACjB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CACN,0DAA0D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACnH,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,GAAG,CACN,4CAA4C,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,CACrE,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAA0B,CAAC;QACnD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC;YAC5C,IAAI,CAAC,GAAG,CACN,6BAA6B,GAAG,mCAAmC,MAAM,CAAC,GAAG,IAAI;gBAC/E,yDAAyD,CAC5D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CACN,2BAA2B,MAAM,CAAC,GAAG,aAAa,MAAM,CAAC,MAAM,GAAG,CACnE,CAAC;IACJ,CAAC;;AAlEe,wBAAW,GAAG,uCAAuC,CAAC;AAEtD,qBAAQ,GAAG,CAAC,iCAAiC,CAAC,CAAC;eAH5C,YAAY","sourcesContent":["import { isJsonRpcFailure } from '@metamask/utils';\nimport { Command } from '@oclif/core';\n\nimport { pingDaemon, sendCommand } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport type { DaemonStatusInfo } from '../../daemon/types';\nimport { isProcessAlive, readPidFile } from '../../daemon/utils';\n\nexport default class DaemonStatus extends Command {\n static override description = 'Check the status of the wallet daemon';\n\n static override examples = ['<%= config.bin %> daemon status'];\n\n public async run(): Promise<void> {\n const { socketPath, pidPath } = getDaemonPaths(this.config.dataDir);\n\n const pid = await readPidFile(pidPath);\n const ping = await pingDaemon(socketPath);\n\n if (ping.status === 'absent') {\n // A missing socket alone does not prove the daemon is gone: stopDaemon\n // treats an absent socket plus an alive recorded PID as a daemon that\n // outlived its socket. Surface that orphan here rather than reporting a\n // clean \"not running\".\n if (pid !== undefined && isProcessAlive(pid)) {\n this.log(\n `Daemon socket is missing at ${socketPath} but recorded PID ${pid} is still alive. ` +\n `The daemon may be running without its socket; run \\`mm daemon stop\\` or \\`mm daemon purge\\`.`,\n );\n return;\n }\n this.log('Daemon is not running.');\n return;\n }\n\n if (ping.status === 'unreachable') {\n const pidPart = pid === undefined ? '' : ` (recorded PID: ${pid})`;\n this.log(\n `Daemon socket exists at ${socketPath} but is unresponsive${pidPart} ` +\n `[${ping.reason}]: ${ping.error.message}`,\n );\n return;\n }\n\n let response;\n try {\n response = await sendCommand({\n socketPath,\n method: 'getStatus',\n timeoutMs: 5_000,\n });\n } catch (error) {\n this.log(\n `Daemon socket is responsive but status request failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n return;\n }\n\n if (isJsonRpcFailure(response)) {\n this.log(\n `Daemon is running but returned an error: ${response.error.message}`,\n );\n return;\n }\n\n const status = response.result as DaemonStatusInfo;\n if (pid !== undefined && pid !== status.pid) {\n this.log(\n `Warning: PID file records ${pid} but the running daemon reports ${status.pid}. ` +\n `Local state may be stale; consider \\`mm daemon purge\\`.`,\n );\n }\n this.log(\n `Daemon is running. PID: ${status.pid}, Uptime: ${status.uptime}s`,\n );\n }\n}\n"]}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const daemon_client_1 = require("../../daemon/daemon-client.cjs");
5
+ const paths_1 = require("../../daemon/paths.cjs");
6
+ const stop_daemon_1 = require("../../daemon/stop-daemon.cjs");
7
+ const utils_1 = require("../../daemon/utils.cjs");
8
+ class DaemonStop extends core_1.Command {
9
+ async run() {
10
+ const { socketPath, pidPath } = (0, paths_1.getDaemonPaths)(this.config.dataDir);
11
+ const ping = await (0, daemon_client_1.pingDaemon)(socketPath);
12
+ const pid = await (0, utils_1.readPidFile)(pidPath);
13
+ if (ping.status === 'absent' && pid === undefined) {
14
+ this.log('Daemon is not running.');
15
+ return;
16
+ }
17
+ const stopped = await (0, stop_daemon_1.stopDaemon)(socketPath, pidPath, (message) => this.log(message));
18
+ if (!stopped) {
19
+ this.error('Daemon did not stop within timeout.');
20
+ }
21
+ }
22
+ }
23
+ DaemonStop.description = 'Stop the wallet daemon';
24
+ DaemonStop.examples = ['<%= config.bin %> daemon stop'];
25
+ exports.default = DaemonStop;
26
+ //# sourceMappingURL=stop.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.cjs","sourceRoot":"","sources":["../../../src/commands/daemon/stop.ts"],"names":[],"mappings":";;AAAA,sCAAsC;AAEtC,kEAAwD;AACxD,kDAAoD;AACpD,8DAAsD;AACtD,kDAAiD;AAEjD,MAAqB,UAAW,SAAQ,cAAO;IAKtC,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,IAAA,sBAAc,EAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEpE,MAAM,IAAI,GAAG,MAAM,IAAA,0BAAU,EAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,MAAM,IAAA,mBAAW,EAAC,OAAO,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAClD,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAA,wBAAU,EAAC,UAAU,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAChE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAClB,CAAC;QAEF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;;AArBe,sBAAW,GAAG,wBAAwB,CAAC;AAEvC,mBAAQ,GAAG,CAAC,+BAA+B,CAAC,CAAC;kBAH1C,UAAU","sourcesContent":["import { Command } from '@oclif/core';\n\nimport { pingDaemon } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport { stopDaemon } from '../../daemon/stop-daemon';\nimport { readPidFile } from '../../daemon/utils';\n\nexport default class DaemonStop extends Command {\n static override description = 'Stop the wallet daemon';\n\n static override examples = ['<%= config.bin %> daemon stop'];\n\n public async run(): Promise<void> {\n const { socketPath, pidPath } = getDaemonPaths(this.config.dataDir);\n\n const ping = await pingDaemon(socketPath);\n const pid = await readPidFile(pidPath);\n if (ping.status === 'absent' && pid === undefined) {\n this.log('Daemon is not running.');\n return;\n }\n\n const stopped = await stopDaemon(socketPath, pidPath, (message) =>\n this.log(message),\n );\n\n if (!stopped) {\n this.error('Daemon did not stop within timeout.');\n }\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonStop extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=stop.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.d.cts","sourceRoot":"","sources":["../../../src/commands/daemon/stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAOtC,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,OAAO;IAC7C,OAAgB,WAAW,SAA4B;IAEvD,OAAgB,QAAQ,WAAqC;IAEhD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAkBlC"}
@@ -0,0 +1,7 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonStop extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=stop.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.d.mts","sourceRoot":"","sources":["../../../src/commands/daemon/stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAOtC,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,OAAO;IAC7C,OAAgB,WAAW,SAA4B;IAEvD,OAAgB,QAAQ,WAAqC;IAEhD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAkBlC"}
@@ -0,0 +1,24 @@
1
+ import { Command } from "@oclif/core";
2
+ import { pingDaemon } from "../../daemon/daemon-client.mjs";
3
+ import { getDaemonPaths } from "../../daemon/paths.mjs";
4
+ import { stopDaemon } from "../../daemon/stop-daemon.mjs";
5
+ import { readPidFile } from "../../daemon/utils.mjs";
6
+ class DaemonStop extends Command {
7
+ async run() {
8
+ const { socketPath, pidPath } = getDaemonPaths(this.config.dataDir);
9
+ const ping = await pingDaemon(socketPath);
10
+ const pid = await readPidFile(pidPath);
11
+ if (ping.status === 'absent' && pid === undefined) {
12
+ this.log('Daemon is not running.');
13
+ return;
14
+ }
15
+ const stopped = await stopDaemon(socketPath, pidPath, (message) => this.log(message));
16
+ if (!stopped) {
17
+ this.error('Daemon did not stop within timeout.');
18
+ }
19
+ }
20
+ }
21
+ DaemonStop.description = 'Stop the wallet daemon';
22
+ DaemonStop.examples = ['<%= config.bin %> daemon stop'];
23
+ export default DaemonStop;
24
+ //# sourceMappingURL=stop.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.mjs","sourceRoot":"","sources":["../../../src/commands/daemon/stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAEtC,OAAO,EAAE,UAAU,EAAE,uCAAmC;AACxD,OAAO,EAAE,cAAc,EAAE,+BAA2B;AACpD,OAAO,EAAE,UAAU,EAAE,qCAAiC;AACtD,OAAO,EAAE,WAAW,EAAE,+BAA2B;AAEjD,MAAqB,UAAW,SAAQ,OAAO;IAKtC,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEpE,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAClD,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAChE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAClB,CAAC;QAEF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;;AArBe,sBAAW,GAAG,wBAAwB,CAAC;AAEvC,mBAAQ,GAAG,CAAC,+BAA+B,CAAC,CAAC;eAH1C,UAAU","sourcesContent":["import { Command } from '@oclif/core';\n\nimport { pingDaemon } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport { stopDaemon } from '../../daemon/stop-daemon';\nimport { readPidFile } from '../../daemon/utils';\n\nexport default class DaemonStop extends Command {\n static override description = 'Stop the wallet daemon';\n\n static override examples = ['<%= config.bin %> daemon stop'];\n\n public async run(): Promise<void> {\n const { socketPath, pidPath } = getDaemonPaths(this.config.dataDir);\n\n const ping = await pingDaemon(socketPath);\n const pid = await readPidFile(pidPath);\n if (ping.status === 'absent' && pid === undefined) {\n this.log('Daemon is not running.');\n return;\n }\n\n const stopped = await stopDaemon(socketPath, pidPath, (message) =>\n this.log(message),\n );\n\n if (!stopped) {\n this.error('Daemon did not stop within timeout.');\n }\n }\n}\n"]}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runCommand = void 0;
4
+ const core_1 = require("@oclif/core");
5
+ const errors_1 = require("@oclif/core/errors");
6
+ const TEST_DATA_DIR = '/tmp/mm-cli-test-data';
7
+ const TEST_PACKAGE_ROOT = '/tmp/mm-cli-test-root';
8
+ /**
9
+ * Invoke an oclif command class with the given argv and return the captured
10
+ * stdout/stderr/error so tests can assert on them.
11
+ *
12
+ * Bypasses `Command.run`'s static plugin-loading path (which requires a real
13
+ * `Config.load`) by constructing the command instance directly with a
14
+ * hand-rolled `Config` and invoking the protected `_run`. Spies on the
15
+ * Command prototype so `this.log` and `this.error` go to local buffers
16
+ * instead of stdout/stderr.
17
+ *
18
+ * @param CommandClass - The command class (a subclass of `@oclif/core` Command).
19
+ * @param argv - Command-line tokens (flags + positional args).
20
+ * @returns Captured stdout, stderr, and any `this.error()` payload.
21
+ */
22
+ async function runCommand(CommandClass, argv = []) {
23
+ let stdout = '';
24
+ let stderr = '';
25
+ let error;
26
+ const fakeConfig = {
27
+ dataDir: TEST_DATA_DIR,
28
+ root: TEST_PACKAGE_ROOT,
29
+ bin: 'mm',
30
+ name: '@metamask/wallet-cli',
31
+ version: '0.0.0-test',
32
+ pjson: { name: '@metamask/wallet-cli', version: '0.0.0-test' },
33
+ findCommand: () => undefined,
34
+ runHook: async () => ({ successes: [], failures: [] }),
35
+ scopedEnvVar: () => undefined,
36
+ scopedEnvVarKey: () => '',
37
+ scopedEnvVarKeys: () => [],
38
+ scopedEnvVarTrue: () => false,
39
+ plugins: new Map(),
40
+ flexibleTaxonomy: false,
41
+ };
42
+ const logSpy = jest
43
+ .spyOn(core_1.Command.prototype, 'log')
44
+ .mockImplementation((message = '') => {
45
+ stdout += `${String(message)}\n`;
46
+ });
47
+ const errorSpy = jest
48
+ .spyOn(core_1.Command.prototype, 'error')
49
+ .mockImplementation((input) => {
50
+ const message = typeof input === 'string' ? input : input.message;
51
+ throw new errors_1.CLIError(message);
52
+ });
53
+ try {
54
+ const instance = new CommandClass(argv, fakeConfig);
55
+ await instance._run();
56
+ }
57
+ catch (caught) {
58
+ if (caught instanceof errors_1.CLIError) {
59
+ error = caught;
60
+ stderr += `${caught.message}\n`;
61
+ }
62
+ else {
63
+ throw caught;
64
+ }
65
+ }
66
+ finally {
67
+ logSpy.mockRestore();
68
+ errorSpy.mockRestore();
69
+ }
70
+ return { stdout, stderr, error };
71
+ }
72
+ exports.runCommand = runCommand;
73
+ //# sourceMappingURL=run-command.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-command.cjs","sourceRoot":"","sources":["../../src/test/run-command.ts"],"names":[],"mappings":";;;AAAA,sCAAsC;AAEtC,+CAA8C;AAS9C,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAC9C,MAAM,iBAAiB,GAAG,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;GAaG;AACI,KAAK,UAAU,UAAU,CAC9B,YAAyB,EACzB,OAAiB,EAAE;IAMnB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,KAA2B,CAAC;IAEhC,MAAM,UAAU,GAAG;QACjB,OAAO,EAAE,aAAa;QACtB,IAAI,EAAE,iBAAiB;QACvB,GAAG,EAAE,IAAI;QACT,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,YAAY;QACrB,KAAK,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,YAAY,EAAE;QAC9D,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;QAC5B,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACtD,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS;QAC7B,eAAe,EAAE,GAAG,EAAE,CAAC,EAAE;QACzB,gBAAgB,EAAE,GAAG,EAAE,CAAC,EAAE;QAC1B,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK;QAC7B,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,gBAAgB,EAAE,KAAK;KACH,CAAC;IAEvB,MAAM,MAAM,GAAG,IAAI;SAChB,KAAK,CAAC,cAAO,CAAC,SAAS,EAAE,KAAK,CAAC;SAC/B,kBAAkB,CAAC,CAAC,UAAmB,EAAE,EAAE,EAAE;QAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACnC,CAAC,CAAC,CAAC;IACL,MAAM,QAAQ,GAAG,IAAI;SAClB,KAAK,CAAC,cAAO,CAAC,SAAS,EAAE,OAAO,CAAC;SACjC,kBAAkB,CAAC,CAAC,KAAqB,EAAE,EAAE;QAC5C,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;QAClE,MAAM,IAAI,iBAAQ,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEL,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACpD,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,MAAe,EAAE,CAAC;QACzB,IAAI,MAAM,YAAY,iBAAQ,EAAE,CAAC;YAC/B,KAAK,GAAG,MAAM,CAAC;YACf,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,CAAC;QACf,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,QAAQ,CAAC,WAAW,EAAE,CAAC;IACzB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC;AAzDD,gCAyDC","sourcesContent":["import { Command } from '@oclif/core';\nimport type { Config } from '@oclif/core';\nimport { CLIError } from '@oclif/core/errors';\n\ntype CommandCtor = new (\n argv: string[],\n config: Config,\n) => Command & {\n _run: () => Promise<unknown>;\n};\n\nconst TEST_DATA_DIR = '/tmp/mm-cli-test-data';\nconst TEST_PACKAGE_ROOT = '/tmp/mm-cli-test-root';\n\n/**\n * Invoke an oclif command class with the given argv and return the captured\n * stdout/stderr/error so tests can assert on them.\n *\n * Bypasses `Command.run`'s static plugin-loading path (which requires a real\n * `Config.load`) by constructing the command instance directly with a\n * hand-rolled `Config` and invoking the protected `_run`. Spies on the\n * Command prototype so `this.log` and `this.error` go to local buffers\n * instead of stdout/stderr.\n *\n * @param CommandClass - The command class (a subclass of `@oclif/core` Command).\n * @param argv - Command-line tokens (flags + positional args).\n * @returns Captured stdout, stderr, and any `this.error()` payload.\n */\nexport async function runCommand(\n CommandClass: CommandCtor,\n argv: string[] = [],\n): Promise<{\n stdout: string;\n stderr: string;\n error: CLIError | undefined;\n}> {\n let stdout = '';\n let stderr = '';\n let error: CLIError | undefined;\n\n const fakeConfig = {\n dataDir: TEST_DATA_DIR,\n root: TEST_PACKAGE_ROOT,\n bin: 'mm',\n name: '@metamask/wallet-cli',\n version: '0.0.0-test',\n pjson: { name: '@metamask/wallet-cli', version: '0.0.0-test' },\n findCommand: () => undefined,\n runHook: async () => ({ successes: [], failures: [] }),\n scopedEnvVar: () => undefined,\n scopedEnvVarKey: () => '',\n scopedEnvVarKeys: () => [],\n scopedEnvVarTrue: () => false,\n plugins: new Map(),\n flexibleTaxonomy: false,\n } as unknown as Config;\n\n const logSpy = jest\n .spyOn(Command.prototype, 'log')\n .mockImplementation((message: unknown = '') => {\n stdout += `${String(message)}\\n`;\n });\n const errorSpy = jest\n .spyOn(Command.prototype, 'error')\n .mockImplementation((input: string | Error) => {\n const message = typeof input === 'string' ? input : input.message;\n throw new CLIError(message);\n });\n\n try {\n const instance = new CommandClass(argv, fakeConfig);\n await instance._run();\n } catch (caught: unknown) {\n if (caught instanceof CLIError) {\n error = caught;\n stderr += `${caught.message}\\n`;\n } else {\n throw caught;\n }\n } finally {\n logSpy.mockRestore();\n errorSpy.mockRestore();\n }\n\n return { stdout, stderr, error };\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import { Command } from "@oclif/core";
2
+ import type { Config } from "@oclif/core";
3
+ import { CLIError } from "@oclif/core/errors";
4
+ type CommandCtor = new (argv: string[], config: Config) => Command & {
5
+ _run: () => Promise<unknown>;
6
+ };
7
+ /**
8
+ * Invoke an oclif command class with the given argv and return the captured
9
+ * stdout/stderr/error so tests can assert on them.
10
+ *
11
+ * Bypasses `Command.run`'s static plugin-loading path (which requires a real
12
+ * `Config.load`) by constructing the command instance directly with a
13
+ * hand-rolled `Config` and invoking the protected `_run`. Spies on the
14
+ * Command prototype so `this.log` and `this.error` go to local buffers
15
+ * instead of stdout/stderr.
16
+ *
17
+ * @param CommandClass - The command class (a subclass of `@oclif/core` Command).
18
+ * @param argv - Command-line tokens (flags + positional args).
19
+ * @returns Captured stdout, stderr, and any `this.error()` payload.
20
+ */
21
+ export declare function runCommand(CommandClass: CommandCtor, argv?: string[]): Promise<{
22
+ stdout: string;
23
+ stderr: string;
24
+ error: CLIError | undefined;
25
+ }>;
26
+ export {};
27
+ //# sourceMappingURL=run-command.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-command.d.cts","sourceRoot":"","sources":["../../src/test/run-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB;AAC1C,OAAO,EAAE,QAAQ,EAAE,2BAA2B;AAE9C,KAAK,WAAW,GAAG,KACjB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,MAAM,KACX,OAAO,GAAG;IACb,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9B,CAAC;AAKF;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAC9B,YAAY,EAAE,WAAW,EACzB,IAAI,GAAE,MAAM,EAAO,GAClB,OAAO,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B,CAAC,CAkDD"}
@@ -0,0 +1,27 @@
1
+ import { Command } from "@oclif/core";
2
+ import type { Config } from "@oclif/core";
3
+ import { CLIError } from "@oclif/core/errors";
4
+ type CommandCtor = new (argv: string[], config: Config) => Command & {
5
+ _run: () => Promise<unknown>;
6
+ };
7
+ /**
8
+ * Invoke an oclif command class with the given argv and return the captured
9
+ * stdout/stderr/error so tests can assert on them.
10
+ *
11
+ * Bypasses `Command.run`'s static plugin-loading path (which requires a real
12
+ * `Config.load`) by constructing the command instance directly with a
13
+ * hand-rolled `Config` and invoking the protected `_run`. Spies on the
14
+ * Command prototype so `this.log` and `this.error` go to local buffers
15
+ * instead of stdout/stderr.
16
+ *
17
+ * @param CommandClass - The command class (a subclass of `@oclif/core` Command).
18
+ * @param argv - Command-line tokens (flags + positional args).
19
+ * @returns Captured stdout, stderr, and any `this.error()` payload.
20
+ */
21
+ export declare function runCommand(CommandClass: CommandCtor, argv?: string[]): Promise<{
22
+ stdout: string;
23
+ stderr: string;
24
+ error: CLIError | undefined;
25
+ }>;
26
+ export {};
27
+ //# sourceMappingURL=run-command.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-command.d.mts","sourceRoot":"","sources":["../../src/test/run-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB;AAC1C,OAAO,EAAE,QAAQ,EAAE,2BAA2B;AAE9C,KAAK,WAAW,GAAG,KACjB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,MAAM,KACX,OAAO,GAAG;IACb,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9B,CAAC;AAKF;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAC9B,YAAY,EAAE,WAAW,EACzB,IAAI,GAAE,MAAM,EAAO,GAClB,OAAO,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B,CAAC,CAkDD"}
@@ -0,0 +1,69 @@
1
+ import { Command } from "@oclif/core";
2
+ import { CLIError } from "@oclif/core/errors";
3
+ const TEST_DATA_DIR = '/tmp/mm-cli-test-data';
4
+ const TEST_PACKAGE_ROOT = '/tmp/mm-cli-test-root';
5
+ /**
6
+ * Invoke an oclif command class with the given argv and return the captured
7
+ * stdout/stderr/error so tests can assert on them.
8
+ *
9
+ * Bypasses `Command.run`'s static plugin-loading path (which requires a real
10
+ * `Config.load`) by constructing the command instance directly with a
11
+ * hand-rolled `Config` and invoking the protected `_run`. Spies on the
12
+ * Command prototype so `this.log` and `this.error` go to local buffers
13
+ * instead of stdout/stderr.
14
+ *
15
+ * @param CommandClass - The command class (a subclass of `@oclif/core` Command).
16
+ * @param argv - Command-line tokens (flags + positional args).
17
+ * @returns Captured stdout, stderr, and any `this.error()` payload.
18
+ */
19
+ export async function runCommand(CommandClass, argv = []) {
20
+ let stdout = '';
21
+ let stderr = '';
22
+ let error;
23
+ const fakeConfig = {
24
+ dataDir: TEST_DATA_DIR,
25
+ root: TEST_PACKAGE_ROOT,
26
+ bin: 'mm',
27
+ name: '@metamask/wallet-cli',
28
+ version: '0.0.0-test',
29
+ pjson: { name: '@metamask/wallet-cli', version: '0.0.0-test' },
30
+ findCommand: () => undefined,
31
+ runHook: async () => ({ successes: [], failures: [] }),
32
+ scopedEnvVar: () => undefined,
33
+ scopedEnvVarKey: () => '',
34
+ scopedEnvVarKeys: () => [],
35
+ scopedEnvVarTrue: () => false,
36
+ plugins: new Map(),
37
+ flexibleTaxonomy: false,
38
+ };
39
+ const logSpy = jest
40
+ .spyOn(Command.prototype, 'log')
41
+ .mockImplementation((message = '') => {
42
+ stdout += `${String(message)}\n`;
43
+ });
44
+ const errorSpy = jest
45
+ .spyOn(Command.prototype, 'error')
46
+ .mockImplementation((input) => {
47
+ const message = typeof input === 'string' ? input : input.message;
48
+ throw new CLIError(message);
49
+ });
50
+ try {
51
+ const instance = new CommandClass(argv, fakeConfig);
52
+ await instance._run();
53
+ }
54
+ catch (caught) {
55
+ if (caught instanceof CLIError) {
56
+ error = caught;
57
+ stderr += `${caught.message}\n`;
58
+ }
59
+ else {
60
+ throw caught;
61
+ }
62
+ }
63
+ finally {
64
+ logSpy.mockRestore();
65
+ errorSpy.mockRestore();
66
+ }
67
+ return { stdout, stderr, error };
68
+ }
69
+ //# sourceMappingURL=run-command.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-command.mjs","sourceRoot":"","sources":["../../src/test/run-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAEtC,OAAO,EAAE,QAAQ,EAAE,2BAA2B;AAS9C,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAC9C,MAAM,iBAAiB,GAAG,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,YAAyB,EACzB,OAAiB,EAAE;IAMnB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,KAA2B,CAAC;IAEhC,MAAM,UAAU,GAAG;QACjB,OAAO,EAAE,aAAa;QACtB,IAAI,EAAE,iBAAiB;QACvB,GAAG,EAAE,IAAI;QACT,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,YAAY;QACrB,KAAK,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,YAAY,EAAE;QAC9D,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;QAC5B,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACtD,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS;QAC7B,eAAe,EAAE,GAAG,EAAE,CAAC,EAAE;QACzB,gBAAgB,EAAE,GAAG,EAAE,CAAC,EAAE;QAC1B,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK;QAC7B,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,gBAAgB,EAAE,KAAK;KACH,CAAC;IAEvB,MAAM,MAAM,GAAG,IAAI;SAChB,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC;SAC/B,kBAAkB,CAAC,CAAC,UAAmB,EAAE,EAAE,EAAE;QAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACnC,CAAC,CAAC,CAAC;IACL,MAAM,QAAQ,GAAG,IAAI;SAClB,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC;SACjC,kBAAkB,CAAC,CAAC,KAAqB,EAAE,EAAE;QAC5C,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;QAClE,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEL,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACpD,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,MAAe,EAAE,CAAC;QACzB,IAAI,MAAM,YAAY,QAAQ,EAAE,CAAC;YAC/B,KAAK,GAAG,MAAM,CAAC;YACf,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,CAAC;QACf,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,QAAQ,CAAC,WAAW,EAAE,CAAC;IACzB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC","sourcesContent":["import { Command } from '@oclif/core';\nimport type { Config } from '@oclif/core';\nimport { CLIError } from '@oclif/core/errors';\n\ntype CommandCtor = new (\n argv: string[],\n config: Config,\n) => Command & {\n _run: () => Promise<unknown>;\n};\n\nconst TEST_DATA_DIR = '/tmp/mm-cli-test-data';\nconst TEST_PACKAGE_ROOT = '/tmp/mm-cli-test-root';\n\n/**\n * Invoke an oclif command class with the given argv and return the captured\n * stdout/stderr/error so tests can assert on them.\n *\n * Bypasses `Command.run`'s static plugin-loading path (which requires a real\n * `Config.load`) by constructing the command instance directly with a\n * hand-rolled `Config` and invoking the protected `_run`. Spies on the\n * Command prototype so `this.log` and `this.error` go to local buffers\n * instead of stdout/stderr.\n *\n * @param CommandClass - The command class (a subclass of `@oclif/core` Command).\n * @param argv - Command-line tokens (flags + positional args).\n * @returns Captured stdout, stderr, and any `this.error()` payload.\n */\nexport async function runCommand(\n CommandClass: CommandCtor,\n argv: string[] = [],\n): Promise<{\n stdout: string;\n stderr: string;\n error: CLIError | undefined;\n}> {\n let stdout = '';\n let stderr = '';\n let error: CLIError | undefined;\n\n const fakeConfig = {\n dataDir: TEST_DATA_DIR,\n root: TEST_PACKAGE_ROOT,\n bin: 'mm',\n name: '@metamask/wallet-cli',\n version: '0.0.0-test',\n pjson: { name: '@metamask/wallet-cli', version: '0.0.0-test' },\n findCommand: () => undefined,\n runHook: async () => ({ successes: [], failures: [] }),\n scopedEnvVar: () => undefined,\n scopedEnvVarKey: () => '',\n scopedEnvVarKeys: () => [],\n scopedEnvVarTrue: () => false,\n plugins: new Map(),\n flexibleTaxonomy: false,\n } as unknown as Config;\n\n const logSpy = jest\n .spyOn(Command.prototype, 'log')\n .mockImplementation((message: unknown = '') => {\n stdout += `${String(message)}\\n`;\n });\n const errorSpy = jest\n .spyOn(Command.prototype, 'error')\n .mockImplementation((input: string | Error) => {\n const message = typeof input === 'string' ? input : input.message;\n throw new CLIError(message);\n });\n\n try {\n const instance = new CommandClass(argv, fakeConfig);\n await instance._run();\n } catch (caught: unknown) {\n if (caught instanceof CLIError) {\n error = caught;\n stderr += `${caught.message}\\n`;\n } else {\n throw caught;\n }\n } finally {\n logSpy.mockRestore();\n errorSpy.mockRestore();\n }\n\n return { stdout, stderr, error };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/wallet-cli",
3
- "version": "0.0.0-preview-43e6d6596",
3
+ "version": "0.0.0-preview-d7951629b",
4
4
  "description": "The CLI of @metamask/wallet",
5
5
  "keywords": [
6
6
  "Ethereum",
@@ -61,7 +61,9 @@
61
61
  "@types/jest": "^29.5.14",
62
62
  "deepmerge": "^4.2.2",
63
63
  "jest": "^29.7.0",
64
+ "jest-environment-node": "^29.7.0",
64
65
  "ts-jest": "^29.2.5",
66
+ "tsx": "^4.20.5",
65
67
  "typescript": "~5.3.3"
66
68
  },
67
69
  "oclif": {