@dunnewold-labs/mr-manager 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +58 -13
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -89,23 +89,62 @@ function openBrowser(url) {
|
|
|
89
89
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
90
90
|
spawn(cmd, [url], { detached: true, stdio: "ignore" }).unref();
|
|
91
91
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
function isHeadless() {
|
|
93
|
+
if (process.env.SSH_CLIENT || process.env.SSH_TTY || process.env.SSH_CONNECTION) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
async function loginWithDeviceCode(apiUrl) {
|
|
102
|
+
const res = await fetch(`${apiUrl}/api/auth/device-code`, { method: "POST" });
|
|
103
|
+
if (!res.ok) {
|
|
104
|
+
throw new Error(`Failed to create device code: ${res.status} ${res.statusText}`);
|
|
105
|
+
}
|
|
106
|
+
const { code } = await res.json();
|
|
107
|
+
const loginUrl = `${apiUrl}/login?deviceCode=${code}`;
|
|
108
|
+
console.log(`
|
|
109
|
+
Remote login \u2014 visit this URL in any browser:
|
|
110
|
+
`);
|
|
111
|
+
console.log(` ${loginUrl}
|
|
112
|
+
`);
|
|
113
|
+
console.log(`Waiting for authentication\u2026`);
|
|
114
|
+
const timeout = 10 * 60 * 1e3;
|
|
115
|
+
const interval = 3e3;
|
|
116
|
+
const start = Date.now();
|
|
117
|
+
while (Date.now() - start < timeout) {
|
|
118
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
119
|
+
const pollRes = await fetch(`${apiUrl}/api/auth/device-code/poll?code=${code}`);
|
|
120
|
+
if (pollRes.status === 410) {
|
|
121
|
+
throw new Error("Device code expired. Please try again.");
|
|
122
|
+
}
|
|
123
|
+
if (!pollRes.ok) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const data = await pollRes.json();
|
|
127
|
+
if (data.status === "complete" && data.key) {
|
|
128
|
+
return data.key;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
throw new Error("Login timed out after 10 minutes");
|
|
132
|
+
}
|
|
133
|
+
async function loginWithLocalServer(apiUrl) {
|
|
95
134
|
const port = getRandomPort();
|
|
96
|
-
|
|
135
|
+
return new Promise((resolve7, reject) => {
|
|
97
136
|
const server = createServer((req, res) => {
|
|
98
137
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
99
|
-
const
|
|
138
|
+
const key = url.searchParams.get("key");
|
|
100
139
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
101
140
|
res.end(`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
141
|
+
<html><body style="font-family:sans-serif;text-align:center;padding:60px">
|
|
142
|
+
<h2>${key ? "\u2713 Authenticated!" : "Something went wrong."}</h2>
|
|
143
|
+
<p>${key ? "You can close this tab and return to the terminal." : "No key received. Please try again."}</p>
|
|
144
|
+
</body></html>
|
|
145
|
+
`);
|
|
107
146
|
server.close();
|
|
108
|
-
if (
|
|
147
|
+
if (key) resolve7(key);
|
|
109
148
|
else reject(new Error("No key received from server"));
|
|
110
149
|
});
|
|
111
150
|
server.listen(port, () => {
|
|
@@ -123,6 +162,12 @@ Opening browser for authentication\u2026`);
|
|
|
123
162
|
reject(new Error("Login timed out after 5 minutes"));
|
|
124
163
|
}, 5 * 60 * 1e3);
|
|
125
164
|
});
|
|
165
|
+
}
|
|
166
|
+
var loginCommand = new Command3("login").description("Authenticate the CLI via browser (Google OAuth)").option("--url <url>", "API URL", "https://mr-manager-gold.vercel.app").option("--headless", "Use device-code flow for remote/headless environments").action(async (opts) => {
|
|
167
|
+
const config = loadConfig();
|
|
168
|
+
const apiUrl = opts.url ?? config.apiUrl ?? "https://mr-manager-gold.vercel.app";
|
|
169
|
+
const useDeviceCode = opts.headless || isHeadless();
|
|
170
|
+
const key = useDeviceCode ? await loginWithDeviceCode(apiUrl) : await loginWithLocalServer(apiUrl);
|
|
126
171
|
config.apiKey = key;
|
|
127
172
|
config.apiUrl = apiUrl;
|
|
128
173
|
saveConfig(config);
|
|
@@ -143,7 +188,7 @@ try {
|
|
|
143
188
|
const pkg = JSON.parse(readFileSync2(join2(__dirname, "..", "package.json"), "utf-8"));
|
|
144
189
|
cliVersion = pkg.version;
|
|
145
190
|
} catch {
|
|
146
|
-
cliVersion = "0.
|
|
191
|
+
cliVersion = "0.2.0";
|
|
147
192
|
}
|
|
148
193
|
var ApiError = class extends Error {
|
|
149
194
|
constructor(status, statusText, body) {
|
|
@@ -5510,7 +5555,7 @@ if (isFirstRun && !shouldBypass) {
|
|
|
5510
5555
|
process.exit(0);
|
|
5511
5556
|
}
|
|
5512
5557
|
var program = new Command29();
|
|
5513
|
-
program.name("mr").description("Mr. Manager - Task and project management CLI").version("0.
|
|
5558
|
+
program.name("mr").description("Mr. Manager - Task and project management CLI").version("0.2.0");
|
|
5514
5559
|
program.addCommand(initCommand);
|
|
5515
5560
|
program.addCommand(authCommand);
|
|
5516
5561
|
program.addCommand(loginCommand);
|