@metamask-previews/wallet-cli 0.0.0-preview-ea5e7f6d0 → 0.0.0-preview-34f2bcbf7

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 (93) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/README.md +41 -0
  3. package/dist/commands/daemon/call.cjs +79 -0
  4. package/dist/commands/daemon/call.cjs.map +1 -0
  5. package/dist/commands/daemon/call.d.cts +14 -0
  6. package/dist/commands/daemon/call.d.cts.map +1 -0
  7. package/dist/commands/daemon/call.d.mts +14 -0
  8. package/dist/commands/daemon/call.d.mts.map +1 -0
  9. package/dist/commands/daemon/call.mjs +77 -0
  10. package/dist/commands/daemon/call.mjs.map +1 -0
  11. package/dist/commands/daemon/list.cjs +48 -0
  12. package/dist/commands/daemon/list.cjs.map +1 -0
  13. package/dist/commands/daemon/list.d.cts +7 -0
  14. package/dist/commands/daemon/list.d.cts.map +1 -0
  15. package/dist/commands/daemon/list.d.mts +7 -0
  16. package/dist/commands/daemon/list.d.mts.map +1 -0
  17. package/dist/commands/daemon/list.mjs +46 -0
  18. package/dist/commands/daemon/list.mjs.map +1 -0
  19. package/dist/commands/daemon/purge.cjs +58 -0
  20. package/dist/commands/daemon/purge.cjs.map +1 -0
  21. package/dist/commands/daemon/purge.d.cts +10 -0
  22. package/dist/commands/daemon/purge.d.cts.map +1 -0
  23. package/dist/commands/daemon/purge.d.mts +10 -0
  24. package/dist/commands/daemon/purge.d.mts.map +1 -0
  25. package/dist/commands/daemon/purge.mjs +56 -0
  26. package/dist/commands/daemon/purge.mjs.map +1 -0
  27. package/dist/commands/daemon/start.cjs +48 -0
  28. package/dist/commands/daemon/start.cjs.map +1 -0
  29. package/dist/commands/daemon/start.d.cts +12 -0
  30. package/dist/commands/daemon/start.d.cts.map +1 -0
  31. package/dist/commands/daemon/start.d.mts +12 -0
  32. package/dist/commands/daemon/start.d.mts.map +1 -0
  33. package/dist/commands/daemon/start.mjs +46 -0
  34. package/dist/commands/daemon/start.mjs.map +1 -0
  35. package/dist/commands/daemon/status.cjs +59 -0
  36. package/dist/commands/daemon/status.cjs.map +1 -0
  37. package/dist/commands/daemon/status.d.cts +7 -0
  38. package/dist/commands/daemon/status.d.cts.map +1 -0
  39. package/dist/commands/daemon/status.d.mts +7 -0
  40. package/dist/commands/daemon/status.d.mts.map +1 -0
  41. package/dist/commands/daemon/status.mjs +57 -0
  42. package/dist/commands/daemon/status.mjs.map +1 -0
  43. package/dist/commands/daemon/stop.cjs +26 -0
  44. package/dist/commands/daemon/stop.cjs.map +1 -0
  45. package/dist/commands/daemon/stop.d.cts +7 -0
  46. package/dist/commands/daemon/stop.d.cts.map +1 -0
  47. package/dist/commands/daemon/stop.d.mts +7 -0
  48. package/dist/commands/daemon/stop.d.mts.map +1 -0
  49. package/dist/commands/daemon/stop.mjs +24 -0
  50. package/dist/commands/daemon/stop.mjs.map +1 -0
  51. package/dist/daemon/daemon-entry.cjs +4 -0
  52. package/dist/daemon/daemon-entry.cjs.map +1 -1
  53. package/dist/daemon/daemon-entry.mjs +4 -0
  54. package/dist/daemon/daemon-entry.mjs.map +1 -1
  55. package/dist/daemon/daemon-spawn.cjs +46 -25
  56. package/dist/daemon/daemon-spawn.cjs.map +1 -1
  57. package/dist/daemon/daemon-spawn.d.cts.map +1 -1
  58. package/dist/daemon/daemon-spawn.d.mts.map +1 -1
  59. package/dist/daemon/daemon-spawn.mjs +47 -26
  60. package/dist/daemon/daemon-spawn.mjs.map +1 -1
  61. package/dist/daemon/socket-line.cjs +8 -4
  62. package/dist/daemon/socket-line.cjs.map +1 -1
  63. package/dist/daemon/socket-line.d.cts +2 -0
  64. package/dist/daemon/socket-line.d.cts.map +1 -1
  65. package/dist/daemon/socket-line.d.mts +2 -0
  66. package/dist/daemon/socket-line.d.mts.map +1 -1
  67. package/dist/daemon/socket-line.mjs +8 -4
  68. package/dist/daemon/socket-line.mjs.map +1 -1
  69. package/dist/daemon/stop-daemon.cjs +23 -9
  70. package/dist/daemon/stop-daemon.cjs.map +1 -1
  71. package/dist/daemon/stop-daemon.d.cts +17 -7
  72. package/dist/daemon/stop-daemon.d.cts.map +1 -1
  73. package/dist/daemon/stop-daemon.d.mts +17 -7
  74. package/dist/daemon/stop-daemon.d.mts.map +1 -1
  75. package/dist/daemon/stop-daemon.mjs +23 -9
  76. package/dist/daemon/stop-daemon.mjs.map +1 -1
  77. package/dist/daemon/utils.cjs +52 -1
  78. package/dist/daemon/utils.cjs.map +1 -1
  79. package/dist/daemon/utils.d.cts +28 -0
  80. package/dist/daemon/utils.d.cts.map +1 -1
  81. package/dist/daemon/utils.d.mts +28 -0
  82. package/dist/daemon/utils.d.mts.map +1 -1
  83. package/dist/daemon/utils.mjs +48 -0
  84. package/dist/daemon/utils.mjs.map +1 -1
  85. package/dist/test/run-command.cjs +73 -0
  86. package/dist/test/run-command.cjs.map +1 -0
  87. package/dist/test/run-command.d.cts +27 -0
  88. package/dist/test/run-command.d.cts.map +1 -0
  89. package/dist/test/run-command.d.mts +27 -0
  90. package/dist/test/run-command.d.mts.map +1 -0
  91. package/dist/test/run-command.mjs +69 -0
  92. package/dist/test/run-command.mjs.map +1 -0
  93. package/package.json +5 -2
package/CHANGELOG.md CHANGED
@@ -9,6 +9,8 @@ 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 list` command, which prints the messenger actions the running daemon can dispatch via `daemon call`, enumerated from the live messenger so the list cannot drift from what `call` accepts ([#9339](https://github.com/MetaMask/core/pull/9339))
13
+ - 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
14
  - 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
15
  - 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
16
  - Add SQLite-backed persistence for wallet controller state ([#9067](https://github.com/MetaMask/core/pull/9067))
@@ -16,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
18
 
17
19
  ### Changed
18
20
 
19
- - Bump `@metamask/wallet` from `^3.0.0` to `^5.0.0` ([#9218](https://github.com/MetaMask/core/pull/9218), [#9263](https://github.com/MetaMask/core/pull/9263))
21
+ - Report daemon socket connection errors consistently across `mm daemon call` and `mm daemon list` ([#9339](https://github.com/MetaMask/core/pull/9339))
22
+ - Bump `@metamask/wallet` from `^3.0.0` to `^7.0.0` ([#9218](https://github.com/MetaMask/core/pull/9218), [#9263](https://github.com/MetaMask/core/pull/9263), [#9349](https://github.com/MetaMask/core/pull/9349), [#9396](https://github.com/MetaMask/core/pull/9396))
20
23
 
21
24
  [Unreleased]: https://github.com/MetaMask/core/
package/README.md CHANGED
@@ -10,6 +10,41 @@ 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
+ Discover what the running wallet can do — `list` prints every messenger action currently dispatchable via `call`. This surface grows as more controllers are wired, so treat it as evolving rather than a stability contract:
24
+
25
+ ```sh
26
+ mm daemon list
27
+ ```
28
+
29
+ Call any messenger action on the running wallet (positional JSON array for arguments, optional `--timeout`):
30
+
31
+ ```sh
32
+ mm daemon call KeyringController:getState
33
+ mm daemon call NetworkController:getState --timeout 10000
34
+ ```
35
+
36
+ For the exact parameters and return shape of a given action, see the TypeDoc/README of the controller that owns it (e.g. [`@metamask/keyring-controller`](https://github.com/MetaMask/core/tree/main/packages/keyring-controller#readme)).
37
+
38
+ Inspect or tear it down:
39
+
40
+ ```sh
41
+ mm daemon status # PID + uptime, or why the socket is unreachable
42
+ mm daemon stop # graceful shutdown (falls back to SIGTERM/SIGKILL)
43
+ mm daemon purge # stop, then delete all daemon state files (--force to skip the prompt)
44
+ ```
45
+
46
+ State (socket, PID file, log, and the SQLite database) lives in the per-user oclif data directory; override it with `MM_DATA_DIR`.
47
+
13
48
  ## Troubleshooting
14
49
 
15
50
  ### Rebuilding `better-sqlite3`
@@ -28,6 +63,12 @@ Or invoke `prebuild-install` directly from the monorepo root (where `better-sqli
28
63
  cd node_modules/better-sqlite3 && node ../.bin/prebuild-install
29
64
  ```
30
65
 
66
+ ## Testing
67
+
68
+ Unit tests run with `yarn workspace @metamask/wallet-cli test`.
69
+
70
+ The subprocess end-to-end suite (in `tests/`) spawns the built `mm` CLI and the native `better-sqlite3` addon as real processes, so it is kept out of the unit run and its coverage gate. Build the workspace dependencies first (`yarn build` from the repo root), then run it with `yarn workspace @metamask/wallet-cli test:e2e`.
71
+
31
72
  ## Contributing
32
73
 
33
74
  This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
@@ -0,0 +1,79 @@
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
+ this.error((0, utils_2.makeDaemonConnectionError)(error));
42
+ }
43
+ if ((0, utils_1.isJsonRpcFailure)(response)) {
44
+ this.error((0, utils_2.formatJsonRpcError)(response.error));
45
+ }
46
+ const isTTY = process.stdout.isTTY ?? false;
47
+ if (isTTY) {
48
+ this.log(JSON.stringify(response.result, null, 2));
49
+ }
50
+ else {
51
+ process.stdout.write(`${JSON.stringify(response.result)}\n`);
52
+ }
53
+ }
54
+ }
55
+ DaemonCall.description = 'Call a messenger action on the wallet daemon';
56
+ DaemonCall.examples = [
57
+ '<%= config.bin %> daemon call KeyringController:getState',
58
+ '<%= config.bin %> daemon call NetworkController:getState',
59
+ '<%= config.bin %> daemon call ApprovalController:getState --timeout 10000',
60
+ ];
61
+ DaemonCall.args = {
62
+ action: core_1.Args.string({
63
+ description: 'The messenger action name (e.g. KeyringController:getState)',
64
+ required: true,
65
+ }),
66
+ params: core_1.Args.string({
67
+ description: 'JSON-encoded arguments array (e.g. \'["arg1", "arg2"]\')',
68
+ required: false,
69
+ }),
70
+ };
71
+ DaemonCall.flags = {
72
+ timeout: core_1.Flags.integer({
73
+ char: 't',
74
+ description: 'Response timeout in milliseconds',
75
+ required: false,
76
+ }),
77
+ };
78
+ exports.default = DaemonCall;
79
+ //# 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 {\n formatJsonRpcError,\n makeDaemonConnectionError,\n} 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. KeyringController:getState)',\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 this.error(makeDaemonConnectionError(error));\n }\n\n if (isJsonRpcFailure(response)) {\n this.error(formatJsonRpcError(response.error));\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;AASnD,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;CAiDlC"}
@@ -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;AASnD,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;CAiDlC"}
@@ -0,0 +1,77 @@
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 { formatJsonRpcError, makeDaemonConnectionError } 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
+ this.error(makeDaemonConnectionError(error));
40
+ }
41
+ if (isJsonRpcFailure(response)) {
42
+ this.error(formatJsonRpcError(response.error));
43
+ }
44
+ const isTTY = process.stdout.isTTY ?? false;
45
+ if (isTTY) {
46
+ this.log(JSON.stringify(response.result, null, 2));
47
+ }
48
+ else {
49
+ process.stdout.write(`${JSON.stringify(response.result)}\n`);
50
+ }
51
+ }
52
+ }
53
+ DaemonCall.description = 'Call a messenger action on the wallet daemon';
54
+ DaemonCall.examples = [
55
+ '<%= config.bin %> daemon call KeyringController:getState',
56
+ '<%= config.bin %> daemon call NetworkController:getState',
57
+ '<%= config.bin %> daemon call ApprovalController:getState --timeout 10000',
58
+ ];
59
+ DaemonCall.args = {
60
+ action: Args.string({
61
+ description: 'The messenger action name (e.g. KeyringController:getState)',
62
+ required: true,
63
+ }),
64
+ params: Args.string({
65
+ description: 'JSON-encoded arguments array (e.g. \'["arg1", "arg2"]\')',
66
+ required: false,
67
+ }),
68
+ };
69
+ DaemonCall.flags = {
70
+ timeout: Flags.integer({
71
+ char: 't',
72
+ description: 'Response timeout in milliseconds',
73
+ required: false,
74
+ }),
75
+ };
76
+ export default DaemonCall;
77
+ //# 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 {\n formatJsonRpcError,\n makeDaemonConnectionError,\n} 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. KeyringController:getState)',\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 this.error(makeDaemonConnectionError(error));\n }\n\n if (isJsonRpcFailure(response)) {\n this.error(formatJsonRpcError(response.error));\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,48 @@
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 DaemonList extends core_1.Command {
9
+ async run() {
10
+ await this.parse(DaemonList);
11
+ const { socketPath } = (0, paths_1.getDaemonPaths)(this.config.dataDir);
12
+ let response;
13
+ try {
14
+ response = await (0, daemon_client_1.sendCommand)({ socketPath, method: 'listActions' });
15
+ }
16
+ catch (error) {
17
+ this.error((0, utils_2.makeDaemonConnectionError)(error));
18
+ }
19
+ if ((0, utils_1.isJsonRpcFailure)(response)) {
20
+ this.error((0, utils_2.formatJsonRpcError)(response.error));
21
+ }
22
+ if (!(0, utils_2.isStringArray)(response.result)) {
23
+ this.error('Daemon returned an unexpected action list.');
24
+ }
25
+ const actions = [...response.result].sort();
26
+ const isTTY = process.stdout.isTTY ?? false;
27
+ if (!isTTY) {
28
+ // Bare output so it pipes cleanly into `grep`/`fzf`.
29
+ if (actions.length > 0) {
30
+ process.stdout.write(`${actions.join('\n')}\n`);
31
+ }
32
+ return;
33
+ }
34
+ if (actions.length === 0) {
35
+ this.log('The daemon has no callable actions registered.');
36
+ return;
37
+ }
38
+ this.log(`${actions.length} callable action${actions.length === 1 ? '' : 's'} ` +
39
+ '(dispatch with `mm daemon call <action>`):');
40
+ for (const action of actions) {
41
+ this.log(` ${action}`);
42
+ }
43
+ }
44
+ }
45
+ DaemonList.description = 'List the messenger actions the running daemon can dispatch via `daemon call`';
46
+ DaemonList.examples = ['<%= config.bin %> daemon list'];
47
+ exports.default = DaemonList;
48
+ //# sourceMappingURL=list.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.cjs","sourceRoot":"","sources":["../../../src/commands/daemon/list.ts"],"names":[],"mappings":";;AAAA,2CAAmD;AACnD,sCAAsC;AAEtC,kEAAyD;AACzD,kDAAoD;AACpD,kDAI4B;AAE5B,MAAqB,UAAW,SAAQ,cAAO;IAMtC,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC7B,MAAM,EAAE,UAAU,EAAE,GAAG,IAAA,sBAAc,EAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAE3D,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAA,2BAAW,EAAC,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,IAAA,iCAAyB,EAAC,KAAK,CAAC,CAAC,CAAC;QAC/C,CAAC;QAED,IAAI,IAAA,wBAAgB,EAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,IAAA,0BAAkB,EAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,CAAC,IAAA,qBAAa,EAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAE5C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;QAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,qDAAqD;YACrD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClD,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,IAAI,CAAC,GAAG,CACN,GAAG,OAAO,CAAC,MAAM,mBAAmB,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG;YACpE,4CAA4C,CAC/C,CAAC;QACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;;AA/Ce,sBAAW,GACzB,8EAA8E,CAAC;AAEjE,mBAAQ,GAAG,CAAC,+BAA+B,CAAC,CAAC;kBAJ1C,UAAU","sourcesContent":["import { isJsonRpcFailure } from '@metamask/utils';\nimport { Command } from '@oclif/core';\n\nimport { sendCommand } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport {\n formatJsonRpcError,\n isStringArray,\n makeDaemonConnectionError,\n} from '../../daemon/utils';\n\nexport default class DaemonList extends Command {\n static override description =\n 'List the messenger actions the running daemon can dispatch via `daemon call`';\n\n static override examples = ['<%= config.bin %> daemon list'];\n\n public async run(): Promise<void> {\n await this.parse(DaemonList);\n const { socketPath } = getDaemonPaths(this.config.dataDir);\n\n let response;\n try {\n response = await sendCommand({ socketPath, method: 'listActions' });\n } catch (error) {\n this.error(makeDaemonConnectionError(error));\n }\n\n if (isJsonRpcFailure(response)) {\n this.error(formatJsonRpcError(response.error));\n }\n\n if (!isStringArray(response.result)) {\n this.error('Daemon returned an unexpected action list.');\n }\n\n const actions = [...response.result].sort();\n\n const isTTY = process.stdout.isTTY ?? false;\n if (!isTTY) {\n // Bare output so it pipes cleanly into `grep`/`fzf`.\n if (actions.length > 0) {\n process.stdout.write(`${actions.join('\\n')}\\n`);\n }\n return;\n }\n\n if (actions.length === 0) {\n this.log('The daemon has no callable actions registered.');\n return;\n }\n\n this.log(\n `${actions.length} callable action${actions.length === 1 ? '' : 's'} ` +\n '(dispatch with `mm daemon call <action>`):',\n );\n for (const action of actions) {\n this.log(` ${action}`);\n }\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonList extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=list.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.cts","sourceRoot":"","sources":["../../../src/commands/daemon/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAUtC,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,OAAO;IAC7C,OAAgB,WAAW,SACsD;IAEjF,OAAgB,QAAQ,WAAqC;IAEhD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA2ClC"}
@@ -0,0 +1,7 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class DaemonList extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=list.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.mts","sourceRoot":"","sources":["../../../src/commands/daemon/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAUtC,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,OAAO;IAC7C,OAAgB,WAAW,SACsD;IAEjF,OAAgB,QAAQ,WAAqC;IAEhD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA2ClC"}
@@ -0,0 +1,46 @@
1
+ import { isJsonRpcFailure } from "@metamask/utils";
2
+ import { Command } from "@oclif/core";
3
+ import { sendCommand } from "../../daemon/daemon-client.mjs";
4
+ import { getDaemonPaths } from "../../daemon/paths.mjs";
5
+ import { formatJsonRpcError, isStringArray, makeDaemonConnectionError } from "../../daemon/utils.mjs";
6
+ class DaemonList extends Command {
7
+ async run() {
8
+ await this.parse(DaemonList);
9
+ const { socketPath } = getDaemonPaths(this.config.dataDir);
10
+ let response;
11
+ try {
12
+ response = await sendCommand({ socketPath, method: 'listActions' });
13
+ }
14
+ catch (error) {
15
+ this.error(makeDaemonConnectionError(error));
16
+ }
17
+ if (isJsonRpcFailure(response)) {
18
+ this.error(formatJsonRpcError(response.error));
19
+ }
20
+ if (!isStringArray(response.result)) {
21
+ this.error('Daemon returned an unexpected action list.');
22
+ }
23
+ const actions = [...response.result].sort();
24
+ const isTTY = process.stdout.isTTY ?? false;
25
+ if (!isTTY) {
26
+ // Bare output so it pipes cleanly into `grep`/`fzf`.
27
+ if (actions.length > 0) {
28
+ process.stdout.write(`${actions.join('\n')}\n`);
29
+ }
30
+ return;
31
+ }
32
+ if (actions.length === 0) {
33
+ this.log('The daemon has no callable actions registered.');
34
+ return;
35
+ }
36
+ this.log(`${actions.length} callable action${actions.length === 1 ? '' : 's'} ` +
37
+ '(dispatch with `mm daemon call <action>`):');
38
+ for (const action of actions) {
39
+ this.log(` ${action}`);
40
+ }
41
+ }
42
+ }
43
+ DaemonList.description = 'List the messenger actions the running daemon can dispatch via `daemon call`';
44
+ DaemonList.examples = ['<%= config.bin %> daemon list'];
45
+ export default DaemonList;
46
+ //# sourceMappingURL=list.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.mjs","sourceRoot":"","sources":["../../../src/commands/daemon/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,wBAAwB;AACnD,OAAO,EAAE,OAAO,EAAE,oBAAoB;AAEtC,OAAO,EAAE,WAAW,EAAE,uCAAmC;AACzD,OAAO,EAAE,cAAc,EAAE,+BAA2B;AACpD,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EAC1B,+BAA2B;AAE5B,MAAqB,UAAW,SAAQ,OAAO;IAMtC,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC7B,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAE3D,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,WAAW,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/C,CAAC;QAED,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAE5C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;QAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,qDAAqD;YACrD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClD,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,IAAI,CAAC,GAAG,CACN,GAAG,OAAO,CAAC,MAAM,mBAAmB,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG;YACpE,4CAA4C,CAC/C,CAAC;QACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;;AA/Ce,sBAAW,GACzB,8EAA8E,CAAC;AAEjE,mBAAQ,GAAG,CAAC,+BAA+B,CAAC,CAAC;eAJ1C,UAAU","sourcesContent":["import { isJsonRpcFailure } from '@metamask/utils';\nimport { Command } from '@oclif/core';\n\nimport { sendCommand } from '../../daemon/daemon-client';\nimport { getDaemonPaths } from '../../daemon/paths';\nimport {\n formatJsonRpcError,\n isStringArray,\n makeDaemonConnectionError,\n} from '../../daemon/utils';\n\nexport default class DaemonList extends Command {\n static override description =\n 'List the messenger actions the running daemon can dispatch via `daemon call`';\n\n static override examples = ['<%= config.bin %> daemon list'];\n\n public async run(): Promise<void> {\n await this.parse(DaemonList);\n const { socketPath } = getDaemonPaths(this.config.dataDir);\n\n let response;\n try {\n response = await sendCommand({ socketPath, method: 'listActions' });\n } catch (error) {\n this.error(makeDaemonConnectionError(error));\n }\n\n if (isJsonRpcFailure(response)) {\n this.error(formatJsonRpcError(response.error));\n }\n\n if (!isStringArray(response.result)) {\n this.error('Daemon returned an unexpected action list.');\n }\n\n const actions = [...response.result].sort();\n\n const isTTY = process.stdout.isTTY ?? false;\n if (!isTTY) {\n // Bare output so it pipes cleanly into `grep`/`fzf`.\n if (actions.length > 0) {\n process.stdout.write(`${actions.join('\\n')}\\n`);\n }\n return;\n }\n\n if (actions.length === 0) {\n this.log('The daemon has no callable actions registered.');\n return;\n }\n\n this.log(\n `${actions.length} callable action${actions.length === 1 ? '' : 's'} ` +\n '(dispatch with `mm daemon call <action>`):',\n );\n for (const action of actions) {\n this.log(` ${action}`);\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"]}