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 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/utils/copy.ts
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
- function parseFrontmatter(content) {
264
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
265
- if (!frontmatterMatch) {
266
- return { description: "", argumentHint: "", body: content };
267
- }
268
- const frontmatter = frontmatterMatch[1];
269
- const body = frontmatterMatch[2].trim();
270
- const descMatch = frontmatter.match(/description:\s*(.+)/);
271
- const argMatch = frontmatter.match(/argument-hint:\s*(.+)/);
272
- return {
273
- description: descMatch ? descMatch[1].trim() : "",
274
- argumentHint: argMatch ? argMatch[1].trim() : "",
275
- body
276
- };
277
- }
278
- function escapeTomlBasicString(str) {
279
- return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t");
280
- }
281
- function convertMdToToml(mdContent) {
282
- const { description, body } = parseFrontmatter(mdContent);
283
- const prompt = body.replace(/\$ARGUMENTS/g, "{{args}}");
284
- const lines = [];
285
- if (description) {
286
- lines.push(`description = "${escapeTomlBasicString(description)}"`);
287
- }
288
- lines.push(`prompt = '''
289
- ${prompt}
290
- '''`);
291
- return lines.join("\n");
292
- }
293
- async function copyItems(items, type, sourceDir, destDir, mergeMode = false) {
294
- const typeDir = join2(sourceDir, type);
295
- const destTypeDir = join2(destDir, type);
296
- if (!fs.existsSync(typeDir)) {
297
- return { copied: [], skipped: items, errors: [] };
298
- }
299
- await fs.ensureDir(destTypeDir);
300
- const copied = [];
301
- const skipped = [];
302
- const errors = [];
303
- for (const item of items) {
304
- try {
305
- const itemPath = join2(typeDir, item);
306
- const itemPathMd = itemPath + ".md";
307
- let srcPath;
308
- if (fs.existsSync(itemPath)) {
309
- srcPath = itemPath;
310
- } else if (fs.existsSync(itemPathMd)) {
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
- copied.push(item);
325
- } catch (err) {
326
- errors.push({ item, error: err.message });
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
- const mdContent = fs.readFileSync(srcPathMd, "utf-8");
448
- const tomlContent = convertMdToToml(mdContent);
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
- if (fs.existsSync(srcPathDir) && fs.statSync(srcPathDir).isDirectory()) {
454
- await convertDirectoryToToml(srcPathDir, join2(destTypeDir, item), mergeMode);
455
- copiedSomething = true;
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
- if (copiedSomething) {
458
- copied.push(item);
459
- } else {
460
- skipped.push(item);
346
+ getItemList(items, typeDir, extension) {
347
+ if (items === "all") {
348
+ return this.listItemsSync(typeDir, extension);
349
+ }
350
+ return items;
461
351
  }
462
- } catch (err) {
463
- errors.push({ item, error: err.message });
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
- return { copied, skipped, errors };
467
- }
468
- async function convertDirectoryToToml(srcDir, destDir, mergeMode = false) {
469
- await fs.ensureDir(destDir);
470
- const entries = fs.readdirSync(srcDir);
471
- for (const entry of entries) {
472
- const srcPath = join2(srcDir, entry);
473
- const stat = fs.statSync(srcPath);
474
- if (stat.isDirectory()) {
475
- await convertDirectoryToToml(srcPath, join2(destDir, entry), mergeMode);
476
- } else if (entry.endsWith(".md")) {
477
- const destPath = join2(destDir, entry.replace(/\.md$/, ".toml"));
478
- if (mergeMode && fs.existsSync(destPath)) {
479
- continue;
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
- const mdContent = fs.readFileSync(srcPath, "utf-8");
482
- const tomlContent = convertMdToToml(mdContent);
483
- await fs.writeFile(destPath, tomlContent, "utf-8");
484
- } else {
485
- const destPath = join2(destDir, entry);
486
- if (mergeMode && fs.existsSync(destPath)) {
487
- continue;
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
- await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
490
- }
491
- }
492
- }
493
- function convertAgentForGemini(mdContent) {
494
- const frontmatterMatch = mdContent.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
495
- if (!frontmatterMatch) return mdContent;
496
- let frontmatter = frontmatterMatch[1];
497
- const body = frontmatterMatch[2];
498
- const modelMap = {
499
- "opus": "gemini-2.5-pro",
500
- "sonnet": "gemini-2.5-flash",
501
- "haiku": "gemini-2.0-flash-lite",
502
- "inherit": ""
503
- // Remove inherit, let Gemini use default
504
- };
505
- for (const [claudeModel, geminiModel] of Object.entries(modelMap)) {
506
- const regex = new RegExp(`^model:\\s*${claudeModel}\\s*$`, "m");
507
- if (geminiModel) {
508
- frontmatter = frontmatter.replace(regex, `model: ${geminiModel}`);
509
- } else {
510
- frontmatter = frontmatter.replace(regex, "");
511
- }
512
- }
513
- frontmatter = frontmatter.replace(/^tools:\s*.+$/m, "");
514
- if (!frontmatter.includes("kind:")) {
515
- frontmatter = frontmatter.trim() + "\nkind: local";
516
- }
517
- return `---
518
- ${frontmatter.trim()}
519
- ---
520
- ${body}`;
521
- }
522
- async function copyAgentsForGemini(items, sourceDir, destDir, mergeMode = false) {
523
- const typeDir = join2(sourceDir, "agents");
524
- const destTypeDir = join2(destDir, "agents");
525
- if (!fs.existsSync(typeDir)) {
526
- return { copied: [], skipped: [], errors: [] };
527
- }
528
- await fs.ensureDir(destTypeDir);
529
- const copied = [];
530
- const skipped = [];
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
- const destPath = join2(destTypeDir, agent + ".md");
547
- if (mergeMode && fs.existsSync(destPath)) {
548
- skipped.push(agent);
549
- continue;
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
- const mdContent = fs.readFileSync(srcPath, "utf-8");
552
- const convertedContent = convertAgentForGemini(mdContent);
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
- const skillMdPath = join2(srcPath, "SKILL.md");
589
- if (!fs.existsSync(skillMdPath)) {
590
- skipped.push(skill);
591
- continue;
550
+ async copyHooks(sourceDir, targetDir, mergeMode) {
551
+ return this.copyDirectory("hooks", sourceDir, targetDir, mergeMode);
592
552
  }
593
- const destPath = join2(destTypeDir, skill);
594
- if (mergeMode && fs.existsSync(destPath)) {
595
- skipped.push(skill);
596
- continue;
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
- await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
599
- copied.push(skill);
600
- } catch (err) {
601
- errors.push({ skill, error: err.message });
602
- }
578
+ };
603
579
  }
604
- return { copied, skipped, errors };
605
- }
606
- async function copyGeminiBaseFiles(destDir, mergeMode = false) {
607
- const geminiTemplates = join2(CLI_ROOT, "templates", "gemini");
608
- const copied = [];
609
- const settingsPath = join2(geminiTemplates, "settings.json");
610
- const destSettingsPath = join2(destDir, "settings.json");
611
- if (fs.existsSync(settingsPath)) {
612
- if (mergeMode && fs.existsSync(destSettingsPath)) {
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 copied;
590
+ return { frontmatter: match[1], body: match[2] };
619
591
  }
620
- function convertCommandForDiscord(mdContent, commandName) {
621
- const { description, body } = parseFrontmatter(mdContent);
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 convertAgentForDiscord(mdContent) {
630
- const frontmatterMatch = mdContent.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
631
- if (!frontmatterMatch) return mdContent;
632
- let frontmatter = frontmatterMatch[1];
633
- const body = frontmatterMatch[2];
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 (discordModel) {
644
- frontmatter = frontmatter.replace(regex, `model: ${discordModel}`);
601
+ if (geminiModel) {
602
+ converted = converted.replace(regex, `model: ${geminiModel}`);
645
603
  } else {
646
- frontmatter = frontmatter.replace(regex, "");
604
+ converted = converted.replace(regex, "");
647
605
  }
648
606
  }
649
- frontmatter = frontmatter.replace(/^tools:\s*.+$/m, "");
650
- if (!frontmatter.includes("kind:")) {
651
- frontmatter = frontmatter.trim() + "\nkind: local";
607
+ converted = converted.replace(/^tools:\s*.+$/m, "");
608
+ if (!converted.includes("kind:")) {
609
+ converted = converted.trim() + "\nkind: local";
652
610
  }
653
611
  return `---
654
- ${frontmatter.trim()}
612
+ ${converted.trim()}
655
613
  ---
656
614
  ${body}`;
657
615
  }
658
- async function copyAgentsForDiscord(items, sourceDir, destDir, mergeMode = false) {
659
- const typeDir = join2(sourceDir, "agents");
660
- const destTypeDir = join2(destDir, "agents");
661
- if (!fs.existsSync(typeDir)) {
662
- return { copied: [], skipped: [], errors: [] };
663
- }
664
- await fs.ensureDir(destTypeDir);
665
- const copied = [];
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
- return { copied, skipped, errors };
625
+ lines.push(`prompt = '''
626
+ ${prompt}
627
+ '''`);
628
+ return lines.join("\n");
696
629
  }
697
- async function copyCommandsForDiscord(items, sourceDir, destDir, mergeMode = false) {
698
- const typeDir = join2(sourceDir, "commands");
699
- const destTypeDir = join2(destDir, "commands");
700
- if (!fs.existsSync(typeDir)) {
701
- return { copied: [], skipped: [], errors: [] };
702
- }
703
- await fs.ensureDir(destTypeDir);
704
- const copied = [];
705
- const skipped = [];
706
- const errors = [];
707
- const commandsConfig = {};
708
- let itemList;
709
- if (items === "all") {
710
- const entries = fs.readdirSync(typeDir);
711
- itemList = entries.map((e) => e.replace(/\.md$/, ""));
712
- itemList = [...new Set(itemList)];
713
- } else {
714
- itemList = items;
715
- }
716
- for (const item of itemList) {
717
- try {
718
- const srcPathMd = join2(typeDir, item + ".md");
719
- const srcPathDir = join2(typeDir, item);
720
- let copiedSomething = false;
721
- if (fs.existsSync(srcPathMd) && fs.statSync(srcPathMd).isFile()) {
722
- const destPath = join2(destTypeDir, item + ".md");
723
- if (!(mergeMode && fs.existsSync(destPath))) {
724
- await fs.ensureDir(dirname2(destPath));
725
- const mdContent = fs.readFileSync(srcPathMd, "utf-8");
726
- await fs.copy(srcPathMd, destPath, { overwrite: !mergeMode });
727
- const cmd = convertCommandForDiscord(mdContent, item);
728
- commandsConfig[item] = {
729
- description: cmd.description,
730
- prompt: cmd.prompt
731
- };
732
- copiedSomething = true;
733
- }
734
- }
735
- if (fs.existsSync(srcPathDir) && fs.statSync(srcPathDir).isDirectory()) {
736
- await copyDirectoryForDiscord(srcPathDir, join2(destTypeDir, item), mergeMode, commandsConfig, item);
737
- copiedSomething = true;
738
- }
739
- if (copiedSomething) {
740
- copied.push(item);
741
- } else {
742
- skipped.push(item);
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
- } catch (err) {
745
- errors.push({ item, error: err.message });
746
- }
747
- }
748
- const configPath = join2(destDir, "commands.json5");
749
- if (Object.keys(commandsConfig).length > 0 && !(mergeMode && fs.existsSync(configPath))) {
750
- const json5Content = generateCommandsJson5(commandsConfig);
751
- await fs.writeFile(configPath, json5Content, "utf-8");
752
- }
753
- return { copied, skipped, errors };
754
- }
755
- async function copyDirectoryForDiscord(srcDir, destDir, mergeMode, commandsConfig, parentName) {
756
- await fs.ensureDir(destDir);
757
- const entries = fs.readdirSync(srcDir);
758
- for (const entry of entries) {
759
- const srcPath = join2(srcDir, entry);
760
- const stat = fs.statSync(srcPath);
761
- if (stat.isDirectory()) {
762
- await copyDirectoryForDiscord(
763
- srcPath,
764
- join2(destDir, entry),
765
- mergeMode,
766
- commandsConfig,
767
- `${parentName}/${entry}`
768
- );
769
- } else if (entry.endsWith(".md")) {
770
- const destPath = join2(destDir, entry);
771
- if (mergeMode && fs.existsSync(destPath)) {
772
- continue;
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
- const mdContent = fs.readFileSync(srcPath, "utf-8");
775
- await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
776
- const cmdName = `${parentName}/${entry.replace(/\.md$/, "")}`;
777
- const cmd = convertCommandForDiscord(mdContent, cmdName);
778
- commandsConfig[cmdName] = {
779
- description: cmd.description,
780
- prompt: cmd.prompt
781
- };
782
- } else {
783
- const destPath = join2(destDir, entry);
784
- if (mergeMode && fs.existsSync(destPath)) {
785
- continue;
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
- await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
788
- }
789
- }
790
- }
791
- function generateCommandsJson5(commands) {
792
- const lines = [
793
- "// Clawbot Commands Configuration",
794
- "// Generated by Apero Kit CLI",
795
- "// These commands can be used as slash commands in Discord",
796
- "{",
797
- ' "commands": {'
798
- ];
799
- const cmdEntries = Object.entries(commands);
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
- await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
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
- await fs.writeFile(configPath, content, "utf-8");
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
- async function setupOpenClawConfig(token) {
859
- const { execSync: execSync3 } = await import("child_process");
860
- try {
861
- execSync3("which openclaw", { stdio: "ignore" });
862
- } catch {
863
- return { success: false, message: "OpenClaw CLI not installed. Run: npm install -g openclaw" };
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
- try {
866
- execSync3(`openclaw config set channels.discord.token '"${token}"' --json`, { stdio: "ignore" });
867
- execSync3("openclaw config set channels.discord.enabled true --json", { stdio: "ignore" });
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", "think"],
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 } = parseFrontmatter(mdContent);
893
+ const { description, argumentHint, body } = parseFrontmatter2(mdContent);
908
894
  const prompt = body.replace(/\$ARGUMENTS/g, "{{args}}");
909
895
  const keywords = extractKeywords(body, commandName);
910
- const skillContent = `---
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
- async function convertCommandsToSkills(items, sourceDir, destDir, mergeMode = false) {
939
- const typeDir = join2(sourceDir, "commands");
940
- const destTypeDir = join2(destDir, "skills");
941
- if (!fs.existsSync(typeDir)) {
942
- return { copied: [], skipped: [], errors: [] };
943
- }
944
- await fs.ensureDir(destTypeDir);
945
- const copied = [];
946
- const skipped = [];
947
- const errors = [];
948
- let itemList;
949
- if (items === "all") {
950
- const entries = fs.readdirSync(typeDir);
951
- itemList = entries.filter((e) => e.endsWith(".md") && e !== "README.md").map((e) => e.replace(/\.md$/, ""));
952
- const dirs = entries.filter((e) => {
953
- const fullPath = join2(typeDir, e);
954
- return fs.statSync(fullPath).isDirectory();
955
- });
956
- itemList = [.../* @__PURE__ */ new Set([...itemList, ...dirs])];
957
- } else {
958
- itemList = items;
959
- }
960
- for (const item of itemList) {
961
- try {
962
- const srcPathMd = join2(typeDir, item + ".md");
963
- const srcPathDir = join2(typeDir, item);
964
- if (fs.existsSync(srcPathMd) && fs.statSync(srcPathMd).isFile()) {
965
- const skillDir = join2(destTypeDir, item.replace(/\//g, "-"));
966
- const skillPath = join2(skillDir, "SKILL.md");
967
- if (mergeMode && fs.existsSync(skillPath)) {
968
- skipped.push(item);
969
- continue;
970
- }
971
- await fs.ensureDir(skillDir);
972
- const mdContent = fs.readFileSync(srcPathMd, "utf-8");
973
- const skillContent = convertCommandToSkill(mdContent, item);
974
- await fs.writeFile(skillPath, skillContent, "utf-8");
975
- copied.push(item);
976
- }
977
- if (fs.existsSync(srcPathDir) && fs.statSync(srcPathDir).isDirectory()) {
978
- await convertNestedCommandsToSkills(srcPathDir, destTypeDir, item, mergeMode);
979
- copied.push(item + "/*");
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
- } catch (err) {
982
- errors.push({ item, error: err.message });
983
- }
984
- }
985
- return { copied, skipped, errors };
986
- }
987
- async function convertNestedCommandsToSkills(srcDir, destDir, parentName, mergeMode) {
988
- const entries = fs.readdirSync(srcDir);
989
- for (const entry of entries) {
990
- const srcPath = join2(srcDir, entry);
991
- const stat = fs.statSync(srcPath);
992
- if (stat.isDirectory()) {
993
- await convertNestedCommandsToSkills(
994
- srcPath,
995
- destDir,
996
- `${parentName}-${entry}`,
997
- mergeMode
998
- );
999
- } else if (entry.endsWith(".md") && entry !== "README.md") {
1000
- const skillName = `${parentName}-${entry.replace(/\.md$/, "")}`;
1001
- const skillDir = join2(destDir, skillName);
1002
- const skillPath = join2(skillDir, "SKILL.md");
1003
- if (mergeMode && fs.existsSync(skillPath)) {
1004
- continue;
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
- await fs.ensureDir(skillDir);
1007
- const mdContent = fs.readFileSync(srcPath, "utf-8");
1008
- const skillContent = convertCommandToSkill(mdContent, skillName);
1009
- await fs.writeFile(skillPath, skillContent, "utf-8");
1010
- }
1011
- }
1012
- }
1013
- async function copyBundledSkillsForDiscord(destDir, mergeMode = false) {
1014
- const bundledSkillsDir = join2(CLI_ROOT, "templates", "discord", "skills");
1015
- const destSkillsDir = join2(destDir, "skills");
1016
- const copied = [];
1017
- if (!fs.existsSync(bundledSkillsDir)) {
1018
- return copied;
1019
- }
1020
- await fs.ensureDir(destSkillsDir);
1021
- const skills = fs.readdirSync(bundledSkillsDir);
1022
- for (const skill of skills) {
1023
- const srcPath = join2(bundledSkillsDir, skill);
1024
- const destPath = join2(destSkillsDir, skill);
1025
- if (fs.statSync(srcPath).isDirectory()) {
1026
- if (mergeMode && fs.existsSync(destPath)) {
1027
- continue;
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
- await fs.copy(srcPath, destPath, { overwrite: !mergeMode });
1030
- copied.push(skill);
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 copied;
1262
+ return adapter;
1034
1263
  }
1035
- var init_copy = __esm({
1036
- "src/utils/copy.ts"() {
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
- init_paths();
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 fs2 from "fs-extra";
1045
- import { join as join3, relative } from "path";
1293
+ import fs5 from "fs-extra";
1294
+ import { join as join6, relative } from "path";
1046
1295
  function hashFile(filePath) {
1047
- if (!fs2.existsSync(filePath)) {
1296
+ if (!fs5.existsSync(filePath)) {
1048
1297
  return null;
1049
1298
  }
1050
- const content = fs2.readFileSync(filePath);
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 (!fs2.existsSync(dirPath)) {
1304
+ if (!fs5.existsSync(dirPath)) {
1056
1305
  return hashes;
1057
1306
  }
1058
- const items = await fs2.readdir(dirPath, { withFileTypes: true });
1307
+ const items = await fs5.readdir(dirPath, { withFileTypes: true });
1059
1308
  for (const item of items) {
1060
- const itemPath = join3(dirPath, item.name);
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 fs3 from "fs-extra";
1082
- import { join as join4 } from "path";
1330
+ import fs6 from "fs-extra";
1331
+ import { join as join7 } from "path";
1083
1332
  function getStatePath(projectDir) {
1084
- return join4(projectDir, STATE_DIR, STATE_FILE);
1333
+ return join7(projectDir, STATE_DIR, STATE_FILE);
1085
1334
  }
1086
1335
  async function loadState(projectDir) {
1087
1336
  const statePath = getStatePath(projectDir);
1088
- if (!fs3.existsSync(statePath)) {
1337
+ if (!fs6.existsSync(statePath)) {
1089
1338
  return null;
1090
1339
  }
1091
1340
  try {
1092
- return await fs3.readJson(statePath);
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 = join4(projectDir, STATE_DIR);
1099
- const statePath = join4(stateDir, STATE_FILE);
1100
- await fs3.ensureDir(stateDir);
1101
- await fs3.writeJson(statePath, state, { spaces: 2 });
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 = join4(projectDir, targetDirName);
1110
- if (fs3.existsSync(targetDir)) {
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 = join4(projectDir, state.target || ".claude");
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 = join4(projectDir, state.target || ".claude");
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(pc.gray("Get your bot token from: https://discord.com/developers/applications"));
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 fs4 from "fs-extra";
1458
- import { join as join5, resolve as resolve2 } from "path";
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 === "claude" || t === "gemini" || t === "discord");
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 = getTargetDir(projectDir, target);
1533
- if (options.fresh && fs4.existsSync(targetDir)) {
1534
- await fs4.remove(targetDir);
1535
- existingTargets.push(TARGETS[target]);
1536
- } else if (fs4.existsSync(targetDir) && !options.force) {
1537
- existingTargets.push(TARGETS[target]);
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 = join5(projectDir, ".ak");
1542
- if (fs4.existsSync(akDir)) {
1543
- await fs4.remove(akDir);
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 && fs4.existsSync(projectDir) && !options.force) {
1564
- const files = fs4.readdirSync(projectDir);
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
- toInstall.includeRouter = await promptIncludeRouter();
1598
- toInstall.includeHooks = await promptIncludeHooks();
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) => TARGETS[t]).join(", ")}/`));
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 fs4.ensureDir(projectDir);
2080
+ await fs8.ensureDir(projectDir);
1644
2081
  for (const target of cliTargets) {
1645
- const targetDir = getTargetDir(projectDir, target);
1646
- await fs4.ensureDir(targetDir);
1647
- const targetLabel = target === "gemini" ? "Gemini" : target === "discord" ? "Discord" : "Claude";
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
- if (target === "gemini") {
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
- if (target === "gemini") {
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
- if (target === "gemini") {
1674
- await copyCommandsForGemini(toInstall.commands, source.claudeDir, targetDir, mergeMode);
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
- if (toInstall.workflows === "all") {
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 (target === "claude" && toInstall.includeRouter) {
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 (target === "claude" && toInstall.includeHooks) {
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
- if (target === "claude") {
1705
- spinner.text = mergeMode ? `Merging extras (${targetLabel})...` : `Copying extras (${targetLabel})...`;
1706
- await copyDirectory("memory", source.claudeDir, targetDir, mergeMode);
1707
- await copyDirectory("output-styles", source.claudeDir, targetDir, mergeMode);
1708
- await copyDirectory("scripts", source.claudeDir, targetDir, mergeMode);
1709
- spinner.text = mergeMode ? `Merging base files (${targetLabel})...` : `Copying base files (${targetLabel})...`;
1710
- await copyBaseFiles(source.claudeDir, targetDir, mergeMode);
1711
- } else if (target === "gemini") {
1712
- spinner.text = mergeMode ? `Merging settings (${targetLabel})...` : `Copying settings (${targetLabel})...`;
1713
- await copyGeminiBaseFiles(targetDir, mergeMode);
1714
- } else if (target === "discord") {
1715
- spinner.text = mergeMode ? `Merging config (${targetLabel})...` : `Copying config (${targetLabel})...`;
1716
- await copyDiscordBaseFiles(targetDir, mergeMode);
1717
- if (discordConfig && !discordConfig.restartOnly) {
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: TARGETS[cliTargets[0]],
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
- init_copy();
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 fs5 from "fs-extra";
1820
- import { join as join6 } from "path";
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 = join6(projectDir, targetFolder);
1876
- const destPath = join6(targetDir, normalizedType, name);
2263
+ const targetDir = join10(projectDir, targetFolder);
2264
+ const destPath = join10(targetDir, normalizedType, name);
1877
2265
  const destPathMd = destPath + ".md";
1878
- if (fs5.existsSync(destPath) || fs5.existsSync(destPathMd)) {
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 fs6 from "fs-extra";
2095
- import { join as join7 } from "path";
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 = join7(source.claudeDir, type);
2135
- if (fs6.existsSync(typeDir)) {
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 = join7(targetDir, path);
2534
+ const currentPath = join11(targetDir, path);
2147
2535
  const originalHash = state.originalHashes?.[path];
2148
- const currentHash = fs6.existsSync(currentPath) ? hashFile(currentPath) : null;
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 = join7(source.claudeDir, path);
2202
- const destPath = join7(targetDir, path);
2203
- await fs6.ensureDir(join7(targetDir, path.split("/").slice(0, -1).join("/")));
2204
- await fs6.copy(srcPath, destPath, { overwrite: true });
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 fs7 from "fs-extra";
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 && !fs7.existsSync(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 fs8 from "fs-extra";
2355
- import { join as join8 } from "path";
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 = join8(projectDir, folder);
2362
- if (fs8.existsSync(dir)) {
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 fs8.ensureDir(join8(projectDir, ".ak"));
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 = join8(targetDir.dir, dir);
2392
- if (fs8.existsSync(fullPath)) {
2393
- const items = fs8.readdirSync(fullPath).filter((f) => !f.startsWith("."));
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: () => fs8.existsSync(join8(projectDir, "AGENTS.md"))
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 fs8.existsSync(state.source);
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 fs8.existsSync(join8(targetDir.dir, "agents"));
2821
+ return fs12.existsSync(join12(targetDir.dir, "agents"));
2434
2822
  },
2435
2823
  fix: async () => {
2436
2824
  if (targetDir) {
2437
- await fs8.ensureDir(join8(targetDir.dir, "agents"));
2825
+ await fs12.ensureDir(join12(targetDir.dir, "agents"));
2438
2826
  }
2439
2827
  },
2440
2828
  getMeta: () => {
2441
2829
  if (!targetDir) return {};
2442
- const fullPath = join8(targetDir.dir, "agents");
2443
- if (fs8.existsSync(fullPath)) {
2444
- const items = fs8.readdirSync(fullPath).length;
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 fs8.existsSync(join8(targetDir.dir, "commands"));
2844
+ return fs12.existsSync(join12(targetDir.dir, "commands"));
2457
2845
  },
2458
2846
  fix: async () => {
2459
2847
  if (targetDir) {
2460
- await fs8.ensureDir(join8(targetDir.dir, "commands"));
2848
+ await fs12.ensureDir(join12(targetDir.dir, "commands"));
2461
2849
  }
2462
2850
  },
2463
2851
  getMeta: () => {
2464
2852
  if (!targetDir) return {};
2465
- const fullPath = join8(targetDir.dir, "commands");
2466
- if (fs8.existsSync(fullPath)) {
2467
- const items = fs8.readdirSync(fullPath).length;
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 fs8.existsSync(join8(targetDir.dir, "skills"));
2867
+ return fs12.existsSync(join12(targetDir.dir, "skills"));
2480
2868
  },
2481
2869
  fix: async () => {
2482
2870
  if (targetDir) {
2483
- await fs8.ensureDir(join8(targetDir.dir, "skills"));
2871
+ await fs12.ensureDir(join12(targetDir.dir, "skills"));
2484
2872
  }
2485
2873
  },
2486
2874
  getMeta: () => {
2487
2875
  if (!targetDir) return {};
2488
- const fullPath = join8(targetDir.dir, "skills");
2489
- if (fs8.existsSync(fullPath)) {
2490
- const items = fs8.readdirSync(fullPath).length;
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 fs8.existsSync(join8(targetDir.dir, "scripts"));
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 fs8.existsSync(join8(targetDir.dir, "hooks"));
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 fs8.existsSync(join8(targetDir.dir, "statusline.cjs")) || fs8.existsSync(join8(targetDir.dir, "statusline.sh"));
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 = join8(projectDir, ".ak", "doctor-report.md");
2679
- await fs8.ensureDir(join8(projectDir, ".ak"));
2680
- await fs8.writeFile(reportPath, markdown, "utf-8");
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 && !fs8.existsSync(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 fs9 from "fs-extra";
2795
- import { join as join9 } from "path";
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 = join9(dir, folder);
2825
- if (fs9.existsSync(targetPath)) {
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 = join9(dir, ".ak");
2830
- const hasAkState = fs9.existsSync(akDir);
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 = join9(target.path, subdir);
2840
- if (fs9.existsSync(subdirPath)) {
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 fs9.remove(path);
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 join10 } from "path";
3423
+ import { join as join14 } from "path";
3036
3424
  function getCurrentVersion() {
3037
3425
  try {
3038
- const pkg = JSON.parse(readFileSync(join10(CLI_ROOT, "package.json"), "utf-8"));
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 fs10 from "fs-extra";
3099
- import { join as join11 } from "path";
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 = join11(source.claudeDir, "skills", skillName);
3178
- if (!fs10.existsSync(skillPath)) {
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 = join11(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
3196
- await fs10.ensureDir(join11(process.cwd(), AGENT_SKILL_PATHS[agent]));
3197
- await fs10.copy(skillPath, targetPath, { overwrite: true });
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 = join11(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
3237
- await fs10.remove(targetPath);
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 = join11(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
3273
- return fs10.existsSync(skillPath);
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 = join11(process.cwd(), AGENT_SKILL_PATHS[agent]);
3277
- if (!fs10.existsSync(skillsDir)) {
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 = fs10.readdirSync(skillsDir);
3669
+ const items = fs14.readdirSync(skillsDir);
3282
3670
  return items.filter((item) => {
3283
- const itemPath = join11(skillsDir, item);
3284
- return fs10.statSync(itemPath).isDirectory();
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 dirname3, join as join13 } from "path";
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 join12 } from "path";
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 = join12(homedir2(), ".apero-kit");
3368
- var CACHE_FILE = join12(CACHE_DIR, "version-check.json");
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 = dirname3(__filename2);
3780
+ var __dirname2 = dirname6(__filename2);
3393
3781
  function getVersion() {
3394
3782
  try {
3395
- const pkg = JSON.parse(readFileSync3(join13(__dirname2, "..", "package.json"), "utf-8"));
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";