milagre 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/package.json +1 -1
- package/src/command-help.cjs +91 -0
- package/src/command.cjs +8 -25
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ npm install --global milagre
|
|
|
15
15
|
milagre serve
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
`milagre help` lists the commands. Use `milagre help serve` or `milagre serve --help` for a command's flags and examples. Help uses color in interactive terminals and plain text when piped; `NO_COLOR` disables color.
|
|
19
|
+
|
|
18
20
|
`serve` runs in the foreground and uses `~/.milagre/server` for its persistent profile. It prints a private pairing link and, in an interactive terminal, a phone QR code. In another desktop's Settings > Devices > Add computer, paste the link. Approve the computer from another terminal on the server:
|
|
19
21
|
|
|
20
22
|
```sh
|
|
@@ -38,4 +40,4 @@ Use `MILAGRE_DATA_DIR` or an absolute `--data-dir` to select another profile. Us
|
|
|
38
40
|
|
|
39
41
|
Ctrl+C and SIGTERM save and stop the server. Use `milagre serve --no-pair` for unattended restarts without printing links or opening a new pairing window. It retains access for devices already paired. `--no-qr` prints links without QR codes. No startup service is installed automatically; run the foreground command through your service manager for an always-on computer.
|
|
40
42
|
|
|
41
|
-
From the repository, `npm run cli -- serve` runs the same command. `npm run package:cli` produces the installable tarball in `release/cli/`; it bundles the private Milagre packages, without Electron. npm installs registry dependencies and sets up native dependencies for the computer where you install it. You can also install that tarball with `npm install --global ./milagre-0.1.
|
|
43
|
+
From the repository, `npm run cli -- serve` runs the same command. `npm run package:cli` produces the installable tarball in `release/cli/`; it bundles the private Milagre packages, without Electron. npm installs registry dependencies and sets up native dependencies for the computer where you install it. You can also install that tarball with `npm install --global ./milagre-0.1.1.tgz`.
|
package/package.json
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const GLOBAL_FLAGS = [
|
|
2
|
+
["--data-dir <path>", "Absolute profile path (MILAGRE_DATA_DIR or ~/.milagre/server)."],
|
|
3
|
+
["--help, -h", "Show command help."],
|
|
4
|
+
["--version, -v", "Show the CLI version."],
|
|
5
|
+
];
|
|
6
|
+
|
|
7
|
+
const COMMANDS = {
|
|
8
|
+
serve: {
|
|
9
|
+
description: "Run the server without a desktop UI and print pairing details.",
|
|
10
|
+
usage: "milagre serve [flags]",
|
|
11
|
+
flags: [
|
|
12
|
+
["--project <path>", "Open a Project on startup. Can be repeated."],
|
|
13
|
+
["--no-pair", "Keep existing device access without opening a pairing window."],
|
|
14
|
+
["--no-qr", "Print pairing links without terminal QR codes."],
|
|
15
|
+
],
|
|
16
|
+
examples: ["milagre serve", "milagre serve --project /path/to/project", "milagre serve --no-pair"],
|
|
17
|
+
note: "Runs in the foreground. Ctrl+C or SIGTERM saves and stops the server.",
|
|
18
|
+
},
|
|
19
|
+
pair: {
|
|
20
|
+
description: "Open a new pairing window for phones and other desktops.",
|
|
21
|
+
usage: "milagre pair [flags]",
|
|
22
|
+
flags: [["--no-qr", "Print pairing links without terminal QR codes."]],
|
|
23
|
+
examples: ["milagre pair", "milagre pair --no-qr"],
|
|
24
|
+
note: "Pairing lasts 10 minutes. Approve computers with milagre devices allow KEY.",
|
|
25
|
+
},
|
|
26
|
+
status: {
|
|
27
|
+
description: "Show the running server's status as JSON.",
|
|
28
|
+
usage: "milagre status [flags]",
|
|
29
|
+
examples: ["milagre status"],
|
|
30
|
+
},
|
|
31
|
+
stop: {
|
|
32
|
+
description: "Save running work and stop the server.",
|
|
33
|
+
usage: "milagre stop [flags]",
|
|
34
|
+
examples: ["milagre stop"],
|
|
35
|
+
},
|
|
36
|
+
devices: {
|
|
37
|
+
description: "List, approve and remove paired devices.",
|
|
38
|
+
usage: "milagre devices <command> [key] [flags]",
|
|
39
|
+
commands: [
|
|
40
|
+
["list", "List paired devices."],
|
|
41
|
+
["pending", "List computers waiting for approval."],
|
|
42
|
+
["allow <key>", "Approve a waiting computer."],
|
|
43
|
+
["deny <key>", "Reject a waiting computer."],
|
|
44
|
+
["remove <key>", "Remove a paired device and close its connections."],
|
|
45
|
+
],
|
|
46
|
+
examples: ["milagre devices pending", "milagre devices allow KEY", "milagre devices list"],
|
|
47
|
+
},
|
|
48
|
+
request: {
|
|
49
|
+
description: "Call a daemon method and print its result as JSON.",
|
|
50
|
+
usage: "milagre request <method> [JSON_ARGS] [flags]",
|
|
51
|
+
arguments: [
|
|
52
|
+
["method", "Daemon method to call, such as project:open or chat:runs."],
|
|
53
|
+
["JSON_ARGS", "Arguments as a JSON array. Defaults to []."],
|
|
54
|
+
],
|
|
55
|
+
examples: ["milagre request project:open '[\"/path/to/project\"]'", "milagre request chat:runs"],
|
|
56
|
+
},
|
|
57
|
+
help: {
|
|
58
|
+
description: "Show all commands or help for a specific command.",
|
|
59
|
+
usage: "milagre help [command]",
|
|
60
|
+
arguments: [["command", "Command to describe. Omit it to show all commands."]],
|
|
61
|
+
examples: ["milagre help", "milagre help serve", "milagre serve --help"],
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function renderHelp(command, { color = false } = {}) {
|
|
66
|
+
const info = command && Object.hasOwn(COMMANDS, command) ? COMMANDS[command] : null;
|
|
67
|
+
if (command && !info) throw new Error(`Unknown command: ${command}. Use milagre help.`);
|
|
68
|
+
const style = (code, value) => (color ? `\u001b[${code}m${value}\u001b[0m` : value);
|
|
69
|
+
const sections = [];
|
|
70
|
+
const section = (title, lines) => sections.push(`${style("1", title)}\n${lines.join("\n")}`);
|
|
71
|
+
const rows = (entries) => {
|
|
72
|
+
const width = Math.max(...entries.map(([name]) => name.length)) + 3;
|
|
73
|
+
return entries.map(([name, description]) => ` ${style("36", name)}${" ".repeat(width - name.length)}${description}`);
|
|
74
|
+
};
|
|
75
|
+
section("DESCRIPTION", [` ${info?.description ?? "Run Milagre agents on a computer without a desktop UI."}`]);
|
|
76
|
+
section("USAGE", [` ${style("36", info?.usage ?? "milagre <command> [flags]")}`]);
|
|
77
|
+
if (info?.arguments) section("ARGUMENTS", rows(info.arguments));
|
|
78
|
+
if (!info) section("COMMANDS", rows(Object.entries(COMMANDS).map(([name, entry]) => [name, entry.description])));
|
|
79
|
+
if (info?.commands) section("COMMANDS", rows(info.commands));
|
|
80
|
+
if (info?.flags) section("FLAGS", rows(info.flags));
|
|
81
|
+
section("GLOBAL FLAGS", rows(GLOBAL_FLAGS));
|
|
82
|
+
section(
|
|
83
|
+
"EXAMPLES",
|
|
84
|
+
(info?.examples ?? ["npx milagre serve", "milagre help serve", "milagre devices pending"]).map((example) => ` ${style("36", example)}`),
|
|
85
|
+
);
|
|
86
|
+
if (info?.note) section("NOTES", [` ${info.note}`]);
|
|
87
|
+
if (!info) section("REQUIRES", [" Node.js 24+ and an installed, signed-in agent CLI (Claude Code or Codex)."]);
|
|
88
|
+
return sections.join("\n\n") + "\n";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = { COMMANDS, renderHelp };
|
package/src/command.cjs
CHANGED
|
@@ -3,29 +3,9 @@ const os = require("node:os");
|
|
|
3
3
|
const path = require("node:path");
|
|
4
4
|
const { parseArgs } = require("node:util");
|
|
5
5
|
const { setTimeout: delay } = require("node:timers/promises");
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
milagre pair
|
|
10
|
-
milagre status
|
|
11
|
-
milagre stop
|
|
12
|
-
milagre devices <list|pending|allow KEY|deny KEY|remove KEY>
|
|
13
|
-
milagre request METHOD [JSON_ARGS]
|
|
14
|
-
|
|
15
|
-
Run a Milagre computer without a desktop UI. Requires Node 24+ and a
|
|
16
|
-
signed-in agent CLI (Claude Code or Codex).
|
|
17
|
-
|
|
18
|
-
Options:
|
|
19
|
-
--data-dir PATH Absolute profile path (default: MILAGRE_DATA_DIR or ~/.milagre/server)
|
|
20
|
-
--project PATH Open a Project on startup; can be repeated
|
|
21
|
-
--no-pair Serve without opening or printing a new pairing window
|
|
22
|
-
--no-qr Print pairing links without terminal QR codes
|
|
23
|
-
--help, -h Show help
|
|
24
|
-
--version, -v Show version
|
|
25
|
-
|
|
26
|
-
serve runs in the foreground. Ctrl+C saves and stops the server.
|
|
27
|
-
Use pair to reopen the pairing window. Approve computers with devices allow.
|
|
28
|
-
`;
|
|
6
|
+
const metadata = require("../package.json");
|
|
7
|
+
const version = metadata.cliVersion ?? metadata.version;
|
|
8
|
+
const { COMMANDS, renderHelp } = require("./command-help.cjs");
|
|
29
9
|
|
|
30
10
|
async function printPairing(client, { output = process.stdout, qr = output.isTTY, timeoutMs = 20000 } = {}) {
|
|
31
11
|
await client.call("phone:set-enabled", [true]);
|
|
@@ -62,9 +42,12 @@ async function main(args = process.argv.slice(2)) {
|
|
|
62
42
|
},
|
|
63
43
|
});
|
|
64
44
|
if (values.version) return process.stdout.write(`${version}\n`);
|
|
65
|
-
if (values.help || !positionals.length
|
|
45
|
+
if (values.help || !positionals.length || positionals[0] === "help") {
|
|
46
|
+
const topic = positionals[0] === "help" ? positionals[1] : positionals[0];
|
|
47
|
+
return process.stdout.write(renderHelp(topic, { color: Boolean(process.stdout.isTTY && !("NO_COLOR" in process.env) && process.env.TERM !== "dumb") }));
|
|
48
|
+
}
|
|
66
49
|
const [command, action, argument] = positionals;
|
|
67
|
-
if (!
|
|
50
|
+
if (!Object.hasOwn(COMMANDS, command)) throw new Error(`Unknown command: ${command}. Use milagre help.`);
|
|
68
51
|
const dataDir = values["data-dir"] ?? process.env.MILAGRE_DATA_DIR ?? path.join(os.homedir(), ".milagre", "server");
|
|
69
52
|
if (!path.isAbsolute(dataDir)) throw new Error("--data-dir (or MILAGRE_DATA_DIR) must be an absolute path");
|
|
70
53
|
if (command !== "serve" && (values.project || values["no-pair"])) throw new Error("--project and --no-pair are only supported by serve");
|