apero-kit-cli 2.4.8 → 2.5.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/index.js +1280 -892
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/discord/README.md +54 -7
- package/templates/discord/start-bot.sh +47 -0
package/dist/index.js
CHANGED
|
@@ -163,6 +163,17 @@ var init_kits = __esm({
|
|
|
163
163
|
});
|
|
164
164
|
|
|
165
165
|
// src/utils/paths.ts
|
|
166
|
+
var paths_exports = {};
|
|
167
|
+
__export(paths_exports, {
|
|
168
|
+
CLI_ROOT: () => CLI_ROOT,
|
|
169
|
+
TARGETS: () => TARGETS,
|
|
170
|
+
TEMPLATES_DIR: () => TEMPLATES_DIR,
|
|
171
|
+
getEmbeddedTemplates: () => getEmbeddedTemplates,
|
|
172
|
+
getGlobalInstallPath: () => getGlobalInstallPath,
|
|
173
|
+
getTargetDir: () => getTargetDir,
|
|
174
|
+
isAkProject: () => isAkProject,
|
|
175
|
+
resolveSource: () => resolveSource
|
|
176
|
+
});
|
|
166
177
|
import { fileURLToPath } from "url";
|
|
167
178
|
import { dirname, join, resolve } from "path";
|
|
168
179
|
import { existsSync } from "fs";
|
|
@@ -257,643 +268,618 @@ var init_paths = __esm({
|
|
|
257
268
|
}
|
|
258
269
|
});
|
|
259
270
|
|
|
260
|
-
// src/
|
|
271
|
+
// src/targets/base-adapter.ts
|
|
261
272
|
import fs from "fs-extra";
|
|
262
273
|
import { join as join2, dirname as dirname2 } from "path";
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
async
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
srcPath = itemPathMd;
|
|
312
|
-
} else {
|
|
313
|
-
skipped.push(item);
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
const stat = fs.statSync(srcPath);
|
|
317
|
-
if (stat.isDirectory()) {
|
|
318
|
-
await fs.copy(srcPath, join2(destTypeDir, item), { overwrite: !mergeMode });
|
|
319
|
-
} else {
|
|
320
|
-
const destPath = srcPath.endsWith(".md") ? join2(destTypeDir, item + ".md") : join2(destTypeDir, item);
|
|
321
|
-
await fs.ensureDir(join2(destTypeDir, item.split("/").slice(0, -1).join("/")));
|
|
322
|
-
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
274
|
+
var BaseTargetAdapter;
|
|
275
|
+
var init_base_adapter = __esm({
|
|
276
|
+
"src/targets/base-adapter.ts"() {
|
|
277
|
+
"use strict";
|
|
278
|
+
BaseTargetAdapter = class {
|
|
279
|
+
supports(feature) {
|
|
280
|
+
return this.config.features[feature];
|
|
281
|
+
}
|
|
282
|
+
getSupportedFeatures() {
|
|
283
|
+
return Object.entries(this.config.features).filter(([_, supported]) => supported).map(([feature]) => feature);
|
|
284
|
+
}
|
|
285
|
+
filterInstallItems(items) {
|
|
286
|
+
return {
|
|
287
|
+
agents: this.supports("agents") ? items.agents : [],
|
|
288
|
+
skills: this.supports("skills") ? items.skills : [],
|
|
289
|
+
commands: this.supports("commands") ? items.commands : [],
|
|
290
|
+
workflows: this.supports("workflows") ? items.workflows : [],
|
|
291
|
+
includeRouter: this.supports("router") && items.includeRouter,
|
|
292
|
+
includeHooks: this.supports("hooks") && items.includeHooks
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Default: not supported - override in subclass if needed
|
|
297
|
+
*/
|
|
298
|
+
async copyWorkflows(_items, _sourceDir, _targetDir, _mergeMode) {
|
|
299
|
+
return { copied: [], skipped: [], errors: [] };
|
|
300
|
+
}
|
|
301
|
+
async copyRouter(_sourceDir, _targetDir, _mergeMode) {
|
|
302
|
+
return { success: false, error: "Router not supported by this target" };
|
|
303
|
+
}
|
|
304
|
+
async copyHooks(_sourceDir, _targetDir, _mergeMode) {
|
|
305
|
+
return { success: false, error: "Hooks not supported by this target" };
|
|
306
|
+
}
|
|
307
|
+
async copyExtras(_sourceDir, _targetDir, _mergeMode) {
|
|
308
|
+
return [];
|
|
309
|
+
}
|
|
310
|
+
// Helper methods for common operations
|
|
311
|
+
async copyDirectory(dirName, sourceDir, destDir, mergeMode) {
|
|
312
|
+
const srcPath = join2(sourceDir, dirName);
|
|
313
|
+
if (!fs.existsSync(srcPath)) {
|
|
314
|
+
return { success: false, error: `${dirName} directory not found` };
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
await fs.copy(srcPath, join2(destDir, dirName), { overwrite: !mergeMode });
|
|
318
|
+
return { success: true };
|
|
319
|
+
} catch (err) {
|
|
320
|
+
return { success: false, error: err.message };
|
|
321
|
+
}
|
|
323
322
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return { copied, skipped, errors };
|
|
330
|
-
}
|
|
331
|
-
async function copyAllOfType(type, sourceDir, destDir, mergeMode = false) {
|
|
332
|
-
const typeDir = join2(sourceDir, type);
|
|
333
|
-
const destTypeDir = join2(destDir, type);
|
|
334
|
-
if (!fs.existsSync(typeDir)) {
|
|
335
|
-
return { success: false, error: `${type} directory not found` };
|
|
336
|
-
}
|
|
337
|
-
try {
|
|
338
|
-
await fs.copy(typeDir, destTypeDir, { overwrite: !mergeMode });
|
|
339
|
-
return { success: true };
|
|
340
|
-
} catch (err) {
|
|
341
|
-
return { success: false, error: err.message };
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
async function copyRouter(sourceDir, destDir, mergeMode = false) {
|
|
345
|
-
const routerDir = join2(sourceDir, "router");
|
|
346
|
-
if (!fs.existsSync(routerDir)) {
|
|
347
|
-
return { success: false, error: "Router directory not found" };
|
|
348
|
-
}
|
|
349
|
-
try {
|
|
350
|
-
await fs.copy(routerDir, join2(destDir, "router"), { overwrite: !mergeMode });
|
|
351
|
-
return { success: true };
|
|
352
|
-
} catch (err) {
|
|
353
|
-
return { success: false, error: err.message };
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
async function copyHooks(sourceDir, destDir, mergeMode = false) {
|
|
357
|
-
const hooksDir = join2(sourceDir, "hooks");
|
|
358
|
-
if (!fs.existsSync(hooksDir)) {
|
|
359
|
-
return { success: false, error: "Hooks directory not found" };
|
|
360
|
-
}
|
|
361
|
-
try {
|
|
362
|
-
await fs.copy(hooksDir, join2(destDir, "hooks"), { overwrite: !mergeMode });
|
|
363
|
-
return { success: true };
|
|
364
|
-
} catch (err) {
|
|
365
|
-
return { success: false, error: err.message };
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
async function copyBaseFiles(sourceDir, destDir, mergeMode = false) {
|
|
369
|
-
const baseFiles = ["README.md", "settings.json", ".env.example", "statusline.cjs", "statusline.ps1", "statusline.sh"];
|
|
370
|
-
const copied = [];
|
|
371
|
-
for (const file of baseFiles) {
|
|
372
|
-
const srcPath = join2(sourceDir, file);
|
|
373
|
-
const destPath = join2(destDir, file);
|
|
374
|
-
if (mergeMode && fs.existsSync(destPath)) {
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
if (fs.existsSync(srcPath)) {
|
|
378
|
-
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
379
|
-
copied.push(file);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
return copied;
|
|
383
|
-
}
|
|
384
|
-
async function copyDirectory(dirName, sourceDir, destDir, mergeMode = false) {
|
|
385
|
-
const srcPath = join2(sourceDir, dirName);
|
|
386
|
-
if (!fs.existsSync(srcPath)) {
|
|
387
|
-
return { success: false, error: `${dirName} directory not found` };
|
|
388
|
-
}
|
|
389
|
-
try {
|
|
390
|
-
await fs.copy(srcPath, join2(destDir, dirName), { overwrite: !mergeMode });
|
|
391
|
-
return { success: true };
|
|
392
|
-
} catch (err) {
|
|
393
|
-
return { success: false, error: err.message };
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
async function copyAgentsMd(agentsMdPath, projectDir, mergeMode = false) {
|
|
397
|
-
if (!agentsMdPath || !fs.existsSync(agentsMdPath)) {
|
|
398
|
-
return false;
|
|
399
|
-
}
|
|
400
|
-
const destPath = join2(projectDir, "AGENTS.md");
|
|
401
|
-
if (mergeMode && fs.existsSync(destPath)) {
|
|
402
|
-
return false;
|
|
403
|
-
}
|
|
404
|
-
await fs.copy(agentsMdPath, destPath, { overwrite: !mergeMode });
|
|
405
|
-
return true;
|
|
406
|
-
}
|
|
407
|
-
function listAvailable(type, sourceDir) {
|
|
408
|
-
const typeDir = join2(sourceDir, type);
|
|
409
|
-
if (!fs.existsSync(typeDir)) {
|
|
410
|
-
return [];
|
|
411
|
-
}
|
|
412
|
-
const items = fs.readdirSync(typeDir);
|
|
413
|
-
return items.map((item) => {
|
|
414
|
-
const itemPath = join2(typeDir, item);
|
|
415
|
-
const isDir = fs.statSync(itemPath).isDirectory();
|
|
416
|
-
const name = item.replace(/\.md$/, "");
|
|
417
|
-
return { name, isDir, path: itemPath };
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
async function copyCommandsForGemini(items, sourceDir, destDir, mergeMode = false) {
|
|
421
|
-
const typeDir = join2(sourceDir, "commands");
|
|
422
|
-
const destTypeDir = join2(destDir, "commands");
|
|
423
|
-
if (!fs.existsSync(typeDir)) {
|
|
424
|
-
return { copied: [], skipped: [], errors: [] };
|
|
425
|
-
}
|
|
426
|
-
await fs.ensureDir(destTypeDir);
|
|
427
|
-
const copied = [];
|
|
428
|
-
const skipped = [];
|
|
429
|
-
const errors = [];
|
|
430
|
-
let itemList;
|
|
431
|
-
if (items === "all") {
|
|
432
|
-
const entries = fs.readdirSync(typeDir);
|
|
433
|
-
itemList = entries.map((e) => e.replace(/\.md$/, ""));
|
|
434
|
-
itemList = [...new Set(itemList)];
|
|
435
|
-
} else {
|
|
436
|
-
itemList = items;
|
|
437
|
-
}
|
|
438
|
-
for (const item of itemList) {
|
|
439
|
-
try {
|
|
440
|
-
const srcPathMd = join2(typeDir, item + ".md");
|
|
441
|
-
const srcPathDir = join2(typeDir, item);
|
|
442
|
-
let copiedSomething = false;
|
|
443
|
-
if (fs.existsSync(srcPathMd) && fs.statSync(srcPathMd).isFile()) {
|
|
444
|
-
const destPath = join2(destTypeDir, item + ".toml");
|
|
445
|
-
if (!(mergeMode && fs.existsSync(destPath))) {
|
|
323
|
+
async copyFile(srcPath, destPath, mergeMode) {
|
|
324
|
+
if (mergeMode && fs.existsSync(destPath)) {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
if (fs.existsSync(srcPath)) {
|
|
446
328
|
await fs.ensureDir(dirname2(destPath));
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
await fs.writeFile(destPath, tomlContent, "utf-8");
|
|
450
|
-
copiedSomething = true;
|
|
329
|
+
await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
330
|
+
return true;
|
|
451
331
|
}
|
|
332
|
+
return false;
|
|
452
333
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
334
|
+
async listItems(typeDir, extension) {
|
|
335
|
+
if (!fs.existsSync(typeDir)) {
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
const entries = fs.readdirSync(typeDir);
|
|
339
|
+
return entries.filter((e) => {
|
|
340
|
+
if (extension) {
|
|
341
|
+
return e.endsWith(extension) && e !== "README.md";
|
|
342
|
+
}
|
|
343
|
+
return e !== "README.md";
|
|
344
|
+
}).map((e) => extension ? e.replace(extension, "") : e);
|
|
456
345
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
346
|
+
getItemList(items, typeDir, extension) {
|
|
347
|
+
if (items === "all") {
|
|
348
|
+
return this.listItemsSync(typeDir, extension);
|
|
349
|
+
}
|
|
350
|
+
return items;
|
|
461
351
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
352
|
+
listItemsSync(typeDir, extension) {
|
|
353
|
+
if (!fs.existsSync(typeDir)) {
|
|
354
|
+
return [];
|
|
355
|
+
}
|
|
356
|
+
const entries = fs.readdirSync(typeDir);
|
|
357
|
+
let result = entries.filter((e) => e !== "README.md");
|
|
358
|
+
if (extension) {
|
|
359
|
+
result = result.filter((e) => e.endsWith(extension)).map((e) => e.replace(extension, ""));
|
|
360
|
+
}
|
|
361
|
+
return [...new Set(result.map((e) => e.replace(/\.md$/, "")))];
|
|
362
|
+
}
|
|
363
|
+
};
|
|
465
364
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// src/targets/claude-adapter.ts
|
|
368
|
+
import fs2 from "fs-extra";
|
|
369
|
+
import { join as join3 } from "path";
|
|
370
|
+
var ClaudeAdapter;
|
|
371
|
+
var init_claude_adapter = __esm({
|
|
372
|
+
"src/targets/claude-adapter.ts"() {
|
|
373
|
+
"use strict";
|
|
374
|
+
init_base_adapter();
|
|
375
|
+
ClaudeAdapter = class extends BaseTargetAdapter {
|
|
376
|
+
config = {
|
|
377
|
+
name: "claude",
|
|
378
|
+
displayName: "Claude Code",
|
|
379
|
+
directory: ".claude",
|
|
380
|
+
features: {
|
|
381
|
+
agents: true,
|
|
382
|
+
skills: true,
|
|
383
|
+
commands: true,
|
|
384
|
+
workflows: true,
|
|
385
|
+
router: true,
|
|
386
|
+
hooks: true,
|
|
387
|
+
memory: true,
|
|
388
|
+
scripts: true,
|
|
389
|
+
"output-styles": true
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
async copyAgents(items, sourceDir, targetDir, mergeMode) {
|
|
393
|
+
const typeDir = join3(sourceDir, "agents");
|
|
394
|
+
const destTypeDir = join3(targetDir, "agents");
|
|
395
|
+
if (!fs2.existsSync(typeDir)) {
|
|
396
|
+
return { copied: [], skipped: [], errors: [] };
|
|
397
|
+
}
|
|
398
|
+
await fs2.ensureDir(destTypeDir);
|
|
399
|
+
if (items === "all") {
|
|
400
|
+
await fs2.copy(typeDir, destTypeDir, { overwrite: !mergeMode });
|
|
401
|
+
const entries = fs2.readdirSync(typeDir).filter((e) => e.endsWith(".md") && e !== "README.md");
|
|
402
|
+
return { copied: entries.map((e) => e.replace(".md", "")), skipped: [], errors: [] };
|
|
403
|
+
}
|
|
404
|
+
const copied = [];
|
|
405
|
+
const skipped = [];
|
|
406
|
+
const errors = [];
|
|
407
|
+
for (const agent of items) {
|
|
408
|
+
try {
|
|
409
|
+
const srcPath = join3(typeDir, agent + ".md");
|
|
410
|
+
if (!fs2.existsSync(srcPath)) {
|
|
411
|
+
skipped.push(agent);
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
const destPath = join3(destTypeDir, agent + ".md");
|
|
415
|
+
if (mergeMode && fs2.existsSync(destPath)) {
|
|
416
|
+
skipped.push(agent);
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
await fs2.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
420
|
+
copied.push(agent);
|
|
421
|
+
} catch (err) {
|
|
422
|
+
errors.push({ item: agent, error: err.message });
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return { copied, skipped, errors };
|
|
480
426
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
427
|
+
async copySkills(items, sourceDir, targetDir, mergeMode) {
|
|
428
|
+
const typeDir = join3(sourceDir, "skills");
|
|
429
|
+
const destTypeDir = join3(targetDir, "skills");
|
|
430
|
+
if (!fs2.existsSync(typeDir)) {
|
|
431
|
+
return { copied: [], skipped: [], errors: [] };
|
|
432
|
+
}
|
|
433
|
+
await fs2.ensureDir(destTypeDir);
|
|
434
|
+
if (items === "all") {
|
|
435
|
+
await fs2.copy(typeDir, destTypeDir, { overwrite: !mergeMode });
|
|
436
|
+
const entries = fs2.readdirSync(typeDir).filter((e) => {
|
|
437
|
+
const fullPath = join3(typeDir, e);
|
|
438
|
+
return fs2.statSync(fullPath).isDirectory() && fs2.existsSync(join3(fullPath, "SKILL.md"));
|
|
439
|
+
});
|
|
440
|
+
return { copied: entries, skipped: [], errors: [] };
|
|
441
|
+
}
|
|
442
|
+
const copied = [];
|
|
443
|
+
const skipped = [];
|
|
444
|
+
const errors = [];
|
|
445
|
+
for (const skill of items) {
|
|
446
|
+
try {
|
|
447
|
+
const srcPath = join3(typeDir, skill);
|
|
448
|
+
if (!fs2.existsSync(srcPath) || !fs2.statSync(srcPath).isDirectory()) {
|
|
449
|
+
skipped.push(skill);
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (!fs2.existsSync(join3(srcPath, "SKILL.md"))) {
|
|
453
|
+
skipped.push(skill);
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
const destPath = join3(destTypeDir, skill);
|
|
457
|
+
if (mergeMode && fs2.existsSync(destPath)) {
|
|
458
|
+
skipped.push(skill);
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
await fs2.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
462
|
+
copied.push(skill);
|
|
463
|
+
} catch (err) {
|
|
464
|
+
errors.push({ item: skill, error: err.message });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return { copied, skipped, errors };
|
|
488
468
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const errors = [];
|
|
532
|
-
let agentList;
|
|
533
|
-
if (items === "all") {
|
|
534
|
-
const entries = fs.readdirSync(typeDir);
|
|
535
|
-
agentList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(/\.md$/, ""));
|
|
536
|
-
} else {
|
|
537
|
-
agentList = items;
|
|
538
|
-
}
|
|
539
|
-
for (const agent of agentList) {
|
|
540
|
-
try {
|
|
541
|
-
const srcPath = join2(typeDir, agent + ".md");
|
|
542
|
-
if (!fs.existsSync(srcPath)) {
|
|
543
|
-
skipped.push(agent);
|
|
544
|
-
continue;
|
|
469
|
+
async copyCommands(items, sourceDir, targetDir, mergeMode) {
|
|
470
|
+
const typeDir = join3(sourceDir, "commands");
|
|
471
|
+
const destTypeDir = join3(targetDir, "commands");
|
|
472
|
+
if (!fs2.existsSync(typeDir)) {
|
|
473
|
+
return { copied: [], skipped: [], errors: [] };
|
|
474
|
+
}
|
|
475
|
+
await fs2.ensureDir(destTypeDir);
|
|
476
|
+
if (items === "all") {
|
|
477
|
+
await fs2.copy(typeDir, destTypeDir, { overwrite: !mergeMode });
|
|
478
|
+
const entries = fs2.readdirSync(typeDir);
|
|
479
|
+
return { copied: [...new Set(entries.map((e) => e.replace(".md", "")))], skipped: [], errors: [] };
|
|
480
|
+
}
|
|
481
|
+
const copied = [];
|
|
482
|
+
const skipped = [];
|
|
483
|
+
const errors = [];
|
|
484
|
+
for (const item of items) {
|
|
485
|
+
try {
|
|
486
|
+
const itemPath = join3(typeDir, item);
|
|
487
|
+
const itemPathMd = itemPath + ".md";
|
|
488
|
+
let srcPath = null;
|
|
489
|
+
if (fs2.existsSync(itemPath)) {
|
|
490
|
+
srcPath = itemPath;
|
|
491
|
+
} else if (fs2.existsSync(itemPathMd)) {
|
|
492
|
+
srcPath = itemPathMd;
|
|
493
|
+
}
|
|
494
|
+
if (!srcPath) {
|
|
495
|
+
skipped.push(item);
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
const stat = fs2.statSync(srcPath);
|
|
499
|
+
const destPath = stat.isDirectory() ? join3(destTypeDir, item) : join3(destTypeDir, item + ".md");
|
|
500
|
+
if (mergeMode && fs2.existsSync(destPath)) {
|
|
501
|
+
skipped.push(item);
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
await fs2.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
505
|
+
copied.push(item);
|
|
506
|
+
} catch (err) {
|
|
507
|
+
errors.push({ item, error: err.message });
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return { copied, skipped, errors };
|
|
545
511
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
512
|
+
async copyWorkflows(items, sourceDir, targetDir, mergeMode) {
|
|
513
|
+
const typeDir = join3(sourceDir, "workflows");
|
|
514
|
+
const destTypeDir = join3(targetDir, "workflows");
|
|
515
|
+
if (!fs2.existsSync(typeDir)) {
|
|
516
|
+
return { copied: [], skipped: [], errors: [] };
|
|
517
|
+
}
|
|
518
|
+
await fs2.ensureDir(destTypeDir);
|
|
519
|
+
if (items === "all") {
|
|
520
|
+
await fs2.copy(typeDir, destTypeDir, { overwrite: !mergeMode });
|
|
521
|
+
const entries = fs2.readdirSync(typeDir);
|
|
522
|
+
return { copied: entries.map((e) => e.replace(".md", "")), skipped: [], errors: [] };
|
|
523
|
+
}
|
|
524
|
+
const copied = [];
|
|
525
|
+
const skipped = [];
|
|
526
|
+
const errors = [];
|
|
527
|
+
for (const item of items) {
|
|
528
|
+
try {
|
|
529
|
+
const srcPath = join3(typeDir, item + ".md");
|
|
530
|
+
if (!fs2.existsSync(srcPath)) {
|
|
531
|
+
skipped.push(item);
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
const destPath = join3(destTypeDir, item + ".md");
|
|
535
|
+
if (mergeMode && fs2.existsSync(destPath)) {
|
|
536
|
+
skipped.push(item);
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
await fs2.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
540
|
+
copied.push(item);
|
|
541
|
+
} catch (err) {
|
|
542
|
+
errors.push({ item, error: err.message });
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return { copied, skipped, errors };
|
|
550
546
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
await fs.writeFile(destPath, convertedContent, "utf-8");
|
|
554
|
-
copied.push(agent);
|
|
555
|
-
} catch (err) {
|
|
556
|
-
errors.push({ item: agent, error: err.message });
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return { copied, skipped, errors };
|
|
560
|
-
}
|
|
561
|
-
async function copySkillsForGemini(items, sourceDir, destDir, mergeMode = false) {
|
|
562
|
-
const typeDir = join2(sourceDir, "skills");
|
|
563
|
-
const destTypeDir = join2(destDir, "skills");
|
|
564
|
-
if (!fs.existsSync(typeDir)) {
|
|
565
|
-
return { copied: [], skipped: [], errors: [] };
|
|
566
|
-
}
|
|
567
|
-
await fs.ensureDir(destTypeDir);
|
|
568
|
-
const copied = [];
|
|
569
|
-
const skipped = [];
|
|
570
|
-
const errors = [];
|
|
571
|
-
let skillList;
|
|
572
|
-
if (items === "all") {
|
|
573
|
-
const entries = fs.readdirSync(typeDir);
|
|
574
|
-
skillList = entries.filter((e) => {
|
|
575
|
-
const fullPath = join2(typeDir, e);
|
|
576
|
-
return fs.statSync(fullPath).isDirectory() && fs.existsSync(join2(fullPath, "SKILL.md"));
|
|
577
|
-
});
|
|
578
|
-
} else {
|
|
579
|
-
skillList = items;
|
|
580
|
-
}
|
|
581
|
-
for (const skill of skillList) {
|
|
582
|
-
try {
|
|
583
|
-
const srcPath = join2(typeDir, skill);
|
|
584
|
-
if (!fs.existsSync(srcPath) || !fs.statSync(srcPath).isDirectory()) {
|
|
585
|
-
skipped.push(skill);
|
|
586
|
-
continue;
|
|
547
|
+
async copyRouter(sourceDir, targetDir, mergeMode) {
|
|
548
|
+
return this.copyDirectory("router", sourceDir, targetDir, mergeMode);
|
|
587
549
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
skipped.push(skill);
|
|
591
|
-
continue;
|
|
550
|
+
async copyHooks(sourceDir, targetDir, mergeMode) {
|
|
551
|
+
return this.copyDirectory("hooks", sourceDir, targetDir, mergeMode);
|
|
592
552
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
553
|
+
async copyExtras(sourceDir, targetDir, mergeMode) {
|
|
554
|
+
const extras = ["memory", "output-styles", "scripts"];
|
|
555
|
+
const copied = [];
|
|
556
|
+
for (const extra of extras) {
|
|
557
|
+
const result = await this.copyDirectory(extra, sourceDir, targetDir, mergeMode);
|
|
558
|
+
if (result.success) {
|
|
559
|
+
copied.push(extra);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return copied;
|
|
563
|
+
}
|
|
564
|
+
async copyBaseFiles(targetDir, mergeMode) {
|
|
565
|
+
const { CLI_ROOT: CLI_ROOT2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
566
|
+
const sourceDir = join3(CLI_ROOT2, "templates");
|
|
567
|
+
const baseFiles = ["README.md", "settings.json", ".env.example", "statusline.cjs", "statusline.ps1", "statusline.sh"];
|
|
568
|
+
const copied = [];
|
|
569
|
+
for (const file of baseFiles) {
|
|
570
|
+
const srcPath = join3(sourceDir, file);
|
|
571
|
+
const destPath = join3(targetDir, file);
|
|
572
|
+
if (await this.copyFile(srcPath, destPath, mergeMode)) {
|
|
573
|
+
copied.push(file);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return copied;
|
|
597
577
|
}
|
|
598
|
-
|
|
599
|
-
copied.push(skill);
|
|
600
|
-
} catch (err) {
|
|
601
|
-
errors.push({ skill, error: err.message });
|
|
602
|
-
}
|
|
578
|
+
};
|
|
603
579
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
const
|
|
611
|
-
if (
|
|
612
|
-
|
|
613
|
-
return copied;
|
|
614
|
-
}
|
|
615
|
-
await fs.copy(settingsPath, destSettingsPath, { overwrite: !mergeMode });
|
|
616
|
-
copied.push("settings.json");
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// src/targets/gemini-adapter.ts
|
|
583
|
+
import fs3 from "fs-extra";
|
|
584
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
585
|
+
function parseFrontmatter(content) {
|
|
586
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
587
|
+
if (!match) {
|
|
588
|
+
return { frontmatter: "", body: content };
|
|
617
589
|
}
|
|
618
|
-
return
|
|
590
|
+
return { frontmatter: match[1], body: match[2] };
|
|
619
591
|
}
|
|
620
|
-
function
|
|
621
|
-
|
|
622
|
-
const prompt = body.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
623
|
-
return {
|
|
624
|
-
name: commandName,
|
|
625
|
-
description: description || `Execute ${commandName} command`,
|
|
626
|
-
prompt
|
|
627
|
-
};
|
|
592
|
+
function escapeTomlString(str) {
|
|
593
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
628
594
|
}
|
|
629
|
-
function
|
|
630
|
-
const
|
|
631
|
-
if (!
|
|
632
|
-
let
|
|
633
|
-
const
|
|
634
|
-
const modelMap = {
|
|
635
|
-
"opus": "claude-3-opus",
|
|
636
|
-
"sonnet": "claude-3-sonnet",
|
|
637
|
-
"haiku": "claude-3-haiku",
|
|
638
|
-
"inherit": ""
|
|
639
|
-
// Remove inherit
|
|
640
|
-
};
|
|
641
|
-
for (const [claudeModel, discordModel] of Object.entries(modelMap)) {
|
|
595
|
+
function convertAgentToGemini(mdContent) {
|
|
596
|
+
const { frontmatter, body } = parseFrontmatter(mdContent);
|
|
597
|
+
if (!frontmatter) return mdContent;
|
|
598
|
+
let converted = frontmatter;
|
|
599
|
+
for (const [claudeModel, geminiModel] of Object.entries(MODEL_MAP)) {
|
|
642
600
|
const regex = new RegExp(`^model:\\s*${claudeModel}\\s*$`, "m");
|
|
643
|
-
if (
|
|
644
|
-
|
|
601
|
+
if (geminiModel) {
|
|
602
|
+
converted = converted.replace(regex, `model: ${geminiModel}`);
|
|
645
603
|
} else {
|
|
646
|
-
|
|
604
|
+
converted = converted.replace(regex, "");
|
|
647
605
|
}
|
|
648
606
|
}
|
|
649
|
-
|
|
650
|
-
if (!
|
|
651
|
-
|
|
607
|
+
converted = converted.replace(/^tools:\s*.+$/m, "");
|
|
608
|
+
if (!converted.includes("kind:")) {
|
|
609
|
+
converted = converted.trim() + "\nkind: local";
|
|
652
610
|
}
|
|
653
611
|
return `---
|
|
654
|
-
${
|
|
612
|
+
${converted.trim()}
|
|
655
613
|
---
|
|
656
614
|
${body}`;
|
|
657
615
|
}
|
|
658
|
-
|
|
659
|
-
const
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const skipped = [];
|
|
667
|
-
const errors = [];
|
|
668
|
-
let agentList;
|
|
669
|
-
if (items === "all") {
|
|
670
|
-
const entries = fs.readdirSync(typeDir);
|
|
671
|
-
agentList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(/\.md$/, ""));
|
|
672
|
-
} else {
|
|
673
|
-
agentList = items;
|
|
674
|
-
}
|
|
675
|
-
for (const agent of agentList) {
|
|
676
|
-
try {
|
|
677
|
-
const srcPath = join2(typeDir, agent + ".md");
|
|
678
|
-
if (!fs.existsSync(srcPath)) {
|
|
679
|
-
skipped.push(agent);
|
|
680
|
-
continue;
|
|
681
|
-
}
|
|
682
|
-
const destPath = join2(destTypeDir, agent + ".md");
|
|
683
|
-
if (mergeMode && fs.existsSync(destPath)) {
|
|
684
|
-
skipped.push(agent);
|
|
685
|
-
continue;
|
|
686
|
-
}
|
|
687
|
-
const mdContent = fs.readFileSync(srcPath, "utf-8");
|
|
688
|
-
const convertedContent = convertAgentForDiscord(mdContent);
|
|
689
|
-
await fs.writeFile(destPath, convertedContent, "utf-8");
|
|
690
|
-
copied.push(agent);
|
|
691
|
-
} catch (err) {
|
|
692
|
-
errors.push({ item: agent, error: err.message });
|
|
693
|
-
}
|
|
616
|
+
function convertCommandToToml(mdContent) {
|
|
617
|
+
const { frontmatter, body } = parseFrontmatter(mdContent);
|
|
618
|
+
const descMatch = frontmatter.match(/description:\s*(.+)/);
|
|
619
|
+
const description = descMatch ? descMatch[1].trim() : "";
|
|
620
|
+
const prompt = body.trim().replace(/\$ARGUMENTS/g, "{{args}}");
|
|
621
|
+
const lines = [];
|
|
622
|
+
if (description) {
|
|
623
|
+
lines.push(`description = "${escapeTomlString(description)}"`);
|
|
694
624
|
}
|
|
695
|
-
|
|
625
|
+
lines.push(`prompt = '''
|
|
626
|
+
${prompt}
|
|
627
|
+
'''`);
|
|
628
|
+
return lines.join("\n");
|
|
696
629
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
copied
|
|
741
|
-
|
|
742
|
-
|
|
630
|
+
var MODEL_MAP, GeminiAdapter;
|
|
631
|
+
var init_gemini_adapter = __esm({
|
|
632
|
+
"src/targets/gemini-adapter.ts"() {
|
|
633
|
+
"use strict";
|
|
634
|
+
init_base_adapter();
|
|
635
|
+
MODEL_MAP = {
|
|
636
|
+
"opus": "gemini-2.5-pro",
|
|
637
|
+
"sonnet": "gemini-2.5-flash",
|
|
638
|
+
"haiku": "gemini-2.0-flash-lite",
|
|
639
|
+
"inherit": ""
|
|
640
|
+
// Remove inherit, let Gemini use default
|
|
641
|
+
};
|
|
642
|
+
GeminiAdapter = class extends BaseTargetAdapter {
|
|
643
|
+
config = {
|
|
644
|
+
name: "gemini",
|
|
645
|
+
displayName: "Gemini CLI",
|
|
646
|
+
directory: ".gemini",
|
|
647
|
+
features: {
|
|
648
|
+
agents: true,
|
|
649
|
+
skills: true,
|
|
650
|
+
commands: true,
|
|
651
|
+
workflows: false,
|
|
652
|
+
router: false,
|
|
653
|
+
hooks: false,
|
|
654
|
+
memory: false,
|
|
655
|
+
scripts: false,
|
|
656
|
+
"output-styles": false
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
async copyAgents(items, sourceDir, targetDir, mergeMode) {
|
|
660
|
+
const typeDir = join4(sourceDir, "agents");
|
|
661
|
+
const destTypeDir = join4(targetDir, "agents");
|
|
662
|
+
if (!fs3.existsSync(typeDir)) {
|
|
663
|
+
return { copied: [], skipped: [], errors: [] };
|
|
664
|
+
}
|
|
665
|
+
await fs3.ensureDir(destTypeDir);
|
|
666
|
+
let agentList;
|
|
667
|
+
if (items === "all") {
|
|
668
|
+
const entries = fs3.readdirSync(typeDir);
|
|
669
|
+
agentList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(".md", ""));
|
|
670
|
+
} else {
|
|
671
|
+
agentList = items;
|
|
672
|
+
}
|
|
673
|
+
const copied = [];
|
|
674
|
+
const skipped = [];
|
|
675
|
+
const errors = [];
|
|
676
|
+
for (const agent of agentList) {
|
|
677
|
+
try {
|
|
678
|
+
const srcPath = join4(typeDir, agent + ".md");
|
|
679
|
+
if (!fs3.existsSync(srcPath)) {
|
|
680
|
+
skipped.push(agent);
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
const destPath = join4(destTypeDir, agent + ".md");
|
|
684
|
+
if (mergeMode && fs3.existsSync(destPath)) {
|
|
685
|
+
skipped.push(agent);
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
const mdContent = fs3.readFileSync(srcPath, "utf-8");
|
|
689
|
+
const convertedContent = convertAgentToGemini(mdContent);
|
|
690
|
+
await fs3.writeFile(destPath, convertedContent, "utf-8");
|
|
691
|
+
copied.push(agent);
|
|
692
|
+
} catch (err) {
|
|
693
|
+
errors.push({ item: agent, error: err.message });
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return { copied, skipped, errors };
|
|
743
697
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
698
|
+
async copySkills(items, sourceDir, targetDir, mergeMode) {
|
|
699
|
+
const typeDir = join4(sourceDir, "skills");
|
|
700
|
+
const destTypeDir = join4(targetDir, "skills");
|
|
701
|
+
if (!fs3.existsSync(typeDir)) {
|
|
702
|
+
return { copied: [], skipped: [], errors: [] };
|
|
703
|
+
}
|
|
704
|
+
await fs3.ensureDir(destTypeDir);
|
|
705
|
+
let skillList;
|
|
706
|
+
if (items === "all") {
|
|
707
|
+
const entries = fs3.readdirSync(typeDir);
|
|
708
|
+
skillList = entries.filter((e) => {
|
|
709
|
+
const fullPath = join4(typeDir, e);
|
|
710
|
+
return fs3.statSync(fullPath).isDirectory() && fs3.existsSync(join4(fullPath, "SKILL.md"));
|
|
711
|
+
});
|
|
712
|
+
} else {
|
|
713
|
+
skillList = items;
|
|
714
|
+
}
|
|
715
|
+
const copied = [];
|
|
716
|
+
const skipped = [];
|
|
717
|
+
const errors = [];
|
|
718
|
+
for (const skill of skillList) {
|
|
719
|
+
try {
|
|
720
|
+
const srcPath = join4(typeDir, skill);
|
|
721
|
+
if (!fs3.existsSync(srcPath) || !fs3.statSync(srcPath).isDirectory()) {
|
|
722
|
+
skipped.push(skill);
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
if (!fs3.existsSync(join4(srcPath, "SKILL.md"))) {
|
|
726
|
+
skipped.push(skill);
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
const destPath = join4(destTypeDir, skill);
|
|
730
|
+
if (mergeMode && fs3.existsSync(destPath)) {
|
|
731
|
+
skipped.push(skill);
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
734
|
+
await fs3.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
735
|
+
copied.push(skill);
|
|
736
|
+
} catch (err) {
|
|
737
|
+
errors.push({ item: skill, error: err.message });
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
return { copied, skipped, errors };
|
|
773
741
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
742
|
+
async copyCommands(items, sourceDir, targetDir, mergeMode) {
|
|
743
|
+
const typeDir = join4(sourceDir, "commands");
|
|
744
|
+
const destTypeDir = join4(targetDir, "commands");
|
|
745
|
+
if (!fs3.existsSync(typeDir)) {
|
|
746
|
+
return { copied: [], skipped: [], errors: [] };
|
|
747
|
+
}
|
|
748
|
+
await fs3.ensureDir(destTypeDir);
|
|
749
|
+
let itemList;
|
|
750
|
+
if (items === "all") {
|
|
751
|
+
const entries = fs3.readdirSync(typeDir);
|
|
752
|
+
itemList = [...new Set(entries.map((e) => e.replace(".md", "")))];
|
|
753
|
+
} else {
|
|
754
|
+
itemList = items;
|
|
755
|
+
}
|
|
756
|
+
const copied = [];
|
|
757
|
+
const skipped = [];
|
|
758
|
+
const errors = [];
|
|
759
|
+
for (const item of itemList) {
|
|
760
|
+
try {
|
|
761
|
+
const srcPathMd = join4(typeDir, item + ".md");
|
|
762
|
+
const srcPathDir = join4(typeDir, item);
|
|
763
|
+
let copiedSomething = false;
|
|
764
|
+
if (fs3.existsSync(srcPathMd) && fs3.statSync(srcPathMd).isFile()) {
|
|
765
|
+
const destPath = join4(destTypeDir, item + ".toml");
|
|
766
|
+
if (!(mergeMode && fs3.existsSync(destPath))) {
|
|
767
|
+
await fs3.ensureDir(dirname3(destPath));
|
|
768
|
+
const mdContent = fs3.readFileSync(srcPathMd, "utf-8");
|
|
769
|
+
const tomlContent = convertCommandToToml(mdContent);
|
|
770
|
+
await fs3.writeFile(destPath, tomlContent, "utf-8");
|
|
771
|
+
copiedSomething = true;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
if (fs3.existsSync(srcPathDir) && fs3.statSync(srcPathDir).isDirectory()) {
|
|
775
|
+
await this.convertDirectoryToToml(srcPathDir, join4(destTypeDir, item), mergeMode);
|
|
776
|
+
copiedSomething = true;
|
|
777
|
+
}
|
|
778
|
+
if (copiedSomething) {
|
|
779
|
+
copied.push(item);
|
|
780
|
+
} else {
|
|
781
|
+
skipped.push(item);
|
|
782
|
+
}
|
|
783
|
+
} catch (err) {
|
|
784
|
+
errors.push({ item, error: err.message });
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return { copied, skipped, errors };
|
|
788
|
+
}
|
|
789
|
+
async convertDirectoryToToml(srcDir, destDir, mergeMode) {
|
|
790
|
+
await fs3.ensureDir(destDir);
|
|
791
|
+
const entries = fs3.readdirSync(srcDir);
|
|
792
|
+
for (const entry of entries) {
|
|
793
|
+
const srcPath = join4(srcDir, entry);
|
|
794
|
+
const stat = fs3.statSync(srcPath);
|
|
795
|
+
if (stat.isDirectory()) {
|
|
796
|
+
await this.convertDirectoryToToml(srcPath, join4(destDir, entry), mergeMode);
|
|
797
|
+
} else if (entry.endsWith(".md")) {
|
|
798
|
+
const destPath = join4(destDir, entry.replace(".md", ".toml"));
|
|
799
|
+
if (mergeMode && fs3.existsSync(destPath)) {
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
const mdContent = fs3.readFileSync(srcPath, "utf-8");
|
|
803
|
+
const tomlContent = convertCommandToToml(mdContent);
|
|
804
|
+
await fs3.writeFile(destPath, tomlContent, "utf-8");
|
|
805
|
+
} else {
|
|
806
|
+
const destPath = join4(destDir, entry);
|
|
807
|
+
if (mergeMode && fs3.existsSync(destPath)) {
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
await fs3.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
811
|
+
}
|
|
812
|
+
}
|
|
786
813
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
cmdEntries.forEach(([name, cmd], index) => {
|
|
801
|
-
const safeName = name.replace(/\//g, ":");
|
|
802
|
-
const isLast = index === cmdEntries.length - 1;
|
|
803
|
-
lines.push(` "${safeName}": {`);
|
|
804
|
-
lines.push(` "description": ${JSON.stringify(cmd.description)},`);
|
|
805
|
-
lines.push(` "prompt": ${JSON.stringify(cmd.prompt)}`);
|
|
806
|
-
lines.push(` }${isLast ? "" : ","}`);
|
|
807
|
-
});
|
|
808
|
-
lines.push(" }");
|
|
809
|
-
lines.push("}");
|
|
810
|
-
return lines.join("\n");
|
|
811
|
-
}
|
|
812
|
-
async function copySkillsForDiscord(items, sourceDir, destDir, mergeMode = false) {
|
|
813
|
-
return copySkillsForGemini(items, sourceDir, destDir, mergeMode);
|
|
814
|
-
}
|
|
815
|
-
async function copyDiscordBaseFiles(destDir, mergeMode = false) {
|
|
816
|
-
const discordTemplates = join2(CLI_ROOT, "templates", "discord");
|
|
817
|
-
const copied = [];
|
|
818
|
-
const filesToCopy = ["config.json5", "README.md"];
|
|
819
|
-
for (const file of filesToCopy) {
|
|
820
|
-
const srcPath = join2(discordTemplates, file);
|
|
821
|
-
const destPath = join2(destDir, file);
|
|
822
|
-
if (fs.existsSync(srcPath)) {
|
|
823
|
-
if (mergeMode && fs.existsSync(destPath)) {
|
|
824
|
-
continue;
|
|
814
|
+
async copyBaseFiles(targetDir, mergeMode) {
|
|
815
|
+
const { CLI_ROOT: CLI_ROOT2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
816
|
+
const geminiTemplates = join4(CLI_ROOT2, "templates", "gemini");
|
|
817
|
+
const copied = [];
|
|
818
|
+
const settingsPath = join4(geminiTemplates, "settings.json");
|
|
819
|
+
const destSettingsPath = join4(targetDir, "settings.json");
|
|
820
|
+
if (fs3.existsSync(settingsPath)) {
|
|
821
|
+
if (!(mergeMode && fs3.existsSync(destSettingsPath))) {
|
|
822
|
+
await fs3.copy(settingsPath, destSettingsPath, { overwrite: !mergeMode });
|
|
823
|
+
copied.push("settings.json");
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return copied;
|
|
825
827
|
}
|
|
826
|
-
|
|
827
|
-
copied.push(file);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
return copied;
|
|
831
|
-
}
|
|
832
|
-
async function updateDiscordConfig(destDir, token, guildId) {
|
|
833
|
-
const configPath = join2(destDir, "config.json5");
|
|
834
|
-
if (!fs.existsSync(configPath)) {
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
let content = await fs.readFile(configPath, "utf-8");
|
|
838
|
-
content = content.replace(
|
|
839
|
-
'"token": "${DISCORD_BOT_TOKEN}"',
|
|
840
|
-
`"token": "${token}"`
|
|
841
|
-
);
|
|
842
|
-
if (guildId) {
|
|
843
|
-
const guildConfig = `"${guildId}": {
|
|
844
|
-
"requireMention": true,
|
|
845
|
-
"users": [],
|
|
846
|
-
"roles": [],
|
|
847
|
-
"channels": {}
|
|
848
|
-
}`;
|
|
849
|
-
content = content.replace(
|
|
850
|
-
'"guilds": {\n // Example guild configuration',
|
|
851
|
-
`"guilds": {
|
|
852
|
-
${guildConfig},
|
|
853
|
-
// Example guild configuration`
|
|
854
|
-
);
|
|
828
|
+
};
|
|
855
829
|
}
|
|
856
|
-
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
// src/targets/discord-adapter.ts
|
|
833
|
+
import fs4 from "fs-extra";
|
|
834
|
+
import { join as join5, dirname as dirname4 } from "path";
|
|
835
|
+
function parseFrontmatter2(content) {
|
|
836
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
837
|
+
if (!match) {
|
|
838
|
+
return { frontmatter: "", body: content, description: "", argumentHint: "" };
|
|
839
|
+
}
|
|
840
|
+
const frontmatter = match[1];
|
|
841
|
+
const body = match[2].trim();
|
|
842
|
+
const descMatch = frontmatter.match(/description:\s*(.+)/);
|
|
843
|
+
const argMatch = frontmatter.match(/argument-hint:\s*(.+)/);
|
|
844
|
+
return {
|
|
845
|
+
frontmatter,
|
|
846
|
+
body,
|
|
847
|
+
description: descMatch ? descMatch[1].trim() : "",
|
|
848
|
+
argumentHint: argMatch ? argMatch[1].trim() : ""
|
|
849
|
+
};
|
|
857
850
|
}
|
|
858
|
-
|
|
859
|
-
const {
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
851
|
+
function convertAgentToDiscord(mdContent) {
|
|
852
|
+
const { frontmatter, body } = parseFrontmatter2(mdContent);
|
|
853
|
+
if (!frontmatter) return mdContent;
|
|
854
|
+
let converted = frontmatter;
|
|
855
|
+
for (const [claudeModel, discordModel] of Object.entries(MODEL_MAP2)) {
|
|
856
|
+
const regex = new RegExp(`^model:\\s*${claudeModel}\\s*$`, "m");
|
|
857
|
+
if (discordModel) {
|
|
858
|
+
converted = converted.replace(regex, `model: ${discordModel}`);
|
|
859
|
+
} else {
|
|
860
|
+
converted = converted.replace(regex, "");
|
|
861
|
+
}
|
|
864
862
|
}
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
execSync3("openclaw config set gateway.mode local", { stdio: "ignore" });
|
|
869
|
-
return { success: true, message: "OpenClaw configured successfully!" };
|
|
870
|
-
} catch (error) {
|
|
871
|
-
return { success: false, message: `Failed to configure OpenClaw: ${error.message}` };
|
|
863
|
+
converted = converted.replace(/^tools:\s*.+$/m, "");
|
|
864
|
+
if (!converted.includes("kind:")) {
|
|
865
|
+
converted = converted.trim() + "\nkind: local";
|
|
872
866
|
}
|
|
867
|
+
return `---
|
|
868
|
+
${converted.trim()}
|
|
869
|
+
---
|
|
870
|
+
${body}`;
|
|
873
871
|
}
|
|
874
872
|
function extractKeywords(content, commandName) {
|
|
875
873
|
const keywords = /* @__PURE__ */ new Set();
|
|
876
874
|
keywords.add(commandName);
|
|
877
875
|
keywords.add(commandName.replace(/-/g, " "));
|
|
878
|
-
const keywordPatterns = [
|
|
879
|
-
/keywords?:\s*([^\n]+)/gi,
|
|
880
|
-
/when.*(?:says?|mentions?|asks?).*["']([^"']+)["']/gi,
|
|
881
|
-
/trigger.*["']([^"']+)["']/gi
|
|
882
|
-
];
|
|
883
|
-
for (const pattern of keywordPatterns) {
|
|
884
|
-
const matches = content.matchAll(pattern);
|
|
885
|
-
for (const match of matches) {
|
|
886
|
-
match[1].split(/[,;]/).forEach((k) => keywords.add(k.trim().toLowerCase()));
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
876
|
const intentMap = {
|
|
890
877
|
"plan": ["plan", "design", "architect", "implement", "create plan"],
|
|
891
|
-
"brainstorm": ["brainstorm", "ideas", "options", "alternatives"
|
|
878
|
+
"brainstorm": ["brainstorm", "ideas", "options", "alternatives"],
|
|
892
879
|
"fix": ["fix", "debug", "error", "broken", "issue", "bug"],
|
|
893
880
|
"code": ["code", "implement", "build", "develop", "write code"],
|
|
894
881
|
"review": ["review", "check", "audit", "look at"],
|
|
895
882
|
"test": ["test", "testing", "spec", "unit test"],
|
|
896
|
-
"cook": ["cook", "implement", "build feature", "develop"],
|
|
897
883
|
"scout": ["scout", "search", "find", "explore codebase"],
|
|
898
884
|
"debug": ["debug", "trace", "diagnose", "investigate"]
|
|
899
885
|
};
|
|
@@ -904,10 +890,10 @@ function extractKeywords(content, commandName) {
|
|
|
904
890
|
return Array.from(keywords).slice(0, 10);
|
|
905
891
|
}
|
|
906
892
|
function convertCommandToSkill(mdContent, commandName) {
|
|
907
|
-
const { description, argumentHint, body } =
|
|
893
|
+
const { description, argumentHint, body } = parseFrontmatter2(mdContent);
|
|
908
894
|
const prompt = body.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
909
895
|
const keywords = extractKeywords(body, commandName);
|
|
910
|
-
|
|
896
|
+
return `---
|
|
911
897
|
name: ${commandName.replace(/\//g, "-")}
|
|
912
898
|
description: ${description || `Execute ${commandName} task`}
|
|
913
899
|
user-invocable: true
|
|
@@ -933,131 +919,394 @@ ${prompt}
|
|
|
933
919
|
|
|
934
920
|
Provide clear, actionable response based on the workflow above.
|
|
935
921
|
`;
|
|
936
|
-
return skillContent;
|
|
937
922
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
923
|
+
var MODEL_MAP2, DiscordAdapter;
|
|
924
|
+
var init_discord_adapter = __esm({
|
|
925
|
+
"src/targets/discord-adapter.ts"() {
|
|
926
|
+
"use strict";
|
|
927
|
+
init_base_adapter();
|
|
928
|
+
MODEL_MAP2 = {
|
|
929
|
+
"opus": "claude-3-opus",
|
|
930
|
+
"sonnet": "claude-3-sonnet",
|
|
931
|
+
"haiku": "claude-3-haiku",
|
|
932
|
+
"inherit": ""
|
|
933
|
+
};
|
|
934
|
+
DiscordAdapter = class extends BaseTargetAdapter {
|
|
935
|
+
config = {
|
|
936
|
+
name: "discord",
|
|
937
|
+
displayName: "Discord + OpenClaw",
|
|
938
|
+
directory: ".discord",
|
|
939
|
+
features: {
|
|
940
|
+
agents: true,
|
|
941
|
+
skills: true,
|
|
942
|
+
commands: true,
|
|
943
|
+
workflows: false,
|
|
944
|
+
router: false,
|
|
945
|
+
hooks: false,
|
|
946
|
+
memory: false,
|
|
947
|
+
scripts: false,
|
|
948
|
+
"output-styles": false
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
async copyAgents(items, sourceDir, targetDir, mergeMode) {
|
|
952
|
+
const typeDir = join5(sourceDir, "agents");
|
|
953
|
+
const destTypeDir = join5(targetDir, "agents");
|
|
954
|
+
if (!fs4.existsSync(typeDir)) {
|
|
955
|
+
return { copied: [], skipped: [], errors: [] };
|
|
956
|
+
}
|
|
957
|
+
await fs4.ensureDir(destTypeDir);
|
|
958
|
+
let agentList;
|
|
959
|
+
if (items === "all") {
|
|
960
|
+
const entries = fs4.readdirSync(typeDir);
|
|
961
|
+
agentList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(".md", ""));
|
|
962
|
+
} else {
|
|
963
|
+
agentList = items;
|
|
964
|
+
}
|
|
965
|
+
const copied = [];
|
|
966
|
+
const skipped = [];
|
|
967
|
+
const errors = [];
|
|
968
|
+
for (const agent of agentList) {
|
|
969
|
+
try {
|
|
970
|
+
const srcPath = join5(typeDir, agent + ".md");
|
|
971
|
+
if (!fs4.existsSync(srcPath)) {
|
|
972
|
+
skipped.push(agent);
|
|
973
|
+
continue;
|
|
974
|
+
}
|
|
975
|
+
const destPath = join5(destTypeDir, agent + ".md");
|
|
976
|
+
if (mergeMode && fs4.existsSync(destPath)) {
|
|
977
|
+
skipped.push(agent);
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
const mdContent = fs4.readFileSync(srcPath, "utf-8");
|
|
981
|
+
const convertedContent = convertAgentToDiscord(mdContent);
|
|
982
|
+
await fs4.writeFile(destPath, convertedContent, "utf-8");
|
|
983
|
+
copied.push(agent);
|
|
984
|
+
} catch (err) {
|
|
985
|
+
errors.push({ item: agent, error: err.message });
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
return { copied, skipped, errors };
|
|
980
989
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
990
|
+
async copySkills(items, sourceDir, targetDir, mergeMode) {
|
|
991
|
+
const typeDir = join5(sourceDir, "skills");
|
|
992
|
+
const destTypeDir = join5(targetDir, "skills");
|
|
993
|
+
if (!fs4.existsSync(typeDir)) {
|
|
994
|
+
return { copied: [], skipped: [], errors: [] };
|
|
995
|
+
}
|
|
996
|
+
await fs4.ensureDir(destTypeDir);
|
|
997
|
+
let skillList;
|
|
998
|
+
if (items === "all") {
|
|
999
|
+
const entries = fs4.readdirSync(typeDir);
|
|
1000
|
+
skillList = entries.filter((e) => {
|
|
1001
|
+
const fullPath = join5(typeDir, e);
|
|
1002
|
+
return fs4.statSync(fullPath).isDirectory() && fs4.existsSync(join5(fullPath, "SKILL.md"));
|
|
1003
|
+
});
|
|
1004
|
+
} else {
|
|
1005
|
+
skillList = items;
|
|
1006
|
+
}
|
|
1007
|
+
const copied = [];
|
|
1008
|
+
const skipped = [];
|
|
1009
|
+
const errors = [];
|
|
1010
|
+
for (const skill of skillList) {
|
|
1011
|
+
try {
|
|
1012
|
+
const srcPath = join5(typeDir, skill);
|
|
1013
|
+
if (!fs4.existsSync(srcPath) || !fs4.statSync(srcPath).isDirectory()) {
|
|
1014
|
+
skipped.push(skill);
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if (!fs4.existsSync(join5(srcPath, "SKILL.md"))) {
|
|
1018
|
+
skipped.push(skill);
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
const destPath = join5(destTypeDir, skill);
|
|
1022
|
+
if (mergeMode && fs4.existsSync(destPath)) {
|
|
1023
|
+
skipped.push(skill);
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
await fs4.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1027
|
+
copied.push(skill);
|
|
1028
|
+
} catch (err) {
|
|
1029
|
+
errors.push({ item: skill, error: err.message });
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const bundledCopied = await this.copyBundledSkills(targetDir, mergeMode);
|
|
1033
|
+
copied.push(...bundledCopied);
|
|
1034
|
+
return { copied, skipped, errors };
|
|
1035
|
+
}
|
|
1036
|
+
async copyCommands(items, sourceDir, targetDir, mergeMode) {
|
|
1037
|
+
const typeDir = join5(sourceDir, "commands");
|
|
1038
|
+
const destTypeDir = join5(targetDir, "commands");
|
|
1039
|
+
const destSkillsDir = join5(targetDir, "skills");
|
|
1040
|
+
if (!fs4.existsSync(typeDir)) {
|
|
1041
|
+
return { copied: [], skipped: [], errors: [] };
|
|
1042
|
+
}
|
|
1043
|
+
await fs4.ensureDir(destTypeDir);
|
|
1044
|
+
await fs4.ensureDir(destSkillsDir);
|
|
1045
|
+
let itemList;
|
|
1046
|
+
if (items === "all") {
|
|
1047
|
+
const entries = fs4.readdirSync(typeDir);
|
|
1048
|
+
itemList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(".md", ""));
|
|
1049
|
+
const dirs = entries.filter((e) => {
|
|
1050
|
+
const fullPath = join5(typeDir, e);
|
|
1051
|
+
return fs4.statSync(fullPath).isDirectory();
|
|
1052
|
+
});
|
|
1053
|
+
itemList = [.../* @__PURE__ */ new Set([...itemList, ...dirs])];
|
|
1054
|
+
} else {
|
|
1055
|
+
itemList = items;
|
|
1056
|
+
}
|
|
1057
|
+
const copied = [];
|
|
1058
|
+
const skipped = [];
|
|
1059
|
+
const errors = [];
|
|
1060
|
+
const commandsConfig = {};
|
|
1061
|
+
for (const item of itemList) {
|
|
1062
|
+
try {
|
|
1063
|
+
const srcPathMd = join5(typeDir, item + ".md");
|
|
1064
|
+
const srcPathDir = join5(typeDir, item);
|
|
1065
|
+
if (fs4.existsSync(srcPathMd) && fs4.statSync(srcPathMd).isFile()) {
|
|
1066
|
+
const destPath = join5(destTypeDir, item + ".md");
|
|
1067
|
+
const skillDir = join5(destSkillsDir, item.replace(/\//g, "-"));
|
|
1068
|
+
const skillPath = join5(skillDir, "SKILL.md");
|
|
1069
|
+
if (!(mergeMode && fs4.existsSync(destPath))) {
|
|
1070
|
+
await fs4.ensureDir(dirname4(destPath));
|
|
1071
|
+
const mdContent = fs4.readFileSync(srcPathMd, "utf-8");
|
|
1072
|
+
await fs4.copy(srcPathMd, destPath, { overwrite: !mergeMode });
|
|
1073
|
+
if (!(mergeMode && fs4.existsSync(skillPath))) {
|
|
1074
|
+
await fs4.ensureDir(skillDir);
|
|
1075
|
+
const skillContent = convertCommandToSkill(mdContent, item);
|
|
1076
|
+
await fs4.writeFile(skillPath, skillContent, "utf-8");
|
|
1077
|
+
}
|
|
1078
|
+
const { description, body } = parseFrontmatter2(mdContent);
|
|
1079
|
+
commandsConfig[item] = {
|
|
1080
|
+
description: description || `Execute ${item} command`,
|
|
1081
|
+
prompt: body.replace(/\$ARGUMENTS/g, "{{args}}")
|
|
1082
|
+
};
|
|
1083
|
+
copied.push(item);
|
|
1084
|
+
} else {
|
|
1085
|
+
skipped.push(item);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
if (fs4.existsSync(srcPathDir) && fs4.statSync(srcPathDir).isDirectory()) {
|
|
1089
|
+
await this.copyNestedCommands(srcPathDir, destTypeDir, destSkillsDir, item, mergeMode, commandsConfig);
|
|
1090
|
+
copied.push(item + "/*");
|
|
1091
|
+
}
|
|
1092
|
+
} catch (err) {
|
|
1093
|
+
errors.push({ item, error: err.message });
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
const configPath = join5(targetDir, "commands.json5");
|
|
1097
|
+
if (Object.keys(commandsConfig).length > 0 && !(mergeMode && fs4.existsSync(configPath))) {
|
|
1098
|
+
const json5Content = this.generateCommandsJson5(commandsConfig);
|
|
1099
|
+
await fs4.writeFile(configPath, json5Content, "utf-8");
|
|
1100
|
+
}
|
|
1101
|
+
return { copied, skipped, errors };
|
|
1102
|
+
}
|
|
1103
|
+
async copyNestedCommands(srcDir, destDir, destSkillsDir, parentName, mergeMode, commandsConfig) {
|
|
1104
|
+
const destTypeDir = join5(destDir, parentName);
|
|
1105
|
+
await fs4.ensureDir(destTypeDir);
|
|
1106
|
+
const entries = fs4.readdirSync(srcDir);
|
|
1107
|
+
for (const entry of entries) {
|
|
1108
|
+
const srcPath = join5(srcDir, entry);
|
|
1109
|
+
const stat = fs4.statSync(srcPath);
|
|
1110
|
+
if (stat.isDirectory()) {
|
|
1111
|
+
await this.copyNestedCommands(
|
|
1112
|
+
srcPath,
|
|
1113
|
+
destTypeDir,
|
|
1114
|
+
destSkillsDir,
|
|
1115
|
+
entry,
|
|
1116
|
+
mergeMode,
|
|
1117
|
+
commandsConfig
|
|
1118
|
+
);
|
|
1119
|
+
} else if (entry.endsWith(".md") && entry !== "README.md") {
|
|
1120
|
+
const destPath = join5(destTypeDir, entry);
|
|
1121
|
+
const cmdName = `${parentName}/${entry.replace(".md", "")}`;
|
|
1122
|
+
const skillName = cmdName.replace(/\//g, "-");
|
|
1123
|
+
const skillDir = join5(destSkillsDir, skillName);
|
|
1124
|
+
const skillPath = join5(skillDir, "SKILL.md");
|
|
1125
|
+
if (mergeMode && fs4.existsSync(destPath)) {
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
const mdContent = fs4.readFileSync(srcPath, "utf-8");
|
|
1129
|
+
await fs4.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1130
|
+
if (!(mergeMode && fs4.existsSync(skillPath))) {
|
|
1131
|
+
await fs4.ensureDir(skillDir);
|
|
1132
|
+
const skillContent = convertCommandToSkill(mdContent, skillName);
|
|
1133
|
+
await fs4.writeFile(skillPath, skillContent, "utf-8");
|
|
1134
|
+
}
|
|
1135
|
+
const { description, body } = parseFrontmatter2(mdContent);
|
|
1136
|
+
commandsConfig[cmdName] = {
|
|
1137
|
+
description: description || `Execute ${cmdName} command`,
|
|
1138
|
+
prompt: body.replace(/\$ARGUMENTS/g, "{{args}}")
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1005
1142
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1143
|
+
generateCommandsJson5(commands) {
|
|
1144
|
+
const lines = [
|
|
1145
|
+
"// Clawbot Commands Configuration",
|
|
1146
|
+
"// Generated by Apero Kit CLI",
|
|
1147
|
+
"{",
|
|
1148
|
+
' "commands": {'
|
|
1149
|
+
];
|
|
1150
|
+
const cmdEntries = Object.entries(commands);
|
|
1151
|
+
cmdEntries.forEach(([name, cmd], index) => {
|
|
1152
|
+
const safeName = name.replace(/\//g, ":");
|
|
1153
|
+
const isLast = index === cmdEntries.length - 1;
|
|
1154
|
+
lines.push(` "${safeName}": {`);
|
|
1155
|
+
lines.push(` "description": ${JSON.stringify(cmd.description)},`);
|
|
1156
|
+
lines.push(` "prompt": ${JSON.stringify(cmd.prompt)}`);
|
|
1157
|
+
lines.push(` }${isLast ? "" : ","}`);
|
|
1158
|
+
});
|
|
1159
|
+
lines.push(" }");
|
|
1160
|
+
lines.push("}");
|
|
1161
|
+
return lines.join("\n");
|
|
1162
|
+
}
|
|
1163
|
+
async copyBundledSkills(targetDir, mergeMode) {
|
|
1164
|
+
const { CLI_ROOT: CLI_ROOT2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
1165
|
+
const bundledSkillsDir = join5(CLI_ROOT2, "templates", "discord", "skills");
|
|
1166
|
+
const destSkillsDir = join5(targetDir, "skills");
|
|
1167
|
+
const copied = [];
|
|
1168
|
+
if (!fs4.existsSync(bundledSkillsDir)) {
|
|
1169
|
+
return copied;
|
|
1170
|
+
}
|
|
1171
|
+
await fs4.ensureDir(destSkillsDir);
|
|
1172
|
+
const skills = fs4.readdirSync(bundledSkillsDir);
|
|
1173
|
+
for (const skill of skills) {
|
|
1174
|
+
const srcPath = join5(bundledSkillsDir, skill);
|
|
1175
|
+
const destPath = join5(destSkillsDir, skill);
|
|
1176
|
+
if (fs4.statSync(srcPath).isDirectory()) {
|
|
1177
|
+
if (mergeMode && fs4.existsSync(destPath)) {
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
await fs4.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1181
|
+
copied.push(`bundled:${skill}`);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
return copied;
|
|
1185
|
+
}
|
|
1186
|
+
async copyBaseFiles(targetDir, mergeMode) {
|
|
1187
|
+
const { CLI_ROOT: CLI_ROOT2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
1188
|
+
const discordTemplates = join5(CLI_ROOT2, "templates", "discord");
|
|
1189
|
+
const copied = [];
|
|
1190
|
+
const filesToCopy = ["config.json5", "README.md"];
|
|
1191
|
+
for (const file of filesToCopy) {
|
|
1192
|
+
const srcPath = join5(discordTemplates, file);
|
|
1193
|
+
const destPath = join5(targetDir, file);
|
|
1194
|
+
if (fs4.existsSync(srcPath)) {
|
|
1195
|
+
if (mergeMode && fs4.existsSync(destPath)) {
|
|
1196
|
+
continue;
|
|
1197
|
+
}
|
|
1198
|
+
await fs4.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1199
|
+
copied.push(file);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
return copied;
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Update Discord config with bot token
|
|
1206
|
+
*/
|
|
1207
|
+
async updateConfig(targetDir, token, guildId) {
|
|
1208
|
+
const configPath = join5(targetDir, "config.json5");
|
|
1209
|
+
if (!fs4.existsSync(configPath)) {
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
let content = await fs4.readFile(configPath, "utf-8");
|
|
1213
|
+
content = content.replace(
|
|
1214
|
+
'"token": "${DISCORD_BOT_TOKEN}"',
|
|
1215
|
+
`"token": "${token}"`
|
|
1216
|
+
);
|
|
1217
|
+
if (guildId) {
|
|
1218
|
+
const guildConfig = `"${guildId}": {
|
|
1219
|
+
"requireMention": true,
|
|
1220
|
+
"users": [],
|
|
1221
|
+
"roles": [],
|
|
1222
|
+
"channels": {}
|
|
1223
|
+
}`;
|
|
1224
|
+
content = content.replace(
|
|
1225
|
+
'"guilds": {\n // Example guild configuration',
|
|
1226
|
+
`"guilds": {
|
|
1227
|
+
${guildConfig},
|
|
1228
|
+
// Example guild configuration`
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
await fs4.writeFile(configPath, content, "utf-8");
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Setup OpenClaw CLI configuration
|
|
1235
|
+
*/
|
|
1236
|
+
async setupOpenClaw(token) {
|
|
1237
|
+
const { execSync: execSync3 } = await import("child_process");
|
|
1238
|
+
try {
|
|
1239
|
+
execSync3("which openclaw", { stdio: "ignore" });
|
|
1240
|
+
} catch {
|
|
1241
|
+
return { success: false, message: "OpenClaw CLI not installed. Run: npm install -g openclaw" };
|
|
1242
|
+
}
|
|
1243
|
+
try {
|
|
1244
|
+
execSync3(`openclaw config set channels.discord.token '"${token}"' --json`, { stdio: "ignore" });
|
|
1245
|
+
execSync3("openclaw config set channels.discord.enabled true --json", { stdio: "ignore" });
|
|
1246
|
+
execSync3("openclaw config set gateway.mode local", { stdio: "ignore" });
|
|
1247
|
+
return { success: true, message: "OpenClaw configured successfully!" };
|
|
1248
|
+
} catch (error) {
|
|
1249
|
+
return { success: false, message: `Failed to configure OpenClaw: ${error.message}` };
|
|
1250
|
+
}
|
|
1028
1251
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
// src/targets/index.ts
|
|
1257
|
+
function getAdapter(target) {
|
|
1258
|
+
const adapter = adapters[target];
|
|
1259
|
+
if (!adapter) {
|
|
1260
|
+
throw new Error(`Unknown target: ${target}. Available: ${Object.keys(adapters).join(", ")}`);
|
|
1032
1261
|
}
|
|
1033
|
-
return
|
|
1262
|
+
return adapter;
|
|
1034
1263
|
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1264
|
+
function isValidTarget(target) {
|
|
1265
|
+
return target in adapters;
|
|
1266
|
+
}
|
|
1267
|
+
function getTargetDirectory(target) {
|
|
1268
|
+
return adapters[target].config.directory;
|
|
1269
|
+
}
|
|
1270
|
+
function getTargetDisplayName(target) {
|
|
1271
|
+
return adapters[target].config.displayName;
|
|
1272
|
+
}
|
|
1273
|
+
var adapters;
|
|
1274
|
+
var init_targets = __esm({
|
|
1275
|
+
"src/targets/index.ts"() {
|
|
1037
1276
|
"use strict";
|
|
1038
|
-
|
|
1277
|
+
init_claude_adapter();
|
|
1278
|
+
init_gemini_adapter();
|
|
1279
|
+
init_discord_adapter();
|
|
1280
|
+
init_claude_adapter();
|
|
1281
|
+
init_gemini_adapter();
|
|
1282
|
+
init_discord_adapter();
|
|
1283
|
+
adapters = {
|
|
1284
|
+
claude: new ClaudeAdapter(),
|
|
1285
|
+
gemini: new GeminiAdapter(),
|
|
1286
|
+
discord: new DiscordAdapter()
|
|
1287
|
+
};
|
|
1039
1288
|
}
|
|
1040
1289
|
});
|
|
1041
1290
|
|
|
1042
1291
|
// src/utils/hash.ts
|
|
1043
1292
|
import { createHash } from "crypto";
|
|
1044
|
-
import
|
|
1045
|
-
import { join as
|
|
1293
|
+
import fs5 from "fs-extra";
|
|
1294
|
+
import { join as join6, relative } from "path";
|
|
1046
1295
|
function hashFile(filePath) {
|
|
1047
|
-
if (!
|
|
1296
|
+
if (!fs5.existsSync(filePath)) {
|
|
1048
1297
|
return null;
|
|
1049
1298
|
}
|
|
1050
|
-
const content =
|
|
1299
|
+
const content = fs5.readFileSync(filePath);
|
|
1051
1300
|
return createHash("md5").update(content).digest("hex");
|
|
1052
1301
|
}
|
|
1053
1302
|
async function hashDirectory(dirPath, baseDir = dirPath) {
|
|
1054
1303
|
const hashes = {};
|
|
1055
|
-
if (!
|
|
1304
|
+
if (!fs5.existsSync(dirPath)) {
|
|
1056
1305
|
return hashes;
|
|
1057
1306
|
}
|
|
1058
|
-
const items = await
|
|
1307
|
+
const items = await fs5.readdir(dirPath, { withFileTypes: true });
|
|
1059
1308
|
for (const item of items) {
|
|
1060
|
-
const itemPath =
|
|
1309
|
+
const itemPath = join6(dirPath, item.name);
|
|
1061
1310
|
const relativePath = relative(baseDir, itemPath);
|
|
1062
1311
|
if (item.isDirectory()) {
|
|
1063
1312
|
const subHashes = await hashDirectory(itemPath, baseDir);
|
|
@@ -1078,27 +1327,27 @@ var init_hash = __esm({
|
|
|
1078
1327
|
});
|
|
1079
1328
|
|
|
1080
1329
|
// src/utils/state.ts
|
|
1081
|
-
import
|
|
1082
|
-
import { join as
|
|
1330
|
+
import fs6 from "fs-extra";
|
|
1331
|
+
import { join as join7 } from "path";
|
|
1083
1332
|
function getStatePath(projectDir) {
|
|
1084
|
-
return
|
|
1333
|
+
return join7(projectDir, STATE_DIR, STATE_FILE);
|
|
1085
1334
|
}
|
|
1086
1335
|
async function loadState(projectDir) {
|
|
1087
1336
|
const statePath = getStatePath(projectDir);
|
|
1088
|
-
if (!
|
|
1337
|
+
if (!fs6.existsSync(statePath)) {
|
|
1089
1338
|
return null;
|
|
1090
1339
|
}
|
|
1091
1340
|
try {
|
|
1092
|
-
return await
|
|
1341
|
+
return await fs6.readJson(statePath);
|
|
1093
1342
|
} catch {
|
|
1094
1343
|
return null;
|
|
1095
1344
|
}
|
|
1096
1345
|
}
|
|
1097
1346
|
async function saveState(projectDir, state) {
|
|
1098
|
-
const stateDir =
|
|
1099
|
-
const statePath =
|
|
1100
|
-
await
|
|
1101
|
-
await
|
|
1347
|
+
const stateDir = join7(projectDir, STATE_DIR);
|
|
1348
|
+
const statePath = join7(stateDir, STATE_FILE);
|
|
1349
|
+
await fs6.ensureDir(stateDir);
|
|
1350
|
+
await fs6.writeJson(statePath, state, { spaces: 2 });
|
|
1102
1351
|
}
|
|
1103
1352
|
async function createInitialState(projectDir, options) {
|
|
1104
1353
|
const { kit, source, target, targets, installed } = options;
|
|
@@ -1106,8 +1355,8 @@ async function createInitialState(projectDir, options) {
|
|
|
1106
1355
|
const targetList = targets || [target.replace(".", "")];
|
|
1107
1356
|
for (const t of targetList) {
|
|
1108
1357
|
const targetDirName = t.startsWith(".") ? t : `.${t}`;
|
|
1109
|
-
const targetDir =
|
|
1110
|
-
if (
|
|
1358
|
+
const targetDir = join7(projectDir, targetDirName);
|
|
1359
|
+
if (fs6.existsSync(targetDir)) {
|
|
1111
1360
|
const hashes = await hashDirectory(targetDir);
|
|
1112
1361
|
for (const [path, hash] of Object.entries(hashes)) {
|
|
1113
1362
|
allHashes[`${targetDirName}/${path}`] = hash;
|
|
@@ -1133,7 +1382,7 @@ async function updateState(projectDir, updates) {
|
|
|
1133
1382
|
if (!state) {
|
|
1134
1383
|
throw new Error("No state found. Is this an ak project?");
|
|
1135
1384
|
}
|
|
1136
|
-
const targetDir =
|
|
1385
|
+
const targetDir = join7(projectDir, state.target || ".claude");
|
|
1137
1386
|
const newHashes = await hashDirectory(targetDir);
|
|
1138
1387
|
const updatedState = {
|
|
1139
1388
|
...state,
|
|
@@ -1149,7 +1398,7 @@ async function getFileStatuses(projectDir) {
|
|
|
1149
1398
|
if (!state) {
|
|
1150
1399
|
return { error: "No state found" };
|
|
1151
1400
|
}
|
|
1152
|
-
const targetDir =
|
|
1401
|
+
const targetDir = join7(projectDir, state.target || ".claude");
|
|
1153
1402
|
const currentHashes = await hashDirectory(targetDir);
|
|
1154
1403
|
const originalHashes = state.originalHashes || {};
|
|
1155
1404
|
const statuses = {
|
|
@@ -1188,6 +1437,78 @@ var init_state = __esm({
|
|
|
1188
1437
|
}
|
|
1189
1438
|
});
|
|
1190
1439
|
|
|
1440
|
+
// src/utils/copy.ts
|
|
1441
|
+
import fs7 from "fs-extra";
|
|
1442
|
+
import { join as join8, dirname as dirname5 } from "path";
|
|
1443
|
+
async function copyItems(items, type, sourceDir, destDir, mergeMode = false) {
|
|
1444
|
+
const typeDir = join8(sourceDir, type);
|
|
1445
|
+
const destTypeDir = join8(destDir, type);
|
|
1446
|
+
if (!fs7.existsSync(typeDir)) {
|
|
1447
|
+
return { copied: [], skipped: items, errors: [] };
|
|
1448
|
+
}
|
|
1449
|
+
await fs7.ensureDir(destTypeDir);
|
|
1450
|
+
const copied = [];
|
|
1451
|
+
const skipped = [];
|
|
1452
|
+
const errors = [];
|
|
1453
|
+
for (const item of items) {
|
|
1454
|
+
try {
|
|
1455
|
+
const itemPath = join8(typeDir, item);
|
|
1456
|
+
const itemPathMd = itemPath + ".md";
|
|
1457
|
+
let srcPath;
|
|
1458
|
+
if (fs7.existsSync(itemPath)) {
|
|
1459
|
+
srcPath = itemPath;
|
|
1460
|
+
} else if (fs7.existsSync(itemPathMd)) {
|
|
1461
|
+
srcPath = itemPathMd;
|
|
1462
|
+
} else {
|
|
1463
|
+
skipped.push(item);
|
|
1464
|
+
continue;
|
|
1465
|
+
}
|
|
1466
|
+
const stat = fs7.statSync(srcPath);
|
|
1467
|
+
if (stat.isDirectory()) {
|
|
1468
|
+
await fs7.copy(srcPath, join8(destTypeDir, item), { overwrite: !mergeMode });
|
|
1469
|
+
} else {
|
|
1470
|
+
const destPath = srcPath.endsWith(".md") ? join8(destTypeDir, item + ".md") : join8(destTypeDir, item);
|
|
1471
|
+
await fs7.ensureDir(join8(destTypeDir, item.split("/").slice(0, -1).join("/")));
|
|
1472
|
+
await fs7.copy(srcPath, destPath, { overwrite: !mergeMode });
|
|
1473
|
+
}
|
|
1474
|
+
copied.push(item);
|
|
1475
|
+
} catch (err) {
|
|
1476
|
+
errors.push({ item, error: err.message });
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
return { copied, skipped, errors };
|
|
1480
|
+
}
|
|
1481
|
+
async function copyAgentsMd(agentsMdPath, projectDir, mergeMode = false) {
|
|
1482
|
+
if (!agentsMdPath || !fs7.existsSync(agentsMdPath)) {
|
|
1483
|
+
return false;
|
|
1484
|
+
}
|
|
1485
|
+
const destPath = join8(projectDir, "AGENTS.md");
|
|
1486
|
+
if (mergeMode && fs7.existsSync(destPath)) {
|
|
1487
|
+
return false;
|
|
1488
|
+
}
|
|
1489
|
+
await fs7.copy(agentsMdPath, destPath, { overwrite: !mergeMode });
|
|
1490
|
+
return true;
|
|
1491
|
+
}
|
|
1492
|
+
function listAvailable(type, sourceDir) {
|
|
1493
|
+
const typeDir = join8(sourceDir, type);
|
|
1494
|
+
if (!fs7.existsSync(typeDir)) {
|
|
1495
|
+
return [];
|
|
1496
|
+
}
|
|
1497
|
+
const items = fs7.readdirSync(typeDir);
|
|
1498
|
+
return items.map((item) => {
|
|
1499
|
+
const itemPath = join8(typeDir, item);
|
|
1500
|
+
const isDir = fs7.statSync(itemPath).isDirectory();
|
|
1501
|
+
const name = item.replace(/\.md$/, "");
|
|
1502
|
+
return { name, isDir, path: itemPath };
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
var init_copy = __esm({
|
|
1506
|
+
"src/utils/copy.ts"() {
|
|
1507
|
+
"use strict";
|
|
1508
|
+
init_paths();
|
|
1509
|
+
}
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1191
1512
|
// src/utils/prompts.ts
|
|
1192
1513
|
import * as p from "@clack/prompts";
|
|
1193
1514
|
import pc from "picocolors";
|
|
@@ -1315,6 +1636,62 @@ function isOpenClawInstalled() {
|
|
|
1315
1636
|
return false;
|
|
1316
1637
|
}
|
|
1317
1638
|
}
|
|
1639
|
+
function isGeminiCliInstalled() {
|
|
1640
|
+
try {
|
|
1641
|
+
const { execSync: execSync3 } = __require("child_process");
|
|
1642
|
+
execSync3("which gemini", { stdio: "ignore" });
|
|
1643
|
+
return true;
|
|
1644
|
+
} catch {
|
|
1645
|
+
return false;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
function isGeminiCliLoggedIn() {
|
|
1649
|
+
try {
|
|
1650
|
+
const fs15 = __require("fs");
|
|
1651
|
+
const path = __require("path");
|
|
1652
|
+
const credsPath = path.join(process.env.HOME || "", ".gemini", "oauth_creds.json");
|
|
1653
|
+
return fs15.existsSync(credsPath);
|
|
1654
|
+
} catch {
|
|
1655
|
+
return false;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
async function setupGeminiCliAuth() {
|
|
1659
|
+
const { execSync: execSync3, spawnSync } = __require("child_process");
|
|
1660
|
+
try {
|
|
1661
|
+
if (!isGeminiCliLoggedIn()) {
|
|
1662
|
+
console.log(pc.cyan("Logging in to Gemini CLI..."));
|
|
1663
|
+
spawnSync("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
1664
|
+
}
|
|
1665
|
+
console.log(pc.cyan("Enabling Gemini CLI auth plugin..."));
|
|
1666
|
+
execSync3("openclaw plugins enable google-gemini-cli-auth", { stdio: "ignore" });
|
|
1667
|
+
console.log(pc.cyan("Setting Gemini CLI as default model provider..."));
|
|
1668
|
+
execSync3("openclaw models auth login --provider google-gemini-cli --set-default", { stdio: "inherit" });
|
|
1669
|
+
console.log(pc.green("\u2713 Gemini CLI OAuth configured successfully!"));
|
|
1670
|
+
return true;
|
|
1671
|
+
} catch (error) {
|
|
1672
|
+
console.log(pc.red("\u2717 Failed to setup Gemini CLI auth"));
|
|
1673
|
+
console.log(pc.gray(" Try manually:"));
|
|
1674
|
+
console.log(pc.gray(" 1. gemini auth login"));
|
|
1675
|
+
console.log(pc.gray(" 2. openclaw plugins enable google-gemini-cli-auth"));
|
|
1676
|
+
console.log(pc.gray(" 3. openclaw models auth login --provider google-gemini-cli --set-default"));
|
|
1677
|
+
return false;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
async function installGeminiCli() {
|
|
1681
|
+
const { execSync: execSync3 } = __require("child_process");
|
|
1682
|
+
try {
|
|
1683
|
+
console.log(pc.cyan("Installing Gemini CLI..."));
|
|
1684
|
+
execSync3("npm install -g @anthropic-ai/gemini-cli", { stdio: "inherit" });
|
|
1685
|
+
console.log(pc.green("\u2713 Gemini CLI installed successfully!"));
|
|
1686
|
+
console.log("");
|
|
1687
|
+
return true;
|
|
1688
|
+
} catch (error) {
|
|
1689
|
+
console.log(pc.red("\u2717 Failed to install Gemini CLI"));
|
|
1690
|
+
console.log(pc.gray(" Try manually: npm install -g @anthropic-ai/gemini-cli"));
|
|
1691
|
+
console.log("");
|
|
1692
|
+
return false;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1318
1695
|
function isDiscordConfigured() {
|
|
1319
1696
|
try {
|
|
1320
1697
|
const { execSync: execSync3 } = __require("child_process");
|
|
@@ -1373,6 +1750,7 @@ async function promptDiscordSetup() {
|
|
|
1373
1750
|
message: "What do you want to do?",
|
|
1374
1751
|
options: [
|
|
1375
1752
|
{ value: "restart", label: "Restart gateway", hint: "Use existing config" },
|
|
1753
|
+
{ value: "gemini-cli", label: "Setup Gemini CLI OAuth", hint: "Use Gemini CLI as AI provider" },
|
|
1376
1754
|
{ value: "reconfigure", label: "Reconfigure", hint: "Enter new token" },
|
|
1377
1755
|
{ value: "skip", label: "Skip setup", hint: "Continue without changes" }
|
|
1378
1756
|
]
|
|
@@ -1387,6 +1765,30 @@ async function promptDiscordSetup() {
|
|
|
1387
1765
|
restartOnly: true
|
|
1388
1766
|
};
|
|
1389
1767
|
}
|
|
1768
|
+
if (action === "gemini-cli") {
|
|
1769
|
+
let geminiInstalled = isGeminiCliInstalled();
|
|
1770
|
+
if (!geminiInstalled) {
|
|
1771
|
+
console.log(pc.yellow("\u26A0 Gemini CLI not found."));
|
|
1772
|
+
const shouldInstall = await p.confirm({
|
|
1773
|
+
message: "Install Gemini CLI now?",
|
|
1774
|
+
initialValue: true
|
|
1775
|
+
});
|
|
1776
|
+
if (p.isCancel(shouldInstall)) process.exit(0);
|
|
1777
|
+
if (shouldInstall) {
|
|
1778
|
+
geminiInstalled = await installGeminiCli();
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
if (geminiInstalled) {
|
|
1782
|
+
await setupGeminiCliAuth();
|
|
1783
|
+
}
|
|
1784
|
+
return {
|
|
1785
|
+
token: "",
|
|
1786
|
+
autoSetup: false,
|
|
1787
|
+
openclawInstalled: true,
|
|
1788
|
+
restartOnly: true,
|
|
1789
|
+
useGeminiCli: true
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1390
1792
|
if (action === "skip") {
|
|
1391
1793
|
return {
|
|
1392
1794
|
token: "",
|
|
@@ -1396,7 +1798,37 @@ async function promptDiscordSetup() {
|
|
|
1396
1798
|
};
|
|
1397
1799
|
}
|
|
1398
1800
|
}
|
|
1399
|
-
console.log(
|
|
1801
|
+
console.log("");
|
|
1802
|
+
console.log(pc.cyan("Choose AI Model Authentication:"));
|
|
1803
|
+
const authMethod = await p.select({
|
|
1804
|
+
message: "How do you want to authenticate with AI models?",
|
|
1805
|
+
options: [
|
|
1806
|
+
{ value: "gemini-cli", label: "Gemini CLI OAuth", hint: "Recommended - uses Google OAuth via Gemini CLI" },
|
|
1807
|
+
{ value: "api-key", label: "API Key", hint: "Use your own API key" }
|
|
1808
|
+
]
|
|
1809
|
+
});
|
|
1810
|
+
if (p.isCancel(authMethod)) process.exit(0);
|
|
1811
|
+
let useGeminiCli = false;
|
|
1812
|
+
if (authMethod === "gemini-cli") {
|
|
1813
|
+
let geminiInstalled = isGeminiCliInstalled();
|
|
1814
|
+
if (!geminiInstalled) {
|
|
1815
|
+
console.log(pc.yellow("\u26A0 Gemini CLI not found."));
|
|
1816
|
+
const shouldInstall = await p.confirm({
|
|
1817
|
+
message: "Install Gemini CLI now?",
|
|
1818
|
+
initialValue: true
|
|
1819
|
+
});
|
|
1820
|
+
if (p.isCancel(shouldInstall)) process.exit(0);
|
|
1821
|
+
if (shouldInstall) {
|
|
1822
|
+
geminiInstalled = await installGeminiCli();
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
if (geminiInstalled && openclawInstalled) {
|
|
1826
|
+
const setupSuccess = await setupGeminiCliAuth();
|
|
1827
|
+
useGeminiCli = setupSuccess;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
console.log("");
|
|
1831
|
+
console.log(pc.gray("Get your Discord bot token from: https://discord.com/developers/applications"));
|
|
1400
1832
|
console.log("");
|
|
1401
1833
|
const token = await p.password({
|
|
1402
1834
|
message: "Discord Bot Token:",
|
|
@@ -1426,19 +1858,22 @@ async function promptDiscordSetup() {
|
|
|
1426
1858
|
guildId = guild;
|
|
1427
1859
|
}
|
|
1428
1860
|
let autoSetup = false;
|
|
1429
|
-
if (openclawInstalled) {
|
|
1861
|
+
if (openclawInstalled && !useGeminiCli) {
|
|
1430
1862
|
const shouldAutoSetup = await p.confirm({
|
|
1431
1863
|
message: "Auto-setup OpenClaw config?",
|
|
1432
1864
|
initialValue: true
|
|
1433
1865
|
});
|
|
1434
1866
|
if (p.isCancel(shouldAutoSetup)) process.exit(0);
|
|
1435
1867
|
autoSetup = shouldAutoSetup;
|
|
1868
|
+
} else if (useGeminiCli) {
|
|
1869
|
+
autoSetup = true;
|
|
1436
1870
|
}
|
|
1437
1871
|
return {
|
|
1438
1872
|
token,
|
|
1439
1873
|
guildId,
|
|
1440
1874
|
autoSetup,
|
|
1441
|
-
openclawInstalled
|
|
1875
|
+
openclawInstalled,
|
|
1876
|
+
useGeminiCli
|
|
1442
1877
|
};
|
|
1443
1878
|
}
|
|
1444
1879
|
var init_prompts = __esm({
|
|
@@ -1454,8 +1889,8 @@ var init_exports = {};
|
|
|
1454
1889
|
__export(init_exports, {
|
|
1455
1890
|
initCommand: () => initCommand
|
|
1456
1891
|
});
|
|
1457
|
-
import
|
|
1458
|
-
import { join as
|
|
1892
|
+
import fs8 from "fs-extra";
|
|
1893
|
+
import { join as join9, resolve as resolve2 } from "path";
|
|
1459
1894
|
import pc2 from "picocolors";
|
|
1460
1895
|
import ora from "ora";
|
|
1461
1896
|
function filterComponents(list, exclude, only) {
|
|
@@ -1511,7 +1946,7 @@ async function initCommand(projectName, options) {
|
|
|
1511
1946
|
let cliTargets;
|
|
1512
1947
|
if (options.target) {
|
|
1513
1948
|
const targetsFromFlag = options.target.split(",").map((t) => t.trim());
|
|
1514
|
-
cliTargets = targetsFromFlag.filter((t) => t
|
|
1949
|
+
cliTargets = targetsFromFlag.filter((t) => isValidTarget(t));
|
|
1515
1950
|
if (cliTargets.length === 0) {
|
|
1516
1951
|
console.log(pc2.yellow(`Unknown target "${options.target}", using "claude"`));
|
|
1517
1952
|
cliTargets = ["claude"];
|
|
@@ -1529,18 +1964,18 @@ async function initCommand(projectName, options) {
|
|
|
1529
1964
|
let existingAction = null;
|
|
1530
1965
|
const existingTargets = [];
|
|
1531
1966
|
for (const target of cliTargets) {
|
|
1532
|
-
const targetDir =
|
|
1533
|
-
if (options.fresh &&
|
|
1534
|
-
await
|
|
1535
|
-
existingTargets.push(
|
|
1536
|
-
} else if (
|
|
1537
|
-
existingTargets.push(
|
|
1967
|
+
const targetDir = join9(projectDir, getTargetDirectory(target));
|
|
1968
|
+
if (options.fresh && fs8.existsSync(targetDir)) {
|
|
1969
|
+
await fs8.remove(targetDir);
|
|
1970
|
+
existingTargets.push(getTargetDisplayName(target));
|
|
1971
|
+
} else if (fs8.existsSync(targetDir) && !options.force) {
|
|
1972
|
+
existingTargets.push(getTargetDisplayName(target));
|
|
1538
1973
|
}
|
|
1539
1974
|
}
|
|
1540
1975
|
if (options.fresh && existingTargets.length > 0) {
|
|
1541
|
-
const akDir =
|
|
1542
|
-
if (
|
|
1543
|
-
await
|
|
1976
|
+
const akDir = join9(projectDir, ".ak");
|
|
1977
|
+
if (fs8.existsSync(akDir)) {
|
|
1978
|
+
await fs8.remove(akDir);
|
|
1544
1979
|
}
|
|
1545
1980
|
console.log(pc2.cyan(`Fresh install: removed existing files (${existingTargets.join(", ")})`));
|
|
1546
1981
|
existingAction = null;
|
|
@@ -1560,8 +1995,8 @@ async function initCommand(projectName, options) {
|
|
|
1560
1995
|
}
|
|
1561
1996
|
}
|
|
1562
1997
|
}
|
|
1563
|
-
if (!isCurrentDir &&
|
|
1564
|
-
const files =
|
|
1998
|
+
if (!isCurrentDir && fs8.existsSync(projectDir) && !options.force) {
|
|
1999
|
+
const files = fs8.readdirSync(projectDir);
|
|
1565
2000
|
if (files.length > 0 && !existingAction) {
|
|
1566
2001
|
console.log(pc2.red(`Directory "${projectName}" already exists and is not empty.`));
|
|
1567
2002
|
console.log(pc2.gray("Use --force to overwrite."));
|
|
@@ -1594,8 +2029,10 @@ async function initCommand(projectName, options) {
|
|
|
1594
2029
|
toInstall.agents = await promptAgents(source.claudeDir);
|
|
1595
2030
|
toInstall.skills = await promptSkills(source.claudeDir);
|
|
1596
2031
|
toInstall.commands = await promptCommands(source.claudeDir);
|
|
1597
|
-
|
|
1598
|
-
|
|
2032
|
+
if (cliTargets.includes("claude")) {
|
|
2033
|
+
toInstall.includeRouter = await promptIncludeRouter();
|
|
2034
|
+
toInstall.includeHooks = await promptIncludeHooks();
|
|
2035
|
+
}
|
|
1599
2036
|
} else {
|
|
1600
2037
|
const kit = getKit(kitName);
|
|
1601
2038
|
if (!kit) {
|
|
@@ -1620,7 +2057,7 @@ async function initCommand(projectName, options) {
|
|
|
1620
2057
|
}
|
|
1621
2058
|
console.log(pc2.cyan("\nWill create:"));
|
|
1622
2059
|
console.log(pc2.white(` Project: ${projectName}/`));
|
|
1623
|
-
console.log(pc2.white(` Targets: ${cliTargets.map((t) =>
|
|
2060
|
+
console.log(pc2.white(` Targets: ${cliTargets.map((t) => getTargetDisplayName(t)).join(", ")}`));
|
|
1624
2061
|
console.log(pc2.white(` Kit: ${kitName}`));
|
|
1625
2062
|
if (Array.isArray(toInstall.agents)) {
|
|
1626
2063
|
console.log(pc2.gray(` Agents: ${toInstall.agents.length}`));
|
|
@@ -1640,95 +2077,50 @@ async function initCommand(projectName, options) {
|
|
|
1640
2077
|
}
|
|
1641
2078
|
const spinner = ora("Creating project...").start();
|
|
1642
2079
|
try {
|
|
1643
|
-
await
|
|
2080
|
+
await fs8.ensureDir(projectDir);
|
|
1644
2081
|
for (const target of cliTargets) {
|
|
1645
|
-
const
|
|
1646
|
-
|
|
1647
|
-
|
|
2082
|
+
const adapter = getAdapter(target);
|
|
2083
|
+
const targetDir = join9(projectDir, adapter.config.directory);
|
|
2084
|
+
await fs8.ensureDir(targetDir);
|
|
2085
|
+
const targetLabel = adapter.config.displayName;
|
|
2086
|
+
const filteredItems = adapter.filterInstallItems(toInstall);
|
|
1648
2087
|
spinner.text = mergeMode ? `Merging agents (${targetLabel})...` : `Copying agents (${targetLabel})...`;
|
|
1649
|
-
|
|
1650
|
-
await copyAgentsForGemini(toInstall.agents, source.claudeDir, targetDir, mergeMode);
|
|
1651
|
-
} else if (target === "discord") {
|
|
1652
|
-
await copyAgentsForDiscord(toInstall.agents, source.claudeDir, targetDir, mergeMode);
|
|
1653
|
-
} else {
|
|
1654
|
-
if (toInstall.agents === "all") {
|
|
1655
|
-
await copyAllOfType("agents", source.claudeDir, targetDir, mergeMode);
|
|
1656
|
-
} else if (toInstall.agents.length > 0) {
|
|
1657
|
-
await copyItems(toInstall.agents, "agents", source.claudeDir, targetDir, mergeMode);
|
|
1658
|
-
}
|
|
1659
|
-
}
|
|
2088
|
+
await adapter.copyAgents(filteredItems.agents, source.claudeDir, targetDir, mergeMode);
|
|
1660
2089
|
spinner.text = mergeMode ? `Merging skills (${targetLabel})...` : `Copying skills (${targetLabel})...`;
|
|
1661
|
-
|
|
1662
|
-
await copySkillsForGemini(toInstall.skills, source.claudeDir, targetDir, mergeMode);
|
|
1663
|
-
} else if (target === "discord") {
|
|
1664
|
-
await copySkillsForDiscord(toInstall.skills, source.claudeDir, targetDir, mergeMode);
|
|
1665
|
-
} else {
|
|
1666
|
-
if (toInstall.skills === "all") {
|
|
1667
|
-
await copyAllOfType("skills", source.claudeDir, targetDir, mergeMode);
|
|
1668
|
-
} else if (toInstall.skills.length > 0) {
|
|
1669
|
-
await copyItems(toInstall.skills, "skills", source.claudeDir, targetDir, mergeMode);
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
2090
|
+
await adapter.copySkills(filteredItems.skills, source.claudeDir, targetDir, mergeMode);
|
|
1672
2091
|
spinner.text = mergeMode ? `Merging commands (${targetLabel})...` : `Copying commands (${targetLabel})...`;
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
} else if (target === "discord") {
|
|
1676
|
-
await copyCommandsForDiscord(toInstall.commands, source.claudeDir, targetDir, mergeMode);
|
|
1677
|
-
spinner.text = mergeMode ? `Converting commands to skills (${targetLabel})...` : `Converting commands to skills (${targetLabel})...`;
|
|
1678
|
-
await convertCommandsToSkills(toInstall.commands, source.claudeDir, targetDir, mergeMode);
|
|
1679
|
-
spinner.text = `Copying bundled skills (${targetLabel})...`;
|
|
1680
|
-
await copyBundledSkillsForDiscord(targetDir, mergeMode);
|
|
1681
|
-
} else {
|
|
1682
|
-
if (toInstall.commands === "all") {
|
|
1683
|
-
await copyAllOfType("commands", source.claudeDir, targetDir, mergeMode);
|
|
1684
|
-
} else if (toInstall.commands.length > 0) {
|
|
1685
|
-
await copyItems(toInstall.commands, "commands", source.claudeDir, targetDir, mergeMode);
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
|
-
if (target === "claude") {
|
|
2092
|
+
await adapter.copyCommands(filteredItems.commands, source.claudeDir, targetDir, mergeMode);
|
|
2093
|
+
if (adapter.supports("workflows") && filteredItems.workflows.length > 0) {
|
|
1689
2094
|
spinner.text = mergeMode ? `Merging workflows (${targetLabel})...` : `Copying workflows (${targetLabel})...`;
|
|
1690
|
-
|
|
1691
|
-
await copyAllOfType("workflows", source.claudeDir, targetDir, mergeMode);
|
|
1692
|
-
} else if (toInstall.workflows && toInstall.workflows.length > 0) {
|
|
1693
|
-
await copyItems(toInstall.workflows, "workflows", source.claudeDir, targetDir, mergeMode);
|
|
1694
|
-
}
|
|
2095
|
+
await adapter.copyWorkflows(filteredItems.workflows, source.claudeDir, targetDir, mergeMode);
|
|
1695
2096
|
}
|
|
1696
|
-
if (
|
|
2097
|
+
if (adapter.supports("router") && filteredItems.includeRouter) {
|
|
1697
2098
|
spinner.text = mergeMode ? `Merging router (${targetLabel})...` : `Copying router (${targetLabel})...`;
|
|
1698
|
-
await copyRouter(source.claudeDir, targetDir, mergeMode);
|
|
2099
|
+
await adapter.copyRouter(source.claudeDir, targetDir, mergeMode);
|
|
1699
2100
|
}
|
|
1700
|
-
if (
|
|
2101
|
+
if (adapter.supports("hooks") && filteredItems.includeHooks) {
|
|
1701
2102
|
spinner.text = mergeMode ? `Merging hooks (${targetLabel})...` : `Copying hooks (${targetLabel})...`;
|
|
1702
|
-
await copyHooks(source.claudeDir, targetDir, mergeMode);
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
spinner.text = "Configuring Discord bot...";
|
|
1719
|
-
await updateDiscordConfig(targetDir, discordConfig.token, discordConfig.guildId);
|
|
1720
|
-
if (discordConfig.autoSetup) {
|
|
1721
|
-
spinner.text = "Setting up OpenClaw...";
|
|
1722
|
-
const result = await setupOpenClawConfig(discordConfig.token);
|
|
1723
|
-
openclawSetupSuccess = result.success;
|
|
1724
|
-
if (!result.success) {
|
|
1725
|
-
console.log(pc2.yellow(`
|
|
2103
|
+
await adapter.copyHooks(source.claudeDir, targetDir, mergeMode);
|
|
2104
|
+
}
|
|
2105
|
+
spinner.text = mergeMode ? `Merging extras (${targetLabel})...` : `Copying extras (${targetLabel})...`;
|
|
2106
|
+
await adapter.copyExtras(source.claudeDir, targetDir, mergeMode);
|
|
2107
|
+
spinner.text = mergeMode ? `Merging base files (${targetLabel})...` : `Copying base files (${targetLabel})...`;
|
|
2108
|
+
await adapter.copyBaseFiles(targetDir, mergeMode);
|
|
2109
|
+
if (target === "discord" && discordConfig && !discordConfig.restartOnly) {
|
|
2110
|
+
const discordAdapter = adapter;
|
|
2111
|
+
spinner.text = "Configuring Discord bot...";
|
|
2112
|
+
await discordAdapter.updateConfig(targetDir, discordConfig.token, discordConfig.guildId);
|
|
2113
|
+
if (discordConfig.autoSetup) {
|
|
2114
|
+
spinner.text = "Setting up OpenClaw...";
|
|
2115
|
+
const result = await discordAdapter.setupOpenClaw(discordConfig.token);
|
|
2116
|
+
openclawSetupSuccess = result.success;
|
|
2117
|
+
if (!result.success) {
|
|
2118
|
+
console.log(pc2.yellow(`
|
|
1726
2119
|
Note: ${result.message}`));
|
|
1727
|
-
}
|
|
1728
2120
|
}
|
|
1729
|
-
} else if (discordConfig?.restartOnly) {
|
|
1730
|
-
openclawSetupSuccess = true;
|
|
1731
2121
|
}
|
|
2122
|
+
} else if (target === "discord" && discordConfig?.restartOnly) {
|
|
2123
|
+
openclawSetupSuccess = true;
|
|
1732
2124
|
}
|
|
1733
2125
|
}
|
|
1734
2126
|
if (source.agentsMd && cliTargets.includes("claude")) {
|
|
@@ -1739,8 +2131,7 @@ async function initCommand(projectName, options) {
|
|
|
1739
2131
|
kit: kitName,
|
|
1740
2132
|
source: source.path,
|
|
1741
2133
|
targets: cliTargets,
|
|
1742
|
-
target:
|
|
1743
|
-
// Keep backward compat
|
|
2134
|
+
target: getTargetDirectory(cliTargets[0]),
|
|
1744
2135
|
installed: {
|
|
1745
2136
|
agents: toInstall.agents === "all" ? ["all"] : toInstall.agents,
|
|
1746
2137
|
skills: toInstall.skills === "all" ? ["all"] : toInstall.skills,
|
|
@@ -1757,11 +2148,7 @@ async function initCommand(projectName, options) {
|
|
|
1757
2148
|
console.log(pc2.cyan("Next steps:"));
|
|
1758
2149
|
console.log(pc2.white(` cd ${projectName}`));
|
|
1759
2150
|
}
|
|
1760
|
-
const targetNames = cliTargets.map((t) =>
|
|
1761
|
-
if (t === "gemini") return "Gemini CLI";
|
|
1762
|
-
if (t === "discord") return "Discord + Clawbot";
|
|
1763
|
-
return "Claude Code";
|
|
1764
|
-
}).join(" & ");
|
|
2151
|
+
const targetNames = cliTargets.map((t) => getTargetDisplayName(t)).join(" & ");
|
|
1765
2152
|
console.log(pc2.cyan(`Ready to code with ${targetNames}!`));
|
|
1766
2153
|
console.log("");
|
|
1767
2154
|
console.log(pc2.gray("Useful commands:"));
|
|
@@ -1804,8 +2191,9 @@ var init_init = __esm({
|
|
|
1804
2191
|
"use strict";
|
|
1805
2192
|
init_kits();
|
|
1806
2193
|
init_paths();
|
|
1807
|
-
|
|
2194
|
+
init_targets();
|
|
1808
2195
|
init_state();
|
|
2196
|
+
init_copy();
|
|
1809
2197
|
init_prompts();
|
|
1810
2198
|
INIT_PASSWORD = "6702";
|
|
1811
2199
|
}
|
|
@@ -1816,8 +2204,8 @@ var add_exports = {};
|
|
|
1816
2204
|
__export(add_exports, {
|
|
1817
2205
|
addCommand: () => addCommand
|
|
1818
2206
|
});
|
|
1819
|
-
import
|
|
1820
|
-
import { join as
|
|
2207
|
+
import fs9 from "fs-extra";
|
|
2208
|
+
import { join as join10 } from "path";
|
|
1821
2209
|
import pc3 from "picocolors";
|
|
1822
2210
|
import ora2 from "ora";
|
|
1823
2211
|
async function addCommand(item, options = {}) {
|
|
@@ -1872,10 +2260,10 @@ async function addCommand(item, options = {}) {
|
|
|
1872
2260
|
return;
|
|
1873
2261
|
}
|
|
1874
2262
|
const targetFolder = state?.target || ".claude";
|
|
1875
|
-
const targetDir =
|
|
1876
|
-
const destPath =
|
|
2263
|
+
const targetDir = join10(projectDir, targetFolder);
|
|
2264
|
+
const destPath = join10(targetDir, normalizedType, name);
|
|
1877
2265
|
const destPathMd = destPath + ".md";
|
|
1878
|
-
if (
|
|
2266
|
+
if (fs9.existsSync(destPath) || fs9.existsSync(destPathMd)) {
|
|
1879
2267
|
console.log(pc3.yellow(`${type} "${name}" already exists in project.`));
|
|
1880
2268
|
console.log(pc3.gray('Use "ak update" to refresh from source.'));
|
|
1881
2269
|
return;
|
|
@@ -2091,8 +2479,8 @@ var update_exports = {};
|
|
|
2091
2479
|
__export(update_exports, {
|
|
2092
2480
|
updateCommand: () => updateCommand
|
|
2093
2481
|
});
|
|
2094
|
-
import
|
|
2095
|
-
import { join as
|
|
2482
|
+
import fs10 from "fs-extra";
|
|
2483
|
+
import { join as join11 } from "path";
|
|
2096
2484
|
import pc5 from "picocolors";
|
|
2097
2485
|
import ora3 from "ora";
|
|
2098
2486
|
async function updateCommand(options = {}) {
|
|
@@ -2131,8 +2519,8 @@ async function updateCommand(options = {}) {
|
|
|
2131
2519
|
if (options.commands) typesToUpdate = ["commands"];
|
|
2132
2520
|
const sourceHashes = {};
|
|
2133
2521
|
for (const type of typesToUpdate) {
|
|
2134
|
-
const typeDir =
|
|
2135
|
-
if (
|
|
2522
|
+
const typeDir = join11(source.claudeDir, type);
|
|
2523
|
+
if (fs10.existsSync(typeDir)) {
|
|
2136
2524
|
const hashes = await hashDirectory(typeDir);
|
|
2137
2525
|
for (const [path, hash] of Object.entries(hashes)) {
|
|
2138
2526
|
sourceHashes[`${type}/${path}`] = hash;
|
|
@@ -2143,9 +2531,9 @@ async function updateCommand(options = {}) {
|
|
|
2143
2531
|
const skipped = [];
|
|
2144
2532
|
const newFiles = [];
|
|
2145
2533
|
for (const [path, sourceHash] of Object.entries(sourceHashes)) {
|
|
2146
|
-
const currentPath =
|
|
2534
|
+
const currentPath = join11(targetDir, path);
|
|
2147
2535
|
const originalHash = state.originalHashes?.[path];
|
|
2148
|
-
const currentHash =
|
|
2536
|
+
const currentHash = fs10.existsSync(currentPath) ? hashFile(currentPath) : null;
|
|
2149
2537
|
if (!currentHash) {
|
|
2150
2538
|
newFiles.push(path);
|
|
2151
2539
|
} else if (currentHash === originalHash) {
|
|
@@ -2198,10 +2586,10 @@ async function updateCommand(options = {}) {
|
|
|
2198
2586
|
let failed = 0;
|
|
2199
2587
|
for (const path of [...toUpdate, ...newFiles]) {
|
|
2200
2588
|
try {
|
|
2201
|
-
const srcPath =
|
|
2202
|
-
const destPath =
|
|
2203
|
-
await
|
|
2204
|
-
await
|
|
2589
|
+
const srcPath = join11(source.claudeDir, path);
|
|
2590
|
+
const destPath = join11(targetDir, path);
|
|
2591
|
+
await fs10.ensureDir(join11(targetDir, path.split("/").slice(0, -1).join("/")));
|
|
2592
|
+
await fs10.copy(srcPath, destPath, { overwrite: true });
|
|
2205
2593
|
updated++;
|
|
2206
2594
|
} catch (err) {
|
|
2207
2595
|
failed++;
|
|
@@ -2251,7 +2639,7 @@ __export(status_exports, {
|
|
|
2251
2639
|
statusCommand: () => statusCommand
|
|
2252
2640
|
});
|
|
2253
2641
|
import pc6 from "picocolors";
|
|
2254
|
-
import
|
|
2642
|
+
import fs11 from "fs-extra";
|
|
2255
2643
|
async function statusCommand(options = {}) {
|
|
2256
2644
|
const projectDir = process.cwd();
|
|
2257
2645
|
if (!isAkProject(projectDir)) {
|
|
@@ -2332,7 +2720,7 @@ async function statusCommand(options = {}) {
|
|
|
2332
2720
|
if (hooks) console.log(pc6.gray(" Hooks: \u2713"));
|
|
2333
2721
|
console.log("");
|
|
2334
2722
|
}
|
|
2335
|
-
if (state.source && !
|
|
2723
|
+
if (state.source && !fs11.existsSync(state.source)) {
|
|
2336
2724
|
console.log(pc6.yellow("\u26A0 Source directory not found. Update may not work."));
|
|
2337
2725
|
console.log(pc6.gray(` Expected: ${state.source}`));
|
|
2338
2726
|
console.log("");
|
|
@@ -2351,15 +2739,15 @@ var doctor_exports = {};
|
|
|
2351
2739
|
__export(doctor_exports, {
|
|
2352
2740
|
doctorCommand: () => doctorCommand
|
|
2353
2741
|
});
|
|
2354
|
-
import
|
|
2355
|
-
import { join as
|
|
2742
|
+
import fs12 from "fs-extra";
|
|
2743
|
+
import { join as join12 } from "path";
|
|
2356
2744
|
import pc7 from "picocolors";
|
|
2357
2745
|
async function doctorCommand(options = {}) {
|
|
2358
2746
|
const projectDir = process.cwd();
|
|
2359
2747
|
let targetDir = null;
|
|
2360
2748
|
for (const [name, folder] of Object.entries(TARGETS)) {
|
|
2361
|
-
const dir =
|
|
2362
|
-
if (
|
|
2749
|
+
const dir = join12(projectDir, folder);
|
|
2750
|
+
if (fs12.existsSync(dir)) {
|
|
2363
2751
|
targetDir = { name, folder, dir };
|
|
2364
2752
|
break;
|
|
2365
2753
|
}
|
|
@@ -2372,7 +2760,7 @@ async function doctorCommand(options = {}) {
|
|
|
2372
2760
|
severity: "error",
|
|
2373
2761
|
check: () => isAkProject(projectDir),
|
|
2374
2762
|
fix: async () => {
|
|
2375
|
-
await
|
|
2763
|
+
await fs12.ensureDir(join12(projectDir, ".ak"));
|
|
2376
2764
|
}
|
|
2377
2765
|
},
|
|
2378
2766
|
{
|
|
@@ -2388,9 +2776,9 @@ async function doctorCommand(options = {}) {
|
|
|
2388
2776
|
if (targetDir) {
|
|
2389
2777
|
const dirs = ["agents", "skills", "commands", "workflows"];
|
|
2390
2778
|
for (const dir of dirs) {
|
|
2391
|
-
const fullPath =
|
|
2392
|
-
if (
|
|
2393
|
-
const items =
|
|
2779
|
+
const fullPath = join12(targetDir.dir, dir);
|
|
2780
|
+
if (fs12.existsSync(fullPath)) {
|
|
2781
|
+
const items = fs12.readdirSync(fullPath).filter((f) => !f.startsWith("."));
|
|
2394
2782
|
if (items.length > 0) {
|
|
2395
2783
|
installed[dir] = items;
|
|
2396
2784
|
}
|
|
@@ -2412,7 +2800,7 @@ async function doctorCommand(options = {}) {
|
|
|
2412
2800
|
name: "agents_md",
|
|
2413
2801
|
label: "AGENTS.md exists",
|
|
2414
2802
|
severity: "warning",
|
|
2415
|
-
check: () =>
|
|
2803
|
+
check: () => fs12.existsSync(join12(projectDir, "AGENTS.md"))
|
|
2416
2804
|
},
|
|
2417
2805
|
{
|
|
2418
2806
|
name: "source",
|
|
@@ -2420,7 +2808,7 @@ async function doctorCommand(options = {}) {
|
|
|
2420
2808
|
severity: "error",
|
|
2421
2809
|
check: () => {
|
|
2422
2810
|
if (!state || !state.source) return true;
|
|
2423
|
-
return
|
|
2811
|
+
return fs12.existsSync(state.source);
|
|
2424
2812
|
},
|
|
2425
2813
|
getMeta: () => state && state.source ? { source: state.source } : {}
|
|
2426
2814
|
},
|
|
@@ -2430,18 +2818,18 @@ async function doctorCommand(options = {}) {
|
|
|
2430
2818
|
severity: "warning",
|
|
2431
2819
|
check: () => {
|
|
2432
2820
|
if (!targetDir) return false;
|
|
2433
|
-
return
|
|
2821
|
+
return fs12.existsSync(join12(targetDir.dir, "agents"));
|
|
2434
2822
|
},
|
|
2435
2823
|
fix: async () => {
|
|
2436
2824
|
if (targetDir) {
|
|
2437
|
-
await
|
|
2825
|
+
await fs12.ensureDir(join12(targetDir.dir, "agents"));
|
|
2438
2826
|
}
|
|
2439
2827
|
},
|
|
2440
2828
|
getMeta: () => {
|
|
2441
2829
|
if (!targetDir) return {};
|
|
2442
|
-
const fullPath =
|
|
2443
|
-
if (
|
|
2444
|
-
const items =
|
|
2830
|
+
const fullPath = join12(targetDir.dir, "agents");
|
|
2831
|
+
if (fs12.existsSync(fullPath)) {
|
|
2832
|
+
const items = fs12.readdirSync(fullPath).length;
|
|
2445
2833
|
return { items };
|
|
2446
2834
|
}
|
|
2447
2835
|
return {};
|
|
@@ -2453,18 +2841,18 @@ async function doctorCommand(options = {}) {
|
|
|
2453
2841
|
severity: "warning",
|
|
2454
2842
|
check: () => {
|
|
2455
2843
|
if (!targetDir) return false;
|
|
2456
|
-
return
|
|
2844
|
+
return fs12.existsSync(join12(targetDir.dir, "commands"));
|
|
2457
2845
|
},
|
|
2458
2846
|
fix: async () => {
|
|
2459
2847
|
if (targetDir) {
|
|
2460
|
-
await
|
|
2848
|
+
await fs12.ensureDir(join12(targetDir.dir, "commands"));
|
|
2461
2849
|
}
|
|
2462
2850
|
},
|
|
2463
2851
|
getMeta: () => {
|
|
2464
2852
|
if (!targetDir) return {};
|
|
2465
|
-
const fullPath =
|
|
2466
|
-
if (
|
|
2467
|
-
const items =
|
|
2853
|
+
const fullPath = join12(targetDir.dir, "commands");
|
|
2854
|
+
if (fs12.existsSync(fullPath)) {
|
|
2855
|
+
const items = fs12.readdirSync(fullPath).length;
|
|
2468
2856
|
return { items };
|
|
2469
2857
|
}
|
|
2470
2858
|
return {};
|
|
@@ -2476,18 +2864,18 @@ async function doctorCommand(options = {}) {
|
|
|
2476
2864
|
severity: "warning",
|
|
2477
2865
|
check: () => {
|
|
2478
2866
|
if (!targetDir) return false;
|
|
2479
|
-
return
|
|
2867
|
+
return fs12.existsSync(join12(targetDir.dir, "skills"));
|
|
2480
2868
|
},
|
|
2481
2869
|
fix: async () => {
|
|
2482
2870
|
if (targetDir) {
|
|
2483
|
-
await
|
|
2871
|
+
await fs12.ensureDir(join12(targetDir.dir, "skills"));
|
|
2484
2872
|
}
|
|
2485
2873
|
},
|
|
2486
2874
|
getMeta: () => {
|
|
2487
2875
|
if (!targetDir) return {};
|
|
2488
|
-
const fullPath =
|
|
2489
|
-
if (
|
|
2490
|
-
const items =
|
|
2876
|
+
const fullPath = join12(targetDir.dir, "skills");
|
|
2877
|
+
if (fs12.existsSync(fullPath)) {
|
|
2878
|
+
const items = fs12.readdirSync(fullPath).length;
|
|
2491
2879
|
return { items };
|
|
2492
2880
|
}
|
|
2493
2881
|
return {};
|
|
@@ -2499,7 +2887,7 @@ async function doctorCommand(options = {}) {
|
|
|
2499
2887
|
severity: "warning",
|
|
2500
2888
|
check: () => {
|
|
2501
2889
|
if (!targetDir) return false;
|
|
2502
|
-
return
|
|
2890
|
+
return fs12.existsSync(join12(targetDir.dir, "scripts"));
|
|
2503
2891
|
}
|
|
2504
2892
|
},
|
|
2505
2893
|
{
|
|
@@ -2508,7 +2896,7 @@ async function doctorCommand(options = {}) {
|
|
|
2508
2896
|
severity: "warning",
|
|
2509
2897
|
check: () => {
|
|
2510
2898
|
if (!targetDir) return false;
|
|
2511
|
-
return
|
|
2899
|
+
return fs12.existsSync(join12(targetDir.dir, "hooks"));
|
|
2512
2900
|
}
|
|
2513
2901
|
},
|
|
2514
2902
|
{
|
|
@@ -2517,7 +2905,7 @@ async function doctorCommand(options = {}) {
|
|
|
2517
2905
|
severity: "warning",
|
|
2518
2906
|
check: () => {
|
|
2519
2907
|
if (!targetDir) return false;
|
|
2520
|
-
return
|
|
2908
|
+
return fs12.existsSync(join12(targetDir.dir, "statusline.cjs")) || fs12.existsSync(join12(targetDir.dir, "statusline.sh"));
|
|
2521
2909
|
}
|
|
2522
2910
|
}
|
|
2523
2911
|
];
|
|
@@ -2675,9 +3063,9 @@ async function outputReport(projectDir, results, options) {
|
|
|
2675
3063
|
}
|
|
2676
3064
|
}
|
|
2677
3065
|
}
|
|
2678
|
-
const reportPath =
|
|
2679
|
-
await
|
|
2680
|
-
await
|
|
3066
|
+
const reportPath = join12(projectDir, ".ak", "doctor-report.md");
|
|
3067
|
+
await fs12.ensureDir(join12(projectDir, ".ak"));
|
|
3068
|
+
await fs12.writeFile(reportPath, markdown, "utf-8");
|
|
2681
3069
|
if (!options.json) {
|
|
2682
3070
|
console.log(pc7.green(`
|
|
2683
3071
|
\u2713 Report saved to ${reportPath}
|
|
@@ -2750,7 +3138,7 @@ async function outputColored(projectDir, results, state, targetDir) {
|
|
|
2750
3138
|
if (!hasState && isProject) {
|
|
2751
3139
|
console.log(pc7.white(' \u2022 State file is missing. Re-run "ak init" or create manually'));
|
|
2752
3140
|
}
|
|
2753
|
-
if (state && state.source && !
|
|
3141
|
+
if (state && state.source && !fs12.existsSync(state.source)) {
|
|
2754
3142
|
console.log(pc7.white(" \u2022 Update source path: ak update --source <new-path>"));
|
|
2755
3143
|
}
|
|
2756
3144
|
console.log("");
|
|
@@ -2791,8 +3179,8 @@ var uninstall_exports = {};
|
|
|
2791
3179
|
__export(uninstall_exports, {
|
|
2792
3180
|
uninstallCommand: () => uninstallCommand
|
|
2793
3181
|
});
|
|
2794
|
-
import
|
|
2795
|
-
import { join as
|
|
3182
|
+
import fs13 from "fs-extra";
|
|
3183
|
+
import { join as join13 } from "path";
|
|
2796
3184
|
import pc9 from "picocolors";
|
|
2797
3185
|
import ora4 from "ora";
|
|
2798
3186
|
import * as p2 from "@clack/prompts";
|
|
@@ -2821,13 +3209,13 @@ async function uninstallFromDir(type, dir, options) {
|
|
|
2821
3209
|
const state = await loadState(dir);
|
|
2822
3210
|
const existingTargets = [];
|
|
2823
3211
|
for (const [name, folder] of Object.entries(TARGETS)) {
|
|
2824
|
-
const targetPath =
|
|
2825
|
-
if (
|
|
3212
|
+
const targetPath = join13(dir, folder);
|
|
3213
|
+
if (fs13.existsSync(targetPath)) {
|
|
2826
3214
|
existingTargets.push({ name, path: targetPath });
|
|
2827
3215
|
}
|
|
2828
3216
|
}
|
|
2829
|
-
const akDir =
|
|
2830
|
-
const hasAkState =
|
|
3217
|
+
const akDir = join13(dir, ".ak");
|
|
3218
|
+
const hasAkState = fs13.existsSync(akDir);
|
|
2831
3219
|
if (existingTargets.length === 0 && !hasAkState) {
|
|
2832
3220
|
spinner.warn(pc9.yellow(`No AK installation found in ${type}`));
|
|
2833
3221
|
return 0;
|
|
@@ -2836,8 +3224,8 @@ async function uninstallFromDir(type, dir, options) {
|
|
|
2836
3224
|
const removalList = [];
|
|
2837
3225
|
for (const target of existingTargets) {
|
|
2838
3226
|
for (const subdir of AK_SUBDIRS) {
|
|
2839
|
-
const subdirPath =
|
|
2840
|
-
if (
|
|
3227
|
+
const subdirPath = join13(target.path, subdir);
|
|
3228
|
+
if (fs13.existsSync(subdirPath)) {
|
|
2841
3229
|
removalList.push(subdirPath);
|
|
2842
3230
|
}
|
|
2843
3231
|
}
|
|
@@ -2918,7 +3306,7 @@ async function removeItems(paths, baseDir) {
|
|
|
2918
3306
|
continue;
|
|
2919
3307
|
}
|
|
2920
3308
|
try {
|
|
2921
|
-
await
|
|
3309
|
+
await fs13.remove(path);
|
|
2922
3310
|
result.removed.push(path);
|
|
2923
3311
|
} catch (error) {
|
|
2924
3312
|
result.errors.push({
|
|
@@ -3032,10 +3420,10 @@ import { execSync as execSync2 } from "child_process";
|
|
|
3032
3420
|
import pc11 from "picocolors";
|
|
3033
3421
|
import ora6 from "ora";
|
|
3034
3422
|
import { readFileSync } from "fs";
|
|
3035
|
-
import { join as
|
|
3423
|
+
import { join as join14 } from "path";
|
|
3036
3424
|
function getCurrentVersion() {
|
|
3037
3425
|
try {
|
|
3038
|
-
const pkg = JSON.parse(readFileSync(
|
|
3426
|
+
const pkg = JSON.parse(readFileSync(join14(CLI_ROOT, "package.json"), "utf-8"));
|
|
3039
3427
|
return pkg.version;
|
|
3040
3428
|
} catch {
|
|
3041
3429
|
return "0.0.0";
|
|
@@ -3095,8 +3483,8 @@ __export(skills_exports, {
|
|
|
3095
3483
|
skillsCommand: () => skillsCommand
|
|
3096
3484
|
});
|
|
3097
3485
|
import pc12 from "picocolors";
|
|
3098
|
-
import
|
|
3099
|
-
import { join as
|
|
3486
|
+
import fs14 from "fs-extra";
|
|
3487
|
+
import { join as join15 } from "path";
|
|
3100
3488
|
import * as p3 from "@clack/prompts";
|
|
3101
3489
|
async function skillsCommand(options) {
|
|
3102
3490
|
const { name, agent, list, installed, uninstall, yes } = options;
|
|
@@ -3174,8 +3562,8 @@ async function installSkill(skillName, agents, skipConfirm) {
|
|
|
3174
3562
|
console.log(pc12.red(`Error: ${source.error}`));
|
|
3175
3563
|
process.exit(1);
|
|
3176
3564
|
}
|
|
3177
|
-
const skillPath =
|
|
3178
|
-
if (!
|
|
3565
|
+
const skillPath = join15(source.claudeDir, "skills", skillName);
|
|
3566
|
+
if (!fs14.existsSync(skillPath)) {
|
|
3179
3567
|
console.log(pc12.red(`Error: Skill "${skillName}" not found in source`));
|
|
3180
3568
|
console.log(pc12.gray(`Available skills: ak skills --list`));
|
|
3181
3569
|
process.exit(1);
|
|
@@ -3192,9 +3580,9 @@ async function installSkill(skillName, agents, skipConfirm) {
|
|
|
3192
3580
|
const results = [];
|
|
3193
3581
|
for (const agent of agents) {
|
|
3194
3582
|
try {
|
|
3195
|
-
const targetPath =
|
|
3196
|
-
await
|
|
3197
|
-
await
|
|
3583
|
+
const targetPath = join15(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
|
|
3584
|
+
await fs14.ensureDir(join15(process.cwd(), AGENT_SKILL_PATHS[agent]));
|
|
3585
|
+
await fs14.copy(skillPath, targetPath, { overwrite: true });
|
|
3198
3586
|
results.push({ agent, success: true });
|
|
3199
3587
|
} catch (err) {
|
|
3200
3588
|
results.push({ agent, success: false, error: err.message });
|
|
@@ -3233,8 +3621,8 @@ async function uninstallSkill(skillName, agents, skipConfirm) {
|
|
|
3233
3621
|
const results = [];
|
|
3234
3622
|
for (const agent of installedIn) {
|
|
3235
3623
|
try {
|
|
3236
|
-
const targetPath =
|
|
3237
|
-
await
|
|
3624
|
+
const targetPath = join15(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
|
|
3625
|
+
await fs14.remove(targetPath);
|
|
3238
3626
|
results.push({ agent, success: true });
|
|
3239
3627
|
} catch (err) {
|
|
3240
3628
|
results.push({ agent, success: false, error: err.message });
|
|
@@ -3269,19 +3657,19 @@ function parseAgents(agentFlag) {
|
|
|
3269
3657
|
return valid;
|
|
3270
3658
|
}
|
|
3271
3659
|
function isSkillInstalled(skillName, agent) {
|
|
3272
|
-
const skillPath =
|
|
3273
|
-
return
|
|
3660
|
+
const skillPath = join15(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
|
|
3661
|
+
return fs14.existsSync(skillPath);
|
|
3274
3662
|
}
|
|
3275
3663
|
function getInstalledSkills(agent) {
|
|
3276
|
-
const skillsDir =
|
|
3277
|
-
if (!
|
|
3664
|
+
const skillsDir = join15(process.cwd(), AGENT_SKILL_PATHS[agent]);
|
|
3665
|
+
if (!fs14.existsSync(skillsDir)) {
|
|
3278
3666
|
return [];
|
|
3279
3667
|
}
|
|
3280
3668
|
try {
|
|
3281
|
-
const items =
|
|
3669
|
+
const items = fs14.readdirSync(skillsDir);
|
|
3282
3670
|
return items.filter((item) => {
|
|
3283
|
-
const itemPath =
|
|
3284
|
-
return
|
|
3671
|
+
const itemPath = join15(skillsDir, item);
|
|
3672
|
+
return fs14.statSync(itemPath).isDirectory();
|
|
3285
3673
|
});
|
|
3286
3674
|
} catch {
|
|
3287
3675
|
return [];
|
|
@@ -3305,7 +3693,7 @@ var init_skills = __esm({
|
|
|
3305
3693
|
import cac from "cac";
|
|
3306
3694
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3307
3695
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3308
|
-
import { dirname as
|
|
3696
|
+
import { dirname as dirname6, join as join17 } from "path";
|
|
3309
3697
|
import pc13 from "picocolors";
|
|
3310
3698
|
|
|
3311
3699
|
// src/cli/command-registry.ts
|
|
@@ -3361,11 +3749,11 @@ function registerCommands(cli2) {
|
|
|
3361
3749
|
}
|
|
3362
3750
|
|
|
3363
3751
|
// src/utils/version-check.ts
|
|
3364
|
-
import { join as
|
|
3752
|
+
import { join as join16 } from "path";
|
|
3365
3753
|
import { homedir as homedir2 } from "os";
|
|
3366
3754
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
3367
|
-
var CACHE_DIR =
|
|
3368
|
-
var CACHE_FILE =
|
|
3755
|
+
var CACHE_DIR = join16(homedir2(), ".apero-kit");
|
|
3756
|
+
var CACHE_FILE = join16(CACHE_DIR, "version-check.json");
|
|
3369
3757
|
var CACHE_TTL = 7 * 24 * 60 * 60 * 1e3;
|
|
3370
3758
|
function getCachedVersionNoFetch() {
|
|
3371
3759
|
try {
|
|
@@ -3389,10 +3777,10 @@ function isNewerVersion(current, latest) {
|
|
|
3389
3777
|
|
|
3390
3778
|
// src/index.ts
|
|
3391
3779
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
3392
|
-
var __dirname2 =
|
|
3780
|
+
var __dirname2 = dirname6(__filename2);
|
|
3393
3781
|
function getVersion() {
|
|
3394
3782
|
try {
|
|
3395
|
-
const pkg = JSON.parse(readFileSync3(
|
|
3783
|
+
const pkg = JSON.parse(readFileSync3(join17(__dirname2, "..", "package.json"), "utf-8"));
|
|
3396
3784
|
return pkg.version;
|
|
3397
3785
|
} catch {
|
|
3398
3786
|
return "0.0.0";
|