@awak-app/simy-cli 0.1.1 → 0.1.3

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.
@@ -0,0 +1,44 @@
1
+ import { spawn } from "node:child_process";
2
+
3
+ const MACOS_CODEX_BINARY = "/Applications/ChatGPT.app/Contents/Resources/codex";
4
+
5
+ export async function resolveBackendExecutable(
6
+ backend,
7
+ { spawnImpl = spawn, candidates = backendCandidates(backend), timeoutMs = 1_500 } = {},
8
+ ) {
9
+ for (const candidate of [...new Set(candidates.filter(Boolean))]) {
10
+ if (await executableAvailable(candidate, { spawnImpl, timeoutMs })) return candidate;
11
+ }
12
+ return null;
13
+ }
14
+
15
+ export function backendCandidates(backend) {
16
+ if (backend === "claude") {
17
+ return [process.env.SIMY_CLAUDE_BIN, "claude"];
18
+ }
19
+ return [
20
+ process.env.SIMY_CODEX_BIN,
21
+ "codex",
22
+ ...(process.platform === "darwin" ? [MACOS_CODEX_BINARY] : []),
23
+ ];
24
+ }
25
+
26
+ function executableAvailable(command, { spawnImpl, timeoutMs }) {
27
+ return new Promise((resolve) => {
28
+ let settled = false;
29
+ let timeout;
30
+ const child = spawnImpl(command, ["--version"], { stdio: "ignore" });
31
+ const finish = (available) => {
32
+ if (settled) return;
33
+ settled = true;
34
+ if (timeout) clearTimeout(timeout);
35
+ resolve(available);
36
+ };
37
+ timeout = setTimeout(() => {
38
+ child.kill?.("SIGTERM");
39
+ finish(false);
40
+ }, timeoutMs);
41
+ child.on("error", () => finish(false));
42
+ child.on("close", (code) => finish(code === 0));
43
+ });
44
+ }
package/src/browser.js ADDED
@@ -0,0 +1,59 @@
1
+ import { spawn as spawnProcess } from "node:child_process";
2
+
3
+ export async function openAuthorizationUrl(
4
+ authorizationUrl,
5
+ {
6
+ platform = process.platform,
7
+ spawn = spawnProcess,
8
+ logger = console,
9
+ } = {},
10
+ ) {
11
+ if (!authorizationUrl) return { opened: false, reason: "not_required" };
12
+
13
+ const target = browserCommand(platform, authorizationUrl);
14
+ logger.log(`Authorize SIMY CLI: ${authorizationUrl}`);
15
+
16
+ if (!target) {
17
+ logger.error(`SIMY could not open a browser on platform ${platform}.`);
18
+ logger.error(`Open this URL manually: ${authorizationUrl}`);
19
+ return { opened: false, reason: "unsupported_platform" };
20
+ }
21
+
22
+ try {
23
+ const child = spawn(target.command, target.args, {
24
+ detached: true,
25
+ stdio: "ignore",
26
+ });
27
+ await waitForSpawn(child);
28
+ child.unref();
29
+ logger.log("Opened the SIMY CLI authorization page in your browser.");
30
+ return { opened: true };
31
+ } catch (error) {
32
+ logger.error(`SIMY could not open the authorization page: ${errorMessage(error)}`);
33
+ logger.error(`Open this URL manually: ${authorizationUrl}`);
34
+ return { opened: false, reason: "launch_failed", error };
35
+ }
36
+ }
37
+
38
+ export function browserCommand(platform, authorizationUrl) {
39
+ if (platform === "darwin") return { command: "open", args: [authorizationUrl] };
40
+ if (platform === "win32") {
41
+ return {
42
+ command: "rundll32",
43
+ args: ["url.dll,FileProtocolHandler", authorizationUrl],
44
+ };
45
+ }
46
+ if (platform === "linux") return { command: "xdg-open", args: [authorizationUrl] };
47
+ return null;
48
+ }
49
+
50
+ function waitForSpawn(child) {
51
+ return new Promise((resolve, reject) => {
52
+ child.once("spawn", resolve);
53
+ child.once("error", reject);
54
+ });
55
+ }
56
+
57
+ function errorMessage(error) {
58
+ return error instanceof Error ? error.message : String(error);
59
+ }