@linzumi/cli 0.0.1-beta → 0.0.2-beta
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 +78 -94
- package/bin/linzumi.js +16 -8
- package/package.json +4 -2
- package/src/authCache.ts +157 -0
- package/src/authResolution.ts +75 -0
- package/src/channelSession.ts +3248 -0
- package/src/channelSessionSupport.ts +255 -0
- package/src/codexAppServer.ts +380 -0
- package/src/codexOutput.ts +846 -0
- package/src/index.ts +354 -0
- package/src/json.ts +49 -0
- package/src/kandanQueue.ts +102 -0
- package/src/oauth.ts +294 -0
- package/src/phoenix.ts +335 -0
- package/src/protocol.ts +211 -0
- package/src/runner.ts +524 -0
- package/src/runnerConsoleReporter.ts +142 -0
- package/src/runnerLogger.ts +50 -0
- package/src/cli.js +0 -240
package/src/cli.js
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
|
|
3
|
-
const version = "0.0.1-beta";
|
|
4
|
-
|
|
5
|
-
const requiredEnv = {
|
|
6
|
-
linzBin: "LINZUMI_LOCAL_CODEX_RUNNER_LINZ_BIN",
|
|
7
|
-
vmId: "LINZUMI_LOCAL_CODEX_RUNNER_VM_ID",
|
|
8
|
-
remoteCodexBin: "LINZUMI_LOCAL_CODEX_RUNNER_REMOTE_CODEX_BIN",
|
|
9
|
-
remoteEnv: "LINZUMI_LOCAL_CODEX_RUNNER_REMOTE_ENV",
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const usage = `linzumi connect [OPTIONS]
|
|
13
|
-
|
|
14
|
-
Connects this machine to Kandan as the local Codex runner.
|
|
15
|
-
|
|
16
|
-
This command runs on your local computer. Use the command shown by Kandan's
|
|
17
|
-
local runner connection flow to start the local Codex runner here.
|
|
18
|
-
|
|
19
|
-
Options:
|
|
20
|
-
--linz-bin <path> LINZ CLI or bridge wrapper to execute
|
|
21
|
-
--vm-id <id> LINZ runner VM id
|
|
22
|
-
--remote-codex-bin <path> Remote Codex binary path
|
|
23
|
-
--remote-env <path> Remote env-file path
|
|
24
|
-
--remote-kandan-linz <path> Remote kandan_linz path
|
|
25
|
-
--help Show this help
|
|
26
|
-
--version Show CLI version
|
|
27
|
-
|
|
28
|
-
Environment defaults:
|
|
29
|
-
${requiredEnv.linzBin}
|
|
30
|
-
${requiredEnv.vmId}
|
|
31
|
-
${requiredEnv.remoteCodexBin}
|
|
32
|
-
${requiredEnv.remoteEnv}
|
|
33
|
-
LINZUMI_LOCAL_CODEX_RUNNER_REMOTE_KANDAN_LINZ
|
|
34
|
-
|
|
35
|
-
Internal runner protocol:
|
|
36
|
-
linzumi connect [OPTIONS] app-server --listen <url>
|
|
37
|
-
`;
|
|
38
|
-
|
|
39
|
-
const defaultRemoteKandanLinz = "/home/linz/.kandan/runner/bin/kandan_linz";
|
|
40
|
-
|
|
41
|
-
const connectGuide = `linzumi connect
|
|
42
|
-
|
|
43
|
-
This command connects this machine to Kandan as a local Codex runner.
|
|
44
|
-
|
|
45
|
-
Open Kandan, start the local runner connection flow, and follow the command it
|
|
46
|
-
shows you. Run that command on this computer.
|
|
47
|
-
|
|
48
|
-
For help:
|
|
49
|
-
linzumi connect --help
|
|
50
|
-
`;
|
|
51
|
-
|
|
52
|
-
const isBlank = (value) => typeof value !== "string" || value.trim() === "";
|
|
53
|
-
|
|
54
|
-
const readOptionValue = (tokens, index, name) => {
|
|
55
|
-
const value = tokens[index + 1];
|
|
56
|
-
if (isBlank(value)) {
|
|
57
|
-
return { ok: false, error: `${name} requires a value` };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return { ok: true, value, nextIndex: index + 2 };
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const shellQuote = (value) => `'${value.replaceAll("'", "'\"'\"'")}'`;
|
|
64
|
-
|
|
65
|
-
export const buildRemoteCommand = ({ remoteKandanLinz, remoteEnv, remoteCodexBin, listenUrl }) => {
|
|
66
|
-
const rendered = [
|
|
67
|
-
"exec",
|
|
68
|
-
shellQuote(remoteKandanLinz),
|
|
69
|
-
"app-server",
|
|
70
|
-
"--env-file",
|
|
71
|
-
shellQuote(remoteEnv),
|
|
72
|
-
shellQuote(remoteCodexBin),
|
|
73
|
-
shellQuote(listenUrl),
|
|
74
|
-
];
|
|
75
|
-
|
|
76
|
-
return rendered.join(" ");
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const normalizeRemotePath = (path) => {
|
|
80
|
-
if (path.startsWith("/")) {
|
|
81
|
-
return path;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return `/home/linz/${path}`;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export const parseLocalCodexRunnerArgs = ({ argv, env }) => {
|
|
88
|
-
const options = {
|
|
89
|
-
linzBin: env[requiredEnv.linzBin],
|
|
90
|
-
vmId: env[requiredEnv.vmId],
|
|
91
|
-
remoteCodexBin: env[requiredEnv.remoteCodexBin],
|
|
92
|
-
remoteEnv: env[requiredEnv.remoteEnv],
|
|
93
|
-
remoteKandanLinz:
|
|
94
|
-
env.LINZUMI_LOCAL_CODEX_RUNNER_REMOTE_KANDAN_LINZ ?? defaultRemoteKandanLinz,
|
|
95
|
-
};
|
|
96
|
-
const command = [];
|
|
97
|
-
|
|
98
|
-
let index = 0;
|
|
99
|
-
while (index < argv.length) {
|
|
100
|
-
const token = argv[index];
|
|
101
|
-
|
|
102
|
-
switch (token) {
|
|
103
|
-
case "--help":
|
|
104
|
-
case "-h":
|
|
105
|
-
return { ok: true, help: true };
|
|
106
|
-
case "--version":
|
|
107
|
-
return { ok: true, version: true };
|
|
108
|
-
case "--linz-bin": {
|
|
109
|
-
const parsed = readOptionValue(argv, index, "--linz-bin");
|
|
110
|
-
if (!parsed.ok) return parsed;
|
|
111
|
-
options.linzBin = parsed.value;
|
|
112
|
-
index = parsed.nextIndex;
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
case "--vm-id": {
|
|
116
|
-
const parsed = readOptionValue(argv, index, "--vm-id");
|
|
117
|
-
if (!parsed.ok) return parsed;
|
|
118
|
-
options.vmId = parsed.value;
|
|
119
|
-
index = parsed.nextIndex;
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
case "--remote-codex-bin": {
|
|
123
|
-
const parsed = readOptionValue(argv, index, "--remote-codex-bin");
|
|
124
|
-
if (!parsed.ok) return parsed;
|
|
125
|
-
options.remoteCodexBin = parsed.value;
|
|
126
|
-
index = parsed.nextIndex;
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
case "--remote-env": {
|
|
130
|
-
const parsed = readOptionValue(argv, index, "--remote-env");
|
|
131
|
-
if (!parsed.ok) return parsed;
|
|
132
|
-
options.remoteEnv = parsed.value;
|
|
133
|
-
index = parsed.nextIndex;
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
case "--remote-kandan-linz": {
|
|
137
|
-
const parsed = readOptionValue(argv, index, "--remote-kandan-linz");
|
|
138
|
-
if (!parsed.ok) return parsed;
|
|
139
|
-
options.remoteKandanLinz = parsed.value;
|
|
140
|
-
index = parsed.nextIndex;
|
|
141
|
-
break;
|
|
142
|
-
}
|
|
143
|
-
case "--":
|
|
144
|
-
command.push(...argv.slice(index + 1));
|
|
145
|
-
index = argv.length;
|
|
146
|
-
break;
|
|
147
|
-
default:
|
|
148
|
-
command.push(...argv.slice(index));
|
|
149
|
-
index = argv.length;
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const [subcommand, listenFlag, listenUrl, ...extra] = command;
|
|
155
|
-
if (subcommand !== "app-server" || listenFlag !== "--listen" || isBlank(listenUrl) || extra.length > 0) {
|
|
156
|
-
return {
|
|
157
|
-
ok: false,
|
|
158
|
-
error: "connect must be launched by Kandan with the internal runner protocol",
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const missing = Object.entries(options)
|
|
163
|
-
.filter(([, value]) => isBlank(value))
|
|
164
|
-
.map(([name]) => name);
|
|
165
|
-
|
|
166
|
-
if (missing.length > 0) {
|
|
167
|
-
return { ok: false, error: `missing connect option(s): ${missing.join(", ")}` };
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
ok: true,
|
|
172
|
-
options: {
|
|
173
|
-
...options,
|
|
174
|
-
remoteCodexBin: normalizeRemotePath(options.remoteCodexBin),
|
|
175
|
-
remoteEnv: normalizeRemotePath(options.remoteEnv),
|
|
176
|
-
remoteKandanLinz: normalizeRemotePath(options.remoteKandanLinz),
|
|
177
|
-
listenUrl,
|
|
178
|
-
},
|
|
179
|
-
};
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
export const runLocalCodexRunner = ({ argv, env, cwd, spawn = spawnSync }) => {
|
|
183
|
-
if (argv.length === 0) {
|
|
184
|
-
return { exitCode: 0, stdout: connectGuide, stderr: "" };
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const parsed = parseLocalCodexRunnerArgs({ argv, env });
|
|
188
|
-
|
|
189
|
-
if (!parsed.ok) {
|
|
190
|
-
return { exitCode: 64, stdout: "", stderr: `${parsed.error}\n` };
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (parsed.help) {
|
|
194
|
-
return { exitCode: 0, stdout: usage, stderr: "" };
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (parsed.version) {
|
|
198
|
-
return { exitCode: 0, stdout: `linzumi ${version}\n`, stderr: "" };
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const { linzBin, vmId, remoteKandanLinz, remoteEnv, remoteCodexBin, listenUrl } = parsed.options;
|
|
202
|
-
const remoteCommand = buildRemoteCommand({ remoteKandanLinz, remoteEnv, remoteCodexBin, listenUrl });
|
|
203
|
-
const result = spawn(linzBin, ["exec", vmId, "--", "sh", "-lc", remoteCommand], {
|
|
204
|
-
cwd,
|
|
205
|
-
encoding: "utf8",
|
|
206
|
-
stdio: ["ignore", "inherit", "inherit"],
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
if (result.error) {
|
|
210
|
-
return { exitCode: 127, stdout: "", stderr: `${result.error.message}\n` };
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return { exitCode: result.status ?? 1, stdout: "", stderr: "" };
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
export const runCliToResult = ({ argv, env, cwd, spawn = spawnSync }) => {
|
|
217
|
-
const [command, ...rest] = argv;
|
|
218
|
-
|
|
219
|
-
switch (command) {
|
|
220
|
-
case undefined:
|
|
221
|
-
return runLocalCodexRunner({ argv: [], env, cwd, spawn });
|
|
222
|
-
case "connect":
|
|
223
|
-
case "local-codex-runner":
|
|
224
|
-
return runLocalCodexRunner({ argv: rest, env, cwd, spawn });
|
|
225
|
-
case "--help":
|
|
226
|
-
case "-h":
|
|
227
|
-
return { exitCode: 0, stdout: usage, stderr: "" };
|
|
228
|
-
case "--version":
|
|
229
|
-
return { exitCode: 0, stdout: `linzumi ${version}\n`, stderr: "" };
|
|
230
|
-
default:
|
|
231
|
-
return { exitCode: 64, stdout: "", stderr: `unknown linzumi command: ${command}\n${usage}` };
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
export const runCli = ({ argv, env, cwd, stdout, stderr, spawn = spawnSync }) => {
|
|
236
|
-
const result = runCliToResult({ argv, env, cwd, spawn });
|
|
237
|
-
if (result.stdout !== "") stdout.write(result.stdout);
|
|
238
|
-
if (result.stderr !== "") stderr.write(result.stderr);
|
|
239
|
-
return { exitCode: result.exitCode };
|
|
240
|
-
};
|