lunel-cli 0.1.22 → 0.1.26
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.js +96 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { WebSocket } from "ws";
|
|
3
3
|
import qrcode from "qrcode-terminal";
|
|
4
|
-
import {
|
|
4
|
+
import { createOpencodeServer, createOpencodeClient } from "@opencode-ai/sdk";
|
|
5
|
+
import * as crypto from "crypto";
|
|
5
6
|
import Ignore from "ignore";
|
|
6
7
|
const ignore = Ignore.default;
|
|
7
8
|
import * as fs from "fs/promises";
|
|
@@ -1171,35 +1172,72 @@ async function handleHttpRequest(payload) {
|
|
|
1171
1172
|
// ============================================================================
|
|
1172
1173
|
// AI Handlers (OpenCode SDK)
|
|
1173
1174
|
// ============================================================================
|
|
1175
|
+
function requireData(response, label) {
|
|
1176
|
+
if (!response.data) {
|
|
1177
|
+
const errMsg = response.error
|
|
1178
|
+
? (typeof response.error === "string" ? response.error : JSON.stringify(response.error))
|
|
1179
|
+
: `${label} returned no data`;
|
|
1180
|
+
console.error(`[ai] ${label} failed:`, errMsg, "raw response:", JSON.stringify(response).substring(0, 500));
|
|
1181
|
+
throw new Error(errMsg);
|
|
1182
|
+
}
|
|
1183
|
+
return response.data;
|
|
1184
|
+
}
|
|
1174
1185
|
async function handleAiCreateSession(payload) {
|
|
1175
1186
|
const title = payload.title || undefined;
|
|
1176
|
-
|
|
1177
|
-
|
|
1187
|
+
console.log("[ai] createSession called, title:", title);
|
|
1188
|
+
try {
|
|
1189
|
+
const response = await opencodeClient.session.create({ body: { title } });
|
|
1190
|
+
console.log("[ai] createSession response ok:", !!response.data, "error:", response.error ? JSON.stringify(response.error).substring(0, 200) : "none");
|
|
1191
|
+
return { session: requireData(response, "session.create") };
|
|
1192
|
+
}
|
|
1193
|
+
catch (err) {
|
|
1194
|
+
console.error("[ai] createSession exception:", err.message, err.stack);
|
|
1195
|
+
throw err;
|
|
1196
|
+
}
|
|
1178
1197
|
}
|
|
1179
1198
|
async function handleAiListSessions() {
|
|
1180
|
-
|
|
1181
|
-
|
|
1199
|
+
console.log("[ai] listSessions called");
|
|
1200
|
+
try {
|
|
1201
|
+
const response = await opencodeClient.session.list();
|
|
1202
|
+
const data = requireData(response, "session.list");
|
|
1203
|
+
console.log("[ai] listSessions returned", Array.isArray(data) ? data.length : typeof data, "sessions");
|
|
1204
|
+
return { sessions: data };
|
|
1205
|
+
}
|
|
1206
|
+
catch (err) {
|
|
1207
|
+
console.error("[ai] listSessions exception:", err.message);
|
|
1208
|
+
throw err;
|
|
1209
|
+
}
|
|
1182
1210
|
}
|
|
1183
1211
|
async function handleAiGetSession(payload) {
|
|
1184
1212
|
const id = payload.id;
|
|
1185
1213
|
const response = await opencodeClient.session.get({ path: { id } });
|
|
1186
|
-
return { session: response.
|
|
1214
|
+
return { session: requireData(response, "session.get") };
|
|
1187
1215
|
}
|
|
1188
1216
|
async function handleAiDeleteSession(payload) {
|
|
1189
1217
|
const id = payload.id;
|
|
1190
|
-
await opencodeClient.session.delete({ path: { id } });
|
|
1218
|
+
const response = await opencodeClient.session.delete({ path: { id } });
|
|
1219
|
+
if (response.error)
|
|
1220
|
+
throw new Error(JSON.stringify(response.error));
|
|
1191
1221
|
return {};
|
|
1192
1222
|
}
|
|
1193
1223
|
async function handleAiGetMessages(payload) {
|
|
1194
1224
|
const id = payload.id;
|
|
1195
|
-
|
|
1196
|
-
|
|
1225
|
+
console.log("[ai] getMessages called, sessionId:", id);
|
|
1226
|
+
try {
|
|
1227
|
+
const response = await opencodeClient.session.messages({ path: { id } });
|
|
1228
|
+
return { messages: requireData(response, "session.messages") };
|
|
1229
|
+
}
|
|
1230
|
+
catch (err) {
|
|
1231
|
+
console.error("[ai] getMessages exception:", err.message);
|
|
1232
|
+
throw err;
|
|
1233
|
+
}
|
|
1197
1234
|
}
|
|
1198
1235
|
async function handleAiPrompt(payload) {
|
|
1199
1236
|
const sessionId = payload.sessionId;
|
|
1200
1237
|
const text = payload.text;
|
|
1201
1238
|
const model = payload.model;
|
|
1202
1239
|
const agent = payload.agent;
|
|
1240
|
+
console.log("[ai] prompt called, sessionId:", sessionId, "model:", JSON.stringify(model), "agent:", agent, "text:", text.substring(0, 100));
|
|
1203
1241
|
// Fire and forget — results stream via SSE events forwarded on data channel
|
|
1204
1242
|
opencodeClient.session.prompt({
|
|
1205
1243
|
path: { id: sessionId },
|
|
@@ -1209,6 +1247,7 @@ async function handleAiPrompt(payload) {
|
|
|
1209
1247
|
...(agent ? { agent } : {}),
|
|
1210
1248
|
},
|
|
1211
1249
|
}).catch((err) => {
|
|
1250
|
+
console.error("[ai] prompt error:", err.message);
|
|
1212
1251
|
if (dataChannel && dataChannel.readyState === WebSocket.OPEN) {
|
|
1213
1252
|
dataChannel.send(JSON.stringify({
|
|
1214
1253
|
v: 1,
|
|
@@ -1230,12 +1269,30 @@ async function handleAiAbort(payload) {
|
|
|
1230
1269
|
return {};
|
|
1231
1270
|
}
|
|
1232
1271
|
async function handleAiAgents() {
|
|
1233
|
-
|
|
1234
|
-
|
|
1272
|
+
console.log("[ai] getAgents called");
|
|
1273
|
+
try {
|
|
1274
|
+
const response = await opencodeClient.app.agents();
|
|
1275
|
+
const data = requireData(response, "app.agents");
|
|
1276
|
+
console.log("[ai] getAgents returned:", JSON.stringify(data).substring(0, 300));
|
|
1277
|
+
return { agents: data };
|
|
1278
|
+
}
|
|
1279
|
+
catch (err) {
|
|
1280
|
+
console.error("[ai] getAgents exception:", err.message);
|
|
1281
|
+
throw err;
|
|
1282
|
+
}
|
|
1235
1283
|
}
|
|
1236
1284
|
async function handleAiProviders() {
|
|
1237
|
-
|
|
1238
|
-
|
|
1285
|
+
console.log("[ai] getProviders called");
|
|
1286
|
+
try {
|
|
1287
|
+
const response = await opencodeClient.config.providers();
|
|
1288
|
+
const data = requireData(response, "config.providers");
|
|
1289
|
+
console.log("[ai] getProviders returned", data.providers?.length, "providers, defaults:", JSON.stringify(data.default));
|
|
1290
|
+
return { providers: data.providers, default: data.default };
|
|
1291
|
+
}
|
|
1292
|
+
catch (err) {
|
|
1293
|
+
console.error("[ai] getProviders exception:", err.message);
|
|
1294
|
+
throw err;
|
|
1295
|
+
}
|
|
1239
1296
|
}
|
|
1240
1297
|
async function handleAiSetAuth(payload) {
|
|
1241
1298
|
const providerId = payload.providerId;
|
|
@@ -1254,7 +1311,7 @@ async function handleAiCommand(payload) {
|
|
|
1254
1311
|
path: { id: sessionId },
|
|
1255
1312
|
body: { command, arguments: args },
|
|
1256
1313
|
});
|
|
1257
|
-
return { result: response.data };
|
|
1314
|
+
return { result: response.data ?? null };
|
|
1258
1315
|
}
|
|
1259
1316
|
async function handleAiRevert(payload) {
|
|
1260
1317
|
const sessionId = payload.sessionId;
|
|
@@ -1273,7 +1330,7 @@ async function handleAiUnrevert(payload) {
|
|
|
1273
1330
|
async function handleAiShare(payload) {
|
|
1274
1331
|
const sessionId = payload.sessionId;
|
|
1275
1332
|
const response = await opencodeClient.session.share({ path: { id: sessionId } });
|
|
1276
|
-
return { share: response.
|
|
1333
|
+
return { share: requireData(response, "session.share") };
|
|
1277
1334
|
}
|
|
1278
1335
|
async function handleAiPermissionReply(payload) {
|
|
1279
1336
|
const permissionId = payload.permissionId;
|
|
@@ -1698,6 +1755,7 @@ async function processMessage(message) {
|
|
|
1698
1755
|
}
|
|
1699
1756
|
catch (error) {
|
|
1700
1757
|
const err = error;
|
|
1758
|
+
console.error(`[router] ${ns}.${action} error:`, err.code || "ERROR", err.message);
|
|
1701
1759
|
return {
|
|
1702
1760
|
v: 1,
|
|
1703
1761
|
id,
|
|
@@ -1867,9 +1925,28 @@ async function main() {
|
|
|
1867
1925
|
console.log("Lunel CLI v" + VERSION);
|
|
1868
1926
|
console.log("=".repeat(20) + "\n");
|
|
1869
1927
|
try {
|
|
1870
|
-
//
|
|
1928
|
+
// Generate auth credentials (like CodeNomad does)
|
|
1929
|
+
const opencodeUsername = "lunel";
|
|
1930
|
+
const opencodePassword = crypto.randomBytes(32).toString("base64url");
|
|
1931
|
+
const authHeader = `Basic ${Buffer.from(`${opencodeUsername}:${opencodePassword}`).toString("base64")}`;
|
|
1932
|
+
// Set auth env vars BEFORE spawning opencode
|
|
1933
|
+
process.env.OPENCODE_SERVER_USERNAME = opencodeUsername;
|
|
1934
|
+
process.env.OPENCODE_SERVER_PASSWORD = opencodePassword;
|
|
1935
|
+
// Start OpenCode server with random port (like CodeNomad: --port 0)
|
|
1871
1936
|
console.log("Starting OpenCode...");
|
|
1872
|
-
const
|
|
1937
|
+
const server = await createOpencodeServer({
|
|
1938
|
+
hostname: "127.0.0.1",
|
|
1939
|
+
port: 0,
|
|
1940
|
+
timeout: 15000,
|
|
1941
|
+
});
|
|
1942
|
+
console.log(`OpenCode server listening on ${server.url}`);
|
|
1943
|
+
// Create client with auth headers
|
|
1944
|
+
const client = createOpencodeClient({
|
|
1945
|
+
baseUrl: server.url,
|
|
1946
|
+
headers: {
|
|
1947
|
+
"Authorization": authHeader,
|
|
1948
|
+
},
|
|
1949
|
+
});
|
|
1873
1950
|
opencodeClient = client;
|
|
1874
1951
|
console.log("OpenCode ready.\n");
|
|
1875
1952
|
// Subscribe to OpenCode events
|
|
@@ -1881,6 +1958,8 @@ async function main() {
|
|
|
1881
1958
|
catch (error) {
|
|
1882
1959
|
if (error instanceof Error) {
|
|
1883
1960
|
console.error(`Error: ${error.message}`);
|
|
1961
|
+
if (error.stack)
|
|
1962
|
+
console.error(error.stack);
|
|
1884
1963
|
}
|
|
1885
1964
|
else {
|
|
1886
1965
|
console.error("An unexpected error occurred");
|