@localskills/cli 0.1.3 → 0.1.4
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 +264 -184
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -165,184 +165,8 @@ import { Command as Command7 } from "commander";
|
|
|
165
165
|
|
|
166
166
|
// src/commands/auth.ts
|
|
167
167
|
import { Command } from "commander";
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
171
|
-
import { join } from "path";
|
|
172
|
-
import { homedir } from "os";
|
|
173
|
-
var CONFIG_DIR = join(homedir(), ".localskills");
|
|
174
|
-
var CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
175
|
-
var DEFAULT_CONFIG = {
|
|
176
|
-
config_version: 2,
|
|
177
|
-
api_url: "https://localskills.sh",
|
|
178
|
-
token: null,
|
|
179
|
-
installed_skills: {},
|
|
180
|
-
defaults: {
|
|
181
|
-
scope: "project",
|
|
182
|
-
method: "symlink"
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
function loadConfig() {
|
|
186
|
-
if (!existsSync(CONFIG_PATH)) {
|
|
187
|
-
return { ...DEFAULT_CONFIG, installed_skills: {} };
|
|
188
|
-
}
|
|
189
|
-
try {
|
|
190
|
-
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
191
|
-
if (!raw.config_version || raw.config_version < 2) {
|
|
192
|
-
return migrateV1toV2(raw);
|
|
193
|
-
}
|
|
194
|
-
return { ...DEFAULT_CONFIG, ...raw };
|
|
195
|
-
} catch {
|
|
196
|
-
return { ...DEFAULT_CONFIG, installed_skills: {} };
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
function saveConfig(config) {
|
|
200
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
201
|
-
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n");
|
|
202
|
-
}
|
|
203
|
-
function migrateV1toV2(v1) {
|
|
204
|
-
const v2 = {
|
|
205
|
-
config_version: 2,
|
|
206
|
-
api_url: v1.api_url || DEFAULT_CONFIG.api_url,
|
|
207
|
-
token: v1.token,
|
|
208
|
-
installed_skills: {},
|
|
209
|
-
defaults: {
|
|
210
|
-
scope: "project",
|
|
211
|
-
method: "symlink"
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
for (const [key, skill] of Object.entries(v1.installed_skills || {})) {
|
|
215
|
-
const isGlobal = skill.path.startsWith(homedir());
|
|
216
|
-
v2.installed_skills[key] = {
|
|
217
|
-
slug: skill.slug,
|
|
218
|
-
name: skill.slug,
|
|
219
|
-
hash: skill.hash,
|
|
220
|
-
version: 0,
|
|
221
|
-
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
222
|
-
installations: [
|
|
223
|
-
{
|
|
224
|
-
platform: skill.target,
|
|
225
|
-
scope: isGlobal ? "global" : "project",
|
|
226
|
-
method: "copy",
|
|
227
|
-
path: skill.path,
|
|
228
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
229
|
-
}
|
|
230
|
-
]
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
saveConfig(v2);
|
|
234
|
-
return v2;
|
|
235
|
-
}
|
|
236
|
-
function getToken() {
|
|
237
|
-
return loadConfig().token;
|
|
238
|
-
}
|
|
239
|
-
function setToken(token) {
|
|
240
|
-
const config = loadConfig();
|
|
241
|
-
config.token = token;
|
|
242
|
-
saveConfig(config);
|
|
243
|
-
}
|
|
244
|
-
function clearToken() {
|
|
245
|
-
const config = loadConfig();
|
|
246
|
-
config.token = null;
|
|
247
|
-
saveConfig(config);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// src/lib/api-client.ts
|
|
251
|
-
var ApiClient = class {
|
|
252
|
-
baseUrl;
|
|
253
|
-
token;
|
|
254
|
-
constructor() {
|
|
255
|
-
const config = loadConfig();
|
|
256
|
-
this.baseUrl = config.api_url;
|
|
257
|
-
this.token = config.token;
|
|
258
|
-
}
|
|
259
|
-
headers() {
|
|
260
|
-
const h = {
|
|
261
|
-
"Content-Type": "application/json"
|
|
262
|
-
};
|
|
263
|
-
if (this.token) {
|
|
264
|
-
h["Authorization"] = `Bearer ${this.token}`;
|
|
265
|
-
}
|
|
266
|
-
return h;
|
|
267
|
-
}
|
|
268
|
-
async get(path) {
|
|
269
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
270
|
-
headers: this.headers()
|
|
271
|
-
});
|
|
272
|
-
return res.json();
|
|
273
|
-
}
|
|
274
|
-
async post(path, body) {
|
|
275
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
276
|
-
method: "POST",
|
|
277
|
-
headers: this.headers(),
|
|
278
|
-
body: body ? JSON.stringify(body) : void 0
|
|
279
|
-
});
|
|
280
|
-
return res.json();
|
|
281
|
-
}
|
|
282
|
-
async put(path, body) {
|
|
283
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
284
|
-
method: "PUT",
|
|
285
|
-
headers: this.headers(),
|
|
286
|
-
body: JSON.stringify(body)
|
|
287
|
-
});
|
|
288
|
-
return res.json();
|
|
289
|
-
}
|
|
290
|
-
async delete(path) {
|
|
291
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
292
|
-
method: "DELETE",
|
|
293
|
-
headers: this.headers()
|
|
294
|
-
});
|
|
295
|
-
return res.json();
|
|
296
|
-
}
|
|
297
|
-
async getRaw(path) {
|
|
298
|
-
return fetch(`${this.baseUrl}${path}`, {
|
|
299
|
-
headers: this.headers()
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
isAuthenticated() {
|
|
303
|
-
return this.token !== null;
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
// src/commands/auth.ts
|
|
308
|
-
var loginCommand = new Command("login").description("Log in to localskills.sh").action(async () => {
|
|
309
|
-
const client = new ApiClient();
|
|
310
|
-
console.log("Opening browser for authentication...");
|
|
311
|
-
console.log("Visit: https://localskills.sh/api/cli/auth to authorize this device\n");
|
|
312
|
-
const readline = await import("readline");
|
|
313
|
-
const rl = readline.createInterface({
|
|
314
|
-
input: process.stdin,
|
|
315
|
-
output: process.stdout
|
|
316
|
-
});
|
|
317
|
-
const token = await new Promise((resolve4) => {
|
|
318
|
-
rl.question("Paste your API token: ", (answer) => {
|
|
319
|
-
rl.close();
|
|
320
|
-
resolve4(answer.trim());
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
if (!token) {
|
|
324
|
-
console.error("No token provided. Login cancelled.");
|
|
325
|
-
process.exit(1);
|
|
326
|
-
}
|
|
327
|
-
setToken(token);
|
|
328
|
-
console.log("Logged in successfully!");
|
|
329
|
-
});
|
|
330
|
-
var logoutCommand = new Command("logout").description("Log out of localskills.sh").action(() => {
|
|
331
|
-
clearToken();
|
|
332
|
-
console.log("Logged out.");
|
|
333
|
-
});
|
|
334
|
-
var whoamiCommand = new Command("whoami").description("Show current user info").action(async () => {
|
|
335
|
-
const token = getToken();
|
|
336
|
-
if (!token) {
|
|
337
|
-
console.log("Not logged in. Run `localskills login` to authenticate.");
|
|
338
|
-
process.exit(1);
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
console.log("Authenticated with token:", token.slice(0, 8) + "...");
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
// src/commands/install.ts
|
|
345
|
-
import { Command as Command2 } from "commander";
|
|
168
|
+
import { randomBytes, createHash } from "crypto";
|
|
169
|
+
import { execSync } from "child_process";
|
|
346
170
|
|
|
347
171
|
// ../../node_modules/.pnpm/@clack+core@1.0.1/node_modules/@clack/core/dist/index.mjs
|
|
348
172
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
@@ -1276,6 +1100,262 @@ ${l}
|
|
|
1276
1100
|
}
|
|
1277
1101
|
} }).prompt();
|
|
1278
1102
|
|
|
1103
|
+
// src/lib/config.ts
|
|
1104
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
1105
|
+
import { join } from "path";
|
|
1106
|
+
import { homedir } from "os";
|
|
1107
|
+
var CONFIG_DIR = join(homedir(), ".localskills");
|
|
1108
|
+
var CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
1109
|
+
var DEFAULT_CONFIG = {
|
|
1110
|
+
config_version: 2,
|
|
1111
|
+
api_url: "https://localskills.sh",
|
|
1112
|
+
token: null,
|
|
1113
|
+
installed_skills: {},
|
|
1114
|
+
defaults: {
|
|
1115
|
+
scope: "project",
|
|
1116
|
+
method: "symlink"
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
function loadConfig() {
|
|
1120
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
1121
|
+
return { ...DEFAULT_CONFIG, installed_skills: {} };
|
|
1122
|
+
}
|
|
1123
|
+
try {
|
|
1124
|
+
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
1125
|
+
if (!raw.config_version || raw.config_version < 2) {
|
|
1126
|
+
return migrateV1toV2(raw);
|
|
1127
|
+
}
|
|
1128
|
+
return { ...DEFAULT_CONFIG, ...raw };
|
|
1129
|
+
} catch {
|
|
1130
|
+
return { ...DEFAULT_CONFIG, installed_skills: {} };
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
function saveConfig(config) {
|
|
1134
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
1135
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n");
|
|
1136
|
+
}
|
|
1137
|
+
function migrateV1toV2(v1) {
|
|
1138
|
+
const v2 = {
|
|
1139
|
+
config_version: 2,
|
|
1140
|
+
api_url: v1.api_url || DEFAULT_CONFIG.api_url,
|
|
1141
|
+
token: v1.token,
|
|
1142
|
+
installed_skills: {},
|
|
1143
|
+
defaults: {
|
|
1144
|
+
scope: "project",
|
|
1145
|
+
method: "symlink"
|
|
1146
|
+
}
|
|
1147
|
+
};
|
|
1148
|
+
for (const [key, skill] of Object.entries(v1.installed_skills || {})) {
|
|
1149
|
+
const isGlobal = skill.path.startsWith(homedir());
|
|
1150
|
+
v2.installed_skills[key] = {
|
|
1151
|
+
slug: skill.slug,
|
|
1152
|
+
name: skill.slug,
|
|
1153
|
+
hash: skill.hash,
|
|
1154
|
+
version: 0,
|
|
1155
|
+
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1156
|
+
installations: [
|
|
1157
|
+
{
|
|
1158
|
+
platform: skill.target,
|
|
1159
|
+
scope: isGlobal ? "global" : "project",
|
|
1160
|
+
method: "copy",
|
|
1161
|
+
path: skill.path,
|
|
1162
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1163
|
+
}
|
|
1164
|
+
]
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
saveConfig(v2);
|
|
1168
|
+
return v2;
|
|
1169
|
+
}
|
|
1170
|
+
function getToken() {
|
|
1171
|
+
return loadConfig().token;
|
|
1172
|
+
}
|
|
1173
|
+
function setToken(token) {
|
|
1174
|
+
const config = loadConfig();
|
|
1175
|
+
config.token = token;
|
|
1176
|
+
saveConfig(config);
|
|
1177
|
+
}
|
|
1178
|
+
function clearToken() {
|
|
1179
|
+
const config = loadConfig();
|
|
1180
|
+
config.token = null;
|
|
1181
|
+
saveConfig(config);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/lib/api-client.ts
|
|
1185
|
+
var ApiClient = class {
|
|
1186
|
+
baseUrl;
|
|
1187
|
+
token;
|
|
1188
|
+
constructor() {
|
|
1189
|
+
const config = loadConfig();
|
|
1190
|
+
this.baseUrl = config.api_url;
|
|
1191
|
+
this.token = config.token;
|
|
1192
|
+
}
|
|
1193
|
+
headers() {
|
|
1194
|
+
const h = {
|
|
1195
|
+
"Content-Type": "application/json"
|
|
1196
|
+
};
|
|
1197
|
+
if (this.token) {
|
|
1198
|
+
h["Authorization"] = `Bearer ${this.token}`;
|
|
1199
|
+
}
|
|
1200
|
+
return h;
|
|
1201
|
+
}
|
|
1202
|
+
async get(path) {
|
|
1203
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
1204
|
+
headers: this.headers()
|
|
1205
|
+
});
|
|
1206
|
+
return res.json();
|
|
1207
|
+
}
|
|
1208
|
+
async post(path, body) {
|
|
1209
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
1210
|
+
method: "POST",
|
|
1211
|
+
headers: this.headers(),
|
|
1212
|
+
body: body ? JSON.stringify(body) : void 0
|
|
1213
|
+
});
|
|
1214
|
+
return res.json();
|
|
1215
|
+
}
|
|
1216
|
+
async put(path, body) {
|
|
1217
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
1218
|
+
method: "PUT",
|
|
1219
|
+
headers: this.headers(),
|
|
1220
|
+
body: JSON.stringify(body)
|
|
1221
|
+
});
|
|
1222
|
+
return res.json();
|
|
1223
|
+
}
|
|
1224
|
+
async delete(path) {
|
|
1225
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
1226
|
+
method: "DELETE",
|
|
1227
|
+
headers: this.headers()
|
|
1228
|
+
});
|
|
1229
|
+
return res.json();
|
|
1230
|
+
}
|
|
1231
|
+
async getRaw(path) {
|
|
1232
|
+
return fetch(`${this.baseUrl}${path}`, {
|
|
1233
|
+
headers: this.headers()
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
isAuthenticated() {
|
|
1237
|
+
return this.token !== null;
|
|
1238
|
+
}
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1241
|
+
// src/commands/auth.ts
|
|
1242
|
+
var USER_CODE_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
|
|
1243
|
+
function generateUserCode(length = 8) {
|
|
1244
|
+
const bytes = randomBytes(length);
|
|
1245
|
+
return Array.from(bytes).map((b) => USER_CODE_CHARS[b % USER_CODE_CHARS.length]).join("");
|
|
1246
|
+
}
|
|
1247
|
+
function openBrowser(url) {
|
|
1248
|
+
try {
|
|
1249
|
+
const platform = process.platform;
|
|
1250
|
+
if (platform === "darwin") {
|
|
1251
|
+
execSync(`open "${url}"`, { stdio: "ignore" });
|
|
1252
|
+
} else if (platform === "win32") {
|
|
1253
|
+
execSync(`start "" "${url}"`, { stdio: "ignore" });
|
|
1254
|
+
} else {
|
|
1255
|
+
execSync(`xdg-open "${url}"`, { stdio: "ignore" });
|
|
1256
|
+
}
|
|
1257
|
+
} catch {
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
function sleep(ms) {
|
|
1261
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
1262
|
+
}
|
|
1263
|
+
var loginCommand = new Command("login").description("Log in to localskills.sh").option("--token <token>", "Use an API token directly (headless mode)").action(async (opts) => {
|
|
1264
|
+
if (opts.token) {
|
|
1265
|
+
setToken(opts.token);
|
|
1266
|
+
const client2 = new ApiClient();
|
|
1267
|
+
const res = await client2.get(
|
|
1268
|
+
"/api/cli/auth"
|
|
1269
|
+
);
|
|
1270
|
+
if (res.success && res.data) {
|
|
1271
|
+
const display = res.data.name || res.data.username || res.data.email;
|
|
1272
|
+
console.log(`Logged in as ${display}`);
|
|
1273
|
+
} else {
|
|
1274
|
+
console.error("Warning: Token stored but could not verify. Check that it's valid.");
|
|
1275
|
+
}
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
We("localskills login");
|
|
1279
|
+
const spinner = bt2();
|
|
1280
|
+
spinner.start("Initializing...");
|
|
1281
|
+
const deviceCode = randomBytes(32);
|
|
1282
|
+
const codeHash = createHash("sha256").update(deviceCode).digest("hex");
|
|
1283
|
+
const userCode = generateUserCode();
|
|
1284
|
+
const client = new ApiClient();
|
|
1285
|
+
const initRes = await client.post("/api/cli/auth/device", { codeHash, userCode });
|
|
1286
|
+
if (!initRes.success || !initRes.data) {
|
|
1287
|
+
spinner.stop(`Failed: ${initRes.error || "Could not start login"}`);
|
|
1288
|
+
process.exit(1);
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
spinner.stop("Ready!");
|
|
1292
|
+
const { verificationUrl } = initRes.data;
|
|
1293
|
+
R2.info(`Your verification code: ${userCode}`);
|
|
1294
|
+
R2.message(`Opening browser to ${verificationUrl}`);
|
|
1295
|
+
R2.message("If the browser doesn't open, visit the URL above manually.");
|
|
1296
|
+
openBrowser(verificationUrl);
|
|
1297
|
+
const pollSpinner = bt2();
|
|
1298
|
+
pollSpinner.start("Waiting for authorization...");
|
|
1299
|
+
const expiresAt = new Date(initRes.data.expiresAt).getTime();
|
|
1300
|
+
const POLL_INTERVAL = 2e3;
|
|
1301
|
+
while (Date.now() < expiresAt) {
|
|
1302
|
+
await sleep(POLL_INTERVAL);
|
|
1303
|
+
try {
|
|
1304
|
+
const pollRes = await client.get(
|
|
1305
|
+
`/api/cli/auth/poll?code_hash=${codeHash}`
|
|
1306
|
+
);
|
|
1307
|
+
if (!pollRes.success || !pollRes.data) continue;
|
|
1308
|
+
if (pollRes.data.status === "approved" && pollRes.data.token) {
|
|
1309
|
+
setToken(pollRes.data.token);
|
|
1310
|
+
pollSpinner.stop("Authorized!");
|
|
1311
|
+
const verifyClient = new ApiClient();
|
|
1312
|
+
const whoami = await verifyClient.get("/api/cli/auth");
|
|
1313
|
+
if (whoami.success && whoami.data) {
|
|
1314
|
+
const display = whoami.data.name || whoami.data.username || whoami.data.email;
|
|
1315
|
+
R2.success(`Logged in as ${display}`);
|
|
1316
|
+
}
|
|
1317
|
+
Le("Done!");
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
if (pollRes.data.status === "expired" || pollRes.data.status === "not_found") {
|
|
1321
|
+
pollSpinner.stop("Login expired. Please try again.");
|
|
1322
|
+
process.exit(1);
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
} catch {
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
pollSpinner.stop("Login expired. Please try again.");
|
|
1329
|
+
process.exit(1);
|
|
1330
|
+
});
|
|
1331
|
+
var logoutCommand = new Command("logout").description("Log out of localskills.sh").action(() => {
|
|
1332
|
+
clearToken();
|
|
1333
|
+
console.log("Logged out.");
|
|
1334
|
+
});
|
|
1335
|
+
var whoamiCommand = new Command("whoami").description("Show current user info").action(async () => {
|
|
1336
|
+
const token = getToken();
|
|
1337
|
+
if (!token) {
|
|
1338
|
+
console.log("Not logged in. Run `localskills login` to authenticate.");
|
|
1339
|
+
process.exit(1);
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const client = new ApiClient();
|
|
1343
|
+
const res = await client.get("/api/cli/auth");
|
|
1344
|
+
if (!res.success || !res.data) {
|
|
1345
|
+
console.error("Failed to fetch user info. Your token may be invalid.");
|
|
1346
|
+
console.error("Run `localskills login` to re-authenticate.");
|
|
1347
|
+
process.exit(1);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
const { username, name, email } = res.data;
|
|
1351
|
+
if (name) console.log(` Name: ${name}`);
|
|
1352
|
+
if (username) console.log(` Username: @${username}`);
|
|
1353
|
+
console.log(` Email: ${email}`);
|
|
1354
|
+
});
|
|
1355
|
+
|
|
1356
|
+
// src/commands/install.ts
|
|
1357
|
+
import { Command as Command2 } from "commander";
|
|
1358
|
+
|
|
1279
1359
|
// src/lib/cache.ts
|
|
1280
1360
|
import {
|
|
1281
1361
|
existsSync as existsSync11,
|
|
@@ -1501,7 +1581,7 @@ var claudeAdapter = {
|
|
|
1501
1581
|
// src/lib/installers/codex.ts
|
|
1502
1582
|
import { join as join4 } from "path";
|
|
1503
1583
|
import { homedir as homedir4 } from "os";
|
|
1504
|
-
import { execSync } from "child_process";
|
|
1584
|
+
import { execSync as execSync2 } from "child_process";
|
|
1505
1585
|
|
|
1506
1586
|
// src/lib/marked-sections.ts
|
|
1507
1587
|
import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5 } from "fs";
|
|
@@ -1570,7 +1650,7 @@ var descriptor3 = {
|
|
|
1570
1650
|
function detect3() {
|
|
1571
1651
|
let hasCommand = false;
|
|
1572
1652
|
try {
|
|
1573
|
-
|
|
1653
|
+
execSync2("which codex", { stdio: "ignore" });
|
|
1574
1654
|
hasCommand = true;
|
|
1575
1655
|
} catch {
|
|
1576
1656
|
}
|
|
@@ -1787,7 +1867,7 @@ var copilotAdapter = {
|
|
|
1787
1867
|
import { existsSync as existsSync9, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, unlinkSync as unlinkSync6 } from "fs";
|
|
1788
1868
|
import { join as join8 } from "path";
|
|
1789
1869
|
import { homedir as homedir6 } from "os";
|
|
1790
|
-
import { execSync as
|
|
1870
|
+
import { execSync as execSync3 } from "child_process";
|
|
1791
1871
|
var descriptor7 = {
|
|
1792
1872
|
id: "opencode",
|
|
1793
1873
|
name: "OpenCode",
|
|
@@ -1800,7 +1880,7 @@ function detect7(projectDir) {
|
|
|
1800
1880
|
const cwd = projectDir || process.cwd();
|
|
1801
1881
|
let hasCommand = false;
|
|
1802
1882
|
try {
|
|
1803
|
-
|
|
1883
|
+
execSync3("which opencode", { stdio: "ignore" });
|
|
1804
1884
|
hasCommand = true;
|
|
1805
1885
|
} catch {
|
|
1806
1886
|
}
|
|
@@ -1852,7 +1932,7 @@ var opencodeAdapter = {
|
|
|
1852
1932
|
// src/lib/installers/aider.ts
|
|
1853
1933
|
import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, unlinkSync as unlinkSync7, readFileSync as readFileSync3 } from "fs";
|
|
1854
1934
|
import { join as join9 } from "path";
|
|
1855
|
-
import { execSync as
|
|
1935
|
+
import { execSync as execSync4 } from "child_process";
|
|
1856
1936
|
var descriptor8 = {
|
|
1857
1937
|
id: "aider",
|
|
1858
1938
|
name: "Aider",
|
|
@@ -1864,7 +1944,7 @@ var descriptor8 = {
|
|
|
1864
1944
|
function detect8() {
|
|
1865
1945
|
let hasCommand = false;
|
|
1866
1946
|
try {
|
|
1867
|
-
|
|
1947
|
+
execSync4("which aider", { stdio: "ignore" });
|
|
1868
1948
|
hasCommand = true;
|
|
1869
1949
|
} catch {
|
|
1870
1950
|
}
|