codex-to-im 0.1.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/cli.mjs ADDED
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'module'; const require = createRequire(import.meta.url);
3
+
4
+ // src/service-manager.ts
5
+ import fs2 from "node:fs";
6
+ import os2 from "node:os";
7
+ import path2 from "node:path";
8
+ import { spawn } from "node:child_process";
9
+ import { fileURLToPath } from "node:url";
10
+
11
+ // src/config.ts
12
+ import fs from "node:fs";
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+ var LEGACY_CTI_HOME = path.join(os.homedir(), ".claude-to-im");
16
+ var DEFAULT_CTI_HOME = path.join(os.homedir(), ".codex-to-im");
17
+ function resolveDefaultCtiHome() {
18
+ if (fs.existsSync(DEFAULT_CTI_HOME)) return DEFAULT_CTI_HOME;
19
+ if (fs.existsSync(LEGACY_CTI_HOME)) return LEGACY_CTI_HOME;
20
+ return DEFAULT_CTI_HOME;
21
+ }
22
+ var CTI_HOME = process.env.CTI_HOME || resolveDefaultCtiHome();
23
+ var CONFIG_PATH = path.join(CTI_HOME, "config.env");
24
+
25
+ // src/service-manager.ts
26
+ var moduleDir = path2.dirname(fileURLToPath(import.meta.url));
27
+ var packageRoot = path2.resolve(moduleDir, "..");
28
+ var runtimeDir = path2.join(CTI_HOME, "runtime");
29
+ var logsDir = path2.join(CTI_HOME, "logs");
30
+ var bridgePidFile = path2.join(runtimeDir, "bridge.pid");
31
+ var bridgeStatusFile = path2.join(runtimeDir, "status.json");
32
+ var uiStatusFile = path2.join(runtimeDir, "ui-server.json");
33
+ var uiPort = 4781;
34
+ function ensureDirs() {
35
+ fs2.mkdirSync(runtimeDir, { recursive: true });
36
+ fs2.mkdirSync(logsDir, { recursive: true });
37
+ }
38
+ function readJsonFile(filePath, fallback) {
39
+ try {
40
+ return JSON.parse(fs2.readFileSync(filePath, "utf-8"));
41
+ } catch {
42
+ return fallback;
43
+ }
44
+ }
45
+ function isProcessAlive(pid) {
46
+ if (!pid) return false;
47
+ try {
48
+ process.kill(pid, 0);
49
+ return true;
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+ function sleep(ms) {
55
+ return new Promise((resolve) => setTimeout(resolve, ms));
56
+ }
57
+ function getUiServerUrl(port = uiPort) {
58
+ return `http://127.0.0.1:${port}`;
59
+ }
60
+ function getCurrentUiServerUrl() {
61
+ const status = readJsonFile(uiStatusFile, null);
62
+ if (!status?.port) return void 0;
63
+ return getUiServerUrl(status.port);
64
+ }
65
+ function getUiServerStatus() {
66
+ const status = readJsonFile(uiStatusFile, { running: false, port: uiPort });
67
+ if (!isProcessAlive(status.pid)) {
68
+ return {
69
+ ...status,
70
+ running: false,
71
+ port: status.port ?? uiPort
72
+ };
73
+ }
74
+ return {
75
+ ...status,
76
+ running: true,
77
+ port: status.port ?? uiPort
78
+ };
79
+ }
80
+ async function waitForUiServer(timeoutMs = 15e3) {
81
+ const startedAt = Date.now();
82
+ while (Date.now() - startedAt < timeoutMs) {
83
+ const status = getUiServerStatus();
84
+ if (status.running) {
85
+ try {
86
+ const response = await fetch(`${getUiServerUrl(status.port)}/api/ping`);
87
+ if (response.ok) return status;
88
+ } catch {
89
+ }
90
+ }
91
+ await sleep(300);
92
+ }
93
+ return getUiServerStatus();
94
+ }
95
+ async function ensureUiServerRunning() {
96
+ ensureDirs();
97
+ const current = getUiServerStatus();
98
+ if (current.running) return current;
99
+ const serverEntry = path2.join(packageRoot, "dist", "ui-server.mjs");
100
+ if (!fs2.existsSync(serverEntry)) {
101
+ throw new Error(`UI server bundle not found at ${serverEntry}. Run npm run build first.`);
102
+ }
103
+ const stdoutFd = fs2.openSync(path2.join(logsDir, "ui-server.out.log"), "a");
104
+ const stderrFd = fs2.openSync(path2.join(logsDir, "ui-server.err.log"), "a");
105
+ const child = spawn(process.execPath, [serverEntry], {
106
+ cwd: packageRoot,
107
+ detached: true,
108
+ env: {
109
+ ...process.env,
110
+ CTI_HOME
111
+ },
112
+ stdio: ["ignore", stdoutFd, stderrFd]
113
+ });
114
+ child.unref();
115
+ const status = await waitForUiServer();
116
+ if (!status.running) {
117
+ throw new Error("UI server failed to start.");
118
+ }
119
+ return status;
120
+ }
121
+ function openBrowser(url) {
122
+ if (process.platform === "win32") {
123
+ const child2 = spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" });
124
+ child2.unref();
125
+ return;
126
+ }
127
+ if (process.platform === "darwin") {
128
+ const child2 = spawn("open", [url], { detached: true, stdio: "ignore" });
129
+ child2.unref();
130
+ return;
131
+ }
132
+ const child = spawn("xdg-open", [url], { detached: true, stdio: "ignore" });
133
+ child.unref();
134
+ }
135
+
136
+ // src/cli.ts
137
+ async function main() {
138
+ const command = process.argv[2] || "open";
139
+ switch (command) {
140
+ case "open": {
141
+ const status = await ensureUiServerRunning();
142
+ const url = getUiServerUrl(status.port);
143
+ openBrowser(url);
144
+ process.stdout.write(`Codex to IM is available at ${url}
145
+ `);
146
+ return;
147
+ }
148
+ case "url": {
149
+ const status = getUiServerStatus();
150
+ const url = getCurrentUiServerUrl();
151
+ if (status.running && url) {
152
+ process.stdout.write(`${url}
153
+ `);
154
+ return;
155
+ }
156
+ if (url) {
157
+ process.stdout.write(`UI server is not running. Last known URL: ${url}
158
+ `);
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+ process.stdout.write("UI server is not running and no known URL is available.\n");
163
+ process.exitCode = 1;
164
+ return;
165
+ }
166
+ case "share-feishu": {
167
+ const status = await ensureUiServerRunning();
168
+ const url = `${getUiServerUrl(status.port)}/#desktop`;
169
+ openBrowser(url);
170
+ process.stdout.write(`Opened Feishu handoff entry at ${url}
171
+ `);
172
+ return;
173
+ }
174
+ default:
175
+ process.stdout.write("Usage: codex-to-im [open|url|share-feishu]\n");
176
+ }
177
+ }
178
+ main().catch((error) => {
179
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}
180
+ `);
181
+ process.exit(1);
182
+ });